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>