From: till straumann <till.straum...@alumni.tu-berlin.de>

Update #4345
---
 libbsd.py                            |  19 +
 rtemsbsd/include/bsp/nexus-devices.h |   7 +-
 rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 965 +++++++++++++++++++++++++++
 3 files changed, 990 insertions(+), 1 deletion(-)
 create mode 100644 rtemsbsd/sys/dev/mve/mv643xx_nexus.c

diff --git a/libbsd.py b/libbsd.py
index a2056f36..b25d7e03 100644
--- a/libbsd.py
+++ b/libbsd.py
@@ -292,6 +292,25 @@ class rtems(builder.Module):
                 'pppd/sys-rtems.c',
                 'pppd/upap.c',
                 'pppd/utils.c',
+                'sys/arm/lpc/if_lpe.c',
+                'sys/arm/lpc/lpc_pwr.c',
+                'sys/dev/atsam/if_atsam.c',
+                'sys/dev/atsam/if_atsam_media.c',
+                'sys/dev/dw_mmc/dw_mmc.c',
+                'sys/dev/ffec/if_ffec_mcf548x.c',
+                'sys/dev/ffec/if_ffec_mpc8xx.c',
+                'sys/dev/mve/mv643xx_nexus.c',
+                'sys/dev/input/touchscreen/tsc_lpc32xx.c',
+                'sys/dev/smc/if_smc_nexus.c',
+                'sys/dev/tsec/if_tsec_nexus.c',
+                'sys/dev/usb/controller/ehci_mpc83xx.c',
+                'sys/dev/usb/controller/ohci_lpc32xx.c',
+                'sys/dev/usb/controller/ohci_lpc.c',
+                'sys/dev/usb/controller/usb_otg_transceiver.c',
+                'sys/dev/usb/controller/usb_otg_transceiver_dump.c',
+                'sys/fs/devfs/devfs_devs.c',
+                'sys/net/if_ppp.c',
+                'sys/net/ppp_tty.c',
                 'telnetd/telnetd-service.c',
             ],
             mm.generator['source']()
diff --git a/rtemsbsd/include/bsp/nexus-devices.h 
b/rtemsbsd/include/bsp/nexus-devices.h
index 53a22798..82a6f332 100644
--- a/rtemsbsd/include/bsp/nexus-devices.h
+++ b/rtemsbsd/include/bsp/nexus-devices.h
@@ -246,6 +246,11 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
 
 RTEMS_BSD_DRIVER_PC_LEGACY;
 
-#endif /* LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H */
+#elif defined(LIBBSP_BEATNIK_BSP_H)
+
+RTEMS_BSD_DEFINE_NEXUS_DEVICE(mve, 0, 0, NULL);
+SYSINIT_DRIVER_REFERENCE(ukphy, miibus);
+
+#endif
 
 #endif
diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c 
b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c
new file mode 100644
index 00000000..804c3e7f
--- /dev/null
+++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c
@@ -0,0 +1,965 @@
+/* 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 <mdh...@momenco.com>
+ * rab...@galileo.co.il
+ * PMC-Sierra, Inc., Manish Lachwani
+ * Ralf Baechle <r...@linux-mips.org>
+ * MontaVista Software, Inc., Dale Farnsworth <d...@farnsworth.org>
+ * Steven J. Hill <sjhi...@rockwellcollins.com>/<sjh...@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 <strau...@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
+ */
+
+/* Nexus port by Till Straumann, <till.straum...@psi.ch>, 3/2021 */
+
+#include <machine/rtems-bsd-kernel-space.h>
+#include <bsp.h>
+
+#ifdef LIBBSP_BEATNIK_BSP_H
+
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <rtems/bsd/local/miibus_if.h>
+#include <stdio.h>
+#include <bsp/mv643xx_eth.h>
+
+#define DRVNAME "mv63xx_nexus"
+
+#undef  MVETH_DEBUG
+
+/* Define default ring sizes */
+
+#ifdef MVETH_TESTING
+
+/* hard and small defaults */
+#define MV643XX_RX_RING_SIZE   2
+#define MV643XX_TX_QUEUE_SIZE   4
+#define MV643XX_BD_PER_PACKET   1
+#define TX_LOWWATER             1
+
+#else /* MVETH_TESTING */
+
+#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!
+                                                                        */
+#define MV643XX_TX_QUEUE_SIZE   40
+#define MV643XX_BD_PER_PACKET   10
+#define TX_LOWWATER             (4*(MV643XX_BD_PER_PACKET))
+#endif /* MVETH_TESTING */
+
+/* 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!
+ */
+#define MV643XX_TX_RING_SIZE   ((MV643XX_TX_QUEUE_SIZE) * 
(MV643XX_BD_PER_PACKET))
+
+/* 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 */
+
+#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 !defined(PPC_CACHE_ALIGNMENT)
+#error "PPC_CACHE_ALIGNMENT not defined"
+#elif PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32
+#error "Cache line size must be 16 or 32"
+#else
+#define RX_BUF_ALIGNMENT                       PPC_CACHE_ALIGNMENT
+#endif
+
+/* HELPER MACROS */
+
+/* Align base to alignment 'a' */
+#define MV643XX_ALIGN(b, a)    ((((uint32_t)(b)) + (a)-1) & (~((a)-1)))
+
+
+#define IRQ_EVENT RTEMS_EVENT_0
+#define TX_EVENT  RTEMS_EVENT_1
+
+/* Hacks -- FIXME */
+rtems_id
+rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void 
*arg);
+#define SIO_RTEMS_SHOW_STATS _IO('i', 250)
+
+#define        MVE643XX_DUMMY_PHY 0 /* phy is defined by low-level driver */
+
+struct mve_enet_softc {
+       device_t                  dev;
+       struct ifnet             *ifp;
+       device_t                  miibus;
+       struct mii_data          *mii_softc;
+       struct mveth_private     *mp;
+    struct mtx                mtx;
+       struct callout            wdCallout;
+       rtems_id                  daemonTid;
+       int                       oif_flags;
+};
+
+typedef struct MveMbufIter {
+       MveEthBufIter it;
+       struct mbuf  *next;
+       struct mbuf  *head;
+} MveMbufIter;
+
+/* Forward Declarations */
+struct mve_enet_softc;
+
+static void
+mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr);
+
+static int
+mve_media_change(struct ifnet *ifp);
+
+static void
+mve_set_filters(struct ifnet *ifp);
+
+static int
+xlateMediaFlags(const struct mii_data *mid);
+
+static void
+mve_ack_link_change(struct mve_enet_softc *sc);
+
+static __inline__ void
+mve_send_event(struct mve_enet_softc *sc, rtems_event_set ev)
+{
+rtems_status_code st;
+       if ( RTEMS_SUCCESSFUL != (st = rtems_event_send(sc->daemonTid, ev)) ) {
+               printk(DRVNAME": rtems_event_send returned 0x%08x (TID: 0x%08x, 
sc: 0x%08x)\n", st, sc->daemonTid, sc);
+               rtems_panic(DRVNAME": rtems_event_send() failed!\n");
+       }
+}
+
+static __inline__ void
+mve_lock(struct mve_enet_softc *sc, const char *from)
+{
+       mtx_lock( & sc->mtx );
+/*printk("L V %s\n", from);*/
+}
+
+static __inline__ void
+mve_unlock(struct mve_enet_softc *sc, const char *from)
+{
+/*printk("L ^ %s\n", from);*/
+       mtx_unlock( & sc->mtx );
+}
+
+static int
+mve_probe(device_t dev)
+{
+       int unit = device_get_unit(dev);
+       int err;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_probe (entering)\n");
+#endif
+
+       if ( unit >= 0 && unit < MV643XXETH_NUM_DRIVER_SLOTS ) {
+               err = BUS_PROBE_DEFAULT;
+       } else {
+               err = ENXIO;
+       }
+
+       return err;
+}
+
+/* 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;
+
+       m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+
+       if ( m ) {
+               m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t));
+               m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len;
+       }
+
+       m_freem(m_head);
+       return m;
+}
+
+/*
+ * starting at 'm' scan the buffer chain until we
+ * find a non-empty buffer (which we return)
+ */
+static __inline__ struct mbuf *
+skipEmpty(struct mbuf *m)
+{
+       while ( m && ( 0 == m->m_len ) ) {
+               m = m->m_next;
+       }
+       return m;
+}
+
+/*
+ * Record a buffer's info in the low-leve driver 'iterator' struct.
+ * Also scan ahead to find the next non-empty buffer (store it in
+ * the iterator's 'next' field). This info is needed because we
+ * want to know if 'this' buffer is the last (non-empty!) one
+ * in a chain.
+ *
+ * On entry 'it->next' identifies 'this' buffer and on return
+ * 'it->next' points to the next non-empty buffer.
+ */
+static MveEthBufIter *
+nextBuf(MveEthBufIter *arg)
+{
+MveMbufIter *it = (MveMbufIter*)arg;
+struct mbuf *m;
+       /* If 'this' buffer is non-null */
+       if ( (m = it->next) ) {
+               /* find next non-empty buffer */
+               it->next    = skipEmpty( m->m_next );
+               /* record 'this' buffer's info */
+               it->it.data = mtod(m, void*);
+               it->it.len  = m->m_len;
+               /* if there is a non-empty buffer after 'this' uptr is NULL
+                * if this is tha last buffer in a chain then record the
+                * head of the chain in the uptr (for eventual cleanup
+                * by release_tx_mbuf()).
+                */
+               it->it.uptr = it->next ? 0 : it->head;
+               return (MveEthBufIter*)it;
+       }
+       return 0;
+}
+
+/*
+ * Initialize the iterator struct
+ */
+static MveEthBufIter *
+initIter(MveMbufIter *it, struct mbuf *m)
+{
+       /* record the head of the chain */
+       it->head = m;
+       /* initialize 'next' field to the first non-empty buffer.
+     * This may be NULL if the chain is entirely empty but
+        * that is handled correctly.
+        */
+       it->next = skipEmpty( m );
+       /* Fill with first buf info */
+       return nextBuf( &it->it );
+}
+
+static int
+mve_send_mbuf( struct mve_enet_softc *sc, struct mbuf *m_head )
+{
+MveMbufIter iter;
+int         rval;
+
+startover:
+
+       if ( ! m_head ) {
+               return 0;
+       }
+
+       if ( ! initIter( &iter, m_head ) ) {
+               /* completely empty chain */
+               m_freem( m_head );
+               return 0;
+       }
+
+       rval = BSP_mve_send_buf_chain( sc->mp, nextBuf, &iter.it );
+
+       if ( -2 == rval ) {
+               /* would never fit (too many fragments) */
+               m_head = repackage_chain( m_head );
+               goto startover;
+       }
+
+       return rval;
+}
+
+static void
+mve_isr(void *closure)
+{
+struct mve_enet_softc *sc = (struct mve_enet_softc*)closure;
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_isr; posting event to %x\n", sc->daemonTid);
+#endif
+       BSP_mve_disable_irqs( sc->mp );
+       mve_send_event( sc, IRQ_EVENT );
+}
+
+static void
+mve_stop(struct mve_enet_softc *sc)
+{
+       BSP_mve_stop_hw( sc->mp );
+       /* clear IF flags */
+       if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING));
+}
+
+static void
+mve_set_filters(struct ifnet *ifp)
+{
+struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc;
+int                   iff = if_getflags(ifp);
+struct ifmultiaddr   *ifma;
+unsigned char        *lladdr;
+
+       BSP_mve_promisc_set( sc->mp, !!(iff & IFF_PROMISC));
+
+       if ( iff & (IFF_PROMISC | IFF_ALLMULTI) ) {
+               BSP_mve_mcast_filter_accept_all(sc->mp);
+       } else {
+               BSP_mve_mcast_filter_clear( sc->mp );
+
+               if_maddr_rlock( ifp );
+
+               CK_STAILQ_FOREACH( ifma, &ifp->if_multiaddrs, ifma_link ) {
+
+                       if ( ifma->ifma_addr->sa_family != AF_LINK ) {
+                               continue;
+                       }
+
+                       lladdr = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
+
+                       BSP_mve_mcast_filter_accept_add( sc->mp, lladdr );
+
+               }
+
+               if_maddr_runlock( ifp );
+       }
+}
+
+/* Daemon task does all the 'interrupt' work */
+static void
+mve_daemon(void *arg)
+{
+struct mve_enet_softc   *sc  = (struct mve_enet_softc*) arg;
+struct ifnet               *ifp = sc->ifp;
+rtems_event_set                     evs;
+struct mbuf             *m;
+int                      avail;
+int                      sndStat;
+uint32_t                 irqstat;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": bsdnet mveth_daemon started\n");
+#endif
+
+       mve_lock( sc, "daemon" );
+
+       for (;;) {
+
+               mve_unlock( sc, "daemon" );
+               if ( RTEMS_SUCCESSFUL != rtems_event_receive( (IRQ_EVENT | 
TX_EVENT), (RTEMS_WAIT | RTEMS_EVENT_ANY), RTEMS_NO_TIMEOUT, &evs ) ) {
+                       rtems_panic(DRVNAME": rtems_event_receive() failed!\n");
+               }
+               mve_lock( sc, "daemon" );
+
+#ifdef MVETH_DEBUG
+               printk(DRVNAME": bsdnet mveth_daemon event received 0x%x\n", 
evs);
+#endif
+
+               if ( !(if_getflags(ifp) & IFF_UP) ) {
+                       mve_stop(sc);
+                       /* clear flag */
+                       if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING);
+                       continue;
+               }
+
+               if ( ! (if_getdrvflags(ifp) & IFF_DRV_RUNNING) ) {
+                       /* event could have been pending at the time hw was 
stopped;
+                        * just ignore...
+                        */
+                       continue;
+               }
+
+               if ( (evs & IRQ_EVENT) ) {
+                       irqstat = BSP_mve_ack_irqs(sc->mp);
+               } else {
+                       irqstat = 0;
+               }
+
+               if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) && sc->mii_softc 
) {
+                       /* phy status changed */
+                       mii_pollstat( sc->mii_softc );
+               }
+
+               /* free tx chain and send */
+               if ( (evs & TX_EVENT) || (MV643XX_ETH_EXT_IRQ_TX_DONE & 
irqstat)  ) {
+                       while ( (avail = BSP_mve_swipe_tx( sc->mp )) > 
TX_LOWWATER ) {
+                               IF_DEQUEUE( &ifp->if_snd, m );
+                               if ( ! m ) {
+                                       /* clear active bit */
+                                       if_setdrvflagbits(ifp, 0, 
IFF_DRV_OACTIVE);
+                                       break;
+                               }
+                               sndStat = mve_send_mbuf( sc, m );
+                               if ( sndStat < 0 ) {
+                                       /* maybe not enough space right now; 
requeue and wait for next IRQ */
+                                       IF_PREPEND( &ifp->if_snd, m );
+                                       break;
+                               }
+                       }
+               }
+               if ( (MV643XX_ETH_IRQ_RX_DONE & irqstat) ) {
+                       BSP_mve_swipe_rx(sc->mp);
+               }
+
+               BSP_mve_enable_irqs(sc->mp);
+       }
+
+       mve_unlock( sc, "daemon (xit)" );
+}
+
+static void
+release_tx_mbuf(void *user_buf, void *closure, int error_on_tx_occurred)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*)closure;
+struct ifnet          *ifp = sc->ifp;
+struct mbuf            *mb = (struct mbuf*)user_buf;
+
+       if ( error_on_tx_occurred ) {
+               if_inc_counter( ifp, IFCOUNTER_OERRORS,               1 );
+       } else {
+               if_inc_counter( ifp, IFCOUNTER_OPACKETS,              1 );
+               if_inc_counter( ifp, IFCOUNTER_OBYTES, mb->m_pkthdr.len );
+       }
+       m_freem(mb);
+}
+
+static void *
+alloc_rx_mbuf(int *p_size, uintptr_t *p_data)
+{
+struct mbuf            *m;
+unsigned long  l,o;
+
+       m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+
+       if ( m ) {
+
+               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;
+               *p_size    = m->m_len;
+               *p_data    = mtod(m, uintptr_t);
+       }
+
+       return (void*) m;
+}
+
+
+static void
+consume_rx_mbuf(void *user_buf, void *closure, int len)
+{
+struct mve_enet_softc *sc  = (struct mve_enet_softc*)closure;
+struct ifnet          *ifp = sc->ifp;
+struct mbuf           *m   = (struct mbuf*)user_buf;
+
+       if ( len <= 0 ) {
+               if_inc_counter( ifp, IFCOUNTER_IQDROPS, 1 );
+               if ( len < 0 ) {
+                       if_inc_counter( ifp, IFCOUNTER_IERRORS, 1 );
+               }
+               m_freem(m);
+       } else {
+                       m->m_len              = m->m_pkthdr.len = len - 
ETH_RX_OFFSET - ETH_CRC_LEN;
+                       m->m_data        += ETH_RX_OFFSET;
+                       m->m_pkthdr.rcvif = ifp;
+
+                       if_inc_counter( ifp, IFCOUNTER_IPACKETS,               
1 );
+                       if_inc_counter( ifp, IFCOUNTER_IBYTES,   
m->m_pkthdr.len );
+
+                       if (0) {
+                               /* Low-level debugging */
+                               int i;
+                               for (i=0; i<m->m_len; i++) {
+                                       if ( !(i&15) )
+                                               printk("\n");
+                                       printk("0x%02x ",mtod(m,char*)[i]);
+                               }
+                               printk("\n");
+                       }
+
+                       mve_unlock( sc, "rx_cleanup" );
+                       (*ifp->if_input)(ifp, m);
+                       mve_lock( sc, "rx_cleanup" );
+       }
+}
+
+/* Translate IFFLAGS to low-level driver representation */
+static int
+xlateMediaFlags(const struct mii_data *mid)
+{
+int lowLevelFlags = 0;
+int msk           = IFM_AVALID | IFM_ACTIVE;
+
+       if ( (mid->mii_media_status & msk) == msk ) {
+               lowLevelFlags |= MV643XX_MEDIA_LINK;
+
+               if ( IFM_OPTIONS( mid->mii_media_active ) & IFM_FDX ) {
+                       lowLevelFlags |= MV643XX_MEDIA_FD;
+               }
+
+               switch ( IFM_ETHER_SUBTYPE_GET( mid->mii_media_active ) ) {
+                       default:
+#ifdef MVETH_DEBUG
+                               printk(DRVNAME"xlateMediaFlags: UNKNOWN 
SPEED\n");
+#endif
+                               break; /* UNKNOWN -- FIXME */
+                       case IFM_10_T:
+#ifdef MVETH_DEBUG
+                               printk(DRVNAME"xlateMediaFlags: 10baseT\n");
+#endif
+                               lowLevelFlags |= MV643XX_MEDIA_10;
+                               break;
+                       case IFM_100_TX:
+#ifdef MVETH_DEBUG
+                               printk(DRVNAME"xlateMediaFlags: 100baseT\n");
+#endif
+                               lowLevelFlags |= MV643XX_MEDIA_100;
+                               break;
+                       case IFM_1000_T:
+#ifdef MVETH_DEBUG
+                               printk(DRVNAME"xlateMediaFlags: 1000baseT\n");
+#endif
+                               lowLevelFlags |= MV643XX_MEDIA_1000;
+                               break;
+               }
+       } else {
+#ifdef MVETH_DEBUG
+                               printk(DRVNAME"xlateMediaFlags: NO LINK\n");
+#endif
+       }
+       return lowLevelFlags;
+}
+
+static void
+mve_init_unlocked(struct mve_enet_softc *sc)
+{
+struct ifnet             *ifp                 = sc->ifp;
+int                    lowLevelMediaStatus = 0;
+int                    promisc;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_init (entering)\n");
+#endif
+
+
+       if ( sc->mii_softc ) {
+               mii_pollstat( sc->mii_softc );
+               lowLevelMediaStatus = xlateMediaFlags( sc->mii_softc );
+               if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) {
+                       if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
+               } else {
+                       if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
+               }
+       }
+
+       promisc = !! (if_getdrvflags(ifp) & IFF_PROMISC);
+
+       BSP_mve_init_hw(sc->mp, promisc, if_getlladdr(ifp), 
lowLevelMediaStatus);
+
+       /* if promiscuous then there is no need to change */
+       if ( ! promisc ) {
+               mve_set_filters(ifp);
+       }
+
+
+       if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
+}
+
+static void
+mve_init(void *arg)
+{
+struct mve_enet_softc *sc = (struct mve_enet_softc*)arg;
+       mve_lock( sc, "mve_init" );
+               mve_init_unlocked( sc );
+       mve_unlock( sc, "mve_init" );
+}
+
+static void
+mve_start_unlocked(struct ifnet *ifp)
+{
+struct mve_enet_softc *sc  = (struct mve_enet_softc*)ifp->if_softc;
+       if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
+       mve_send_event( sc, TX_EVENT );
+}
+
+static void
+mve_start(struct ifnet *ifp)
+{
+struct mve_enet_softc *sc  = (struct mve_enet_softc*)ifp->if_softc;
+       mve_lock( sc, "mve_start" );
+               mve_start_unlocked( ifp );
+       mve_unlock( sc, "mve_start" );
+}
+
+
+static int
+mve_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*)ifp->if_softc;
+struct ifreq          *ifr = (struct ifreq *)data;
+int                    err = 0;
+int                      f, df;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_ioctl (entering)\n");
+#endif
+
+       mve_lock( sc, "mve_ioctl" );
+
+       switch ( cmd ) {
+               case SIOCSIFFLAGS:
+                       f  = if_getflags( ifp );
+                       df = if_getdrvflags( ifp );
+                       if ( (f & IFF_UP) ) {
+                               if ( ! ( df & IFF_DRV_RUNNING ) ) {
+                                       mve_init_unlocked(sc);
+                               } else {
+                                       if ( (f & IFF_PROMISC) != 
(sc->oif_flags & IFF_PROMISC) ) {
+                                               mve_set_filters(ifp);
+                                       }
+                                       /* FIXME: other flag changes are 
ignored/unimplemented */
+                               }
+                       } else {
+                               if ( df & IFF_DRV_RUNNING ) {
+                                       mve_stop(sc);
+                               }
+                       }
+                       sc->oif_flags = f;
+               break;
+
+               case SIOCGIFMEDIA:
+               case SIOCSIFMEDIA:
+                       if ( sc->mii_softc ) {
+                               err = ifmedia_ioctl( ifp, ifr, 
&sc->mii_softc->mii_media, cmd );
+                       } else {
+                               err = EINVAL;
+                       }
+               break;
+
+               case SIOCADDMULTI:
+               case SIOCDELMULTI:
+                       if ( if_getdrvflags( ifp ) & IFF_DRV_RUNNING ) {
+                               mve_set_filters(ifp);
+                       }
+               break;
+
+               case SIO_RTEMS_SHOW_STATS:
+                       BSP_mve_dump_stats(sc->mp, stdout);
+               break;
+
+               default:
+                       err = ether_ioctl(ifp, cmd, data);
+               break;
+       }
+
+       mve_unlock( sc, "mve_ioctl" );
+
+       return err;
+}
+
+/*
+ * Used to update speed settings in the hardware
+ * when the phy setup changes.
+ *
+ * ASSUME: caller holds lock
+ */
+static void
+mve_ack_link_change(struct mve_enet_softc *sc)
+{
+struct mii_data *mii                 = sc->mii_softc;
+int              lowLevelMediaStatus;
+
+       if ( !mii )
+               return;
+
+       lowLevelMediaStatus = xlateMediaFlags( mii );
+
+       if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) {
+               BSP_mve_update_serial_port( sc->mp, lowLevelMediaStatus );
+               if_setdrvflagbits( sc->ifp, 0, IFF_DRV_OACTIVE );
+        mve_start_unlocked( sc->ifp );
+       } else {
+               if_setdrvflagbits( sc->ifp, IFF_DRV_OACTIVE, 0 );
+       }
+}
+
+/* Callback from ifmedia_ioctl()
+ *
+ * Caller probably holds the lock already but
+ * since it is recursive we may as well make sure
+ * in case there are other possible execution paths.
+ */
+static int
+mve_media_change(struct ifnet *ifp)
+{
+struct mve_enet_softc  *sc  = (struct mve_enet_softc *)ifp->if_softc;
+struct mii_data        *mii = sc->mii_softc;
+int                     err;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_media_change\n");
+#endif
+
+       if ( ! mii ) {
+               return ENXIO;
+       }
+
+       err = mii_mediachg( mii );
+
+       return err;
+}
+
+static void
+mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+struct mve_enet_softc  *sc  = (struct mve_enet_softc *)ifp->if_softc;
+struct mii_data        *mii = sc->mii_softc;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_media_status\n");
+#endif
+
+       if ( mii ) {
+               mii_pollstat( mii );
+               ifmr->ifm_active = mii->mii_media_active;
+               ifmr->ifm_status = mii->mii_media_status;
+       }
+
+}
+
+static int
+mve_attach(device_t dev)
+{
+struct mve_enet_softc  *sc;
+struct ifnet           *ifp;
+uint8_t                 hwaddr[ETHER_ADDR_LEN];
+struct mveth_private   *mp;
+int                     unit         = device_get_unit(dev);
+int                     tx_ring_size = MV643XX_TX_RING_SIZE;
+int                     rx_ring_size = MV643XX_RX_RING_SIZE;
+int                     tx_q_size    = MV643XX_TX_QUEUE_SIZE;
+
+       sc            = device_get_softc( dev );
+       sc->dev       = dev;
+       sc->ifp       = ifp = if_alloc(IFT_ETHER);
+       sc->daemonTid = 0;
+       sc->mii_softc = 0;
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_attach (entering)\n");
+#endif
+
+       mtx_init( &sc->mtx, device_get_nameunit( sc->dev ), MTX_NETWORK_LOCK, 
MTX_RECURSE );
+       callout_init_mtx( &sc->wdCallout, &sc->mtx, 0 );
+
+       ifp->if_softc = sc;
+       if_initname(ifp, device_get_name(dev), unit);
+       ifp->if_init  = mve_init;
+       ifp->if_ioctl = mve_ioctl;
+       ifp->if_start = mve_start;
+       if_setflags(ifp, (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX) );
+       sc->oif_flags = if_getflags(ifp);
+       if_setsendqlen( ifp, tx_q_size );
+       if_setsendqready( ifp );
+
+       mp = BSP_mve_create(
+               unit + 1, /* low-level driver' unit numbers are 1-based */
+               0,
+               mve_isr, (void*)sc,
+               release_tx_mbuf, (void*)sc,
+               alloc_rx_mbuf,
+               consume_rx_mbuf, (void*)sc,
+               rx_ring_size,
+               tx_ring_size,
+               (   MV643XX_ETH_IRQ_RX_DONE
+                 | MV643XX_ETH_EXT_IRQ_TX_DONE
+                 | MV643XX_ETH_EXT_IRQ_LINK_CHG));
+
+       if ( ! mp ) {
+               rtems_panic("Unable to create mv643xx low-level driver");
+       }
+
+       sc->mp = mp;
+
+
+       BSP_mve_read_eaddr( mp, hwaddr );
+
+       if ( 0 == mii_attach( sc->dev,
+                            &sc->miibus,
+                             ifp,
+                             mve_media_change,
+                             mve_media_status,
+                             BMSR_DEFCAPMASK,
+                             MVE643XX_DUMMY_PHY,
+                             MII_OFFSET_ANY,
+                             0 ) ) {
+               sc->mii_softc = device_get_softc( sc->miibus );
+       }
+
+       sc->daemonTid = rtems_bsdnet_newproc("MVE", 4096, mve_daemon, 
(void*)sc);
+
+       ether_ifattach( ifp, hwaddr );
+
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_attach (leaving)\n");
+#endif
+
+       return 0;
+}
+
+static int
+mve_miibus_read_reg(device_t dev, int phy, int reg)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*) device_get_softc(dev);
+
+       /* low-level driver knows what phy to use; ignore arg */
+       return (int) BSP_mve_mii_read( sc->mp, reg );
+}
+
+static int
+mve_miibus_write_reg(device_t dev, int phy, int reg, int val)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*) device_get_softc(dev);
+
+       /* low-level driver knows what phy to use; ignore arg */
+       BSP_mve_mii_write( sc->mp, reg, val );
+       return 0;
+}
+
+static void
+mve_miibus_statchg(device_t dev)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*) device_get_softc(dev);
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_miibus_statchg\n");
+#endif
+       /* assume this ends up being called either from the ioctl or the driver
+        * task -- either of which holds the lock.
+        */
+       mve_ack_link_change( sc );
+}
+
+static void
+mve_miibus_linkchg(device_t dev)
+{
+struct mve_enet_softc  *sc = (struct mve_enet_softc*) device_get_softc(dev);
+#ifdef MVETH_DEBUG
+       printk(DRVNAME": mve_miibus_linkchg\n");
+#endif
+       /* assume this ends up being called either from the ioctl or the driver
+        * task -- either of which holds the lock.
+        */
+       mve_ack_link_change( sc );
+}
+
+
+static device_method_t mve_methods[] = {
+       DEVMETHOD(device_probe,    mve_probe ),
+       DEVMETHOD(device_attach,   mve_attach),
+
+       DEVMETHOD(miibus_readreg,  mve_miibus_read_reg ),
+       DEVMETHOD(miibus_writereg, mve_miibus_write_reg),
+       DEVMETHOD(miibus_statchg , mve_miibus_statchg  ),
+       DEVMETHOD(miibus_linkchg , mve_miibus_linkchg  ),
+
+       DEVMETHOD_END
+};
+
+static driver_t mve_nexus_driver = {
+       "mve",
+       mve_methods,
+       sizeof( struct mve_enet_softc )
+};
+
+static devclass_t mve_devclass;
+
+DRIVER_MODULE(mve, nexus, mve_nexus_driver, mve_devclass, 0, 0);
+DRIVER_MODULE(miibus, mve, miibus_driver,   miibus_devclass, 0, 0);
+
+MODULE_DEPEND(mve, nexus, 1, 1, 1);
+MODULE_DEPEND(mve, ether, 1, 1, 1);
+#endif
-- 
2.26.2

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to