diff options
Diffstat (limited to 'sys/dev/firewire/fwohci.c')
-rw-r--r-- | sys/dev/firewire/fwohci.c | 434 |
1 files changed, 219 insertions, 215 deletions
diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index ea6e3d2..78c238e 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -42,6 +42,7 @@ #define IRX_CH 0x24 #include <sys/param.h> +#include <sys/proc.h> #include <sys/systm.h> #include <sys/types.h> #include <sys/mbuf.h> @@ -847,17 +848,15 @@ txloop: db_tr->dbcnt++; } else { + int mchain=0; /* XXX we assume mbuf chain is shorter than ndesc */ for (m = xfer->mbuf; m != NULL; m = m->m_next) { if (m->m_len == 0) - /* unrecoverable error could ocurre. */ + /* unrecoverable error could occur. */ + continue; + mchain++; + if (db_tr->dbcnt >= dbch->ndesc) continue; - if (db_tr->dbcnt >= dbch->ndesc) { - device_printf(sc->fc.dev, - "dbch->ndesc is too small" - ", trancated.\n"); - break; - } db->db.desc.addr = vtophys(mtod(m, caddr_t)); db->db.desc.cmd = OHCI_OUTPUT_MORE | m->m_len; @@ -865,6 +864,11 @@ txloop: db++; db_tr->dbcnt++; } + if (mchain > dbch->ndesc - 2) + device_printf(sc->fc.dev, + "dbch->ndesc(%d) is too small for" + " mbuf chain(%d), trancated.\n", + dbch->ndesc, mchain); } } if (maxdesc < db_tr->dbcnt) { @@ -1201,9 +1205,13 @@ static int fwohci_itx_disable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; + int dummy; + OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); + /* XXX we cannot free buffers until the DMA really stops */ + tsleep((void *)&dummy, FWPRI, "fwitxd", hz); fwohci_db_free(&sc->it[dmach]); sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; return 0; @@ -1213,10 +1221,13 @@ static int fwohci_irx_disable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; + int dummy; OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); + /* XXX we cannot free buffers until the DMA really stops */ + tsleep((void *)&dummy, FWPRI, "fwirxd", hz); if(sc->ir[dmach].dummy != NULL){ free(sc->ir[dmach].dummy, M_DEVBUF); } @@ -1416,21 +1427,51 @@ fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) } static int +fwochi_next_cycle(struct firewire_comm *fc, int cycle_now) +{ + int sec, cycle, cycle_match; + + cycle = cycle_now & 0x1fff; + sec = cycle_now >> 13; +#define CYCLE_MOD 0x10 +#define CYCLE_DELAY 8 /* min delay to start DMA */ + cycle = cycle + CYCLE_DELAY; + if (cycle >= 8000) { + sec ++; + cycle -= 8000; + } + cycle = ((cycle + CYCLE_MOD - 1) / CYCLE_MOD) * CYCLE_MOD; + if (cycle >= 8000) { + sec ++; + if (cycle == 8000) + cycle = 0; + else + cycle = CYCLE_MOD; + } + cycle_match = ((sec << 13) | cycle) & 0x7ffff; + + return(cycle_match); +} + +static int fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; int err = 0; unsigned short tag, ich; struct fwohci_dbch *dbch; - int cycle_now, sec, cycle, cycle_match; + int cycle_match, cycle_now, s, ldesc; u_int32_t stat; + struct fw_bulkxfer *first, *chunk, *prev; + struct fw_xferq *it; - tag = (sc->it[dmach].xferq.flag >> 6) & 3; - ich = sc->it[dmach].xferq.flag & 0x3f; dbch = &sc->it[dmach]; + it = &dbch->xferq; + + tag = (it->flag >> 6) & 3; + ich = it->flag & 0x3f; if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { - dbch->xferq.queued = 0; - dbch->ndb = dbch->xferq.bnpacket * dbch->xferq.bnchunk; + dbch->ndb = it->bnpacket * it->bnchunk; dbch->ndesc = 3; fwohci_db_init(dbch); if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) @@ -1439,56 +1480,53 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) } if(err) return err; - stat = OREAD(sc, OHCI_ITCTL(dmach)); - if (stat & OHCI_CNTL_DMA_ACTIVE) { - if(dbch->xferq.stdma2 != NULL){ - fwohci_txbufdb(sc, dmach, dbch->xferq.stdma2); - ((struct fwohcidb_tr *) - (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.cmd - |= OHCI_BRANCH_ALWAYS; - ((struct fwohcidb_tr *) - (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; - ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[0].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; - ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; - ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; - } else { - device_printf(fc->dev, - "fwohci_itxbuf_enable: queue underrun\n"); + + s = splfw(); + prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); + while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { + volatile struct fwohcidb *db; + + fwohci_txbufdb(sc, dmach, chunk); + ldesc = dbch->ndesc - 1; + db = ((struct fwohcidb_tr *)(chunk->end))->db; + db[ldesc].db.desc.status = db[0].db.desc.status = 0; + db[ldesc].db.desc.count = db[0].db.desc.count = 0; + db[ldesc].db.desc.depend &= ~0xf; + db[0].db.desc.depend &= ~0xf; + if (prev != NULL) { + db = ((struct fwohcidb_tr *)(prev->end))->db; + db[ldesc].db.desc.cmd |= OHCI_BRANCH_ALWAYS; + db[ldesc].db.desc.depend = db[0].db.desc.depend = + vtophys(((struct fwohcidb_tr *) + (chunk->start))->db) | dbch->ndesc; } - return err; - } - if (firewire_debug) - printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); - fw_tbuf_update(&sc->fc, dmach, 0); - if(dbch->xferq.stdma == NULL){ - return err; - } - if(dbch->xferq.stdma2 == NULL){ - /* wait until 2 chunks buffered */ - return err; + STAILQ_REMOVE_HEAD(&it->stvalid, link); + STAILQ_INSERT_TAIL(&it->stdma, chunk, link); + prev = chunk; } + splx(s); + stat = OREAD(sc, OHCI_ITCTL(dmach)); + if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) + return 0; + + OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); OWRITE(sc, OHCI_IT_MASK, 1 << dmach); - fwohci_txbufdb(sc, dmach, dbch->xferq.stdma); - fwohci_txbufdb(sc, dmach, dbch->xferq.stdma2); - ((struct fwohcidb_tr *) - (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.cmd - |= OHCI_BRANCH_ALWAYS; - ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; - ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[0].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; - ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; - ((struct fwohcidb_tr *) (dbch->xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; - OWRITE(sc, OHCI_ITCMD(dmach), - vtophys(((struct fwohcidb_tr *) - (dbch->xferq.stdma->start))->db) | dbch->ndesc); -#define CYCLE_OFFSET 1 + + first = STAILQ_FIRST(&it->stdma); + OWRITE(sc, OHCI_ITCMD(dmach), vtophys(((struct fwohcidb_tr *) + (first->start))->db) | dbch->ndesc); + if (firewire_debug) + printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); if ((stat & OHCI_CNTL_DMA_RUN) == 0) { +#if 1 + /* Don't start until all chunks are buffered */ + if (STAILQ_FIRST(&it->stfree) != NULL) + goto out; +#endif #ifdef FWXFERQ_DV +#define CYCLE_OFFSET 1 if(dbch->xferq.flag & FWXFERQ_DV){ struct fw_pkt *fp; struct fwohcidb_tr *db_tr; @@ -1499,41 +1537,26 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) fp->mode.ld[2] |= htonl(dbch->xferq.dvoffset << 12); } #endif - /* 2bit second + 13bit cycle */ - cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; - cycle = cycle_now & 0x1fff; - sec = cycle_now >> 13; -#define CYCLE_MOD 0x10 -#define CYCLE_DELAY 8 /* min delay to start DMA */ - cycle = cycle + CYCLE_DELAY; - if (cycle >= 8000) { - sec ++; - cycle -= 8000; - } - cycle = ((cycle + CYCLE_MOD - 1) / CYCLE_MOD) * CYCLE_MOD; - if (cycle >= 8000) { - sec ++; - if (cycle == 8000) - cycle = 0; - else - cycle = CYCLE_MOD; - } - cycle_match = ((sec << 13) | cycle) & 0x7ffff; /* Clear cycle match counter bits */ OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); + OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); + + /* 2bit second + 13bit cycle */ + cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; + cycle_match = fwochi_next_cycle(fc, cycle_now); + OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) | OHCI_CNTL_DMA_RUN); - OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); if (firewire_debug) printf("cycle_match: 0x%04x->0x%04x\n", cycle_now, cycle_match); } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { - if (firewire_debug) - printf("fwohci_itxbuf_enable: restart 0x%08x\n", stat); - OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); + device_printf(sc->fc.dev, + "IT DMA underrun (0x%08x)\n", stat); OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); } +out: return err; } @@ -1541,71 +1564,84 @@ static int fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; - int err = 0; + int err = 0, s, ldesc; unsigned short tag, ich; u_int32_t stat; + struct fwohci_dbch *dbch; + struct fw_bulkxfer *first, *prev, *chunk; + struct fw_xferq *ir; - if(!(sc->ir[dmach].xferq.flag & FWXFERQ_RUNNING)){ - tag = (sc->ir[dmach].xferq.flag >> 6) & 3; - ich = sc->ir[dmach].xferq.flag & 0x3f; + dbch = &sc->ir[dmach]; + ir = &dbch->xferq; + ldesc = dbch->ndesc - 1; + + if ((ir->flag & FWXFERQ_RUNNING) == 0) { + tag = (ir->flag >> 6) & 3; + ich = ir->flag & 0x3f; OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); - sc->ir[dmach].xferq.queued = 0; - sc->ir[dmach].ndb = sc->ir[dmach].xferq.bnpacket * - sc->ir[dmach].xferq.bnchunk; - sc->ir[dmach].dummy = - malloc(sizeof(u_int32_t) * sc->ir[dmach].ndb, - M_DEVBUF, M_NOWAIT); - if(sc->ir[dmach].dummy == NULL){ + ir->queued = 0; + dbch->ndb = ir->bnpacket * ir->bnchunk; + dbch->dummy = malloc(sizeof(u_int32_t) * dbch->ndb, + M_DEVBUF, M_NOWAIT); + if (dbch->dummy == NULL) { err = ENOMEM; return err; } - sc->ir[dmach].ndesc = 2; - fwohci_db_init(&sc->ir[dmach]); - if ((sc->ir[dmach].flags & FWOHCI_DBCH_INIT) == 0) + dbch->ndesc = 2; + fwohci_db_init(dbch); + if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; - err = fwohci_rx_enable(sc, &sc->ir[dmach]); + err = fwohci_rx_enable(sc, dbch); } if(err) return err; - stat = OREAD(sc, OHCI_IRCTL(dmach)); - if (stat & OHCI_CNTL_DMA_ACTIVE) { - if(sc->ir[dmach].xferq.stdma2 != NULL){ - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db) | sc->ir[dmach].ndesc; - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db); - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; - } - } else if (!(stat & OHCI_CNTL_DMA_ACTIVE) - && !(sc->ir[dmach].xferq.flag & FWXFERQ_PACKET)) { - if (firewire_debug) - device_printf(sc->fc.dev, "IR DMA stat %x\n", stat); - fw_rbuf_update(&sc->fc, dmach, 0); + s = splfw(); - OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); - OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); - OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); - OWRITE(sc, OHCI_IR_MASK, 1 << dmach); - OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); - OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); - if(sc->ir[dmach].xferq.stdma2 != NULL){ - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db) | sc->ir[dmach].ndesc; - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend = - vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db); - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; - }else{ - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; - ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend &= ~0xf; + first = STAILQ_FIRST(&ir->stfree); + if (first == NULL) { + device_printf(fc->dev, "IR DMA no free chunk\n"); + splx(s); + return 0; + } + + prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); + while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { + volatile struct fwohcidb *db; + + db = ((struct fwohcidb_tr *)(chunk->end))->db; + db[ldesc].db.desc.status = db[ldesc].db.desc.count = 0; + db[ldesc].db.desc.depend &= ~0xf; + if (prev != NULL) { + db = ((struct fwohcidb_tr *)(prev->end))->db; + db[ldesc].db.desc.depend = + vtophys(((struct fwohcidb_tr *) + (chunk->start))->db) | dbch->ndesc; } - OWRITE(sc, OHCI_IRCMD(dmach), - vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->start))->db) | sc->ir[dmach].ndesc); - OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); - OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); + STAILQ_REMOVE_HEAD(&ir->stfree, link); + STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); + prev = chunk; + } + splx(s); + stat = OREAD(sc, OHCI_IRCTL(dmach)); + if (stat & OHCI_CNTL_DMA_ACTIVE) + return 0; + if (stat & OHCI_CNTL_DMA_RUN) { + OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); + device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); } + + OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); + OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); + OWRITE(sc, OHCI_IR_MASK, 1 << dmach); + OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); + OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); + OWRITE(sc, OHCI_IRCMD(dmach), + vtophys(((struct fwohcidb_tr *)(first->start))->db) + | dbch->ndesc); + OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); + OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); return err; } @@ -1959,92 +1995,72 @@ fwohci_set_intr(struct firewire_comm *fc, int enable) static void fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) { - int stat; struct firewire_comm *fc = &sc->fc; - struct fwohci_dbch *dbch; - struct fwohcidb_tr *db_tr; - - dbch = &sc->it[dmach]; -#if 0 /* XXX OHCI interrupt before the last packet is really on the wire */ - if((dbch->xferq.flag & FWXFERQ_DV) && (dbch->xferq.stdma2 != NULL)){ - db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma2->start; -/* - * Overwrite highest significant 4 bits timestamp information - */ - fp = (struct fw_pkt *)db_tr->buf; - fp->mode.ld[2] &= htonl(0xffff0fff); - fp->mode.ld[2] |= htonl((fc->cyctimer(fc) + 0x4000) & 0xf000); - } + volatile struct fwohcidb *db; + struct fw_bulkxfer *chunk; + struct fw_xferq *it; + u_int32_t stat, count; + int s, w=0; + + it = fc->it[dmach]; + s = splfw(); /* unnecessary ? */ + while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { + db = ((struct fwohcidb_tr *)(chunk->end))->db; + stat = db[sc->it[dmach].ndesc - 1].db.desc.status; + db = ((struct fwohcidb_tr *)(chunk->start))->db; + count = db[sc->it[dmach].ndesc - 1].db.desc.count; + if (stat == 0) + break; + STAILQ_REMOVE_HEAD(&it->stdma, link); + switch (stat & FWOHCIEV_MASK){ + case FWOHCIEV_ACKCOMPL: +#if 0 + device_printf(fc->dev, "0x%08x\n", count); #endif - /* - * XXX interrupt could be missed. - * We have to check more than one buffer/chunk - */ - if (firewire_debug && dbch->xferq.stdma2 != NULL) { - db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma2->end; - stat = db_tr->db[2].db.desc.status; - if (stat) + break; + default: device_printf(fc->dev, - "stdma2 already done stat:0x%x\n", stat); - } - - stat = OREAD(sc, OHCI_ITCTL(dmach)) & 0x1f; - switch(stat){ - case FWOHCIEV_ACKCOMPL: -#ifdef FWXFERQ_DV - if (dbch->xferq.flag & FWXFERQ_DV) { - struct ciphdr *ciph; - int timer, timestamp, cycl, diff; - static int last_timer=0; - struct fw_pkt *fp; - - timer = (fc->cyctimer(fc) >> 12) & 0xffff; - db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start; - fp = (struct fw_pkt *)db_tr->buf; - ciph = (struct ciphdr *) &fp->mode.ld[1]; - timestamp = db_tr->db[2].db.desc.count & 0xffff; - cycl = ntohs(ciph->fdf.dv.cyc) >> 12; - diff = cycl - (timestamp & 0xf) - CYCLE_OFFSET; - if (diff < 0) - diff += 16; - if (diff > 8) - diff -= 16; - if (firewire_debug || diff != 0) - printf("dbc: %3d timer: 0x%04x packet: 0x%04x" - " cyc: 0x%x diff: %+1d\n", - ciph->dbc, last_timer, timestamp, cycl, diff); - last_timer = timer; - /* XXX adjust dbch->xferq.dvoffset if diff != 0 or 1 */ - } -#endif - fw_tbuf_update(fc, dmach, 1); - break; - default: - device_printf(fc->dev, "Isochronous transmit err %02x\n", stat); - fw_tbuf_update(fc, dmach, 0); - break; + "Isochronous transmit err %02x\n", stat); + } + STAILQ_INSERT_TAIL(&it->stfree, chunk, link); + w++; } - fwohci_itxbuf_enable(fc, dmach); + splx(s); + if (w) + wakeup(it); } static void fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) { struct firewire_comm *fc = &sc->fc; - int stat; + volatile struct fwohcidb *db; + struct fw_bulkxfer *chunk; + struct fw_xferq *ir; + u_int32_t stat; + int s, w=0; - stat = OREAD(sc, OHCI_IRCTL(dmach)) & 0x1f; - switch(stat){ - case FWOHCIEV_ACKCOMPL: - fw_rbuf_update(fc, dmach, 1); - wakeup(fc->ir[dmach]); - fwohci_irx_enable(fc, dmach); - break; - default: - device_printf(fc->dev, "Isochronous receive err %02x\n", - stat); - break; + ir = fc->ir[dmach]; + s = splfw(); + while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { + db = ((struct fwohcidb_tr *)(chunk->end))->db; + stat = db[sc->ir[dmach].ndesc - 1].db.desc.status; + if (stat == 0) + break; + STAILQ_REMOVE_HEAD(&ir->stdma, link); + STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); + switch (stat & FWOHCIEV_MASK) { + case FWOHCIEV_ACKCOMPL: + break; + default: + device_printf(fc->dev, + "Isochronous receive err %02x\n", stat); + } + w++; } + splx(s); + if (w) + wakeup(ir); } void @@ -2294,10 +2310,6 @@ fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) /* device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), vtophys(fdb_tr->db)); */ - if(bulkxfer->flag != 0){ - return; - } - bulkxfer->flag = 1; for( idb = 0 ; idb < bulkxfer->npacket ; idb ++){ db_tr->db[0].db.desc.cmd = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8; @@ -2308,9 +2320,7 @@ device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), v ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); ohcifp->mode.stream.chtag = chtag; ohcifp->mode.stream.tcode = 0xa; - ohcifp->mode.stream.spd = 4; - ohcifp->mode.ld[2] = ntohl(fp->mode.ld[1]); - ohcifp->mode.ld[3] = ntohl(fp->mode.ld[2]); + ohcifp->mode.stream.spd = 0; db_tr->db[2].db.desc.cmd = OHCI_OUTPUT_LAST @@ -2329,12 +2339,6 @@ device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), v db_tr = (struct fwohcidb_tr *)bulkxfer->end; db_tr->db[0].db.desc.depend &= ~0xf; db_tr->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; -#if 0 -/**/ - db_tr->db[dbch->ndesc - 1].db.desc.cmd &= ~OHCI_BRANCH_ALWAYS; - db_tr->db[dbch->ndesc - 1].db.desc.cmd |= OHCI_BRANCH_NEVER; -/**/ -#endif db_tr->db[dbch->ndesc - 1].db.desc.cmd |= OHCI_INTERRUPT_ALWAYS; /* OHCI 1.1 and above */ db_tr->db[0].db.desc.cmd |= OHCI_INTERRUPT_ALWAYS; |