[BACK]Return to if_shmem.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / rump / net / lib / libshmif

Annotation of src/sys/rump/net/lib/libshmif/if_shmem.c, Revision 1.53

1.53    ! pooka       1: /*     $NetBSD: if_shmem.c,v 1.52 2013/04/29 20:08:49 pooka Exp $      */
1.1       pooka       2:
                      3: /*
1.39      pooka       4:  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
1.1       pooka       5:  *
                      6:  * Development of this software was supported by The Nokia Foundation.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     18:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     19:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     20:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     23:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: #include <sys/cdefs.h>
1.53    ! pooka      31: __KERNEL_RCSID(0, "$NetBSD: if_shmem.c,v 1.52 2013/04/29 20:08:49 pooka Exp $");
1.1       pooka      32:
                     33: #include <sys/param.h>
1.13      pooka      34: #include <sys/atomic.h>
1.1       pooka      35: #include <sys/fcntl.h>
                     36: #include <sys/kmem.h>
                     37: #include <sys/kthread.h>
                     38: #include <sys/lock.h>
1.31      pooka      39: #include <sys/vmem.h>
1.44      tls        40: #include <sys/cprng.h>
1.1       pooka      41:
1.35      pooka      42: #include <net/bpf.h>
1.1       pooka      43: #include <net/if.h>
1.37      pooka      44: #include <net/if_dl.h>
1.1       pooka      45: #include <net/if_ether.h>
                     46:
                     47: #include <netinet/in.h>
                     48: #include <netinet/in_var.h>
                     49:
                     50: #include <rump/rump.h>
                     51: #include <rump/rumpuser.h>
                     52:
                     53: #include "rump_private.h"
1.9       pooka      54: #include "rump_net_private.h"
1.48      pooka      55: #include "rumpcomp_user.h"
1.1       pooka      56:
1.29      pooka      57: static int shmif_clone(struct if_clone *, int);
                     58: static int shmif_unclone(struct ifnet *);
                     59:
                     60: struct if_clone shmif_cloner =
                     61:     IF_CLONE_INITIALIZER("shmif", shmif_clone, shmif_unclone);
                     62:
1.1       pooka      63: /*
1.28      pooka      64:  * Do r/w prefault for backend pages when attaching the interface.
1.29      pooka      65:  * At least logically thinking improves performance (although no
                     66:  * mlocking is done, so they might go away).
1.28      pooka      67:  */
                     68: #define PREFAULT_RW
                     69:
                     70: /*
1.1       pooka      71:  * A virtual ethernet interface which uses shared memory from a
                     72:  * memory mapped file as the bus.
                     73:  */
                     74:
                     75: static int     shmif_init(struct ifnet *);
                     76: static int     shmif_ioctl(struct ifnet *, u_long, void *);
                     77: static void    shmif_start(struct ifnet *);
                     78: static void    shmif_stop(struct ifnet *, int);
                     79:
1.16      pooka      80: #include "shmifvar.h"
                     81:
1.1       pooka      82: struct shmif_sc {
                     83:        struct ethercom sc_ec;
1.16      pooka      84:        struct shmif_mem *sc_busmem;
1.1       pooka      85:        int sc_memfd;
                     86:        int sc_kq;
1.32      pooka      87:        int sc_unit;
1.1       pooka      88:
1.29      pooka      89:        char *sc_backfile;
                     90:        size_t sc_backfilelen;
                     91:
1.26      pooka      92:        uint64_t sc_devgen;
1.1       pooka      93:        uint32_t sc_nextpacket;
1.32      pooka      94:
                     95:        kmutex_t sc_mtx;
                     96:        kcondvar_t sc_cv;
                     97:
                     98:        struct lwp *sc_rcvl;
                     99:        bool sc_dying;
1.1       pooka     100: };
                    101:
1.17      pooka     102: static const uint32_t busversion = SHMIF_VERSION;
1.1       pooka     103:
                    104: static void shmif_rcv(void *);
                    105:
1.23      pooka     106: #define LOCK_UNLOCKED  0
                    107: #define LOCK_LOCKED    1
                    108: #define LOCK_COOLDOWN  1001
                    109:
1.31      pooka     110: vmem_t *shmif_units;
                    111:
1.52      pooka     112: static void
                    113: dowakeup(struct shmif_sc *sc)
                    114: {
                    115:        struct rumpuser_iovec iov;
                    116:        uint32_t ver = SHMIF_VERSION;
1.53    ! pooka     117:        size_t n;
1.52      pooka     118:
                    119:        iov.iov_base = &ver;
                    120:        iov.iov_len = sizeof(ver);
1.53    ! pooka     121:        rumpuser_iovwrite(sc->sc_memfd, &iov, 1, IFMEM_WAKEUP, &n);
1.52      pooka     122: }
                    123:
1.23      pooka     124: /*
                    125:  * This locking needs work and will misbehave severely if:
                    126:  * 1) the backing memory has to be paged in
                    127:  * 2) some lockholder exits while holding the lock
                    128:  */
                    129: static void
                    130: shmif_lockbus(struct shmif_mem *busmem)
                    131: {
                    132:        int i = 0;
                    133:
                    134:        while (__predict_false(atomic_cas_32(&busmem->shm_lock,
                    135:            LOCK_UNLOCKED, LOCK_LOCKED) == LOCK_LOCKED)) {
                    136:                if (__predict_false(++i > LOCK_COOLDOWN)) {
1.50      pooka     137:                        /* wait 1ms */
                    138:                        rumpuser_clock_sleep(0, 1000*1000,
                    139:                            RUMPUSER_CLOCK_RELWALL);
1.23      pooka     140:                        i = 0;
                    141:                }
                    142:                continue;
                    143:        }
                    144:        membar_enter();
                    145: }
                    146:
                    147: static void
                    148: shmif_unlockbus(struct shmif_mem *busmem)
                    149: {
                    150:        unsigned int old;
                    151:
                    152:        membar_exit();
                    153:        old = atomic_swap_32(&busmem->shm_lock, LOCK_UNLOCKED);
                    154:        KASSERT(old == LOCK_LOCKED);
                    155: }
                    156:
1.29      pooka     157: static int
                    158: allocif(int unit, struct shmif_sc **scp)
1.1       pooka     159: {
1.29      pooka     160:        uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0xa0, 0x00, 0x00, 0x00, 0x00 };
1.1       pooka     161:        struct shmif_sc *sc;
                    162:        struct ifnet *ifp;
                    163:        uint32_t randnum;
1.32      pooka     164:        int error;
1.1       pooka     165:
1.44      tls       166:        randnum = cprng_fast32();
1.15      pooka     167:        memcpy(&enaddr[2], &randnum, sizeof(randnum));
1.1       pooka     168:
                    169:        sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
1.29      pooka     170:        sc->sc_memfd = -1;
1.32      pooka     171:        sc->sc_unit = unit;
1.29      pooka     172:
1.1       pooka     173:        ifp = &sc->sc_ec.ec_if;
                    174:
1.32      pooka     175:        sprintf(ifp->if_xname, "shmif%d", unit);
1.29      pooka     176:        ifp->if_softc = sc;
                    177:        ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
                    178:        ifp->if_init = shmif_init;
                    179:        ifp->if_ioctl = shmif_ioctl;
                    180:        ifp->if_start = shmif_start;
                    181:        ifp->if_stop = shmif_stop;
                    182:        ifp->if_mtu = ETHERMTU;
1.37      pooka     183:        ifp->if_dlt = DLT_EN10MB;
1.29      pooka     184:
1.32      pooka     185:        mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
                    186:        cv_init(&sc->sc_cv, "shmifcv");
                    187:
1.29      pooka     188:        if_attach(ifp);
                    189:        ether_ifattach(ifp, enaddr);
                    190:
                    191:        aprint_verbose("shmif%d: Ethernet address %s\n",
1.32      pooka     192:            unit, ether_sprintf(enaddr));
1.29      pooka     193:
                    194:        if (scp)
                    195:                *scp = sc;
                    196:
1.32      pooka     197:        error = 0;
                    198:        if (rump_threads) {
                    199:                error = kthread_create(PRI_NONE,
1.40      rmind     200:                    KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
1.32      pooka     201:                    shmif_rcv, ifp, &sc->sc_rcvl, "shmif");
                    202:        } else {
                    203:                printf("WARNING: threads not enabled, shmif NOT working\n");
                    204:        }
                    205:
                    206:        if (error) {
                    207:                shmif_unclone(ifp);
                    208:        }
                    209:
                    210:        return error;
1.29      pooka     211: }
                    212:
                    213: static int
                    214: initbackend(struct shmif_sc *sc, int memfd)
                    215: {
                    216:        volatile uint8_t v;
                    217:        volatile uint8_t *p;
1.53    ! pooka     218:        void *mem;
1.29      pooka     219:        int error;
                    220:
1.53    ! pooka     221:        error = rumpcomp_shmif_mmap(memfd, BUSMEM_SIZE, &mem);
1.1       pooka     222:        if (error)
1.29      pooka     223:                return error;
1.53    ! pooka     224:        sc->sc_busmem = mem;
1.17      pooka     225:
1.29      pooka     226:        if (sc->sc_busmem->shm_magic
                    227:            && sc->sc_busmem->shm_magic != SHMIF_MAGIC) {
                    228:                printf("bus is not magical");
                    229:                rumpuser_unmap(sc->sc_busmem, BUSMEM_SIZE);
                    230:                return ENOEXEC;
                    231:        }
1.28      pooka     232:
1.36      pooka     233:        /*
                    234:         * Prefault in pages to minimize runtime penalty with buslock.
                    235:         * Use 512 instead of PAGE_SIZE to make sure we catch cases where
                    236:         * rump kernel PAGE_SIZE > host page size.
                    237:         */
1.28      pooka     238:        for (p = (uint8_t *)sc->sc_busmem;
                    239:            p < (uint8_t *)sc->sc_busmem + BUSMEM_SIZE;
1.36      pooka     240:            p += 512)
1.28      pooka     241:                v = *p;
                    242:
1.19      pooka     243:        shmif_lockbus(sc->sc_busmem);
                    244:        /* we're first?  initialize bus */
                    245:        if (sc->sc_busmem->shm_magic == 0) {
                    246:                sc->sc_busmem->shm_magic = SHMIF_MAGIC;
                    247:                sc->sc_busmem->shm_first = BUSMEM_DATASIZE;
                    248:        }
                    249:
1.16      pooka     250:        sc->sc_nextpacket = sc->sc_busmem->shm_last;
1.26      pooka     251:        sc->sc_devgen = sc->sc_busmem->shm_gen;
1.28      pooka     252:
                    253: #ifdef PREFAULT_RW
                    254:        for (p = (uint8_t *)sc->sc_busmem;
                    255:            p < (uint8_t *)sc->sc_busmem + BUSMEM_SIZE;
                    256:            p += PAGE_SIZE) {
                    257:                v = *p;
                    258:                *p = v;
                    259:        }
                    260: #endif
1.19      pooka     261:        shmif_unlockbus(sc->sc_busmem);
1.1       pooka     262:
1.53    ! pooka     263:        sc->sc_kq = -1;
        !           264:        error = rumpcomp_shmif_watchsetup(&sc->sc_kq, memfd);
        !           265:        if (error) {
1.32      pooka     266:                rumpuser_unmap(sc->sc_busmem, BUSMEM_SIZE);
1.29      pooka     267:                return error;
1.32      pooka     268:        }
1.1       pooka     269:
1.29      pooka     270:        sc->sc_memfd = memfd;
1.32      pooka     271:
                    272:        return error;
1.29      pooka     273: }
                    274:
                    275: static void
                    276: finibackend(struct shmif_sc *sc)
                    277: {
                    278:
1.32      pooka     279:        if (sc->sc_backfile == NULL)
                    280:                return;
                    281:
                    282:        if (sc->sc_backfile) {
                    283:                kmem_free(sc->sc_backfile, sc->sc_backfilelen);
                    284:                sc->sc_backfile = NULL;
                    285:                sc->sc_backfilelen = 0;
                    286:        }
1.29      pooka     287:
                    288:        rumpuser_unmap(sc->sc_busmem, BUSMEM_SIZE);
1.53    ! pooka     289:        rumpuser_close(sc->sc_memfd);
        !           290:        rumpuser_close(sc->sc_kq);
1.32      pooka     291:
                    292:        sc->sc_memfd = -1;
1.29      pooka     293: }
                    294:
                    295: int
                    296: rump_shmif_create(const char *path, int *ifnum)
                    297: {
                    298:        struct shmif_sc *sc;
1.43      dyoung    299:        vmem_addr_t t;
1.33      pooka     300:        int unit, error;
                    301:        int memfd = -1; /* XXXgcc */
1.29      pooka     302:
1.33      pooka     303:        if (path) {
1.53    ! pooka     304:                error = rumpuser_open(path,
        !           305:                    RUMPUSER_OPEN_RDWR | RUMPUSER_OPEN_CREATE, &memfd);
        !           306:                if (error)
1.33      pooka     307:                        return error;
                    308:        }
1.1       pooka     309:
1.43      dyoung    310:        error = vmem_xalloc(shmif_units, 1, 0, 0, 0,
                    311:            VMEM_ADDR_MIN, VMEM_ADDR_MAX, VM_INSTANTFIT | VM_SLEEP, &t);
                    312:
                    313:        if (error != 0) {
                    314:                if (path)
1.53    ! pooka     315:                        rumpuser_close(memfd);
1.43      dyoung    316:                return error;
                    317:        }
                    318:
                    319:        unit = t - 1;
1.31      pooka     320:
1.32      pooka     321:        if ((error = allocif(unit, &sc)) != 0) {
1.33      pooka     322:                if (path)
1.53    ! pooka     323:                        rumpuser_close(memfd);
1.29      pooka     324:                return error;
                    325:        }
1.33      pooka     326:
                    327:        if (!path)
                    328:                goto out;
                    329:
1.29      pooka     330:        error = initbackend(sc, memfd);
                    331:        if (error) {
1.32      pooka     332:                shmif_unclone(&sc->sc_ec.ec_if);
1.29      pooka     333:                return error;
                    334:        }
1.1       pooka     335:
1.29      pooka     336:        sc->sc_backfilelen = strlen(path)+1;
                    337:        sc->sc_backfile = kmem_alloc(sc->sc_backfilelen, KM_SLEEP);
                    338:        strcpy(sc->sc_backfile, path);
1.12      pooka     339:
1.33      pooka     340:  out:
1.2       pooka     341:        if (ifnum)
1.32      pooka     342:                *ifnum = unit;
1.29      pooka     343:
1.1       pooka     344:        return 0;
1.29      pooka     345: }
1.1       pooka     346:
1.29      pooka     347: static int
                    348: shmif_clone(struct if_clone *ifc, int unit)
                    349: {
1.43      dyoung    350:        int rc;
                    351:        vmem_addr_t unit2;
1.29      pooka     352:
1.31      pooka     353:        /*
                    354:         * Ok, we know the unit number, but we must still reserve it.
                    355:         * Otherwise the wildcard-side of things might get the same one.
                    356:         * This is slightly offset-happy due to vmem.  First, we offset
                    357:         * the range of unit numbers by +1 since vmem cannot deal with
1.41      dyoung    358:         * ranges starting from 0.  Talk about uuuh.
1.31      pooka     359:         */
1.43      dyoung    360:        rc = vmem_xalloc(shmif_units, 1, 0, 0, 0, unit+1, unit+1,
                    361:            VM_SLEEP | VM_INSTANTFIT, &unit2);
                    362:        KASSERT(rc == 0 && unit2-1 == unit);
1.29      pooka     363:
                    364:        return allocif(unit, NULL);
                    365: }
                    366:
                    367: static int
                    368: shmif_unclone(struct ifnet *ifp)
                    369: {
1.32      pooka     370:        struct shmif_sc *sc = ifp->if_softc;
                    371:
                    372:        shmif_stop(ifp, 1);
                    373:        if_down(ifp);
                    374:        finibackend(sc);
                    375:
                    376:        mutex_enter(&sc->sc_mtx);
                    377:        sc->sc_dying = true;
                    378:        cv_broadcast(&sc->sc_cv);
                    379:        mutex_exit(&sc->sc_mtx);
1.29      pooka     380:
1.32      pooka     381:        if (sc->sc_rcvl)
                    382:                kthread_join(sc->sc_rcvl);
                    383:        sc->sc_rcvl = NULL;
                    384:
                    385:        vmem_xfree(shmif_units, sc->sc_unit+1, 1);
                    386:
                    387:        ether_ifdetach(ifp);
                    388:        if_detach(ifp);
                    389:
                    390:        cv_destroy(&sc->sc_cv);
                    391:        mutex_destroy(&sc->sc_mtx);
                    392:
                    393:        kmem_free(sc, sizeof(*sc));
                    394:
                    395:        return 0;
1.1       pooka     396: }
                    397:
                    398: static int
                    399: shmif_init(struct ifnet *ifp)
                    400: {
1.29      pooka     401:        struct shmif_sc *sc = ifp->if_softc;
1.4       pooka     402:        int error = 0;
                    403:
1.29      pooka     404:        if (sc->sc_memfd == -1)
                    405:                return ENXIO;
1.32      pooka     406:        KASSERT(sc->sc_busmem);
1.29      pooka     407:
1.32      pooka     408:        ifp->if_flags |= IFF_RUNNING;
                    409:
                    410:        mutex_enter(&sc->sc_mtx);
                    411:        sc->sc_nextpacket = sc->sc_busmem->shm_last;
                    412:        sc->sc_devgen = sc->sc_busmem->shm_gen;
                    413:
                    414:        cv_broadcast(&sc->sc_cv);
                    415:        mutex_exit(&sc->sc_mtx);
1.1       pooka     416:
1.4       pooka     417:        return error;
1.1       pooka     418: }
                    419:
                    420: static int
                    421: shmif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
                    422: {
1.29      pooka     423:        struct shmif_sc *sc = ifp->if_softc;
                    424:        struct ifdrv *ifd;
                    425:        char *path;
1.32      pooka     426:        int s, rv, memfd;
1.1       pooka     427:
                    428:        s = splnet();
1.29      pooka     429:        switch (cmd) {
                    430:        case SIOCGLINKSTR:
                    431:                ifd = data;
                    432:
                    433:                if (sc->sc_backfilelen == 0) {
                    434:                        rv = ENOENT;
                    435:                        break;
                    436:                }
                    437:
                    438:                ifd->ifd_len = sc->sc_backfilelen;
                    439:                if (ifd->ifd_cmd == IFLINKSTR_QUERYLEN) {
                    440:                        rv = 0;
                    441:                        break;
                    442:                }
                    443:
                    444:                if (ifd->ifd_cmd != 0) {
                    445:                        rv = EINVAL;
                    446:                        break;
                    447:                }
                    448:
                    449:                rv = copyoutstr(sc->sc_backfile, ifd->ifd_data,
                    450:                    MIN(sc->sc_backfilelen, ifd->ifd_len), NULL);
                    451:                break;
                    452:        case SIOCSLINKSTR:
                    453:                if (ifp->if_flags & IFF_UP) {
                    454:                        rv = EBUSY;
                    455:                        break;
                    456:                }
                    457:
                    458:                ifd = data;
                    459:                if (ifd->ifd_cmd == IFLINKSTR_UNSET) {
                    460:                        finibackend(sc);
                    461:                        rv = 0;
                    462:                        break;
                    463:                } else if (ifd->ifd_cmd != 0) {
                    464:                        rv = EINVAL;
                    465:                        break;
                    466:                } else if (sc->sc_backfile) {
                    467:                        rv = EBUSY;
                    468:                        break;
                    469:                }
                    470:
                    471:                if (ifd->ifd_len > MAXPATHLEN) {
                    472:                        rv = E2BIG;
                    473:                        break;
                    474:                } else if (ifd->ifd_len < 1) {
                    475:                        rv = EINVAL;
                    476:                        break;
                    477:                }
                    478:
                    479:                path = kmem_alloc(ifd->ifd_len, KM_SLEEP);
                    480:                rv = copyinstr(ifd->ifd_data, path, ifd->ifd_len, NULL);
                    481:                if (rv) {
                    482:                        kmem_free(path, ifd->ifd_len);
                    483:                        break;
                    484:                }
1.53    ! pooka     485:                rv = rumpuser_open(path,
        !           486:                    RUMPUSER_OPEN_RDWR | RUMPUSER_OPEN_CREATE, &memfd);
        !           487:                if (rv) {
1.29      pooka     488:                        kmem_free(path, ifd->ifd_len);
                    489:                        break;
                    490:                }
                    491:                rv = initbackend(sc, memfd);
                    492:                if (rv) {
                    493:                        kmem_free(path, ifd->ifd_len);
1.53    ! pooka     494:                        rumpuser_close(memfd);
1.29      pooka     495:                        break;
                    496:                }
                    497:                sc->sc_backfile = path;
                    498:                sc->sc_backfilelen = ifd->ifd_len;
                    499:
                    500:                break;
                    501:        default:
                    502:                rv = ether_ioctl(ifp, cmd, data);
                    503:                if (rv == ENETRESET)
                    504:                        rv = 0;
                    505:                break;
                    506:        }
1.1       pooka     507:        splx(s);
                    508:
                    509:        return rv;
                    510: }
                    511:
1.32      pooka     512: /* send everything in-context since it's just a matter of mem-to-mem copy */
1.1       pooka     513: static void
                    514: shmif_start(struct ifnet *ifp)
                    515: {
                    516:        struct shmif_sc *sc = ifp->if_softc;
1.26      pooka     517:        struct shmif_mem *busmem = sc->sc_busmem;
1.1       pooka     518:        struct mbuf *m, *m0;
1.26      pooka     519:        uint32_t dataoff;
                    520:        uint32_t pktsize, pktwrote;
1.1       pooka     521:        bool wrote = false;
1.24      pooka     522:        bool wrap;
1.1       pooka     523:
1.26      pooka     524:        ifp->if_flags |= IFF_OACTIVE;
                    525:
1.1       pooka     526:        for (;;) {
1.20      pooka     527:                struct shmif_pkthdr sp;
                    528:                struct timeval tv;
                    529:
1.1       pooka     530:                IF_DEQUEUE(&ifp->if_snd, m0);
                    531:                if (m0 == NULL) {
                    532:                        break;
                    533:                }
                    534:
1.25      pooka     535:                pktsize = 0;
1.19      pooka     536:                for (m = m0; m != NULL; m = m->m_next) {
                    537:                        pktsize += m->m_len;
                    538:                }
1.26      pooka     539:                KASSERT(pktsize <= ETHERMTU + ETHER_HDR_LEN);
1.19      pooka     540:
1.20      pooka     541:                getmicrouptime(&tv);
                    542:                sp.sp_len = pktsize;
                    543:                sp.sp_sec = tv.tv_sec;
                    544:                sp.sp_usec = tv.tv_usec;
                    545:
1.35      pooka     546:                bpf_mtap(ifp, m0);
                    547:
1.26      pooka     548:                shmif_lockbus(busmem);
                    549:                KASSERT(busmem->shm_magic == SHMIF_MAGIC);
                    550:                busmem->shm_last = shmif_nextpktoff(busmem, busmem->shm_last);
1.21      pooka     551:
1.24      pooka     552:                wrap = false;
1.26      pooka     553:                dataoff = shmif_buswrite(busmem,
                    554:                    busmem->shm_last, &sp, sizeof(sp), &wrap);
                    555:                pktwrote = 0;
1.1       pooka     556:                for (m = m0; m != NULL; m = m->m_next) {
1.26      pooka     557:                        pktwrote += m->m_len;
                    558:                        dataoff = shmif_buswrite(busmem, dataoff,
1.19      pooka     559:                            mtod(m, void *), m->m_len, &wrap);
1.1       pooka     560:                }
1.26      pooka     561:                KASSERT(pktwrote == pktsize);
1.27      pooka     562:                if (wrap) {
1.26      pooka     563:                        busmem->shm_gen++;
1.47      pooka     564:                        DPRINTF(("bus generation now %" PRIu64 "\n",
                    565:                            busmem->shm_gen));
1.27      pooka     566:                }
1.26      pooka     567:                shmif_unlockbus(busmem);
1.1       pooka     568:
                    569:                m_freem(m0);
                    570:                wrote = true;
                    571:
                    572:                DPRINTF(("shmif_start: send %d bytes at off %d\n",
1.27      pooka     573:                    pktsize, busmem->shm_last));
1.1       pooka     574:        }
1.26      pooka     575:
                    576:        ifp->if_flags &= ~IFF_OACTIVE;
                    577:
1.32      pooka     578:        /* wakeup? */
1.52      pooka     579:        if (wrote) {
                    580:                dowakeup(sc);
                    581:        }
1.1       pooka     582: }
                    583:
                    584: static void
                    585: shmif_stop(struct ifnet *ifp, int disable)
                    586: {
1.32      pooka     587:        struct shmif_sc *sc = ifp->if_softc;
1.1       pooka     588:
1.32      pooka     589:        ifp->if_flags &= ~IFF_RUNNING;
                    590:        membar_producer();
                    591:
                    592:        /*
                    593:         * wakeup thread.  this will of course wake up all bus
                    594:         * listeners, but that's life.
                    595:         */
1.52      pooka     596:        if (sc->sc_memfd != -1) {
                    597:                dowakeup(sc);
                    598:        }
1.1       pooka     599: }
                    600:
1.27      pooka     601:
                    602: /*
                    603:  * Check if we have been sleeping too long.  Basically,
                    604:  * our in-sc nextpkt must by first <= nextpkt <= last"+1".
                    605:  * We use the fact that first is guaranteed to never overlap
                    606:  * with the last frame in the ring.
                    607:  */
                    608: static __inline bool
                    609: stillvalid_p(struct shmif_sc *sc)
                    610: {
                    611:        struct shmif_mem *busmem = sc->sc_busmem;
                    612:        unsigned gendiff = busmem->shm_gen - sc->sc_devgen;
                    613:        uint32_t lastoff, devoff;
                    614:
                    615:        KASSERT(busmem->shm_first != busmem->shm_last);
                    616:
                    617:        /* normalize onto a 2x busmem chunk */
                    618:        devoff = sc->sc_nextpacket;
                    619:        lastoff = shmif_nextpktoff(busmem, busmem->shm_last);
                    620:
                    621:        /* trivial case */
                    622:        if (gendiff > 1)
                    623:                return false;
                    624:        KASSERT(gendiff <= 1);
                    625:
                    626:        /* Normalize onto 2x busmem chunk */
                    627:        if (busmem->shm_first >= lastoff) {
                    628:                lastoff += BUSMEM_DATASIZE;
                    629:                if (gendiff == 0)
                    630:                        devoff += BUSMEM_DATASIZE;
                    631:        } else {
                    632:                if (gendiff)
                    633:                        return false;
                    634:        }
                    635:
                    636:        return devoff >= busmem->shm_first && devoff <= lastoff;
                    637: }
                    638:
1.1       pooka     639: static void
                    640: shmif_rcv(void *arg)
                    641: {
                    642:        struct ifnet *ifp = arg;
                    643:        struct shmif_sc *sc = ifp->if_softc;
1.32      pooka     644:        struct shmif_mem *busmem;
1.1       pooka     645:        struct mbuf *m = NULL;
                    646:        struct ether_header *eth;
1.27      pooka     647:        uint32_t nextpkt;
1.37      pooka     648:        bool wrap, passup;
1.1       pooka     649:        int error;
                    650:
1.32      pooka     651:  reup:
                    652:        mutex_enter(&sc->sc_mtx);
                    653:        while ((ifp->if_flags & IFF_RUNNING) == 0 && !sc->sc_dying)
                    654:                cv_wait(&sc->sc_cv, &sc->sc_mtx);
                    655:        mutex_exit(&sc->sc_mtx);
                    656:
                    657:        busmem = sc->sc_busmem;
                    658:
                    659:        while (ifp->if_flags & IFF_RUNNING) {
1.20      pooka     660:                struct shmif_pkthdr sp;
                    661:
1.1       pooka     662:                if (m == NULL) {
                    663:                        m = m_gethdr(M_WAIT, MT_DATA);
                    664:                        MCLGET(m, M_WAIT);
                    665:                }
                    666:
1.47      pooka     667:                DPRINTF(("waiting %d/%" PRIu64 "\n",
                    668:                    sc->sc_nextpacket, sc->sc_devgen));
1.26      pooka     669:                KASSERT(m->m_flags & M_EXT);
1.1       pooka     670:
1.26      pooka     671:                shmif_lockbus(busmem);
                    672:                KASSERT(busmem->shm_magic == SHMIF_MAGIC);
1.27      pooka     673:                KASSERT(busmem->shm_gen >= sc->sc_devgen);
1.1       pooka     674:
                    675:                /* need more data? */
1.27      pooka     676:                if (sc->sc_devgen == busmem->shm_gen &&
1.26      pooka     677:                    shmif_nextpktoff(busmem, busmem->shm_last)
                    678:                     == sc->sc_nextpacket) {
                    679:                        shmif_unlockbus(busmem);
1.1       pooka     680:                        error = 0;
1.53    ! pooka     681:                        rumpcomp_shmif_watchwait(sc->sc_kq);
1.1       pooka     682:                        if (__predict_false(error))
                    683:                                printf("shmif_rcv: wait failed %d\n", error);
1.32      pooka     684:                        membar_consumer();
1.1       pooka     685:                        continue;
                    686:                }
                    687:
1.27      pooka     688:                if (stillvalid_p(sc)) {
                    689:                        nextpkt = sc->sc_nextpacket;
                    690:                } else {
                    691:                        KASSERT(busmem->shm_gen > 0);
1.26      pooka     692:                        nextpkt = busmem->shm_first;
                    693:                        if (busmem->shm_first > busmem->shm_last)
1.27      pooka     694:                                sc->sc_devgen = busmem->shm_gen - 1;
1.26      pooka     695:                        else
1.27      pooka     696:                                sc->sc_devgen = busmem->shm_gen;
1.47      pooka     697:                        DPRINTF(("dev %p overrun, new data: %d/%" PRIu64 "\n",
1.27      pooka     698:                            sc, nextpkt, sc->sc_devgen));
1.26      pooka     699:                }
                    700:
                    701:                /*
                    702:                 * If our read pointer is ahead the bus last write, our
                    703:                 * generation must be one behind.
                    704:                 */
                    705:                KASSERT(!(nextpkt > busmem->shm_last
1.27      pooka     706:                    && sc->sc_devgen == busmem->shm_gen));
1.26      pooka     707:
1.24      pooka     708:                wrap = false;
1.26      pooka     709:                nextpkt = shmif_busread(busmem, &sp,
                    710:                    nextpkt, sizeof(sp), &wrap);
                    711:                KASSERT(sp.sp_len <= ETHERMTU + ETHER_HDR_LEN);
                    712:                nextpkt = shmif_busread(busmem, mtod(m, void *),
                    713:                    nextpkt, sp.sp_len, &wrap);
1.1       pooka     714:
                    715:                DPRINTF(("shmif_rcv: read packet of length %d at %d\n",
1.20      pooka     716:                    sp.sp_len, nextpkt));
1.1       pooka     717:
1.26      pooka     718:                sc->sc_nextpacket = nextpkt;
1.19      pooka     719:                shmif_unlockbus(sc->sc_busmem);
1.1       pooka     720:
1.27      pooka     721:                if (wrap) {
1.26      pooka     722:                        sc->sc_devgen++;
1.47      pooka     723:                        DPRINTF(("dev %p generation now %" PRIu64 "\n",
1.27      pooka     724:                            sc, sc->sc_devgen));
                    725:                }
1.26      pooka     726:
1.20      pooka     727:                m->m_len = m->m_pkthdr.len = sp.sp_len;
1.1       pooka     728:                m->m_pkthdr.rcvif = ifp;
                    729:
1.37      pooka     730:                /*
                    731:                 * Test if we want to pass the packet upwards
                    732:                 */
1.1       pooka     733:                eth = mtod(m, struct ether_header *);
1.37      pooka     734:                if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
                    735:                    ETHER_ADDR_LEN) == 0) {
                    736:                        passup = true;
1.46      pooka     737:                } else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
1.37      pooka     738:                        passup = true;
                    739:                } else if (ifp->if_flags & IFF_PROMISC) {
                    740:                        m->m_flags |= M_PROMISC;
                    741:                        passup = true;
1.38      pooka     742:                } else {
                    743:                        passup = false;
1.37      pooka     744:                }
                    745:
                    746:                if (passup) {
1.22      pooka     747:                        KERNEL_LOCK(1, NULL);
1.35      pooka     748:                        bpf_mtap(ifp, m);
1.1       pooka     749:                        ifp->if_input(ifp, m);
1.22      pooka     750:                        KERNEL_UNLOCK_ONE(NULL);
1.1       pooka     751:                        m = NULL;
                    752:                }
1.37      pooka     753:                /* else: reuse mbuf for a future packet */
1.1       pooka     754:        }
1.32      pooka     755:        m_freem(m);
                    756:        m = NULL;
                    757:
                    758:        if (!sc->sc_dying)
                    759:                goto reup;
1.1       pooka     760:
1.32      pooka     761:        kthread_exit(0);
1.1       pooka     762: }

CVSweb <webmaster@jp.NetBSD.org>