[PATCH rtems-net-legacy] powerpc/beatnik: Add mv643xx_eth.c driver from RTEMS 5

Chris Johns chrisj at rtems.org
Wed Jul 19 02:10:38 UTC 2023


Looks good.

On 19/7/2023 5:30 am, Joel Sherrill wrote:
> I'm ok with this.
> 
> Is there anything documentation-ish that needs updating? README? User Guide info
> on the BSP? 
> 
> --joel
> 
> On Tue, Jul 18, 2023 at 10:37 AM Vijay Kumar Banerjee <vijay at rtems.org
> <mailto:vijay at rtems.org>> wrote:
> 
>     ---
>      bsp_drivers.py                                |    2 +
>      bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c | 3318 +++++++++++++++++
>      2 files changed, 3320 insertions(+)
>      create mode 100644 bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c
> 
>     diff --git a/bsp_drivers.py b/bsp_drivers.py
>     index e2250aa..5628ff3 100644
>     --- a/bsp_drivers.py
>     +++ b/bsp_drivers.py
>     @@ -79,6 +79,7 @@ include = {
>              'bsps/powerpc/beatnik/net',
>              'bsps/powerpc/beatnik/net/if_em',
>              'bsps/powerpc/beatnik/net/if_gfe',
>     +        'bsps/powerpc/beatnik/net/if_mve',
>              'bsps/powerpc/beatnik/net/porting',
>          ],
>          'powerpc/mpc8260ads': [
>     @@ -174,6 +175,7 @@ source = {
>              'bsps/powerpc/beatnik/net/if_em/if_em_rtems.c',
>              'bsps/powerpc/beatnik/net/if_gfe/if_gfe.c',
>              'bsps/powerpc/beatnik/net/if_gfe/if_gfe_rtems.c',
>     +        'bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c',
>              'bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c',
>              'bsps/powerpc/beatnik/net/support/bsp_attach.c',
>              'bsps/powerpc/beatnik/net/support/early_link_status.c',
>     diff --git a/bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c
>     b/bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c
>     new file mode 100644
>     index 0000000..85ab038
>     --- /dev/null
>     +++ b/bsps/powerpc/beatnik/net/if_mve/mv643xx_eth.c
>     @@ -0,0 +1,3318 @@
>     +/* RTEMS driver for the mv643xx gigabit ethernet chip */
>     +
>     +/* Acknowledgement:
>     + *
>     + * Valuable information for developing this driver was obtained
>     + * from the linux open-source driver mv643xx_eth.c which was written
>     + * by the following people and organizations:
>     + *
>     + * Matthew Dharm <mdharm at momenco.com <mailto:mdharm at momenco.com>>
>     + * rabeeh at galileo.co.il <mailto:rabeeh at galileo.co.il>
>     + * PMC-Sierra, Inc., Manish Lachwani
>     + * Ralf Baechle <ralf at linux-mips.org <mailto:ralf at linux-mips.org>>
>     + * MontaVista Software, Inc., Dale Farnsworth <dale at farnsworth.org
>     <mailto:dale at farnsworth.org>>
>     + * Steven J. Hill <sjhill1 at rockwellcollins.com
>     <mailto:sjhill1 at rockwellcollins.com>>/<sjhill at realitydiluted.com
>     <mailto:sjhill at realitydiluted.com>>
>     + *
>     + * Note however, that in spite of the identical name of this file
>     + * (and some of the symbols used herein) this file provides a
>     + * new implementation and is the original work by the author.
>     + */
>     +
>     +/*
>     + * Authorship
>     + * ----------
>     + * This software (mv643xx ethernet driver for RTEMS) was
>     + *     created by Till Straumann <strauman at slac.stanford.edu
>     <mailto:strauman at slac.stanford.edu>>, 2005-2007,
>     + *        Stanford Linear Accelerator Center, Stanford University.
>     + *
>     + * Acknowledgement of sponsorship
>     + * ------------------------------
>     + * The 'mv643xx ethernet driver for RTEMS' was produced by
>     + *     the Stanford Linear Accelerator Center, Stanford University,
>     + *        under Contract DE-AC03-76SFO0515 with the Department of Energy.
>     + *
>     + * Government disclaimer of liability
>     + * ----------------------------------
>     + * Neither the United States nor the United States Department of Energy,
>     + * nor any of their employees, makes any warranty, express or implied, or
>     + * assumes any legal liability or responsibility for the accuracy,
>     + * completeness, or usefulness of any data, apparatus, product, or process
>     + * disclosed, or represents that its use would not infringe privately owned
>     + * rights.
>     + *
>     + * Stanford disclaimer of liability
>     + * --------------------------------
>     + * Stanford University makes no representations or warranties, express or
>     + * implied, nor assumes any liability for the use of this software.
>     + *
>     + * Stanford disclaimer of copyright
>     + * --------------------------------
>     + * Stanford University, owner of the copyright, hereby disclaims its
>     + * copyright and all other rights in this software.  Hence, anyone may
>     + * freely use it for any purpose without restriction. 
>     + *
>     + * Maintenance of notices
>     + * ----------------------
>     + * In the interest of clarity regarding the origin and status of this
>     + * SLAC software, this and all the preceding Stanford University notices
>     + * are to remain affixed to any copy or derivative of this software made
>     + * or distributed by the recipient and are to be affixed to any copy of
>     + * software made or distributed by the recipient that contains a copy or
>     + * derivative of this software.
>     + *
>     + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
>     + */
>     +
>     +/*
>     + * NOTE: Some register (e.g., the SMI register) are SHARED among the
>     + *       three devices. Concurrent access protection is provided by
>     + *       the global networking semaphore.
>     + *       If other drivers are running on a subset of IFs then proper
>     + *       locking of all shared registers must be implemented!
>     + *
>     + *       Some things I learned about this hardware can be found
>     + *       further down...
>     + */
>     +
>     +#ifndef KERNEL
>     +#define KERNEL
>     +#endif
>     +#ifndef _KERNEL
>     +#define _KERNEL
>     +#endif
>     +
>     +#include <rtems.h>
>     +#include <rtems/bspIo.h>
>     +#include <rtems/error.h>
>     +#include <bsp.h>
>     +#include <bsp/irq.h>
>     +#include <bsp/gtreg.h>
>     +#include <libcpu/byteorder.h>
>     +
>     +#include <sys/param.h>
>     +#include <sys/proc.h>
>     +#include <sys/socket.h>
>     +#include <sys/sockio.h>
>     +#include <dev/mii/mii.h>
>     +#include <net/if_var.h>
>     +#include <net/if_media.h>
>     +
>     +/* Not so nice; would be more elegant not to depend on C library but the
>     + * RTEMS-specific ioctl for dumping statistics needs stdio anyways.
>     + */
>     +
>     +/*#define NDEBUG effectively removes all assertions
>     + * If defining NDEBUG, MAKE SURE assert() EXPRESSION HAVE NO SIDE_EFFECTS!!
>     + * This driver DOES have side-effects, so DONT DEFINE NDEBUG
>     + * Performance-critical assertions are removed by undefining MVETH_TESTING.
>     + */
>     +
>     +#undef NDEBUG
>     +#include <assert.h>
>     +#include <stdio.h>
>     +#include <errno.h>
>     +#include <inttypes.h>
>     +
>     +#include <rtems/rtems_bsdnet.h>
>     +#include <sys/param.h>
>     +#include <sys/mbuf.h>
>     +#include <sys/socket.h>
>     +#include <sys/sockio.h>
>     +#include <net/ethernet.h>
>     +#include <net/if.h>
>     +#include <netinet/in.h>
>     +#include <netinet/if_ether.h>
>     +
>     +#include <rtems/rtems_mii_ioctl.h>
>     +#include <bsp/early_enet_link_status.h>
>     +#include <bsp/if_mve_pub.h>
>     +
>     +/* CONFIGURABLE PARAMETERS */
>     +
>     +/* Enable Hardware Snooping; if this is disabled (undefined),
>     + * cache coherency is maintained by software.
>     + */
>     +#undef  ENABLE_HW_SNOOPING
>     +
>     +/* Compile-time debugging features */
>     +
>     +/* Enable paranoia assertions and checks; reduce # of descriptors to
>     minimum for stressing   */
>     +#undef  MVETH_TESTING
>     +
>     +/* Enable debugging messages and some support routines  (dump rings etc.) 
>                       */     
>     +#undef  MVETH_DEBUG
>     +
>     +/* Hack for driver development; rtems bsdnet doesn't implement detaching an
>     interface :-(
>     + * but this hack allows us to unload/reload the driver module which makes
>     development
>     + * a lot less painful.
>     + */
>     +#undef MVETH_DETACH_HACK
>     +
>     +/* Ring sizes */
>     +
>     +#ifdef MVETH_TESTING
>     +
>     +/* hard and small defaults */
>     +#undef  MV643XX_RX_RING_SIZE
>     +#define MV643XX_RX_RING_SIZE   2
>     +#undef  MV643XX_TX_RING_SIZE
>     +#define MV643XX_TX_RING_SIZE   4
>     +
>     +#else /* MVETH_TESTING */
>     +
>     +/* Define default ring sizes, allow override from bsp.h, Makefile,... and
>     from ifcfg->rbuf_count/xbuf_count */
>     +
>     +#ifndef MV643XX_RX_RING_SIZE
>     +#define MV643XX_RX_RING_SIZE   40      /* attached buffers are always 2k
>     clusters, i.e., this
>     +                                                                        *
>     driver - with a configured ring size of 40 - constantly
>     +                                                                        *
>     locks 80k of cluster memory - your app config better
>     +                                                                        *
>     provides enough space!
>     +                                                                        */
>     +#endif
>     +
>     +#ifndef MV643XX_TX_RING_SIZE
>     +/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain;
>     + *       in 'TESTING' mode, special code is compiled in to repackage
>     + *              chains that are longer than the ring size. Normally, this is
>     + *              disabled for sake of speed.
>     + *              I observed chains of >17 entries regularly!
>     + *
>     + *       Also, TX_NUM_TAG_SLOTS (1) must be left empty as a marker, hence
>     + *       the ring size must be > max. #frags + 1.
>     + */
>     +#define MV643XX_TX_RING_SIZE   200     /* these are smaller fragments and
>     not occupied when
>     +                                                                        *
>     the driver is idle.
>     +                                                                        */
>     +#endif
>     +
>     +#endif /* MVETH_TESTING */
>     +
>     +/* How many instances to we support (bsp.h could override) */
>     +#ifndef MV643XXETH_NUM_DRIVER_SLOTS
>     +#define MV643XXETH_NUM_DRIVER_SLOTS    2
>     +#endif
>     +
>     +#define TX_NUM_TAG_SLOTS                       1 /* leave room for tag;
>     must not be 0 */
>     +
>     +/* This is REAL; chip reads from 64-bit down-aligned buffer
>     + * if the buffer size is < 8 !!! for buffer sizes 8 and upwards
>     + * alignment is not an issue. This was verified using the
>     + * 'mve_smallbuf_test.c'
>     + */
>     +#define ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
>     +
>     +/* Chip register configuration values */
>     +#define        MVETH_PORT_CONFIG_VAL                   (0                 
>                 \
>     +                       | MV643XX_ETH_DFLT_RX_Q(0)                         
>                 \
>     +                       | MV643XX_ETH_DFLT_RX_ARP_Q(0)                     
>         \
>     +                       | MV643XX_ETH_DFLT_RX_TCP_Q(0)                     
>         \
>     +                       | MV643XX_ETH_DFLT_RX_UDP_Q(0)                     
>         \
>     +                       | MV643XX_ETH_DFLT_RX_BPDU_Q(0)                     
>        \
>     +                       )
>     +
>     +
>     +#define        MVETH_PORT_XTEND_CONFIG_VAL             0
>     +
>     +#ifdef OLDCONFIGVAL
>     +#define        MVETH_SERIAL_CTRL_CONFIG_VAL    (0                         
>         \
>     +                        | MV643XX_ETH_FORCE_LINK_PASS                     
>         \
>     +                        | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL     \
>     +                        | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL      \
>     +                        | MV643XX_ETH_BIT9_UNKNOWN                         
>                \
>     +                        | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE          \
>     +                        | MV643XX_ETH_SC_MAX_RX_1552                       
>        \
>     +                        | MV643XX_ETH_SET_FULL_DUPLEX                     
>         \
>     +                        | MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD         \
>     +                        )
>     +#endif
>     +/* If we enable autoneg (duplex, speed, ...) then it seems
>     + * that the chip automatically updates link settings
>     + * (correct link settings are reflected in PORT_STATUS_R).
>     + * However, when we disable aneg in the PHY then things
>     + * can get messed up and the port doesn't work anymore.
>     + * => we follow the linux driver in disabling all aneg
>     + * in the serial config reg. and manually updating the
>     + * speed & duplex bits when the phy link status changes.
>     + * FIXME: don't know what to do about pause/flow-ctrl.
>     + * It is best to just use ANEG anyways!!!
>     + */
>     +#define        MVETH_SERIAL_CTRL_CONFIG_VAL    (0                         
>         \
>     +                        | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX      \
>     +                        | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL     \
>     +                        | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL      \
>     +                        | MV643XX_ETH_BIT9_UNKNOWN                         
>                \
>     +                        | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE          \
>     +                        | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII      \
>     +                        | MV643XX_ETH_SC_MAX_RX_1552                       
>        \
>     +                        )
>     +
>     +#define        MVETH_SERIAL_CTRL_CONFIG_MSK    (0                         
>         \
>     +                        | MV643XX_ETH_SERIAL_PORT_ENBL                     
>        \
>     +                        | MV643XX_ETH_FORCE_LINK_PASS                     
>         \
>     +                        | MV643XX_ETH_SC_MAX_RX_MASK                       
>        \
>     +                        )
>     +
>     +
>     +#ifdef __PPC__
>     +#define MVETH_SDMA_CONFIG_VAL                  (0                         
>         \
>     +                       | MV643XX_ETH_RX_BURST_SZ_4_64BIT                   
>        \
>     +                       | MV643XX_ETH_TX_BURST_SZ_4_64BIT                   
>        \
>     +                       )
>     +#else
>     +#define MVETH_SDMA_CONFIG_VAL                  (0                         
>         \
>     +                       | MV643XX_ETH_RX_BURST_SZ_16_64BIT                 
>         \
>     +                       | MV643XX_ETH_TX_BURST_SZ_16_64BIT                 
>         \
>     +                       )
>     +#endif
>     +
>     +/* minimal frame size we accept */
>     +#define MVETH_MIN_FRAMSZ_CONFIG_VAL    40
>     +
>     +/* END OF CONFIGURABLE SECTION */
>     +
>     +/*
>     + * Here's stuff I learned about this chip:
>     + *
>     + *
>     + * RX interrupt flags:
>     + *
>     + * broadcast packet RX: 0x00000005
>     + *           last buf:  0x00000c05
>     + *           overrun:   0x00000c00           
>     + * unicast   packet RX: 0x00000005
>     + * bad CRC received:    0x00000005
>     + *
>     + * clearing 0x00000004 -> clears 0x00000001
>     + * clearing 0x00000400 -> clears 0x00000800
>     + *
>     + * --> 0x0801 are probably some sort of summary bits.
>     + *
>     + * TX interrupt flags:
>     + *
>     + * broadcast packet in 1 buf: xcause: 0x00000001 (cause 0x00080000)
>     + *        into disconn. link:             "                 "
>     + *
>     + * in some cases, I observed  xcause: 0x00000101 (reason for 0x100 unknown
>     + * but the linux driver accepts it also).
>     + *
>     + *
>     + * Here a few more ugly things about this piece of hardware I learned
>     + * (painfully, painfully; spending many many hours & nights :-()
>     + *
>     + * a) Especially in the case of 'chained' descriptors, the DMA keeps
>     + *    clobbering 'cmd_sts' long after it cleared the OWNership flag!!!
>     + *    Only after the whole chain is processed (OWN cleared on the
>     + *    last descriptor) it is safe to change cmd_sts.
>     + *    However, in the case of hardware snooping I found that the
>     + *    last descriptor in chain has its cmd_sts still clobbered *after*
>     + *    checking ownership!, I.e.,
>     + *        if ( ! OWN & cmd_sts ) {
>     + *            cmd_sts = 0;
>     + *        }
>     + *    --> sometimes, cmd_sts is STILL != 0 here
>     + *
>     + * b) Sometimes, the OWNership flag is *not cleared*. 
>     + *
>     + * c) Weird things happen if the chip finds a descriptor with 'OWN'
>     + *    still set (i.e., not properly loaded), i.e., corrupted packets
>     + *    are sent [with OK checksum since the chip calculates it].
>     + *
>     + * Combine a+b+c and we end up with a real mess.
>     + *
>     + * The fact that the chip doesn't reliably reset OWN and that OTOH,
>     + * it can't be reliably reset by the driver and still, the chip needs
>     + * it for proper communication doesn't make things easy...
>     + *
>     + * Here the basic workarounds:
>     + *
>     + *     - In addition to check OWN, the scavenger compares the "currently
>     + *       served desc" register to the descriptor it tries to recover and
>     + *       ignores OWN if they do not match. Hope this is OK.
>     + *       Otherwise, we could scan the list of used descriptors and proceed
>     + *       recycling descriptors if we find a !OWNed one behind the target...
>     + *
>     + *     - Always keep an empty slot around to mark the end of the list of
>     + *       jobs. The driver clears the descriptor ahead when enqueueing a new
>     + *       packet.
>     + */
>     +
>     +#define DRVNAME                        "mve"
>     +#define MAX_NUM_SLOTS  3
>     +
>     +#if MV643XXETH_NUM_DRIVER_SLOTS > MAX_NUM_SLOTS
>     +#error "mv643xxeth: only MAX_NUM_SLOTS supported"
>     +#endif
>     +
>     +#ifdef NDEBUG
>     +#error "Driver uses assert() statements with side-effects; MUST NOT define
>     NDEBUG"
>     +#endif
>     +
>     +#ifdef MVETH_DEBUG
>     +#define STATIC
>     +#else
>     +#define STATIC static
>     +#endif
>     +
>     +#define TX_AVAILABLE_RING_SIZE(mp)             ((mp)->xbuf_count -
>     (TX_NUM_TAG_SLOTS))
>     +
>     +/* macros for ring alignment; proper alignment is a hardware req; . */
>     +
>     +#ifdef ENABLE_HW_SNOOPING
>     +
>     +#define RING_ALIGNMENT                         16
>     +/* rx buffers must be 64-bit aligned (chip requirement) */
>     +#define RX_BUF_ALIGNMENT                       8
>     +
>     +#else /* ENABLE_HW_SNOOPING */
>     +
>     +/* Software cache management */
>     +
>     +#ifndef __PPC__
>     +#error "Dont' know how to deal with cache on this CPU architecture"
>     +#endif
>     +
>     +/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software
>     coherency
>     + * management works for cache line sizes of 16 and 32 bytes only. If the
>     line size
>     + * is bigger, the descriptors could be padded...
>     + */
>     +#if    PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
>     +#error "Cache line size must be 16 or 32"
>     +#else
>     +#define RING_ALIGNMENT                         PPC_CACHE_ALIGNMENT
>     +#define RX_BUF_ALIGNMENT                       PPC_CACHE_ALIGNMENT
>     +#endif
>     +
>     +#endif /* ENABLE_HW_SNOOPING */
>     +
>     +
>     +/* HELPER MACROS */
>     +
>     +/* Align base to alignment 'a' */
>     +#define MV643XX_ALIGN(b, a)    ((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
>     +
>     +#define NOOP()                 do {} while(0)
>     +
>     +/* Function like macros */
>     +#define MV_READ(off) \
>     +               ld_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)))
>     +#define MV_WRITE(off, data)            \
>     +               st_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)),
>     ((unsigned)data))
>     +
>     +
>     +/* ENET window mapped 1:1 to CPU addresses by our BSP/MotLoad
>     + * -- if this is changed, we should think about caching the 'next' and
>     'buf' pointers.
>     + */
>     +#define CPUADDR2ENET(a) ((Dma_addr_t)(a))
>     +#define ENET2CPUADDR(a) (a)
>     +
>     +#if 1  /* Whether to automatically try to reclaim descriptors when
>     enqueueing new packets */
>     +#define MVETH_CLEAN_ON_SEND(mp) (BSP_mve_swipe_tx(mp))
>     +#else
>     +#define MVETH_CLEAN_ON_SEND(mp) (-1)
>     +#endif
>     +
>     +#define NEXT_TXD(d)    (d)->next
>     +#define NEXT_RXD(d)    (d)->next
>     +
>     +/* REGISTER AND DESCRIPTOR OFFSET AND BIT DEFINITIONS */
>     +
>     +/* Descriptor Definitions */
>     +/* Rx descriptor */
>     +#define RDESC_ERROR                                                       
>                 (1<< 0) /* Error summary    */
>     +
>     +/* Error code (bit 1&2) is only valid if summary bit is set */
>     +#define RDESC_CRC_ERROR                                                   
>                 (    1)
>     +#define RDESC_OVERRUN_ERROR                                               
>         (    3)
>     +#define RDESC_MAX_FRAMELENGTH_ERROR                                    (    5)
>     +#define RDESC_RESOURCE_ERROR                                           (    7)
>     +
>     +#define RDESC_LAST                                                         
>                (1<<26) /* Last Descriptor   */
>     +#define RDESC_FRST                                                         
>                (1<<27) /* First Descriptor  */
>     +#define RDESC_INT_ENA                                                     
>         (1<<29) /* Enable Interrupts */
>     +#define RDESC_DMA_OWNED                                                   
>                 (1<<31)
>     +
>     +/* Tx descriptor */
>     +#define TDESC_ERROR                                                       
>                 (1<< 0) /* Error summary     */
>     +#define TDESC_ZERO_PAD                                                     
>        (1<<19)
>     +#define TDESC_LAST                                                         
>                (1<<20) /* Last Descriptor   */
>     +#define TDESC_FRST                                                         
>                (1<<21) /* First Descriptor  */
>     +#define TDESC_GEN_CRC                                                     
>         (1<<22)
>     +#define TDESC_INT_ENA                                                     
>         (1<<23) /* Enable Interrupts */
>     +#define TDESC_DMA_OWNED                                                   
>                 (1<<31)
>     +
>     +
>     +
>     +/* Register Definitions */
>     +#define MV643XX_ETH_PHY_ADDR_R                                         (0x2000)
>     +#define MV643XX_ETH_SMI_R                                                 
>         (0x2004)
>     +#define MV643XX_ETH_SMI_BUSY                                           (1<<28)
>     +#define MV643XX_ETH_SMI_VALID                                          (1<<27)
>     +#define MV643XX_ETH_SMI_OP_WR                                          (0<<26)
>     +#define MV643XX_ETH_SMI_OP_RD                                          (1<<26)
>     +
>     +#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)     (0x2448 + ((port)<<10))
>     +#define MV643XX_ETH_TX_START(queue)                                   
>     (0x0001<<(queue))
>     +#define MV643XX_ETH_TX_STOP(queue)                                   
>      (0x0100<<(queue))
>     +#define MV643XX_ETH_TX_START_M(queues)                         ((queues)&0xff)
>     +#define MV643XX_ETH_TX_STOP_M(queues)                         
>     (((queues)&0xff)<<8)
>     +#define MV643XX_ETH_TX_STOP_ALL                                           
>         (0xff00)
>     +#define MV643XX_ETH_TX_ANY_RUNNING                                     (0x00ff)
>     +
>     +#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(port)      (0x2680 + ((port)<<10))
>     +#define MV643XX_ETH_RX_START(queue)                                   
>     (0x0001<<(queue))
>     +#define MV643XX_ETH_RX_STOP(queue)                                   
>      (0x0100<<(queue))
>     +#define MV643XX_ETH_RX_STOP_ALL                                           
>         (0xff00)
>     +#define MV643XX_ETH_RX_ANY_RUNNING                                     (0x00ff)
>     +
>     +#define MV643XX_ETH_CURRENT_SERVED_TX_DESC(port)       (0x2684 + ((port)<<10))
>     +
>     +/* The chip puts the ethernet header at offset 2 into the buffer so
>     + * that the payload is aligned
>     + */
>     +#define ETH_RX_OFFSET                                                     
>         2
>     +#define ETH_CRC_LEN                                                       
>                 4       /* strip FCS at end of packet */
>     +
>     +
>     +#define MV643XX_ETH_INTERRUPT_CAUSE_R(port)                    (0x2460 +
>     ((port)<<10))
>     +/* not fully understood; RX seems to raise 0x0005 or 0x0c05 if last buffer
>     is filled and 0x0c00
>     + * if there are no buffers
>     + */
>     +#define MV643XX_ETH_ALL_IRQS                                         
>      (0x0007ffff)
>     +#define MV643XX_ETH_KNOWN_IRQS                                       
>      (0x00000c05)
>     +#define MV643XX_ETH_IRQ_EXT_ENA                                           
>         (1<<1)
>     +#define MV643XX_ETH_IRQ_RX_DONE                                           
>         (1<<2)
>     +#define MV643XX_ETH_IRQ_RX_NO_DESC                                     (1<<10)
>     +
>     +#define MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(port)     (0x2464 + ((port)<<10))
>     +/* not fully understood; TX seems to raise 0x0001 and link change is 0x00010000
>     + * if there are no buffers
>     + */
>     +#define MV643XX_ETH_ALL_EXT_IRQS                                     
>      (0x0011ffff)
>     +#define MV643XX_ETH_KNOWN_EXT_IRQS                                   
>      (0x00010101)
>     +#define MV643XX_ETH_EXT_IRQ_TX_DONE                                    (1<<0)
>     +#define MV643XX_ETH_EXT_IRQ_LINK_CHG                           (1<<16)
>     +#define MV643XX_ETH_INTERRUPT_ENBL_R(port)                     (0x2468 +
>     ((port)<<10))
>     +#define MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(port)      (0x246c + ((port)<<10))
>     +
>     +/* port configuration */
>     +#define MV643XX_ETH_PORT_CONFIG_R(port)                               
>     (0x2400 + ((port)<<10))
>     +#define        MV643XX_ETH_UNICAST_PROMISC_MODE                        (1<<0)
>     +#define        MV643XX_ETH_DFLT_RX_Q(q)                                   
>         ((q)<<1)
>     +#define        MV643XX_ETH_DFLT_RX_ARP_Q(q)                            ((q)<<4)
>     +#define MV643XX_ETH_REJ_BCAST_IF_NOT_IP_OR_ARP         (1<<7)
>     +#define MV643XX_ETH_REJ_BCAST_IF_IP                                    (1<<8)
>     +#define MV643XX_ETH_REJ_BCAST_IF_ARP                           (1<<9)
>     +#define MV643XX_ETH_TX_AM_NO_UPDATE_ERR_SUMMARY                (1<<12)
>     +#define MV643XX_ETH_CAPTURE_TCP_FRAMES_ENBL                    (1<<14)
>     +#define MV643XX_ETH_CAPTURE_UDP_FRAMES_ENBL                    (1<<15)
>     +#define        MV643XX_ETH_DFLT_RX_TCP_Q(q)                           
>     ((q)<<16)
>     +#define        MV643XX_ETH_DFLT_RX_UDP_Q(q)                           
>     ((q)<<19)
>     +#define        MV643XX_ETH_DFLT_RX_BPDU_Q(q)                         
>      ((q)<<22)
>     +
>     +
>     +
>     +#define MV643XX_ETH_PORT_CONFIG_XTEND_R(port)          (0x2404 + ((port)<<10))
>     +#define MV643XX_ETH_CLASSIFY_ENBL                                      (1<<0)
>     +#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL                (0<<1)
>     +#define MV643XX_ETH_SPAN_BPDU_PACKETS_2_Q7                     (1<<1)
>     +#define MV643XX_ETH_PARTITION_DISBL                                    (0<<2)
>     +#define MV643XX_ETH_PARTITION_ENBL                                     (1<<2)
>     +
>     +#define MV643XX_ETH_SDMA_CONFIG_R(port)                               
>     (0x241c + ((port)<<10))
>     +#define MV643XX_ETH_SDMA_RIFB                                          (1<<0)
>     +#define MV643XX_ETH_RX_BURST_SZ_1_64BIT                                (0<<1)
>     +#define MV643XX_ETH_RX_BURST_SZ_2_64BIT                                (1<<1)
>     +#define MV643XX_ETH_RX_BURST_SZ_4_64BIT                                (2<<1)
>     +#define MV643XX_ETH_RX_BURST_SZ_8_64BIT                                (3<<1)
>     +#define MV643XX_ETH_RX_BURST_SZ_16_64BIT                       (4<<1)
>     +#define MV643XX_ETH_SMDA_BLM_RX_NO_SWAP                                (1<<4)
>     +#define MV643XX_ETH_SMDA_BLM_TX_NO_SWAP                                (1<<5)
>     +#define MV643XX_ETH_SMDA_DESC_BYTE_SWAP                                (1<<6)
>     +#define MV643XX_ETH_TX_BURST_SZ_1_64BIT                                (0<<22)
>     +#define MV643XX_ETH_TX_BURST_SZ_2_64BIT                                (1<<22)
>     +#define MV643XX_ETH_TX_BURST_SZ_4_64BIT                                (2<<22)
>     +#define MV643XX_ETH_TX_BURST_SZ_8_64BIT                                (3<<22)
>     +#define MV643XX_ETH_TX_BURST_SZ_16_64BIT                       (4<<22)
>     +
>     +#define        MV643XX_ETH_RX_MIN_FRAME_SIZE_R(port)           (0x247c +
>     ((port)<<10))
>     +
>     +
>     +#define MV643XX_ETH_SERIAL_CONTROL_R(port)                     (0x243c +
>     ((port)<<10))
>     +#define MV643XX_ETH_SERIAL_PORT_ENBL                           (1<<0)  /*
>     Enable serial port */
>     +#define MV643XX_ETH_FORCE_LINK_PASS                                    (1<<1)
>     +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX                (1<<2)
>     +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL       (1<<3)
>     +#define MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL                (1<<4)
>     +#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS         (1<<5)
>     +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX                       (1<<7)
>     +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR     (1<<8)
>     +#define MV643XX_ETH_BIT9_UNKNOWN                                     
>      (1<<9)  /* unknown purpose; linux sets this */
>     +#define MV643XX_ETH_FORCE_LINK_FAIL_DISABLE                    (1<<10)
>     +#define MV643XX_ETH_RETRANSMIT_FOREVER                         (1<<11) /*
>     limit to 16 attempts if clear    */
>     +#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII                (1<<13)
>     +#define MV643XX_ETH_DTE_ADV_1                                          (1<<14)
>     +#define MV643XX_ETH_AUTO_NEG_BYPASS_ENBL                       (1<<15)
>     +#define MV643XX_ETH_RESTART_AUTO_NEG                           (1<<16)
>     +#define MV643XX_ETH_SC_MAX_RX_1518                                   
>      (0<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_1522                                   
>      (1<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_1552                                   
>      (2<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_9022                                   
>      (3<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_9192                                   
>      (4<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_9700                                   
>      (5<<17) /* Limit RX packet size */
>     +#define MV643XX_ETH_SC_MAX_RX_MASK                                   
>      (7<<17) /* bitmask */
>     +#define MV643XX_ETH_SET_EXT_LOOPBACK                           (1<<20)
>     +#define MV643XX_ETH_SET_FULL_DUPLEX                                    (1<<21)
>     +#define MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD           (1<<22) /* enable
>     flow ctrl on rx and tx in full-duplex */
>     +#define MV643XX_ETH_SET_GMII_SPEED_1000                               
>     (1<<23) /* 10/100 if clear */
>     +#define MV643XX_ETH_SET_MII_SPEED_100                          (1<<24) /*
>     10 if clear     */
>     +
>     +#define MV643XX_ETH_PORT_STATUS_R(port)                               
>     (0x2444 + ((port)<<10))
>     +
>     +#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT                    (1<<0)
>     +#define MV643XX_ETH_PORT_STATUS_LINK_UP                                (1<<1)
>     +#define MV643XX_ETH_PORT_STATUS_FDX                                    (1<<2)
>     +#define MV643XX_ETH_PORT_STATUS_FC                                     (1<<3)
>     +#define MV643XX_ETH_PORT_STATUS_1000                           (1<<4)
>     +#define MV643XX_ETH_PORT_STATUS_100                                    (1<<5)
>     +/* PSR bit 6 unknown */
>     +#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS         (1<<7)
>     +#define MV643XX_ETH_PORT_STATUS_ANEG_BYPASSED          (1<<8)
>     +#define MV643XX_ETH_PORT_STATUS_PARTITION                      (1<<9)
>     +#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY          (1<<10)
>     +
>     +#define MV643XX_ETH_MIB_COUNTERS(port)                         (0x3000 +
>     ((port)<<7))
>     +#define MV643XX_ETH_NUM_MIB_COUNTERS                           32
>     +
>     +#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO                      (0)
>     +#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_HI                      (1<<2)
>     +#define MV643XX_ETH_MIB_BAD_OCTS_RCVD                          (2<<2)
>     +#define MV643XX_ETH_MIB_INTERNAL_MAC_TX_ERR                    (3<<2)
>     +#define MV643XX_ETH_MIB_GOOD_FRAMES_RCVD                       (4<<2)
>     +#define MV643XX_ETH_MIB_BAD_FRAMES_RCVD                                (5<<2)
>     +#define MV643XX_ETH_MIB_BCAST_FRAMES_RCVD                      (6<<2)
>     +#define MV643XX_ETH_MIB_MCAST_FRAMES_RCVD                      (7<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_64_OCTS                         (8<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_65_127_OCTS                     (9<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_128_255_OCTS                    (10<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_256_511_OCTS                    (11<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_512_1023_OCTS           (12<<2)
>     +#define MV643XX_ETH_MIB_FRAMES_1024_MAX_OCTS           (13<<2)
>     +#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO                      (14<<2)
>     +#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_HI                      (15<<2)
>     +#define MV643XX_ETH_MIB_GOOD_FRAMES_SENT                       (16<<2)
>     +#define MV643XX_ETH_MIB_EXCESSIVE_COLL                         (17<<2)
>     +#define MV643XX_ETH_MIB_MCAST_FRAMES_SENT                      (18<<2)
>     +#define MV643XX_ETH_MIB_BCAST_FRAMES_SENT                      (19<<2)
>     +#define MV643XX_ETH_MIB_UNREC_MAC_CTRL_RCVD                    (20<<2)
>     +#define MV643XX_ETH_MIB_FC_SENT                                           
>         (21<<2)
>     +#define MV643XX_ETH_MIB_GOOD_FC_RCVD                           (22<<2)
>     +#define MV643XX_ETH_MIB_BAD_FC_RCVD                                    (23<<2)
>     +#define MV643XX_ETH_MIB_UNDERSIZE_RCVD                         (24<<2)
>     +#define MV643XX_ETH_MIB_FRAGMENTS_RCVD                         (25<<2)
>     +#define MV643XX_ETH_MIB_OVERSIZE_RCVD                          (26<<2)
>     +#define MV643XX_ETH_MIB_JABBER_RCVD                                    (27<<2)
>     +#define MV643XX_ETH_MIB_MAC_RX_ERR                                     (28<<2)
>     +#define MV643XX_ETH_MIB_BAD_CRC_EVENT                          (29<<2)
>     +#define MV643XX_ETH_MIB_COLL                                           (30<<2)
>     +#define MV643XX_ETH_MIB_LATE_COLL                                      (31<<2)
>     +
>     +#define MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(port) (0x3400+((port)<<10))
>     +#define MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(port) (0x3500+((port)<<10))
>     +#define MV643XX_ETH_DA_FILTER_UNICAST_TBL(port)               
>     (0x3600+((port)<<10))
>     +#define MV643XX_ETH_NUM_MCAST_ENTRIES                          64
>     +#define MV643XX_ETH_NUM_UNICAST_ENTRIES                                4
>     +
>     +#define MV643XX_ETH_BAR_0                                                 
>         (0x2200)
>     +#define MV643XX_ETH_SIZE_R_0                                           (0x2204)
>     +#define MV643XX_ETH_BAR_1                                                 
>         (0x2208)
>     +#define MV643XX_ETH_SIZE_R_1                                           (0x220c)
>     +#define MV643XX_ETH_BAR_2                                                 
>         (0x2210)
>     +#define MV643XX_ETH_SIZE_R_2                                           (0x2214)
>     +#define MV643XX_ETH_BAR_3                                                 
>         (0x2218)
>     +#define MV643XX_ETH_SIZE_R_3                                           (0x221c)
>     +#define MV643XX_ETH_BAR_4                                                 
>         (0x2220)
>     +#define MV643XX_ETH_SIZE_R_4                                           (0x2224)
>     +#define MV643XX_ETH_BAR_5                                                 
>         (0x2228)
>     +#define MV643XX_ETH_SIZE_R_5                                           (0x222c)
>     +#define MV643XX_ETH_NUM_BARS                                           6
>     +
>     +/* Bits in the BAR reg to program cache snooping */
>     +#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
>     +#define MV64360_ENET2MEM_SNOOP_WT      0x1000
>     +#define MV64360_ENET2MEM_SNOOP_WB      0x2000
>     +#define MV64360_ENET2MEM_SNOOP_MSK     0x3000
>     +
>     +
>     +#define MV643XX_ETH_BAR_ENBL_R                                         (0x2290)
>     +#define MV643XX_ETH_BAR_DISABLE(bar)                           (1<<(bar))
>     +#define MV643XX_ETH_BAR_DISBL_ALL                                      0x3f
>     +
>     +#define MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(port)       (0x260c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q1_CURRENT_DESC_PTR(port)       (0x261c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q2_CURRENT_DESC_PTR(port)       (0x262c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q3_CURRENT_DESC_PTR(port)       (0x263c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q4_CURRENT_DESC_PTR(port)       (0x264c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q5_CURRENT_DESC_PTR(port)       (0x265c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q6_CURRENT_DESC_PTR(port)       (0x266c+((port)<<10))
>     +#define MV643XX_ETH_RX_Q7_CURRENT_DESC_PTR(port)       (0x267c+((port)<<10))
>     +
>     +#define MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(port)       (0x26c0+((port)<<10))
>     +#define MV643XX_ETH_TX_Q1_CURRENT_DESC_PTR(port)       (0x26c4+((port)<<10))
>     +#define MV643XX_ETH_TX_Q2_CURRENT_DESC_PTR(port)       (0x26c8+((port)<<10))
>     +#define MV643XX_ETH_TX_Q3_CURRENT_DESC_PTR(port)       (0x26cc+((port)<<10))
>     +#define MV643XX_ETH_TX_Q4_CURRENT_DESC_PTR(port)       (0x26d0+((port)<<10))
>     +#define MV643XX_ETH_TX_Q5_CURRENT_DESC_PTR(port)       (0x26d4+((port)<<10))
>     +#define MV643XX_ETH_TX_Q6_CURRENT_DESC_PTR(port)       (0x26d8+((port)<<10))
>     +#define MV643XX_ETH_TX_Q7_CURRENT_DESC_PTR(port)       (0x26dc+((port)<<10))
>     +
>     +#define MV643XX_ETH_MAC_ADDR_LO(port)                         
>     (0x2414+((port)<<10))
>     +#define MV643XX_ETH_MAC_ADDR_HI(port)                         
>     (0x2418+((port)<<10))
>     +
>     +/* TYPE DEFINITIONS */
>     +
>     +/* just to make the purpose explicit; vars of this
>     + * type may need CPU-dependent address translation,
>     + * endian conversion etc.
>     + */
>     +typedef uint32_t Dma_addr_t;
>     +
>     +typedef volatile struct mveth_rx_desc {
>     +#ifndef __BIG_ENDIAN__
>     +#error "descriptor declaration not implemented for little endian machines"
>     +#endif
>     +       uint16_t        byte_cnt;
>     +       uint16_t        buf_size;
>     +       uint32_t        cmd_sts;                                        /*
>     control and status */
>     +       Dma_addr_t      next_desc_ptr;                          /* next
>     descriptor (as seen from DMA) */
>     +       Dma_addr_t      buf_ptr;
>     +       /* fields below here are not used by the chip */
>     +       void            *u_buf;                                         /*
>     user buffer */
>     +       volatile struct mveth_rx_desc *next;    /* next descriptor (CPU
>     address; next_desc_ptr is a DMA address) */
>     +       uint32_t        pad[2];
>     +} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthRxDescRec, *MvEthRxDesc;
>     +
>     +typedef volatile struct mveth_tx_desc {
>     +#ifndef __BIG_ENDIAN__
>     +#error "descriptor declaration not implemented for little endian machines"
>     +#endif
>     +       uint16_t        byte_cnt;
>     +       uint16_t        l4i_chk;
>     +       uint32_t        cmd_sts;                                        /*
>     control and status */
>     +       Dma_addr_t      next_desc_ptr;                          /* next
>     descriptor (as seen from DMA) */
>     +       Dma_addr_t      buf_ptr;
>     +       /* fields below here are not used by the chip */
>     +       uint32_t        workaround[2];                          /* use this
>     space to work around the 8byte problem (is this real?) */
>     +       void            *u_buf;                                         /*
>     user buffer */
>     +       volatile struct mveth_tx_desc *next;    /* next descriptor (CPU
>     address; next_desc_ptr is a DMA address)   */
>     +} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthTxDescRec, *MvEthTxDesc;
>     +
>     +/* Assume there are never more then 64k aliasing entries */
>     +typedef uint16_t Mc_Refcnt[MV643XX_ETH_NUM_MCAST_ENTRIES*4];
>     +
>     +/* driver private data and bsdnet interface structure */
>     +struct mveth_private {
>     +       MvEthRxDesc             rx_ring;                                   
>         /* pointers to aligned ring area             */
>     +       MvEthTxDesc             tx_ring;                                   
>         /* pointers to aligned ring area             */
>     +       MvEthRxDesc             ring_area;                                 
>         /* allocated ring area                       */
>     +       int                             rbuf_count, xbuf_count;         /*
>     saved ring sizes from ifconfig            */
>     +       int                             port_num;
>     +       int                             phy;
>     +       MvEthRxDesc             d_rx_t;                                     
>        /* tail of the RX ring; next received packet */
>     +       MvEthTxDesc             d_tx_t, d_tx_h;                         
>     +       uint32_t                rx_desc_dma, tx_desc_dma;       /* ring
>     address as seen by DMA; (1:1 on this BSP) */
>     +       int                             avail;
>     +       void            (*isr)(void*);
>     +       void            *isr_arg;
>     +       /* Callbacks to handle buffers */
>     +       void                    (*cleanup_txbuf)(void*, void*, int);    /*
>     callback to cleanup TX buffer */
>     +       void                    *cleanup_txbuf_arg;
>     +       void                    *(*alloc_rxbuf)(int *psize, uintptr_t
>     *paddr);  /* allocate RX buffer  */
>     +       void                    (*consume_rxbuf)(void*, void*,  int);   /*
>     callback to consume RX buffer */
>     +       void                    *consume_rxbuf_arg;
>     +       rtems_id        tid;
>     +       uint32_t                irq_mask;                                   
>        /* IRQs we use                              */
>     +       uint32_t                xirq_mask;
>     +    int             promisc;
>     +       struct          {
>     +               unsigned                irqs;
>     +               unsigned                maxchain;
>     +               unsigned                repack;
>     +               unsigned                packet;
>     +               unsigned                odrops;                             
>        /* no counter in core code                   */
>     +               struct {
>     +                       uint64_t        good_octs_rcvd;         /* 64-bit */
>     +                       uint32_t        bad_octs_rcvd;
>     +                       uint32_t        internal_mac_tx_err;
>     +                       uint32_t        good_frames_rcvd;
>     +                       uint32_t        bad_frames_rcvd;
>     +                       uint32_t        bcast_frames_rcvd;
>     +                       uint32_t        mcast_frames_rcvd;
>     +                       uint32_t        frames_64_octs;
>     +                       uint32_t        frames_65_127_octs;
>     +                       uint32_t        frames_128_255_octs;
>     +                       uint32_t        frames_256_511_octs;
>     +                       uint32_t        frames_512_1023_octs;
>     +                       uint32_t        frames_1024_max_octs;
>     +                       uint64_t        good_octs_sent;         /* 64-bit */
>     +                       uint32_t        good_frames_sent;
>     +                       uint32_t        excessive_coll;
>     +                       uint32_t        mcast_frames_sent;
>     +                       uint32_t        bcast_frames_sent;
>     +                       uint32_t        unrec_mac_ctrl_rcvd;
>     +                       uint32_t        fc_sent;
>     +                       uint32_t        good_fc_rcvd;
>     +                       uint32_t        bad_fc_rcvd;
>     +                       uint32_t        undersize_rcvd;
>     +                       uint32_t        fragments_rcvd;
>     +                       uint32_t        oversize_rcvd;
>     +                       uint32_t        jabber_rcvd;
>     +                       uint32_t        mac_rx_err;
>     +                       uint32_t        bad_crc_event;
>     +                       uint32_t        coll;
>     +                       uint32_t        late_coll;
>     +               } mib;
>     +       }                       stats;
>     +       struct {
>     +               Mc_Refcnt       specl, other;
>     +       }           mc_refcnt;
>     +};
>     +
>     +/* stuff needed for bsdnet support */
>     +struct mveth_bsdsupp {
>     +       int                             oif_flags;                         
>                 /* old / cached if_flags */
>     +};
>     +
>     +struct mveth_softc {
>     +       struct arpcom                   arpcom;
>     +       struct mveth_bsdsupp    bsd;
>     +       struct mveth_private    pvt;
>     +};
>     +
>     +/* GLOBAL VARIABLES */
>     +#ifdef MVETH_DEBUG_TX_DUMP
>     +int mveth_tx_dump = 0;
>     +#endif
>     +
>     +/* THE array of driver/bsdnet structs */
>     +
>     +/* If detaching/module unloading is enabled, the main driver data
>     + * structure must remain in memory; hence it must reside in its own
>     + * 'dummy' module...
>     + */
>     +#ifdef  MVETH_DETACH_HACK
>     +extern
>     +#else
>     +STATIC
>     +#endif
>     +struct mveth_softc theMvEths[MV643XXETH_NUM_DRIVER_SLOTS]
>     +#ifndef MVETH_DETACH_HACK
>     += {{{{0}},}}
>     +#endif
>     +;
>     +
>     +/* daemon task id */
>     +STATIC rtems_id        mveth_tid = 0;
>     +/* register access protection mutex */
>     +STATIC rtems_id mveth_mtx = 0;
>     +#define REGLOCK()      do { \
>     +               if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(mveth_mtx,
>     RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \
>     +                       rtems_panic(DRVNAME": unable to lock register
>     protection mutex"); \
>     +               } while (0)
>     +#define REGUNLOCK()    rtems_semaphore_release(mveth_mtx)
>     +
>     +/* Format strings for statistics messages */
>     +static const char *mibfmt[] = {
>     +       "  GOOD_OCTS_RCVD:      %"PRIu64"\n",
>     +       0,
>     +       "  BAD_OCTS_RCVD:       %"PRIu32"\n",
>     +       "  INTERNAL_MAC_TX_ERR: %"PRIu32"\n",
>     +       "  GOOD_FRAMES_RCVD:    %"PRIu32"\n",
>     +       "  BAD_FRAMES_RCVD:     %"PRIu32"\n",
>     +       "  BCAST_FRAMES_RCVD:   %"PRIu32"\n",
>     +       "  MCAST_FRAMES_RCVD:   %"PRIu32"\n",
>     +       "  FRAMES_64_OCTS:      %"PRIu32"\n",
>     +       "  FRAMES_65_127_OCTS:  %"PRIu32"\n",
>     +       "  FRAMES_128_255_OCTS: %"PRIu32"\n",
>     +       "  FRAMES_256_511_OCTS: %"PRIu32"\n",
>     +       "  FRAMES_512_1023_OCTS:%"PRIu32"\n",
>     +       "  FRAMES_1024_MAX_OCTS:%"PRIu32"\n",
>     +       "  GOOD_OCTS_SENT:      %"PRIu64"\n",
>     +       0,
>     +       "  GOOD_FRAMES_SENT:    %"PRIu32"\n",
>     +       "  EXCESSIVE_COLL:      %"PRIu32"\n",
>     +       "  MCAST_FRAMES_SENT:   %"PRIu32"\n",
>     +       "  BCAST_FRAMES_SENT:   %"PRIu32"\n",
>     +       "  UNREC_MAC_CTRL_RCVD: %"PRIu32"\n",
>     +       "  FC_SENT:             %"PRIu32"\n",
>     +       "  GOOD_FC_RCVD:        %"PRIu32"\n",
>     +       "  BAD_FC_RCVD:         %"PRIu32"\n",
>     +       "  UNDERSIZE_RCVD:      %"PRIu32"\n",
>     +       "  FRAGMENTS_RCVD:      %"PRIu32"\n",
>     +       "  OVERSIZE_RCVD:       %"PRIu32"\n",
>     +       "  JABBER_RCVD:         %"PRIu32"\n",
>     +       "  MAC_RX_ERR:          %"PRIu32"\n",
>     +       "  BAD_CRC_EVENT:       %"PRIu32"\n",
>     +       "  COLL:                %"PRIu32"\n",
>     +       "  LATE_COLL:           %"PRIu32"\n",
>     +};
>     +
>     +/* Interrupt Handler Connection */
>     +
>     +/* forward decls + implementation for IRQ API funcs */
>     +
>     +static void mveth_isr(rtems_irq_hdl_param unit);
>     +static void mveth_isr_1(rtems_irq_hdl_param unit);
>     +static void noop(const rtems_irq_connect_data *unused)  {}
>     +static int  noop1(const rtems_irq_connect_data *unused) { return 0; }
>     +
>     +static rtems_irq_connect_data irq_data[MAX_NUM_SLOTS] = {
>     +       {
>     +               BSP_IRQ_ETH0,
>     +               0,
>     +               (rtems_irq_hdl_param)0,
>     +               noop,
>     +               noop,
>     +               noop1
>     +       },
>     +       {
>     +               BSP_IRQ_ETH1,
>     +               0,
>     +               (rtems_irq_hdl_param)1,
>     +               noop,
>     +               noop,
>     +               noop1
>     +       },
>     +       {
>     +               BSP_IRQ_ETH2,
>     +               0,
>     +               (rtems_irq_hdl_param)2,
>     +               noop,
>     +               noop,
>     +               noop1
>     +       },
>     +};
>     +
>     +/* MII Ioctl Interface */
>     +
>     +STATIC unsigned
>     +mveth_mii_read(struct mveth_private *mp, unsigned addr);
>     +
>     +STATIC unsigned
>     +mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v);
>     +
>     +
>     +/* mdio / mii interface wrappers for rtems_mii_ioctl API */
>     +
>     +static int mveth_mdio_r(int phy, void *uarg, unsigned reg, uint32_t *pval)
>     +{
>     +       if ( phy > 1 )
>     +               return -1;
>     +
>     +       *pval = mveth_mii_read(uarg, reg);
>     +       return 0;
>     +}
>     +
>     +static int mveth_mdio_w(int phy, void *uarg, unsigned reg, uint32_t val)
>     +{
>     +       if ( phy > 1 )
>     +               return -1;
>     +       mveth_mii_write(uarg, reg, val);
>     +       return 0;
>     +}
>     +
>     +static struct rtems_mdio_info mveth_mdio = {
>     +       mdio_r:   mveth_mdio_r,
>     +       mdio_w:   mveth_mdio_w,
>     +       has_gmii: 1,
>     +};
>     +
>     +/* LOW LEVEL SUPPORT ROUTINES */
>     +
>     +/* Software Cache Coherency */
>     +#ifndef ENABLE_HW_SNOOPING
>     +#ifndef __PPC__
>     +#error "Software cache coherency maintenance is not implemented for your
>     CPU architecture"
>     +#endif
>     +
>     +static inline unsigned INVAL_DESC(volatile void *d)
>     +{
>     +typedef const char cache_line[PPC_CACHE_ALIGNMENT];
>     +       asm volatile("dcbi 0, %1":"=m"(*(cache_line*)d):"r"(d));
>     +       return (unsigned)d;     /* so this can be used in comma expression */
>     +}
>     +
>     +static inline void FLUSH_DESC(volatile void *d)
>     +{
>     +typedef const char cache_line[PPC_CACHE_ALIGNMENT];
>     +       asm volatile("dcbf 0, %0"::"r"(d),"m"(*(cache_line*)d));
>     +}
>     +
>     +static inline void FLUSH_BARRIER(void)
>     +{
>     +       asm volatile("eieio");
>     +}
>     +
>     +/* RX buffers are always cache-line aligned
>     + * ASSUMPTIONS:
>     + *   - 'addr' is cache aligned
>     + *   -  len   is a multiple >0 of cache lines
>     + */
>     +static inline void INVAL_BUF(register uintptr_t addr, register int len)
>     +{
>     +typedef char maxbuf[2048]; /* more than an ethernet packet */
>     +       do {
>     +               len -= RX_BUF_ALIGNMENT;
>     +               asm volatile("dcbi %0, %1"::"b"(addr),"r"(len));
>     +       } while (len > 0);
>     +       asm volatile("":"=m"(*(maxbuf*)addr));
>     +}
>     +
>     +/* Flushing TX buffers is a little bit trickier; we don't really know their
>     + * alignment but *assume* adjacent addresses are covering 'ordinary' memory
>     + * so that flushing them does no harm!
>     + */
>     +static inline void FLUSH_BUF(register uintptr_t addr, register int len)
>     +{
>     +       asm volatile("":::"memory");
>     +       len = MV643XX_ALIGN(len, RX_BUF_ALIGNMENT);
>     +       do {
>     +               asm volatile("dcbf %0, %1"::"b"(addr),"r"(len));
>     +               len -= RX_BUF_ALIGNMENT;
>     +       } while ( len >= 0 );
>     +}
>     +
>     +#else /* hardware snooping enabled */
>     +
>     +/* inline this to silence compiler warnings */
>     +static inline int INVAL_DESC(volatile void *d)
>     +{ return 0; }
>     +
>     +#define FLUSH_DESC(d)  NOOP()
>     +#define INVAL_BUF(b,l) NOOP()
>     +#define FLUSH_BUF(b,l) NOOP()
>     +#define FLUSH_BARRIER()        NOOP()
>     +
>     +#endif /* cache coherency support */
>     +
>     +/* Synchronize memory access */
>     +#ifdef __PPC__
>     +static inline void membarrier(void)
>     +{
>     +       asm volatile("sync":::"memory");
>     +}
>     +#else
>     +#error "memory barrier instruction not defined (yet) for this CPU"
>     +#endif
>     +
>     +/* Enable and disable interrupts at the device */
>     +static inline void
>     +mveth_enable_irqs(struct mveth_private *mp, uint32_t mask)
>     +{
>     +rtems_interrupt_level l;
>     +uint32_t val;
>     +       rtems_interrupt_disable(l);
>     +
>     +       val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
>     +       val  = (val | mask | MV643XX_ETH_IRQ_EXT_ENA) & mp->irq_mask;
>     +
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        val);
>     +
>     +       val  = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
>     +       val  = (val | mask) & mp->xirq_mask;
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), val);
>     +
>     +       rtems_interrupt_enable(l);
>     +}
>     +
>     +static inline uint32_t
>     +mveth_disable_irqs(struct mveth_private *mp, uint32_t mask)
>     +{
>     +rtems_interrupt_level l;
>     +uint32_t val,xval,tmp;
>     +       rtems_interrupt_disable(l);
>     +
>     +       val  = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num));
>     +       tmp  = ( (val & ~mask) | MV643XX_ETH_IRQ_EXT_ENA ) & mp->irq_mask;
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        tmp);
>     +
>     +       xval = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num));
>     +       tmp  = (xval & ~mask) & mp->xirq_mask;
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), tmp);
>     +
>     +       rtems_interrupt_enable(l);
>     +
>     +       return (val | xval);
>     +}
>     +
>     +/* This should be safe even w/o turning off interrupts if multiple
>     + * threads ack different bits in the cause register (and ignore
>     + * other ones) since writing 'ones' into the cause register doesn't
>     + * 'stick'.
>     + */
>     +
>     +static inline uint32_t
>     +mveth_ack_irqs(struct mveth_private *mp, uint32_t mask)
>     +{
>     +register uint32_t x,xe,p;
>     +
>     +               p  = mp->port_num;
>     +               /* Get cause */
>     +               x  = MV_READ(MV643XX_ETH_INTERRUPT_CAUSE_R(p));
>     +
>     +               /* Ack interrupts filtering the ones we're interested in */
>     +
>     +               /* Note: EXT_IRQ bit clears by itself if EXT interrupts are
>     cleared */
>     +               MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(p), ~ (x &
>     mp->irq_mask & mask));
>     +
>     +                               /* linux driver tests 1<<1 as a summary bit
>     for extended interrupts;
>     +                                * the mv64360 seems to use 1<<19 for that
>     purpose; for the moment,
>     +                                * I just check both.
>     +                                * Update: link status irq (1<<16 in xe)
>     doesn't set (1<<19) in x!
>     +                                */
>     +               if ( 1 /* x & 2 */ )
>     +               {
>     +                       xe = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p));
>     +
>     +                       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p), ~
>     (xe & mp->xirq_mask & mask));
>     +               } else {
>     +                       xe = 0;
>     +               }
>     +#ifdef MVETH_TESTING
>     +               if (    ((x & MV643XX_ETH_ALL_IRQS) & ~MV643XX_ETH_KNOWN_IRQS)
>     +                        || ((xe & MV643XX_ETH_ALL_EXT_IRQS) &
>     ~MV643XX_ETH_KNOWN_EXT_IRQS) ) {
>     +                       fprintf(stderr, "Unknown IRQs detected; leaving all
>     disabled for debugging:\n");
>     +                       fprintf(stderr, "Cause reg was 0x%08x, ext cause
>     0x%08x\n", x, xe);
>     +                       mp->irq_mask  = 0;
>     +                       mp->xirq_mask = 0;
>     +               }
>     +#endif
>     +               /* luckily, the extended and 'normal' interrupts we use
>     don't overlap so
>     +                * we can just OR them into a single word
>     +                */
>     +               return  (xe & mp->xirq_mask) | (x & mp->irq_mask);
>     +}
>     +
>     +static void mveth_isr(rtems_irq_hdl_param arg)
>     +{
>     +unsigned unit = (unsigned)arg;
>     +       mveth_disable_irqs(&theMvEths[unit].pvt, -1);
>     +       theMvEths[unit].pvt.stats.irqs++;
>     +       rtems_bsdnet_event_send( theMvEths[unit].pvt.tid, 1<<unit );
>     +}
>     +
>     +static void mveth_isr_1(rtems_irq_hdl_param arg)
>     +{
>     +unsigned              unit = (unsigned)arg;
>     +struct mveth_private *mp   = &theMvEths[unit].pvt;
>     +
>     +       mp->stats.irqs++;
>     +       mp->isr(mp->isr_arg);
>     +}
>     +
>     +static void
>     +mveth_clear_mib_counters(struct mveth_private *mp)
>     +{
>     +register int           i;
>     +register uint32_t      b;
>     +       /* reading the counters resets them */
>     +       b = MV643XX_ETH_MIB_COUNTERS(mp->port_num);
>     +       for (i=0; i< MV643XX_ETH_NUM_MIB_COUNTERS; i++, b+=4)
>     +               (void)MV_READ(b);
>     +}
>     +
>     +/* Reading a MIB register also clears it. Hence we read the lo
>     + * register first, then the hi one. Correct reading is guaranteed since
>     + * the 'lo' register cannot overflow after it is read since it had
>     + * been reset to 0.
>     + */
>     +static unsigned long long
>     +read_long_mib_counter(int port_num, int idx)
>     +{
>     +unsigned long lo;
>     +unsigned long long hi;
>     +       lo = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
>     +       idx++;
>     +       hi = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
>     +       return (hi<<32) | lo;
>     +}
>     +
>     +static inline unsigned long
>     +read_mib_counter(int port_num, int idx)
>     +{
>     +       return MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2));
>     +}
>     +
>     +
>     +/* write ethernet address from buffer to hardware (need to change unicast
>     filter after this) */
>     +static void
>     +mveth_write_eaddr(struct mveth_private *mp, unsigned char *eaddr)
>     +{
>     +int                    i;
>     +uint32_t       x;
>     +
>     +       /* build hi word */
>     +       for (i=4,x=0; i; i--, eaddr++) {
>     +               x = (x<<8) | *eaddr;
>     +       }
>     +       MV_WRITE(MV643XX_ETH_MAC_ADDR_HI(mp->port_num), x);
>     +
>     +       /* build lo word */
>     +       for (i=2,x=0; i; i--, eaddr++) {
>     +               x = (x<<8) | *eaddr;
>     +       }
>     +       MV_WRITE(MV643XX_ETH_MAC_ADDR_LO(mp->port_num), x);
>     +}
>     +
>     +/* PHY/MII Interface
>     + *
>     + * Read/write a PHY register;
>     + *
>     + * NOTE: The SMI register is shared among the three devices.
>     + *       Protection is provided by the global networking semaphore.
>     + *       If non-bsd drivers are running on a subset of IFs proper
>     + *       locking of all shared registers must be implemented!
>     + */
>     +STATIC unsigned
>     +mveth_mii_read(struct mveth_private *mp, unsigned addr)
>     +{
>     +unsigned v;
>     +unsigned wc = 0;
>     +
>     +       addr  &= 0x1f;
>     +
>     +       /* wait until not busy */
>     +       do {
>     +               v = MV_READ(MV643XX_ETH_SMI_R);
>     +               wc++;
>     +       } while ( MV643XX_ETH_SMI_BUSY & v );
>     +
>     +       MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) |
>     MV643XX_ETH_SMI_OP_RD );
>     +
>     +       do {
>     +               v = MV_READ(MV643XX_ETH_SMI_R);
>     +               wc++;
>     +       } while ( MV643XX_ETH_SMI_BUSY & v );
>     +
>     +       if (wc>0xffff)
>     +               wc = 0xffff;
>     +       return (wc<<16) | (v & 0xffff);
>     +}
>     +
>     +STATIC unsigned
>     +mveth_mii_write(struct mveth_private *mp, unsigned addr, unsigned v)
>     +{
>     +unsigned wc = 0;
>     +
>     +       addr  &= 0x1f;
>     +       v     &= 0xffff;
>     +
>     +       /* busywait is ugly but not preventing ISRs or high priority tasks from
>     +        * preempting us
>     +        */
>     +
>     +       /* wait until not busy */
>     +       while ( MV643XX_ETH_SMI_BUSY & MV_READ(MV643XX_ETH_SMI_R) )
>     +               wc++ /* wait */;
>     +
>     +       MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (mp->phy<<16) |
>     MV643XX_ETH_SMI_OP_WR | v );
>     +
>     +       return wc;
>     +}
>     +
>     +/* MID-LAYER SUPPORT ROUTINES */
>     +
>     +/* Start TX if descriptors are exhausted */
>     +static __inline__ void
>     +mveth_start_tx(struct mveth_private *mp)
>     +{
>     +uint32_t running;
>     +       if ( mp->avail <= 0 ) {
>     +               running =
>     MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num));
>     +               if ( ! (running & MV643XX_ETH_TX_START(0)) ) {
>     +                     
>      MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_TX_START(0));
>     +               }
>     +       }
>     +}
>     +
>     +/* Stop TX and wait for the command queues to stop and the fifo to drain */
>     +static uint32_t
>     +mveth_stop_tx(int port)
>     +{
>     +uint32_t active_q;
>     +
>     +       active_q = (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) &
>     MV643XX_ETH_TX_ANY_RUNNING);
>     +
>     +       if ( active_q ) {
>     +               /* Halt TX and wait for activity to stop */
>     +               MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port),
>     MV643XX_ETH_TX_STOP_ALL);
>     +               while ( MV643XX_ETH_TX_ANY_RUNNING &
>     MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) )
>     +                       /* poll-wait */;
>     +               /* Wait for Tx FIFO to drain */
>     +               while ( ! (MV643XX_ETH_PORT_STATUS_R(port) &
>     MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY) )
>     +                       /* poll-wait */;
>     +       }
>     +
>     +       return active_q;
>     +}
>     +
>     +/* update serial port settings from current link status */
>     +static void
>     +mveth_update_serial_port(struct mveth_private *mp, int media)
>     +{
>     +int port = mp->port_num;
>     +uint32_t old, new;
>     +
>     +       new = old = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(port));
>     +
>     +       /* mask speed and duplex settings */
>     +       new &= ~(  MV643XX_ETH_SET_GMII_SPEED_1000
>     +                        | MV643XX_ETH_SET_MII_SPEED_100
>     +                        | MV643XX_ETH_SET_FULL_DUPLEX );
>     +
>     +       if ( IFM_FDX & media )
>     +               new |= MV643XX_ETH_SET_FULL_DUPLEX;
>     +
>     +       switch ( IFM_SUBTYPE(media) ) {
>     +               default: /* treat as 10 */
>     +                       break;
>     +               case IFM_100_TX:
>     +                       new |= MV643XX_ETH_SET_MII_SPEED_100;
>     +                       break;
>     +               case IFM_1000_T:
>     +                       new |= MV643XX_ETH_SET_GMII_SPEED_1000;
>     +                       break;
>     +       }
>     +
>     +       if ( new != old ) {
>     +               if ( ! (MV643XX_ETH_SERIAL_PORT_ENBL & new) ) {
>     +                       /* just write */
>     +                       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
>     +               } else {
>     +                       uint32_t were_running;
>     +
>     +                       were_running = mveth_stop_tx(port);
>     +
>     +                       old &= ~MV643XX_ETH_SERIAL_PORT_ENBL;
>     +                       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), old);
>     +                       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
>     +                       /* linux driver writes twice... */
>     +                       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new);
>     +
>     +                       if ( were_running ) {
>     +                             
>      MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_TX_START(0));
>     +                       }
>     +               }
>     +       }
>     +}
>     +
>     +/* Clear multicast filters                        */
>     +void
>     +BSP_mve_mcast_filter_clear(struct mveth_private *mp)
>     +{
>     +int                 i;
>     +register uint32_t      s,o;
>     +uint32_t            v = mp->promisc ? 0x01010101 : 0x00000000;
>     +       s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
>     +       o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
>     +       for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
>     +               MV_WRITE(s,v);
>     +               MV_WRITE(o,v);
>     +               s+=4;
>     +               o+=4;
>     +       }
>     +       for (i=0;
>     i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
>     +               mp->mc_refcnt.specl[i] = 0;
>     +               mp->mc_refcnt.other[i] = 0;
>     +       }
>     +}
>     +
>     +void
>     +BSP_mve_mcast_filter_accept_all(struct mveth_private *mp)
>     +{
>     +int                 i;
>     +register uint32_t      s,o;
>     +       s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
>     +       o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
>     +       for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) {
>     +               MV_WRITE(s,0x01010101);
>     +               MV_WRITE(o,0x01010101);
>     +               s+=4;
>     +               o+=4;
>     +               /* Not clear what we should do with the reference count.
>     +                * For now just increment it.
>     +                */
>     +               for (i=0;
>     i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) {
>     +                       mp->mc_refcnt.specl[i]++;
>     +                       mp->mc_refcnt.other[i]++;
>     +               }
>     +       }
>     +}
>     +
>     +static void add_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
>     +{
>     +uint32_t val;
>     +uint32_t slot = hash & 0xfc;
>     +
>     +       if ( 0 == (*refcnt)[hash]++ ) {
>     +               val = MV_READ(off+slot) | ( 1 << ((hash&3)<<3) );
>     +               MV_WRITE(off+slot, val);
>     +       }
>     +}
>     +
>     +static void del_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt)
>     +{
>     +uint32_t val;
>     +uint32_t slot = hash & 0xfc;
>     +
>     +       if ( (*refcnt)[hash] > 0 && 0 == --(*refcnt)[hash] ) {
>     +               val = MV_READ(off+slot) & ~( 1 << ((hash&3)<<3) );
>     +               MV_WRITE(off+slot, val);
>     +       }
>     +}
>     +
>     +void
>     +BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char
>     *enaddr)
>     +{
>     +uint32_t   hash;
>     +static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
>     +static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
>     +uint32_t   tabl;
>     +Mc_Refcnt  *refcnt;
>     +
>     +       if ( ! (0x01 & enaddr[0]) ) {
>     +               /* not a multicast address; ignore */
>     +               return;
>     +       }
>     +
>     +       if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
>     +               /* broadcast address; ignore */
>     +               return;
>     +       }
>     +
>     +       if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
>     +               hash   = enaddr[5];
>     +               tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
>     +               refcnt = &mp->mc_refcnt.specl;
>     +       } else {
>     +               uint32_t test, mask;
>     +               int      i;
>     +               /* algorithm used by linux driver */
>     +               for ( hash=0, i=0; i<6; i++ ) {
>     +                       hash = (hash ^ enaddr[i]) << 8;
>     +                       for ( test=0x8000, mask=0x8380; test>0x0080;
>     test>>=1, mask>>=1 ) {
>     +                               if ( hash & test )
>     +                                       hash ^= mask;
>     +                       }
>     +               }
>     +               tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
>     +               refcnt = &mp->mc_refcnt.other;
>     +       }
>     +       add_entry(tabl, hash, refcnt);
>     +}
>     +
>     +void
>     +BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char
>     *enaddr)
>     +{
>     +uint32_t   hash;
>     +static const char spec[]={0x01,0x00,0x5e,0x00,0x00};
>     +static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff};
>     +uint32_t   tabl;
>     +Mc_Refcnt  *refcnt;
>     +
>     +       if ( ! (0x01 & enaddr[0]) ) {
>     +               /* not a multicast address; ignore */
>     +               return;
>     +       }
>     +
>     +       if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) {
>     +               /* broadcast address; ignore */
>     +               return;
>     +       }
>     +
>     +       if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) {
>     +               hash   = enaddr[5];
>     +               tabl   = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num);
>     +               refcnt = &mp->mc_refcnt.specl;
>     +       } else {
>     +               uint32_t test, mask;
>     +               int      i;
>     +               /* algorithm used by linux driver */
>     +               for ( hash=0, i=0; i<6; i++ ) {
>     +                       hash = (hash ^ enaddr[i]) << 8;
>     +                       for ( test=0x8000, mask=0x8380; test>0x0080;
>     test>>=1, mask>>=1 ) {
>     +                               if ( hash & test )
>     +                                       hash ^= mask;
>     +                       }
>     +               }
>     +               tabl   = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num);
>     +               refcnt = &mp->mc_refcnt.other;
>     +       }
>     +       del_entry(tabl, hash, refcnt);
>     +}
>     +
>     +/* Clear all address filters (multi- and unicast) */
>     +static void
>     +mveth_clear_addr_filters(struct mveth_private *mp)
>     +{
>     +register int      i;
>     +register uint32_t u;
>     +       u = MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num);
>     +       for (i=0; i<MV643XX_ETH_NUM_UNICAST_ENTRIES; i++) {
>     +               MV_WRITE(u,0);
>     +               u+=4;
>     +       }
>     +       BSP_mve_mcast_filter_clear(mp);
>     +}
>     +
>     +/* Setup unicast filter for a given MAC address (least significant nibble) */
>     +static void
>     +mveth_ucfilter(struct mveth_private *mp, unsigned char mac_lsbyte, int accept)
>     +{
>     +unsigned nib, slot, bit;
>     +uint32_t       val;
>     +       /* compute slot in table */
>     +       nib  = mac_lsbyte & 0xf;        /* strip nibble     */
>     +       slot = nib & ~3;                        /* (nibble/4)*4     */
>     +       bit  = (nib &  3)<<3;           /*  8*(nibble % 4)  */
>     +       val = MV_READ(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot);
>     +       if ( accept ) {
>     +               val |= 0x01 << bit;
>     +       } else {
>     +               val &= 0x0e << bit;
>     +       }
>     +       MV_WRITE(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot, val);
>     +}
>     +
>     +#if defined( ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM ) && 0
>     +/* Currently unused; small unaligned buffers seem to be rare
>     + * so we just use memcpy()...
>     + */
>     +
>     +/* memcpy for 0..7 bytes; arranged so that gcc
>     + * optimizes for powerpc...
>     + */
>     +
>     +static inline void memcpy8(void *to, void *fr, unsigned x)
>     +{
>     +register uint8_t *d = to, *s = fro;
>     +
>     +       d+=l; s+=l;
>     +       if ( l & 1 ) {
>     +               *--d=*--s;
>     +       }
>     +       if ( l & 2 ) {
>     +               /* pre-decrementing causes gcc to use auto-decrementing
>     +                * PPC instructions (lhzu rx, -2(ry))
>     +                */
>     +               d-=2; s-=2;
>     +               /* use memcpy; don't cast to short -- accessing
>     +                * misaligned data as short is not portable
>     +                * (but it works on PPC).
>     +                */
>     +               __builtin_memcpy(d,s,2);
>     +       }
>     +       if ( l & 4 ) {
>     +               d-=4; s-=4;
>     +               /* see above */
>     +               __builtin_memcpy(d,s,4);
>     +       }
>     +}
>     +#endif
>     +
>     +/* Assign values (buffer + user data) to a tx descriptor slot */
>     +static int
>     +mveth_assign_desc(MvEthTxDesc d, struct mbuf *m, unsigned long extra)
>     +{
>     +int rval = (d->byte_cnt = m->m_len);
>     +
>     +#ifdef MVETH_TESTING
>     +       assert( !d->mb      );
>     +       assert(  m->m_len   );
>     +#endif
>     +
>     +       /* set CRC on all descriptors; seems to be necessary */
>     +       d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
>     +
>     +#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
>     +       /* The buffer must be 64bit aligned if the payload is <8 (??) */
>     +       if ( rval < 8 && ((mtod(m, uintptr_t)) & 7) ) {
>     +               d->buf_ptr = CPUADDR2ENET( d->workaround );
>     +               memcpy((void*)d->workaround, mtod(m, void*), rval);
>     +       } else
>     +#endif
>     +       {
>     +               d->buf_ptr  = CPUADDR2ENET( mtod(m, unsigned long) );
>     +       }
>     +       d->l4i_chk  = 0;
>     +       return rval;
>     +}
>     +
>     +static int
>     +mveth_assign_desc_raw(MvEthTxDesc d, void *buf, int len, unsigned long extra)
>     +{
>     +int rval = (d->byte_cnt = len);
>     +
>     +#ifdef MVETH_TESTING
>     +       assert( !d->u_buf );
>     +       assert(  len   );
>     +#endif
>     +
>     +       /* set CRC on all descriptors; seems to be necessary */
>     +       d->cmd_sts  = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD);
>     +
>     +#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM
>     +       /* The buffer must be 64bit aligned if the payload is <8 (??) */
>     +       if ( rval < 8 && ( ((uintptr_t)buf) & 7) ) {
>     +               d->buf_ptr = CPUADDR2ENET( d->workaround );
>     +               memcpy((void*)d->workaround, buf, rval);
>     +       } else
>     +#endif
>     +       {
>     +               d->buf_ptr  = CPUADDR2ENET( (unsigned long)buf );
>     +       }
>     +       d->l4i_chk  = 0;
>     +       return rval;
>     +}
>     +
>     +/*
>     + * Ring Initialization
>     + *
>     + * ENDIAN ASSUMPTION: DMA engine matches CPU endianness (???)
>     + *
>     + * Linux driver discriminates __LITTLE and __BIG endian for re-arranging
>     + * the u16 fields in the descriptor structs. However, no endian conversion
>     + * is done on the individual fields (SDMA byte swapping is disabled on LE).
>     + */
>     +
>     +STATIC int
>     +mveth_init_rx_desc_ring(struct mveth_private *mp)
>     +{
>     +int i,sz;
>     +MvEthRxDesc    d;
>     +uintptr_t baddr;
>     +
>     +       memset((void*)mp->rx_ring, 0, sizeof(*mp->rx_ring)*mp->rbuf_count);
>     +
>     +       mp->rx_desc_dma = CPUADDR2ENET(mp->rx_ring);
>     +
>     +       for ( i=0, d = mp->rx_ring; i<mp->rbuf_count; i++, d++ ) {
>     +               d->u_buf = mp->alloc_rxbuf(&sz, &baddr);
>     +               assert( d->u_buf );
>     +
>     +#ifndef ENABLE_HW_SNOOPING
>     +               /* could reduce the area to max. ethernet packet size */
>     +               INVAL_BUF(baddr, sz);
>     +#endif
>     +
>     +               d->buf_size = sz;
>     +               d->byte_cnt = 0;
>     +               d->cmd_sts  = RDESC_DMA_OWNED | RDESC_INT_ENA;
>     +               d->next         = mp->rx_ring + (i+1) % mp->rbuf_count;
>     +
>     +               d->buf_ptr  = CPUADDR2ENET( baddr );
>     +               d->next_desc_ptr = CPUADDR2ENET(d->next);
>     +               FLUSH_DESC(d);
>     +       }
>     +       FLUSH_BARRIER();
>     +
>     +       mp->d_rx_t = mp->rx_ring;
>     +
>     +       /* point the chip to the start of the ring */
>     +     
>      MV_WRITE(MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->rx_desc_dma);
>     +
>     +
>     +       return i;
>     +}
>     +
>     +STATIC int
>     +mveth_init_tx_desc_ring(struct mveth_private *mp)
>     +{
>     +int i;
>     +MvEthTxDesc d;
>     +
>     +       memset((void*)mp->tx_ring, 0, sizeof(*mp->tx_ring)*mp->xbuf_count);
>     +
>     +       /* DMA and CPU live in the same address space (rtems) */
>     +       mp->tx_desc_dma = CPUADDR2ENET(mp->tx_ring);
>     +       mp->avail       = TX_AVAILABLE_RING_SIZE(mp);
>     +
>     +       for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++,d++ ) {
>     +               d->l4i_chk  = 0;
>     +               d->byte_cnt = 0;
>     +               d->cmd_sts  = 0;
>     +               d->buf_ptr  = 0;
>     +
>     +               d->next     = mp->tx_ring + (i+1) % mp->xbuf_count;
>     +               d->next_desc_ptr = CPUADDR2ENET(d->next);
>     +               FLUSH_DESC(d);
>     +       }
>     +       FLUSH_BARRIER();
>     +
>     +       mp->d_tx_h = mp->d_tx_t = mp->tx_ring;
>     +
>     +       /* point the chip to the start of the ring */
>     +     
>      MV_WRITE(MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->tx_desc_dma);
>     +
>     +       return i;
>     +}
>     +
>     +/* PUBLIC LOW-LEVEL DRIVER ACCESS */
>     +
>     +static struct mveth_private *
>     +mve_setup_internal(
>     +       int              unit,
>     +       rtems_id tid,
>     +       void     (*isr)(void*isr_arg),
>     +       void     *isr_arg,
>     +       void (*cleanup_txbuf)(void *user_buf, void *closure, int
>     error_on_tx_occurred),
>     +       void *cleanup_txbuf_arg,
>     +       void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
>     +       void (*consume_rxbuf)(void *user_buf, void *closure, int len),
>     +       void *consume_rxbuf_arg,
>     +       int             rx_ring_size,
>     +       int             tx_ring_size,
>     +       int             irq_mask
>     +)
>     +
>     +{
>     +struct mveth_private *mp;
>     +struct ifnet         *ifp;
>     +int                  InstallISRSuccessful;
>     +
>     +       if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
>     +               printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit,
>     MV643XXETH_NUM_DRIVER_SLOTS);
>     +               return 0;
>     +       }
>     +       ifp = &theMvEths[unit-1].arpcom.ac_if;
>     +       if ( ifp->if_init ) {
>     +               if ( ifp->if_init ) {
>     +                       printk(DRVNAME": instance %i already attached.\n",
>     unit);
>     +                       return 0;
>     +               }
>     +       }
>     +
>     +       if ( rx_ring_size < 0 && tx_ring_size < 0 )
>     +               return 0;
>     +
>     +       if ( MV_64360 != BSP_getDiscoveryVersion(0) ) {
>     +               printk(DRVNAME": not mv64360 chip\n");
>     +               return 0;
>     +       }
>     +
>     +       /* lazy init of mutex (non thread-safe! - we assume 1st
>     initialization is single-threaded) */
>     +       if ( ! mveth_mtx ) {
>     +               rtems_status_code sc;
>     +               sc = rtems_semaphore_create(
>     +                               rtems_build_name('m','v','e','X'),
>     +                               1,
>     +                               RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY |
>     RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES,
>     +                               0,
>     +                               &mveth_mtx);
>     +               if ( RTEMS_SUCCESSFUL != sc ) {
>     +                       rtems_error(sc,DRVNAME": creating mutex\n");
>     +                       rtems_panic("unable to proceed\n");
>     +               }
>     +       }
>     +
>     +       mp = &theMvEths[unit-1].pvt;
>     +
>     +       memset(mp, 0, sizeof(*mp));
>     +
>     +       mp->port_num          = unit-1;
>     +       mp->phy               = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >>
>     (5*mp->port_num)) & 0x1f;
>     +
>     +       mp->tid               = tid;
>     +       mp->isr               = isr;
>     +       mp->isr_arg           = isr_arg;
>     +
>     +       mp->cleanup_txbuf     = cleanup_txbuf;
>     +       mp->cleanup_txbuf_arg = cleanup_txbuf_arg;
>     +       mp->alloc_rxbuf       = alloc_rxbuf;
>     +       mp->consume_rxbuf     = consume_rxbuf;
>     +       mp->consume_rxbuf_arg = consume_rxbuf_arg;
>     +
>     +       mp->rbuf_count = rx_ring_size ? rx_ring_size : MV643XX_RX_RING_SIZE;
>     +       mp->xbuf_count = tx_ring_size ? tx_ring_size : MV643XX_TX_RING_SIZE;
>     +
>     +       if ( mp->xbuf_count > 0 )
>     +               mp->xbuf_count += TX_NUM_TAG_SLOTS;
>     +
>     +       if ( mp->rbuf_count < 0 )
>     +               mp->rbuf_count = 0;
>     +       if ( mp->xbuf_count < 0 )
>     +               mp->xbuf_count = 0;
>     +
>     +       /* allocate ring area; add 1 entry -- room for alignment */
>     +       assert( !mp->ring_area );
>     +       mp->ring_area = malloc(
>     +                                                       sizeof(*mp->ring_area) *
>     +                                                             
>      (mp->rbuf_count + mp->xbuf_count + 1),
>     +                                                       M_DEVBUF,
>     +                                                       M_WAIT );
>     +       assert( mp->ring_area );
>     +
>     +       BSP_mve_stop_hw(mp);
>     +
>     +       if ( irq_mask ) {
>     +               irq_data[mp->port_num].hdl = tid ? mveth_isr : mveth_isr_1;     
>     +               InstallISRSuccessful = BSP_install_rtems_irq_handler(
>     &irq_data[mp->port_num] );
>     +               assert( InstallISRSuccessful );
>     +       }
>     +
>     +       /* mark as used */
>     +       ifp->if_init = (void*)(-1);
>     +
>     +       if ( rx_ring_size < 0 )
>     +               irq_mask &= ~ MV643XX_ETH_IRQ_RX_DONE;
>     +       if ( tx_ring_size < 0 )
>     +               irq_mask &= ~ MV643XX_ETH_EXT_IRQ_TX_DONE;
>     +
>     +       mp->irq_mask = (irq_mask & MV643XX_ETH_IRQ_RX_DONE);
>     +       if ( (irq_mask &= (MV643XX_ETH_EXT_IRQ_TX_DONE |
>     MV643XX_ETH_EXT_IRQ_LINK_CHG)) ) {
>     +               mp->irq_mask |= MV643XX_ETH_IRQ_EXT_ENA;
>     +               mp->xirq_mask = irq_mask;
>     +       } else {
>     +               mp->xirq_mask = 0;
>     +       }
>     +
>     +       return mp;
>     +}
>     +
>     +struct mveth_private *
>     +BSP_mve_setup(
>     +       int              unit,
>     +       rtems_id tid,
>     +       void (*cleanup_txbuf)(void *user_buf, void *closure, int
>     error_on_tx_occurred),
>     +       void *cleanup_txbuf_arg,
>     +       void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
>     +       void (*consume_rxbuf)(void *user_buf, void *closure, int len),
>     +       void *consume_rxbuf_arg,
>     +       int             rx_ring_size,
>     +       int             tx_ring_size,
>     +       int             irq_mask
>     +)
>     +{
>     +       if ( irq_mask && 0 == tid ) {
>     +               printk(DRVNAME": must supply a TID if irq_msk not zero\n");
>     +               return 0;       
>     +       }
>     +
>     +       return mve_setup_internal(
>     +                               unit,
>     +                               tid,
>     +                               0, 0,
>     +                               cleanup_txbuf, cleanup_txbuf_arg,
>     +                               alloc_rxbuf,
>     +                               consume_rxbuf, consume_rxbuf_arg,
>     +                               rx_ring_size, tx_ring_size,
>     +                               irq_mask);
>     +}
>     +
>     +struct mveth_private *
>     +BSP_mve_setup_1(
>     +       int              unit,
>     +       void     (*isr)(void *isr_arg),
>     +       void     *isr_arg,
>     +       void (*cleanup_txbuf)(void *user_buf, void *closure, int
>     error_on_tx_occurred),
>     +       void *cleanup_txbuf_arg,
>     +       void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr),
>     +       void (*consume_rxbuf)(void *user_buf, void *closure, int len),
>     +       void *consume_rxbuf_arg,
>     +       int             rx_ring_size,
>     +       int             tx_ring_size,
>     +       int             irq_mask
>     +)
>     +{
>     +       if ( irq_mask && 0 == isr ) {
>     +               printk(DRVNAME": must supply an ISR if irq_msk not zero\n");
>     +               return 0;       
>     +       }
>     +
>     +       return mve_setup_internal(
>     +                               unit,
>     +                               0,
>     +                               isr, isr_arg,
>     +                               cleanup_txbuf, cleanup_txbuf_arg,
>     +                               alloc_rxbuf,
>     +                               consume_rxbuf, consume_rxbuf_arg,
>     +                               rx_ring_size, tx_ring_size,
>     +                               irq_mask);
>     +}
>     +
>     +rtems_id
>     +BSP_mve_get_tid(struct mveth_private *mp)
>     +{
>     +    return mp->tid;
>     +}
>     +
>     +int
>     +BSP_mve_detach(struct mveth_private *mp)
>     +{
>     +int unit = mp->port_num;
>     +       BSP_mve_stop_hw(mp);
>     +       if ( mp->irq_mask || mp->xirq_mask ) {
>     +               if ( !BSP_remove_rtems_irq_handler( &irq_data[mp->port_num] ) )
>     +                       return -1;
>     +       }
>     +       free( (void*)mp->ring_area, M_DEVBUF );
>     +       memset(mp, 0, sizeof(*mp));
>     +       __asm__ __volatile__("":::"memory");
>     +       /* mark as unused */
>     +       theMvEths[unit].arpcom.ac_if.if_init = 0;
>     +       return 0;
>     +}
>     +
>     +/* MAIN RX-TX ROUTINES
>     + *
>     + * BSP_mve_swipe_tx():  descriptor scavenger; releases mbufs
>     + * BSP_mve_send_buf():  xfer mbufs from IF to chip
>     + * BSP_mve_swipe_rx():  enqueue received mbufs to interface
>     + *                    allocate new ones and yield them to the
>     + *                    chip.
>     + */
>     +
>     +/* clean up the TX ring freeing up buffers */
>     +int
>     +BSP_mve_swipe_tx(struct mveth_private *mp)
>     +{
>     +int                                            rval = 0;
>     +register MvEthTxDesc   d;
>     +
>     +       for ( d = mp->d_tx_t; d->buf_ptr; d = NEXT_TXD(d) ) {
>     +
>     +               INVAL_DESC(d);
>     +
>     +               if (    (TDESC_DMA_OWNED & d->cmd_sts)
>     +                        &&     (uint32_t)d ==
>     MV_READ(MV643XX_ETH_CURRENT_SERVED_TX_DESC(mp->port_num)) )
>     +                       break;
>     +
>     +               /* d->u_buf is only set on the last descriptor in a chain;
>     +                * we only count errors in the last descriptor;
>     +                */
>     +               if ( d->u_buf ) {
>     +                       mp->cleanup_txbuf(d->u_buf, mp->cleanup_txbuf_arg,
>     (d->cmd_sts & TDESC_ERROR) ? 1 : 0);
>     +                       d->u_buf = 0;
>     +               }
>     +
>     +               d->buf_ptr = 0;
>     +
>     +               rval++;
>     +       }
>     +       mp->d_tx_t = d;
>     +       mp->avail += rval;
>     +
>     +       return rval;
>     +}
>     +
>     +/* allocate a new cluster and copy an existing chain there;
>     + * old chain is released...
>     + */
>     +static struct mbuf *
>     +repackage_chain(struct mbuf *m_head)
>     +{
>     +struct mbuf *m;
>     +       MGETHDR(m, M_DONTWAIT, MT_DATA);
>     +
>     +       if ( !m ) {
>     +               goto bail;
>     +       }
>     +
>     +       MCLGET(m, M_DONTWAIT);
>     +
>     +       if ( !(M_EXT & m->m_flags) ) {
>     +               m_freem(m);
>     +               m = 0;
>     +               goto bail;
>     +       }
>     +
>     +       m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t));
>     +       m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len;
>     +
>     +bail:
>     +       m_freem(m_head);
>     +       return m;
>     +}
>     +
>     +/* Enqueue a mbuf chain or a raw data buffer for transmission;
>     + * RETURN: #bytes sent or -1 if there are not enough descriptors
>     + *
>     + * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain.
>     + * OTOH, a raw data packet may be send (non-BSD driver) by pointing
>     + * m_head to the start of the data and passing 'len' > 0.
>     + *
>     + * Comments: software cache-flushing incurs a penalty if the
>     + *           packet cannot be queued since it is flushed anyways.
>     + *           The algorithm is slightly more efficient in the normal
>     + *                      case, though.
>     + */
>     +int
>     +BSP_mve_send_buf(struct mveth_private *mp, void *m_head, void *data_p, int len)
>     +{
>     +int                                            rval;
>     +register MvEthTxDesc   l,d,h;
>     +register struct mbuf   *m1;
>     +int                                            nmbs;
>     +int                                            ismbuf = (len <= 0);
>     +
>     +/* Only way to get here is when we discover that the mbuf chain
>     + * is too long for the tx ring
>     + */
>     +startover:
>     +
>     +       rval = 0;
>     +
>     +#ifdef MVETH_TESTING
>     +       assert(m_head);
>     +#endif
>     +
>     +       /* if no descriptor is available; try to wipe the queue */
>     +       if ( (mp->avail < 1) && MVETH_CLEAN_ON_SEND(mp)<=0 ) {
>     +               /* Maybe TX is stalled and needs to be restarted */
>     +               mveth_start_tx(mp);
>     +               return -1;
>     +       }
>     +
>     +       h = mp->d_tx_h;
>     +
>     +#ifdef MVETH_TESTING
>     +       assert( !h->buf_ptr );
>     +       assert( !h->mb      );
>     +#endif
>     +
>     +       if ( ! (m1 = m_head) )
>     +               return 0;
>     +
>     +       if ( ismbuf ) {
>     +               /* find first mbuf with actual data */
>     +               while ( 0 == m1->m_len ) {
>     +                       if ( ! (m1 = m1->m_next) ) {
>     +                               /* end reached and still no data to send ?? */
>     +                               m_freem(m_head);
>     +                               return 0;
>     +                       }
>     +               }
>     +       }
>     +
>     +       /* Don't use the first descriptor yet because BSP_mve_swipe_tx()
>     +        * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
>     +        * start with the second mbuf and fill the first descriptor
>     +        * last.
>     +        */
>     +
>     +       l = h;
>     +       d = NEXT_TXD(h);
>     +
>     +       mp->avail--;
>     +
>     +       nmbs = 1;
>     +       if ( ismbuf ) {
>     +                       register struct mbuf *m;
>     +                       for ( m=m1->m_next; m; m=m->m_next ) {
>     +                                       if ( 0 == m->m_len )
>     +                                                       continue;       /*
>     skip empty mbufs */
>     +
>     +                                       nmbs++;
>     +
>     +                                       if ( mp->avail < 1 &&
>     MVETH_CLEAN_ON_SEND(mp)<=0 ) {
>     +                                                       /* Maybe TX was
>     stalled - try to restart */
>     +                                                       mveth_start_tx(mp);
>     +
>     +                                                       /* not enough
>     descriptors; cleanup...
>     +                                                        * the first slot
>     was never used, so we start
>     +                                                        * at mp->d_tx_h->next;
>     +                                                        */
>     +                                                       for ( l =
>     NEXT_TXD(h); l!=d; l=NEXT_TXD(l) ) {
>     +#ifdef MVETH_TESTING
>     +                                                                     
>      assert( l->mb == 0 );
>     +#endif
>     +                                                                     
>      l->buf_ptr  = 0;
>     +                                                                     
>      l->cmd_sts  = 0;
>     +                                                                     
>      mp->avail++;
>     +                                                       }
>     +                                                       mp->avail++;
>     +                                                       if ( nmbs >
>     TX_AVAILABLE_RING_SIZE(mp) ) {
>     +                                                                       /*
>     this chain will never fit into the ring */
>     +                                                                       if (
>     nmbs > mp->stats.maxchain )
>     +                                                                           
>                mp->stats.maxchain = nmbs;
>     +                                                                     
>      mp->stats.repack++;
>     +                                                                       if (
>     ! (m_head = repackage_chain(m_head)) ) {
>     +                                                                           
>                /* no cluster available */
>     +                                                                           
>                mp->stats.odrops++;
>     +                                                                           
>                return 0;
>     +                                                                       }
>     +                                                                       goto
>     startover;
>     +                                                       }
>     +                                                       return -1;
>     +                                       }
>     +
>     +                                       mp->avail--;
>     +
>     +#ifdef MVETH_TESTING
>     +                                       assert( d != h      );
>     +                                       assert( !d->buf_ptr );
>     +#endif
>     +
>     +                                       /* fill this slot */
>     +                                       rval += mveth_assign_desc(d, m,
>     TDESC_DMA_OWNED);
>     +
>     +                                       FLUSH_BUF(mtod(m, uint32_t), m->m_len);
>     +
>     +                                       l = d;
>     +                                       d = NEXT_TXD(d);
>     +
>     +                                       FLUSH_DESC(l);
>     +                       }
>     +
>     +               /* fill first slot - don't release to DMA yet */
>     +               rval += mveth_assign_desc(h, m1, TDESC_FRST);
>     +
>     +
>     +               FLUSH_BUF(mtod(m1, uint32_t), m1->m_len);
>     +
>     +       } else {
>     +               /* fill first slot with raw buffer - don't release to DMA yet */
>     +               rval += mveth_assign_desc_raw(h, data_p, len, TDESC_FRST);
>     +
>     +               FLUSH_BUF( (uint32_t)data_p, len);
>     +       }
>     +
>     +       /* tag last slot; this covers the case where 1st==last */
>     +       l->cmd_sts      |= TDESC_LAST | TDESC_INT_ENA;
>     +       /* mbuf goes into last desc */
>     +       l->u_buf         = m_head;
>     +
>     +
>     +       FLUSH_DESC(l);
>     +
>     +       /* Tag end; make sure chip doesn't try to read ahead of here! */
>     +       l->next->cmd_sts = 0;
>     +       FLUSH_DESC(l->next);
>     +
>     +#ifdef MVETH_DEBUG_TX_DUMP
>     +       if ( (mveth_tx_dump & (1<<mp->port_num)) ) {
>     +               int ll,kk;
>     +               if ( ismbuf ) {
>     +                       struct mbuf *m;
>     +                       for ( kk=0, m=m_head; m; m=m->m_next) {
>     +                               for ( ll=0; ll<m->m_len; ll++ ) {
>     +                                       printf("%02X ",*(mtod(m,char*) + ll));
>     +                                       if ( ((++kk)&0xf) == 0 )
>     +                                               printf("\n");
>     +                               }
>     +                       }
>     +               } else {
>     +                       for ( ll=0; ll<len; ) {
>     +                               printf("%02X ",*((char*)data_p + ll));
>     +                               if ( ((++ll)&0xf) == 0 )
>     +                                       printf("\n");
>     +                       }       
>     +               }
>     +               printf("\n");
>     +       }
>     +#endif
>     +
>     +       membarrier();
>     +
>     +       /* turn over the whole chain by flipping ownership of the first desc */
>     +       h->cmd_sts |= TDESC_DMA_OWNED;
>     +
>     +       FLUSH_DESC(h);
>     +
>     +       membarrier();
>     +
>     +       /* notify the device */
>     +       MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_TX_START(0));
>     +
>     +       /* Update softc */
>     +       mp->stats.packet++;
>     +       if ( nmbs > mp->stats.maxchain )
>     +               mp->stats.maxchain = nmbs;
>     +
>     +       /* remember new head */
>     +       mp->d_tx_h = d;
>     +
>     +       return rval; /* #bytes sent */
>     +}
>     +
>     +int
>     +BSP_mve_send_buf_raw(
>     +       struct mveth_private *mp,
>     +       void                 *head_p,
>     +       int                   h_len,
>     +       void                 *data_p,
>     +    int                   d_len)
>     +{
>     +int                                            rval;
>     +register MvEthTxDesc   l,d,h;
>     +int                                            needed;
>     +void                    *frst_buf;
>     +int                     frst_len;
>     +
>     +       rval = 0;
>     +
>     +#ifdef MVETH_TESTING
>     +       assert(header || data);
>     +#endif
>     +
>     +       needed = head_p && data_p ? 2 : 1;
>     +
>     +       /* if no descriptor is available; try to wipe the queue */
>     +       if (   ( mp->avail < needed )
>     +        && ( MVETH_CLEAN_ON_SEND(mp) <= 0 || mp->avail < needed ) ) {
>     +               /* Maybe TX was stalled and needs a restart */
>     +               mveth_start_tx(mp);
>     +               return -1;
>     +       }
>     +
>     +       h = mp->d_tx_h;
>     +
>     +#ifdef MVETH_TESTING
>     +       assert( !h->buf_ptr );
>     +       assert( !h->mb      );
>     +#endif
>     +
>     +       /* find the 'first' user buffer */
>     +       if ( (frst_buf = head_p) ) {
>     +               frst_len = h_len;
>     +       } else {
>     +               frst_buf = data_p;
>     +               frst_len = d_len;
>     +       }
>     +
>     +       /* Don't use the first descriptor yet because BSP_mve_swipe_tx()
>     +        * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we
>     +        * start with the second (optional) slot and fill the first
>     +     * descriptor last.
>     +        */
>     +
>     +       l = h;
>     +       d = NEXT_TXD(h);
>     +
>     +       mp->avail--;
>     +
>     +       if ( needed > 1 ) {
>     +               mp->avail--;
>     +#ifdef MVETH_TESTING
>     +               assert( d != h      );
>     +               assert( !d->buf_ptr );
>     +#endif
>     +               rval += mveth_assign_desc_raw(d, data_p, d_len,
>     TDESC_DMA_OWNED);
>     +               FLUSH_BUF( (uint32_t)data_p, d_len );
>     +               d->u_buf = data_p;
>     +
>     +               l = d;
>     +               d = NEXT_TXD(d);
>     +
>     +               FLUSH_DESC(l);
>     +       }
>     +
>     +       /* fill first slot with raw buffer - don't release to DMA yet */
>     +       rval       += mveth_assign_desc_raw(h, frst_buf, frst_len, TDESC_FRST);
>     +
>     +       FLUSH_BUF( (uint32_t)frst_buf, frst_len);
>     +
>     +       /* tag last slot; this covers the case where 1st==last */
>     +       l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA;
>     +
>     +       /* first buffer of 'chain' goes into last desc */
>     +       l->u_buf    = frst_buf;
>     +
>     +       FLUSH_DESC(l);
>     +
>     +       /* Tag end; make sure chip doesn't try to read ahead of here! */
>     +       l->next->cmd_sts = 0;
>     +       FLUSH_DESC(l->next);
>     +
>     +       membarrier();
>     +
>     +       /* turn over the whole chain by flipping ownership of the first desc */
>     +       h->cmd_sts |= TDESC_DMA_OWNED;
>     +
>     +       FLUSH_DESC(h);
>     +
>     +       membarrier();
>     +
>     +       /* notify the device */
>     +       MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_TX_START(0));
>     +
>     +       /* Update softc */
>     +       mp->stats.packet++;
>     +       if ( needed > mp->stats.maxchain )
>     +               mp->stats.maxchain = needed;
>     +
>     +       /* remember new head */
>     +       mp->d_tx_h = d;
>     +
>     +       return rval; /* #bytes sent */
>     +}
>     +
>     +/* send received buffers upwards and replace them
>     + * with freshly allocated ones;
>     + * ASSUMPTION: buffer length NEVER changes and is set
>     + *                             when the ring is initialized.
>     + * TS 20060727: not sure if this assumption is still necessary - I believe
>     it isn't.
>     + */
>     +
>     +int
>     +BSP_mve_swipe_rx(struct mveth_private *mp)
>     +{
>     +int                                            rval = 0, err;
>     +register MvEthRxDesc   d;
>     +void                                   *newbuf;
>     +int                                            sz;
>     +uintptr_t                              baddr;
>     +
>     +       for ( d = mp->d_rx_t; ! (INVAL_DESC(d), (RDESC_DMA_OWNED &
>     d->cmd_sts)); d=NEXT_RXD(d) ) {
>     +
>     +#ifdef MVETH_TESTING
>     +               assert(d->u_buf);
>     +#endif
>     +
>     +               err = (RDESC_ERROR & d->cmd_sts);
>     +
>     +               if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) {
>     +                       /* drop packet and recycle buffer */
>     +                       newbuf = d->u_buf;
>     +                       mp->consume_rxbuf(0, mp->consume_rxbuf_arg, err ? -1
>     : 0);
>     +               } else {
>     +#ifdef MVETH_TESTING
>     +                       assert( d->byte_cnt > 0 );
>     +#endif
>     +                       mp->consume_rxbuf(d->u_buf, mp->consume_rxbuf_arg,
>     d->byte_cnt);
>     +
>     +#ifndef ENABLE_HW_SNOOPING
>     +                       /* could reduce the area to max. ethernet packet size */
>     +                       INVAL_BUF(baddr, sz);
>     +#endif
>     +                       d->u_buf    = newbuf;
>     +                       d->buf_ptr  = CPUADDR2ENET(baddr);
>     +                       d->buf_size = sz;
>     +                       FLUSH_DESC(d);
>     +               }
>     +
>     +               membarrier();
>     +
>     +               d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA;
>     +
>     +               FLUSH_DESC(d);
>     +
>     +               rval++;
>     +       }
>     +       MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_RX_START(0));
>     +       mp->d_rx_t = d;
>     +       return rval;
>     +}
>     +
>     +/* Stop hardware and clean out the rings */
>     +void
>     +BSP_mve_stop_hw(struct mveth_private *mp)
>     +{
>     +MvEthTxDesc    d;
>     +MvEthRxDesc    r;
>     +int                    i;
>     +
>     +       mveth_disable_irqs(mp, -1);
>     +
>     +       mveth_stop_tx(mp->port_num);
>     +
>     +       /* cleanup TX rings */
>     +       if (mp->d_tx_t) { /* maybe ring isn't initialized yet */
>     +               for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
>     +                       /* should be safe to clear ownership */
>     +                       d->cmd_sts &= ~TDESC_DMA_OWNED;
>     +                       FLUSH_DESC(d);
>     +               }
>     +               FLUSH_BARRIER();
>     +
>     +               BSP_mve_swipe_tx(mp);
>     +
>     +#ifdef MVETH_TESTING
>     +               assert( mp->d_tx_h == mp->d_tx_t );
>     +               for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) {
>     +                       assert( !d->buf_ptr );
>     +               }
>     +#endif
>     +       }
>     +
>     +       MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_RX_STOP_ALL);
>     +       while ( MV643XX_ETH_RX_ANY_RUNNING &
>     MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num)) )
>     +               /* poll-wait */;
>     +
>     +       /* stop serial port */
>     +       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
>     +               MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num))
>     +               & ~( MV643XX_ETH_SERIAL_PORT_ENBL |
>     MV643XX_ETH_FORCE_LINK_FAIL_DISABLE | MV643XX_ETH_FORCE_LINK_PASS)
>     +               );
>     +
>     +       /* clear pending interrupts */
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
>     +
>     +       /* cleanup RX rings */
>     +       if ( mp->rx_ring ) {
>     +               for ( i=0, r=mp->rx_ring; i<mp->rbuf_count; i++, r++ ) {
>     +                       /* should be OK to clear ownership flag */
>     +                       r->cmd_sts = 0;
>     +                       FLUSH_DESC(r);
>     +                       mp->consume_rxbuf(r->u_buf, mp->consume_rxbuf_arg, 0);
>     +                       r->u_buf = 0;
>     +               }
>     +               FLUSH_BARRIER();
>     +       }
>     +
>     +
>     +}
>     +
>     +uint32_t mveth_serial_ctrl_config_val = MVETH_SERIAL_CTRL_CONFIG_VAL;
>     +
>     +/* Fire up the low-level driver
>     + *
>     + * - make sure hardware is halted
>     + * - enable cache snooping
>     + * - clear address filters
>     + * - clear mib counters
>     + * - reset phy
>     + * - initialize (or reinitialize) descriptor rings
>     + * - check that the firmware has set up a reasonable mac address.
>     + * - generate unicast filter entry for our mac address
>     + * - write register config values to the chip
>     + * - start hardware (serial port and SDMA)
>     + */
>     +
>     +void
>     +BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr)
>     +{
>     +int                                    i;
>     +uint32_t                       v;
>     +static int                     inited = 0;
>     +
>     +#ifdef MVETH_DEBUG
>     +       printk(DRVNAME"%i: Entering BSP_mve_init_hw()\n", mp->port_num+1);
>     +#endif
>     +
>     +       /* since enable/disable IRQ routine only operate on select bitsets
>     +        * we must make sure everything is masked initially.
>     +        */
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num),        0);
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), 0);
>     +
>     +       BSP_mve_stop_hw(mp);
>     +
>     +       memset(&mp->stats, 0, sizeof(mp->stats));
>     +
>     +       mp->promisc = promisc;
>     +
>     +       /* MotLoad has cache snooping disabled on the ENET2MEM windows.
>     +        * Some comments in (linux) indicate that there are errata
>     +        * which cause problems which would be a real bummer.
>     +        * We try it anyways...
>     +        */
>     +       if ( !inited ) {
>     +       unsigned long disbl, bar;
>     +               inited = 1;     /* FIXME: non-thread safe lazy init */
>     +               disbl = MV_READ(MV643XX_ETH_BAR_ENBL_R);
>     +                       /* disable all 6 windows */
>     +                       MV_WRITE(MV643XX_ETH_BAR_ENBL_R,
>     MV643XX_ETH_BAR_DISBL_ALL);
>     +                       /* set WB snooping on enabled bars */
>     +                       for ( i=0; i<MV643XX_ETH_NUM_BARS*8; i+=8 ) {
>     +                               if ( (bar = MV_READ(MV643XX_ETH_BAR_0 + i))
>     && MV_READ(MV643XX_ETH_SIZE_R_0 + i) ) {
>     +#ifdef ENABLE_HW_SNOOPING
>     +                                       MV_WRITE(MV643XX_ETH_BAR_0 + i, bar
>     | MV64360_ENET2MEM_SNOOP_WB);
>     +#else
>     +                                       MV_WRITE(MV643XX_ETH_BAR_0 + i, bar
>     & ~MV64360_ENET2MEM_SNOOP_MSK);
>     +#endif
>     +                                       /* read back to flush fifo [linux
>     comment] */
>     +                                       (void)MV_READ(MV643XX_ETH_BAR_0 + i);
>     +                               }
>     +                       }
>     +                       /* restore/re-enable */
>     +               MV_WRITE(MV643XX_ETH_BAR_ENBL_R, disbl);
>     +       }
>     +
>     +       mveth_clear_mib_counters(mp);
>     +       mveth_clear_addr_filters(mp);
>     +
>     +/*     Just leave it alone...
>     +       reset_phy();
>     +*/
>     +
>     +       if ( mp->rbuf_count > 0 ) {
>     +               mp->rx_ring = (MvEthRxDesc)MV643XX_ALIGN(mp->ring_area,
>     RING_ALIGNMENT);
>     +               mveth_init_rx_desc_ring(mp);
>     +       }
>     +
>     +       if ( mp->xbuf_count > 0 ) {
>     +               mp->tx_ring = (MvEthTxDesc)mp->rx_ring + mp->rbuf_count;
>     +               mveth_init_tx_desc_ring(mp);
>     +       }
>     +
>     +       if ( enaddr ) {
>     +               /* set ethernet address from arpcom struct */
>     +#ifdef MVETH_DEBUG
>     +               printk(DRVNAME"%i: Writing MAC addr ", mp->port_num+1);
>     +               for (i=5; i>=0; i--) {
>     +                       printk("%02X%c", enaddr[i], i?':':'\n');
>     +               }
>     +#endif
>     +               mveth_write_eaddr(mp, enaddr);
>     +       }
>     +
>     +       /* set mac address and unicast filter */
>     +
>     +       {
>     +       uint32_t machi, maclo;
>     +               maclo = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
>     +               machi = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
>     +               /* ASSUME: firmware has set the mac address for us
>     +                *         - if assertion fails, we have to do more work...
>     +                */
>     +               assert( maclo && machi && maclo != 0xffffffff && machi !=
>     0xffffffff );
>     +               mveth_ucfilter(mp, maclo&0xff, 1/* accept */);
>     +       }
>     +       
>     +       /* port, serial and sdma configuration */
>     +       v = MVETH_PORT_CONFIG_VAL;
>     +       if ( promisc ) {
>     +               /* multicast filters were already set up to
>     +                * accept everything (mveth_clear_addr_filters())
>     +                */
>     +               v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
>     +       } else {
>     +               v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
>     +       }
>     +       MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num),
>     +                               v);
>     +       MV_WRITE(MV643XX_ETH_PORT_CONFIG_XTEND_R(mp->port_num),
>     +                               MVETH_PORT_XTEND_CONFIG_VAL);
>     +
>     +       v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
>     +       v &= ~(MVETH_SERIAL_CTRL_CONFIG_MSK);
>     +       v |= mveth_serial_ctrl_config_val;
>     +       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), v);
>     +
>     +       i = IFM_MAKEWORD(0, 0, 0, 0);
>     +       if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &i) ) {
>     +           if ( (IFM_LINK_OK & i) ) {
>     +                       mveth_update_serial_port(mp, i);
>     +               }
>     +       }
>     +
>     +       /* enable serial port */
>     +       v  = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num));
>     +       MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num),
>     +                               v | MV643XX_ETH_SERIAL_PORT_ENBL);
>     +
>     +#ifndef __BIG_ENDIAN__
>     +#error "byte swapping needs to be disabled for little endian machines"
>     +#endif
>     +       MV_WRITE(MV643XX_ETH_SDMA_CONFIG_R(mp->port_num),
>     MVETH_SDMA_CONFIG_VAL);
>     +
>     +       /* allow short frames */
>     +       MV_WRITE(MV643XX_ETH_RX_MIN_FRAME_SIZE_R(mp->port_num),
>     MVETH_MIN_FRAMSZ_CONFIG_VAL);
>     +
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0);
>     +       MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0);
>     +       /* TODO: set irq coalescing */
>     +
>     +       /* enable Rx */
>     +       if ( mp->rbuf_count > 0 ) {
>     +               MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num),
>     MV643XX_ETH_RX_START(0));
>     +       }
>     +
>     +       mveth_enable_irqs(mp, -1);
>     +
>     +#ifdef MVETH_DEBUG
>     +       printk(DRVNAME"%i: Leaving BSP_mve_init_hw()\n", mp->port_num+1);
>     +#endif
>     +}
>     +
>     +/* read ethernet address from hw to buffer */
>     +void
>     +BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr)
>     +{
>     +int                            i;
>     +uint32_t               x;
>     +unsigned char  buf[6], *eaddr;
>     +
>     +       eaddr = oeaddr ? oeaddr : buf;
>     +
>     +       eaddr += 5;
>     +       x = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num));
>     +
>     +       /* lo word */
>     +       for (i=2; i; i--, eaddr--) {
>     +               *eaddr = (unsigned char)(x & 0xff);
>     +               x>>=8;
>     +       }
>     +
>     +       x = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num));
>     +       /* hi word */
>     +       for (i=4; i; i--, eaddr--) {
>     +               *eaddr = (unsigned char)(x & 0xff);
>     +               x>>=8;
>     +       }
>     +
>     +       if ( !oeaddr ) {
>     +               printf("%02X",buf[0]);
>     +               for (i=1; i<sizeof(buf); i++)
>     +                       printf(":%02X",buf[i]);
>     +               printf("\n");
>     +       }
>     +}
>     +
>     +int
>     +BSP_mve_media_ioctl(struct mveth_private *mp, int cmd, int *parg)
>     +{
>     +int rval;
>     +       /* alias cmd == 0,1 */
>     +       switch ( cmd ) {
>     +               case 0: cmd = SIOCGIFMEDIA;
>     +                       break;
>     +               case 1: cmd = SIOCSIFMEDIA;
>     +               case SIOCGIFMEDIA:
>     +               case SIOCSIFMEDIA:
>     +                       break;
>     +               default: return -1;
>     +       }
>     +       REGLOCK();
>     +       rval = rtems_mii_ioctl(&mveth_mdio, mp, cmd, parg);
>     +       REGUNLOCK();
>     +       return rval;
>     +}
>     +
>     +void
>     +BSP_mve_enable_irqs(struct mveth_private *mp)
>     +{
>     +       mveth_enable_irqs(mp, -1);
>     +}
>     +
>     +void
>     +BSP_mve_disable_irqs(struct mveth_private *mp)
>     +{
>     +       mveth_disable_irqs(mp, -1);
>     +}
>     +
>     +uint32_t
>     +BSP_mve_ack_irqs(struct mveth_private *mp)
>     +{
>     +       return mveth_ack_irqs(mp, -1);
>     +}
>     +
>     +
>     +void
>     +BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t mask)
>     +{
>     +       mveth_enable_irqs(mp, mask);
>     +}
>     +
>     +uint32_t
>     +BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t mask)
>     +{
>     +       return mveth_disable_irqs(mp, mask);
>     +}
>     +
>     +uint32_t
>     +BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask)
>     +{
>     +       return mveth_ack_irqs(mp, mask);
>     +}
>     +
>     +int
>     +BSP_mve_ack_link_chg(struct mveth_private *mp, int *pmedia)
>     +{
>     +int media = IFM_MAKEWORD(0,0,0,0);
>     +
>     +       if ( 0 == BSP_mve_media_ioctl(mp, SIOCGIFMEDIA, &media)) {
>     +               if ( IFM_LINK_OK & media ) {
>     +                       mveth_update_serial_port(mp, media);
>     +                       /* If TX stalled because there was no buffer then
>     whack it */
>     +                       mveth_start_tx(mp);
>     +               }
>     +               if ( pmedia )
>     +                       *pmedia = media;
>     +               return 0;
>     +       }
>     +       return -1;
>     +}
>     +
>     +/* BSDNET SUPPORT/GLUE ROUTINES */
>     +
>     +static void
>     +mveth_set_filters(struct ifnet *ifp);
>     +
>     +STATIC void
>     +mveth_stop(struct mveth_softc *sc)
>     +{
>     +       BSP_mve_stop_hw(&sc->pvt);
>     +       sc->arpcom.ac_if.if_timer = 0;
>     +}
>     +
>     +/* allocate a mbuf for RX with a properly aligned data buffer
>     + * RETURNS 0 if allocation fails
>     + */
>     +static void *
>     +alloc_mbuf_rx(int *psz, uintptr_t *paddr)
>     +{
>     +struct mbuf            *m;
>     +unsigned long  l,o;
>     +
>     +       MGETHDR(m, M_DONTWAIT, MT_DATA);
>     +       if ( !m )
>     +               return 0;
>     +       MCLGET(m, M_DONTWAIT);
>     +       if ( ! (m->m_flags & M_EXT) ) {
>     +               m_freem(m);
>     +               return 0;
>     +       }
>     +
>     +       o = mtod(m, unsigned long);
>     +       l = MV643XX_ALIGN(o, RX_BUF_ALIGNMENT) - o;
>     +
>     +       /* align start of buffer */
>     +       m->m_data += l;
>     +
>     +       /* reduced length */
>     +       l = MCLBYTES - l;
>     +
>     +       m->m_len   = m->m_pkthdr.len = l;
>     +       *psz       = m->m_len;
>     +       *paddr     = mtod(m, uintptr_t);
>     +
>     +       return (void*) m;
>     +}
>     +
>     +static void consume_rx_mbuf(void *buf, void *arg, int len)
>     +{
>     +struct ifnet *ifp = arg;
>     +struct mbuf    *m = buf;
>     +
>     +       if ( len <= 0 ) {
>     +               ifp->if_iqdrops++;
>     +               if ( len < 0 ) {
>     +                       ifp->if_ierrors++;
>     +               }
>     +               if ( m )
>     +                       m_freem(m);
>     +       } else {
>     +               struct ether_header *eh;
>     +
>     +                       eh                      = (struct ether_header
>     *)(mtod(m, unsigned long) + ETH_RX_OFFSET);
>     +                       m->m_len        = m->m_pkthdr.len = len -
>     sizeof(struct ether_header) - ETH_RX_OFFSET - ETH_CRC_LEN;
>     +                       m->m_data  += sizeof(struct ether_header) +
>     ETH_RX_OFFSET;
>     +                       m->m_pkthdr.rcvif = ifp;
>     +
>     +                       ifp->if_ipackets++;
>     +                       ifp->if_ibytes  += m->m_pkthdr.len;
>     +                       
>     +                       if (0) {
>     +                               /* Low-level debugging */
>     +                               int i;
>     +                               for (i=0; i<13; i++) {
>     +                                       printf("%02X:",((char*)eh)[i]);
>     +                               }
>     +                               printf("%02X\n",((char*)eh)[i]);
>     +                               for (i=0; i<m->m_len; i++) {
>     +                                       if ( !(i&15) )
>     +                                               printf("\n");
>     +                                       printf("0x%02x ",mtod(m,char*)[i]);
>     +                               }
>     +                               printf("\n");
>     +                       }
>     +
>     +                       if (0) {
>     +                               /* Low-level debugging/testing without bsd
>     stack */
>     +                               m_freem(m);
>     +                       } else {
>     +                               /* send buffer upwards */
>     +                               ether_input(ifp, eh, m);
>     +                       }
>     +       }
>     +}
>     +
>     +static void release_tx_mbuf(void *buf, void *arg, int err)
>     +{
>     +struct ifnet *ifp = arg;
>     +struct mbuf  *mb  = buf;
>     +
>     +       if ( err ) {
>     +               ifp->if_oerrors++;
>     +       } else {
>     +               ifp->if_opackets++;
>     +       }
>     +       ifp->if_obytes += mb->m_pkthdr.len;
>     +       m_freem(mb);
>     +}
>     +
>     +static void
>     +dump_update_stats(struct mveth_private *mp, FILE *f)
>     +{
>     +int      p = mp->port_num;
>     +int      idx;
>     +uint32_t v;
>     +
>     +       if ( !f )
>     +               f = stdout;
>     +
>     +       fprintf(f, DRVNAME"%i Statistics:\n",        mp->port_num + 1);
>     +       fprintf(f, "  # IRQS:                 %i\n", mp->stats.irqs);
>     +       fprintf(f, "  Max. mbuf chain length: %i\n", mp->stats.maxchain);
>     +       fprintf(f, "  # repacketed:           %i\n", mp->stats.repack);
>     +       fprintf(f, "  # packets:              %i\n", mp->stats.packet);
>     +       fprintf(f, "MIB Counters:\n");
>     +       for ( idx = MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2;
>     +                       idx < MV643XX_ETH_NUM_MIB_COUNTERS;
>     +                       idx++ ) {
>     +               switch ( idx ) {
>     +                       case MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2:
>     +                               mp->stats.mib.good_octs_rcvd +=
>     read_long_mib_counter(p, idx);
>     +                               fprintf(f, mibfmt[idx],
>     mp->stats.mib.good_octs_rcvd);
>     +                               idx++;
>     +                               break;
>     +
>     +                       case MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO>>2:
>     +                               mp->stats.mib.good_octs_sent +=
>     read_long_mib_counter(p, idx);
>     +                               fprintf(f, mibfmt[idx],
>     mp->stats.mib.good_octs_sent);
>     +                               idx++;
>     +                               break;
>     +
>     +                       default:
>     +                               v = ((uint32_t*)&mp->stats.mib)[idx] +=
>     read_mib_counter(p, idx);
>     +                               fprintf(f, mibfmt[idx], v);
>     +                               break;
>     +               }
>     +       }
>     +       fprintf(f, "\n");
>     +}
>     +
>     +void
>     +BSP_mve_dump_stats(struct mveth_private *mp, FILE *f)
>     +{
>     +       dump_update_stats(mp, f);
>     +}
>     +
>     +/* BSDNET DRIVER CALLBACKS */
>     +
>     +static void
>     +mveth_init(void *arg)
>     +{
>     +struct mveth_softc     *sc  = arg;
>     +struct ifnet           *ifp = &sc->arpcom.ac_if;
>     +int                 media;
>     +
>     +       BSP_mve_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC,
>     sc->arpcom.ac_enaddr);
>     +
>     +       media = IFM_MAKEWORD(0, 0, 0, 0);
>     +       if ( 0 == BSP_mve_media_ioctl(&sc->pvt, SIOCGIFMEDIA, &media) ) {
>     +           if ( (IFM_LINK_OK & media) ) {
>     +                       ifp->if_flags &= ~IFF_OACTIVE;
>     +               } else {
>     +                       ifp->if_flags |= IFF_OACTIVE;
>     +               }
>     +       }
>     +
>     +       /* if promiscuous then there is no need to change */
>     +       if ( ! (ifp->if_flags & IFF_PROMISC) )
>     +               mveth_set_filters(ifp);
>     +
>     +       ifp->if_flags |= IFF_RUNNING;
>     +       sc->arpcom.ac_if.if_timer = 0;
>     +}
>     +
>     +/* bsdnet driver entry to start transmission */
>     +static void
>     +mveth_start(struct ifnet *ifp)
>     +{
>     +struct mveth_softc     *sc = ifp->if_softc;
>     +struct mbuf                    *m  = 0;
>     +
>     +       while ( ifp->if_snd.ifq_head ) {
>     +               IF_DEQUEUE( &ifp->if_snd, m );
>     +               if ( BSP_mve_send_buf(&sc->pvt, m, 0, 0) < 0 ) {
>     +                       IF_PREPEND( &ifp->if_snd, m);
>     +                       ifp->if_flags |= IFF_OACTIVE;
>     +                       break;
>     +               }
>     +               /* need to do this really only once
>     +                * but it's cheaper this way.
>     +                */
>     +               ifp->if_timer = 2*IFNET_SLOWHZ;
>     +       }
>     +}
>     +
>     +/* bsdnet driver entry; */
>     +static void
>     +mveth_watchdog(struct ifnet *ifp)
>     +{
>     +struct mveth_softc     *sc = ifp->if_softc;
>     +
>     +       ifp->if_oerrors++;
>     +       printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit);
>     +
>     +       mveth_init(sc);
>     +       mveth_start(ifp);
>     +}
>     +
>     +static void
>     +mveth_set_filters(struct ifnet *ifp)
>     +{
>     +struct mveth_softc  *sc = ifp->if_softc;
>     +uint32_t              v;
>     +
>     +       v = MV_READ(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num));
>     +       if ( ifp->if_flags & IFF_PROMISC )
>     +               v |= MV643XX_ETH_UNICAST_PROMISC_MODE;
>     +       else
>     +               v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE;
>     +       MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(sc->pvt.port_num), v);
>     +
>     +       if ( ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI) ) {
>     +               BSP_mve_mcast_filter_accept_all(&sc->pvt);
>     +       } else {
>     +               struct ether_multi     *enm;
>     +               struct ether_multistep step;
>     +
>     +               BSP_mve_mcast_filter_clear( &sc->pvt );
>     +               
>     +               ETHER_FIRST_MULTI(step, (struct arpcom *)ifp, enm);
>     +
>     +               while ( enm ) {
>     +                       if ( memcmp(enm->enm_addrlo, enm->enm_addrhi,
>     ETHER_ADDR_LEN) )
>     +                               assert( !"Should never get here;
>     IFF_ALLMULTI should be set!" );
>     +
>     +                       BSP_mve_mcast_filter_accept_add(&sc->pvt,
>     enm->enm_addrlo);
>     +
>     +                       ETHER_NEXT_MULTI(step, enm);
>     +               }
>     +       }
>     +}
>     +
>     +/* bsdnet driver ioctl entry */
>     +static int
>     +mveth_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
>     +{
>     +struct mveth_softc     *sc   = ifp->if_softc;
>     +struct ifreq           *ifr  = (struct ifreq *)data;
>     +int                                    error = 0;
>     +int                                    f;
>     +
>     +       switch ( cmd ) {
>     +               case SIOCSIFFLAGS:
>     +                       f = ifp->if_flags;
>     +                       if ( f & IFF_UP ) {
>     +                               if ( ! ( f & IFF_RUNNING ) ) {
>     +                                       mveth_init(sc);
>     +                               } else {
>     +                                       if ( (f & IFF_PROMISC) !=
>     (sc->bsd.oif_flags & IFF_PROMISC) ) {
>     +                                               /* Note: in all other
>     scenarios the 'promisc' flag
>     +                                                * in the low-level driver
>     [which affects the way
>     +                                                * the multicast filter is
>     setup: accept none vs.
>     +                                                * accept all in promisc
>     mode] is eventually
>     +                                                * set when the IF is
>     brought up...
>     +                                                */
>     +                                               sc->pvt.promisc = (f &
>     IFF_PROMISC);
>     +
>     +                                               mveth_set_filters(ifp);
>     +                                       }
>     +                                       /* FIXME: other flag changes are
>     ignored/unimplemented */
>     +                               }
>     +                       } else {
>     +                               if ( f & IFF_RUNNING ) {
>     +                                       mveth_stop(sc);
>     +                                       ifp->if_flags  &= ~(IFF_RUNNING |
>     IFF_OACTIVE);
>     +                               }
>     +                       }
>     +                       sc->bsd.oif_flags = ifp->if_flags;
>     +               break;
>     +
>     +               case SIOCGIFMEDIA:
>     +               case SIOCSIFMEDIA:
>     +                       error = BSP_mve_media_ioctl(&sc->pvt, cmd,
>     &ifr->ifr_media);
>     +               break;
>     +
>     +               case SIOCADDMULTI:
>     +               case SIOCDELMULTI:
>     +                       error = (cmd == SIOCADDMULTI)
>     +                               ? ether_addmulti(ifr, &sc->arpcom)
>     +                                   : ether_delmulti(ifr, &sc->arpcom);
>     +
>     +                       if (error == ENETRESET) {
>     +                               if (ifp->if_flags & IFF_RUNNING) {
>     +                                       mveth_set_filters(ifp);
>     +                               }
>     +                               error = 0;
>     +                       }
>     +               break;
>     +
>     +
>     +               break;
>     +
>     +               case SIO_RTEMS_SHOW_STATS:
>     +                       dump_update_stats(&sc->pvt, stdout);
>     +               break;
>     +
>     +               default:
>     +                       error = ether_ioctl(ifp, cmd, data);
>     +               break;
>     +       }
>     +
>     +       return error;
>     +}
>     +
>     +/* DRIVER TASK */
>     +
>     +/* Daemon task does all the 'interrupt' work */
>     +static void mveth_daemon(void *arg)
>     +{
>     +struct mveth_softc     *sc;
>     +struct ifnet           *ifp;
>     +rtems_event_set                evs;
>     +       for (;;) {
>     +               rtems_bsdnet_event_receive( 7, RTEMS_WAIT | RTEMS_EVENT_ANY,
>     RTEMS_NO_TIMEOUT, &evs );
>     +               evs &= 7;
>     +               for ( sc = theMvEths; evs; evs>>=1, sc++ ) {
>     +                       if ( (evs & 1) ) {
>     +                               register uint32_t x;
>     +
>     +                               ifp = &sc->arpcom.ac_if;
>     +
>     +                               if ( !(ifp->if_flags & IFF_UP) ) {
>     +                                       mveth_stop(sc);
>     +                                       ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
>     +                                       continue;
>     +                               }
>     +
>     +                               if ( !(ifp->if_flags & IFF_RUNNING) ) {
>     +                                       /* event could have been pending at
>     the time hw was stopped;
>     +                                        * just ignore...
>     +                                        */
>     +                                       continue;
>     +                               }
>     +
>     +                               x = mveth_ack_irqs(&sc->pvt, -1);
>     +
>     +                               if ( MV643XX_ETH_EXT_IRQ_LINK_CHG & x ) {
>     +                                       /* phy status changed */
>     +                                       int media;
>     +
>     +                                       if ( 0 ==
>     BSP_mve_ack_link_chg(&sc->pvt, &media) ) {
>     +                                               if ( IFM_LINK_OK & media ) {
>     +                                                       ifp->if_flags &=
>     ~IFF_OACTIVE;
>     +                                                       mveth_start(ifp);
>     +                                               } else {
>     +                                                       /* stop sending */
>     +                                                       ifp->if_flags |=
>     IFF_OACTIVE;
>     +                                               }
>     +                                       }
>     +                               }
>     +                               /* free tx chain */
>     +                               if ( (MV643XX_ETH_EXT_IRQ_TX_DONE & x) &&
>     BSP_mve_swipe_tx(&sc->pvt) ) {
>     +                                       ifp->if_flags &= ~IFF_OACTIVE;
>     +                                       if (
>     TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.avail )
>     +                                               ifp->if_timer = 0;
>     +                                       mveth_start(ifp);
>     +                               }
>     +                               if ( (MV643XX_ETH_IRQ_RX_DONE & x) )
>     +                                       BSP_mve_swipe_rx(&sc->pvt);
>     +
>     +                               mveth_enable_irqs(&sc->pvt, -1);
>     +                       }
>     +               }
>     +       }
>     +}
>     +
>     +#ifdef  MVETH_DETACH_HACK
>     +static int mveth_detach(struct mveth_softc *sc);
>     +#endif
>     +
>     +
>     +/* PUBLIC RTEMS BSDNET ATTACH FUNCTION */
>     +int
>     +rtems_mve_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching)
>     +{
>     +char                           *unitName;
>     +int                                    unit,i,cfgUnits;
>     +struct mveth_softc *sc;
>     +struct ifnet           *ifp;
>     +
>     +       unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName);
>     +       if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) {
>     +               printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit,
>     MV643XXETH_NUM_DRIVER_SLOTS);
>     +               return 1;
>     +       }
>     +
>     +       sc  = &theMvEths[unit-1];
>     +       ifp = &sc->arpcom.ac_if;
>     +       sc->pvt.port_num = unit-1;
>     +       sc->pvt.phy      = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >>
>     (5*sc->pvt.port_num)) & 0x1f;
>     +
>     +       if ( attaching ) {
>     +               if ( ifp->if_init ) {
>     +                       printk(DRVNAME": instance %i already attached.\n",
>     unit);
>     +                       return -1;
>     +               }
>     +
>     +               for ( i=cfgUnits = 0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
>     +                       if ( theMvEths[i].arpcom.ac_if.if_init )
>     +                               cfgUnits++;
>     +               }
>     +               cfgUnits++; /* this new one */
>     +
>     +               /* lazy init of TID should still be thread-safe because we
>     are protected
>     +                * by the global networking semaphore..
>     +                */
>     +               if ( !mveth_tid ) {
>     +                       /* newproc uses the 1st 4 chars of name string to
>     build an rtems name */
>     +                       mveth_tid = rtems_bsdnet_newproc("MVEd", 4096,
>     mveth_daemon, 0);
>     +               }
>     +
>     +               if ( !BSP_mve_setup( unit,
>     +                                                    mveth_tid,
>     +                                                    release_tx_mbuf, ifp,
>     +                                                    alloc_mbuf_rx,
>     +                                                    consume_rx_mbuf, ifp,
>     +                                                    ifcfg->rbuf_count,
>     +                                                    ifcfg->xbuf_count,
>     +                                        BSP_MVE_IRQ_TX | BSP_MVE_IRQ_RX |
>     BSP_MVE_IRQ_LINK) ) {
>     +                       return -1;
>     +               }
>     +
>     +               if ( nmbclusters < sc->pvt.rbuf_count * cfgUnits + 60 /*
>     arbitrary */ )  {
>     +                       printk(DRVNAME"%i: (mv643xx ethernet) Your
>     application has not enough mbuf clusters\n", unit);
>     +                       printk(     "                         configured for
>     this driver.\n");
>     +                       return -1;
>     +               }
>     +
>     +               if ( ifcfg->hardware_address ) {
>     +                       memcpy(sc->arpcom.ac_enaddr,
>     ifcfg->hardware_address, ETHER_ADDR_LEN);
>     +               } else {
>     +                       /* read back from hardware assuming that MotLoad
>     already had set it up */
>     +                       BSP_mve_read_eaddr(&sc->pvt, sc->arpcom.ac_enaddr);
>     +               }
>     +
>     +               ifp->if_softc                   = sc;
>     +               ifp->if_unit                    = unit;
>     +               ifp->if_name                    = unitName;
>     +
>     +               ifp->if_mtu                             = ifcfg->mtu ?
>     ifcfg->mtu : ETHERMTU;
>     +
>     +               ifp->if_init                    = mveth_init;
>     +               ifp->if_ioctl                   = mveth_ioctl;
>     +               ifp->if_start                   = mveth_start;
>     +               ifp->if_output                  = ether_output;
>     +               /*
>     +                * While nonzero, the 'if->if_timer' is decremented
>     +                * (by the networking code) at a rate of IFNET_SLOWHZ (1hz)
>     and 'if_watchdog'
>     +                * is called when it expires.
>     +                * If either of those fields is 0 the feature is disabled.
>     +                */
>     +               ifp->if_watchdog                = mveth_watchdog;
>     +               ifp->if_timer                   = 0;
>     +
>     +               sc->bsd.oif_flags               = /* ... */
>     +               ifp->if_flags                   = IFF_BROADCAST |
>     IFF_MULTICAST | IFF_SIMPLEX;
>     +
>     +               /*
>     +                * if unset, this set to 10Mbps by ether_ifattach; seems to
>     be unused by bsdnet stack;
>     +                * could be updated along with phy speed, though...
>     +               ifp->if_baudrate                = 10000000;
>     +               */
>     +
>     +               /* NOTE: ether_output drops packets if ifq_len >= ifq_maxlen
>     +                *       but this is the packet count, not the fragment count!
>     +               ifp->if_snd.ifq_maxlen  = sc->pvt.xbuf_count;
>     +               */
>     +               ifp->if_snd.ifq_maxlen  = ifqmaxlen;
>     +
>     +#ifdef  MVETH_DETACH_HACK
>     +               if ( !ifp->if_addrlist ) /* do only the first time [reattach
>     hack] */
>     +#endif
>     +               {
>     +                       if_attach(ifp);
>     +                       ether_ifattach(ifp);
>     +               }
>     +
>     +       } else {
>     +#ifdef  MVETH_DETACH_HACK
>     +               if ( !ifp->if_init ) {
>     +                       printk(DRVNAME": instance %i not attached.\n", unit);
>     +                       return -1;
>     +               }
>     +               return mveth_detach(sc);
>     +#else
>     +               printk(DRVNAME": interface detaching not implemented\n");
>     +               return -1;
>     +#endif
>     +       }
>     +
>     +       return 0;
>     +}
>     +
>     +/* EARLY PHY ACCESS */
>     +static int
>     +mveth_early_init(int idx)
>     +{
>     +       if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
>     +               return -1;
>     +
>     +       /* determine the phy */
>     +       theMvEths[idx].pvt.phy = (MV_READ(MV643XX_ETH_PHY_ADDR_R) >>
>     (5*idx)) & 0x1f;
>     +       return 0;
>     +}
>     +
>     +static int
>     +mveth_early_read_phy(int idx, unsigned reg)
>     +{
>     +int rval;
>     +
>     +       if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
>     +               return -1;
>     +
>     +       rval = mveth_mii_read(&theMvEths[idx].pvt, reg);
>     +       return rval < 0 ? rval : rval & 0xffff;
>     +}
>     +
>     +static int
>     +mveth_early_write_phy(int idx, unsigned reg, unsigned val)
>     +{
>     +       if ( idx < 0 || idx >= MV643XXETH_NUM_DRIVER_SLOTS )
>     +               return -1;
>     +
>     +       mveth_mii_write(&theMvEths[idx].pvt, reg, val);
>     +       return 0;
>     +}
>     +
>     +rtems_bsdnet_early_link_check_ops
>     +rtems_mve_early_link_check_ops = {
>     +       init:           mveth_early_init,
>     +       read_phy:       mveth_early_read_phy,
>     +       write_phy:      mveth_early_write_phy,
>     +       name:           DRVNAME,
>     +       num_slots:      MAX_NUM_SLOTS
>     +};
>     +
>     +/* DEBUGGING */
>     +
>     +#ifdef MVETH_DEBUG
>     +/* Display/dump descriptor rings */
>     +
>     +int
>     +mveth_dring(struct mveth_softc *sc)
>     +{
>     +int i;
>     +if (1) {
>     +MvEthRxDesc pr;
>     +printf("RX:\n");
>     +
>     +       for (i=0, pr=sc->pvt.rx_ring; i<sc->pvt.rbuf_count; i++, pr++) {
>     +#ifndef ENABLE_HW_SNOOPING
>     +               /* can't just invalidate the descriptor - if it contains
>     +                * data that hasn't been flushed yet, we create an
>     inconsistency...
>     +                */
>     +               rtems_bsdnet_semaphore_obtain();
>     +               INVAL_DESC(pr);
>     +#endif
>     +               printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next:
>     0x%08x, buf: 0x%08x\n",
>     +                       pr->byte_cnt, pr->buf_size, pr->cmd_sts,
>     (uint32_t)pr->next_desc_ptr, pr->buf_ptr);
>     +
>     +#ifndef ENABLE_HW_SNOOPING
>     +               rtems_bsdnet_semaphore_release();
>     +#endif
>     +       }
>     +}
>     +if (1) {
>     +MvEthTxDesc pt;
>     +printf("TX:\n");
>     +       for (i=0, pt=sc->pvt.tx_ring; i<sc->pvt.xbuf_count; i++, pt++) {
>     +#ifndef ENABLE_HW_SNOOPING
>     +               rtems_bsdnet_semaphore_obtain();
>     +               INVAL_DESC(pt);
>     +#endif
>     +               printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf:
>     0x%08x, mb: 0x%08x\n",
>     +                       pt->byte_cnt, pt->cmd_sts,
>     (uint32_t)pt->next_desc_ptr, pt->buf_ptr,
>     +                       (uint32_t)pt->mb);
>     +
>     +#ifndef ENABLE_HW_SNOOPING
>     +               rtems_bsdnet_semaphore_release();
>     +#endif
>     +       }
>     +}
>     +       return 0;
>     +}
>     +
>     +#endif
>     +
>     +/* DETACH HACK DETAILS */
>     +
>     +#ifdef  MVETH_DETACH_HACK
>     +int
>     +_cexpModuleFinalize(void *mh)
>     +{
>     +int i;
>     +       for ( i=0; i<MV643XXETH_NUM_DRIVER_SLOTS; i++ ) {
>     +               if ( theMvEths[i].arpcom.ac_if.if_init ) {
>     +                       printf("Interface %i still attached; refuse to
>     unload\n", i+1);
>     +                       return -1;
>     +               }
>     +       }
>     +       /* delete task; since there are no attached interfaces, it should block
>     +        * for events and hence not hold the semaphore or other resources...
>     +        */
>     +       rtems_task_delete(mveth_tid);
>     +       return 0;
>     +}
>     +
>     +/* ugly hack to allow unloading/reloading the driver core.
>     + * needed because rtems' bsdnet release doesn't implement
>     + * if_detach(). Therefore, we bring the interface down but
>     + * keep the device record alive...
>     + */
>     +static void
>     +ether_ifdetach_pvt(struct ifnet *ifp)
>     +{
>     +        ifp->if_flags = 0;
>     +        ifp->if_ioctl = 0;
>     +        ifp->if_start = 0;
>     +        ifp->if_watchdog = 0;
>     +        ifp->if_init  = 0;
>     +}
>     +
>     +static int
>     +mveth_detach(struct mveth_softc *sc)
>     +{
>     +struct ifnet   *ifp = &sc->arpcom.ac_if;
>     +       if ( ifp->if_init ) {
>     +               if ( ifp->if_flags & (IFF_UP | IFF_RUNNING) ) {
>     +                       printf(DRVNAME"%i: refuse to detach; interface still
>     up\n",sc->pvt.port_num+1);
>     +                       return -1;
>     +               }
>     +               mveth_stop(sc);
>     +/* not implemented in BSDnet/RTEMS (yet) but declared in header */
>     +#define ether_ifdetach ether_ifdetach_pvt
>     +               ether_ifdetach(ifp);
>     +       }
>     +       free( (void*)sc->pvt.ring_area, M_DEVBUF );
>     +       sc->pvt.ring_area = 0;
>     +       sc->pvt.tx_ring   = 0;
>     +       sc->pvt.rx_ring   = 0;
>     +       sc->pvt.d_tx_t    = sc->pvt.d_tx_h   = 0;
>     +       sc->pvt.d_rx_t    = 0;
>     +       sc->pvt.avail     = 0;
>     +       /* may fail if ISR was not installed yet */
>     +       BSP_remove_rtems_irq_handler( &irq_data[sc->pvt.port_num] );
>     +       return 0;
>     +}
>     +
>     +#ifdef MVETH_DEBUG
>     +struct rtems_bsdnet_ifconfig mveth_dbg_config = {
>     +       name:                           DRVNAME"1",
>     +       attach:                         rtems_mve_attach,
>     +       ip_address:                     "192.168.2.10",         /* not used
>     by rtems_bsdnet_attach */
>     +       ip_netmask:                     "255.255.255.0",        /* not used
>     by rtems_bsdnet_attach */
>     +       hardware_address:       0, /* (void *) */
>     +       ignore_broadcast:       0,                                      /*
>     TODO driver should honour this  */
>     +       mtu:                            0,
>     +       rbuf_count:                     0,                                 
>         /* TODO driver should honour this  */
>     +       xbuf_count:                     0,                                 
>         /* TODO driver should honour this  */
>     +};
>     +#endif
>     +#endif
>     -- 
>     2.39.3
> 
>     _______________________________________________
>     devel mailing list
>     devel at rtems.org <mailto:devel at rtems.org>
>     http://lists.rtems.org/mailman/listinfo/devel
>     <http://lists.rtems.org/mailman/listinfo/devel>
> 
> 
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list