diff options
author | Hidetoshi Shimokawa <simokawa@FreeBSD.org> | 2007-06-06 14:31:36 +0000 |
---|---|---|
committer | Hidetoshi Shimokawa <simokawa@FreeBSD.org> | 2007-06-06 14:31:36 +0000 |
commit | 9950b741e91ab7a7e26badccc0d82f2e103a1f1e (patch) | |
tree | bda94d3de727b214eea64936b54deb3b46a61f52 /sys/dev/firewire/fwdev.c | |
parent | e9bf9fb67c4e86cd24d4132b20c40af5ec4a983d (diff) | |
download | src-9950b741e91ab7a7e26badccc0d82f2e103a1f1e.tar.gz src-9950b741e91ab7a7e26badccc0d82f2e103a1f1e.zip |
MFp4: MPSAFE firewire stack.
- lock its own locks and drop Giant.
- create its own taskqueue thread.
- split interrupt routine
- use interrupt filter as a fast interrupt.
- run watchdog timer in taskqueue so that it should be
serialized with the bottom half.
- add extra sanity check for transaction labels.
disable ad-hoc workaround for unknown tlabels.
- add sleep/wakeup synchronization primitives
- don't reset OHCI in fwohci_stop()
Notes
Notes:
svn path=/head/; revision=170374
Diffstat (limited to 'sys/dev/firewire/fwdev.c')
-rw-r--r-- | sys/dev/firewire/fwdev.c | 107 |
1 files changed, 67 insertions, 40 deletions
diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c index 2d91df4699b1..9e6602d068ce 100644 --- a/sys/dev/firewire/fwdev.c +++ b/sys/dev/firewire/fwdev.c @@ -98,7 +98,7 @@ struct cdevsw firewire_cdevsw = { .d_mmap = fw_mmap, .d_strategy = fw_strategy, .d_name = "fw", - .d_flags = D_MEM | D_NEEDGIANT + .d_flags = D_MEM #else #define CDEV_MAJOR 127 fw_open, fw_close, fw_read, fw_write, fw_ioctl, @@ -191,8 +191,22 @@ fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) if (DEV_FWMEM(dev)) return fwmem_open(dev, flags, fmt, td); - if (dev->si_drv1 != NULL) + sc = devclass_get_softc(firewire_devclass, unit); + if (sc == NULL) + return (ENXIO); + + FW_GLOCK(sc->fc); + if (dev->si_drv1 != NULL) { + FW_GUNLOCK(sc->fc); return (EBUSY); + } + /* set dummy value for allocation */ + dev->si_drv1 = (void *)-1; + FW_GUNLOCK(sc->fc); + + dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); + if (dev->si_drv1 == NULL) + return (ENOMEM); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 if ((dev->si_flags & SI_NAMED) == 0) { @@ -204,13 +218,7 @@ fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) "fw%d.%d", unit, sub); } #endif - - dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); - if (dev->si_drv1 == NULL) - return (ENOMEM); - d = (struct fw_drv1 *)dev->si_drv1; - sc = devclass_get_softc(firewire_devclass, unit); d->fc = sc->fc; STAILQ_INIT(&d->binds); STAILQ_INIT(&d->rq); @@ -296,14 +304,18 @@ fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) struct fw_pkt *fp; struct tcode_info *tinfo; + FW_GLOCK(d->fc); while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) - err = tsleep(&d->rq, FWPRI, "fwra", 0); + err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); - if (err != 0) + if (err != 0) { + FW_GUNLOCK(d->fc); return (err); + } s = splfw(); STAILQ_REMOVE_HEAD(&d->rq, link); + FW_GUNLOCK(xfer->fc); splx(s); fp = &xfer->recv.hdr; #if 0 /* for GASP ?? */ @@ -321,7 +333,9 @@ out: fwb = (struct fw_bind *)xfer->sc; fw_xfer_unload(xfer); xfer->recv.pay_len = PAGE_SIZE; + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); + FW_GUNLOCK(xfer->fc); return (err); } @@ -338,8 +352,7 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag) struct fw_pkt *fp; if (DEV_FWMEM(dev)) - return physio(dev, uio, ioflag); - + return (physio(dev, uio, ioflag)); d = (struct fw_drv1 *)dev->si_drv1; fc = d->fc; @@ -351,6 +364,7 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag) if (ir->buf == NULL) return (EIO); + FW_GLOCK(fc); readloop: if (ir->stproc == NULL) { /* iso bulkxfer */ @@ -367,15 +381,17 @@ readloop: if (slept == 0) { slept = 1; ir->flag |= FWXFERQ_WAKEUP; - err = tsleep(ir, FWPRI, "fw_read", hz); + err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; + FW_GUNLOCK(fc); return err; } else if(ir->stproc != NULL) { /* iso bulkxfer */ + FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, ir->stproc->poffset + ir->queued); if(fc->irx_post != NULL) @@ -396,6 +412,7 @@ readloop: } if (uio->uio_resid >= ir->psize) { slept = -1; + FW_GLOCK(fc); goto readloop; } } @@ -432,13 +449,13 @@ fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) xfer->fc = d->fc; xfer->sc = NULL; - xfer->hand = fw_asy_callback; + xfer->hand = fw_xferwake; xfer->send.spd = 2 /* XXX */; if ((err = fw_asyreq(xfer->fc, -1, xfer))) goto out; - if ((err = tsleep(xfer, FWPRI, "fwwa", 0))) + if ((err = fw_xferwait(xfer))) goto out; if (xfer->resp != 0) { @@ -446,8 +463,10 @@ fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) goto out; } - if (xfer->state == FWXF_RCVD) { + if (xfer->flag & FWXF_RCVD) { + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); + FW_GUNLOCK(xfer->fc); return (0); } @@ -467,7 +486,7 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag) struct fw_xferq *it; if (DEV_FWMEM(dev)) - return physio(dev, uio, ioflag); + return (physio(dev, uio, ioflag)); d = (struct fw_drv1 *)dev->si_drv1; fc = d->fc; @@ -478,6 +497,8 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag) if (it->buf == NULL) return (EIO); + + FW_GLOCK(fc); isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); @@ -488,18 +509,21 @@ isoloop: it->queued = 0; } else if (slept == 0) { slept = 1; +#if 0 /* XXX to avoid lock recursion */ err = fc->itx_enable(fc, it->dmach); if (err) - return err; - err = tsleep(it, FWPRI, "fw_write", hz); + goto out; +#endif + err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); if (err) - return err; + goto out; goto isoloop; } else { err = EIO; - return err; + goto out; } } + FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(it->buf, it->stproc->poffset + it->queued); err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); @@ -515,9 +539,14 @@ isoloop: } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; + FW_GLOCK(fc); goto isoloop; } return err; + +out: + FW_GUNLOCK(fc); + return err; } static void @@ -528,7 +557,9 @@ fw_hand(struct fw_xfer *xfer) fwb = (struct fw_bind *)xfer->sc; d = (struct fw_drv1 *)fwb->sc; + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); + FW_GUNLOCK(xfer->fc); wakeup(&d->rq); } @@ -570,19 +601,17 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) switch (cmd) { case FW_STSTREAM: if (it == NULL) { - for (i = 0; i < fc->nisodma; i ++) { - it = fc->it[i]; - if ((it->flag & FWXFERQ_OPEN) == 0) - break; - } - if (i >= fc->nisodma) { + i = fw_open_isodma(fc, /* tx */1); + if (i < 0) { err = EBUSY; break; } + it = fc->it[i]; err = fwdev_allocbuf(fc, it, &d->bufreq.tx); - if (err) + if (err) { + it->flag &= ~FWXFERQ_OPEN; break; - it->flag |= FWXFERQ_OPEN; + } } it->flag &= ~0xff; it->flag |= (0x3f & ichreq->ch); @@ -598,19 +627,17 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) break; case FW_SRSTREAM: if (ir == NULL) { - for (i = 0; i < fc->nisodma; i ++) { - ir = fc->ir[i]; - if ((ir->flag & FWXFERQ_OPEN) == 0) - break; - } - if (i >= fc->nisodma) { + i = fw_open_isodma(fc, /* tx */0); + if (i < 0) { err = EBUSY; break; } + ir = fc->ir[i]; err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); - if (err) + if (err) { + ir->flag &= ~FWXFERQ_OPEN; break; - ir->flag |= FWXFERQ_OPEN; + } } ir->flag &= ~0xff; ir->flag |= (0x3f & ichreq->ch); @@ -684,11 +711,11 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) bcopy((char *)fp + tinfo->hdr_len, (void *)xfer->send.payload, pay_len); xfer->send.spd = asyreq->req.sped; - xfer->hand = fw_asy_callback; + xfer->hand = fw_xferwake; if ((err = fw_asyreq(fc, -1, xfer)) != 0) goto out; - if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) + if ((err = fw_xferwait(xfer)) != 0) goto out; if (xfer->resp != 0) { err = EIO; @@ -742,7 +769,7 @@ out: err = EINVAL; break; } - fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); + fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK); if(fwb == NULL){ err = ENOMEM; break; |