From 48bd413cd6403e02e8249b4f05063443d019e063 Mon Sep 17 00:00:00 2001 From: till straumann Date: Wed, 10 Mar 2021 11:47:35 +0100 Subject: [PATCH 1/7] mv643xx_nexus.c, libbsd.py, bsp/nexus-devices.h: First stab at mv643xx; port almost complete (mii stuff missing) and compiles -- no tests yet! --- libbsd.py | 1 + rtemsbsd/include/bsp/nexus-devices.h | 4 + rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 616 +++++++++++++++++++++++++++ 3 files changed, 621 insertions(+) create mode 100644 rtemsbsd/sys/dev/mve/mv643xx_nexus.c diff --git a/libbsd.py b/libbsd.py index 334a79916..10d8aa474 100644 --- a/libbsd.py +++ b/libbsd.py @@ -268,6 +268,7 @@ def generate(self): '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', diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h index d2ceab8e1..9023c5577 100644 --- a/rtemsbsd/include/bsp/nexus-devices.h +++ b/rtemsbsd/include/bsp/nexus-devices.h @@ -197,6 +197,10 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus); RTEMS_BSD_DEFINE_NEXUS_DEVICE(fec, 0, 0, NULL); SYSINIT_DRIVER_REFERENCE(ukphy, miibus); +#elif defined(LIBBSP_BEATNIK_BSP_H) + +RTEMS_BSD_DEFINE_NEXUS_DEVICE(mve, 0, 0, NULL); + #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 000000000..96b08c327 --- /dev/null +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -0,0 +1,616 @@ +#include +#include + +#ifdef LIBBSP_BEATNIK_BSP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + +/* Hack -- FIXME */ +#define SIO_RTEMS_SHOW_STATS _IO('i', 250) + + +struct mve_enet_softc { + device_t dev; + struct ifnet *ifp; + 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; + +static __inline__ void +mve_send_event(struct mve_enet_softc *sc, rtems_event_set ev) +{ + rtems_event_send(sc->daemonTid, ev); +} + +static __inline__ void +mve_lock(struct mve_enet_softc *sc) +{ + mtx_lock( & sc->mtx ); +} + +static __inline__ void +mve_unlock(struct mve_enet_softc *sc) +{ + mtx_unlock( & sc->mtx ); +} + +static int +mve_probe(device_t dev) +{ + int unit = device_get_unit(dev); + int err; + + 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; + BSP_mve_disable_irqs( sc->mp ); + mve_send_event( sc->daemonTid, IRQ_EVENT ); +} + +static void +mveth_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)); +} + +/* 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 + sleep(1); + printk(DRVNAME": bsdnet mveth_daemon started\n"); +#endif + + mve_lock( sc ); + + for (;;) { + + mve_unlock( sc ); + rtems_event_receive( IRQ_EVENT | TX_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs ); + mve_lock( sc ); + +#ifdef MVETH_DEBUG + printk(DRVNAME": bsdnet mveth_daemon event received 0x%x\n", evs); +#endif + + if ( !(if_getflags(ifp) & IFF_UP) ) { + mveth_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; + } + +#warning TODO_ +#if 0 + if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) ) { + /* phy status changed */ + int media; + + if ( 0 == BSP_mve_ack_link_chg(sc->pvt, &media) ) { + if ( IFM_LINK_OK & media ) { + /* stop sending */ + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); + mveth_start(ifp); + } else { + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + } + } + } +#endif + /* 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 ); +} + +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; im_len; i++) { + if ( !(i&15) ) + printf("\n"); + printf("0x%02x ",mtod(m,char*)[i]); + } + printf("\n"); + } + + mve_unlock( sc ); + (*ifp->if_input)(ifp, m); + mve_lock( sc ); + } +} + +static void +mve_init(void *arg) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)arg; +struct ifnet *ifp = sc->ifp; +int lowLevelMediaStatus = 0; +int promisc; + + mve_lock( sc ); + +#ifdef TODO__ +int media; + + media = IFM_MAKEWORD(0, 0, 0, 0); + if ( 0 == BSP_mve_media_ioctl(sc->pvt, SIOCGIFMEDIA, &media) ) { + if ( (IFM_LINK_OK & media) ) { + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); + } else { + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + } + } + + lowLevelMediaStatus = xlateMediaFlags( media ); +#endif + + 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 ) { + mveth_set_filters(ifp); + } + + if ( ! sc->daemonTid ) { + sc->daemonTid = rtems_bsd_newproc("MVE", 4096, mve_daemon, (void*)sc); + } + + if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); + + mve_unlock( sc ); +} + +static void +mve_start(struct ifnet *ifp) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc; + mve_lock( sc ); + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + mve_unlock( sc ); + mve_send_event( sc, TX_EVENT ); +} + +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; + + mve_lock( sc ); + + switch ( cmd ) { + case SIOCSIFFLAGS: + f = if_getflags( ifp ); + df = if_getdrvflags( ifp ); + if ( (f & IFF_UP) ) { + if ( ! ( df & IFF_DRV_RUNNING ) ) { + mveth_init(sc); + } else { + if ( (f & IFF_PROMISC) != (sc->oif_flags & IFF_PROMISC) ) { + mveth_set_filters(ifp); + } + /* FIXME: other flag changes are ignored/unimplemented */ + } + } else { + if ( df & IFF_DRV_RUNNING ) { + mveth_stop(sc); + } + } + sc->oif_flags = f; + break; + +#ifdef TODO_ +/* what to do with lock ? */ + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + err = BSP_mve_media_ioctl(sc->pvt, cmd, &ifr->ifr_media); + break; +#endif + + case SIOCADDMULTI: + case SIOCDELMULTI: + if ( if_getdrvflags( ifp ) & IFF_DRV_RUNNING ) { + mveth_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 ); + + return err; +} + +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; + + mtx_init( &sc->mtx, device_get_nameunit( sc->dev ), MTX_NETWORK_LOCK, MTX_DEF ); + 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, + 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 ); + + ether_ifattach( ifp, hwaddr ); +} + +static device_method_t mve_methods[] = { + DEVMETHOD(device_probe, mve_probe), + 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); +#endif From 8a2815c8a867afc7e4479f21fce255e60bfa8073 Mon Sep 17 00:00:00 2001 From: till straumann Date: Wed, 10 Mar 2021 21:24:42 +0100 Subject: [PATCH 2/7] mv643xx_nexus.c: first working version was delayed by waf not printing compiler warnings by default! Three little typos cost me almost a day: - missing 'return 0;' at the end of mve_attach() - two bad pointers (wrong type) used All of these would have been found within minutes had the warnings not been disabled :-( --- rtemsbsd/include/bsp/nexus-devices.h | 1 + rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 426 ++++++++++++++++++++++----- 2 files changed, 355 insertions(+), 72 deletions(-) diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h index 9023c5577..4987ad881 100644 --- a/rtemsbsd/include/bsp/nexus-devices.h +++ b/rtemsbsd/include/bsp/nexus-devices.h @@ -200,6 +200,7 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus); #elif defined(LIBBSP_BEATNIK_BSP_H) RTEMS_BSD_DEFINE_NEXUS_DEVICE(mve, 0, 0, NULL); +SYSINIT_DRIVER_REFERENCE(ukphy, miibus); #endif diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index 96b08c327..efee04f7d 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -3,6 +3,7 @@ #ifdef LIBBSP_BEATNIK_BSP_H +#include #include #include #include @@ -12,10 +13,19 @@ #include #include #include +#include +#include #include +#include +#include +#include #include #include +#define DRVNAME "mv63xx_nexus" + +#undef MVETH_DEBUG + /* Define default ring sizes */ #ifdef MVETH_TESTING @@ -77,13 +87,18 @@ #define IRQ_EVENT RTEMS_EVENT_0 #define TX_EVENT RTEMS_EVENT_1 -/* Hack -- FIXME */ +/* 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; @@ -97,21 +112,45 @@ typedef struct MveMbufIter { 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_event_send(sc->daemonTid, 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) +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) +mve_unlock(struct mve_enet_softc *sc, const char *from) { +/*printk("L ^ %s\n", from);*/ mtx_unlock( & sc->mtx ); } @@ -121,9 +160,13 @@ 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 { + } else { err = ENXIO; } @@ -245,18 +288,54 @@ 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->daemonTid, IRQ_EVENT ); + mve_send_event( sc, IRQ_EVENT ); } static void -mveth_stop(struct mve_enet_softc *sc) +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) @@ -270,24 +349,25 @@ int sndStat; uint32_t irqstat; #ifdef MVETH_DEBUG - sleep(1); printk(DRVNAME": bsdnet mveth_daemon started\n"); #endif - mve_lock( sc ); + mve_lock( sc, "daemon" ); for (;;) { - mve_unlock( sc ); - rtems_event_receive( IRQ_EVENT | TX_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs ); - mve_lock( sc ); + 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) ) { - mveth_stop(sc); + mve_stop(sc); /* clear flag */ if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING); continue; @@ -306,23 +386,11 @@ uint32_t irqstat; irqstat = 0; } -#warning TODO_ -#if 0 - if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) ) { + if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) && sc->mii_softc ) { /* phy status changed */ - int media; - - if ( 0 == BSP_mve_ack_link_chg(sc->pvt, &media) ) { - if ( IFM_LINK_OK & media ) { - /* stop sending */ - if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); - mveth_start(ifp); - } else { - if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); - } - } + mii_pollstat( sc->mii_softc ); } -#endif + /* 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 ) { @@ -347,7 +415,7 @@ uint32_t irqstat; BSP_mve_enable_irqs(sc->mp); } - mve_unlock( sc ); + mve_unlock( sc, "daemon (xit)" ); } static void @@ -387,7 +455,7 @@ unsigned long l,o; m->m_len = m->m_pkthdr.len = l; *p_size = m->m_len; - *p_data = mtod(m, uintptr_t); + *p_data = mtod(m, uintptr_t); } return (void*) m; @@ -414,77 +482,133 @@ struct mbuf *m = (struct mbuf*)user_buf; 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; im_len; i++) { if ( !(i&15) ) - printf("\n"); - printf("0x%02x ",mtod(m,char*)[i]); + printk("\n"); + printk("0x%02x ",mtod(m,char*)[i]); } - printf("\n"); + printk("\n"); } - mve_unlock( sc ); + mve_unlock( sc, "rx_cleanup" ); (*ifp->if_input)(ifp, m); - mve_lock( sc ); + 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(void *arg) +mve_init_unlocked(struct mve_enet_softc *sc) { -struct mve_enet_softc *sc = (struct mve_enet_softc*)arg; struct ifnet *ifp = sc->ifp; int lowLevelMediaStatus = 0; -int promisc; +int promisc; - mve_lock( sc ); +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_init (entering)\n"); +#endif -#ifdef TODO__ -int media; - media = IFM_MAKEWORD(0, 0, 0, 0); - if ( 0 == BSP_mve_media_ioctl(sc->pvt, SIOCGIFMEDIA, &media) ) { - if ( (IFM_LINK_OK & media) ) { + 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); } } - lowLevelMediaStatus = xlateMediaFlags( media ); -#endif - 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 ) { - mveth_set_filters(ifp); + mve_set_filters(ifp); } - if ( ! sc->daemonTid ) { - sc->daemonTid = rtems_bsd_newproc("MVE", 4096, mve_daemon, (void*)sc); - } if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); +} - mve_unlock( sc ); +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(struct ifnet *ifp) +mve_start_unlocked(struct ifnet *ifp) { struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc; - mve_lock( sc ); - if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); - mve_unlock( sc ); + 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) { @@ -493,7 +617,11 @@ struct ifreq *ifr = (struct ifreq *)data; int err = 0; int f, df; - mve_lock( sc ); +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_ioctl (entering)\n"); +#endif + + mve_lock( sc, "mve_ioctl" ); switch ( cmd ) { case SIOCSIFFLAGS: @@ -501,33 +629,34 @@ int f, df; df = if_getdrvflags( ifp ); if ( (f & IFF_UP) ) { if ( ! ( df & IFF_DRV_RUNNING ) ) { - mveth_init(sc); + mve_init_unlocked(sc); } else { if ( (f & IFF_PROMISC) != (sc->oif_flags & IFF_PROMISC) ) { - mveth_set_filters(ifp); + mve_set_filters(ifp); } /* FIXME: other flag changes are ignored/unimplemented */ } } else { if ( df & IFF_DRV_RUNNING ) { - mveth_stop(sc); + mve_stop(sc); } } sc->oif_flags = f; break; -#ifdef TODO_ -/* what to do with lock ? */ case SIOCGIFMEDIA: case SIOCSIFMEDIA: - err = BSP_mve_media_ioctl(sc->pvt, cmd, &ifr->ifr_media); + if ( sc->mii_softc ) { + err = ifmedia_ioctl( ifp, ifr, &sc->mii_softc->mii_media, cmd ); + } else { + err = EINVAL; + } break; -#endif - + case SIOCADDMULTI: case SIOCDELMULTI: if ( if_getdrvflags( ifp ) & IFF_DRV_RUNNING ) { - mveth_set_filters(ifp); + mve_set_filters(ifp); } break; @@ -540,11 +669,81 @@ int f, df; break; } - mve_unlock( sc ); + 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) { @@ -561,8 +760,13 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; 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_DEF ); + 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; @@ -576,7 +780,7 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; if_setsendqready( ifp ); mp = BSP_mve_create( - unit, + unit + 1, /* low-level driver' unit numbers are 1-based */ 0, mve_isr, (void*)sc, release_tx_mbuf, (void*)sc, @@ -594,23 +798,101 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; 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_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 ) + 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 From 01f0797b96db93b982a7c6d3462c96ebe8a2d8cf Mon Sep 17 00:00:00 2001 From: till straumann Date: Wed, 10 Mar 2021 21:40:18 +0100 Subject: [PATCH 3/7] mv643xx_nexus.c: removed unlocked mve_init(), mve_start() The recursive lock takes care of this... --- rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 100 ++++++++++++++++++++------- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index efee04f7d..3cfccf512 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -1,3 +1,70 @@ +/* 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 + * rabeeh@galileo.co.il + * PMC-Sierra, Inc., Manish Lachwani + * Ralf Baechle + * MontaVista Software, Inc., Dale Farnsworth + * Steven J. Hill / + * + * 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 , 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, , 3/2021 */ + #include #include @@ -548,9 +615,10 @@ int msk = IFM_AVALID | IFM_ACTIVE; } static void -mve_init_unlocked(struct mve_enet_softc *sc) +mve_init(void *arg) { -struct ifnet *ifp = sc->ifp; +struct mve_enet_softc *sc = (struct mve_enet_softc*)arg; +struct ifnet *ifp = sc->ifp; int lowLevelMediaStatus = 0; int promisc; @@ -558,7 +626,6 @@ int promisc; printk(DRVNAME": mve_init (entering)\n"); #endif - if ( sc->mii_softc ) { mii_pollstat( sc->mii_softc ); lowLevelMediaStatus = xlateMediaFlags( sc->mii_softc ); @@ -582,33 +649,16 @@ int promisc; 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 ); + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); mve_unlock( sc, "mve_start" ); + mve_send_event( sc, TX_EVENT ); } - static int mve_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) { @@ -629,7 +679,7 @@ int f, df; df = if_getdrvflags( ifp ); if ( (f & IFF_UP) ) { if ( ! ( df & IFF_DRV_RUNNING ) ) { - mve_init_unlocked(sc); + mve_init( (void*)sc ); } else { if ( (f & IFF_PROMISC) != (sc->oif_flags & IFF_PROMISC) ) { mve_set_filters(ifp); @@ -694,7 +744,7 @@ int lowLevelMediaStatus; 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 ); + mve_start( sc->ifp ); } else { if_setdrvflagbits( sc->ifp, IFF_DRV_OACTIVE, 0 ); } @@ -741,7 +791,6 @@ struct mii_data *mii = sc->mii_softc; ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; } - } static int @@ -798,7 +847,6 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; sc->mp = mp; - BSP_mve_read_eaddr( mp, hwaddr ); if ( 0 == mii_attach( sc->dev, From 62a18c220581820f05d5a0f4190f26ef381a138a Mon Sep 17 00:00:00 2001 From: till straumann Date: Thu, 11 Mar 2021 17:37:03 +0100 Subject: [PATCH 4/7] mv643xx_nexus.c: removed 'repackage_chain()'. Testing (TCP with larger amounts of data while MVETH_TESTING was defined which reduces the ring sizes to very small numbers) revealed that the BSD stack honours the 'sendqlen' and never hands us chains exceeding the ring size. --- rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 33 ++-------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index 3cfccf512..e72fe98c2 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -95,8 +95,9 @@ /* Define default ring sizes */ -#ifdef MVETH_TESTING +#undef MVETH_TESTING +#ifdef MVETH_TESTING /* hard and small defaults */ #define MV643XX_RX_RING_SIZE 2 #define MV643XX_TX_QUEUE_SIZE 4 @@ -116,9 +117,6 @@ #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)) @@ -240,25 +238,6 @@ mve_probe(device_t dev) 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) @@ -328,8 +307,6 @@ mve_send_mbuf( struct mve_enet_softc *sc, struct mbuf *m_head ) MveMbufIter iter; int rval; -startover: - if ( ! m_head ) { return 0; } @@ -342,12 +319,6 @@ int rval; 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; } From 1b84c28292af3b0f049d7114d0a988c7e96c8601 Mon Sep 17 00:00:00 2001 From: till straumann Date: Thu, 11 Mar 2021 17:39:05 +0100 Subject: [PATCH 5/7] mv643xx_nexus.c: added a helper routine that allows printing of driver statistics The 'legal' access by means of a special ioctl() is way too cumbersome when you need to do quick diagnosis. --- rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index e72fe98c2..9bca4d779 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -171,6 +171,8 @@ struct mve_enet_softc { int oif_flags; }; +static struct mve_enet_softc * ifaces[MV643XXETH_NUM_DRIVER_SLOTS] = { 0 }; + typedef struct MveMbufIter { MveEthBufIter it; struct mbuf *next; @@ -695,6 +697,18 @@ int f, df; return err; } +/* SIO RTEMS_SHOW_STATS is too cumbersome to use -- for debugging, provide direct hack */ +int +mv643xx_nexus_dump_stats(int unit, FILE *f) +{ + if ( unit < 0 || unit >= MV643XXETH_NUM_DRIVER_SLOTS || ! ifaces[unit] ) + return -EINVAL; + if ( ! f ) + f = stdout; + BSP_mve_dump_stats(ifaces[unit]->mp, f); + return 0; +} + /* * Used to update speed settings in the hardware * when the phy setup changes. @@ -840,6 +854,8 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; printk(DRVNAME": mve_attach (leaving)\n"); #endif + ifaces[unit] = sc; + return 0; } From 978ee3bc0d7775cf33d91e2e75163c5eef12c8b7 Mon Sep 17 00:00:00 2001 From: till straumann Date: Thu, 11 Mar 2021 17:45:13 +0100 Subject: [PATCH 6/7] mv643xx_nexus.c: more use of if_xxx() access functions avoid using struct members directly. --- rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index 9bca4d779..041e8c515 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -346,7 +346,7 @@ mve_stop(struct mve_enet_softc *sc) static void mve_set_filters(struct ifnet *ifp) { -struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc; +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); int iff = if_getflags(ifp); struct ifmultiaddr *ifma; unsigned char *lladdr; @@ -625,7 +625,7 @@ int promisc; static void mve_start(struct ifnet *ifp) { -struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc; +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); mve_lock( sc, "mve_start" ); if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); mve_unlock( sc, "mve_start" ); @@ -635,7 +635,7 @@ struct mve_enet_softc *sc = (struct mve_enet_softc*)ifp->if_softc; 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 mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); struct ifreq *ifr = (struct ifreq *)data; int err = 0; int f, df; @@ -744,7 +744,7 @@ int lowLevelMediaStatus; static int mve_media_change(struct ifnet *ifp) { -struct mve_enet_softc *sc = (struct mve_enet_softc *)ifp->if_softc; +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); struct mii_data *mii = sc->mii_softc; int err; @@ -764,7 +764,7 @@ int 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 mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); struct mii_data *mii = sc->mii_softc; #ifdef MVETH_DEBUG @@ -803,14 +803,15 @@ int tx_q_size = MV643XX_TX_QUEUE_SIZE; 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_setsoftc ( ifp, sc ); + if_initname ( ifp, device_get_name(dev), unit); + if_setinitfn ( ifp, mve_init ); + if_setioctlfn ( ifp, mve_ioctl ); + if_setstartfn ( ifp, 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( From c305316a6a35ed24216af44fd5f3712700dffe21 Mon Sep 17 00:00:00 2001 From: till straumann Date: Thu, 11 Mar 2021 17:46:20 +0100 Subject: [PATCH 7/7] mv643xx_nexus.c: removed trailing blanks --- rtemsbsd/sys/dev/mve/mv643xx_nexus.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c index 041e8c515..872ce1894 100644 --- a/rtemsbsd/sys/dev/mve/mv643xx_nexus.c +++ b/rtemsbsd/sys/dev/mve/mv643xx_nexus.c @@ -18,19 +18,19 @@ * new implementation and is the original work by the author. */ -/* +/* * Authorship * ---------- * This software (mv643xx ethernet driver for RTEMS) was * created by Till Straumann , 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, @@ -39,18 +39,18 @@ * 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. - * + * freely use it for any purpose without restriction. + * * Maintenance of notices * ---------------------- * In the interest of clarity regarding the origin and status of this @@ -59,9 +59,9 @@ * 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, , 3/2021 */