summaryrefslogtreecommitdiffstats
path: root/sys/dev/firewire
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
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')
-rw-r--r--sys/dev/firewire/firewire.c283
-rw-r--r--sys/dev/firewire/firewirereg.h37
-rw-r--r--sys/dev/firewire/fwdev.c107
-rw-r--r--sys/dev/firewire/fwdma.c4
-rw-r--r--sys/dev/firewire/fwmem.c41
-rw-r--r--sys/dev/firewire/fwohci.c495
-rw-r--r--sys/dev/firewire/fwohci_pci.c13
-rw-r--r--sys/dev/firewire/fwohcivar.h18
-rw-r--r--sys/dev/firewire/if_fwe.c54
-rw-r--r--sys/dev/firewire/if_fwevar.h5
-rw-r--r--sys/dev/firewire/if_fwip.c68
-rw-r--r--sys/dev/firewire/if_fwipvar.h3
-rw-r--r--sys/dev/firewire/sbp.c77
-rw-r--r--sys/dev/firewire/sbp_targ.c141
14 files changed, 849 insertions, 497 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
index c8e8a53..e1ee133 100644
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -46,6 +46,8 @@
#include <sys/sysctl.h>
#include <sys/kthread.h>
+#include <sys/kdb.h>
+
#if defined(__DragonFly__) || __FreeBSD_version < 500000
#include <machine/clock.h> /* for DELAY() */
#endif
@@ -95,6 +97,7 @@ static int firewire_probe (device_t);
static int firewire_attach (device_t);
static int firewire_detach (device_t);
static int firewire_resume (device_t);
+static void firewire_xfer_timeout(void *, int);
#if 0
static int firewire_shutdown (device_t);
#endif
@@ -110,6 +113,7 @@ static void fw_bus_probe_thread(void *);
static void fw_vmaccess (struct fw_xfer *);
#endif
static int fw_bmr (struct firewire_comm *);
+static void fw_dump_hdr(struct fw_pkt *, char *);
static device_method_t firewire_methods[] = {
/* Device interface */
@@ -178,9 +182,11 @@ fw_noderesolve_eui64(struct firewire_comm *fc, struct fw_eui64 *eui)
int s;
s = splfw();
+ FW_GLOCK(fc);
STAILQ_FOREACH(fwdev, &fc->devices, link)
if (FW_EUI64_EQUAL(fwdev->eui, *eui))
break;
+ FW_GUNLOCK(fc);
splx(s);
if(fwdev == NULL) return NULL;
@@ -196,7 +202,7 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
{
int err = 0;
struct fw_xferq *xferq;
- int tl = -1, len;
+ int len;
struct fw_pkt *fp;
int tcode;
struct tcode_info *info;
@@ -242,16 +248,15 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
if(!(xferq->queued < xferq->maxq)){
device_printf(fc->bdev, "Discard a packet (queued=%d)\n",
xferq->queued);
- return EINVAL;
+ return EAGAIN;
}
+ xfer->tl = -1;
if (info->flag & FWTI_TLABEL) {
- if ((tl = fw_get_tlabel(fc, xfer)) == -1)
+ if (fw_get_tlabel(fc, xfer) < 0)
return EAGAIN;
- fp->mode.hdr.tlrt = tl << 2;
}
- xfer->tl = tl;
xfer->resp = 0;
xfer->fc = fc;
xfer->q = xferq;
@@ -263,11 +268,32 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
* Wakeup blocked process.
*/
void
-fw_asy_callback(struct fw_xfer *xfer){
+fw_xferwake(struct fw_xfer *xfer)
+{
+ struct mtx *lock = &xfer->fc->wait_lock;
+
+ mtx_lock(lock);
+ xfer->flag |= FWXF_WAKE;
+ mtx_unlock(lock);
+
wakeup(xfer);
return;
}
+int
+fw_xferwait(struct fw_xfer *xfer)
+{
+ struct mtx *lock = &xfer->fc->wait_lock;
+ int err = 0;
+
+ mtx_lock(lock);
+ if ((xfer->flag & FWXF_WAKE) == 0)
+ err = msleep((void *)xfer, lock, PWAIT|PCATCH, "fw_xferwait", 0);
+ mtx_unlock(lock);
+
+ return (err);
+}
+
/*
* Async. request with given xfer structure.
*/
@@ -279,17 +305,22 @@ fw_asystart(struct fw_xfer *xfer)
#if 0 /* XXX allow bus explore packets only after bus rest */
if (fc->status < FWBUSEXPLORE) {
xfer->resp = EAGAIN;
- xfer->state = FWXF_BUSY;
+ xfer->flag = FWXF_BUSY;
if (xfer->hand != NULL)
xfer->hand(xfer);
return;
}
#endif
- microtime(&xfer->tv);
s = splfw();
- xfer->state = FWXF_INQ;
+ /* Protect from interrupt/timeout */
+ FW_GLOCK(fc);
+ microtime(&xfer->tv);
+ xfer->flag = FWXF_INQ;
STAILQ_INSERT_TAIL(&xfer->q->q, xfer, link);
+#if 0
xfer->q->queued ++;
+#endif
+ FW_GUNLOCK(fc);
splx(s);
/* XXX just queue for mbuf */
if (xfer->mbuf == NULL)
@@ -311,11 +342,13 @@ firewire_probe(device_t dev)
}
static void
-firewire_xfer_timeout(struct firewire_comm *fc)
+firewire_xfer_timeout(void *arg, int pending)
{
- struct fw_xfer *xfer;
+ struct firewire_comm *fc = (struct firewire_comm *)arg;
+ struct fw_xfer *xfer, *txfer;
struct timeval tv;
struct timeval split_timeout;
+ STAILQ_HEAD(, fw_xfer) xfer_timeout;
int i, s;
split_timeout.tv_sec = 0;
@@ -323,32 +356,41 @@ firewire_xfer_timeout(struct firewire_comm *fc)
microtime(&tv);
timevalsub(&tv, &split_timeout);
+ STAILQ_INIT(&xfer_timeout);
s = splfw();
+ FW_GLOCK(fc);
for (i = 0; i < 0x40; i ++) {
while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
if (timevalcmp(&xfer->tv, &tv, >))
/* the rests are newer than this */
break;
- if (xfer->state == FWXF_START)
+ if ((xfer->flag & FWXF_SENT) == 0)
/* not sent yet */
break;
device_printf(fc->bdev,
- "split transaction timeout dst=0x%x tl=0x%x state=%d\n",
- xfer->send.hdr.mode.hdr.dst, i, xfer->state);
+ "split transaction timeout: "
+ "tl=0x%x flag=0x%02x\n", i, xfer->flag);
+ fw_dump_hdr(&xfer->send.hdr, "send");
xfer->resp = ETIMEDOUT;
- fw_xfer_done(xfer);
+ STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel);
+ STAILQ_INSERT_TAIL(&xfer_timeout, xfer, tlabel);
}
}
+ FW_GUNLOCK(fc);
splx(s);
+ fc->timeout(fc);
+
+ STAILQ_FOREACH_SAFE(xfer, &xfer_timeout, tlabel, txfer)
+ xfer->hand(xfer);
}
-#define WATCHDOC_HZ 10
+#define WATCHDOG_HZ 10
static void
firewire_watchdog(void *arg)
{
struct firewire_comm *fc;
- static int watchdoc_clock = 0;
+ static int watchdog_clock = 0;
fc = (struct firewire_comm *)arg;
@@ -357,13 +399,12 @@ firewire_watchdog(void *arg)
* We encounter a timeout easily. To avoid this,
* ignore clock interrupt for a while.
*/
- if (watchdoc_clock > WATCHDOC_HZ * 15) {
- firewire_xfer_timeout(fc);
- fc->timeout(fc);
- } else
- watchdoc_clock ++;
+ if (watchdog_clock > WATCHDOG_HZ * 15)
+ taskqueue_enqueue(fc->taskqueue, &fc->task_timeout);
+ else
+ watchdog_clock ++;
- callout_reset(&fc->timeout_callout, hz / WATCHDOC_HZ,
+ callout_reset(&fc->timeout_callout, hz / WATCHDOG_HZ,
(void *)firewire_watchdog, (void *)fc);
}
@@ -377,7 +418,6 @@ firewire_attach(device_t dev)
struct firewire_softc *sc = device_get_softc(dev);
device_t pa = device_get_parent(dev);
struct firewire_comm *fc;
- struct proc *p;
fc = (struct firewire_comm *)device_get_softc(pa);
sc->fc = fc;
@@ -388,15 +428,17 @@ firewire_attach(device_t dev)
fwdev_makedev(sc);
- CALLOUT_INIT(&sc->fc->timeout_callout);
- CALLOUT_INIT(&sc->fc->bmr_callout);
- CALLOUT_INIT(&sc->fc->busprobe_callout);
+ mtx_init(&fc->wait_lock, "fwwait", NULL, MTX_DEF);
+ CALLOUT_INIT(&fc->timeout_callout);
+ CALLOUT_INIT(&fc->bmr_callout);
+ CALLOUT_INIT(&fc->busprobe_callout);
+ TASK_INIT(&fc->task_timeout, 0, firewire_xfer_timeout, (void *)fc);
callout_reset(&sc->fc->timeout_callout, hz,
(void *)firewire_watchdog, (void *)sc->fc);
/* create thread */
- kthread_create(fw_bus_probe_thread, (void *)fc, &p,
+ kthread_create(fw_bus_probe_thread, (void *)fc, &fc->probe_thread,
0, 0, "fw%d_probe", unit);
/* Locate our children */
@@ -457,7 +499,12 @@ firewire_detach(device_t dev)
sc = (struct firewire_softc *)device_get_softc(dev);
fc = sc->fc;
+ mtx_lock(&fc->wait_lock);
fc->status = FWBUSDETACH;
+ wakeup(fc);
+ if (msleep(fc->probe_thread, &fc->wait_lock, PWAIT, "fwthr", hz * 60))
+ printf("firewire probe thread didn't die\n");
+ mtx_unlock(&fc->wait_lock);
if ((err = fwdev_destroydev(sc)) != 0)
return err;
@@ -479,10 +526,7 @@ firewire_detach(device_t dev)
free(fc->speed_map, M_FW);
free(fc->crom_src_buf, M_FW);
- wakeup(fc);
- if (tsleep(fc, PWAIT, "fwthr", hz * 60))
- printf("firewire task thread didn't die\n");
-
+ mtx_destroy(&fc->wait_lock);
return(0);
}
#if 0
@@ -501,9 +545,11 @@ fw_xferq_drain(struct fw_xferq *xferq)
while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) {
STAILQ_REMOVE_HEAD(&xferq->q, link);
+#if 0
xferq->queued --;
+#endif
xfer->resp = EAGAIN;
- xfer->state = FWXF_SENTERR;
+ xfer->flag = FWXF_SENTERR;
fw_xfer_done(xfer);
}
}
@@ -511,12 +557,30 @@ fw_xferq_drain(struct fw_xferq *xferq)
void
fw_drain_txq(struct firewire_comm *fc)
{
+ struct fw_xfer *xfer, *txfer;
+ STAILQ_HEAD(, fw_xfer) xfer_drain;
int i;
+ STAILQ_INIT(&xfer_drain);
+
+ FW_GLOCK(fc);
fw_xferq_drain(fc->atq);
fw_xferq_drain(fc->ats);
for(i = 0; i < fc->nisodma; i++)
fw_xferq_drain(fc->it[i]);
+
+ for (i = 0; i < 0x40; i ++)
+ while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
+ if (firewire_debug)
+ printf("tl=%d flag=%d\n", i, xfer->flag);
+ xfer->resp = EAGAIN;
+ STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel);
+ STAILQ_INSERT_TAIL(&xfer_drain, xfer, tlabel);
+ }
+ FW_GUNLOCK(fc);
+
+ STAILQ_FOREACH_SAFE(xfer, &xfer_drain, tlabel, txfer)
+ xfer->hand(xfer);
}
static void
@@ -802,13 +866,17 @@ struct fw_bind *
fw_bindlookup(struct firewire_comm *fc, uint16_t dest_hi, uint32_t dest_lo)
{
u_int64_t addr;
- struct fw_bind *tfw;
+ struct fw_bind *tfw, *r = NULL;
addr = ((u_int64_t)dest_hi << 32) | dest_lo;
+ FW_GLOCK(fc);
STAILQ_FOREACH(tfw, &fc->binds, fclist)
- if (BIND_CMP(addr, tfw) == 0)
- return(tfw);
- return(NULL);
+ if (BIND_CMP(addr, tfw) == 0) {
+ r = tfw;
+ break;
+ }
+ FW_GUNLOCK(fc);
+ return(r);
}
/*
@@ -818,28 +886,29 @@ int
fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
{
struct fw_bind *tfw, *prev = NULL;
+ int r = 0;
if (fwb->start > fwb->end) {
printf("%s: invalid range\n", __func__);
return EINVAL;
}
+ FW_GLOCK(fc);
STAILQ_FOREACH(tfw, &fc->binds, fclist) {
if (fwb->end < tfw->start)
break;
prev = tfw;
}
- if (prev == NULL) {
+ if (prev == NULL)
STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
- return (0);
- }
- if (prev->end < fwb->start) {
+ else if (prev->end < fwb->start)
STAILQ_INSERT_AFTER(&fc->binds, prev, fwb, fclist);
- return (0);
+ else {
+ printf("%s: bind failed\n", __func__);
+ r = EBUSY;
}
-
- printf("%s: bind failed\n", __func__);
- return (EBUSY);
+ FW_GUNLOCK(fc);
+ return (r);
}
/*
@@ -855,6 +924,7 @@ fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
int s;
s = splfw();
+ FW_GLOCK(fc);
STAILQ_FOREACH(tfw, &fc->binds, fclist)
if (tfw == fwb) {
STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
@@ -862,6 +932,7 @@ fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
}
printf("%s: no such binding\n", __func__);
+ FW_GUNLOCK(fc);
splx(s);
return (1);
found:
@@ -873,6 +944,7 @@ found:
}
STAILQ_INIT(&fwb->xferlist);
#endif
+ FW_GUNLOCK(fc);
splx(s);
return 0;
@@ -911,6 +983,19 @@ fw_xferlist_remove(struct fw_xferlist *q)
}
STAILQ_INIT(q);
}
+/*
+ * dump packet header
+ */
+static void
+fw_dump_hdr(struct fw_pkt *fp, char *prefix)
+{
+ printf("%s: dst=0x%02x tl=0x%02x rt=%d tcode=0x%x pri=0x%x "
+ "src=0x%03x\n", prefix,
+ fp->mode.hdr.dst & 0x3f,
+ fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tlrt & 3,
+ fp->mode.hdr.tcode, fp->mode.hdr.pri,
+ fp->mode.hdr.src);
+}
/*
* To free transaction label.
@@ -925,19 +1010,26 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
return;
s = splfw();
+ FW_GLOCK(fc);
#if 1 /* make sure the label is allocated */
STAILQ_FOREACH(txfer, &fc->tlabels[xfer->tl], tlabel)
if(txfer == xfer)
break;
if (txfer == NULL) {
- printf("%s: the xfer is not in the tlabel(%d)\n",
- __FUNCTION__, xfer->tl);
+ printf("%s: the xfer is not in the queue "
+ "(tlabel=%d, flag=0x%x)\n",
+ __FUNCTION__, xfer->tl, xfer->flag);
+ fw_dump_hdr(&xfer->send.hdr, "send");
+ fw_dump_hdr(&xfer->recv.hdr, "recv");
+ kdb_backtrace();
+ FW_GUNLOCK(fc);
splx(s);
return;
}
#endif
STAILQ_REMOVE(&fc->tlabels[xfer->tl], xfer, fw_xfer, tlabel);
+ FW_GUNLOCK(fc);
splx(s);
return;
}
@@ -946,18 +1038,33 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
* To obtain XFER structure by transaction label.
*/
static struct fw_xfer *
-fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel)
+fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel, int tcode)
{
struct fw_xfer *xfer;
int s = splfw();
+ int req;
+ FW_GLOCK(fc);
STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel)
if(xfer->send.hdr.mode.hdr.dst == node) {
+ FW_GUNLOCK(fc);
splx(s);
+ KASSERT(xfer->tl == tlabel,
+ ("xfer->tl 0x%x != 0x%x", xfer->tl, tlabel));
+ /* extra sanity check */
+ req = xfer->send.hdr.mode.hdr.tcode;
+ if (xfer->fc->tcode[req].valid_res != tcode) {
+ printf("%s: invalid response tcode "
+ "(0x%x for 0x%x)\n", __FUNCTION__,
+ tcode, req);
+ return(NULL);
+ }
+
if (firewire_debug > 2)
printf("fw_tl2xfer: found tl=%d\n", tlabel);
return(xfer);
}
+ FW_GUNLOCK(fc);
if (firewire_debug > 1)
printf("fw_tl2xfer: not found tl=%d\n", tlabel);
splx(s);
@@ -1034,16 +1141,20 @@ fw_xfer_unload(struct fw_xfer* xfer)
int s;
if(xfer == NULL ) return;
- if(xfer->state == FWXF_INQ){
+ if(xfer->flag & FWXF_INQ){
printf("fw_xfer_free FWXF_INQ\n");
s = splfw();
+ FW_GLOCK(xfer->fc);
STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link);
+#if 0
xfer->q->queued --;
+#endif
+ FW_GUNLOCK(xfer->fc);
splx(s);
}
if (xfer->fc != NULL) {
#if 1
- if(xfer->state == FWXF_START)
+ if(xfer->flag & FWXF_START)
/*
* This could happen if:
* 1. We call fwohci_arcv() before fwohci_txd().
@@ -1052,7 +1163,7 @@ fw_xfer_unload(struct fw_xfer* xfer)
printf("fw_xfer_free FWXF_START\n");
#endif
}
- xfer->state = FWXF_INIT;
+ xfer->flag = FWXF_INIT;
xfer->resp = 0;
}
/*
@@ -1090,8 +1201,8 @@ void
fw_asy_callback_free(struct fw_xfer *xfer)
{
#if 0
- printf("asyreq done state=%d resp=%d\n",
- xfer->state, xfer->resp);
+ printf("asyreq done flag=0x%02x resp=%d\n",
+ xfer->flag, xfer->resp);
#endif
fw_xfer_free(xfer);
}
@@ -1297,10 +1408,10 @@ fw_explore_read_quads(struct fw_device *fwdev, int offset,
for (i = 0; i < n; i ++, offset += sizeof(uint32_t)) {
xfer = fwmem_read_quad(fwdev, NULL, -1,
0xffff, 0xf0000000 | offset, (void *)&tmp,
- fw_asy_callback);
+ fw_xferwake);
if (xfer == NULL)
return (-1);
- tsleep((void *)xfer, PWAIT|PCATCH, "rquad", 0);
+ fw_xferwait(xfer);
if (xfer->resp == 0)
quad[i] = ntohl(tmp);
@@ -1532,20 +1643,20 @@ fw_bus_probe_thread(void *arg)
fc = (struct firewire_comm *)arg;
- mtx_lock(&Giant);
- while (1) {
+ mtx_lock(&fc->wait_lock);
+ while (fc->status != FWBUSDETACH) {
if (fc->status == FWBUSEXPLORE) {
+ mtx_unlock(&fc->wait_lock);
fw_explore(fc);
fc->status = FWBUSEXPDONE;
if (firewire_debug)
printf("bus_explore done\n");
fw_attach_dev(fc);
- } else if (fc->status == FWBUSDETACH)
- break;
- tsleep((void *)fc, PWAIT|PCATCH, "-", 0);
+ mtx_lock(&fc->wait_lock);
+ }
+ msleep((void *)fc, &fc->wait_lock, PWAIT|PCATCH, "-", 0);
}
- mtx_unlock(&Giant);
- wakeup(fc);
+ mtx_unlock(&fc->wait_lock);
kthread_exit(0);
}
@@ -1606,6 +1717,7 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
static uint32_t label = 0;
s = splfw();
+ FW_GLOCK(fc);
for( i = 0 ; i < 0x40 ; i ++){
label = (label + 1) & 0x3f;
STAILQ_FOREACH(txfer, &fc->tlabels[label], tlabel)
@@ -1613,14 +1725,19 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
xfer->send.hdr.mode.hdr.dst)
break;
if(txfer == NULL) {
+ xfer->tl = label;
+ xfer->send.hdr.mode.hdr.tlrt = label << 2;
STAILQ_INSERT_TAIL(&fc->tlabels[label], xfer, tlabel);
+ FW_GUNLOCK(fc);
splx(s);
if (firewire_debug > 1)
printf("fw_get_tlabel: dst=%d tl=%d\n",
xfer->send.hdr.mode.hdr.dst, label);
- return(label);
+ /* note: label may be incremanted after unlock */
+ return(xfer->tl);
}
}
+ FW_GUNLOCK(fc);
splx(s);
if (firewire_debug > 1)
@@ -1713,7 +1830,7 @@ fw_rcv(struct fw_rcv_buf *rb)
case FWTCODE_RRESB:
case FWTCODE_LRES:
rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
- fp->mode.hdr.tlrt >> 2);
+ fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tcode);
if(rb->xfer == NULL) {
printf("fw_rcv: unknown response "
"%s(%x) src=0x%x tl=0x%x rt=%d data=0x%x\n",
@@ -1722,7 +1839,7 @@ fw_rcv(struct fw_rcv_buf *rb)
fp->mode.hdr.tlrt >> 2,
fp->mode.hdr.tlrt & 3,
fp->mode.rresq.data);
-#if 1
+#if 0
printf("try ad-hoc work around!!\n");
rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
(fp->mode.hdr.tlrt >> 2)^3);
@@ -1740,8 +1857,8 @@ fw_rcv(struct fw_rcv_buf *rb)
else
rb->xfer->resp = 0;
/* make sure the packet is drained in AT queue */
- oldstate = rb->xfer->state;
- rb->xfer->state = FWXF_RCVD;
+ oldstate = rb->xfer->flag;
+ rb->xfer->flag = FWXF_RCVD;
switch (oldstate) {
case FWXF_SENT:
fw_xfer_done(rb->xfer);
@@ -1753,7 +1870,7 @@ fw_rcv(struct fw_rcv_buf *rb)
#endif
break;
default:
- printf("unexpected state %d\n", rb->xfer->state);
+ printf("unexpected flag 0x%02x\n", rb->xfer->flag);
}
return;
case FWTCODE_WREQQ:
@@ -1806,7 +1923,7 @@ fw_rcv(struct fw_rcv_buf *rb)
resfp->mode.rresb.extcode = 0;
resfp->mode.rresb.len = 0;
/*
- rb->xfer->hand = fw_asy_callback;
+ rb->xfer->hand = fw_xferwake;
*/
rb->xfer->hand = fw_xfer_free;
if(fw_asyreq(rb->fc, -1, rb->xfer)){
@@ -2099,6 +2216,34 @@ fw_bmr(struct firewire_comm *fc)
return 0;
}
+int
+fw_open_isodma(struct firewire_comm *fc, int tx)
+{
+ struct fw_xferq **xferqa;
+ struct fw_xferq *xferq;
+ int i;
+
+ if (tx)
+ xferqa = &fc->it[0];
+ else
+ xferqa = &fc->ir[0];
+
+ FW_GLOCK(fc);
+ for (i = 0; i < fc->nisodma; i ++) {
+ xferq = xferqa[i];
+ if ((xferq->flag & FWXFERQ_OPEN) == 0) {
+ xferq->flag |= FWXFERQ_OPEN;
+ break;
+ }
+ }
+ if (i == fc->nisodma) {
+ printf("no free dma channel (tx=%d)\n", tx);
+ i = -1;
+ }
+ FW_GUNLOCK(fc);
+ return (i);
+}
+
static int
fw_modevent(module_t mode, int type, void *data)
{
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
index 05280f1..5038868 100644
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -47,6 +47,8 @@ typedef struct proc fw_proc;
#endif
#include <sys/uio.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
#define splfw splimp
@@ -98,6 +100,7 @@ struct tcode_info {
#define FWTI_TLABEL (1 << 2)
#define FWTI_BLOCK_STR (1 << 3)
#define FWTI_BLOCK_ASY (1 << 4)
+ u_char valid_res;
};
struct firewire_comm{
@@ -145,6 +148,7 @@ struct firewire_comm{
struct callout busprobe_callout;
struct callout bmr_callout;
struct callout timeout_callout;
+ struct task task_timeout;
uint32_t (*cyctimer) (struct firewire_comm *);
void (*ibr) (struct firewire_comm *);
uint32_t (*set_bmr) (struct firewire_comm *, uint32_t);
@@ -160,9 +164,18 @@ struct firewire_comm{
void (*itx_post) (struct firewire_comm *, uint32_t *);
struct tcode_info *tcode;
bus_dma_tag_t dmat;
+ struct mtx mtx;
+ struct mtx wait_lock;
+ struct taskqueue *taskqueue;
+ struct proc *probe_thread;
};
#define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4])
+#define FW_GMTX(fc) (&(fc)->mtx)
+#define FW_GLOCK(fc) mtx_lock(FW_GMTX(fc))
+#define FW_GUNLOCK(fc) mtx_unlock(FW_GMTX(fc))
+#define FW_GLOCK_ASSERT(fc) mtx_assert(FW_GMTX(fc), MA_OWNED)
+
struct fw_xferq {
int flag;
#define FWXFERQ_CHTAGMASK 0xff
@@ -220,14 +233,16 @@ struct fw_xfer{
struct fw_xferq *q;
struct timeval tv;
int8_t resp;
-#define FWXF_INIT 0
-#define FWXF_INQ 1
-#define FWXF_START 2
-#define FWXF_SENT 3
-#define FWXF_SENTERR 4
-#define FWXF_BUSY 8
-#define FWXF_RCVD 10
- uint8_t state;
+#define FWXF_INIT 0x00
+#define FWXF_INQ 0x01
+#define FWXF_START 0x02
+#define FWXF_SENT 0x04
+#define FWXF_SENTERR 0x08
+#define FWXF_BUSY 0x10
+#define FWXF_RCVD 0x20
+
+#define FWXF_WAKE 0x80
+ uint8_t flag;
int8_t tl;
void (*hand) (struct fw_xfer *);
struct {
@@ -270,7 +285,8 @@ void fw_busreset (struct firewire_comm *, uint32_t);
uint16_t fw_crc16 (uint32_t *, uint32_t);
void fw_xfer_timeout (void *);
void fw_xfer_done (struct fw_xfer *);
-void fw_asy_callback (struct fw_xfer *);
+void fw_xferwake (struct fw_xfer *);
+int fw_xferwait (struct fw_xfer *);
void fw_asy_callback_free (struct fw_xfer *);
struct fw_device *fw_noderesolve_nodeid (struct firewire_comm *, int);
struct fw_device *fw_noderesolve_eui64 (struct firewire_comm *, struct fw_eui64 *);
@@ -279,6 +295,7 @@ void fw_drain_txq (struct firewire_comm *);
int fwdev_makedev (struct firewire_softc *);
int fwdev_destroydev (struct firewire_softc *);
void fwdev_clone (void *, struct ucred *, char *, int, struct cdev **);
+int fw_open_isodma(struct firewire_comm *, int);
extern int firewire_debug;
extern devclass_t firewire_devclass;
@@ -292,7 +309,7 @@ extern devclass_t firewire_devclass;
#if defined(__DragonFly__) || __FreeBSD_version < 500000
#define CALLOUT_INIT(x) callout_init(x)
#else
-#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
+#define CALLOUT_INIT(x) callout_init(x, 1 /* mpsafe */)
#endif
#if defined(__DragonFly__) || __FreeBSD_version < 500000
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;
diff --git a/sys/dev/firewire/fwdma.c b/sys/dev/firewire/fwdma.c
index 2c84ebc..bf3bb6f 100644
--- a/sys/dev/firewire/fwdma.c
+++ b/sys/dev/firewire/fwdma.c
@@ -92,7 +92,7 @@ fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
/*flags*/ BUS_DMA_ALLOCNOW,
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
/*lockfunc*/busdma_lock_mutex,
- /*lockarg*/&Giant,
+ /*lockarg*/FW_GMTX(fc),
#endif
&dma->dma_tag);
if (err) {
@@ -190,7 +190,7 @@ fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
/*flags*/ BUS_DMA_ALLOCNOW,
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
/*lockfunc*/busdma_lock_mutex,
- /*lockarg*/&Giant,
+ /*lockarg*/FW_GMTX(fc),
#endif
&am->dma_tag)) {
printf("fwdma_malloc_multiseg: tag_create failed\n");
diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c
index b6e7f70..f0aa7ae 100644
--- a/sys/dev/firewire/fwmem.c
+++ b/sys/dev/firewire/fwmem.c
@@ -90,6 +90,7 @@ MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
struct fwmem_softc {
struct fw_eui64 eui;
+ struct firewire_softc *sc;
int refcount;
};
@@ -276,20 +277,33 @@ int
fwmem_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
{
struct fwmem_softc *fms;
+ struct firewire_softc *sc;
+ int unit = DEV2UNIT(dev);
+
+ sc = devclass_get_softc(firewire_devclass, unit);
+ if (sc == NULL)
+ return (ENXIO);
+ FW_GLOCK(sc->fc);
if (dev->si_drv1 != NULL) {
- if ((flags & FWRITE) != 0)
- return (EBUSY);
+ if ((flags & FWRITE) != 0) {
+ FW_GUNLOCK(sc->fc);
+ return(EBUSY);
+ }
+ FW_GUNLOCK(sc->fc);
fms = (struct fwmem_softc *)dev->si_drv1;
fms->refcount ++;
} else {
- fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc),
- M_FWMEM, M_WAITOK);
- if (fms == NULL)
- return ENOMEM;
- bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
- dev->si_drv1 = (void *)fms;
+ dev->si_drv1 = (void *)-1;
+ FW_GUNLOCK(sc->fc);
+ dev->si_drv1 = malloc(sizeof(struct fwmem_softc),
+ M_FWMEM, M_WAITOK);
+ if (dev->si_drv1 == NULL)
+ return(ENOMEM);
dev->si_iosize_max = DFLTPHYS;
+ fms = (struct fwmem_softc *)dev->si_drv1;
+ bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
+ fms->sc = sc;
fms->refcount = 1;
}
if (fwmem_debug)
@@ -304,7 +318,10 @@ fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
struct fwmem_softc *fms;
fms = (struct fwmem_softc *)dev->si_drv1;
+
+ FW_GLOCK(fms->sc->fc);
fms->refcount --;
+ FW_GUNLOCK(fms->sc->fc);
if (fwmem_debug)
printf("%s: refcount=%d\n", __func__, fms->refcount);
if (fms->refcount < 1) {
@@ -338,22 +355,18 @@ fwmem_biodone(struct fw_xfer *xfer)
void
fwmem_strategy(struct bio *bp)
{
- struct firewire_softc *sc;
struct fwmem_softc *fms;
struct fw_device *fwdev;
struct fw_xfer *xfer;
struct cdev *dev;
- int unit, err=0, s, iolen;
+ int err=0, s, iolen;
dev = bp->bio_dev;
/* XXX check request length */
- unit = DEV2UNIT(dev);
- sc = devclass_get_softc(firewire_devclass, unit);
-
s = splfw();
fms = (struct fwmem_softc *)dev->si_drv1;
- fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui);
+ fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
if (fwdev == NULL) {
if (fwmem_debug)
printf("fwmem: no such device ID:%08x%08x\n",
diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c
index 4e7c366..06bdc01 100644
--- a/sys/dev/firewire/fwohci.c
+++ b/sys/dev/firewire/fwohci.c
@@ -52,6 +52,7 @@
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/endian.h>
+#include <sys/kdb.h>
#include <machine/bus.h>
@@ -90,7 +91,7 @@ static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3",
static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"};
char fwohcicode[32][0x20]={
"No stat","Undef","long","miss Ack err",
- "underrun","overrun","desc err", "data read err",
+ "FIFO underrun","FIFO overrun","desc err", "data read err",
"data write err","bus reset","timeout","tcode err",
"Undef","Undef","unknown event","flushed",
"Undef","ack complete","ack pend","Undef",
@@ -103,23 +104,23 @@ extern char *linkspeed[];
uint32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
static struct tcode_info tinfo[] = {
-/* hdr_len block flag*/
-/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL},
-/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
-/* 2 WRES */ {12, FWTI_RES},
-/* 3 XXX */ { 0, 0},
-/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL},
-/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL},
-/* 6 RRESQ */ {16, FWTI_RES},
-/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY},
-/* 8 CYCS */ { 0, 0},
-/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
-/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR},
-/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY},
-/* c XXX */ { 0, 0},
-/* d XXX */ { 0, 0},
-/* e PHY */ {12, FWTI_REQ},
-/* f XXX */ { 0, 0}
+/* hdr_len block flag valid_response */
+/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_WRES},
+/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES},
+/* 2 WRES */ {12, FWTI_RES, 0xff},
+/* 3 XXX */ { 0, 0, 0xff},
+/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ},
+/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB},
+/* 6 RRESQ */ {16, FWTI_RES, 0xff},
+/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff},
+/* 8 CYCS */ { 0, 0, 0xff},
+/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES},
+/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR, 0xff},
+/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff},
+/* c XXX */ { 0, 0, 0xff},
+/* d XXX */ { 0, 0, 0xff},
+/* e PHY */ {12, FWTI_REQ, 0xff},
+/* f XXX */ { 0, 0, 0xff}
};
#define OHCI_WRITE_SIGMASK 0xffff0000
@@ -159,9 +160,9 @@ static uint32_t fwohci_cyctimer (struct firewire_comm *);
static void fwohci_rbuf_update (struct fwohci_softc *, int);
static void fwohci_tbuf_update (struct fwohci_softc *, int);
void fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *);
-#if FWOHCI_TASKQUEUE
-static void fwohci_complete(void *, int);
-#endif
+static void fwohci_task_busreset(void *, int);
+static void fwohci_task_sid(void *, int);
+static void fwohci_task_dma(void *, int);
/*
* memory allocated for DMA programs
@@ -264,6 +265,7 @@ d_ioctl_t fwohci_ioctl;
/*
* Communication with PHY device
*/
+/* XXX need lock for phy access */
static uint32_t
fwphy_wrdata( struct fwohci_softc *sc, uint32_t addr, uint32_t data)
{
@@ -589,11 +591,13 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev)
/* Enable interrupts */
- OWRITE(sc, FWOHCI_INTMASK,
- OHCI_INT_ERR | OHCI_INT_PHY_SID
+ sc->intmask = (OHCI_INT_ERR | OHCI_INT_PHY_SID
| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
+ sc->intmask |= OHCI_INT_DMA_IR | OHCI_INT_DMA_IT;
+ sc->intmask |= OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT;
+ OWRITE(sc, FWOHCI_INTMASK, sc->intmask);
fwohci_set_intr(&sc->fc, 1);
}
@@ -605,10 +609,6 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
uint32_t reg;
uint8_t ui[8];
-#if FWOHCI_TASKQUEUE
- TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
-#endif
-
/* OHCI version */
reg = OREAD(sc, OHCI_VERSION);
mver = (reg >> 16) & 0xff;
@@ -761,6 +761,15 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
sc->intmask = sc->irstat = sc->itstat = 0;
+ /* Init task queue */
+ sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK,
+ taskqueue_thread_enqueue, &sc->fc.taskqueue);
+ taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq",
+ device_get_unit(dev));
+ TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc);
+ TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc);
+ TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc);
+
fw_init(&sc->fc);
fwohci_reset(sc, dev);
@@ -802,6 +811,14 @@ fwohci_detach(struct fwohci_softc *sc, device_t dev)
fwohci_db_free(&sc->it[i]);
fwohci_db_free(&sc->ir[i]);
}
+ if (sc->fc.taskqueue != NULL) {
+ taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset);
+ taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid);
+ taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma);
+ taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout);
+ taskqueue_free(sc->fc.taskqueue);
+ sc->fc.taskqueue = NULL;
+ }
return 0;
}
@@ -860,6 +877,8 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
struct tcode_info *info;
static int maxdesc=0;
+ FW_GLOCK_ASSERT(&sc->fc);
+
if(&sc->atrq == dbch){
off = OHCI_ATQOFF;
}else if(&sc->atrs == dbch){
@@ -878,12 +897,14 @@ txloop:
if(xfer == NULL){
goto kick;
}
+#if 0
if(dbch->xferq.queued == 0 ){
device_printf(sc->fc.dev, "TX queue empty\n");
}
+#endif
STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
db_tr->xfer = xfer;
- xfer->state = FWXF_START;
+ xfer->flag = FWXF_START;
fp = &xfer->send.hdr;
tcode = fp->mode.common.tcode;
@@ -993,6 +1014,7 @@ again:
LAST_DB(dbch->pdb_tr, db);
FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
}
+ dbch->xferq.queued ++;
dbch->pdb_tr = db_tr;
db_tr = STAILQ_NEXT(db_tr, link);
if(db_tr != dbch->bottom){
@@ -1026,7 +1048,9 @@ static void
fwohci_start_atq(struct firewire_comm *fc)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+ FW_GLOCK(&sc->fc);
fwohci_start( sc, &(sc->atrq));
+ FW_GUNLOCK(&sc->fc);
return;
}
@@ -1034,7 +1058,9 @@ static void
fwohci_start_ats(struct firewire_comm *fc)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+ FW_GLOCK(&sc->fc);
fwohci_start( sc, &(sc->atrs));
+ FW_GUNLOCK(&sc->fc);
return;
}
@@ -1122,22 +1148,22 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
}
if (tr->xfer != NULL) {
xfer = tr->xfer;
- if (xfer->state == FWXF_RCVD) {
+ if (xfer->flag & FWXF_RCVD) {
#if 0
if (firewire_debug)
printf("already rcvd\n");
#endif
fw_xfer_done(xfer);
} else {
- xfer->state = FWXF_SENT;
+ xfer->flag = FWXF_SENT;
if (err == EBUSY && fc->status != FWBUSRESET) {
- xfer->state = FWXF_BUSY;
+ xfer->flag = FWXF_BUSY;
xfer->resp = err;
xfer->recv.pay_len = 0;
fw_xfer_done(xfer);
} else if (stat != FWOHCIEV_ACKPEND) {
if (stat != FWOHCIEV_ACKCOMPL)
- xfer->state = FWXF_SENTERR;
+ xfer->flag = FWXF_SENTERR;
xfer->resp = err;
xfer->recv.pay_len = 0;
fw_xfer_done(xfer);
@@ -1150,7 +1176,9 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
} else {
printf("this shouldn't happen\n");
}
+ FW_GLOCK(fc);
dbch->xferq.queued --;
+ FW_GUNLOCK(fc);
tr->xfer = NULL;
packets ++;
@@ -1167,7 +1195,9 @@ out:
if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
printf("make free slot\n");
dbch->flags &= ~FWOHCI_DBCH_FULL;
+ FW_GLOCK(fc);
fwohci_start(sc, dbch);
+ FW_GUNLOCK(fc);
}
splx(s);
}
@@ -1221,7 +1251,7 @@ fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
/*flags*/ 0,
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
/*lockfunc*/busdma_lock_mutex,
- /*lockarg*/&Giant,
+ /*lockarg*/FW_GMTX(&sc->fc),
#endif
&dbch->dmat))
return;
@@ -1508,6 +1538,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
fwohci_db_init(sc, dbch);
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
+
err = fwohci_tx_enable(sc, dbch);
}
if(err)
@@ -1515,6 +1546,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
ldesc = dbch->ndesc - 1;
s = splfw();
+ FW_GLOCK(fc);
prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
struct fwohcidb *db;
@@ -1541,6 +1573,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
prev = chunk;
}
+ FW_GUNLOCK(fc);
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
splx(s);
@@ -1642,6 +1675,8 @@ fwohci_irx_enable(struct firewire_comm *fc, int dmach)
ldesc = dbch->ndesc - 1;
s = splfw();
+ if ((ir->flag & FWXFERQ_HANDLER) == 0)
+ FW_GLOCK(fc);
prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
struct fwohcidb *db;
@@ -1669,6 +1704,8 @@ fwohci_irx_enable(struct firewire_comm *fc, int dmach)
STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
prev = chunk;
}
+ if ((ir->flag & FWXFERQ_HANDLER) == 0)
+ FW_GUNLOCK(fc);
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
splx(s);
@@ -1714,9 +1751,10 @@ fwohci_stop(struct fwohci_softc *sc, device_t dev)
OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
}
-/* FLUSH FIFO and reset Transmitter/Reciever */
- OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
+ if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0)
+ fw_drain_txq(&sc->fc);
+#if 0 /* Let dcons(4) be accessed */
/* Stop interrupt */
OWRITE(sc, FWOHCI_INTMASKCLR,
OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID
@@ -1726,8 +1764,9 @@ fwohci_stop(struct fwohci_softc *sc, device_t dev)
| OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS
| OHCI_INT_PHY_BUS_R);
- if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0)
- fw_drain_txq(&sc->fc);
+/* FLUSH FIFO and reset Transmitter/Reciever */
+ OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
+#endif
/* XXX Link down? Bus reset? */
return 0;
@@ -1762,15 +1801,10 @@ fwohci_resume(struct fwohci_softc *sc, device_t dev)
return 0;
}
-#define ACK_ALL
+#ifdef OHCI_DEBUG
static void
-fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
+fwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat)
{
- uint32_t irstat, itstat;
- u_int i;
- struct firewire_comm *fc = (struct firewire_comm *)sc;
-
-#ifdef OHCI_DEBUG
if(stat & OREAD(sc, FWOHCI_INTMASK))
device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n",
stat & OHCI_INT_EN ? "DMA_EN ":"",
@@ -1796,11 +1830,16 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"",
stat, OREAD(sc, FWOHCI_INTMASK)
);
+}
#endif
-/* Bus reset */
- if(stat & OHCI_INT_PHY_BUS_R ){
- if (fc->status == FWBUSRESET)
- goto busresetout;
+static void
+fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count)
+{
+ struct firewire_comm *fc = (struct firewire_comm *)sc;
+ uint32_t node_id, plen;
+
+ if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) {
+ fc->status = FWBUSRESET;
/* Disable bus reset interrupt until sid recv. */
OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R);
@@ -1813,24 +1852,72 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
-#ifndef ACK_ALL
+ if (!kdb_active)
+ taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset);
+ }
+ if (stat & OHCI_INT_PHY_SID) {
+ /* Enable bus reset interrupt */
OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
-#endif
- fw_busreset(fc, FWBUSRESET);
- OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
- OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
- }
-busresetout:
- if((stat & OHCI_INT_DMA_IR )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR);
-#endif
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
- irstat = sc->irstat;
- sc->irstat = 0;
-#else
+ OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R);
+
+ /* Allow async. request to us */
+ OWRITE(sc, OHCI_AREQHI, 1 << 31);
+ /* XXX insecure ?? */
+ /* allow from all nodes */
+ OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
+ OWRITE(sc, OHCI_PREQLO, 0xffffffff);
+ /* 0 to 4GB regison */
+ OWRITE(sc, OHCI_PREQUPPER, 0x10000);
+ /* Set ATRetries register */
+ OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
+
+ /*
+ * Checking whether the node is root or not. If root, turn on
+ * cycle master.
+ */
+ node_id = OREAD(sc, FWOHCI_NODEID);
+ plen = OREAD(sc, OHCI_SID_CNT);
+
+ fc->nodeid = node_id & 0x3f;
+ device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
+ node_id, (plen >> 16) & 0xff);
+ if (!(node_id & OHCI_NODE_VALID)) {
+ printf("Bus reset failure\n");
+ goto sidout;
+ }
+
+ /* cycle timer */
+ sc->cycle_lost = 0;
+ OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST);
+ if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) {
+ printf("CYCLEMASTER mode\n");
+ OWRITE(sc, OHCI_LNKCTL,
+ OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
+ } else {
+ printf("non CYCLEMASTER mode\n");
+ OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
+ OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
+ }
+
+ fc->status = FWBUSINIT;
+
+ if (!kdb_active)
+ taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid);
+ }
+sidout:
+ if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active))
+ taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma);
+}
+
+static void
+fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count)
+{
+ uint32_t irstat, itstat;
+ u_int i;
+ struct firewire_comm *fc = (struct firewire_comm *)sc;
+
+ if (stat & OHCI_INT_DMA_IR) {
irstat = atomic_readandclear_int(&sc->irstat);
-#endif
for(i = 0; i < fc->nisodma ; i++){
struct fwohci_dbch *dbch;
@@ -1845,36 +1932,22 @@ busresetout:
}
}
}
- if((stat & OHCI_INT_DMA_IT )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT);
-#endif
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
- itstat = sc->itstat;
- sc->itstat = 0;
-#else
+ if (stat & OHCI_INT_DMA_IT) {
itstat = atomic_readandclear_int(&sc->itstat);
-#endif
for(i = 0; i < fc->nisodma ; i++){
if((itstat & (1 << i)) != 0){
fwohci_tbuf_update(sc, i);
}
}
}
- if((stat & OHCI_INT_DMA_PRRS )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS);
-#endif
+ if (stat & OHCI_INT_DMA_PRRS) {
#if 0
dump_dma(sc, ARRS_CH);
dump_db(sc, ARRS_CH);
#endif
fwohci_arcv(sc, &sc->arrs, count);
}
- if((stat & OHCI_INT_DMA_PRRQ )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ);
-#endif
+ if (stat & OHCI_INT_DMA_PRRQ) {
#if 0
dump_dma(sc, ARRQ_CH);
dump_db(sc, ARRQ_CH);
@@ -1894,120 +1967,77 @@ busresetout:
"no cycle master presents?\n");
}
}
- if(stat & OHCI_INT_PHY_SID){
- uint32_t *buf, node_id;
- int plen;
-
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID);
-#endif
- /* Enable bus reset interrupt */
- OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R);
- /* Allow async. request to us */
- OWRITE(sc, OHCI_AREQHI, 1 << 31);
- /* XXX insecure ?? */
- /* allow from all nodes */
- OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
- OWRITE(sc, OHCI_PREQLO, 0xffffffff);
- /* 0 to 4GB regison */
- OWRITE(sc, OHCI_PREQUPPER, 0x10000);
- /* Set ATRetries register */
- OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
-/*
-** Checking whether the node is root or not. If root, turn on
-** cycle master.
-*/
- node_id = OREAD(sc, FWOHCI_NODEID);
- plen = OREAD(sc, OHCI_SID_CNT);
-
- device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
- node_id, (plen >> 16) & 0xff);
- if (!(node_id & OHCI_NODE_VALID)) {
- printf("Bus reset failure\n");
- goto sidout;
- }
-
- /* cycle timer */
- sc->cycle_lost = 0;
- OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST);
- if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) {
- printf("CYCLEMASTER mode\n");
- OWRITE(sc, OHCI_LNKCTL,
- OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
- } else {
- printf("non CYCLEMASTER mode\n");
- OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
- OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
- }
-
- fc->nodeid = node_id & 0x3f;
-
- if (plen & OHCI_SID_ERR) {
- device_printf(fc->dev, "SID Error\n");
- goto sidout;
- }
- plen &= OHCI_SID_CNT_MASK;
- if (plen < 4 || plen > OHCI_SIDSIZE) {
- device_printf(fc->dev, "invalid SID len = %d\n", plen);
- goto sidout;
- }
- plen -= 4; /* chop control info */
- buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
- if (buf == NULL) {
- device_printf(fc->dev, "malloc failed\n");
- goto sidout;
- }
- for (i = 0; i < plen / 4; i ++)
- buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
-#if 1 /* XXX needed?? */
- /* pending all pre-bus_reset packets */
- fwohci_txd(sc, &sc->atrq);
- fwohci_txd(sc, &sc->atrs);
- fwohci_arcv(sc, &sc->arrs, -1);
- fwohci_arcv(sc, &sc->arrq, -1);
- fw_drain_txq(fc);
-#endif
- fw_sidrcv(fc, buf, plen);
- free(buf, M_FW);
- }
-sidout:
- if((stat & OHCI_INT_DMA_ATRQ )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ);
-#endif
+ if (stat & OHCI_INT_DMA_ATRQ) {
fwohci_txd(sc, &(sc->atrq));
}
- if((stat & OHCI_INT_DMA_ATRS )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS);
-#endif
+ if (stat & OHCI_INT_DMA_ATRS) {
fwohci_txd(sc, &(sc->atrs));
}
- if((stat & OHCI_INT_PW_ERR )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR);
-#endif
+ if (stat & OHCI_INT_PW_ERR) {
device_printf(fc->dev, "posted write error\n");
}
- if((stat & OHCI_INT_ERR )){
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR);
-#endif
+ if (stat & OHCI_INT_ERR) {
device_printf(fc->dev, "unrecoverable error\n");
}
- if((stat & OHCI_INT_PHY_INT)) {
-#ifndef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT);
-#endif
+ if (stat & OHCI_INT_PHY_INT) {
device_printf(fc->dev, "phy int\n");
}
return;
}
-#if FWOHCI_TASKQUEUE
static void
-fwohci_complete(void *arg, int pending)
+fwohci_task_busreset(void *arg, int pending)
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)arg;
+
+ fw_busreset(&sc->fc, FWBUSRESET);
+ OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
+ OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
+}
+
+static void
+fwohci_task_sid(void *arg, int pending)
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)arg;
+ struct firewire_comm *fc = &sc->fc;
+ uint32_t *buf;
+ int i, plen;
+
+
+ plen = OREAD(sc, OHCI_SID_CNT);
+
+ if (plen & OHCI_SID_ERR) {
+ device_printf(fc->dev, "SID Error\n");
+ return;
+ }
+ plen &= OHCI_SID_CNT_MASK;
+ if (plen < 4 || plen > OHCI_SIDSIZE) {
+ device_printf(fc->dev, "invalid SID len = %d\n", plen);
+ return;
+ }
+ plen -= 4; /* chop control info */
+ buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
+ if (buf == NULL) {
+ device_printf(fc->dev, "malloc failed\n");
+ return;
+ }
+ for (i = 0; i < plen / 4; i ++)
+ buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
+#if 1 /* XXX needed?? */
+ /* pending all pre-bus_reset packets */
+ fwohci_txd(sc, &sc->atrq);
+ fwohci_txd(sc, &sc->atrs);
+ fwohci_arcv(sc, &sc->arrs, -1);
+ fwohci_arcv(sc, &sc->arrq, -1);
+ fw_drain_txq(fc);
+#endif
+ fw_sidrcv(fc, buf, plen);
+ free(buf, M_FW);
+}
+
+static void
+fwohci_task_dma(void *arg, int pending)
{
struct fwohci_softc *sc = (struct fwohci_softc *)arg;
uint32_t stat;
@@ -2015,15 +2045,14 @@ fwohci_complete(void *arg, int pending)
again:
stat = atomic_readandclear_int(&sc->intstat);
if (stat)
- fwohci_intr_body(sc, stat, -1);
+ fwohci_intr_dma(sc, stat, -1);
else
return;
goto again;
}
-#endif
-static uint32_t
-fwochi_check_stat(struct fwohci_softc *sc)
+static int
+fwohci_check_stat(struct fwohci_softc *sc)
{
uint32_t stat, irstat, itstat;
@@ -2031,12 +2060,16 @@ fwochi_check_stat(struct fwohci_softc *sc)
if (stat == 0xffffffff) {
device_printf(sc->fc.dev,
"device physically ejected?\n");
- return(stat);
+ return (FILTER_STRAY);
}
-#ifdef ACK_ALL
if (stat)
- OWRITE(sc, FWOHCI_INTSTATCLR, stat);
-#endif
+ OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R);
+
+ stat &= sc->intmask;
+ if (stat == 0)
+ return (FILTER_STRAY);
+
+ atomic_set_int(&sc->intstat, stat);
if (stat & OHCI_INT_DMA_IR) {
irstat = OREAD(sc, OHCI_IR_STAT);
OWRITE(sc, OHCI_IR_STATCLR, irstat);
@@ -2047,68 +2080,34 @@ fwochi_check_stat(struct fwohci_softc *sc)
OWRITE(sc, OHCI_IT_STATCLR, itstat);
atomic_set_int(&sc->itstat, itstat);
}
- return(stat);
+
+ fwohci_intr_core(sc, stat, -1);
+ return (FILTER_HANDLED);
}
-void
-fwohci_intr(void *arg)
+int
+fwohci_filt(void *arg)
{
struct fwohci_softc *sc = (struct fwohci_softc *)arg;
- uint32_t stat;
-#if !FWOHCI_TASKQUEUE
- uint32_t bus_reset = 0;
-#endif
if (!(sc->intmask & OHCI_INT_EN)) {
/* polling mode */
- return;
+ return (FILTER_STRAY);
}
+ return (fwohci_check_stat(sc));
+}
-#if !FWOHCI_TASKQUEUE
-again:
-#endif
- stat = fwochi_check_stat(sc);
- if (stat == 0 || stat == 0xffffffff)
- return;
-#if FWOHCI_TASKQUEUE
- atomic_set_int(&sc->intstat, stat);
- /* XXX mask bus reset intr. during bus reset phase */
- if (stat)
- taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete);
-#else
- /* We cannot clear bus reset event during bus reset phase */
- if ((stat & ~bus_reset) == 0)
- return;
- bus_reset = stat & OHCI_INT_PHY_BUS_R;
- fwohci_intr_body(sc, stat, -1);
- goto again;
-#endif
+void
+fwohci_intr(void *arg)
+{
+ fwohci_filt(arg);
}
void
fwohci_poll(struct firewire_comm *fc, int quick, int count)
{
- int s;
- uint32_t stat;
- struct fwohci_softc *sc;
-
-
- sc = (struct fwohci_softc *)fc;
- stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT |
- OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ |
- OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS;
-#if 0
- if (!quick) {
-#else
- if (1) {
-#endif
- stat = fwochi_check_stat(sc);
- if (stat == 0 || stat == 0xffffffff)
- return;
- }
- s = splfw();
- fwohci_intr_body(sc, stat, count);
- splx(s);
+ struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+ fwohci_check_stat(sc);
}
static void
@@ -2141,6 +2140,7 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
it = fc->it[dmach];
ldesc = sc->it[dmach].ndesc - 1;
s = splfw(); /* unnecessary ? */
+ FW_GLOCK(fc);
fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
if (firewire_debug)
dump_db(sc, ITX_CH + dmach);
@@ -2169,6 +2169,7 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
w++;
}
+ FW_GUNLOCK(fc);
splx(s);
if (w)
wakeup(it);
@@ -2182,14 +2183,17 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
struct fw_bulkxfer *chunk;
struct fw_xferq *ir;
uint32_t stat;
- int s, w=0, ldesc;
+ int s, w = 0, ldesc;
ir = fc->ir[dmach];
ldesc = sc->ir[dmach].ndesc - 1;
+
#if 0
dump_db(sc, dmach);
#endif
s = splfw();
+ if ((ir->flag & FWXFERQ_HANDLER) == 0)
+ FW_GLOCK(fc);
fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
db_tr = (struct fwohcidb_tr *)chunk->end;
@@ -2224,13 +2228,16 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
}
w++;
}
+ if ((ir->flag & FWXFERQ_HANDLER) == 0)
+ FW_GUNLOCK(fc);
splx(s);
- if (w) {
- if (ir->flag & FWXFERQ_HANDLER)
- ir->hand(ir);
- else
- wakeup(ir);
- }
+ if (w == 0)
+ return;
+
+ if (ir->flag & FWXFERQ_HANDLER)
+ ir->hand(ir);
+ else
+ wakeup(ir);
}
void
@@ -2487,6 +2494,8 @@ fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
unsigned short chtag;
int idb;
+ FW_GLOCK_ASSERT(&sc->fc);
+
dbch = &sc->it[dmach];
chtag = sc->it[dmach].xferq.flag & 0xff;
diff --git a/sys/dev/firewire/fwohci_pci.c b/sys/dev/firewire/fwohci_pci.c
index ddc4f48..b21bb28 100644
--- a/sys/dev/firewire/fwohci_pci.c
+++ b/sys/dev/firewire/fwohci_pci.c
@@ -302,6 +302,7 @@ fwohci_pci_attach(device_t self)
firewire_debug = bootverbose;
#endif
+ mtx_init(FW_GMTX(&sc->fc), "firewire", NULL, MTX_DEF);
fwohci_pci_init(self);
rid = PCI_CBMEM;
@@ -335,12 +336,12 @@ fwohci_pci_attach(device_t self)
err = bus_setup_intr(self, sc->irq_res,
-#if FWOHCI_TASKQUEUE
INTR_TYPE_NET | INTR_MPSAFE,
+#if FWOHCI_INTFILT
+ fwohci_filt, NULL, sc, &sc->ih);
#else
- INTR_TYPE_NET,
-#endif
NULL, (driver_intr_t *) fwohci_intr, sc, &sc->ih);
+#endif
#if defined(__DragonFly__) || __FreeBSD_version < 500000
/* XXX splcam() should mask this irq for sbp.c*/
err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM,
@@ -376,7 +377,7 @@ fwohci_pci_attach(device_t self)
/*flags*/BUS_DMA_ALLOCNOW,
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
/*lockfunc*/busdma_lock_mutex,
- /*lockarg*/&Giant,
+ /*lockarg*/FW_GMTX(&sc->fc),
#endif
&sc->fc.dmat);
if (err != 0) {
@@ -448,6 +449,7 @@ fwohci_pci_detach(device_t self)
}
fwohci_detach(sc, self);
+ mtx_destroy(FW_GMTX(&sc->fc));
splx(s);
return 0;
@@ -492,7 +494,7 @@ fwohci_pci_add_child(device_t dev, int order, const char *name, int unit)
{
struct fwohci_softc *sc;
device_t child;
- int s, err = 0;
+ int err = 0;
sc = (struct fwohci_softc *)device_get_softc(dev);
child = device_add_child(dev, name, unit);
@@ -516,6 +518,7 @@ fwohci_pci_add_child(device_t dev, int order, const char *name, int unit)
* interrupt is disabled during the boot process.
*/
if (cold) {
+ int s;
DELAY(250); /* 2 cycles */
s = splfw();
fwohci_poll((void *)sc, 0, -1);
diff --git a/sys/dev/firewire/fwohcivar.h b/sys/dev/firewire/fwohcivar.h
index 8435c5d..d0ee9f6 100644
--- a/sys/dev/firewire/fwohcivar.h
+++ b/sys/dev/firewire/fwohcivar.h
@@ -35,13 +35,12 @@
*
*/
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
-#define FWOHCI_TASKQUEUE 0
-#else
-#define FWOHCI_TASKQUEUE 1
-#endif
-#if FWOHCI_TASKQUEUE
#include <sys/taskqueue.h>
+
+#if defined(__DragonFly__) || __FreeBSD_version < 700043
+#define FWOHCI_INTFILT 0
+#else
+#define FWOHCI_INTFILT 1
#endif
typedef struct fwohci_softc {
@@ -77,14 +76,15 @@ typedef struct fwohci_softc {
struct fwdma_alloc crom_dma;
struct fwdma_alloc dummy_dma;
uint32_t intmask, irstat, itstat;
-#if FWOHCI_TASKQUEUE
uint32_t intstat;
- struct task fwohci_task_complete;
-#endif
+ struct task fwohci_task_busreset;
+ struct task fwohci_task_sid;
+ struct task fwohci_task_dma;
int cycle_lost;
} fwohci_softc_t;
void fwohci_intr (void *arg);
+int fwohci_filt (void *arg);
int fwohci_init (struct fwohci_softc *, device_t);
void fwohci_poll (struct firewire_comm *, int, int);
void fwohci_reset (struct fwohci_softc *, device_t);
diff --git a/sys/dev/firewire/if_fwe.c b/sys/dev/firewire/if_fwe.c
index b56c5cd..438838d 100644
--- a/sys/dev/firewire/if_fwe.c
+++ b/sys/dev/firewire/if_fwe.c
@@ -157,6 +157,7 @@ fwe_attach(device_t dev)
unit = device_get_unit(dev);
bzero(fwe, sizeof(struct fwe_softc));
+ mtx_init(&fwe->mtx, "fwe", NULL, MTX_DEF);
/* XXX */
fwe->stream_ch = stream_ch;
fwe->dma_ch = -1;
@@ -213,8 +214,7 @@ fwe_attach(device_t dev)
ifp->if_start = fwe_start;
ifp->if_ioctl = fwe_ioctl;
ifp->if_mtu = ETHERMTU;
- ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|
- IFF_NEEDSGIANT);
+ ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
s = splimp();
@@ -305,6 +305,7 @@ fwe_detach(device_t dev)
#endif
splx(s);
+ mtx_destroy(&fwe->mtx);
return 0;
}
@@ -325,22 +326,15 @@ fwe_init(void *arg)
ifp->if_flags |= IFF_PROMISC;
fc = fwe->fd.fc;
-#define START 0
if (fwe->dma_ch < 0) {
- for (i = START; i < fc->nisodma; i ++) {
- xferq = fc->ir[i];
- if ((xferq->flag & FWXFERQ_OPEN) == 0)
- goto found;
- }
- printf("no free dma channel\n");
- return;
-found:
- fwe->dma_ch = i;
+ fwe->dma_ch = fw_open_isodma(fc, /* tx */0);
+ if (fwe->dma_ch < 0)
+ return;
+ xferq = fc->ir[fwe->dma_ch];
+ xferq->flag |= FWXFERQ_EXTBUF |
+ FWXFERQ_HANDLER | FWXFERQ_STREAM;
fwe->stream_ch = stream_ch;
fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
- /* allocate DMA channel and init packet mode */
- xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
- FWXFERQ_HANDLER | FWXFERQ_STREAM;
xferq->flag &= ~0xff;
xferq->flag |= fwe->stream_ch & 0xff;
/* register fwe_input handler */
@@ -375,7 +369,7 @@ found:
STAILQ_INSERT_TAIL(&xferq->stfree,
&xferq->bulkxfer[i], link);
} else
- printf("fwe_as_input: m_getcl failed\n");
+ printf("%s: m_getcl failed\n", __FUNCTION__);
}
STAILQ_INIT(&fwe->xferlist);
for (i = 0; i < TX_MAX_QUEUE; i++) {
@@ -520,7 +514,9 @@ fwe_output_callback(struct fw_xfer *xfer)
fw_xfer_unload(xfer);
s = splimp();
+ FWE_LOCK(fwe);
STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
+ FWE_UNLOCK(fwe);
splx(s);
/* for queue full */
@@ -534,8 +530,6 @@ fwe_start(struct ifnet *ifp)
struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
int s;
- GIANT_REQUIRED;
-
FWEDEBUG(ifp, "starting\n");
if (fwe->dma_ch < 0) {
@@ -589,16 +583,27 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
xfer = NULL;
xferq = fwe->fd.fc->atq;
- while (xferq->queued < xferq->maxq - 1) {
+ while ((xferq->queued < xferq->maxq - 1) &&
+ (ifp->if_snd.ifq_head != NULL)) {
+ FWE_LOCK(fwe);
xfer = STAILQ_FIRST(&fwe->xferlist);
if (xfer == NULL) {
+#if 0
printf("if_fwe: lack of xfer\n");
- return;
+#endif
+ FWE_UNLOCK(fwe);
+ break;
}
+ STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
+ FWE_UNLOCK(fwe);
+
IF_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
+ if (m == NULL) {
+ FWE_LOCK(fwe);
+ STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link);
+ FWE_UNLOCK(fwe);
break;
- STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
+ }
#if defined(__DragonFly__) || __FreeBSD_version < 500000
if (ifp->if_bpf != NULL)
bpf_mtap(ifp, m);
@@ -649,6 +654,7 @@ fwe_as_input(struct fw_xferq *xferq)
fwe = (struct fwe_softc *)xferq->sc;
ifp = fwe->eth_softc.ifp;
+ /* We do not need a lock here because the bottom half is serialized */
while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
fp = mtod(sxfer->mbuf, struct fw_pkt *);
@@ -662,7 +668,7 @@ fwe_as_input(struct fw_xferq *xferq)
m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
} else
- printf("fwe_as_input: m_getcl failed\n");
+ printf("%s: m_getcl failed\n", __FUNCTION__);
if (sxfer->resp != 0 || fp->mode.stream.len <
ETHER_ALIGN + sizeof(struct ether_header)) {
@@ -672,7 +678,7 @@ fwe_as_input(struct fw_xferq *xferq)
}
m->m_data += HDR_LEN + ETHER_ALIGN;
- c = mtod(m, char *);
+ c = mtod(m, u_char *);
#if defined(__DragonFly__) || __FreeBSD_version < 500000
eh = (struct ether_header *)c;
m->m_data += sizeof(struct ether_header);
diff --git a/sys/dev/firewire/if_fwevar.h b/sys/dev/firewire/if_fwevar.h
index 73fcb3d..4b8eb76 100644
--- a/sys/dev/firewire/if_fwevar.h
+++ b/sys/dev/firewire/if_fwevar.h
@@ -38,7 +38,7 @@
#define _NET_IF_FWEVAR_H_
struct fwe_softc {
- /* XXX this must be first for fd.post_explore() */
+ /* XXX this must be the first for fd.post_explore() */
struct firewire_dev_comm fd;
short stream_ch;
short dma_ch;
@@ -48,5 +48,8 @@ struct fwe_softc {
struct ifnet *ifp;
struct fwe_softc *fwe;
} eth_softc;
+ struct mtx mtx;
};
+#define FWE_LOCK(fwe) mtx_lock(&(fwe)->mtx)
+#define FWE_UNLOCK(fwe) mtx_unlock(&(fwe)->mtx)
#endif /* !_NET_IF_FWEVAR_H_ */
diff --git a/sys/dev/firewire/if_fwip.c b/sys/dev/firewire/if_fwip.c
index d7b2c31..a9d1f38 100644
--- a/sys/dev/firewire/if_fwip.c
+++ b/sys/dev/firewire/if_fwip.c
@@ -161,6 +161,7 @@ fwip_attach(device_t dev)
if (ifp == NULL)
return (ENOSPC);
+ mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF);
/* XXX */
fwip->dma_ch = -1;
@@ -197,8 +198,7 @@ fwip_attach(device_t dev)
ifp->if_init = fwip_init;
ifp->if_start = fwip_start;
ifp->if_ioctl = fwip_ioctl;
- ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|
- IFF_NEEDSGIANT);
+ ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
@@ -282,6 +282,7 @@ fwip_detach(device_t dev)
fwip_stop(fwip);
firewire_ifdetach(ifp);
if_free(ifp);
+ mtx_destroy(&fwip->mtx);
splx(s);
return 0;
@@ -303,17 +304,11 @@ fwip_init(void *arg)
fc = fwip->fd.fc;
#define START 0
if (fwip->dma_ch < 0) {
- for (i = START; i < fc->nisodma; i ++) {
- xferq = fc->ir[i];
- if ((xferq->flag & FWXFERQ_OPEN) == 0)
- goto found;
- }
- printf("no free dma channel\n");
- return;
-found:
- fwip->dma_ch = i;
- /* allocate DMA channel and init packet mode */
- xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
+ fwip->dma_ch = fw_open_isodma(fc, /* tx */0);
+ if (fwip->dma_ch < 0)
+ return;
+ xferq = fc->ir[fwip->dma_ch];
+ xferq->flag |= FWXFERQ_EXTBUF |
FWXFERQ_HANDLER | FWXFERQ_STREAM;
xferq->flag &= ~0xff;
xferq->flag |= broadcast_channel & 0xff;
@@ -522,8 +517,6 @@ fwip_output_callback(struct fw_xfer *xfer)
struct ifnet *ifp;
int s;
- GIANT_REQUIRED;
-
fwip = (struct fwip_softc *)xfer->sc;
ifp = fwip->fw_softc.fwip_ifp;
/* XXX error check */
@@ -535,12 +528,15 @@ fwip_output_callback(struct fw_xfer *xfer)
fw_xfer_unload(xfer);
s = splimp();
+ FWIP_LOCK(fwip);
STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
+ FWIP_UNLOCK(fwip);
splx(s);
/* for queue full */
- if (ifp->if_snd.ifq_head != NULL)
+ if (ifp->if_snd.ifq_head != NULL) {
fwip_start(ifp);
+ }
}
static void
@@ -549,8 +545,6 @@ fwip_start(struct ifnet *ifp)
struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip;
int s;
- GIANT_REQUIRED;
-
FWIPDEBUG(ifp, "starting\n");
if (fwip->dma_ch < 0) {
@@ -603,19 +597,29 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp)
int error;
int i = 0;
- GIANT_REQUIRED;
-
xfer = NULL;
- xferq = fwip->fd.fc->atq;
- while (xferq->queued < xferq->maxq - 1) {
+ xferq = fc->atq;
+ while ((xferq->queued < xferq->maxq - 1) &&
+ (ifp->if_snd.ifq_head != NULL)) {
+ FWIP_LOCK(fwip);
xfer = STAILQ_FIRST(&fwip->xferlist);
if (xfer == NULL) {
+ FWIP_UNLOCK(fwip);
+#if 0
printf("if_fwip: lack of xfer\n");
- return;
+#endif
+ break;
}
+ STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
+ FWIP_UNLOCK(fwip);
+
IF_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
+ if (m == NULL) {
+ FWIP_LOCK(fwip);
+ STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link);
+ FWIP_UNLOCK(fwip);
break;
+ }
/*
* Dig out the link-level address which
@@ -629,7 +633,6 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp)
else
destfw = (struct fw_hwaddr *) (mtag + 1);
- STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
/*
* We don't do any bpf stuff here - the generic code
@@ -722,7 +725,9 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp)
* for later transmission.
*/
xfer->mbuf = 0;
+ FWIP_LOCK(fwip);
STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
+ FWIP_UNLOCK(fwip);
IF_PREPEND(&ifp->if_snd, m);
break;
}
@@ -741,13 +746,8 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp)
if (i > 1)
printf("%d queued\n", i);
#endif
- if (i > 0) {
-#if 1
+ if (i > 0)
xferq->start(fc);
-#else
- taskqueue_enqueue(taskqueue_swi_giant, &fwip->start_send);
-#endif
- }
}
static void
@@ -755,7 +755,6 @@ fwip_start_send (void *arg, int count)
{
struct fwip_softc *fwip = arg;
- GIANT_REQUIRED;
fwip->fd.fc->atq->start(fwip->fd.fc);
}
@@ -772,7 +771,6 @@ fwip_stream_input(struct fw_xferq *xferq)
uint16_t src;
uint32_t *p;
- GIANT_REQUIRED;
fwip = (struct fwip_softc *)xferq->sc;
ifp = fwip->fw_softc.fwip_ifp;
@@ -874,8 +872,6 @@ fwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer)
{
struct mbuf *m;
- GIANT_REQUIRED;
-
/*
* We have finished with a unicast xfer. Allocate a new
* cluster and stick it on the back of the input queue.
@@ -900,8 +896,6 @@ fwip_unicast_input(struct fw_xfer *xfer)
//struct fw_pkt *sfp;
int rtcode;
- GIANT_REQUIRED;
-
fwip = (struct fwip_softc *)xfer->sc;
ifp = fwip->fw_softc.fwip_ifp;
m = xfer->mbuf;
diff --git a/sys/dev/firewire/if_fwipvar.h b/sys/dev/firewire/if_fwipvar.h
index 153ce94..57e7904 100644
--- a/sys/dev/firewire/if_fwipvar.h
+++ b/sys/dev/firewire/if_fwipvar.h
@@ -58,5 +58,8 @@ struct fwip_softc {
struct ifnet *fwip_ifp;
struct fwip_softc *fwip;
} fw_softc;
+ struct mtx mtx;
};
+#define FWIP_LOCK(fwip) mtx_lock(&(fwip)->mtx)
+#define FWIP_UNLOCK(fwip) mtx_unlock(&(fwip)->mtx)
#endif /* !_NET_IF_FWIPVAR_H_ */
diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c
index 1971e38..a004f95 100644
--- a/sys/dev/firewire/sbp.c
+++ b/sys/dev/firewire/sbp.c
@@ -245,7 +245,10 @@ struct sbp_softc {
struct timeval last_busreset;
#define SIMQ_FREEZED 1
int flags;
+ struct mtx mtx;
};
+#define SBP_LOCK(sbp) mtx_lock(&(sbp)->mtx)
+#define SBP_UNLOCK(sbp) mtx_unlock(&(sbp)->mtx)
static void sbp_post_explore (void *);
static void sbp_recv (struct fw_xfer *);
@@ -736,8 +739,10 @@ END_DEBUG
continue;
if (alive && (sdev->status != SBP_DEV_DEAD)) {
if (sdev->path != NULL) {
+ SBP_LOCK(sbp);
xpt_freeze_devq(sdev->path, 1);
sdev->freeze ++;
+ SBP_UNLOCK(sbp);
}
sbp_probe_lun(sdev);
SBP_DEBUG(0)
@@ -769,8 +774,10 @@ SBP_DEBUG(0)
printf("lost target\n");
END_DEBUG
if (sdev->path) {
+ SBP_LOCK(sbp);
xpt_freeze_devq(sdev->path, 1);
sdev->freeze ++;
+ SBP_UNLOCK(sbp);
}
sdev->status = SBP_DEV_RETRY;
sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
@@ -798,8 +805,10 @@ SBP_DEBUG(0)
printf("sbp_post_busreset\n");
END_DEBUG
if ((sbp->sim->flags & SIMQ_FREEZED) == 0) {
+ SBP_LOCK(sbp);
xpt_freeze_simq(sbp->sim, /*count*/1);
sbp->sim->flags |= SIMQ_FREEZED;
+ SBP_UNLOCK(sbp);
}
microtime(&sbp->last_busreset);
}
@@ -870,8 +879,10 @@ END_DEBUG
if (target->num_lun == 0)
sbp_free_target(target);
}
+ SBP_LOCK(sbp);
xpt_release_simq(sbp->sim, /*run queue*/TRUE);
sbp->sim->flags &= ~SIMQ_FREEZED;
+ SBP_UNLOCK(sbp);
}
#if NEED_RESPONSE
@@ -901,7 +912,9 @@ sbp_xfer_free(struct fw_xfer *xfer)
sdev = (struct sbp_dev *)xfer->sc;
fw_xfer_unload(xfer);
s = splfw();
+ SBP_LOCK(sdev->target->sbp);
STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link);
+ SBP_UNLOCK(sdev->target->sbp);
splx(s);
}
@@ -1043,9 +1056,11 @@ END_DEBUG
ccb->ccb_h.ccb_sdev_ptr = sdev;
/* The scan is in progress now. */
+ SBP_LOCK(target->sbp);
xpt_action(ccb);
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
sdev->freeze = 1;
+ SBP_UNLOCK(target->sbp);
}
static __inline void
@@ -1108,8 +1123,10 @@ END_DEBUG
sbp_xfer_free(xfer);
if (sdev->path) {
+ SBP_LOCK(sdev->target->sbp);
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
sdev->freeze = 0;
+ SBP_UNLOCK(sdev->target->sbp);
}
}
@@ -1353,20 +1370,25 @@ sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
nid = target->sbp->fd.fc->nodeid | FWLOCALBUS;
s = splfw();
+ SBP_LOCK(target->sbp);
if (func == ORB_FUN_RUNQUEUE) {
ocb = STAILQ_FIRST(&target->mgm_ocb_queue);
if (target->mgm_ocb_cur != NULL || ocb == NULL) {
+ SBP_UNLOCK(target->sbp);
splx(s);
return;
}
STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb);
+ SBP_UNLOCK(target->sbp);
goto start;
}
if ((ocb = sbp_get_ocb(sdev)) == NULL) {
+ SBP_UNLOCK(target->sbp);
splx(s);
/* XXX */
return;
}
+ SBP_UNLOCK(target->sbp);
ocb->flags = OCB_ACT_MGM;
ocb->sdev = sdev;
@@ -1404,7 +1426,9 @@ END_DEBUG
if (target->mgm_ocb_cur != NULL) {
/* there is a standing ORB */
+ SBP_LOCK(target->sbp);
STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb);
+ SBP_UNLOCK(target->sbp);
splx(s);
return;
}
@@ -1738,8 +1762,10 @@ END_DEBUG
/* we have to reset the fetch agent if it's dead */
if (sbp_status->dead) {
if (sdev->path) {
+ SBP_LOCK(sbp);
xpt_freeze_devq(sdev->path, 1);
sdev->freeze ++;
+ SBP_UNLOCK(sbp);
}
reset_agent = 1;
}
@@ -1847,7 +1873,9 @@ printf("len %d\n", sbp_status->len);
/* fix up inq data */
if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY)
sbp_fix_inq_data(ocb);
+ SBP_LOCK(sbp);
xpt_done(ccb);
+ SBP_UNLOCK(sbp);
}
break;
default:
@@ -1910,6 +1938,7 @@ sbp_attach(device_t dev)
{
struct sbp_softc *sbp;
struct cam_devq *devq;
+ struct firewire_comm *fc;
int i, s, error;
if (DFLTPHYS > SBP_MAXPHYS)
@@ -1926,12 +1955,13 @@ END_DEBUG
sbp = ((struct sbp_softc *)device_get_softc(dev));
bzero(sbp, sizeof(struct sbp_softc));
sbp->fd.dev = dev;
- sbp->fd.fc = device_get_ivars(dev);
+ sbp->fd.fc = fc = device_get_ivars(dev);
+ mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF);
if (max_speed < 0)
- max_speed = sbp->fd.fc->speed;
+ max_speed = fc->speed;
- error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat,
+ error = bus_dma_tag_create(/*parent*/fc->dmat,
/* XXX shoud be 4 for sane backend? */
/*alignment*/1,
/*boundary*/0,
@@ -1943,7 +1973,7 @@ END_DEBUG
/*flags*/BUS_DMA_ALLOCNOW,
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
/*lockfunc*/busdma_lock_mutex,
- /*lockarg*/&Giant,
+ /*lockarg*/&sbp->mtx,
#endif
&sbp->dmat);
if (error != 0) {
@@ -1963,7 +1993,7 @@ END_DEBUG
sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
device_get_unit(dev),
- &Giant,
+ &sbp->mtx,
/*untagged*/ 1,
/*tagged*/ SBP_QUEUE_LEN - 1,
devq);
@@ -1973,7 +2003,7 @@ END_DEBUG
return (ENXIO);
}
-
+ SBP_LOCK(sbp);
if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS)
goto fail;
@@ -1982,6 +2012,7 @@ END_DEBUG
xpt_bus_deregister(cam_sim_path(sbp->sim));
goto fail;
}
+ SBP_UNLOCK(sbp);
/* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
sbp->fwb.start = ((u_int64_t)SBP_BIND_HI << 32) | SBP_DEV2ADDR(0, 0);
@@ -1990,22 +2021,26 @@ END_DEBUG
STAILQ_INIT(&sbp->fwb.xferlist);
fw_xferlist_add(&sbp->fwb.xferlist, M_SBP,
/*send*/ 0, /*recv*/ SBP_RECV_LEN, SBP_NUM_OCB/2,
- sbp->fd.fc, (void *)sbp, sbp_recv);
- fw_bindadd(sbp->fd.fc, &sbp->fwb);
+ fc, (void *)sbp, sbp_recv);
+
+ fw_bindadd(fc, &sbp->fwb);
sbp->fd.post_busreset = sbp_post_busreset;
sbp->fd.post_explore = sbp_post_explore;
- if (sbp->fd.fc->status != -1) {
+ if (fc->status != -1) {
s = splfw();
sbp_post_busreset((void *)sbp);
sbp_post_explore((void *)sbp);
splx(s);
}
+ SBP_LOCK(sbp);
xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
+ SBP_UNLOCK(sbp);
return (0);
fail:
+ SBP_UNLOCK(sbp);
cam_sim_free(sbp->sim, /*free_devq*/TRUE);
return (ENXIO);
}
@@ -2100,10 +2135,13 @@ END_DEBUG
for (i = 0; i < SBP_NUM_TARGETS; i ++)
sbp_cam_detach_target(&sbp->targets[i]);
+
+ SBP_LOCK(sbp);
xpt_async(AC_LOST_DEVICE, sbp->path, NULL);
xpt_free_path(sbp->path);
xpt_bus_deregister(cam_sim_path(sbp->sim));
cam_sim_free(sbp->sim, /*free_devq*/ TRUE),
+ SBP_UNLOCK(sbp);
sbp_logout_all(sbp);
@@ -2117,6 +2155,7 @@ END_DEBUG
fw_xferlist_remove(&sbp->fwb.xferlist);
bus_dma_tag_destroy(sbp->dmat);
+ mtx_destroy(&sbp->mtx);
return (0);
}
@@ -2130,15 +2169,17 @@ sbp_cam_detach_sdev(struct sbp_dev *sdev)
return;
if (sdev->status == SBP_DEV_RESET)
return;
+ sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
if (sdev->path) {
+ SBP_LOCK(sdev->target->sbp);
xpt_release_devq(sdev->path,
sdev->freeze, TRUE);
sdev->freeze = 0;
xpt_async(AC_LOST_DEVICE, sdev->path, NULL);
xpt_free_path(sdev->path);
sdev->path = NULL;
+ SBP_UNLOCK(sdev->target->sbp);
}
- sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
}
static void
@@ -2171,8 +2212,10 @@ sbp_target_reset(struct sbp_dev *sdev, int method)
continue;
if (tsdev->status == SBP_DEV_RESET)
continue;
+ SBP_LOCK(target->sbp);
xpt_freeze_devq(tsdev->path, 1);
tsdev->freeze ++;
+ SBP_UNLOCK(target->sbp);
sbp_abort_all_ocbs(tsdev, CAM_CMD_TIMEOUT);
if (method == 2)
tsdev->status = SBP_DEV_LOGIN;
@@ -2227,8 +2270,10 @@ sbp_timeout(void *arg)
switch(sdev->timeout) {
case 1:
printf("agent reset\n");
+ SBP_LOCK(sdev->target->sbp);
xpt_freeze_devq(sdev->path, 1);
sdev->freeze ++;
+ SBP_UNLOCK(sdev->target->sbp);
sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
sbp_agent_reset(sdev);
break;
@@ -2332,6 +2377,7 @@ END_DEBUG
void *cdb;
csio = &ccb->csio;
+ mtx_assert(sim->mtx, MA_OWNED);
SBP_DEBUG(2)
printf("%s:%d:%d XPT_SCSI_IO: "
@@ -2375,8 +2421,10 @@ END_DEBUG
if ((ocb = sbp_get_ocb(sdev)) == NULL) {
ccb->ccb_h.status = CAM_REQUEUE_REQ;
if (sdev->freeze == 0) {
+ SBP_LOCK(sdev->target->sbp);
xpt_freeze_devq(sdev->path, 1);
sdev->freeze ++;
+ SBP_UNLOCK(sdev->target->sbp);
}
xpt_done(ccb);
return;
@@ -2681,6 +2729,7 @@ SBP_DEBUG(1)
#endif
__func__, ntohl(sbp_status->orb_lo), sbp_status->src);
END_DEBUG
+ SBP_LOCK(sdev->target->sbp);
for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
next = STAILQ_NEXT(ocb, ocb);
flags = ocb->flags;
@@ -2728,6 +2777,7 @@ END_DEBUG
} else
order ++;
}
+ SBP_UNLOCK(sdev->target->sbp);
splx(s);
SBP_DEBUG(0)
if (ocb && order > 0) {
@@ -2785,6 +2835,8 @@ sbp_get_ocb(struct sbp_dev *sdev)
{
struct sbp_ocb *ocb;
int s = splfw();
+
+ mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
ocb = STAILQ_FIRST(&sdev->free_ocbs);
if (ocb == NULL) {
sdev->flags |= ORB_SHORTAGE;
@@ -2803,6 +2855,8 @@ sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
{
ocb->flags = 0;
ocb->ccb = NULL;
+
+ SBP_LOCK(sdev->target->sbp);
STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb);
if ((sdev->flags & ORB_SHORTAGE) != 0) {
int count;
@@ -2812,6 +2866,7 @@ sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
sdev->freeze = 0;
xpt_release_devq(sdev->path, count, TRUE);
}
+ SBP_UNLOCK(sdev->target->sbp);
}
static void
@@ -2842,7 +2897,9 @@ END_DEBUG
untimeout(sbp_timeout, (caddr_t)ocb,
ocb->ccb->ccb_h.timeout_ch);
ocb->ccb->ccb_h.status = status;
+ SBP_LOCK(sdev->target->sbp);
xpt_done(ocb->ccb);
+ SBP_UNLOCK(sdev->target->sbp);
}
sbp_free_ocb(sdev, ocb);
}
diff --git a/sys/dev/firewire/sbp_targ.c b/sys/dev/firewire/sbp_targ.c
index ef14efc..911460d 100644
--- a/sys/dev/firewire/sbp_targ.c
+++ b/sys/dev/firewire/sbp_targ.c
@@ -140,7 +140,10 @@ struct sbp_targ_softc {
struct sbp_targ_lstate *lstate[MAX_LUN];
struct sbp_targ_lstate *black_hole;
struct sbp_targ_login *logins[MAX_LOGINS];
+ struct mtx mtx;
};
+#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
struct corb4 {
#if BYTE_ORDER == BIG_ENDIAN
@@ -215,6 +218,7 @@ static char *orb_fun_name[] = {
static void sbp_targ_recv(struct fw_xfer *);
static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
uint16_t, uint32_t, struct sbp_targ_login *, int);
+static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
static void
sbp_targ_identify(driver_t *driver, device_t parent)
@@ -289,8 +293,10 @@ sbp_targ_post_busreset(void *arg)
unit = &sc->unit;
if ((sc->flags & F_FREEZED) == 0) {
+ SBP_LOCK(sc);
sc->flags |= F_FREEZED;
xpt_freeze_simq(sc->sim, /*count*/1);
+ SBP_UNLOCK(sc);
} else {
printf("%s: already freezed\n", __func__);
}
@@ -321,6 +327,7 @@ sbp_targ_post_busreset(void *arg)
login = sc->logins[i];
if (login == NULL)
continue;
+ sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
if (login->flags & F_LOGIN) {
login->flags |= F_HOLD;
callout_reset(&login->hold_callout,
@@ -336,8 +343,10 @@ sbp_targ_post_explore(void *arg)
struct sbp_targ_softc *sc;
sc = (struct sbp_targ_softc *)arg;
+ SBP_LOCK(sc);
sc->flags &= ~F_FREEZED;
xpt_release_simq(sc->sim, /*run queue*/TRUE);
+ SBP_UNLOCK(sc);
return;
}
@@ -484,10 +493,19 @@ sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
#endif
}
+
+static __inline void
+sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
+{
+ STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
+}
+
static __inline void
sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
{
+ SBP_LOCK(orbi->sc);
STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
+ SBP_UNLOCK(orbi->sc);
}
/*
@@ -518,19 +536,21 @@ sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
STAILQ_FOREACH(orbi, &login->orbs, link)
if (orbi->orb_lo == tag_id)
goto found;
- printf("%s: orb not found tag_id=0x%08x\n", __func__, tag_id);
+ printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
+ __func__, tag_id, init_id);
return (NULL);
found:
return (orbi);
}
static void
-sbp_targ_abort(struct orb_info *orbi)
+sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
{
struct orb_info *norbi;
+ SBP_LOCK(sc);
for (; orbi != NULL; orbi = norbi) {
- printf("%s: status=%d\n", __func__, orbi->state);
+ printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
norbi = STAILQ_NEXT(orbi, link);
if (orbi->state != ORBI_STATUS_ABORTED) {
if (orbi->ccb != NULL) {
@@ -538,13 +558,16 @@ sbp_targ_abort(struct orb_info *orbi)
xpt_done(orbi->ccb);
orbi->ccb = NULL;
}
+#if 0
if (orbi->state <= ORBI_STATUS_ATIO) {
- sbp_targ_remove_orb_info(orbi->login, orbi);
+ sbp_targ_remove_orb_info_locked(orbi->login, orbi);
free(orbi, M_SBP_TARG);
} else
+#endif
orbi->state = ORBI_STATUS_ABORTED;
}
}
+ SBP_UNLOCK(sc);
}
static void
@@ -585,6 +608,7 @@ static void
sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
{
struct sbp_status *sbp_status;
+ struct orb_info *norbi;
sbp_status = &orbi->status;
@@ -614,7 +638,24 @@ sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
sbp_cmd_status->status = ccb->csio.scsi_status;
sense = &ccb->csio.sense_data;
- sbp_targ_abort(STAILQ_NEXT(orbi, link));
+#if 0 /* XXX What we should do? */
+#if 0
+ sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
+#else
+ norbi = STAILQ_NEXT(orbi, link);
+ while (norbi) {
+ printf("%s: status=%d\n", __func__, norbi->state);
+ if (norbi->ccb != NULL) {
+ norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
+ xpt_done(norbi->ccb);
+ norbi->ccb = NULL;
+ }
+ sbp_targ_remove_orb_info_locked(orbi->login, norbi);
+ norbi = STAILQ_NEXT(norbi, link);
+ free(norbi, M_SBP_TARG);
+ }
+#endif
+#endif
if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR)
sbp_cmd_status->sfmt = SBP_SFMT_CURR;
@@ -653,11 +694,11 @@ sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
sbp_status->status);
}
- sbp_targ_status_FIFO(orbi,
- orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
-
if (orbi->page_table != NULL)
free(orbi->page_table, M_SBP_TARG);
+
+ sbp_targ_status_FIFO(orbi,
+ orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
}
static void
@@ -677,13 +718,14 @@ sbp_targ_cam_done(struct fw_xfer *xfer)
orbi->status.resp = SBP_TRANS_FAIL;
orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
orbi->status.dead = 1;
- sbp_targ_abort(STAILQ_NEXT(orbi, link));
+ sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
}
orbi->refcount --;
ccb = orbi->ccb;
if (orbi->refcount == 0) {
+ orbi->ccb = NULL;
if (orbi->state == ORBI_STATUS_ABORTED) {
if (debug)
printf("%s: orbi aborted\n", __func__);
@@ -695,14 +737,18 @@ sbp_targ_cam_done(struct fw_xfer *xfer)
if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
sbp_targ_send_status(orbi, ccb);
ccb->ccb_h.status = CAM_REQ_CMP;
+ SBP_LOCK(orbi->sc);
xpt_done(ccb);
+ SBP_UNLOCK(orbi->sc);
} else {
orbi->status.len = 1;
sbp_targ_status_FIFO(orbi,
orbi->login->fifo_hi, orbi->login->fifo_lo,
/*dequeue*/1);
ccb->ccb_h.status = CAM_REQ_ABORTED;
+ SBP_LOCK(orbi->sc);
xpt_done(ccb);
+ SBP_UNLOCK(orbi->sc);
}
}
@@ -823,7 +869,7 @@ sbp_targ_pt_done(struct fw_xfer *xfer)
orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
orbi->status.dead = 1;
orbi->status.len = 1;
- sbp_targ_abort(STAILQ_NEXT(orbi, link));
+ sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
sbp_targ_status_FIFO(orbi,
orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
@@ -901,7 +947,8 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
struct orb_info *orbi;
if (debug)
- printf("%s: XPT_CONT_TARGET_IO\n", __func__);
+ printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
+ __func__, ccb->csio.tag_id);
if (status != CAM_REQ_CMP) {
ccb->ccb_h.status = status;
@@ -919,8 +966,10 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
if (orbi->state == ORBI_STATUS_ABORTED) {
if (debug)
printf("%s: ctio aborted\n", __func__);
- sbp_targ_remove_orb_info(orbi->login, orbi);
+ sbp_targ_remove_orb_info_locked(orbi->login, orbi);
free(orbi, M_SBP_TARG);
+ ccb->ccb_h.status = CAM_REQ_ABORTED;
+ xpt_done(ccb);
break;
}
orbi->state = ORBI_STATUS_CTIO;
@@ -966,8 +1015,12 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
sbp_targ_cam_done);
if (ccb_dir == CAM_DIR_NONE) {
- if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
+ if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
+ /* XXX */
+ SBP_UNLOCK(sc);
sbp_targ_send_status(orbi, ccb);
+ SBP_LOCK(sc);
+ }
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
}
@@ -1106,7 +1159,7 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
orbi->status.dead = 1;
orbi->status.len = 1;
- sbp_targ_abort(STAILQ_NEXT(orbi, link));
+ sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
sbp_targ_status_FIFO(orbi,
orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
@@ -1115,10 +1168,16 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
}
fp = &xfer->recv.hdr;
+ atio = orbi->atio;
+
if (orbi->state == ORBI_STATUS_ABORTED) {
printf("%s: aborted\n", __func__);
sbp_targ_remove_orb_info(orbi->login, orbi);
free(orbi, M_SBP_TARG);
+ atio->ccb_h.status = CAM_REQ_ABORTED;
+ SBP_LOCK(orbi->sc);
+ xpt_done((union ccb*)atio);
+ SBP_UNLOCK(orbi->sc);
goto done0;
}
orbi->state = ORBI_STATUS_ATIO;
@@ -1134,7 +1193,6 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
}
- atio = orbi->atio;
atio->ccb_h.target_id = 0; /* XXX */
atio->ccb_h.target_lun = orbi->login->lstate->lun;
atio->sense_len = 0;
@@ -1143,10 +1201,10 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
atio->init_id = orbi->login->id;
atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
- bytes = (char *)&orb[5];
+ bytes = (u_char *)&orb[5];
if (debug)
- printf("%s: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- __func__,
+ printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ __func__, (void *)atio,
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
switch (bytes[0] >> 5) {
@@ -1191,7 +1249,9 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
orbi->data_lo = orb[3];
orbi->orb4 = *orb4;
+ SBP_LOCK(orbi->sc);
xpt_done((union ccb*)atio);
+ SBP_UNLOCK(orbi->sc);
done0:
fw_xfer_free(xfer);
return;
@@ -1256,7 +1316,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer)
orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
orbi->status.dead = 1;
orbi->status.len = 1;
- sbp_targ_abort(STAILQ_NEXT(orbi, link));
+ sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
sbp_targ_status_FIFO(orbi,
orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
@@ -1309,6 +1369,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer)
orbi->status.len = 1;
break;
}
+ printf("%s: login id=%d\n", __func__, login->id);
login->fifo_hi = orb[6];
login->fifo_lo = orb[7];
@@ -1318,10 +1379,10 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer)
login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
login->loginres.recon_hold = htons(login->hold_sec);
+ STAILQ_INSERT_TAIL(&lstate->logins, login, link);
fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
sizeof(struct sbp_login_res), (void *)&login->loginres,
fw_asy_callback_free);
- STAILQ_INSERT_TAIL(&lstate->logins, login, link);
/* XXX return status after loginres is successfully written */
break;
}
@@ -1418,9 +1479,11 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
login->last_lo = orb_lo;
login->flags |= F_LINK_ACTIVE;
/* dequeue */
+ SBP_LOCK(sc);
orbi->atio = (struct ccb_accept_tio *)
SLIST_FIRST(&login->lstate->accept_tios);
if (orbi->atio == NULL) {
+ SBP_UNLOCK(sc);
printf("%s: no free atio\n", __func__);
login->lstate->flags |= F_ATIO_STARVED;
login->flags |= F_ATIO_STARVED;
@@ -1431,10 +1494,11 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
break;
}
SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
+ STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
+ SBP_UNLOCK(sc);
fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
sizeof(uint32_t) * 8, &orbi->orb[0],
sbp_targ_cmd_handler);
- STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
break;
case FETCH_POINTER:
orbi->state = ORBI_STATUS_POINTER;
@@ -1489,7 +1553,7 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
switch (reg) {
case 0x08: /* ORB_POINTER */
if (debug)
- printf("%s: ORB_POINTER\n", __func__);
+ printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
if ((login->flags & F_LINK_ACTIVE) != 0) {
if (debug)
printf("link active (ORB_POINTER)\n");
@@ -1502,14 +1566,14 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
break;
case 0x04: /* AGENT_RESET */
if (debug)
- printf("%s: AGENT RESET\n", __func__);
+ printf("%s: AGENT RESET(%d)\n", __func__, login_id);
login->last_hi = 0xffff;
login->last_lo = 0xffffffff;
- sbp_targ_abort(STAILQ_FIRST(&login->orbs));
+ sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
break;
case 0x10: /* DOORBELL */
if (debug)
- printf("%s: DOORBELL\n", __func__);
+ printf("%s: DOORBELL(%d)\n", __func__, login_id);
if (login->last_hi == 0xffff &&
login->last_lo == 0xffffffff) {
printf("%s: no previous pointer(DOORBELL)\n",
@@ -1526,13 +1590,15 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
login, FETCH_POINTER);
break;
case 0x00: /* AGENT_STATE */
- printf("%s: AGENT_STATE (ignore)\n", __func__);
+ printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
break;
case 0x14: /* UNSOLICITED_STATE_ENABLE */
- printf("%s: UNSOLICITED_STATE_ENABLE (ignore)\n", __func__);
+ printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
+ __func__, login_id);
break;
default:
- printf("%s: invalid register %d\n", __func__, reg);
+ printf("%s: invalid register %d(%d)\n",
+ __func__, reg, login_id);
rtcode = RESP_ADDRESS_ERROR;
}
@@ -1561,7 +1627,6 @@ sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
return(0);
}
-
static void
sbp_targ_recv(struct fw_xfer *xfer)
{
@@ -1582,6 +1647,7 @@ sbp_targ_recv(struct fw_xfer *xfer)
goto done;
}
lo = fp->mode.wreqb.dest_lo;
+
if (lo == SBP_TARG_BIND_LO(-1))
rtcode = sbp_targ_mgm(xfer, fwdev);
else if (lo >= SBP_TARG_BIND_LO(0))
@@ -1611,11 +1677,13 @@ sbp_targ_attach(device_t dev)
{
struct sbp_targ_softc *sc;
struct cam_devq *devq;
+ struct firewire_comm *fc;
sc = (struct sbp_targ_softc *) device_get_softc(dev);
bzero((void *)sc, sizeof(struct sbp_targ_softc));
- sc->fd.fc = device_get_ivars(dev);
+ mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
+ sc->fd.fc = fc = device_get_ivars(dev);
sc->fd.dev = dev;
sc->fd.post_explore = (void *) sbp_targ_post_explore;
sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
@@ -1625,13 +1693,14 @@ sbp_targ_attach(device_t dev)
return (ENXIO);
sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
- "sbp_targ", sc, device_get_unit(dev), &Giant,
+ "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
/*untagged*/ 1, /*tagged*/ 1, devq);
if (sc->sim == NULL) {
cam_simq_free(devq);
return (ENXIO);
}
+ SBP_LOCK(sc);
if (xpt_bus_register(sc->sim, /*bus*/0) != CAM_SUCCESS)
goto fail;
@@ -1640,6 +1709,7 @@ sbp_targ_attach(device_t dev)
xpt_bus_deregister(cam_sim_path(sc->sim));
goto fail;
}
+ SBP_UNLOCK(sc);
sc->fwb.start = SBP_TARG_BIND_START;
sc->fwb.end = SBP_TARG_BIND_END;
@@ -1648,11 +1718,12 @@ sbp_targ_attach(device_t dev)
STAILQ_INIT(&sc->fwb.xferlist);
fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
/*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
- sc->fd.fc, (void *)sc, sbp_targ_recv);
- fw_bindadd(sc->fd.fc, &sc->fwb);
+ fc, (void *)sc, sbp_targ_recv);
+ fw_bindadd(fc, &sc->fwb);
return 0;
fail:
+ SBP_UNLOCK(sc);
cam_sim_free(sc->sim, /*free_devq*/TRUE);
return (ENXIO);
}
@@ -1667,8 +1738,10 @@ sbp_targ_detach(device_t dev)
sc = (struct sbp_targ_softc *)device_get_softc(dev);
sc->fd.post_busreset = NULL;
+ SBP_LOCK(sc);
xpt_free_path(sc->path);
xpt_bus_deregister(cam_sim_path(sc->sim));
+ SBP_UNLOCK(sc);
cam_sim_free(sc->sim, /*free_devq*/TRUE);
for (i = 0; i < MAX_LUN; i ++) {
@@ -1686,6 +1759,8 @@ sbp_targ_detach(device_t dev)
fw_bindremove(sc->fd.fc, &sc->fwb);
fw_xferlist_remove(&sc->fwb.xferlist);
+ mtx_destroy(&sc->mtx);
+
return 0;
}
OpenPOWER on IntegriCloud