diff --git a/sys/rump/net/lib/libshmif/if_shmem.c b/sys/rump/net/lib/libshmif/if_shmem.c index 2c64b29dfff0..6c7f73339c11 100644 --- a/sys/rump/net/lib/libshmif/if_shmem.c +++ b/sys/rump/net/lib/libshmif/if_shmem.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_shmem.c,v 1.26 2010/08/16 17:33:52 pooka Exp $ */ +/* $NetBSD: if_shmem.c,v 1.27 2010/08/17 11:35:23 pooka Exp $ */ /* * Copyright (c) 2009 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_shmem.c,v 1.26 2010/08/16 17:33:52 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_shmem.c,v 1.27 2010/08/17 11:35:23 pooka Exp $"); #include #include @@ -267,16 +267,17 @@ shmif_start(struct ifnet *ifp) mtod(m, void *), m->m_len, &wrap); } KASSERT(pktwrote == pktsize); - - if (wrap) + if (wrap) { busmem->shm_gen++; + DPRINTF(("bus generation now %d\n", busmem->shm_gen)); + } shmif_unlockbus(busmem); m_freem(m0); wrote = true; DPRINTF(("shmif_start: send %d bytes at off %d\n", - pktsize, npktlenoff)); + pktsize, busmem->shm_last)); } ifp->if_flags &= ~IFF_OACTIVE; @@ -294,6 +295,44 @@ shmif_stop(struct ifnet *ifp, int disable) panic("%s: unimpl", __func__); } + +/* + * Check if we have been sleeping too long. Basically, + * our in-sc nextpkt must by first <= nextpkt <= last"+1". + * We use the fact that first is guaranteed to never overlap + * with the last frame in the ring. + */ +static __inline bool +stillvalid_p(struct shmif_sc *sc) +{ + struct shmif_mem *busmem = sc->sc_busmem; + unsigned gendiff = busmem->shm_gen - sc->sc_devgen; + uint32_t lastoff, devoff; + + KASSERT(busmem->shm_first != busmem->shm_last); + + /* normalize onto a 2x busmem chunk */ + devoff = sc->sc_nextpacket; + lastoff = shmif_nextpktoff(busmem, busmem->shm_last); + + /* trivial case */ + if (gendiff > 1) + return false; + KASSERT(gendiff <= 1); + + /* Normalize onto 2x busmem chunk */ + if (busmem->shm_first >= lastoff) { + lastoff += BUSMEM_DATASIZE; + if (gendiff == 0) + devoff += BUSMEM_DATASIZE; + } else { + if (gendiff) + return false; + } + + return devoff >= busmem->shm_first && devoff <= lastoff; +} + static void shmif_rcv(void *arg) { @@ -302,7 +341,7 @@ shmif_rcv(void *arg) struct shmif_mem *busmem = sc->sc_busmem; struct mbuf *m = NULL; struct ether_header *eth; - uint32_t nextpkt, busgen; + uint32_t nextpkt; bool wrap; int error; @@ -318,12 +357,11 @@ shmif_rcv(void *arg) KASSERT(m->m_flags & M_EXT); shmif_lockbus(busmem); - busgen = busmem->shm_gen; KASSERT(busmem->shm_magic == SHMIF_MAGIC); - KASSERT(busgen >= sc->sc_devgen); + KASSERT(busmem->shm_gen >= sc->sc_devgen); /* need more data? */ - if (sc->sc_devgen == busgen && + if (sc->sc_devgen == busmem->shm_gen && shmif_nextpktoff(busmem, busmem->shm_last) == sc->sc_nextpacket) { shmif_unlockbus(busmem); @@ -334,23 +372,17 @@ shmif_rcv(void *arg) continue; } - /* - * Check if we have been sleeping too long. There are - * basically two scenarios: - * 1) our next packet is behind the first packet and - * we are a generation behind - * 2) we are over two generations behind - */ - if ((sc->sc_nextpacket < busmem->shm_first - && sc->sc_devgen < busgen) || (sc->sc_devgen+1 < busgen)) { - KASSERT(busgen > 0); + if (stillvalid_p(sc)) { + nextpkt = sc->sc_nextpacket; + } else { + KASSERT(busmem->shm_gen > 0); nextpkt = busmem->shm_first; if (busmem->shm_first > busmem->shm_last) - sc->sc_devgen = busgen - 1; + sc->sc_devgen = busmem->shm_gen - 1; else - sc->sc_devgen = busgen; - } else { - nextpkt = sc->sc_nextpacket; + sc->sc_devgen = busmem->shm_gen; + DPRINTF(("dev %p overrun, new data: %d/%d\n", + sc, nextpkt, sc->sc_devgen)); } /* @@ -358,7 +390,7 @@ shmif_rcv(void *arg) * generation must be one behind. */ KASSERT(!(nextpkt > busmem->shm_last - && sc->sc_devgen == busgen)); + && sc->sc_devgen == busmem->shm_gen)); wrap = false; nextpkt = shmif_busread(busmem, &sp, @@ -373,8 +405,11 @@ shmif_rcv(void *arg) sc->sc_nextpacket = nextpkt; shmif_unlockbus(sc->sc_busmem); - if (wrap) + if (wrap) { sc->sc_devgen++; + DPRINTF(("dev %p generation now %d\n", + sc, sc->sc_devgen)); + } m->m_len = m->m_pkthdr.len = sp.sp_len; m->m_pkthdr.rcvif = ifp; diff --git a/sys/rump/net/lib/libshmif/shmif_busops.c b/sys/rump/net/lib/libshmif/shmif_busops.c index 934d30cfb771..3821df5797ac 100644 --- a/sys/rump/net/lib/libshmif/shmif_busops.c +++ b/sys/rump/net/lib/libshmif/shmif_busops.c @@ -1,4 +1,4 @@ -/* $NetBSD: shmif_busops.c,v 1.5 2010/08/16 17:33:52 pooka Exp $ */ +/* $NetBSD: shmif_busops.c,v 1.6 2010/08/17 11:35:23 pooka Exp $ */ /* * Copyright (c) 2009 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: shmif_busops.c,v 1.5 2010/08/16 17:33:52 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: shmif_busops.c,v 1.6 2010/08/17 11:35:23 pooka Exp $"); #include #include @@ -64,11 +64,12 @@ shmif_busread(struct shmif_mem *busmem, void *dest, uint32_t off, size_t len, memcpy(dest, busmem->shm_data + off, chunk); len -= chunk; - if (len == 0) - return off + chunk; + if (off + chunk == BUSMEM_DATASIZE) + *wrap = true; - /* else, wraps around */ - *wrap = true; + if (len == 0) { + return (off + chunk) % BUSMEM_DATASIZE; + } /* finish reading */ memcpy((uint8_t *)dest + chunk, busmem->shm_data, len); @@ -104,22 +105,21 @@ shmif_buswrite(struct shmif_mem *busmem, uint32_t off, void *data, size_t len, DPRINTF(("buswrite: wrote %d bytes to %d", chunk, off)); + if (off + chunk == BUSMEM_DATASIZE) + *wrap = true; + if (len == 0) { DPRINTF(("\n")); - return off + chunk; + return (off + chunk) % BUSMEM_DATASIZE; } DPRINTF((", wrapped bytes %d to 0\n", len)); - /* else, wraps around */ - off = 0; - *wrap = true; - - shmif_advancefirst(busmem, off, len); + shmif_advancefirst(busmem, 0, len); /* finish writing */ - memcpy(busmem->shm_data + off, (uint8_t *)data + chunk, len); - return off + len; + memcpy(busmem->shm_data, (uint8_t *)data + chunk, len); + return len; } uint32_t