source: rtems/c/src/lib/libbsp/powerpc/beatnik/network/if_mve/mv643xx_eth.c @ 74a13c8

Last change on this file since 74a13c8 was 74a13c8, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 12, 2017 at 1:30:13 PM

bsp/beatnik: Fixes due to header file changes

Update #2833.

  • Property mode set to 100644
File size: 89.5 KB
Line 
1/* RTEMS driver for the mv643xx gigabit ethernet chip */
2
3/* Acknowledgement:
4 *
5 * Valuable information for developing this driver was obtained
6 * from the linux open-source driver mv643xx_eth.c which was written
7 * by the following people and organizations:
8 *
9 * Matthew Dharm <mdharm@momenco.com>
10 * rabeeh@galileo.co.il
11 * PMC-Sierra, Inc., Manish Lachwani
12 * Ralf Baechle <ralf@linux-mips.org>
13 * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org>
14 * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com>
15 *
16 * Note however, that in spite of the identical name of this file
17 * (and some of the symbols used herein) this file provides a
18 * new implementation and is the original work by the author.
19 */
20
21/*
22 * Authorship
23 * ----------
24 * This software (mv643xx ethernet driver for RTEMS) was
25 *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
26 *         Stanford Linear Accelerator Center, Stanford University.
27 *
28 * Acknowledgement of sponsorship
29 * ------------------------------
30 * The 'mv643xx ethernet driver for RTEMS' was produced by
31 *     the Stanford Linear Accelerator Center, Stanford University,
32 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
33 *
34 * Government disclaimer of liability
35 * ----------------------------------
36 * Neither the United States nor the United States Department of Energy,
37 * nor any of their employees, makes any warranty, express or implied, or
38 * assumes any legal liability or responsibility for the accuracy,
39 * completeness, or usefulness of any data, apparatus, product, or process
40 * disclosed, or represents that its use would not infringe privately owned
41 * rights.
42 *
43 * Stanford disclaimer of liability
44 * --------------------------------
45 * Stanford University makes no representations or warranties, express or
46 * implied, nor assumes any liability for the use of this software.
47 *
48 * Stanford disclaimer of copyright
49 * --------------------------------
50 * Stanford University, owner of the copyright, hereby disclaims its
51 * copyright and all other rights in this software.  Hence, anyone may
52 * freely use it for any purpose without restriction. 
53 *
54 * Maintenance of notices
55 * ----------------------
56 * In the interest of clarity regarding the origin and status of this
57 * SLAC software, this and all the preceding Stanford University notices
58 * are to remain affixed to any copy or derivative of this software made
59 * or distributed by the recipient and are to be affixed to any copy of
60 * software made or distributed by the recipient that contains a copy or
61 * derivative of this software.
62 *
63 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
64 */ 
65
66/*
67 * NOTE: Some register (e.g., the SMI register) are SHARED among the
68 *       three devices. Concurrent access protection is provided by
69 *       the global networking semaphore.
70 *       If other drivers are running on a subset of IFs then proper
71 *       locking of all shared registers must be implemented!
72 *
73 *       Some things I learned about this hardware can be found
74 *       further down...
75 */
76
77#ifndef KERNEL
78#define KERNEL
79#endif
80#ifndef _KERNEL
81#define _KERNEL
82#endif
83
84#include <rtems.h>
85#include <rtems/bspIo.h>
86#include <rtems/error.h>
87#include <bsp.h>
88#include <bsp/irq.h>
89#include <bsp/gtreg.h>
90#include <libcpu/byteorder.h>
91
92#include <sys/param.h>
93#include <dev/mii/mii.h>
94#include <net/if_media.h>
95
96/* Not so nice; would be more elegant not to depend on C library but the
97 * RTEMS-specific ioctl for dumping statistics needs stdio anyways.
98 */
99
100/*#define NDEBUG effectively removes all assertions
101 * If defining NDEBUG, MAKE SURE assert() EXPRESSION HAVE NO SIDE_EFFECTS!!
102 * This driver DOES have side-effects, so DONT DEFINE NDEBUG
103 * Performance-critical assertions are removed by undefining MVETH_TESTING.
104 */
105
106#undef NDEBUG
107#include <assert.h>
108#include <stdio.h>
109#include <errno.h>
110#include <inttypes.h>
111
112#include <rtems/rtems_bsdnet.h>
113#include <sys/mbuf.h>
114#include <sys/socket.h>
115#include <sys/sockio.h>
116#include <net/ethernet.h>
117#include <net/if.h>
118#include <netinet/in.h>
119#include <netinet/if_ether.h>
120
121#include <rtems/rtems_mii_ioctl.h>
122#include <bsp/early_enet_link_status.h>
123#include <bsp/if_mve_pub.h>
124
125/* CONFIGURABLE PARAMETERS */
126
127/* Enable Hardware Snooping; if this is disabled (undefined),
128 * cache coherency is maintained by software.
129 */
130#undef  ENABLE_HW_SNOOPING
131
132/* Compile-time debugging features */
133
134/* Enable paranoia assertions and checks; reduce # of descriptors to minimum for stressing   */
135#undef  MVETH_TESTING
136
137/* Enable debugging messages and some support routines  (dump rings etc.)                    */     
138#undef  MVETH_DEBUG
139
140#ifndef DISABLE_DETACHING       /* can override from Makefile */
141/* Hack for driver development; rtems bsdnet doesn't implement detaching an interface :-(
142 * but this hack allows us to unload/reload the driver module which makes development
143 * a lot less painful.
144 */
145#define MVETH_DETACH_HACK
146#endif
147
148/* Ring sizes */
149
150#ifdef MVETH_TESTING
151
152/* hard and small defaults */
153#undef  MV643XX_RX_RING_SIZE
154#define MV643XX_RX_RING_SIZE    2
155#undef  MV643XX_TX_RING_SIZE
156#define MV643XX_TX_RING_SIZE    4
157
158#else /* MVETH_TESTING */
159
160/* Define default ring sizes, allow override from bsp.h, Makefile,... and from ifcfg->rbuf_count/xbuf_count */
161
162#ifndef MV643XX_RX_RING_SIZE
163#define MV643XX_RX_RING_SIZE    40      /* attached buffers are always 2k clusters, i.e., this
164                                                                         * driver - with a configured ring size of 40 - constantly
165                                                                         * locks 80k of cluster memory - your app config better
166                                                                         * provides enough space!
167                                                                         */
168#endif
169
170#ifndef MV643XX_TX_RING_SIZE
171/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain;
172 *       in 'TESTING' mode, special code is compiled in to repackage
173 *               chains that are longer than the ring size. Normally, this is
174 *               disabled for sake of speed.
175 *               I observed chains of >17 entries regularly!
176 *
177 *       Also, TX_NUM_TAG_SLOTS (1) must be left empty as a marker, hence
178 *       the ring size must be > max. #frags + 1.
179 */
180#define MV643XX_TX_RING_SIZE    200     /* these are smaller fragments and not occupied when
181                                                                         * the driver is idle.
182                                                                         */
183#endif
184
185#endif /* MVETH_TESTING */
186
187/* How many instances to we support (bsp.h could override) */
188#ifndef MV643XXETH_NUM_DRIVER_SLOTS
189#define MV643XXETH_NUM_DRIVER_SLOTS     2
190#endif
191
192#define TX_NUM_TAG_SLOTS                        1 /* leave room for tag; must not be 0 */
193
194/* This is REAL; chip reads from 64-bit down-aligned buffer
195 * if the buffer size is < 8 !!! for buffer sizes 8 and upwards
196 * alignment is not an issue. This was verified using the
197 * 'mve_smallbuf_test.c'
198 */
199#define ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
200
201/* Chip register configuration values */
202#define MVETH_PORT_CONFIG_VAL                   (0                              \
203                        | MV643XX_ETH_DFLT_RX_Q(0)                                      \
204                        | MV643XX_ETH_DFLT_RX_ARP_Q(0)                          \
205                        | MV643XX_ETH_DFLT_RX_TCP_Q(0)                          \
206                        | MV643XX_ETH_DFLT_RX_UDP_Q(0)                          \
207                        | MV643XX_ETH_DFLT_RX_BPDU_Q(0)                         \
208                        )
209
210
211#define MVETH_PORT_XTEND_CONFIG_VAL             0
212
213#ifdef OLDCONFIGVAL
214#define MVETH_SERIAL_CTRL_CONFIG_VAL    (0                              \
215                         | MV643XX_ETH_FORCE_LINK_PASS                          \
216                         | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL     \
217                         | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL      \
218                         | MV643XX_ETH_BIT9_UNKNOWN                                     \
219                         | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE          \
220                         | MV643XX_ETH_SC_MAX_RX_1552                           \
221                         | MV643XX_ETH_SET_FULL_DUPLEX                          \
222                         | MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD         \
223                         )
224#endif
225/* If we enable autoneg (duplex, speed, ...) then it seems
226 * that the chip automatically updates link settings
227 * (correct link settings are reflected in PORT_STATUS_R).
228 * However, when we disable aneg in the PHY then things
229 * can get messed up and the port doesn't work anymore.
230 * => we follow the linux driver in disabling all aneg
231 * in the serial config reg. and manually updating the
232 * speed & duplex bits when the phy link status changes.
233 * FIXME: don't know what to do about pause/flow-ctrl.
234 * It is best to just use ANEG anyways!!!
235 */
236#define MVETH_SERIAL_CTRL_CONFIG_VAL    (0                              \
237                         | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX      \
238                         | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL     \
239                         | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL      \
240                         | MV643XX_ETH_BIT9_UNKNOWN                                     \
241                         | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE          \
242                         | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII      \
243                         | MV643XX_ETH_SC_MAX_RX_1552                           \
244                         )
245
246#define MVETH_SERIAL_CTRL_CONFIG_MSK    (0                              \
247                         | MV643XX_ETH_SERIAL_PORT_ENBL                         \
248                         | MV643XX_ETH_FORCE_LINK_PASS                          \
249                         | MV643XX_ETH_SC_MAX_RX_MASK                           \
250                         )
251
252
253#ifdef __PPC__
254#define MVETH_SDMA_CONFIG_VAL                   (0                              \
255                        | MV643XX_ETH_RX_BURST_SZ_4_64BIT                       \
256                        | MV643XX_ETH_TX_BURST_SZ_4_64BIT                       \
257                        )
258#else
259#define MVETH_SDMA_CONFIG_VAL                   (0                              \
260                        | MV643XX_ETH_RX_BURST_SZ_16_64BIT                      \
261                        | MV643XX_ETH_TX_BURST_SZ_16_64BIT                      \
262                        )
263#endif
264
265/* minimal frame size we accept */
266#define MVETH_MIN_FRAMSZ_CONFIG_VAL     40
267
268/* END OF CONFIGURABLE SECTION */
269
270/*
271 * Here's stuff I learned about this chip:
272 *
273 *
274 * RX interrupt flags:
275 *
276 * broadcast packet RX: 0x00000005
277 *           last buf:  0x00000c05
278 *           overrun:   0x00000c00           
279 * unicast   packet RX: 0x00000005
280 * bad CRC received:    0x00000005
281 *
282 * clearing 0x00000004 -> clears 0x00000001
283 * clearing 0x00000400 -> clears 0x00000800
284 *
285 * --> 0x0801 are probably some sort of summary bits.
286 *
287 * TX interrupt flags:
288 *
289 * broadcast packet in 1 buf: xcause: 0x00000001 (cause 0x00080000)
290 *        into disconn. link:             "                 "
291 *
292 * in some cases, I observed  xcause: 0x00000101 (reason for 0x100 unknown
293 * but the linux driver accepts it also).
294 *
295 *
296 * Here a few more ugly things about this piece of hardware I learned
297 * (painfully, painfully; spending many many hours & nights :-()
298 *
299 * a) Especially in the case of 'chained' descriptors, the DMA keeps
300 *    clobbering 'cmd_sts' long after it cleared the OWNership flag!!!
301 *    Only after the whole chain is processed (OWN cleared on the
302 *    last descriptor) it is safe to change cmd_sts.
303 *    However, in the case of hardware snooping I found that the
304 *    last descriptor in chain has its cmd_sts still clobbered *after*
305 *    checking ownership!, I.e.,
306 *        if ( ! OWN & cmd_sts ) {
307 *            cmd_sts = 0;
308 *        }
309 *    --> sometimes, cmd_sts is STILL != 0 here
310 *
311 * b) Sometimes, the OWNership flag is *not cleared*. 
312 *
313 * c) Weird things happen if the chip finds a descriptor with 'OWN'
314 *    still set (i.e., not properly loaded), i.e., corrupted packets
315 *    are sent [with OK checksum since the chip calculates it].
316 *
317 * Combine a+b+c and we end up with a real mess.
318 *
319 * The fact that the chip doesn't reliably reset OWN and that OTOH,
320 * it can't be reliably reset by the driver and still, the chip needs
321 * it for proper communication doesn't make things easy...
322 *
323 * Here the basic workarounds:
324 *
325 *     - In addition to check OWN, the scavenger compares the "currently
326 *       served desc" register to the descriptor it tries to recover and
327 *       ignores OWN if they do not match. Hope this is OK.
328 *       Otherwise, we could scan the list of used descriptors and proceed
329 *       recycling descriptors if we find a !OWNed one behind the target...
330 *
331 *     - Always keep an empty slot around to mark the end of the list of
332 *       jobs. The driver clears the descriptor ahead when enqueueing a new
333 *       packet.
334 */
335
336#define DRVNAME                 "mve"
337#define MAX_NUM_SLOTS   3
338
339#if MV643XXETH_NUM_DRIVER_SLOTS > MAX_NUM_SLOTS
340#error "mv643xxeth: only MAX_NUM_SLOTS supported"
341#endif
342
343#ifdef NDEBUG
344#error "Driver uses assert() statements with side-effects; MUST NOT define NDEBUG"
345#endif
346
347#ifdef MVETH_DEBUG
348#define STATIC
349#else
350#define STATIC static
351#endif
352
353#define TX_AVAILABLE_RING_SIZE(mp)              ((mp)->xbuf_count - (TX_NUM_TAG_SLOTS))
354
355/* macros for ring alignment; proper alignment is a hardware req; . */
356
357#ifdef ENABLE_HW_SNOOPING
358
359#define RING_ALIGNMENT                          16
360/* rx buffers must be 64-bit aligned (chip requirement) */
361#define RX_BUF_ALIGNMENT                        8
362
363#else /* ENABLE_HW_SNOOPING */
364
365/* Software cache management */
366
367#ifndef __PPC__
368#error  "Dont' know how to deal with cache on this CPU architecture"
369#endif
370
371/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency
372 * management works for cache line sizes of 16 and 32 bytes only. If the line size
373 * is bigger, the descriptors could be padded...
374 */
375#if     PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
376#error "Cache line size must be 16 or 32"
377#else
378#define RING_ALIGNMENT                          PPC_CACHE_ALIGNMENT
379#define RX_BUF_ALIGNMENT                        PPC_CACHE_ALIGNMENT
380#endif
381
382#endif /* ENABLE_HW_SNOOPING */
383
384
385/* HELPER MACROS */
386
387/* Align base to alignment 'a' */
388#define MV643XX_ALIGN(b, a)     ((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
389
390#define NOOP()                  do {} while(0)
391
392/* Function like macros */
393#define MV_READ(off) \
394                ld_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)))
395#define MV_WRITE(off, data)             \
396                st_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)), ((unsigned)data))
397
398
399/* ENET window mapped 1:1 to CPU addresses by our BSP/MotLoad
400 * -- if this is changed, we should think about caching the 'next' and 'buf' pointers.
401 */
402#define CPUADDR2ENET(a) ((Dma_addr_t)(a))
403#define ENET2CPUADDR(a) (a)
404
405#if 1   /* Whether to automatically try to reclaim descriptors when enqueueing new packets */
406#define MVETH_CLEAN_ON_SEND(mp) (BSP_mve_swipe_tx(mp))
407#else
408#define MVETH_CLEAN_ON_SEND(mp) (-1)
409#endif
410
411#define NEXT_TXD(d)     (d)->next
412#define NEXT_RXD(d)     (d)->next
413
414/* REGISTER AND DESCRIPTOR OFFSET AND BIT DEFINITIONS */
415
416/* Descriptor Definitions */
417/* Rx descriptor */
418#define RDESC_ERROR                                                                     (1<< 0) /* Error summary    */
419
420/* Error code (bit 1&2) is only valid if summary bit is set */
421#define RDESC_CRC_ERROR                                                         (    1)
422#define RDESC_OVERRUN_ERROR                                                     (    3)
423#define RDESC_MAX_FRAMELENGTH_ERROR                                     (    5)
424#define RDESC_RESOURCE_ERROR                                            (    7)
425
426#define RDESC_LAST                                                                      (1<<26) /* Last Descriptor   */
427#define RDESC_FRST                                                                      (1<<27) /* First Descriptor  */
428#define RDESC_INT_ENA                                                           (1<<29) /* Enable Interrupts */
429#define RDESC_DMA_OWNED                                                         (1<<31)
430
431/* Tx descriptor */
432#define TDESC_ERROR                                                                     (1<< 0) /* Error summary     */
433#define TDESC_ZERO_PAD                                                          (1<<19)
434#define TDESC_LAST                                                                      (1<<20) /* Last Descriptor   */
435#define TDESC_FRST                                                                      (1<<21) /* First Descriptor  */
436#define TDESC_GEN_CRC                                                           (1<<22)
437#define TDESC_INT_ENA                                                           (1<<23) /* Enable Interrupts */
438#define TDESC_DMA_OWNED                                                         (1<<31)
439
440
441
442/* Register Definitions */
443#define MV643XX_ETH_PHY_ADDR_R                                          (0x2000)
444#define MV643XX_ETH_SMI_R                                                       (0x2004)
445#define MV643XX_ETH_SMI_BUSY                                            (1<<28)
446#define MV643XX_ETH_SMI_VALID                                           (1<<27)
447#define MV643XX_ETH_SMI_OP_WR                                           (0<<26)
448#define MV643XX_ETH_SMI_OP_RD                                           (1<<26)
449
450#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)      (0x2448 + ((port)<<10))
451#define MV643XX_ETH_TX_START(queue)                                     (0x0001<<(queue))
452#define MV643XX_ETH_TX_STOP(queue)                                      (0x0100<<(queue))
453#define MV643XX_ETH_TX_START_M(queues)                          ((queues)&0xff)
454#define MV643XX_ETH_TX_STOP_M(queues)                           (((queues)&0xff)<<8)
455#define MV643XX_ETH_TX_STOP_ALL                                         (0xff00)
456#define MV643XX_ETH_TX_ANY_RUNNING                                      (0x00ff)
457
458#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(port)       (0x2680 + ((port)<<10))
459#define MV643XX_ETH_RX_START(queue)                                     (0x0001<<(queue))
460#define MV643XX_ETH_RX_STOP(queue)                                      (0x0100<<(queue))
461#define MV643XX_ETH_RX_STOP_ALL                                         (0xff00)
462#define MV643XX_ETH_RX_ANY_RUNNING                                      (0x00ff)
463
464#define MV643XX_ETH_CURRENT_SERVED_TX_DESC(port)        (0x2684 + ((port)<<10))
465
466/* The chip puts the ethernet header at offset 2 into the buffer so
467 * that the payload is aligned
468 */
469#define ETH_RX_OFFSET                                                           2
470#define ETH_CRC_LEN                                                                     4       /* strip FCS at end of packet */
471
472
473#define MV643XX_ETH_INTERRUPT_CAUSE_R(port)                     (0x2460 + ((port)<<10))
474/* not fully understood; RX seems to raise 0x0005 or 0x0c05 if last buffer is filled and 0x0c00
475 * if there are no buffers
476 */
477#define MV643XX_ETH_ALL_IRQS                                            (0x0007ffff)
478#define MV643XX_ETH_KNOWN_IRQS                                          (0x00000c05)
479#define MV643XX_ETH_IRQ_EXT_ENA                                         (1<<1)
480#define MV643XX_ETH_IRQ_RX_DONE                                         (1<<2)
481#define MV643XX_ETH_IRQ_RX_NO_DESC                                      (1<<10)
482
483#define MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(port)      (0x2464 + ((port)<<10))
484/* not fully understood; TX seems to raise 0x0001 and link change is 0x00010000
485 * if there are no buffers
486 */
487#define MV643XX_ETH_ALL_EXT_IRQS                                        (0x0011ffff)
488#define MV643XX_ETH_KNOWN_EXT_IRQS                                      (0x00010101)
489#define MV643XX_ETH_EXT_IRQ_TX_DONE                                     (1<<0)
490#define MV643XX_ETH_EXT_IRQ_LINK_CHG                            (1<<16)
491#define MV643XX_ETH_INTERRUPT_ENBL_R(port)                      (0x2468 + ((port)<<10))
492#define MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(port)       (0x246c + ((port)<<10))
493
494/* port configuration */
495#define MV643XX_ETH_PORT_CONFIG_R(port)                         (0x2400 + ((port)<<10))
496#define MV643XX_ETH_UNICAST_PROMISC_MODE                        (1<<0)
497#define MV643XX_ETH_DFLT_RX_Q(q)                                        ((q)<<1)
498#define MV643XX_ETH_DFLT_RX_ARP_Q(q)                            ((q)<<4)
499#define MV643XX_ETH_REJ_BCAST_IF_NOT_IP_OR_ARP          (1<<7)
500#define MV643XX_ETH_REJ_BCAST_IF_IP                                     (1<<8)
501#define MV643XX_ETH_REJ_BCAST_IF_ARP                            (1<<9)
502#define MV643XX_ETH_TX_AM_NO_UPDATE_ERR_SUMMARY         (1<<12)
503#define MV643XX_ETH_CAPTURE_TCP_FRAMES_ENBL                     (1<<14)
504#define MV643XX_ETH_CAPTURE_UDP_FRAMES_ENBL                     (1<<15)
505#define MV643XX_ETH_DFLT_RX_TCP_Q(q)                            ((q)<<16)
506#define MV643XX_ETH_DFLT_RX_UDP_Q(q)                            ((q)<<19)
507#define MV643XX_ETH_DFLT_RX_BPDU_Q(q)                           ((q)<<22)
508
509
510
511#define MV643XX_ETH_PORT_CONFIG_XTEND_R(port)           (0x2404 + ((port)<<10))
512#define MV643XX_ETH_CLASSIFY_ENBL                                       (1<<0)
513#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL         (0<<1)
514#define MV643XX_ETH_SPAN_BPDU_PACKETS_2_Q7                      (1<<1)
515#define MV643XX_ETH_PARTITION_DISBL                                     (0<<2)
516#define MV643XX_ETH_PARTITION_ENBL                                      (1<<2)
517
518#define MV643XX_ETH_SDMA_CONFIG_R(port)                         (0x241c + ((port)<<10))
519#define MV643XX_ETH_SDMA_RIFB                                           (1<<0)
520#define MV643XX_ETH_RX_BURST_SZ_1_64BIT                         (0<<1)
521#define MV643XX_ETH_RX_BURST_SZ_2_64BIT                         (1<<1)
522#define MV643XX_ETH_RX_BURST_SZ_4_64BIT                         (2<<1)
523#define MV643XX_ETH_RX_BURST_SZ_8_64BIT                         (3<<1)
524#define MV643XX_ETH_RX_BURST_SZ_16_64BIT                        (4<<1)
525#define MV643XX_ETH_SMDA_BLM_RX_NO_SWAP                         (1<<4)
526#define MV643XX_ETH_SMDA_BLM_TX_NO_SWAP                         (1<<5)
527#define MV643XX_ETH_SMDA_DESC_BYTE_SWAP                         (1<<6)
528#define MV643XX_ETH_TX_BURST_SZ_1_64BIT                         (0<<22)
529#define MV643XX_ETH_TX_BURST_SZ_2_64BIT                         (1<<22)
530#define MV643XX_ETH_TX_BURST_SZ_4_64BIT                         (2<<22)
531#define MV643XX_ETH_TX_BURST_SZ_8_64BIT                         (3<<22)
532#define MV643XX_ETH_TX_BURST_SZ_16_64BIT                        (4<<22)
533
534#define MV643XX_ETH_RX_MIN_FRAME_SIZE_R(port)           (0x247c + ((port)<<10))
535
536
537#define MV643XX_ETH_SERIAL_CONTROL_R(port)                      (0x243c + ((port)<<10))
538#define MV643XX_ETH_SERIAL_PORT_ENBL                            (1<<0)  /* Enable serial port */
539#define MV643XX_ETH_FORCE_LINK_PASS                                     (1<<1)
540#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX         (1<<2)
541#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL        (1<<3)
542#define MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL         (1<<4)
543#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS          (1<<5)
544#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX                        (1<<7)
545#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR      (1<<8)
546#define MV643XX_ETH_BIT9_UNKNOWN                                        (1<<9)  /* unknown purpose; linux sets this */
547#define MV643XX_ETH_FORCE_LINK_FAIL_DISABLE                     (1<<10)
548#define MV643XX_ETH_RETRANSMIT_FOREVER                          (1<<11) /* limit to 16 attempts if clear    */
549#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII         (1<<13)
550#define MV643XX_ETH_DTE_ADV_1                                           (1<<14)
551#define MV643XX_ETH_AUTO_NEG_BYPASS_ENBL                        (1<<15)
552#define MV643XX_ETH_RESTART_AUTO_NEG                            (1<<16)
553#define MV643XX_ETH_SC_MAX_RX_1518                                      (0<<17) /* Limit RX packet size */
554#define MV643XX_ETH_SC_MAX_RX_1522                                      (1<<17) /* Limit RX packet size */
555#define MV643XX_ETH_SC_MAX_RX_1552                                      (2<<17) /* Limit RX packet size */
556#define MV643XX_ETH_SC_MAX_RX_9022                                      (3<<17) /* Limit RX packet size */
557#define MV643XX_ETH_SC_MAX_RX_9192                                      (4<<17) /* Limit RX packet size */
558#define MV643XX_ETH_SC_MAX_RX_9700                                      (5<<17) /* Limit RX packet size */
559#define MV643XX_ETH_SC_MAX_RX_MASK                                      (7<<17) /* bitmask */
560#define MV643XX_ETH_SET_EXT_LOOPBACK                            (1<<20)
561#define MV643XX_ETH_SET_FULL_DUPLEX                                     (1<<21)
562#define MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD            (1<<22) /* enable flow ctrl on rx and tx in full-duplex */
563#define MV643XX_ETH_SET_GMII_SPEED_1000                         (1<<23) /* 10/100 if clear */
564#define MV643XX_ETH_SET_MII_SPEED_100                           (1<<24) /* 10 if clear     */
565
566#define MV643XX_ETH_PORT_STATUS_R(port)                         (0x2444 + ((port)<<10))
567
568#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT                     (1<<0)
569#define MV643XX_ETH_PORT_STATUS_LINK_UP                         (1<<1)
570#define MV643XX_ETH_PORT_STATUS_FDX                                     (1<<2)
571#define MV643XX_ETH_PORT_STATUS_FC                                      (1<<3)
572#define MV643XX_ETH_PORT_STATUS_1000                            (1<<4)
573#define MV643XX_ETH_PORT_STATUS_100                                     (1<<5)
574/* PSR bit 6 unknown */
575#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS          (1<<7)
576#define MV643XX_ETH_PORT_STATUS_ANEG_BYPASSED           (1<<8)
577#define MV643XX_ETH_PORT_STATUS_PARTITION                       (1<<9)
578#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY           (1<<10)
579
580#define MV643XX_ETH_MIB_COUNTERS(port)                          (0x3000 + ((port)<<7))
581#define MV643XX_ETH_NUM_MIB_COUNTERS                            32
582
583#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO                       (0)
584#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_HI                       (1<<2)
585#define MV643XX_ETH_MIB_BAD_OCTS_RCVD                           (2<<2)
586#define MV643XX_ETH_MIB_INTERNAL_MAC_TX_ERR                     (3<<2)
587#define MV643XX_ETH_MIB_GOOD_FRAMES_RCVD                        (4<<2)
588#define MV643XX_ETH_MIB_BAD_FRAMES_RCVD                         (5<<2)
589#define MV643XX_ETH_MIB_BCAST_FRAMES_RCVD                       (6<<2)
590#define MV643XX_ETH_MIB_MCAST_FRAMES_RCVD                       (7<<2)
591#define MV643XX_ETH_MIB_FRAMES_64_OCTS                          (8<<2)
592#define MV643XX_ETH_MIB_FRAMES_65_127_OCTS                      (9<<2)
593#define MV643XX_ETH_MIB_FRAMES_128_255_OCTS                     (10<<2)
594#define MV643XX_ETH_MIB_FRAMES_256_511_OCTS                     (11<<2)
595#define MV643XX_ETH_MIB_FRAMES_512_1023_OCTS            (12<<2)
596#define MV643XX_ETH_MIB_FRAMES_1024_MAX_OCTS            (13<<2)
597#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO                       (14<<2)
598#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_HI                       (15<<2)
599#define MV643XX_ETH_MIB_GOOD_FRAMES_SENT                        (16<<2)
600#define MV643XX_ETH_MIB_EXCESSIVE_COLL                          (17<<2)
601#define MV643XX_ETH_MIB_MCAST_FRAMES_SENT                       (18<<2)
602#define MV643XX_ETH_MIB_BCAST_FRAMES_SENT                       (19<<2)
603#define MV643XX_ETH_MIB_UNREC_MAC_CTRL_RCVD                     (20<<2)
604#define MV643XX_ETH_MIB_FC_SENT                                         (21<<2)
605#define MV643XX_ETH_MIB_GOOD_FC_RCVD                            (22<<2)
606#define MV643XX_ETH_MIB_BAD_FC_RCVD                                     (23<<2)
607#define MV643XX_ETH_MIB_UNDERSIZE_RCVD                          (24<<2)
608#define MV643XX_ETH_MIB_FRAGMENTS_RCVD                          (25<<2)
609#define MV643XX_ETH_MIB_OVERSIZE_RCVD                           (26<<2)
610#define MV643XX_ETH_MIB_JABBER_RCVD                                     (27<<2)
611#define MV643XX_ETH_MIB_MAC_RX_ERR                                      (28<<2)
612#define MV643XX_ETH_MIB_BAD_CRC_EVENT                           (29<<2)
613#define MV643XX_ETH_MIB_COLL                                            (30<<2)
614#define MV643XX_ETH_MIB_LATE_COLL                                       (31<<2)
615
616#define MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(port) (0x3400+((port)<<10))
617#define MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(port) (0x3500+((port)<<10))
618#define MV643XX_ETH_DA_FILTER_UNICAST_TBL(port)         (0x3600+((port)<<10))
619#define MV643XX_ETH_NUM_MCAST_ENTRIES                           64
620#define MV643XX_ETH_NUM_UNICAST_ENTRIES                         4
621
622#define MV643XX_ETH_BAR_0                                                       (0x2200)
623#define MV643XX_ETH_SIZE_R_0                                            (0x2204)
624#define MV643XX_ETH_BAR_1                                                       (0x2208)
625#define MV643XX_ETH_SIZE_R_1                                            (0x220c)
626#define MV643XX_ETH_BAR_2                                                       (0x2210)
627#define MV643XX_ETH_SIZE_R_2                                            (0x2214)
628#define MV643XX_ETH_BAR_3                                                       (0x2218)
629#define MV643XX_ETH_SIZE_R_3                                            (0x221c)
630#define MV643XX_ETH_BAR_4                                                       (0x2220)
631#define MV643XX_ETH_SIZE_R_4                                            (0x2224)
632#define MV643XX_ETH_BAR_5                                                       (0x2228)
633#define MV643XX_ETH_SIZE_R_5                                            (0x222c)
634#define MV643XX_ETH_NUM_BARS                                            6
635
636/* Bits in the BAR reg to program cache snooping */
637#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
638#define MV64360_ENET2MEM_SNOOP_WT       0x1000
639#define MV64360_ENET2MEM_SNOOP_WB       0x2000
640#define MV64360_ENET2MEM_SNOOP_MSK      0x3000
641
642
643#define MV643XX_ETH_BAR_ENBL_R                                          (0x2290)
644#define MV643XX_ETH_BAR_DISABLE(bar)                            (1<<(bar))
645#define MV643XX_ETH_BAR_DISBL_ALL                                       0x3f
646
647#define MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(port)        (0x260c+((port)<<10))
648#define MV643XX_ETH_RX_Q1_CURRENT_DESC_PTR(port)        (0x261c+((port)<<10))
649#define MV643XX_ETH_RX_Q2_CURRENT_DESC_PTR(port)        (0x262c+((port)<<10))
650#define MV643XX_ETH_RX_Q3_CURRENT_DESC_PTR(port)        (0x263c+((port)<<10))
651#define MV643XX_ETH_RX_Q4_CURRENT_DESC_PTR(port)        (0x264c+((port)<<10))
652#define MV643XX_ETH_RX_Q5_CURRENT_DESC_PTR(port)        (0x265c+((port)<<10))
653#define MV643XX_ETH_RX_Q6_CURRENT_DESC_PTR(port)        (0x266c+((port)<<10))
654#define MV643XX_ETH_RX_Q7_CURRENT_DESC_PTR(port)        (0x267c+((port)<<10))
655
656#define MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(port)        (0x26c0+((port)<<10))
657#define MV643XX_ETH_TX_Q1_CURRENT_DESC_PTR(port)        (0x26c4+((port)<<10))
658#define MV643XX_ETH_TX_Q2_CURRENT_DESC_PTR(port)        (0x26c8+((port)<<10))
659#define MV643XX_ETH_TX_Q3_CURRENT_DESC_PTR(port)        (0x26cc+((port)<<10))
660#define MV643XX_ETH_TX_Q4_CURRENT_DESC_PTR(port)        (0x26d0+((port)<<10))
661#define MV643XX_ETH_TX_Q5_CURRENT_DESC_PTR(port)        (0x26d4+((port)<<10))
662#define MV643XX_ETH_TX_Q6_CURRENT_DESC_PTR(port)        (0x26d8+((port)<<10))
663#define MV643XX_ETH_TX_Q7_CURRENT_DESC_PTR(port)        (0x26dc+((port)<<10))
664
665#define MV643XX_ETH_MAC_ADDR_LO(port)                           (0x2414+((port)<<10))
666#define MV643XX_ETH_MAC_ADDR_HI(port)                           (0x2418+((port)<<10))
667
668/* TYPE DEFINITIONS */
669
670/* just to make the purpose explicit; vars of this
671 * type may need CPU-dependent address translation,
672 * endian conversion etc.
673 */
674typedef uint32_t Dma_addr_t;
675
676typedef volatile struct mveth_rx_desc {
677#ifndef __BIG_ENDIAN__
678#error  "descriptor declaration not implemented for little endian machines"
679#endif
680        uint16_t        byte_cnt;
681        uint16_t        buf_size;
682        uint32_t        cmd_sts;                                        /* control and status */
683        Dma_addr_t      next_desc_ptr;                          /* next descriptor (as seen from DMA) */
684        Dma_addr_t      buf_ptr;
685        /* fields below here are not used by the chip */
686        void            *u_buf;                                         /* user buffer */
687        volatile struct mveth_rx_desc *next;    /* next descriptor (CPU address; next_desc_ptr is a DMA address) */
688        uint32_t        pad[2];
689} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthRxDescRec, *MvEthRxDesc;
690
691typedef volatile struct mveth_tx_desc {
692#ifndef __BIG_ENDIAN__
693#error  "descriptor declaration not implemented for little endian machines"
694#endif
695        uint16_t        byte_cnt;
696        uint16_t        l4i_chk;
697        uint32_t        cmd_sts;                                        /* control and status */
698        Dma_addr_t      next_desc_ptr;                          /* next descriptor (as seen from DMA) */
699        Dma_addr_t      buf_ptr;
700        /* fields below here are not used by the chip */
701        uint32_t        workaround[2];                          /* use this space to work around the 8byte problem (is this real?) */
702        void            *u_buf;                                         /* user buffer */
703        volatile struct mveth_tx_desc *next;    /* next descriptor (CPU address; next_desc_ptr is a DMA address)   */
704} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthTxDescRec, *MvEthTxDesc;
705
706/* Assume there are never more then 64k aliasing entries */
707typedef uint16_t Mc_Refcnt[MV643XX_ETH_NUM_MCAST_ENTRIES*4];
708
709/* driver private data and bsdnet interface structure */
710struct mveth_private {
711        MvEthRxDesc             rx_ring;                                        /* pointers to aligned ring area             */
712        MvEthTxDesc             tx_ring;                                        /* pointers to aligned ring area             */
713        MvEthRxDesc             ring_area;                                      /* allocated ring area                       */
714        int                             rbuf_count, xbuf_count;         /* saved ring sizes from ifconfig            */
715        int                             port_num;
716        int                             phy;
717        MvEthRxDesc             d_rx_t;                                         /* tail of the RX ring; next received packet */
718        MvEthTxDesc             d_tx_t, d_tx_h;                         
719        uint32_t                rx_desc_dma, tx_desc_dma;       /* ring address as seen by DMA; (1:1 on this BSP) */
720        int                             avail;
721        void            (*isr)(void*);
722        void            *isr_arg;
723        /* Callbacks to handle buffers */
724        void                    (*cleanup_txbuf)(void*, void*, int);    /* callback to cleanup TX buffer */
725        void                    *cleanup_txbuf_arg;
726        void                    *(*alloc_rxbuf)(int *psize, uintptr_t *paddr);  /* allocate RX buffer  */
727        void                    (*consume_rxbuf)(void*, void*,  int);   /* callback to consume RX buffer */
728        void                    *consume_rxbuf_arg;
729        rtems_id        tid;
730        uint32_t                irq_mask;                                       /* IRQs we use                              */
731        uint32_t                xirq_mask;
732    int             promisc;
733        struct          {
734                unsigned                irqs;
735                unsigned                maxchain;
736                unsigned                repack;
737                unsigned                packet;
738                unsigned                odrops;                                 /* no counter in core code                   */
739                struct {
740                        uint64_t        good_octs_rcvd;         /* 64-bit */
741                        uint32_t        bad_octs_rcvd;
742                        uint32_t        internal_mac_tx_err;
743                        uint32_t        good_frames_rcvd;
744                        uint32_t        bad_frames_rcvd;
745                        uint32_t        bcast_frames_rcvd;
746                        uint32_t        mcast_frames_rcvd;
747                        uint32_t        frames_64_octs;
748                        uint32_t        frames_65_127_octs;
749                        uint32_t        frames_128_255_octs;
750                        uint32_t        frames_256_511_octs;
751                        uint32_t        frames_512_1023_octs;
752                        uint32_t        frames_1024_max_octs;
753                        uint64_t        good_octs_sent;         /* 64-bit */
754                        uint32_t        good_frames_sent;
755                        uint32_t        excessive_coll;
756                        uint32_t        mcast_frames_sent;
757                        uint32_t        bcast_frames_sent;
758                        uint32_t        unrec_mac_ctrl_rcvd;
759                        uint32_t        fc_sent;
760                        uint32_t        good_fc_rcvd;
761                        uint32_t        bad_fc_rcvd;
762                        uint32_t        undersize_rcvd;
763                        uint32_t        fragments_rcvd;
764                        uint32_t        oversize_rcvd;
765                        uint32_t        jabber_rcvd;
766                        uint32_t        mac_rx_err;
767                        uint32_t        bad_crc_event;
768                        uint32_t        coll;
769                        uint32_t        late_coll;
770                } mib;
771        }                       stats;
772        struct {
773                Mc_Refcnt       specl, other;
774        }           mc_refcnt;
775};
776
777/* stuff needed for bsdnet support */
778struct mveth_bsdsupp {
779        int                             oif_flags;                                      /* old / cached if_flags */
780};
781
782struct mveth_softc {
783        struct arpcom                   arpcom;
784        struct mveth_bsdsupp    bsd;
785        struct mveth_private    pvt;
786};
787
788/* GLOBAL VARIABLES */
789#ifdef MVETH_DEBUG_TX_DUMP
790int mveth_tx_dump = 0;
791#endif
792
793/* THE array of driver/bsdnet structs */
794
795/* If detaching/module unloading is enabled, the main driver data
796 * structure must remain in memory; hence it must reside in its own
797 * 'dummy' module...
798 */
799#ifdef  MVETH_DETACH_HACK
800extern
801#else
802STATIC
803#endif
804struct mveth_softc theMvEths[MV643XXETH_NUM_DRIVER_SLOTS]
805#ifndef MVETH_DETACH_HACK
806= {{{{0}},}}
807#endif
808;
809
810/* daemon task id */
811STATIC rtems_id mveth_tid = 0;
812/* register access protection mutex */
813STATIC rtems_id mveth_mtx = 0;
814#define REGLOCK()       do { \
815                if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(mveth_mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \
816                        rtems_panic(DRVNAME": unable to lock register protection mutex"); \
817                } while (0)
818#define REGUNLOCK()     rtems_semaphore_release(mveth_mtx)
819
820/* Format strings for statistics messages */
821static const char *mibfmt[] = {
822        "  GOOD_OCTS_RCVD:      %"PRIu64"\n",
823        0,
824        "  BAD_OCTS_RCVD:       %"PRIu32"\n",
825        "  INTERNAL_MAC_TX_ERR: %"PRIu32"\n",
826        "  GOOD_FRAMES_RCVD:    %"PRIu32"\n",
827        "  BAD_FRAMES_RCVD:     %"PRIu32"\n",
828        "  BCAST_FRAMES_RCVD:   %"PRIu32"\n",
829        "  MCAST_FRAMES_RCVD:   %"PRIu32"\n",
830        "  FRAMES_64_OCTS:      %"PRIu32"\n",
831        "  FRAMES_65_127_OCTS:  %"PRIu32"\n",
832        "  FRAMES_128_255_OCTS: %"PRIu32"\n",
833        "  FRAMES_256_511_OCTS: %"PRIu32"\n",
834        "  FRAMES_512_1023_OCTS:%"PRIu32"\n",
835        "  FRAMES_1024_MAX_OCTS:%"PRIu32"\n",
836        "  GOOD_OCTS_SENT:      %"PRIu64"\n",
837        0,
838        "  GOOD_FRAMES_SENT:    %"PRIu32"\n",
839        "  EXCESSIVE_COLL:      %"PRIu32"\n",
840        "  MCAST_FRAMES_SENT:   %"PRIu32"\n",
841        "  BCAST_FRAMES_SENT:   %"PRIu32"\n",
842        "  UNREC_MAC_CTRL_RCVD: %"PRIu32"\n",
843        "  FC_SENT:             %"PRIu32"\n",
844        "  GOOD_FC_RCVD:        %"PRIu32"\n",
845        "  BAD_FC_RCVD:         %"PRIu32"\n",
846        "  UNDERSIZE_RCVD:      %"PRIu32"\n",
847        "  FRAGMENTS_RCVD:      %"PRIu32"\n",
848        "  OVERSIZE_RCVD:       %"PRIu32"\n",
849        "  JABBER_RCVD:         %"PRIu32"\n",
850        "  MAC_RX_ERR:          %"PRIu32"\n",
851        "  BAD_CRC_EVENT:       %"PRIu32"\n",
852        "  COLL:                %"PRIu32"\n",
853        "  LATE_COLL:           %"PRIu32"\n",
854};
855
856/* Interrupt Handler Connection */
857
858/* forward decls + implementation for IRQ API funcs */
859
860static void mveth_isr(rtems_irq_hdl_param unit);
861static void mveth_isr_1(rtems_irq_hdl_param unit);
862static void noop(const rtems_irq_connect_data *unused)  {}
863static int  noop1(const rtems_irq_connect_data *unused) { return 0; }
864
865static rtems_irq_connect_data irq_data[MAX_NUM_SLOTS] = {
866        {
867                BSP_IRQ_ETH0,
868                0,
869                (rtems_irq_hdl_param)0,
870                noop,
871                noop,
872                noop1
873        },
874        {
875                BSP_IRQ_ETH1,
876                0,
877                (rtems_irq_hdl_param)1,
878                noop,
879                noop,
880                noop1
881        },
882        {
883                BSP_IRQ_ETH2,
884                0,
885                (rtems_irq_hdl_param)2,
886                noop,
887                noop,
888                noop1
889        },
890};
891
892/* MII Ioctl Interface */
893
894STATIC unsigned
895mveth_mii_read(struct mveth_private *mp, unsigned addr);
896
897STATIC unsigned
898mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v);
899
900
901/* mdio / mii interface wrappers for rtems_mii_ioctl API */
902
903static int mveth_mdio_r(int phy, void *uarg, unsigned reg, uint32_t *pval)
904{
905        if ( phy > 1 )
906                return -1;
907
908        *pval = mveth_mii_read(uarg, reg);
909        return 0;
910}
911
912static int mveth_mdio_w(int phy, void *uarg, unsigned reg, uint32_t val)
913{
914        if ( phy > 1 )
915                return -1;
916        mveth_mii_write(uarg, reg, val);
917        return 0;
918}
919
920static struct rtems_mdio_info mveth_mdio = {
921        mdio_r:   mveth_mdio_r,
922        mdio_w:   mveth_mdio_w,
923        has_gmii: 1,
924};
925
926/* LOW LEVEL SUPPORT ROUTINES */
927
928/* Software Cache Coherency */
929#ifndef ENABLE_HW_SNOOPING
930#ifndef __PPC__
931#error "Software cache coherency maintenance is not implemented for your CPU architecture"
932#endif
933
934static inline unsigned INVAL_DESC(volatile void *d)
935{
936typedef const char cache_line[PPC_CACHE_ALIGNMENT];
937        asm volatile("dcbi 0, %1":"=m"(*(cache_line*)d):"r"(d));
938        return (unsigned)d;     /* so this can be used in comma expression */
939}
940
941static inline void FLUSH_DESC(volatile void *d)
942{
943typedef const char cache_line[PPC_CACHE_ALIGNMENT];
944        asm volatile("dcbf 0, %0"::"r"(d),"m"(*(cache_line*)d));
945}
946
947static inline void FLUSH_BARRIER(void)
948{
949        asm volatile("eieio");
950}
951
952/* RX buffers are always cache-line aligned
953 * ASSUMPTIONS:
954 *   - 'addr' is cache aligned
955 *   -  len   is a multiple >0 of cache lines
956 */
957static inline void INVAL_BUF(register uintptr_t addr, register int len)
958{
959typedef char maxbuf[2048]; /* more than an ethernet packet */
960        do {
961                len -= RX_BUF_ALIGNMENT;
962                asm volatile("dcbi %0, %1"::"b"(addr),"r"(len));
963        } while (len > 0);
964        asm volatile("":"=m"(*(maxbuf*)addr));
965}
966
967/* Flushing TX buffers is a little bit trickier; we don't really know their
968 * alignment but *assume* adjacent addresses are covering 'ordinary' memory
969 * so that flushing them does no harm!
970 */
971static inline void FLUSH_BUF(register uintptr_t addr, register int len)
972{
973        asm volatile("":::"memory");
974        len = MV643XX_ALIGN(len, RX_BUF_ALIGNMENT);
975        do { 
976                asm volatile("dcbf %0, %1"::"b"(addr),"r"(len));
977                len -= RX_BUF_ALIGNMENT;
978        } while ( len >= 0 );
979}
980
981#else /* hardware snooping enabled */
982
983/* inline this to silence compiler warnings */
984static inline int INVAL_DESC(volatile void *d)
985{ return 0; }
986
987#define FLUSH_DESC(d)   NOOP()
988#define INVAL_BUF(b,l)  NOOP()
989#define FLUSH_BUF(b,l)  NOOP()
990#define FLUSH_BARRIER() NOOP()
991
992#endif  /* cache coherency support */
993
994/* Synchronize memory access */
995#ifdef __PPC__
996static inline void membarrier(void)
997{
998        asm volatile("sync":::"memory");
999}
1000#else
1001#error "memory barrier instruction not defined (yet) for this CPU"
1002#endif
1003
1004/* Enable and disable interrupts at the device */
1005static inline void
1006mveth_enable_irqs(struct mveth_private *mp, uint32_t mask)
1007{
1008rtems_interrupt_level l;
1009uint32_t val;
1010        rtems_interrupt_disable(l);
1011
1012        val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
1013        val  = (val | mask | MV643XX_ETH_IRQ_EXT_ENA) & mp->irq_mask;
1014
1015        MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        val);
1016
1017        val  = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
1018        val  = (val | mask) & mp->xirq_mask;
1019        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), val);
1020
1021        rtems_interrupt_enable(l);
1022}
1023
1024static inline uint32_t
1025mveth_disable_irqs(struct mveth_private *mp, uint32_t mask)
1026{
1027rtems_interrupt_level l;
1028uint32_t val,xval,tmp;
1029        rtems_interrupt_disable(l);
1030
1031        val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
1032        tmp  = ( (val & ~mask) | MV643XX_ETH_IRQ_EXT_ENA ) & mp->irq_mask;
1033        MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        tmp);
1034
1035        xval = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
1036        tmp  = (xval & ~mask) & mp->xirq_mask;
1037        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), tmp);
1038
1039        rtems_interrupt_enable(l);
1040
1041        return (val | xval);
1042}
1043
1044/* This should be safe even w/o turning off interrupts if multiple
1045 * threads ack different bits in the cause register (and ignore
1046 * other ones) since writing 'ones' into the cause register doesn't
1047 * 'stick'.
1048 */
1049
1050static inline uint32_t
1051mveth_ack_irqs(struct mveth_private *mp, uint32_t mask)
1052{
1053register uint32_t x,xe,p;
1054
1055                p  = mp->port_num;
1056                /* Get cause */
1057                x  = MV_READ(MV643XX_ETH_INTERRUPT_CAUSE_R(p));
1058
1059                /* Ack interrupts filtering the ones we're interested in */
1060
1061                /* Note: EXT_IRQ bit clears by itself if EXT interrupts are cleared */
1062                MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(p), ~ (x & mp->irq_mask & mask));
1063
1064                                /* linux driver tests 1<<1 as a summary bit for extended interrupts;
1065                                 * the mv64360 seems to use 1<<19 for that purpose; for the moment,
1066                                 * I just check both.
1067                                 * Update: link status irq (1<<16 in xe) doesn't set (1<<19) in x!
1068                                 */
1069                if ( 1 /* x & 2 */ )
1070                {
1071                        xe = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p));
1072
1073                        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p), ~ (xe & mp->xirq_mask & mask));
1074                } else {
1075                        xe = 0;
1076                }
1077#ifdef MVETH_TESTING
1078                if (    ((x & MV643XX_ETH_ALL_IRQS) & ~MV643XX_ETH_KNOWN_IRQS)
1079                         || ((xe & MV643XX_ETH_ALL_EXT_IRQS) & ~MV643XX_ETH_KNOWN_EXT_IRQS) ) {
1080                        fprintf(stderr, "Unknown IRQs detected; leaving all disabled for debugging:\n");
1081                        fprintf(stderr, "Cause reg was 0x%08x, ext cause 0x%08x\n", x, xe);
1082                        mp->irq_mask  = 0;
1083                        mp->xirq_mask = 0;
1084                }
1085#endif
1086                /* luckily, the extended and 'normal' interrupts we use don't overlap so
1087                 * we can just OR them into a single word
1088                 */
1089                return  (xe & mp->xirq_mask) | (x & mp->irq_mask);
1090}
1091
1092static void mveth_isr(rtems_irq_hdl_param arg)
1093{
1094unsigned unit = (unsigned)arg;
1095        mveth_disable_irqs(&theMvEths[unit].pvt, -1);
1096        theMvEths[unit].pvt.stats.irqs++;
1097        rtems_bsdnet_event_send( theMvEths[unit].pvt.tid, 1<<unit );
1098}
1099
1100static void mveth_isr_1(rtems_irq_hdl_param arg)
1101{
1102unsigned              unit = (unsigned)arg;
1103struct mveth_private *mp   = &theMvEths[unit].pvt;
1104
1105        mp->stats.irqs++;
1106        mp->isr(mp->isr_arg);
1107}
1108
1109static void
1110mveth_clear_mib_counters(struct mveth_private *mp)
1111{
1112register int            i;
1113register uint32_t       b;
1114        /* reading the counters resets them */
1115        b = MV643XX_ETH_MIB_COUNTERS(mp->port_num);
1116        for (i=0; i< MV643XX_ETH_NUM_MIB_COUNTERS; i++, b+=4)
1117                (void)MV_READ(b);
1118}
1119
1120/* Reading a MIB register also clears it. Hence we read the lo
1121 * register first, then the hi one. Correct reading is guaranteed since
1122 * the 'lo' register cannot overflow after it is read since it had
1123 * been reset to 0.
1124 */
1125static unsigned long long
1126read_long_mib_counter(int port_num, int idx)
1127{
1128unsigned long lo;
1129unsigned long long hi;
1130        lo = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
1131        idx++;
1132        hi = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
1133        return (hi<<32) | lo;
1134}
1135
1136static inline unsigned long
1137read_mib_counter(int port_num, int idx)
1138{
1139        return MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
1140}
1141
1142
1143/* write ethernet address from buffer to hardware (need to change unicast filter after this) */
1144static void
1145mveth_write_eaddr(struct mveth_private *mp, unsigned char *eaddr)
1146{
1147int                     i;
1148uint32_t        x;
1149
1150        /* build hi word */
1151        for (i=4,x=0; i; i--, eaddr++) {
1152                x = (x<<8) | *eaddr;
1153        }
1154        MV_WRITE(MV643XX_ETH_MAC_ADDR_HI(mp->port_num), x);
1155
1156        /* build lo word */
1157        for (i=2,x=0; i; i--, eaddr++) {
1158                x = (x<<8) | *eaddr;
1159        }
1160        MV_WRITE(MV643XX_ETH_MAC_ADDR_LO(mp->port_num), x);
1161}
1162
1163/* PHY/MII Interface
1164 *
1165 * Read/write a PHY register;
1166 *
1167 * NOTE: The SMI register is shared among the three devices.
1168 *       Protection is provided by the global networking semaphore.
1169 *       If non-bsd drivers are running on a subset of IFs proper
1170 *       locking of all shared registers must be implemented!
1171 */
1172STATIC unsigned
1173mveth_mii_read(struct mveth_private *mp, unsigned addr)
1174{
1175unsigned v;
1176unsigned wc = 0;
1177
1178        addr  &= 0x1f;
1179
1180        /* wait until not busy */
1181        do {
1182                v = MV_READ(MV643XX_ETH_SMI_R);
1183                wc++;
1184        } while ( MV643XX_ETH_SMI_BUSY & v );
1185
1186        MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_RD );
1187
1188        do {
1189                v = MV_READ(MV643XX_ETH_SMI_R);
1190                wc++;
1191        } while ( MV643XX_ETH_SMI_BUSY & v );
1192
1193        if (wc>0xffff)
1194                wc = 0xffff;
1195        return (wc<<16) | (v & 0xffff);
1196}
1197
1198STATIC unsigned
1199mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v)
1200{
1201unsigned wc = 0;
1202
1203        addr  &= 0x1f;
1204        v     &= 0xffff;
1205
1206        /* busywait is ugly but not preventing ISRs or high priority tasks from
1207         * preempting us
1208         */
1209
1210        /* wait until not busy */
1211        while ( MV643XX_ETH_SMI_BUSY & MV_READ(MV643XX_ETH_SMI_R) )
1212                wc++ /* wait */;
1213
1214        MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) | MV643XX_ETH_SMI_OP_WR | v );
1215
1216        return wc;
1217}
1218
1219/* MID-LAYER SUPPORT ROUTINES */
1220
1221/* Start TX if descriptors are exhausted */
1222static __inline__ void
1223mveth_start_tx(struct mveth_private *mp)
1224{
1225uint32_t running;
1226        if ( mp->avail <= 0 ) {
1227                running = MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num));
1228                if ( ! (running & MV643XX_ETH_TX_START(0)) ) {
1229                        MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
1230                }
1231        }
1232}
1233
1234/* Stop TX and wait for the command queues to stop and the fifo to drain */
1235static uint32_t
1236mveth_stop_tx(int port)
1237{
1238uint32_t active_q;
1239
1240        active_q = (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) & MV643XX_ETH_TX_ANY_RUNNING);
1241
1242        if ( active_q ) {
1243                /* Halt TX and wait for activity to stop */
1244                MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port), MV643XX_ETH_TX_STOP_ALL);
1245                while ( MV643XX_ETH_TX_ANY_RUNNING & MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) )
1246                        /* poll-wait */;
1247                /* Wait for Tx FIFO to drain */
1248                while ( ! (MV643XX_ETH_PORT_STATUS_R(port) & MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY) )
1249                        /* poll-wait */;
1250        }
1251
1252        return active_q;
1253}
1254
1255/* update serial port settings from current link status */
1256static void
1257mveth_update_serial_port(struct mveth_private *mp, int media)
1258{
1259int port = mp->port_num;
1260uint32_t old, new;
1261
1262        new = old = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(port));
1263
1264        /* mask speed and duplex settings */
1265        new &= ~(  MV643XX_ETH_SET_GMII_SPEED_1000
1266                         | MV643XX_ETH_SET_MII_SPEED_100
1267                         | MV643XX_ETH_SET_FULL_DUPLEX );
1268
1269        if ( IFM_FDX & media )
1270                new |= MV643XX_ETH_SET_FULL_DUPLEX;
1271
1272        switch ( IFM_SUBTYPE(media) ) {
1273                default: /* treat as 10 */
1274                        break;
1275                case IFM_100_TX:
1276                        new |= MV643XX_ETH_SET_MII_SPEED_100;
1277                        break;
1278                case IFM_1000_T:
1279                        new |= MV643XX_ETH_SET_GMII_SPEED_1000;
1280                        break;
1281        }
1282
1283        if ( new != old ) {
1284                if ( ! (MV643XX_ETH_SERIAL_PORT_ENBL & new) ) {
1285                        /* just write */
1286                        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
1287                } else {
1288                        uint32_t were_running;
1289
1290                        were_running = mveth_stop_tx(port);
1291
1292                        old &= ~MV643XX_ETH_SERIAL_PORT_ENBL;
1293                        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), old);
1294                        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
1295                        /* linux driver writes twice... */
1296                        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
1297
1298                        if ( were_running ) {
1299                                MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
1300                        }
1301                }
1302        }
1303}
1304
1305/* Clear multicast filters                        */
1306void
1307BSP_mve_mcast_filter_clear(struct mveth_private *mp)
1308{
1309int                 i;
1310register uint32_t       s,o;
1311uint32_t            v = mp->promisc ? 0x01010101 : 0x00000000;
1312        s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
1313        o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
1314        for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
1315                MV_WRITE(s,v);
1316                MV_WRITE(o,v);
1317                s+=4;
1318                o+=4;
1319        }
1320        for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
1321                mp->mc_refcnt.specl[i] = 0;
1322                mp->mc_refcnt.other[i] = 0;
1323        }
1324}
1325
1326void
1327BSP_mve_mcast_filter_accept_all(struct mveth_private *mp)
1328{
1329int                 i;
1330register uint32_t       s,o;
1331        s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
1332        o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
1333        for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
1334                MV_WRITE(s,0x01010101);
1335                MV_WRITE(o,0x01010101);
1336                s+=4;
1337                o+=4;
1338                /* Not clear what we should do with the reference count.
1339                 * For now just increment it.
1340                 */
1341                for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
1342                        mp->mc_refcnt.specl[i]++;
1343                        mp->mc_refcnt.other[i]++;
1344                }
1345        }
1346}
1347
1348static void add_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
1349{
1350uint32_t val;
1351uint32_t slot = hash & 0xfc;
1352
1353        if ( 0 == (*refcnt)[hash]++ ) {
1354                val = MV_READ(off+slot) | ( 1 << ((hash&3)<<3) );
1355                MV_WRITE(off+slot, val);
1356        }
1357}
1358
1359static void del_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
1360{
1361uint32_t val;
1362uint32_t slot = hash & 0xfc;
1363
1364        if ( (*refcnt)[hash] > 0 && 0 == --(*refcnt)[hash] ) {
1365                val = MV_READ(off+slot) & ~( 1 << ((hash&3)<<3) );
1366                MV_WRITE(off+slot, val);
1367        }
1368}
1369
1370void
1371BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr)
1372{
1373uint32_t   hash;
1374static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
1375static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
1376uint32_t   tabl;
1377Mc_Refcnt  *refcnt;
1378
1379        if ( ! (0x01 & enaddr[0]) ) {
1380                /* not a multicast address; ignore */
1381                return;
1382        }
1383
1384        if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
1385                /* broadcast address; ignore */
1386                return;
1387        }
1388
1389        if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
1390                hash   = enaddr[5];
1391                tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
1392                refcnt = &mp->mc_refcnt.specl;
1393        } else {
1394                uint32_t test, mask;
1395                int      i;
1396                /* algorithm used by linux driver */
1397                for ( hash=0, i=0; i<6; i++ ) {
1398                        hash = (hash ^ enaddr[i]) << 8;
1399                        for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
1400                                if ( hash & test )
1401                                        hash ^= mask;
1402                        }
1403                }
1404                tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
1405                refcnt = &mp->mc_refcnt.other;
1406        }
1407        add_entry(tabl, hash, refcnt);
1408}
1409
1410void
1411BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr)
1412{
1413uint32_t   hash;
1414static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
1415static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
1416uint32_t   tabl;
1417Mc_Refcnt  *refcnt;
1418
1419        if ( ! (0x01 & enaddr[0]) ) {
1420                /* not a multicast address; ignore */
1421                return;
1422        }
1423
1424        if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
1425                /* broadcast address; ignore */
1426                return;
1427        }
1428
1429        if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
1430                hash   = enaddr[5];
1431                tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
1432                refcnt = &mp->mc_refcnt.specl;
1433        } else {
1434                uint32_t test, mask;
1435                int      i;
1436                /* algorithm used by linux driver */
1437                for ( hash=0, i=0; i<6; i++ ) {
1438                        hash = (hash ^ enaddr[i]) << 8;
1439                        for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) {
1440                                if ( hash & test )
1441                                        hash ^= mask;
1442                        }
1443                }
1444                tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
1445                refcnt = &mp->mc_refcnt.other;
1446        }
1447        del_entry(tabl, hash, refcnt);
1448}
1449
1450/* Clear all address filters (multi- and unicast) */
1451static void
1452mveth_clear_addr_filters(struct mveth_private *mp)
1453{
1454register int      i;
1455register uint32_t u;
1456        u = MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num);
1457        for (i=0; i<MV643XX_ETH_NUM_UNICAST_ENTRIES; i++) {
1458                MV_WRITE(u,0);
1459                u+=4;
1460        }
1461        BSP_mve_mcast_filter_clear(mp);
1462}
1463
1464/* Setup unicast filter for a given MAC address (least significant nibble) */
1465static void
1466mveth_ucfilter(struct mveth_private *mp, unsigned char mac_lsbyte, int accept)
1467{
1468unsigned nib, slot, bit;
1469uint32_t        val;
1470        /* compute slot in table */
1471        nib  = mac_lsbyte & 0xf;        /* strip nibble     */
1472        slot = nib & ~3;                        /* (nibble/4)*4     */
1473        bit  = (nib &  3)<<3;           /*  8*(nibble % 4)  */
1474        val = MV_READ(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot);
1475        if ( accept ) {
1476                val |= 0x01 << bit;
1477        } else {
1478                val &= 0x0e << bit;
1479        }
1480        MV_WRITE(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot, val);
1481}
1482
1483#if defined( ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM ) && 0
1484/* Currently unused; small unaligned buffers seem to be rare
1485 * so we just use memcpy()...
1486 */
1487
1488/* memcpy for 0..7 bytes; arranged so that gcc
1489 * optimizes for powerpc...
1490 */
1491
1492static inline void memcpy8(void *to, void *fr, unsigned x)
1493{
1494register uint8_t *d = to, *s = fro;
1495
1496        d+=l; s+=l;
1497        if ( l & 1 ) {
1498                *--d=*--s;
1499        }
1500        if ( l & 2 ) {
1501                /* pre-decrementing causes gcc to use auto-decrementing
1502                 * PPC instructions (lhzu rx, -2(ry))
1503                 */
1504                d-=2; s-=2;
1505                /* use memcpy; don't cast to short -- accessing
1506                 * misaligned data as short is not portable
1507                 * (but it works on PPC).
1508                 */
1509                __builtin_memcpy(d,s,2);
1510        }
1511        if ( l & 4 ) {
1512                d-=4; s-=4;
1513                /* see above */
1514                __builtin_memcpy(d,s,4);
1515        }
1516}
1517#endif
1518
1519/* Assign values (buffer + user data) to a tx descriptor slot */
1520static int
1521mveth_assign_desc(MvEthTxDesc d, struct mbuf *m, unsigned long extra)
1522{
1523int rval = (d->byte_cnt = m->m_len);
1524
1525#ifdef MVETH_TESTING
1526        assert( !d->mb      );
1527        assert(  m->m_len   );
1528#endif
1529
1530        /* set CRC on all descriptors; seems to be necessary */
1531        d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
1532
1533#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
1534        /* The buffer must be 64bit aligned if the payload is <8 (??) */
1535        if ( rval < 8 && ((mtod(m, uintptr_t)) & 7) ) {
1536                d->buf_ptr = CPUADDR2ENET( d->workaround );
1537                memcpy((void*)d->workaround, mtod(m, void*), rval);
1538        } else
1539#endif
1540        {
1541                d->buf_ptr  = CPUADDR2ENET( mtod(m, unsigned long) );
1542        }
1543        d->l4i_chk  = 0;
1544        return rval;
1545}
1546
1547static int
1548mveth_assign_desc_raw(MvEthTxDesc d, void *buf, int len, unsigned long extra)
1549{
1550int rval = (d->byte_cnt = len);
1551
1552#ifdef MVETH_TESTING
1553        assert( !d->u_buf );
1554        assert(  len   );
1555#endif
1556
1557        /* set CRC on all descriptors; seems to be necessary */
1558        d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
1559
1560#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
1561        /* The buffer must be 64bit aligned if the payload is <8 (??) */
1562        if ( rval < 8 && ( ((uintptr_t)buf) & 7) ) {
1563                d->buf_ptr = CPUADDR2ENET( d->workaround );
1564                memcpy((void*)d->workaround, buf, rval);
1565        } else
1566#endif
1567        {
1568                d->buf_ptr  = CPUADDR2ENET( (unsigned long)buf );
1569        }
1570        d->l4i_chk  = 0;
1571        return rval;
1572}
1573
1574/*
1575 * Ring Initialization
1576 *
1577 * ENDIAN ASSUMPTION: DMA engine matches CPU endianness (???)
1578 *
1579 * Linux driver discriminates __LITTLE and __BIG endian for re-arranging
1580 * the u16 fields in the descriptor structs. However, no endian conversion
1581 * is done on the individual fields (SDMA byte swapping is disabled on LE).
1582 */
1583
1584STATIC int
1585mveth_init_rx_desc_ring(struct mveth_private *mp)
1586{
1587int i,sz;
1588MvEthRxDesc     d;
1589uintptr_t baddr;
1590
1591        memset((void*)mp->rx_ring, 0, sizeof(*mp->rx_ring)*mp->rbuf_count);
1592
1593        mp->rx_desc_dma = CPUADDR2ENET(mp->rx_ring);
1594
1595        for ( i=0, d = mp->rx_ring; i<mp->rbuf_count; i++, d++ ) {
1596                d->u_buf = mp->alloc_rxbuf(&sz, &baddr);
1597                assert( d->u_buf );
1598
1599#ifndef ENABLE_HW_SNOOPING
1600                /* could reduce the area to max. ethernet packet size */
1601                INVAL_BUF(baddr, sz);
1602#endif
1603
1604                d->buf_size = sz;
1605                d->byte_cnt = 0;
1606                d->cmd_sts  = RDESC_DMA_OWNED | RDESC_INT_ENA;
1607                d->next         = mp->rx_ring + (i+1) % mp->rbuf_count;
1608
1609                d->buf_ptr  = CPUADDR2ENET( baddr );
1610                d->next_desc_ptr = CPUADDR2ENET(d->next);
1611                FLUSH_DESC(d);
1612        }
1613        FLUSH_BARRIER();
1614
1615        mp->d_rx_t = mp->rx_ring;
1616
1617        /* point the chip to the start of the ring */
1618        MV_WRITE(MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->rx_desc_dma);
1619
1620
1621        return i;
1622}
1623
1624STATIC int
1625mveth_init_tx_desc_ring(struct mveth_private *mp)
1626{
1627int i;
1628MvEthTxDesc d;
1629
1630        memset((void*)mp->tx_ring, 0, sizeof(*mp->tx_ring)*mp->xbuf_count);
1631
1632        /* DMA and CPU live in the same address space (rtems) */
1633        mp->tx_desc_dma = CPUADDR2ENET(mp->tx_ring);
1634        mp->avail       = TX_AVAILABLE_RING_SIZE(mp);
1635
1636        for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++,d++ ) {
1637                d->l4i_chk  = 0;
1638                d->byte_cnt = 0;
1639                d->cmd_sts  = 0;
1640                d->buf_ptr  = 0;
1641
1642                d->next     = mp->tx_ring + (i+1) % mp->xbuf_count;
1643                d->next_desc_ptr = CPUADDR2ENET(d->next);
1644                FLUSH_DESC(d);
1645        }
1646        FLUSH_BARRIER();
1647
1648        mp->d_tx_h = mp->d_tx_t = mp->tx_ring;
1649
1650        /* point the chip to the start of the ring */
1651        MV_WRITE(MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->tx_desc_dma);
1652
1653        return i;
1654}
1655
1656/* PUBLIC LOW-LEVEL DRIVER ACCESS */
1657
1658static struct mveth_private *
1659mve_setup_internal(
1660        int              unit,
1661        rtems_id tid,
1662        void     (*isr)(void*isr_arg),
1663        void     *isr_arg,
1664        void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
1665        void *cleanup_txbuf_arg,
1666        void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
1667        void (*consume_rxbuf)(void *user_buf, void *closure, int len),
1668        void *consume_rxbuf_arg,
1669        int             rx_ring_size,
1670        int             tx_ring_size,
1671        int             irq_mask
1672)
1673
1674{
1675struct mveth_private *mp;
1676struct ifnet         *ifp;
1677int                  InstallISRSuccessful;
1678
1679        if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
1680                printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
1681                return 0;
1682        }
1683        ifp = &theMvEths[unit-1].arpcom.ac_if;
1684        if ( ifp->if_init ) {
1685                if ( ifp->if_init ) {
1686                        printk(DRVNAME": instance %i already attached.\n", unit);
1687                        return 0;
1688                }
1689        }
1690
1691        if ( rx_ring_size < 0 && tx_ring_size < 0 )
1692                return 0;
1693
1694        if ( MV_64360 != BSP_getDiscoveryVersion(0) ) {
1695                printk(DRVNAME": not mv64360 chip\n");
1696                return 0;
1697        }
1698
1699        /* lazy init of mutex (non thread-safe! - we assume 1st initialization is single-threaded) */
1700        if ( ! mveth_mtx ) {
1701                rtems_status_code sc;
1702                sc = rtems_semaphore_create(
1703                                rtems_build_name('m','v','e','X'),
1704                                1,
1705                                RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES,
1706                                0,
1707                                &mveth_mtx);
1708                if ( RTEMS_SUCCESSFUL != sc ) {
1709                        rtems_error(sc,DRVNAME": creating mutex\n");
1710                        rtems_panic("unable to proceed\n");
1711                }
1712        }
1713
1714        mp = &theMvEths[unit-1].pvt;
1715
1716        memset(mp, 0, sizeof(*mp));
1717
1718        mp->port_num          = unit-1;
1719        mp->phy               = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*mp->port_num)) & 0x1f;
1720
1721        mp->tid               = tid;
1722        mp->isr               = isr;
1723        mp->isr_arg           = isr_arg;
1724
1725        mp->cleanup_txbuf     = cleanup_txbuf;
1726        mp->cleanup_txbuf_arg = cleanup_txbuf_arg;
1727        mp->alloc_rxbuf       = alloc_rxbuf;
1728        mp->consume_rxbuf     = consume_rxbuf;
1729        mp->consume_rxbuf_arg = consume_rxbuf_arg;
1730
1731        mp->rbuf_count = rx_ring_size ? rx_ring_size : MV643XX_RX_RING_SIZE;
1732        mp->xbuf_count = tx_ring_size ? tx_ring_size : MV643XX_TX_RING_SIZE;
1733
1734        if ( mp->xbuf_count > 0 )
1735                mp->xbuf_count += TX_NUM_TAG_SLOTS;
1736
1737        if ( mp->rbuf_count < 0 )
1738                mp->rbuf_count = 0;
1739        if ( mp->xbuf_count < 0 )
1740                mp->xbuf_count = 0;
1741
1742        /* allocate ring area; add 1 entry -- room for alignment */
1743        assert( !mp->ring_area );
1744        mp->ring_area = malloc(
1745                                                        sizeof(*mp->ring_area) *
1746                                                                (mp->rbuf_count + mp->xbuf_count + 1),
1747                                                        M_DEVBUF,
1748                                                        M_WAIT );
1749        assert( mp->ring_area );
1750
1751        BSP_mve_stop_hw(mp);
1752
1753        if ( irq_mask ) {
1754                irq_data[mp->port_num].hdl = tid ? mveth_isr : mveth_isr_1;     
1755                InstallISRSuccessful = BSP_install_rtems_irq_handler( &irq_data[mp->port_num] );
1756                assert( InstallISRSuccessful );
1757        }
1758
1759        /* mark as used */
1760        ifp->if_init = (void*)(-1);
1761
1762        if ( rx_ring_size < 0 )
1763                irq_mask &= ~ MV643XX_ETH_IRQ_RX_DONE;
1764        if ( tx_ring_size < 0 )
1765                irq_mask &= ~ MV643XX_ETH_EXT_IRQ_TX_DONE;
1766
1767        mp->irq_mask = (irq_mask & MV643XX_ETH_IRQ_RX_DONE);
1768        if ( (irq_mask &= (MV643XX_ETH_EXT_IRQ_TX_DONE | MV643XX_ETH_EXT_IRQ_LINK_CHG)) ) {
1769                mp->irq_mask |= MV643XX_ETH_IRQ_EXT_ENA;
1770                mp->xirq_mask = irq_mask;
1771        } else {
1772                mp->xirq_mask = 0;
1773        }
1774
1775        return mp;
1776}
1777
1778struct mveth_private *
1779BSP_mve_setup(
1780        int              unit,
1781        rtems_id tid,
1782        void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
1783        void *cleanup_txbuf_arg,
1784        void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
1785        void (*consume_rxbuf)(void *user_buf, void *closure, int len),
1786        void *consume_rxbuf_arg,
1787        int             rx_ring_size,
1788        int             tx_ring_size,
1789        int             irq_mask
1790)
1791{
1792        if ( irq_mask && 0 == tid ) {
1793                printk(DRVNAME": must supply a TID if irq_msk not zero\n");
1794                return 0;       
1795        }
1796
1797        return mve_setup_internal(
1798                                unit,
1799                                tid,
1800                                0, 0,
1801                                cleanup_txbuf, cleanup_txbuf_arg,
1802                                alloc_rxbuf,
1803                                consume_rxbuf, consume_rxbuf_arg,
1804                                rx_ring_size, tx_ring_size,
1805                                irq_mask);
1806}
1807
1808struct mveth_private *
1809BSP_mve_setup_1(
1810        int              unit,
1811        void     (*isr)(void *isr_arg),
1812        void     *isr_arg,
1813        void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), 
1814        void *cleanup_txbuf_arg,
1815        void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
1816        void (*consume_rxbuf)(void *user_buf, void *closure, int len),
1817        void *consume_rxbuf_arg,
1818        int             rx_ring_size,
1819        int             tx_ring_size,
1820        int             irq_mask
1821)
1822{
1823        if ( irq_mask && 0 == isr ) {
1824                printk(DRVNAME": must supply an ISR if irq_msk not zero\n");
1825                return 0;       
1826        }
1827
1828        return mve_setup_internal(
1829                                unit,
1830                                0,
1831                                isr, isr_arg,
1832                                cleanup_txbuf, cleanup_txbuf_arg,
1833                                alloc_rxbuf,
1834                                consume_rxbuf, consume_rxbuf_arg,
1835                                rx_ring_size, tx_ring_size,
1836                                irq_mask);
1837}
1838
1839rtems_id
1840BSP_mve_get_tid(struct mveth_private *mp)
1841{
1842    return mp->tid;
1843}
1844
1845int
1846BSP_mve_detach(struct mveth_private *mp)
1847{
1848int unit = mp->port_num;
1849        BSP_mve_stop_hw(mp);
1850        if ( mp->irq_mask || mp->xirq_mask ) {
1851                if ( !BSP_remove_rtems_irq_handler( &irq_data[mp->port_num] ) )
1852                        return -1;
1853        }
1854        free( (void*)mp->ring_area, M_DEVBUF );
1855        memset(mp, 0, sizeof(*mp));
1856        __asm__ __volatile__("":::"memory");
1857        /* mark as unused */
1858        theMvEths[unit].arpcom.ac_if.if_init = 0;
1859        return 0;
1860}
1861
1862/* MAIN RX-TX ROUTINES
1863 *
1864 * BSP_mve_swipe_tx():  descriptor scavenger; releases mbufs
1865 * BSP_mve_send_buf():  xfer mbufs from IF to chip
1866 * BSP_mve_swipe_rx():  enqueue received mbufs to interface
1867 *                    allocate new ones and yield them to the
1868 *                    chip.
1869 */
1870
1871/* clean up the TX ring freeing up buffers */
1872int
1873BSP_mve_swipe_tx(struct mveth_private *mp)
1874{
1875int                                             rval = 0;
1876register MvEthTxDesc    d;
1877
1878        for ( d = mp->d_tx_t; d->buf_ptr; d = NEXT_TXD(d) ) {
1879
1880                INVAL_DESC(d);
1881
1882                if (    (TDESC_DMA_OWNED & d->cmd_sts)
1883                         &&     (uint32_t)d == MV_READ(MV643XX_ETH_CURRENT_SERVED_TX_DESC(mp->port_num)) )
1884                        break;
1885
1886                /* d->u_buf is only set on the last descriptor in a chain;
1887                 * we only count errors in the last descriptor;
1888                 */
1889                if ( d->u_buf ) {
1890                        mp->cleanup_txbuf(d->u_buf, mp->cleanup_txbuf_arg, (d->cmd_sts & TDESC_ERROR) ? 1 : 0);
1891                        d->u_buf = 0;
1892                }
1893
1894                d->buf_ptr = 0;
1895
1896                rval++;
1897        }
1898        mp->d_tx_t = d;
1899        mp->avail += rval;
1900
1901        return rval;
1902}
1903
1904/* allocate a new cluster and copy an existing chain there;
1905 * old chain is released...
1906 */
1907static struct mbuf *
1908repackage_chain(struct mbuf *m_head)
1909{
1910struct mbuf *m;
1911        MGETHDR(m, M_DONTWAIT, MT_DATA);
1912
1913        if ( !m ) {
1914                goto bail;
1915        }
1916
1917        MCLGET(m, M_DONTWAIT);
1918
1919        if ( !(M_EXT & m->m_flags) ) {
1920                m_freem(m);
1921                m = 0;
1922                goto bail;
1923        }
1924
1925        m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t));
1926        m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len;
1927
1928bail:
1929        m_freem(m_head);
1930        return m;
1931}
1932
1933/* Enqueue a mbuf chain or a raw data buffer for transmission;
1934 * RETURN: #bytes sent or -1 if there are not enough descriptors
1935 *
1936 * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
1937 * OTOH, a raw data packet may be send (non-BSD driver) by pointing
1938 * m_head to the start of the data and passing 'len' > 0.
1939 *
1940 * Comments: software cache-flushing incurs a penalty if the
1941 *           packet cannot be queued since it is flushed anyways.
1942 *           The algorithm is slightly more efficient in the normal
1943 *                       case, though.
1944 */
1945int
1946BSP_mve_send_buf(struct mveth_private *mp, void *m_head, void *data_p, int len)
1947{
1948int                                             rval;
1949register MvEthTxDesc    l,d,h;
1950register struct mbuf    *m1;
1951int                                             nmbs;
1952int                                             ismbuf = (len <= 0);
1953
1954/* Only way to get here is when we discover that the mbuf chain
1955 * is too long for the tx ring
1956 */
1957startover:
1958
1959        rval = 0;
1960
1961#ifdef MVETH_TESTING
1962        assert(m_head);
1963#endif
1964
1965        /* if no descriptor is available; try to wipe the queue */
1966        if ( (mp->avail < 1) && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
1967                /* Maybe TX is stalled and needs to be restarted */
1968                mveth_start_tx(mp);
1969                return -1;
1970        }
1971
1972        h = mp->d_tx_h;
1973
1974#ifdef MVETH_TESTING
1975        assert( !h->buf_ptr );
1976        assert( !h->mb      );
1977#endif
1978
1979        if ( ! (m1 = m_head) )
1980                return 0;
1981
1982        if ( ismbuf ) {
1983                /* find first mbuf with actual data */
1984                while ( 0 == m1->m_len ) {
1985                        if ( ! (m1 = m1->m_next) ) {
1986                                /* end reached and still no data to send ?? */
1987                                m_freem(m_head);
1988                                return 0;
1989                        }
1990                }
1991        }
1992
1993        /* Don't use the first descriptor yet because BSP_mve_swipe_tx()
1994         * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
1995         * start with the second mbuf and fill the first descriptor
1996         * last.
1997         */
1998
1999        l = h;
2000        d = NEXT_TXD(h);
2001
2002        mp->avail--;
2003
2004        nmbs = 1;
2005        if ( ismbuf ) {
2006                        register struct mbuf *m;
2007                        for ( m=m1->m_next; m; m=m->m_next ) {
2008                                        if ( 0 == m->m_len )
2009                                                        continue;       /* skip empty mbufs */
2010
2011                                        nmbs++;
2012
2013                                        if ( mp->avail < 1 && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
2014                                                        /* Maybe TX was stalled - try to restart */
2015                                                        mveth_start_tx(mp);
2016
2017                                                        /* not enough descriptors; cleanup...
2018                                                         * the first slot was never used, so we start
2019                                                         * at mp->d_tx_h->next;
2020                                                         */
2021                                                        for ( l = NEXT_TXD(h); l!=d; l=NEXT_TXD(l) ) {
2022#ifdef MVETH_TESTING
2023                                                                        assert( l->mb == 0 );
2024#endif
2025                                                                        l->buf_ptr  = 0;
2026                                                                        l->cmd_sts  = 0;
2027                                                                        mp->avail++;
2028                                                        }
2029                                                        mp->avail++;
2030                                                        if ( nmbs > TX_AVAILABLE_RING_SIZE(mp) ) {
2031                                                                        /* this chain will never fit into the ring */
2032                                                                        if ( nmbs > mp->stats.maxchain )
2033                                                                                        mp->stats.maxchain = nmbs;
2034                                                                        mp->stats.repack++;
2035                                                                        if ( ! (m_head = repackage_chain(m_head)) ) {
2036                                                                                        /* no cluster available */
2037                                                                                        mp->stats.odrops++;
2038                                                                                        return 0;
2039                                                                        }
2040                                                                        goto startover;
2041                                                        }
2042                                                        return -1;
2043                                        }
2044
2045                                        mp->avail--;
2046
2047#ifdef MVETH_TESTING
2048                                        assert( d != h      );
2049                                        assert( !d->buf_ptr );
2050#endif
2051
2052                                        /* fill this slot */
2053                                        rval += mveth_assign_desc(d, m, TDESC_DMA_OWNED);
2054
2055                                        FLUSH_BUF(mtod(m, uint32_t), m->m_len);
2056
2057                                        l = d;
2058                                        d = NEXT_TXD(d);
2059
2060                                        FLUSH_DESC(l);
2061                        }
2062
2063                /* fill first slot - don't release to DMA yet */
2064                rval += mveth_assign_desc(h, m1, TDESC_FRST);
2065
2066
2067                FLUSH_BUF(mtod(m1, uint32_t), m1->m_len);
2068
2069        } else {
2070                /* fill first slot with raw buffer - don't release to DMA yet */
2071                rval += mveth_assign_desc_raw(h, data_p, len, TDESC_FRST);
2072
2073                FLUSH_BUF( (uint32_t)data_p, len);
2074        }
2075
2076        /* tag last slot; this covers the case where 1st==last */
2077        l->cmd_sts      |= TDESC_LAST | TDESC_INT_ENA;
2078        /* mbuf goes into last desc */
2079        l->u_buf         = m_head;
2080
2081
2082        FLUSH_DESC(l);
2083
2084        /* Tag end; make sure chip doesn't try to read ahead of here! */
2085        l->next->cmd_sts = 0;
2086        FLUSH_DESC(l->next);
2087
2088#ifdef MVETH_DEBUG_TX_DUMP
2089        if ( (mveth_tx_dump & (1<<mp->port_num)) ) {
2090                int ll,kk;
2091                if ( ismbuf ) {
2092                        struct mbuf *m;
2093                        for ( kk=0, m=m_head; m; m=m->m_next) {
2094                                for ( ll=0; ll<m->m_len; ll++ ) {
2095                                        printf("%02X ",*(mtod(m,char*) + ll));
2096                                        if ( ((++kk)&0xf) == 0 )
2097                                                printf("\n");
2098                                }
2099                        }
2100                } else {
2101                        for ( ll=0; ll<len; ) {
2102                                printf("%02X ",*((char*)data_p + ll));
2103                                if ( ((++ll)&0xf) == 0 )
2104                                        printf("\n");
2105                        }       
2106                }
2107                printf("\n");
2108        }
2109#endif
2110
2111        membarrier();
2112
2113        /* turn over the whole chain by flipping ownership of the first desc */
2114        h->cmd_sts |= TDESC_DMA_OWNED;
2115
2116        FLUSH_DESC(h);
2117
2118        membarrier();
2119
2120        /* notify the device */
2121        MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
2122
2123        /* Update softc */
2124        mp->stats.packet++;
2125        if ( nmbs > mp->stats.maxchain )
2126                mp->stats.maxchain = nmbs;
2127
2128        /* remember new head */
2129        mp->d_tx_h = d;
2130
2131        return rval; /* #bytes sent */
2132}
2133
2134int
2135BSP_mve_send_buf_raw(
2136        struct mveth_private *mp,
2137        void                 *head_p,
2138        int                   h_len,
2139        void                 *data_p,
2140    int                   d_len)
2141{
2142int                                             rval;
2143register MvEthTxDesc    l,d,h;
2144int                                             needed;
2145void                    *frst_buf;
2146int                     frst_len;
2147
2148        rval = 0;
2149
2150#ifdef MVETH_TESTING
2151        assert(header || data);
2152#endif
2153
2154        needed = head_p && data_p ? 2 : 1;
2155
2156        /* if no descriptor is available; try to wipe the queue */
2157        if (   ( mp->avail < needed )
2158        && ( MVETH_CLEAN_ON_SEND(mp) <= 0 || mp->avail < needed ) ) {
2159                /* Maybe TX was stalled and needs a restart */
2160                mveth_start_tx(mp);
2161                return -1;
2162        }
2163
2164        h = mp->d_tx_h;
2165
2166#ifdef MVETH_TESTING
2167        assert( !h->buf_ptr );
2168        assert( !h->mb      );
2169#endif
2170
2171        /* find the 'first' user buffer */
2172        if ( (frst_buf = head_p) ) {
2173                frst_len = h_len;
2174        } else {
2175                frst_buf = data_p;
2176                frst_len = d_len;
2177        }
2178
2179        /* Don't use the first descriptor yet because BSP_mve_swipe_tx()
2180         * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
2181         * start with the second (optional) slot and fill the first
2182     * descriptor last.
2183         */
2184
2185        l = h;
2186        d = NEXT_TXD(h);
2187
2188        mp->avail--;
2189
2190        if ( needed > 1 ) {
2191                mp->avail--;
2192#ifdef MVETH_TESTING
2193                assert( d != h      );
2194                assert( !d->buf_ptr );
2195#endif
2196                rval += mveth_assign_desc_raw(d, data_p, d_len, TDESC_DMA_OWNED);
2197                FLUSH_BUF( (uint32_t)data_p, d_len );
2198                d->u_buf = data_p;
2199
2200                l = d;
2201                d = NEXT_TXD(d);
2202
2203                FLUSH_DESC(l);
2204        }
2205
2206        /* fill first slot with raw buffer - don't release to DMA yet */
2207        rval       += mveth_assign_desc_raw(h, frst_buf, frst_len, TDESC_FRST);
2208
2209        FLUSH_BUF( (uint32_t)frst_buf, frst_len);
2210
2211        /* tag last slot; this covers the case where 1st==last */
2212        l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA;
2213
2214        /* first buffer of 'chain' goes into last desc */
2215        l->u_buf    = frst_buf;
2216
2217        FLUSH_DESC(l);
2218
2219        /* Tag end; make sure chip doesn't try to read ahead of here! */
2220        l->next->cmd_sts = 0;
2221        FLUSH_DESC(l->next);
2222
2223        membarrier();
2224
2225        /* turn over the whole chain by flipping ownership of the first desc */
2226        h->cmd_sts |= TDESC_DMA_OWNED;
2227
2228        FLUSH_DESC(h);
2229
2230        membarrier();
2231
2232        /* notify the device */
2233        MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0));
2234
2235        /* Update softc */
2236        mp->stats.packet++;
2237        if ( needed > mp->stats.maxchain )
2238                mp->stats.maxchain = needed;
2239
2240        /* remember new head */
2241        mp->d_tx_h = d;
2242
2243        return rval; /* #bytes sent */
2244}
2245
2246/* send received buffers upwards and replace them
2247 * with freshly allocated ones;
2248 * ASSUMPTION:  buffer length NEVER changes and is set
2249 *                              when the ring is initialized.
2250 * TS 20060727: not sure if this assumption is still necessary - I believe it isn't.
2251 */
2252
2253int
2254BSP_mve_swipe_rx(struct mveth_private *mp)
2255{
2256int                                             rval = 0, err;
2257register MvEthRxDesc    d;
2258void                                    *newbuf;
2259int                                             sz;
2260uintptr_t                               baddr;
2261
2262        for ( d = mp->d_rx_t; ! (INVAL_DESC(d), (RDESC_DMA_OWNED & d->cmd_sts)); d=NEXT_RXD(d) ) {
2263
2264#ifdef MVETH_TESTING
2265                assert(d->u_buf);
2266#endif
2267
2268                err = (RDESC_ERROR & d->cmd_sts);
2269
2270                if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) {
2271                        /* drop packet and recycle buffer */
2272                        newbuf = d->u_buf;
2273                        mp->consume_rxbuf(0, mp->consume_rxbuf_arg, err ? -1 : 0);
2274                } else {
2275#ifdef MVETH_TESTING
2276                        assert( d->byte_cnt > 0 );
2277#endif
2278                        mp->consume_rxbuf(d->u_buf, mp->consume_rxbuf_arg, d->byte_cnt);
2279
2280#ifndef ENABLE_HW_SNOOPING
2281                        /* could reduce the area to max. ethernet packet size */
2282                        INVAL_BUF(baddr, sz);
2283#endif
2284                        d->u_buf    = newbuf;
2285                        d->buf_ptr  = CPUADDR2ENET(baddr);
2286                        d->buf_size = sz;
2287                        FLUSH_DESC(d);
2288                }
2289
2290                membarrier();
2291
2292                d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA;
2293
2294                FLUSH_DESC(d);
2295
2296                rval++;
2297        }
2298        MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
2299        mp->d_rx_t = d;
2300        return rval;
2301}
2302
2303/* Stop hardware and clean out the rings */
2304void
2305BSP_mve_stop_hw(struct mveth_private *mp)
2306{
2307MvEthTxDesc     d;
2308MvEthRxDesc     r;
2309int                     i;
2310
2311        mveth_disable_irqs(mp, -1);
2312
2313        mveth_stop_tx(mp->port_num);
2314
2315        /* cleanup TX rings */
2316        if (mp->d_tx_t) { /* maybe ring isn't initialized yet */
2317                for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
2318                        /* should be safe to clear ownership */
2319                        d->cmd_sts &= ~TDESC_DMA_OWNED;
2320                        FLUSH_DESC(d);
2321                }
2322                FLUSH_BARRIER();
2323
2324                BSP_mve_swipe_tx(mp);
2325
2326#ifdef MVETH_TESTING
2327                assert( mp->d_tx_h == mp->d_tx_t );
2328                for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
2329                        assert( !d->buf_ptr );
2330                }
2331#endif
2332        }
2333
2334        MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_STOP_ALL);
2335        while ( MV643XX_ETH_RX_ANY_RUNNING & MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num)) )
2336                /* poll-wait */;
2337
2338        /* stop serial port */
2339        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
2340                MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num))
2341                & ~( MV643XX_ETH_SERIAL_PORT_ENBL | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE | MV643XX_ETH_FORCE_LINK_PASS)
2342                );
2343
2344        /* clear pending interrupts */
2345        MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
2346        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
2347
2348        /* cleanup RX rings */
2349        if ( mp->rx_ring ) {
2350                for ( i=0, r=mp->rx_ring; i<mp->rbuf_count; i++, r++ ) {
2351                        /* should be OK to clear ownership flag */
2352                        r->cmd_sts = 0;
2353                        FLUSH_DESC(r);
2354                        mp->consume_rxbuf(r->u_buf, mp->consume_rxbuf_arg, 0);
2355                        r->u_buf = 0;
2356                }
2357                FLUSH_BARRIER();
2358        }
2359
2360
2361}
2362
2363uint32_t mveth_serial_ctrl_config_val = MVETH_SERIAL_CTRL_CONFIG_VAL;
2364
2365/* Fire up the low-level driver
2366 *
2367 * - make sure hardware is halted
2368 * - enable cache snooping
2369 * - clear address filters
2370 * - clear mib counters
2371 * - reset phy
2372 * - initialize (or reinitialize) descriptor rings
2373 * - check that the firmware has set up a reasonable mac address.
2374 * - generate unicast filter entry for our mac address
2375 * - write register config values to the chip
2376 * - start hardware (serial port and SDMA)
2377 */
2378
2379void
2380BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr)
2381{
2382int                                     i;
2383uint32_t                        v;
2384static int                      inited = 0;
2385
2386#ifdef MVETH_DEBUG
2387        printk(DRVNAME"%i: Entering BSP_mve_init_hw()\n", mp->port_num+1);
2388#endif
2389
2390        /* since enable/disable IRQ routine only operate on select bitsets
2391         * we must make sure everything is masked initially.
2392         */
2393        MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        0);
2394        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), 0);
2395
2396        BSP_mve_stop_hw(mp);
2397
2398        memset(&mp->stats, 0, sizeof(mp->stats));
2399
2400        mp->promisc = promisc;
2401
2402        /* MotLoad has cache snooping disabled on the ENET2MEM windows.
2403         * Some comments in (linux) indicate that there are errata
2404         * which cause problems which would be a real bummer.
2405         * We try it anyways...
2406         */
2407        if ( !inited ) {
2408        unsigned long disbl, bar;
2409                inited = 1;     /* FIXME: non-thread safe lazy init */
2410                disbl = MV_READ(MV643XX_ETH_BAR_ENBL_R);
2411                        /* disable all 6 windows */
2412                        MV_WRITE(MV643XX_ETH_BAR_ENBL_R, MV643XX_ETH_BAR_DISBL_ALL);
2413                        /* set WB snooping on enabled bars */
2414                        for ( i=0; i<MV643XX_ETH_NUM_BARS*8; i+=8 ) {
2415                                if ( (bar = MV_READ(MV643XX_ETH_BAR_0 + i)) && MV_READ(MV643XX_ETH_SIZE_R_0 + i) ) {
2416#ifdef ENABLE_HW_SNOOPING
2417                                        MV_WRITE(MV643XX_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
2418#else
2419                                        MV_WRITE(MV643XX_ETH_BAR_0 + i, bar & ~MV64360_ENET2MEM_SNOOP_MSK);
2420#endif
2421                                        /* read back to flush fifo [linux comment] */
2422                                        (void)MV_READ(MV643XX_ETH_BAR_0 + i);
2423                                }
2424                        }
2425                        /* restore/re-enable */
2426                MV_WRITE(MV643XX_ETH_BAR_ENBL_R, disbl);
2427        }
2428
2429        mveth_clear_mib_counters(mp);
2430        mveth_clear_addr_filters(mp);
2431
2432/*      Just leave it alone...
2433        reset_phy();
2434*/
2435
2436        if ( mp->rbuf_count > 0 ) {
2437                mp->rx_ring = (MvEthRxDesc)MV643XX_ALIGN(mp->ring_area, RING_ALIGNMENT);
2438                mveth_init_rx_desc_ring(mp);
2439        }
2440
2441        if ( mp->xbuf_count > 0 ) {
2442                mp->tx_ring = (MvEthTxDesc)mp->rx_ring + mp->rbuf_count;
2443                mveth_init_tx_desc_ring(mp);
2444        }
2445
2446        if ( enaddr ) {
2447                /* set ethernet address from arpcom struct */
2448#ifdef MVETH_DEBUG
2449                printk(DRVNAME"%i: Writing MAC addr ", mp->port_num+1);
2450                for (i=5; i>=0; i--) {
2451                        printk("%02X%c", enaddr[i], i?':':'\n');
2452                }
2453#endif
2454                mveth_write_eaddr(mp, enaddr);
2455        }
2456
2457        /* set mac address and unicast filter */
2458
2459        {
2460        uint32_t machi, maclo;
2461                maclo = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
2462                machi = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
2463                /* ASSUME: firmware has set the mac address for us
2464                 *         - if assertion fails, we have to do more work...
2465                 */
2466                assert( maclo && machi && maclo != 0xffffffff && machi != 0xffffffff );
2467                mveth_ucfilter(mp, maclo&0xff, 1/* accept */);
2468        }
2469       
2470        /* port, serial and sdma configuration */
2471        v = MVETH_PORT_CONFIG_VAL;
2472        if ( promisc ) {
2473                /* multicast filters were already set up to
2474                 * accept everything (mveth_clear_addr_filters())
2475                 */
2476                v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
2477        } else {
2478                v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
2479        }
2480        MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num),
2481                                v);
2482        MV_WRITE(MV643XX_ETH_PORT_CONFIG_XTEND_R(mp->port_num),
2483                                MVETH_PORT_XTEND_CONFIG_VAL);
2484
2485        v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
2486        v &= ~(MVETH_SERIAL_CTRL_CONFIG_MSK);
2487        v |= mveth_serial_ctrl_config_val;
2488        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), v);
2489
2490        i = IFM_MAKEWORD(0, 0, 0, 0);
2491        if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &i) ) {
2492            if ( (IFM_LINK_OK & i) ) {
2493                        mveth_update_serial_port(mp, i);
2494                }
2495        }
2496
2497        /* enable serial port */
2498        v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
2499        MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
2500                                v | MV643XX_ETH_SERIAL_PORT_ENBL);
2501
2502#ifndef __BIG_ENDIAN__
2503#error  "byte swapping needs to be disabled for little endian machines"
2504#endif
2505        MV_WRITE(MV643XX_ETH_SDMA_CONFIG_R(mp->port_num), MVETH_SDMA_CONFIG_VAL);
2506
2507        /* allow short frames */
2508        MV_WRITE(MV643XX_ETH_RX_MIN_FRAME_SIZE_R(mp->port_num), MVETH_MIN_FRAMSZ_CONFIG_VAL);
2509
2510        MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
2511        MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
2512        /* TODO: set irq coalescing */
2513
2514        /* enable Rx */
2515        if ( mp->rbuf_count > 0 ) {
2516                MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0));
2517        }
2518
2519        mveth_enable_irqs(mp, -1);
2520
2521#ifdef MVETH_DEBUG
2522        printk(DRVNAME"%i: Leaving BSP_mve_init_hw()\n", mp->port_num+1);
2523#endif
2524}
2525
2526/* read ethernet address from hw to buffer */
2527void
2528BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr)
2529{
2530int                             i;
2531uint32_t                x;
2532unsigned char   buf[6], *eaddr;
2533
2534        eaddr = oeaddr ? oeaddr : buf;
2535
2536        eaddr += 5;
2537        x = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
2538
2539        /* lo word */
2540        for (i=2; i; i--, eaddr--) {
2541                *eaddr = (unsigned char)(x & 0xff);
2542                x>>=8;
2543        }
2544
2545        x = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
2546        /* hi word */
2547        for (i=4; i; i--, eaddr--) {
2548                *eaddr = (unsigned char)(x & 0xff);
2549                x>>=8;
2550        }
2551
2552        if ( !oeaddr ) {
2553                printf("%02X",buf[0]);
2554                for (i=1; i<sizeof(buf); i++)
2555                        printf(":%02X",buf[i]);
2556                printf("\n");
2557        }
2558}
2559
2560int
2561BSP_mve_media_ioctl(struct mveth_private *mp, int cmd, int *parg)
2562{
2563int rval;
2564        /* alias cmd == 0,1 */
2565        switch ( cmd ) {
2566                case 0: cmd = SIOCGIFMEDIA;
2567                        break;
2568                case 1: cmd = SIOCSIFMEDIA;
2569                case SIOCGIFMEDIA:
2570                case SIOCSIFMEDIA:
2571                        break;
2572                default: return -1;
2573        }
2574        REGLOCK();
2575        rval = rtems_mii_ioctl(&mveth_mdio, mp, cmd, parg);
2576        REGUNLOCK();
2577        return rval;
2578}
2579
2580void
2581BSP_mve_enable_irqs(struct mveth_private *mp)
2582{
2583        mveth_enable_irqs(mp, -1);
2584}
2585
2586void
2587BSP_mve_disable_irqs(struct mveth_private *mp)
2588{
2589        mveth_disable_irqs(mp, -1);
2590}
2591
2592uint32_t
2593BSP_mve_ack_irqs(struct mveth_private *mp)
2594{
2595        return mveth_ack_irqs(mp, -1);
2596}
2597
2598
2599void
2600BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t mask)
2601{
2602        mveth_enable_irqs(mp, mask);
2603}
2604
2605uint32_t
2606BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t mask)
2607{
2608        return mveth_disable_irqs(mp, mask);
2609}
2610
2611uint32_t
2612BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask)
2613{
2614        return mveth_ack_irqs(mp, mask);
2615}
2616
2617int
2618BSP_mve_ack_link_chg(struct mveth_private *mp, int *pmedia)
2619{
2620int media = IFM_MAKEWORD(0,0,0,0);
2621
2622        if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &media)) {
2623                if ( IFM_LINK_OK & media ) {
2624                        mveth_update_serial_port(mp, media);
2625                        /* If TX stalled because there was no buffer then whack it */
2626                        mveth_start_tx(mp);
2627                }
2628                if ( pmedia )
2629                        *pmedia = media;
2630                return 0;
2631        }
2632        return -1;
2633}
2634
2635/* BSDNET SUPPORT/GLUE ROUTINES */
2636
2637static void
2638mveth_set_filters(struct ifnet *ifp);
2639
2640STATIC void
2641mveth_stop(struct mveth_softc *sc)
2642{
2643        BSP_mve_stop_hw(&sc->pvt);
2644        sc->arpcom.ac_if.if_timer = 0;
2645}
2646
2647/* allocate a mbuf for RX with a properly aligned data buffer
2648 * RETURNS 0 if allocation fails
2649 */
2650static void *
2651alloc_mbuf_rx(int *psz, uintptr_t *paddr)
2652{
2653struct mbuf             *m;
2654unsigned long   l,o;
2655
2656        MGETHDR(m, M_DONTWAIT, MT_DATA);
2657        if ( !m )
2658                return 0;
2659        MCLGET(m, M_DONTWAIT);
2660        if ( ! (m->m_flags & M_EXT) ) {
2661                m_freem(m);
2662                return 0;
2663        }
2664
2665        o = mtod(m, unsigned long);
2666        l = MV643XX_ALIGN(o, RX_BUF_ALIGNMENT) - o;
2667
2668        /* align start of buffer */
2669        m->m_data += l;
2670
2671        /* reduced length */
2672        l = MCLBYTES - l;
2673
2674        m->m_len   = m->m_pkthdr.len = l;
2675        *psz       = m->m_len;
2676        *paddr     = mtod(m, uintptr_t); 
2677
2678        return (void*) m;
2679}
2680
2681static void consume_rx_mbuf(void *buf, void *arg, int len)
2682{
2683struct ifnet *ifp = arg;
2684struct mbuf    *m = buf;
2685
2686        if ( len <= 0 ) {
2687                ifp->if_iqdrops++;
2688                if ( len < 0 ) {
2689                        ifp->if_ierrors++;
2690                }
2691                if ( m )
2692                        m_freem(m);
2693        } else {
2694                struct ether_header *eh;
2695
2696                        eh                      = (struct ether_header *)(mtod(m, unsigned long) + ETH_RX_OFFSET);
2697                        m->m_len        = m->m_pkthdr.len = len - sizeof(struct ether_header) - ETH_RX_OFFSET - ETH_CRC_LEN;
2698                        m->m_data  += sizeof(struct ether_header) + ETH_RX_OFFSET;
2699                        m->m_pkthdr.rcvif = ifp;
2700
2701                        ifp->if_ipackets++;
2702                        ifp->if_ibytes  += m->m_pkthdr.len;
2703                       
2704                        if (0) {
2705                                /* Low-level debugging */
2706                                int i;
2707                                for (i=0; i<13; i++) {
2708                                        printf("%02X:",((char*)eh)[i]);
2709                                }
2710                                printf("%02X\n",((char*)eh)[i]);
2711                                for (i=0; i<m->m_len; i++) {
2712                                        if ( !(i&15) )
2713                                                printf("\n");
2714                                        printf("0x%02x ",mtod(m,char*)[i]);
2715                                }
2716                                printf("\n");
2717                        }
2718
2719                        if (0) {
2720                                /* Low-level debugging/testing without bsd stack */
2721                                m_freem(m);
2722                        } else {
2723                                /* send buffer upwards */
2724                                ether_input(ifp, eh, m);
2725                        }
2726        }
2727}
2728
2729static void release_tx_mbuf(void *buf, void *arg, int err)
2730{
2731struct ifnet *ifp = arg;
2732struct mbuf  *mb  = buf;
2733
2734        if ( err ) {
2735                ifp->if_oerrors++;
2736        } else {
2737                ifp->if_opackets++;
2738        }
2739        ifp->if_obytes += mb->m_pkthdr.len;
2740        m_freem(mb);
2741}
2742
2743static void
2744dump_update_stats(struct mveth_private *mp, FILE *f)
2745{
2746int      p = mp->port_num;
2747int      idx;
2748uint32_t v;
2749
2750        if ( !f )
2751                f = stdout;
2752
2753        fprintf(f, DRVNAME"%i Statistics:\n",        mp->port_num + 1);
2754        fprintf(f, "  # IRQS:                 %i\n", mp->stats.irqs);
2755        fprintf(f, "  Max. mbuf chain length: %i\n", mp->stats.maxchain);
2756        fprintf(f, "  # repacketed:           %i\n", mp->stats.repack);
2757        fprintf(f, "  # packets:              %i\n", mp->stats.packet);
2758        fprintf(f, "MIB Counters:\n");
2759        for ( idx = MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2;
2760                        idx < MV643XX_ETH_NUM_MIB_COUNTERS;
2761                        idx++ ) {
2762                switch ( idx ) {
2763                        case MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2:
2764                                mp->stats.mib.good_octs_rcvd += read_long_mib_counter(p, idx);
2765                                fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_rcvd);
2766                                idx++;
2767                                break;
2768
2769                        case MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO>>2:
2770                                mp->stats.mib.good_octs_sent += read_long_mib_counter(p, idx);
2771                                fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_sent);
2772                                idx++;
2773                                break;
2774
2775                        default:
2776                                v = ((uint32_t*)&mp->stats.mib)[idx] += read_mib_counter(p, idx);
2777                                fprintf(f, mibfmt[idx], v);
2778                                break;
2779                }
2780        }
2781        fprintf(f, "\n");
2782}
2783
2784void
2785BSP_mve_dump_stats(struct mveth_private *mp, FILE *f)
2786{
2787        dump_update_stats(mp, f);
2788}
2789
2790/* BSDNET DRIVER CALLBACKS */
2791
2792static void
2793mveth_init(void *arg)
2794{
2795struct mveth_softc      *sc  = arg;
2796struct ifnet            *ifp = &sc->arpcom.ac_if;
2797int                 media;
2798
2799        BSP_mve_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr);
2800
2801        media = IFM_MAKEWORD(0, 0, 0, 0);
2802        if ( 0 == BSP_mve_media_ioctl(&sc->pvt, SIOCGIFMEDIA, &media) ) {
2803            if ( (IFM_LINK_OK & media) ) {
2804                        ifp->if_flags &= ~IFF_OACTIVE;
2805                } else {
2806                        ifp->if_flags |= IFF_OACTIVE;
2807                }
2808        }
2809
2810        /* if promiscuous then there is no need to change */
2811        if ( ! (ifp->if_flags & IFF_PROMISC) )
2812                mveth_set_filters(ifp);
2813
2814        ifp->if_flags |= IFF_RUNNING;
2815        sc->arpcom.ac_if.if_timer = 0;
2816}
2817
2818/* bsdnet driver entry to start transmission */
2819static void
2820mveth_start(struct ifnet *ifp)
2821{
2822struct mveth_softc      *sc = ifp->if_softc;
2823struct mbuf                     *= 0;
2824
2825        while ( ifp->if_snd.ifq_head ) {
2826                IF_DEQUEUE( &ifp->if_snd, m );
2827                if ( BSP_mve_send_buf(&sc->pvt, m, 0, 0) < 0 ) {
2828                        IF_PREPEND( &ifp->if_snd, m);
2829                        ifp->if_flags |= IFF_OACTIVE;
2830                        break;
2831                }
2832                /* need to do this really only once
2833                 * but it's cheaper this way.
2834                 */
2835                ifp->if_timer = 2*IFNET_SLOWHZ;
2836        }
2837}
2838
2839/* bsdnet driver entry; */
2840static void
2841mveth_watchdog(struct ifnet *ifp)
2842{
2843struct mveth_softc      *sc = ifp->if_softc;
2844
2845        ifp->if_oerrors++;
2846        printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit);
2847
2848        mveth_init(sc);
2849        mveth_start(ifp);
2850}
2851
2852static void
2853mveth_set_filters(struct ifnet *ifp)
2854{
2855struct mveth_softc  *sc = ifp->if_softc;
2856uint32_t              v;
2857
2858        v = MV_READ(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num));
2859        if ( ifp->if_flags & IFF_PROMISC )
2860                v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
2861        else
2862                v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
2863        MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num), v);
2864
2865        if ( ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI) ) {
2866                BSP_mve_mcast_filter_accept_all(&sc->pvt);
2867        } else {
2868                struct ether_multi     *enm;
2869                struct ether_multistep step;
2870
2871                BSP_mve_mcast_filter_clear( &sc->pvt );
2872               
2873                ETHER_FIRST_MULTI(step, (struct arpcom *)ifp, enm);
2874
2875                while ( enm ) {
2876                        if ( memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) )
2877                                assert( !"Should never get here; IFF_ALLMULTI should be set!" );
2878
2879                        BSP_mve_mcast_filter_accept_add(&sc->pvt, enm->enm_addrlo);
2880
2881                        ETHER_NEXT_MULTI(step, enm);
2882                }
2883        }
2884}
2885
2886/* bsdnet driver ioctl entry */
2887static int
2888mveth_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
2889{
2890struct mveth_softc      *sc   = ifp->if_softc;
2891struct ifreq            *ifr  = (struct ifreq *)data;
2892int                                     error = 0;
2893int                                     f;
2894
2895        switch ( cmd ) {
2896                case SIOCSIFFLAGS:
2897                        f = ifp->if_flags;
2898                        if ( f & IFF_UP ) {
2899                                if ( ! ( f & IFF_RUNNING ) ) {
2900                                        mveth_init(sc);
2901                                } else {
2902                                        if ( (f & IFF_PROMISC) != (sc->bsd.oif_flags & IFF_PROMISC) ) {
2903                                                /* Note: in all other scenarios the 'promisc' flag
2904                                                 * in the low-level driver [which affects the way
2905                                                 * the multicast filter is setup: accept none vs.
2906                                                 * accept all in promisc mode] is eventually
2907                                                 * set when the IF is brought up...
2908                                                 */
2909                                                sc->pvt.promisc = (f & IFF_PROMISC);
2910
2911                                                mveth_set_filters(ifp);
2912                                        }
2913                                        /* FIXME: other flag changes are ignored/unimplemented */
2914                                }
2915                        } else {
2916                                if ( f & IFF_RUNNING ) {
2917                                        mveth_stop(sc);
2918                                        ifp->if_flags  &= ~(IFF_RUNNING | IFF_OACTIVE);
2919                                }
2920                        }
2921                        sc->bsd.oif_flags = ifp->if_flags;
2922                break;
2923
2924                case SIOCGIFMEDIA:
2925                case SIOCSIFMEDIA:
2926                        error = BSP_mve_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media);
2927                break;
2928 
2929                case SIOCADDMULTI:
2930                case SIOCDELMULTI:
2931                        error = (cmd == SIOCADDMULTI)
2932                                ? ether_addmulti(ifr, &sc->arpcom)
2933                                    : ether_delmulti(ifr, &sc->arpcom);
2934
2935                        if (error == ENETRESET) {
2936                                if (ifp->if_flags & IFF_RUNNING) {
2937                                        mveth_set_filters(ifp);
2938                                }
2939                                error = 0;
2940                        }
2941                break;
2942
2943
2944                break;
2945
2946                case SIO_RTEMS_SHOW_STATS:
2947                        dump_update_stats(&sc->pvt, stdout);
2948                break;
2949
2950                default:
2951                        error = ether_ioctl(ifp, cmd, data);
2952                break;
2953        }
2954
2955        return error;
2956}
2957
2958/* DRIVER TASK */
2959
2960/* Daemon task does all the 'interrupt' work */
2961static void mveth_daemon(void *arg)
2962{
2963struct mveth_softc      *sc;
2964struct ifnet            *ifp;
2965rtems_event_set         evs;
2966        for (;;) {
2967                rtems_bsdnet_event_receive( 7, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs );
2968                evs &= 7;
2969                for ( sc = theMvEths; evs; evs>>=1, sc++ ) {
2970                        if ( (evs & 1) ) {
2971                                register uint32_t x;
2972
2973                                ifp = &sc->arpcom.ac_if;
2974
2975                                if ( !(ifp->if_flags & IFF_UP) ) {
2976                                        mveth_stop(sc);
2977                                        ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
2978                                        continue;
2979                                }
2980
2981                                if ( !(ifp->if_flags & IFF_RUNNING) ) {
2982                                        /* event could have been pending at the time hw was stopped;
2983                                         * just ignore...
2984                                         */
2985                                        continue;
2986                                }
2987
2988                                x = mveth_ack_irqs(&sc->pvt, -1);
2989
2990                                if ( MV643XX_ETH_EXT_IRQ_LINK_CHG & x ) {
2991                                        /* phy status changed */
2992                                        int media;
2993
2994                                        if ( 0 == BSP_mve_ack_link_chg(&sc->pvt, &media) ) {
2995                                                if ( IFM_LINK_OK & media ) {
2996                                                        ifp->if_flags &= ~IFF_OACTIVE;
2997                                                        mveth_start(ifp);
2998                                                } else {
2999                                                        /* stop sending */
3000                                                        ifp->if_flags |= IFF_OACTIVE;
3001                                                }
3002                                        }
3003                                }
3004                                /* free tx chain */
3005                                if ( (MV643XX_ETH_EXT_IRQ_TX_DONE & x) && BSP_mve_swipe_tx(&sc->pvt) ) {
3006                                        ifp->if_flags &= ~IFF_OACTIVE;
3007                                        if ( TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.avail )
3008                                                ifp->if_timer = 0;
3009                                        mveth_start(ifp);
3010                                }
3011                                if ( (MV643XX_ETH_IRQ_RX_DONE & x) )
3012                                        BSP_mve_swipe_rx(&sc->pvt);
3013
3014                                mveth_enable_irqs(&sc->pvt, -1);
3015                        }
3016                }
3017        }
3018}
3019
3020#ifdef  MVETH_DETACH_HACK
3021static int mveth_detach(struct mveth_softc *sc);
3022#endif
3023
3024
3025/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
3026int
3027rtems_mve_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
3028{
3029char                            *unitName;
3030int                                     unit,i,cfgUnits;
3031struct  mveth_softc *sc;
3032struct  ifnet           *ifp;
3033
3034        unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
3035        if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
3036                printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS);
3037                return 1;
3038        }
3039
3040        sc  = &theMvEths[unit-1];
3041        ifp = &sc->arpcom.ac_if;
3042        sc->pvt.port_num = unit-1;
3043        sc->pvt.phy      = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*sc->pvt.port_num)) & 0x1f;
3044
3045        if ( attaching ) {
3046                if ( ifp->if_init ) {
3047                        printk(DRVNAME": instance %i already attached.\n", unit);
3048                        return -1;
3049                }
3050
3051                for ( i=cfgUnits = 0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
3052                        if ( theMvEths[i].arpcom.ac_if.if_init )
3053                                cfgUnits++;
3054                }
3055                cfgUnits++; /* this new one */
3056
3057                /* lazy init of TID should still be thread-safe because we are protected
3058                 * by the global networking semaphore..
3059                 */
3060                if ( !mveth_tid ) {
3061                        /* newproc uses the 1st 4 chars of name string to build an rtems name */
3062                        mveth_tid = rtems_bsdnet_newproc("MVEd", 4096, mveth_daemon, 0);
3063                }
3064
3065                if ( !BSP_mve_setup( unit,
3066                                                     mveth_tid,
3067                                                     release_tx_mbuf, ifp,
3068                                                     alloc_mbuf_rx,
3069                                                     consume_rx_mbuf, ifp,
3070                                                     ifcfg->rbuf_count,
3071                                                     ifcfg->xbuf_count,
3072                                         BSP_MVE_IRQ_TX | BSP_MVE_IRQ_RX | BSP_MVE_IRQ_LINK) ) {
3073                        return -1;
3074                }
3075
3076                if ( nmbclusters < sc->pvt.rbuf_count * cfgUnits + 60 /* arbitrary */ )  {
3077                        printk(DRVNAME"%i: (mv643xx ethernet) Your application has not enough mbuf clusters\n", unit);
3078                        printk(     "                         configured for this driver.\n");
3079                        return -1;
3080                }
3081
3082                if ( ifcfg->hardware_address ) {
3083                        memcpy(sc->arpcom.ac_enaddr, ifcfg->hardware_address, ETHER_ADDR_LEN);
3084                } else {
3085                        /* read back from hardware assuming that MotLoad already had set it up */
3086                        BSP_mve_read_eaddr(&sc->pvt, sc->arpcom.ac_enaddr);
3087                }
3088
3089                ifp->if_softc                   = sc;
3090                ifp->if_unit                    = unit;
3091                ifp->if_name                    = unitName;
3092
3093                ifp->if_mtu                             = ifcfg->mtu ? ifcfg->mtu : ETHERMTU;
3094
3095                ifp->if_init                    = mveth_init;
3096                ifp->if_ioctl                   = mveth_ioctl;
3097                ifp->if_start                   = mveth_start;
3098                ifp->if_output                  = ether_output;
3099                /*
3100                 * While nonzero, the 'if->if_timer' is decremented
3101                 * (by the networking code) at a rate of IFNET_SLOWHZ (1hz) and 'if_watchdog'
3102                 * is called when it expires.
3103                 * If either of those fields is 0 the feature is disabled.
3104                 */
3105                ifp->if_watchdog                = mveth_watchdog;
3106                ifp->if_timer                   = 0;
3107
3108                sc->bsd.oif_flags               = /* ... */
3109                ifp->if_flags                   = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
3110
3111                /*
3112                 * if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack;
3113                 * could be updated along with phy speed, though...
3114                ifp->if_baudrate                = 10000000;
3115                */
3116
3117                /* NOTE: ether_output drops packets if ifq_len >= ifq_maxlen
3118                 *       but this is the packet count, not the fragment count!
3119                ifp->if_snd.ifq_maxlen  = sc->pvt.xbuf_count;
3120                */
3121                ifp->if_snd.ifq_maxlen  = ifqmaxlen;
3122
3123#ifdef  MVETH_DETACH_HACK
3124                if ( !ifp->if_addrlist ) /* do only the first time [reattach hack] */
3125#endif
3126                {
3127                        if_attach(ifp);
3128                        ether_ifattach(ifp);
3129                }
3130
3131        } else {
3132#ifdef  MVETH_DETACH_HACK
3133                if ( !ifp->if_init ) {
3134                        printk(DRVNAME": instance %i not attached.\n", unit);
3135                        return -1;
3136                }
3137                return mveth_detach(sc);
3138#else
3139                printk(DRVNAME": interface detaching not implemented\n");
3140                return -1;
3141#endif
3142        }
3143
3144        return 0;
3145}
3146
3147/* EARLY PHY ACCESS */
3148static int
3149mveth_early_init(int idx)
3150{
3151        if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
3152                return -1;
3153
3154        /* determine the phy */
3155        theMvEths[idx].pvt.phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*idx)) & 0x1f;
3156        return 0;
3157}
3158
3159static int
3160mveth_early_read_phy(int idx, unsigned reg)
3161{
3162int rval;
3163
3164        if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
3165                return -1;
3166
3167        rval = mveth_mii_read(&theMvEths[idx].pvt, reg);
3168        return rval < 0 ? rval : rval & 0xffff;
3169}
3170
3171static int
3172mveth_early_write_phy(int idx, unsigned reg, unsigned val)
3173{
3174        if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
3175                return -1;
3176
3177        mveth_mii_write(&theMvEths[idx].pvt, reg, val);
3178        return 0;
3179}
3180
3181rtems_bsdnet_early_link_check_ops
3182rtems_mve_early_link_check_ops = {
3183        init:           mveth_early_init,
3184        read_phy:       mveth_early_read_phy,
3185        write_phy:      mveth_early_write_phy,
3186        name:           DRVNAME,
3187        num_slots:      MAX_NUM_SLOTS
3188};
3189
3190/* DEBUGGING */
3191
3192#ifdef MVETH_DEBUG
3193/* Display/dump descriptor rings */
3194
3195int
3196mveth_dring(struct mveth_softc *sc)
3197{
3198int i;
3199if (1) {
3200MvEthRxDesc pr;
3201printf("RX:\n");
3202
3203        for (i=0, pr=sc->pvt.rx_ring; i<sc->pvt.rbuf_count; i++, pr++) {
3204#ifndef ENABLE_HW_SNOOPING
3205                /* can't just invalidate the descriptor - if it contains
3206                 * data that hasn't been flushed yet, we create an inconsistency...
3207                 */
3208                rtems_bsdnet_semaphore_obtain();
3209                INVAL_DESC(pr);
3210#endif
3211                printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
3212                        pr->byte_cnt, pr->buf_size, pr->cmd_sts, (uint32_t)pr->next_desc_ptr, pr->buf_ptr);
3213
3214#ifndef ENABLE_HW_SNOOPING
3215                rtems_bsdnet_semaphore_release();
3216#endif
3217        }
3218}
3219if (1) {
3220MvEthTxDesc pt;
3221printf("TX:\n");
3222        for (i=0, pt=sc->pvt.tx_ring; i<sc->pvt.xbuf_count; i++, pt++) {
3223#ifndef ENABLE_HW_SNOOPING
3224                rtems_bsdnet_semaphore_obtain();
3225                INVAL_DESC(pt);
3226#endif
3227                printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x, mb: 0x%08x\n",
3228                        pt->byte_cnt, pt->cmd_sts, (uint32_t)pt->next_desc_ptr, pt->buf_ptr,
3229                        (uint32_t)pt->mb);
3230
3231#ifndef ENABLE_HW_SNOOPING
3232                rtems_bsdnet_semaphore_release();
3233#endif
3234        }
3235}
3236        return 0;
3237}
3238
3239#endif
3240
3241/* DETACH HACK DETAILS */
3242
3243#ifdef  MVETH_DETACH_HACK
3244int
3245_cexpModuleFinalize(void *mh)
3246{
3247int i;
3248        for ( i=0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
3249                if ( theMvEths[i].arpcom.ac_if.if_init ) {
3250                        printf("Interface %i still attached; refuse to unload\n", i+1);
3251                        return -1;
3252                }
3253        }
3254        /* delete task; since there are no attached interfaces, it should block
3255         * for events and hence not hold the semaphore or other resources...
3256         */
3257        rtems_task_delete(mveth_tid);
3258        return 0;
3259}
3260
3261/* ugly hack to allow unloading/reloading the driver core.
3262 * needed because rtems' bsdnet release doesn't implement
3263 * if_detach(). Therefore, we bring the interface down but
3264 * keep the device record alive...
3265 */
3266static void
3267ether_ifdetach_pvt(struct ifnet *ifp)
3268{
3269        ifp->if_flags = 0;
3270        ifp->if_ioctl = 0;
3271        ifp->if_start = 0;
3272        ifp->if_watchdog = 0;
3273        ifp->if_init  = 0;
3274}
3275
3276static int
3277mveth_detach(struct mveth_softc *sc)
3278{
3279struct ifnet    *ifp = &sc->arpcom.ac_if;
3280        if ( ifp->if_init ) {
3281                if ( ifp->if_flags & (IFF_UP | IFF_RUNNING) ) {
3282                        printf(DRVNAME"%i: refuse to detach; interface still up\n",sc->pvt.port_num+1);
3283                        return -1;
3284                }
3285                mveth_stop(sc);
3286/* not implemented in BSDnet/RTEMS (yet) but declared in header */
3287#define ether_ifdetach ether_ifdetach_pvt
3288                ether_ifdetach(ifp);
3289        }
3290        free( (void*)sc->pvt.ring_area, M_DEVBUF );
3291        sc->pvt.ring_area = 0;
3292        sc->pvt.tx_ring   = 0;
3293        sc->pvt.rx_ring   = 0;
3294        sc->pvt.d_tx_t    = sc->pvt.d_tx_h   = 0;
3295        sc->pvt.d_rx_t    = 0;
3296        sc->pvt.avail     = 0;
3297        /* may fail if ISR was not installed yet */
3298        BSP_remove_rtems_irq_handler( &irq_data[sc->pvt.port_num] );
3299        return 0;
3300}
3301
3302#ifdef MVETH_DEBUG
3303struct rtems_bsdnet_ifconfig mveth_dbg_config = {
3304        name:                           DRVNAME"1",
3305        attach:                         rtems_mve_attach,
3306        ip_address:                     "192.168.2.10",         /* not used by rtems_bsdnet_attach */
3307        ip_netmask:                     "255.255.255.0",        /* not used by rtems_bsdnet_attach */
3308        hardware_address:       0, /* (void *) */
3309        ignore_broadcast:       0,                                      /* TODO driver should honour this  */
3310        mtu:                            0,
3311        rbuf_count:                     0,                                      /* TODO driver should honour this  */
3312        xbuf_count:                     0,                                      /* TODO driver should honour this  */
3313};
3314#endif
3315#endif
Note: See TracBrowser for help on using the repository browser.