summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2003-01-26 15:39:04 +0000
committersimokawa <simokawa@FreeBSD.org>2003-01-26 15:39:04 +0000
commit376bd949e066a9aef4b2331a6b8e66e5eba8132f (patch)
tree07df55b90f7e481cf05714448e507f62ace570ba /sys
parent4865a58cd6760c2a3695e5f7b6b7bf42560ced68 (diff)
downloadFreeBSD-src-376bd949e066a9aef4b2331a6b8e66e5eba8132f.zip
FreeBSD-src-376bd949e066a9aef4b2331a6b8e66e5eba8132f.tar.gz
- Improve IT/IR DMA queue management.
- Improve debug message for mbuf handling. - Wait 1 sec for DMA stop in fwohci_i{t,r}x_disable() before freeing buffers.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/firewire/firewire.c178
-rw-r--r--sys/dev/firewire/firewirereg.h10
-rw-r--r--sys/dev/firewire/fwdev.c41
-rw-r--r--sys/dev/firewire/fwohci.c434
4 files changed, 235 insertions, 428 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
index 7252cea..e555266 100644
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -122,184 +122,6 @@ static driver_t firewire_driver = {
};
/*
- * transmitter buffer update.
- */
-int
-fw_tbuf_update(struct firewire_comm *fc, int sub, int flag){
- struct fw_bulkxfer *bulkxfer, *bulkxfer2 = NULL;
- struct fw_xferq *it;
- int s, err = 0;
-
- it = fc->it[sub];
-
- s = splfw();
- if(it->stdma == NULL){
- bulkxfer = STAILQ_FIRST(&it->stvalid);
- }else if(flag != 0){
- bulkxfer = STAILQ_FIRST(&it->stvalid);
- if(bulkxfer == it->stdma){
- STAILQ_REMOVE_HEAD(&it->stvalid, link);
- it->stdma->flag = 0;
- STAILQ_INSERT_TAIL(&it->stfree, it->stdma, link);
-#ifdef FWXFERQ_DV
- if(!(it->flag & FWXFERQ_DV))
-#endif
- wakeup(it);
- }
- bulkxfer = STAILQ_FIRST(&it->stvalid);
- }else{
- bulkxfer = it->stdma;
- }
- if(bulkxfer != NULL){
- bulkxfer2 = STAILQ_NEXT(bulkxfer, link);
-#if 0
- if(it->flag & FWXFERQ_DV && bulkxfer2 == NULL){
- bulkxfer2 = STAILQ_FIRST(&it->stfree);
- STAILQ_REMOVE_HEAD(&it->stfree, link);
- bcopy(bulkxfer->buf, bulkxfer2->buf,
- it->psize * it->btpacket);
- STAILQ_INSERT_TAIL(&it->stvalid, bulkxfer2, link);
- }
-#endif
- }
- it->stdma = bulkxfer;
- it->stdma2 = bulkxfer2;
-
-#ifdef FWXFERQ_DV
- if(it->flag & FWXFERQ_DV){
- struct fw_dvbuf *dvbuf = NULL;
- int i, j, chtag;
- struct fw_pkt *fp;
- u_int64_t cycle, dvsync;
-
- chtag = it->flag & 0xff;
-dvloop:
- if(it->dvdma == NULL){
- dvbuf = STAILQ_FIRST(&it->dvvalid);
- if(dvbuf != NULL){
- STAILQ_REMOVE_HEAD(&it->dvvalid, link);
- it->dvdma = dvbuf;
- it->queued = 0;
- }
- }
- if(it->dvdma == NULL)
- goto out;
-
- it->stproc = STAILQ_FIRST(&it->stfree);
- if(it->stproc != NULL){
- STAILQ_REMOVE_HEAD(&it->stfree, link);
- }else{
- goto out;
- }
-#if DV_PAL
-#define DVSEC 3
-#define DVFRAC 75 /* PAL: 25 Hz (1875 = 25 * 3) */
-#define DVDIFF 5 /* 125 = (8000/300 - 25) * 3 */
-#else
-#define DVSEC 100
-#define DVFRAC 2997 /* NTSC: 29.97 Hz (2997 = 29.97 * 100) */
-#define DVDIFF 203 /* 203 = (8000/250 - 29.97) * 100 */
-#endif
-#define CYCLEFRAC 0xc00
- cycle = (u_int64_t) 8000 * DVSEC * it->dvsync;
- /* least significant 12 bits */
- dvsync = (cycle * CYCLEFRAC / DVFRAC) % CYCLEFRAC;
- /* most significat 4 bits */
- cycle = (cycle / DVFRAC + it->dvoffset) & 0xf;
- fp = (struct fw_pkt *)(it->dvdma->buf);
-#if 1
- fp->mode.ld[2] = htonl(0x80000000 | (cycle << 12) | dvsync);
-#else
- fp->mode.ld[2] = htonl(0x80000000 | dvsync);
-#endif
- it->dvsync ++;
- it->dvsync %= 2997;
-
- for( i = 0, j = 0 ; i < it->dvpacket ; i++){
- bcopy(it->dvdma->buf + it->queued * it->psize,
- it->stproc->buf + j * it->psize, it->psize);
- fp = (struct fw_pkt *)(it->stproc->buf + j * it->psize);
- fp->mode.stream.len = htons(488);
- fp->mode.stream.chtag = chtag;
- fp->mode.stream.tcode = FWTCODE_STREAM;
- fp->mode.ld[1] = htonl((fc->nodeid << 24) | 0x00780000 | it->dvdbc);
- it->dvdbc++;
- it->dvdbc %= 256;
- it->queued ++;
- j++;
- it->dvdiff += DVDIFF;
- if(it->dvdiff >= DVFRAC){
- it->dvdiff %= DVFRAC;
- fp = (struct fw_pkt *)(it->stproc->buf + j * it->psize);
-
- fp->mode.stream.len = htons(0x8);
- fp->mode.stream.chtag = chtag;
- fp->mode.stream.tcode = FWTCODE_STREAM;
- fp->mode.ld[1] = htonl((fc->nodeid << 24) |
- 0x00780000 | it->dvdbc);
- j++;
- }
- }
- it->stproc->npacket = j;
- STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
- if(it->queued >= it->dvpacket){
- STAILQ_INSERT_TAIL(&it->dvfree, it->dvdma, link);
- it->dvdma = NULL;
- wakeup(it);
- goto dvloop;
- }
- }
-out:
-#endif
- splx(s);
- return err;
-}
-/*
- * receving buffer update.
- */
-int
-fw_rbuf_update(struct firewire_comm *fc, int sub, int flag){
- struct fw_bulkxfer *bulkxfer, *bulkxfer2 = NULL;
- struct fw_xferq *ir;
- int s, err = 0;
-
- ir = fc->ir[sub];
- s = splfw();
- if(ir->stdma != NULL){
- if(flag != 0){
- STAILQ_INSERT_TAIL(&ir->stvalid, ir->stdma, link);
- }else{
- ir->stdma->flag = 0;
- STAILQ_INSERT_TAIL(&ir->stfree, ir->stdma, link);
- }
- }
- if(ir->stdma2 != NULL){
- bulkxfer = ir->stdma2;
- bulkxfer2 = STAILQ_FIRST(&ir->stfree);
- if(bulkxfer2 != NULL){
- STAILQ_REMOVE_HEAD(&ir->stfree, link);
- }
- }else{
- bulkxfer = STAILQ_FIRST(&ir->stfree);
- if(bulkxfer != NULL){
- STAILQ_REMOVE_HEAD(&ir->stfree, link);
- bulkxfer2 = STAILQ_FIRST(&ir->stfree);
- if(bulkxfer2 != NULL){
- STAILQ_REMOVE_HEAD(&ir->stfree, link);
- }
- }else{
- device_printf(fc->bdev, "no free chunk available\n");
- bulkxfer = STAILQ_FIRST(&ir->stvalid);
- STAILQ_REMOVE_HEAD(&ir->stvalid, link);
- }
- }
- splx(s);
- ir->stdma = bulkxfer;
- ir->stdma2 = bulkxfer2;
- return err;
-}
-
-/*
* To lookup node id. from EUI64.
*/
struct fw_device *
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
index a2c994e..ffdd8b7 100644
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -186,7 +186,7 @@ struct fw_xferq {
#define FWXFERQ_PACKET (1 << 10)
#define FWXFERQ_BULK (1 << 11)
-#if 0
+#if 0 /* BROKEN */
#define FWXFERQ_DV (1 << 12)
#endif
#define FWXFERQ_MODEMASK (7 << 10)
@@ -213,10 +213,9 @@ struct fw_xferq {
struct fw_bulkxfer *bulkxfer;
STAILQ_HEAD(, fw_bulkxfer) stvalid;
STAILQ_HEAD(, fw_bulkxfer) stfree;
- struct fw_bulkxfer *stdma;
- struct fw_bulkxfer *stdma2;
+ STAILQ_HEAD(, fw_bulkxfer) stdma;
struct fw_bulkxfer *stproc;
- u_int procptr;
+#ifdef FWXFERQ_DV
int dvdbc, dvdiff, dvsync, dvoffset;
struct fw_dvbuf *dvbuf;
STAILQ_HEAD(, fw_dvbuf) dvvalid;
@@ -225,14 +224,13 @@ struct fw_xferq {
struct fw_dvbuf *dvproc;
u_int dvptr;
u_int dvpacket;
- u_int need_wakeup;
+#endif
struct selinfo rsel;
caddr_t sc;
void (*hand) __P((struct fw_xferq *));
};
struct fw_bulkxfer{
- u_int32_t flag;
caddr_t buf;
STAILQ_ENTRY(fw_bulkxfer) link;
caddr_t start;
diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c
index 7233f35..460e8b8 100644
--- a/sys/dev/firewire/fwdev.c
+++ b/sys/dev/firewire/fwdev.c
@@ -173,7 +173,9 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
sc->fc->it[sub]->buf = NULL;
free(sc->fc->it[sub]->bulkxfer, M_DEVBUF);
sc->fc->it[sub]->bulkxfer = NULL;
+#ifdef FWXFERQ_DV
sc->fc->it[sub]->dvbuf = NULL;
+#endif
sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
sc->fc->it[sub]->psize = 0;
sc->fc->it[sub]->maxq = FWMAXQUEUE;
@@ -284,24 +286,12 @@ readloop:
ir->queued ++;
if(ir->queued >= ir->bnpacket){
s = splfw();
- ir->stproc->flag = 0;
STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
splx(s);
+ sc->fc->irx_enable(sc->fc, sub);
ir->stproc = NULL;
}
}
-#if 0
- if(STAILQ_FIRST(&ir->q) == NULL &&
- (ir->flag & FWXFERQ_RUNNING) && (ir->flag & FWXFERQ_PACKET)){
- err = sc->fc->irx_enable(sc->fc, sub);
- }
-#endif
-#if 0
- if(STAILQ_FIRST(&ir->stvalid) == NULL &&
- (ir->flag & FWXFERQ_RUNNING) && !(ir->flag & FWXFERQ_PACKET)){
- err = sc->fc->irx_enable(sc->fc, sub);
- }
-#endif
return err;
}
@@ -357,7 +347,6 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
/* Discard unsent buffered stream packet, when sending Asyrequrst */
if(xferq != NULL && it->stproc != NULL){
s = splfw();
- it->stproc->flag = 0;
STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
splx(s);
it->stproc = NULL;
@@ -368,14 +357,14 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
if (xferq == NULL) {
#endif
isoloop:
- if(it->stproc == NULL){
+ if (it->stproc == NULL) {
it->stproc = STAILQ_FIRST(&it->stfree);
- if(it->stproc != NULL){
+ if (it->stproc != NULL) {
s = splfw();
STAILQ_REMOVE_HEAD(&it->stfree, link);
splx(s);
it->queued = 0;
- }else if(slept == 0){
+ } else if (slept == 0) {
slept = 1;
err = sc->fc->itx_enable(sc->fc, sub);
if(err){
@@ -391,10 +380,6 @@ isoloop:
return err;
}
}
-#if 0 /* What's this for? (overwritten by the following uiomove)*/
- fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize);
- fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
-#endif
err = uiomove(it->stproc->buf + it->queued * it->psize,
uio->uio_resid, uio);
it->queued ++;
@@ -403,7 +388,6 @@ isoloop:
STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
splx(s);
it->stproc = NULL;
- fw_tbuf_update(sc->fc, sub, 0);
err = sc->fc->itx_enable(sc->fc, sub);
}
return err;
@@ -684,22 +668,23 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->bnpacket = ibufreq->tx.npacket;
it->btpacket = ibufreq->tx.npacket;
it->psize = (ibufreq->tx.psize + 3) & ~3;
- ir->queued = 0;
+ it->queued = 0;
+
+#ifdef FWXFERQ_DV
it->dvdbc = 0;
it->dvdiff = 0;
it->dvsync = 0;
it->dvoffset = 0;
+#endif
STAILQ_INIT(&ir->stvalid);
STAILQ_INIT(&ir->stfree);
- ir->stdma = NULL;
- ir->stdma2 = NULL;
+ STAILQ_INIT(&ir->stdma);
ir->stproc = NULL;
STAILQ_INIT(&it->stvalid);
STAILQ_INIT(&it->stfree);
- it->stdma = NULL;
- it->stdma2 = NULL;
+ STAILQ_INIT(&it->stdma);
it->stproc = NULL;
for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
@@ -707,7 +692,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ir->buf +
i * sc->fc->ir[sub]->bnpacket *
sc->fc->ir[sub]->psize;
- ir->bulkxfer[i].flag = 0;
STAILQ_INSERT_TAIL(&ir->stfree,
&ir->bulkxfer[i], link);
ir->bulkxfer[i].npacket = ir->bnpacket;
@@ -717,7 +701,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->buf +
i * sc->fc->it[sub]->bnpacket *
sc->fc->it[sub]->psize;
- it->bulkxfer[i].flag = 0;
STAILQ_INSERT_TAIL(&it->stfree,
&it->bulkxfer[i], link);
it->bulkxfer[i].npacket = it->bnpacket;
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;
OpenPOWER on IntegriCloud