summaryrefslogtreecommitdiffstats
path: root/sys/dev/firewire/fwdev.c
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2007-06-06 14:31:36 +0000
committersimokawa <simokawa@FreeBSD.org>2007-06-06 14:31:36 +0000
commit6052bc5731ca66f7ae519ab26941c42ceef6daaf (patch)
treebda94d3de727b214eea64936b54deb3b46a61f52 /sys/dev/firewire/fwdev.c
parent27c6e3f25e2c0ab488171e7704cea4e8b215f483 (diff)
downloadFreeBSD-src-6052bc5731ca66f7ae519ab26941c42ceef6daaf.zip
FreeBSD-src-6052bc5731ca66f7ae519ab26941c42ceef6daaf.tar.gz
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()
Diffstat (limited to 'sys/dev/firewire/fwdev.c')
-rw-r--r--sys/dev/firewire/fwdev.c107
1 files changed, 67 insertions, 40 deletions
diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c
index 2d91df4..9e6602d 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;
OpenPOWER on IntegriCloud