summaryrefslogtreecommitdiffstats
path: root/sys/dev/firewire/fwohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/firewire/fwohci.c')
-rw-r--r--sys/dev/firewire/fwohci.c495
1 files changed, 252 insertions, 243 deletions
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;
OpenPOWER on IntegriCloud