summaryrefslogtreecommitdiffstats
path: root/sys/dev/firewire
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2007-04-30 14:06:30 +0000
committersimokawa <simokawa@FreeBSD.org>2007-04-30 14:06:30 +0000
commit042e9b5d41bac05194e97718e264f65dfea49699 (patch)
tree326eb8cb958b2dcd43ae57f310365678583dd6f0 /sys/dev/firewire
parent86a25e2852e1b099d529d404f77a8bb21546d760 (diff)
downloadFreeBSD-src-042e9b5d41bac05194e97718e264f65dfea49699.zip
FreeBSD-src-042e9b5d41bac05194e97718e264f65dfea49699.tar.gz
MFp4: Improve asynchronous packet receive process.
- Wake up DMA engine after adding a new receive buffer. - Skip buffers which have unknown state after error. - More rigid error detection. MFC after: 1 week
Diffstat (limited to 'sys/dev/firewire')
-rw-r--r--sys/dev/firewire/fwohci.c100
-rw-r--r--sys/dev/firewire/fwohcireg.h5
2 files changed, 73 insertions, 32 deletions
diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c
index 18d31b6..4e7c366 100644
--- a/sys/dev/firewire/fwohci.c
+++ b/sys/dev/firewire/fwohci.c
@@ -2683,13 +2683,16 @@ fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt
if ((info->flag & FWTI_BLOCK_ASY) != 0)
r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t));
- if (r == sizeof(uint32_t))
+ if (r == sizeof(uint32_t)) {
/* XXX */
device_printf(sc->fc.dev, "Unknown tcode %d\n",
fp->mode.common.tcode);
+ return (-1);
+ }
if (r > dbch->xferq.psize) {
device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
+ return (-1);
/* panic ? */
}
@@ -2697,7 +2700,8 @@ fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt
}
static void
-fwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
+fwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch,
+ struct fwohcidb_tr *db_tr, uint32_t off, int wake)
{
struct fwohcidb *db = &db_tr->db[0];
@@ -2706,6 +2710,9 @@ fwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
dbch->bottom = db_tr;
+
+ if (wake)
+ OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
}
static void
@@ -2717,7 +2724,7 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
int nvec;
struct fw_pkt *fp;
uint8_t *ld;
- uint32_t stat, off, status;
+ uint32_t stat, off, status, event;
u_int spd;
int len, plen, hlen, pcnt, offset;
int s;
@@ -2740,10 +2747,13 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
+ while (status & OHCI_CNTL_DMA_ACTIVE) {
#if 0
- printf("status 0x%04x, resCount 0x%04x\n", status, resCount);
+
+ if (off == OHCI_ARQOFF)
+ printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n",
+ db_tr->bus_addr, status, resCount);
#endif
- while (status & OHCI_CNTL_DMA_ACTIVE) {
len = dbch->xferq.psize - resCount;
ld = (uint8_t *)db_tr->buf;
if (dbch->pdb_tr == NULL) {
@@ -2783,8 +2793,9 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
ld += rlen;
len -= rlen;
hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
- if (hlen < 0) {
- printf("hlen < 0 shouldn't happen");
+ if (hlen <= 0) {
+ printf("hlen should be positive.");
+ goto err;
}
offset = sizeof(pktbuf);
vec[0].iov_base = (char *)&pktbuf;
@@ -2802,16 +2813,16 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
fp=(struct fw_pkt *)ld;
hlen = fwohci_arcv_swap(fp, len);
if (hlen == 0)
- /* XXX need reset */
- goto out;
+ goto err;
if (hlen < 0) {
dbch->pdb_tr = db_tr;
dbch->buf_offset = - dbch->buf_offset;
/* sanity check */
- if (resCount != 0)
- printf("resCount = %d !?\n",
- resCount);
- /* XXX clear pdb_tr */
+ if (resCount != 0) {
+ printf("resCount=%d hlen=%d\n",
+ resCount, hlen);
+ goto err;
+ }
goto out;
}
offset = 0;
@@ -2823,8 +2834,7 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
= sizeof(fw_pkt) so this shouldn't happens */
printf("plen(%d) is negative! offset=%d\n",
plen, offset);
- /* XXX clear pdb_tr */
- goto out;
+ goto err;
}
if (plen > 0) {
len -= plen;
@@ -2833,10 +2843,12 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
if (firewire_debug)
printf("splitted payload\n");
/* sanity check */
- if (resCount != 0)
- printf("resCount = %d !?\n",
- resCount);
- /* XXX clear pdb_tr */
+ if (resCount != 0) {
+ printf("resCount=%d plen=%d"
+ " len=%d\n",
+ resCount, plen, len);
+ goto err;
+ }
goto out;
}
vec[nvec].iov_base = ld;
@@ -2849,18 +2861,14 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
printf("nvec == 0\n");
/* DMA result-code will be written at the tail of packet */
-#if BYTE_ORDER == BIG_ENDIAN
- stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16;
-#else
- stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
-#endif
+ stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer)));
#if 0
printf("plen: %d, stat %x\n",
plen ,stat);
#endif
- spd = (stat >> 5) & 0x3;
- stat &= 0x1f;
- switch(stat){
+ spd = (stat >> 21) & 0x3;
+ event = (stat >> 16) & 0x1f;
+ switch (event) {
case FWOHCIEV_ACKPEND:
#if 0
printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
@@ -2885,15 +2893,23 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
printf("got BUSRST packet!?\n");
break;
default:
- device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]);
-#if 0 /* XXX */
- goto out;
+ device_printf(sc->fc.dev,
+ "Async DMA Receive error err=%02x %s"
+ " plen=%d offset=%d len=%d status=0x%08x"
+ " tcode=0x%x, stat=0x%08x\n",
+ event, fwohcicode[event], plen,
+ dbch->buf_offset, len,
+ OREAD(sc, OHCI_DMACTL(off)),
+ fp->mode.common.tcode, stat);
+#if 1 /* XXX */
+ goto err;
#endif
break;
}
pcnt ++;
if (dbch->pdb_tr != NULL) {
- fwohci_arcv_free_buf(dbch, dbch->pdb_tr);
+ fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr,
+ off, 1);
dbch->pdb_tr = NULL;
}
@@ -2902,7 +2918,7 @@ out:
if (resCount == 0) {
/* done on this buffer */
if (dbch->pdb_tr == NULL) {
- fwohci_arcv_free_buf(dbch, db_tr);
+ fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1);
dbch->buf_offset = 0;
} else
if (dbch->pdb_tr != db_tr)
@@ -2925,4 +2941,24 @@ out:
printf("fwohci_arcv: no packets\n");
#endif
splx(s);
+ return;
+
+err:
+ device_printf(sc->fc.dev, "AR DMA status=%x, ",
+ OREAD(sc, OHCI_DMACTL(off)));
+ dbch->pdb_tr = NULL;
+ /* skip until resCount != 0 */
+ printf(" skip buffer");
+ while (resCount == 0) {
+ printf(" #");
+ fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0);
+ db_tr = STAILQ_NEXT(db_tr, link);
+ resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
+ & OHCI_COUNT_MASK;
+ } while (resCount == 0)
+ printf(" done\n");
+ dbch->top = db_tr;
+ dbch->buf_offset = dbch->xferq.psize - resCount;
+ OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
+ splx(s);
}
diff --git a/sys/dev/firewire/fwohcireg.h b/sys/dev/firewire/fwohcireg.h
index 2cccb25..32b029c 100644
--- a/sys/dev/firewire/fwohcireg.h
+++ b/sys/dev/firewire/fwohcireg.h
@@ -396,8 +396,13 @@ struct fwohci_txpkthdr{
}mode;
};
struct fwohci_trailer{
+#if BYTE_ORDER == BIG_ENDIAN
+ uint32_t stat:16,
+ time:16;
+#else
uint32_t time:16,
stat:16;
+#endif
};
#define OHCI_CNTL_CYCSRC (0x1 << 22)
OpenPOWER on IntegriCloud