summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/firewire/firewire.c467
-rw-r--r--sys/dev/firewire/firewire.h263
-rw-r--r--sys/dev/firewire/firewire_phy.h2
-rw-r--r--sys/dev/firewire/firewirereg.h94
-rw-r--r--sys/dev/firewire/fwcrom.c265
-rw-r--r--sys/dev/firewire/fwdev.c377
-rw-r--r--sys/dev/firewire/fwdma.c208
-rw-r--r--sys/dev/firewire/fwdma.h116
-rw-r--r--sys/dev/firewire/fwmem.c72
-rw-r--r--sys/dev/firewire/fwmem.h2
-rw-r--r--sys/dev/firewire/fwohci.c1565
-rw-r--r--sys/dev/firewire/fwohci_pci.c77
-rw-r--r--sys/dev/firewire/fwohcireg.h155
-rw-r--r--sys/dev/firewire/fwohcivar.h39
-rw-r--r--sys/dev/firewire/iec13213.h130
-rw-r--r--sys/dev/firewire/iec68113.h53
-rw-r--r--sys/dev/firewire/if_fwe.c97
-rw-r--r--sys/dev/firewire/if_fwevar.h2
-rw-r--r--sys/dev/firewire/sbp.c632
-rw-r--r--sys/modules/firewire/Makefile.inc1
-rw-r--r--sys/modules/firewire/firewire/Makefile2
-rw-r--r--sys/modules/firewire/fwe/Makefile1
-rw-r--r--usr.sbin/fwcontrol/fwcontrol.c26
-rw-r--r--usr.sbin/fwcontrol/fwcrom.c259
-rw-r--r--usr.sbin/fwcontrol/fwdv.c6
25 files changed, 2755 insertions, 2156 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
index dc10d3b..500ab51 100644
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -44,13 +45,13 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
-#include <sys/uio.h>
#include <sys/sysctl.h>
#include <machine/cpufunc.h> /* for rdtsc proto for clock.h below */
#include <machine/clock.h>
#include <sys/bus.h> /* used by smbus and newbus */
+#include <machine/bus.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
@@ -71,8 +72,6 @@ MALLOC_DEFINE(M_FWXFER, "fw_xfer", "XFER/FireWire");
#define FW_MAXASYRTY 4
#define FW_MAXDEVRCNT 4
-#define XFER_TIMEOUT 0
-
devclass_t firewire_devclass;
static int firewire_match __P((device_t));
@@ -202,9 +201,9 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
xferq = fc->ats;
len = info->hdr_len;
if (info->flag & FWTI_BLOCK_STR)
- len += ntohs(fp->mode.stream.len);
+ len += fp->mode.stream.len;
else if (info->flag & FWTI_BLOCK_ASY)
- len += ntohs(fp->mode.rresb.len);
+ len += fp->mode.rresb.len;
if( len > xfer->send.len ){
printf("len(%d) > send.len(%d) (tcode=%d)\n",
len, xfer->send.len, tcode);
@@ -230,11 +229,9 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
}
xfer->tl = tl;
- xfer->tcode = tcode;
xfer->resp = 0;
xfer->fc = fc;
xfer->q = xferq;
- xfer->act_type = FWACT_XFER;
xfer->retry_req = fw_asybusy;
fw_asystart(xfer);
@@ -252,12 +249,7 @@ fw_asy_callback(struct fw_xfer *xfer){
* Postpone to later retry.
*/
void fw_asybusy(struct fw_xfer *xfer){
-#if 1
printf("fw_asybusy\n");
-#endif
-#if XFER_TIMEOUT
- untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
-#endif
/*
xfer->ch = timeout((timeout_t *)fw_asystart, (void *)xfer, 20000);
*/
@@ -265,24 +257,7 @@ void fw_asybusy(struct fw_xfer *xfer){
fw_asystart(xfer);
return;
}
-#if XFER_TIMEOUT
-/*
- * Post timeout for async. request.
- */
-void
-fw_xfer_timeout(void *arg)
-{
- int s;
- struct fw_xfer *xfer;
- xfer = (struct fw_xfer *)arg;
- printf("fw_xfer_timeout status=%d resp=%d\n", xfer->state, xfer->resp);
- /* XXX set error code */
- s = splfw();
- xfer->act.hand(xfer);
- splx(s);
-}
-#endif
/*
* Async. request with given xfer structure.
*/
@@ -292,6 +267,7 @@ fw_asystart(struct fw_xfer *xfer)
struct firewire_comm *fc = xfer->fc;
int s;
if(xfer->retry++ >= fc->max_asyretry){
+ device_printf(fc->bdev, "max_asyretry exceeded\n");
xfer->resp = EBUSY;
xfer->state = FWXF_BUSY;
xfer->act.hand(xfer);
@@ -314,10 +290,6 @@ fw_asystart(struct fw_xfer *xfer)
/* XXX just queue for mbuf */
if (xfer->mbuf == NULL)
xfer->q->start(fc);
-#if XFER_TIMEOUT
- if (xfer->act.hand != NULL)
- xfer->ch = timeout(fw_xfer_timeout, (void *)xfer, hz);
-#endif
return;
}
@@ -355,15 +327,7 @@ firewire_xfer_timeout(struct firewire_comm *fc)
xfer->dst, i);
xfer->resp = ETIMEDOUT;
STAILQ_REMOVE_HEAD(&fc->tlabels[i], link);
- switch (xfer->act_type) {
- case FWACT_XFER:
- fw_xfer_done(xfer);
- break;
- default:
- /* ??? */
- fw_xfer_free(xfer);
- break;
- }
+ fw_xfer_done(xfer);
}
}
splx(s);
@@ -437,10 +401,8 @@ firewire_attach( device_t dev )
/* launch attachement of the added children */
bus_generic_attach(dev);
-#if 1
/* bus_reset */
fc->ibr(fc);
-#endif
return 0;
}
@@ -524,15 +486,7 @@ fw_xferq_drain(struct fw_xferq *xferq)
STAILQ_REMOVE_HEAD(&xferq->q, link);
xferq->queued --;
xfer->resp = EAGAIN;
- switch (xfer->act_type) {
- case FWACT_XFER:
- fw_xfer_done(xfer);
- break;
- default:
- /* ??? */
- fw_xfer_free(xfer);
- break;
- }
+ fw_xfer_done(xfer);
}
}
@@ -553,6 +507,9 @@ fw_drain_txq(struct firewire_comm *fc)
void
fw_busreset(struct firewire_comm *fc)
{
+ struct firewire_dev_comm *fdc;
+ device_t *devlistp;
+ int devcnt;
int i;
switch(fc->status){
@@ -601,6 +558,16 @@ fw_busreset(struct firewire_comm *fc)
CSRARC(fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 );
CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
+
+ if (device_get_children(fc->bdev, &devlistp, &devcnt) == 0) {
+ for( i = 0 ; i < devcnt ; i++)
+ if (device_get_state(devlistp[i]) >= DS_ATTACHED) {
+ fdc = device_get_softc(devlistp[i]);
+ if (fdc->post_busreset != NULL)
+ fdc->post_busreset(fdc);
+ }
+ free(devlistp, M_TEMP);
+ }
}
/* Call once after reboot */
@@ -620,21 +587,15 @@ void fw_init(struct firewire_comm *fc)
fc->atq->queued = 0;
fc->ats->queued = 0;
- fc->arq->psize = PAGE_SIZE;
- fc->ars->psize = PAGE_SIZE;
- fc->atq->psize = 0;
- fc->ats->psize = 0;
-
-
fc->arq->buf = NULL;
fc->ars->buf = NULL;
fc->atq->buf = NULL;
fc->ats->buf = NULL;
- fc->arq->flag = FWXFERQ_PACKET;
- fc->ars->flag = FWXFERQ_PACKET;
- fc->atq->flag = FWXFERQ_PACKET;
- fc->ats->flag = FWXFERQ_PACKET;
+ fc->arq->flag = 0;
+ fc->ars->flag = 0;
+ fc->atq->flag = 0;
+ fc->ats->flag = 0;
STAILQ_INIT(&fc->atq->q);
STAILQ_INIT(&fc->ats->q);
@@ -723,7 +684,6 @@ void fw_init(struct firewire_comm *fc)
fw_xfer_free(xfer);
}
xfer->act.hand = fw_vmaccess;
- xfer->act_type = FWACT_XFER;
xfer->fc = fc;
xfer->sc = NULL;
@@ -744,7 +704,7 @@ fw_bindlookup(struct firewire_comm *fc, u_int32_t dest_hi, u_int32_t dest_lo)
struct fw_bind *tfw;
for(tfw = STAILQ_FIRST(&fc->binds) ; tfw != NULL ;
tfw = STAILQ_NEXT(tfw, fclist)){
- if(tfw->xfer->act_type != FWACT_NULL &&
+ if (tfw->act_type != FWACT_NULL &&
tfw->start_hi == dest_hi &&
tfw->start_lo <= dest_lo &&
(tfw->start_lo + tfw->addrlen) > dest_lo){
@@ -796,9 +756,8 @@ fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
STAILQ_INSERT_TAIL(&fc->binds, fwb, fclist);
}
out:
- if(!err && fwb->xfer->act_type == FWACT_CH){
- STAILQ_INSERT_HEAD(&fc->ir[fwb->xfer->sub]->binds, fwb, chlist);
- }
+ if (!err && fwb->act_type == FWACT_CH)
+ STAILQ_INSERT_HEAD(&fc->ir[fwb->sub]->binds, fwb, chlist);
return err;
}
@@ -809,14 +768,19 @@ int
fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
{
int s;
+ struct fw_xfer *xfer, *next;
s = splfw();
/* shall we check the existance? */
STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
- splx(s);
- if (fwb->xfer)
- fw_xfer_free(fwb->xfer);
+ /* shall we do this? */
+ for (xfer = STAILQ_FIRST(&fwb->xferlist); xfer != NULL; xfer = next) {
+ next = STAILQ_NEXT(xfer, link);
+ fw_xfer_free(xfer);
+ }
+ STAILQ_INIT(&fwb->xferlist);
+ splx(s);
return 0;
}
@@ -881,12 +845,40 @@ fw_xfer_alloc(struct malloc_type *type)
return xfer;
microtime(&xfer->tv);
- xfer->sub = -1;
xfer->malloc = type;
return xfer;
}
+struct fw_xfer *
+fw_xfer_alloc_buf(struct malloc_type *type, int send_len, int recv_len)
+{
+ struct fw_xfer *xfer;
+
+ xfer = fw_xfer_alloc(type);
+ xfer->send.len = send_len;
+ xfer->recv.len = recv_len;
+ if (xfer == NULL)
+ return(NULL);
+ if (send_len) {
+ xfer->send.buf = malloc(send_len, type, M_NOWAIT | M_ZERO);
+ if (xfer->send.buf == NULL) {
+ fw_xfer_free(xfer);
+ return(NULL);
+ }
+ }
+ if (recv_len) {
+ xfer->recv.buf = malloc(recv_len, type, M_NOWAIT);
+ if (xfer->recv.buf == NULL) {
+ if (xfer->send.buf != NULL)
+ free(xfer->send.buf, type);
+ fw_xfer_free(xfer);
+ return(NULL);
+ }
+ }
+ return(xfer);
+}
+
/*
* IEEE1394 XFER post process.
*/
@@ -896,10 +888,6 @@ fw_xfer_done(struct fw_xfer *xfer)
if (xfer->act.hand == NULL)
return;
-#if XFER_TIMEOUT
- untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
-#endif
-
if (xfer->fc->status != FWBUSRESET)
xfer->act.hand(xfer);
else {
@@ -911,13 +899,11 @@ fw_xfer_done(struct fw_xfer *xfer)
}
}
-/*
- * To free IEEE1394 XFER structure.
- */
void
-fw_xfer_free( struct fw_xfer* xfer)
+fw_xfer_unload(struct fw_xfer* xfer)
{
int s;
+
if(xfer == NULL ) return;
if(xfer->state == FWXF_INQ){
printf("fw_xfer_free FWXF_INQ\n");
@@ -926,24 +912,30 @@ fw_xfer_free( struct fw_xfer* xfer)
xfer->q->queued --;
splx(s);
}
- if(xfer->fc != NULL){
- if(xfer->state == FWXF_START){
-#if 0 /* this could happen if we call fwohci_arcv() before fwohci_txd() */
- printf("fw_xfer_free FWXF_START\n");
+ if (xfer->fc != NULL) {
+#if 1 /* this could happen if we call fwohci_arcv() before fwohci_txd() */
+ if(xfer->state == FWXF_START)
+ panic("fw_xfer_free FWXF_START\n");
#endif
- s = splfw();
- xfer->q->drain(xfer->fc, xfer);
- splx(s);
- }
+ fw_tl_free(xfer->fc, xfer);
}
+ xfer->state = FWXF_INIT;
+ xfer->resp = 0;
+ xfer->retry = 0;
+}
+/*
+ * To free IEEE1394 XFER structure.
+ */
+void
+fw_xfer_free( struct fw_xfer* xfer)
+{
+ if(xfer == NULL ) return;
+ fw_xfer_unload(xfer);
if(xfer->send.buf != NULL){
- free(xfer->send.buf, M_FW);
+ free(xfer->send.buf, xfer->malloc);
}
if(xfer->recv.buf != NULL){
- free(xfer->recv.buf, M_FW);
- }
- if(xfer->fc != NULL){
- fw_tl_free(xfer->fc, xfer);
+ free(xfer->recv.buf, xfer->malloc);
}
free(xfer, xfer->malloc);
}
@@ -969,24 +961,19 @@ fw_phy_config(struct firewire_comm *fc, int root_node, int gap_count)
fc->status = FWBUSPHYCONF;
-#if 0
- DELAY(100000);
-#endif
- xfer = fw_xfer_alloc(M_FWXFER);
- xfer->send.len = 12;
- xfer->send.off = 0;
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 12, 0);
+ if (xfer == NULL)
+ return;
xfer->fc = fc;
xfer->retry_req = fw_asybusy;
xfer->act.hand = fw_asy_callback_free;
- xfer->send.buf = malloc(sizeof(u_int32_t),
- M_FW, M_NOWAIT | M_ZERO);
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.ld[1] = 0;
if (root_node >= 0)
- fp->mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
+ fp->mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
if (gap_count >= 0)
- fp->mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
+ fp->mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
fp->mode.ld[2] = ~fp->mode.ld[1];
/* XXX Dangerous, how to pass PHY packet to device driver */
fp->mode.common.tcode |= FWTCODE_PHY;
@@ -1018,9 +1005,9 @@ fw_print_sid(u_int32_t sid)
/*
* To receive self ID.
*/
-void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
+void fw_sidrcv(struct firewire_comm* fc, u_int32_t *sid, u_int len)
{
- u_int32_t *p, *sid = (u_int32_t *)(buf + off);
+ u_int32_t *p;
union fw_self_id *self_id;
u_int i, j, node, c_port = 0, i_branch = 0;
@@ -1103,9 +1090,7 @@ void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
bcopy(p, &CSRARC(fc, SPED_MAP + 8), (fc->speed_map->crc_len - 1)*4);
fc->max_hop = fc->max_node - i_branch;
-#if 1
printf(", maxhop <= %d", fc->max_hop);
-#endif
if(fc->irm == -1 ){
printf(", Not found IRM capable node");
@@ -1132,7 +1117,6 @@ void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
CSRARC(fc, BUS_MGR_ID));
#endif
}
- free(buf, M_FW);
if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){
/* I am BMGR */
fw_bmr(fc);
@@ -1240,12 +1224,7 @@ loop:
fwdev->dst = fc->ongonode;
fwdev->eui.hi = fc->ongoeui.hi; fwdev->eui.lo = fc->ongoeui.lo;
fwdev->status = FWDEVINIT;
-#if 0
- fwdev->speed = CSRARC(fc, SPED_MAP + 8 + fc->ongonode / 4)
- >> ((3 - (fc->ongonode % 4)) * 8);
-#else
fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode];
-#endif
pfwdev = NULL;
STAILQ_FOREACH(tfwdev, &fc->devices, link) {
@@ -1276,28 +1255,20 @@ loop:
fw_bus_explore_callback);
if(xfer == NULL) goto done;
#else
- xfer = fw_xfer_alloc(M_FWXFER);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16);
if(xfer == NULL){
goto done;
}
- xfer->send.len = 16;
xfer->spd = 0;
- xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- fw_xfer_free( xfer);
- return;
- }
-
- xfer->send.off = 0;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.rreqq.dest_hi = htons(0xffff);
+ fp->mode.rreqq.dest_hi = 0xffff;
fp->mode.rreqq.tlrt = 0;
fp->mode.rreqq.tcode = FWTCODE_RREQQ;
fp->mode.rreqq.pri = 0;
fp->mode.rreqq.src = 0;
xfer->dst = FWLOCALBUS | fc->ongonode;
- fp->mode.rreqq.dst = htons(xfer->dst);
- fp->mode.rreqq.dest_lo = htonl(addr);
+ fp->mode.rreqq.dst = xfer->dst;
+ fp->mode.rreqq.dest_lo = addr;
xfer->act.hand = fw_bus_explore_callback;
if (firewire_debug)
@@ -1330,21 +1301,13 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
struct fw_pkt *fp;
int err;
- xfer = fw_xfer_alloc(M_FWXFER);
- if(xfer == NULL){
- return NULL;
- }
- xfer->send.len = 16;
- xfer->spd = spd; /* XXX:min(spd, fc->spd) */
- xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- fw_xfer_free( xfer);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16);
+ if (xfer == NULL)
return NULL;
- }
- xfer->send.off = 0;
+ xfer->spd = spd; /* XXX:min(spd, fc->spd) */
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.rreqq.dest_hi = htons(addr_hi & 0xffff);
+ fp->mode.rreqq.dest_hi = addr_hi & 0xffff;
if(tl & FWP_TL_VALID){
fp->mode.rreqq.tlrt = (tl & 0x3f) << 2;
}else{
@@ -1355,8 +1318,8 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
fp->mode.rreqq.pri = 0;
fp->mode.rreqq.src = 0;
xfer->dst = addr_hi >> 16;
- fp->mode.rreqq.dst = htons(xfer->dst);
- fp->mode.rreqq.dest_lo = htonl(addr_lo);
+ fp->mode.rreqq.dst = xfer->dst;
+ fp->mode.rreqq.dest_lo = addr_lo;
xfer->act.hand = hand;
err = fw_asyreq(fc, -1, xfer);
@@ -1420,14 +1383,14 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
qld = (u_int32_t *)xfer->recv.buf;
printf("len:%d\n", xfer->recv.len);
for( i = 0 ; i <= xfer->recv.len && i < 32; i+= 4){
- printf("0x%08x ", ntohl(rfp->mode.ld[i/4]));
+ printf("0x%08x ", rfp->mode.ld[i/4]);
if((i % 16) == 15) printf("\n");
}
if((i % 16) != 15) printf("\n");
}
#endif
if(fc->ongodev == NULL){
- if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 | CSRROMOFF))){
+ if(sfp->mode.rreqq.dest_lo == (0xf0000000 | CSRROMOFF)){
rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data);
chdr = (struct csrhdr *)(&rfp->mode.rresq.data);
/* If CSR is minimal confinguration, more investgation is not needed. */
@@ -1439,10 +1402,10 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
}else{
fc->ongoaddr = CSRROMOFF + 0xc;
}
- }else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0xc)))){
+ }else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0xc))){
fc->ongoeui.hi = ntohl(rfp->mode.rresq.data);
fc->ongoaddr = CSRROMOFF + 0x10;
- }else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0x10)))){
+ }else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0x10))){
fc->ongoeui.lo = ntohl(rfp->mode.rresq.data);
if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0) {
if (firewire_debug)
@@ -1701,17 +1664,42 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
return(-1);
}
+static void
+fw_rcv_copy(struct fw_xfer *xfer, struct iovec *vec, int nvec)
+{
+ char *p;
+ int res, i, len;
+
+ p = xfer->recv.buf;
+ res = xfer->recv.len;
+ for (i = 0; i < nvec; i++, vec++) {
+ len = vec->iov_len;
+ if (res < len) {
+ printf("rcv buffer(%d) is %d bytes short.\n",
+ xfer->recv.len, len - res);
+ len = res;
+ }
+ bcopy(vec->iov_base, p, len);
+ p += len;
+ res -= len;
+ if (res <= 0)
+ break;
+ }
+ xfer->recv.len -= res;
+}
+
/*
* Generic packet receving process.
*/
void
-fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u_int spd)
+fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int spd)
{
struct fw_pkt *fp, *resfp;
struct fw_xfer *xfer;
struct fw_bind *bind;
struct firewire_softc *sc;
- int s;
+ int tcode, s;
+ int i, len, oldstate;
#if 0
{
u_int32_t *qld;
@@ -1725,25 +1713,37 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
if((i % 16) != 15) printf("\n");
}
#endif
- fp = (struct fw_pkt *)(buf + off);
- switch(fp->mode.common.tcode){
+ fp = (struct fw_pkt *)vec[0].iov_base;
+ tcode = fp->mode.common.tcode;
+#if 0 /* XXX this check is not valid for RRESQ and WREQQ */
+ if (vec[0].iov_len < fc->tcode[tcode].hdr_len) {
+#if __FreeBSD_version >= 500000
+ printf("fw_rcv: iov_len(%zu) is less than"
+#else
+ printf("fw_rcv: iov_len(%u) is less than"
+#endif
+ " hdr_len(%d:tcode=%d)\n", vec[0].iov_len,
+ fc->tcode[tcode].hdr_len, tcode);
+ }
+#endif
+ switch (tcode) {
case FWTCODE_WRES:
case FWTCODE_RRESQ:
case FWTCODE_RRESB:
case FWTCODE_LRES:
- xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
+ xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
fp->mode.hdr.tlrt >> 2);
if(xfer == NULL) {
printf("fw_rcv: unknown response "
"tcode=%d src=0x%x tl=0x%x rt=%d data=0x%x\n",
- fp->mode.common.tcode,
- ntohs(fp->mode.hdr.src),
+ tcode,
+ fp->mode.hdr.src,
fp->mode.hdr.tlrt >> 2,
fp->mode.hdr.tlrt & 3,
fp->mode.rresq.data);
#if 1
printf("try ad-hoc work around!!\n");
- xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
+ xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
(fp->mode.hdr.tlrt >> 2)^3);
if (xfer == NULL) {
printf("no use...\n");
@@ -1753,56 +1753,48 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
goto err;
#endif
}
- switch(xfer->act_type){
- case FWACT_XFER:
- if((xfer->sub >= 0) &&
- ((fc->ir[xfer->sub]->flag & FWXFERQ_MODEMASK ) == 0)){
- xfer->resp = EINVAL;
- fw_xfer_done(xfer);
- goto err;
- }
- xfer->recv.len = len;
- xfer->recv.off = off;
- xfer->recv.buf = buf;
- xfer->resp = 0;
+ fw_rcv_copy(xfer, vec, nvec);
+ xfer->resp = 0;
+ /* make sure the packet is drained in AT queue */
+ oldstate = xfer->state;
+ xfer->state = FWXF_RCVD;
+ switch (oldstate) {
+ case FWXF_SENT:
fw_xfer_done(xfer);
- return;
break;
- case FWACT_CH:
- default:
- goto err;
+ case FWXF_START:
+ if (firewire_debug)
+ printf("not sent yet\n");
break;
+ default:
+ printf("unexpected state %d\n", xfer->state);
}
- break;
+ return;
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
case FWTCODE_RREQQ:
case FWTCODE_RREQB:
case FWTCODE_LREQ:
- bind = fw_bindlookup(fc, ntohs(fp->mode.rreqq.dest_hi),
- ntohl(fp->mode.rreqq.dest_lo));
+ bind = fw_bindlookup(fc, fp->mode.rreqq.dest_hi,
+ fp->mode.rreqq.dest_lo);
if(bind == NULL){
-#if __FreeBSD_version >= 500000
- printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n src=0x%x",
-#else
- printf("Unknown service addr 0x%08x:0x%08lx tcode=%x src=0x%x\n",
-#endif
- ntohs(fp->mode.rreqq.dest_hi),
- ntohl(fp->mode.rreqq.dest_lo),
- fp->mode.common.tcode,
- fp->mode.hdr.src);
+ printf("Unknown service addr 0x%08x:0x%08x tcode=%x src=0x%x data=%x\n",
+ fp->mode.wreqq.dest_hi,
+ fp->mode.wreqq.dest_lo,
+ tcode,
+ fp->mode.hdr.src,
+ ntohl(fp->mode.wreqq.data));
if (fc->status == FWBUSRESET) {
printf("fw_rcv: cannot respond(bus reset)!\n");
goto err;
}
- xfer = fw_xfer_alloc(M_FWXFER);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 0);
if(xfer == NULL){
return;
}
xfer->spd = spd;
- xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
resfp = (struct fw_pkt *)xfer->send.buf;
- switch(fp->mode.common.tcode){
+ switch (tcode) {
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
resfp->mode.hdr.tcode = FWTCODE_WRES;
@@ -1837,17 +1829,20 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
}
goto err;
}
- switch(bind->xfer->act_type){
+ len = 0;
+ for (i = 0; i < nvec; i ++)
+ len += vec[i].iov_len;
+ switch(bind->act_type){
case FWACT_XFER:
- xfer = fw_xfer_alloc(M_FWXFER);
- if(xfer == NULL) goto err;
- xfer->fc = bind->xfer->fc;
- xfer->sc = bind->xfer->sc;
- xfer->recv.buf = buf;
- xfer->recv.len = len;
- xfer->recv.off = off;
+ /* splfw()?? */
+ xfer = STAILQ_FIRST(&bind->xferlist);
+ if (xfer == NULL) {
+ printf("Discard a packet for this bind.\n");
+ goto err;
+ }
+ STAILQ_REMOVE_HEAD(&bind->xferlist, link);
+ fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
- xfer->act.hand = bind->xfer->act.hand;
if (fc->status != FWBUSRESET)
xfer->act.hand(xfer);
else
@@ -1855,26 +1850,28 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
return;
break;
case FWACT_CH:
- if(fc->ir[bind->xfer->sub]->queued >=
- fc->ir[bind->xfer->sub]->maxq){
+ if(fc->ir[bind->sub]->queued >=
+ fc->ir[bind->sub]->maxq){
device_printf(fc->bdev,
"Discard a packet %x %d\n",
- bind->xfer->sub,
- fc->ir[bind->xfer->sub]->queued);
+ bind->sub,
+ fc->ir[bind->sub]->queued);
goto err;
}
- xfer = fw_xfer_alloc(M_FWXFER);
- if(xfer == NULL) goto err;
- xfer->recv.buf = buf;
- xfer->recv.len = len;
- xfer->recv.off = off;
+ xfer = STAILQ_FIRST(&bind->xferlist);
+ if (xfer == NULL) {
+ printf("Discard packet for this bind\n");
+ goto err;
+ }
+ STAILQ_REMOVE_HEAD(&bind->xferlist, link);
+ fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
s = splfw();
- fc->ir[bind->xfer->sub]->queued++;
- STAILQ_INSERT_TAIL(&fc->ir[bind->xfer->sub]->q, xfer, link);
+ fc->ir[bind->sub]->queued++;
+ STAILQ_INSERT_TAIL(&fc->ir[bind->sub]->q, xfer, link);
splx(s);
- wakeup((caddr_t)fc->ir[bind->xfer->sub]);
+ wakeup((caddr_t)fc->ir[bind->sub]);
return;
break;
@@ -1896,11 +1893,12 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
printf("receive queue is full\n");
goto err;
}
- xfer = fw_xfer_alloc(M_FWXFER);
+ /* XXX get xfer from xfer queue, we don't need copy for
+ per packet mode */
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */
+ vec[0].iov_len);
if(xfer == NULL) goto err;
- xfer->recv.buf = buf;
- xfer->recv.len = len;
- xfer->recv.off = off;
+ fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
s = splfw();
xferq->queued++;
@@ -1924,11 +1922,11 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
break;
}
default:
- printf("fw_rcv: unknow tcode\n");
+ printf("fw_rcv: unknow tcode %d\n", tcode);
break;
}
err:
- free(buf, M_FW);
+ return;
}
/*
@@ -1971,6 +1969,7 @@ error:
fw_xfer_free(xfer);
}
+
/*
* To candidate Bus Manager election process.
*/
@@ -1982,35 +1981,26 @@ fw_try_bmr(void *arg)
struct fw_pkt *fp;
int err = 0;
- xfer = fw_xfer_alloc(M_FWXFER);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, 24, 20);
if(xfer == NULL){
return;
}
- xfer->send.len = 24;
xfer->spd = 0;
- xfer->send.buf = malloc(24, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- fw_xfer_free( xfer);
- return;
- }
-
fc->status = FWBUSMGRELECT;
- xfer->send.off = 0;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.lreq.dest_hi = htons(0xffff);
+ fp->mode.lreq.dest_hi = 0xffff;
fp->mode.lreq.tlrt = 0;
fp->mode.lreq.tcode = FWTCODE_LREQ;
fp->mode.lreq.pri = 0;
fp->mode.lreq.src = 0;
- fp->mode.lreq.len = htons(8);
- fp->mode.lreq.extcode = htons(FW_LREQ_CMPSWAP);
+ fp->mode.lreq.len = 8;
+ fp->mode.lreq.extcode = FW_LREQ_CMPSWAP;
xfer->dst = FWLOCALBUS | fc->irm;
- fp->mode.lreq.dst = htons(xfer->dst);
- fp->mode.lreq.dest_lo = htonl(0xf0000000 | BUS_MGR_ID);
+ fp->mode.lreq.dst = xfer->dst;
+ fp->mode.lreq.dest_lo = 0xf0000000 | BUS_MGR_ID;
fp->mode.lreq.payload[0] = htonl(0x3f);
fp->mode.lreq.payload[1] = htonl(fc->nodeid);
- xfer->act_type = FWACT_XFER;
xfer->act.hand = fw_try_bmr_callback;
err = fw_asyreq(fc, -1, xfer);
@@ -2029,10 +2019,10 @@ fw_try_bmr(void *arg)
static void
fw_vmaccess(struct fw_xfer *xfer){
struct fw_pkt *rfp, *sfp = NULL;
- u_int32_t *ld = (u_int32_t *)(xfer->recv.buf + xfer->recv.off);
+ u_int32_t *ld = (u_int32_t *)xfer->recv.buf;
- printf("vmaccess spd:%2x len:%03x %d data:%08x %08x %08x %08x\n",
- xfer->spd, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
+ printf("vmaccess spd:%2x len:%03x data:%08x %08x %08x %08x\n",
+ xfer->spd, xfer->recv.len, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
printf("vmaccess data:%08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
if(xfer->resp != 0){
fw_xfer_free( xfer);
@@ -2084,7 +2074,6 @@ fw_vmaccess(struct fw_xfer *xfer){
fw_xfer_free( xfer);
return;
}
- xfer->send.off = 0;
sfp->mode.hdr.dst = rfp->mode.hdr.src;
xfer->dst = ntohs(rfp->mode.hdr.src);
xfer->act.hand = fw_xfer_free;
@@ -2121,17 +2110,25 @@ static int
fw_bmr(struct firewire_comm *fc)
{
struct fw_device fwdev;
+ union fw_self_id *self_id;
int cmstr;
- /* XXX Assume that the current root node is cycle master capable */
- cmstr = fc->max_node;
+ /* Check to see if the current root node is cycle master capable */
+ self_id = &fc->topology_map->self_id[fc->max_node];
+ if (fc->max_node > 0) {
+ if (self_id->p0.contender)
+ cmstr = fc->max_node;
+ else
+ /* XXX shall we be cycle master? */
+ cmstr = fc->nodeid;
+ /* XXX bus reset? */
+ } else
+ cmstr = -1;
/* If I am the bus manager, optimize gapcount */
- if(fc->max_hop <= MAX_GAPHOP ){
- fw_phy_config(fc, (fc->max_node > 0)?cmstr:-1,
- gap_cnt[fc->max_hop]);
- }
+ if(fc->max_hop <= MAX_GAPHOP )
+ fw_phy_config(fc, cmstr, gap_cnt[fc->max_hop]);
/* If we are the cycle master, nothing to do */
- if (cmstr == fc->nodeid)
+ if (cmstr == fc->nodeid || cmstr == -1)
return 0;
/* Bus probe has not finished, make dummy fwdev for cmstr */
bzero(&fwdev, sizeof(fwdev));
diff --git a/sys/dev/firewire/firewire.h b/sys/dev/firewire/firewire.h
index 1f1e07b..f90596f 100644
--- a/sys/dev/firewire/firewire.h
+++ b/sys/dev/firewire/firewire.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -40,29 +41,6 @@
#define DEV_DEF 0
#define DEV_DV 2
-#if 0
-struct dv_data{
- u_int32_t n_write;
- u_int32_t a_write;
- u_int32_t k_write;
- u_int32_t write_done;
- u_int32_t write_len[16];
- u_int32_t write_off[16];
- u_int32_t n_read;
- u_int32_t a_read;
- u_int32_t k_read;
- u_int32_t read_done;
- u_int32_t read_len[16];
- u_int32_t read_off[16];
-};
-
-struct dv_data_req_t {
- unsigned long index;
- unsigned long len;
- unsigned long off;
-};
-#endif
-
struct fw_isochreq {
unsigned char ch:6,
tag:2;
@@ -93,7 +71,7 @@ struct fw_reg_req_t {
#define MAXREC(x) (2 << (x))
#define FWPMAX_S400 (2048 + 20) /* MAXREC plus space for control data */
-#define FWMAXQUEUE 256
+#define FWMAXQUEUE 64
#define FWLOCALBUS 0xffc0
@@ -135,139 +113,83 @@ struct fw_asyhdr {
u_int32_t hdr[4];
};
-#if 0
-#define FWPHYSIDSUBS(SID) (((SID) >> 23) & 1)
-#define FWPHYSIDNODE(SID) (((SID) >> 24) & 0x3f)
-#define FWPHYSIDLINK(SID) (((SID) >> 22) & 1)
-#define FWPHYSIDGAP(SID) (((SID) >> 16) & 0x3f)
-#define FWPHYSIDSPD(SID) (((SID) >> 14) & 0x3)
-#define FWPHYSIDDEL(SID) (((SID) >> 12) & 0x3)
-#define FWPHYSIDCON(SID) (((SID) >> 11) & 1)
-#define FWPHYSIDPWR(SID) (((SID) >> 8) & 0x7)
-#define FWPHYSIDP0(SID) (((SID) >> 6) & 0x3)
-#define FWPHYSIDP1(SID) (((SID) >> 4) & 0x3)
-#define FWPHYSIDP2(SID) (((SID) >> 2) & 0x3)
-#define FWPHYSIDIR(SID) (((SID) >> 1) & 1)
-#define FWPHYSIDMORE(SID) ((SID) & 1)
-#define FWPHYSIDSEQ(SID) (((SID) >> 20) & 0x7)
-#define FWPHYSIDPA(SID) (((SID) >> 16) & 0x3)
-#define FWPHYSIDPB(SID) (((SID) >> 14) & 0x3)
-#define FWPHYSIDPC(SID) (((SID) >> 12) & 0x3)
-#define FWPHYSIDPD(SID) (((SID) >> 10) & 0x3)
-#define FWPHYSIDPE(SID) (((SID) >> 8) & 0x3)
-#define FWPHYSIDPF(SID) (((SID) >> 6) & 0x3)
-#define FWPHYSIDPG(SID) (((SID) >> 4) & 0x3)
-#define FWPHYSIDPH(SID) (((SID) >> 2) & 0x3)
+#if BYTE_ORDER == BIG_ENDIAN
+#define BIT4x2(x,y) u_int8_t x:4, y:4
+#define BIT16x2(x,y) u_int32_t x:16, y:16
+#else
+#define BIT4x2(x,y) u_int8_t y:4, x:4
+#define BIT16x2(x,y) u_int32_t y:16, x:16
+#endif
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define COMMON_HDR(a,b,c,d) u_int32_t a:16,b:8,c:4,d:4
+#define COMMON_RES(a,b,c,d) u_int32_t a:16,b:4,c:4,d:8
+#else
+#define COMMON_HDR(a,b,c,d) u_int32_t d:4,c:4,b:8,a:16
+#define COMMON_RES(a,b,c,d) u_int32_t d:8,c:4,b:4,a:16
#endif
struct fw_pkt {
union {
u_int32_t ld[0];
struct {
- u_int16_t :16;
- u_int8_t :8;
- u_int8_t :4,
- tcode:4;
+ COMMON_HDR(, , tcode, );
} common;
struct {
- u_int16_t len;
- u_int8_t chtag;
- u_int8_t sy:4,
- tcode:4;
+ COMMON_HDR(len, chtag, tcode, sy);
u_int32_t payload[0];
} stream;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, );
} hdr;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
} rreqq;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int8_t :4,
- rtcode:4;
- u_int8_t :8;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ COMMON_RES(src, rtcode, , );
u_int32_t :32;
} wres;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
- u_int16_t len;
- u_int16_t extcode:16;
+ BIT16x2(len, extcode);
} rreqb;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int32_t data;
} wreqq;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int32_t data;
} cyc;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int8_t :4,
- rtcode:4;
- u_int8_t :8;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ COMMON_RES(src, rtcode, , );
u_int32_t :32;
u_int32_t data;
} rresq;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
- u_int16_t len;
- u_int16_t extcode;
+ BIT16x2(len, extcode);
u_int32_t payload[0];
} wreqb;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int16_t dest_hi;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ BIT16x2(src, dest_hi);
u_int32_t dest_lo;
- u_int16_t len;
- u_int16_t extcode;
+ BIT16x2(len, extcode);
#define FW_LREQ_MSKSWAP 1
#define FW_LREQ_CMPSWAP 2
#define FW_LREQ_FTADD 3
@@ -277,31 +199,17 @@ struct fw_pkt {
u_int32_t payload[0];
} lreq;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int8_t :4,
- rtcode:4;
- u_int8_t :8;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ COMMON_RES(src, rtcode, , );
u_int32_t :32;
- u_int16_t len;
- u_int16_t extcode;
+ BIT16x2(len, extcode);
u_int32_t payload[0];
} rresb;
struct {
- u_int16_t dst;
- u_int8_t tlrt;
- u_int8_t pri:4,
- tcode:4;
- u_int16_t src;
- u_int8_t :4,
- rtcode:4;
- u_int8_t :8;
+ COMMON_HDR(dst, tlrt, tcode, pri);
+ COMMON_RES(src, rtcode, , );
u_int32_t :32;
- u_int16_t len;
- u_int16_t extcode;
+ BIT16x2(len, extcode);
u_int32_t payload[0];
} lres;
} mode;
@@ -352,7 +260,44 @@ struct fw_devlstreq {
#define FW_SELF_ID_PORT_CONNECTED_TO_PARENT 2
#define FW_SELF_ID_PORT_NOT_CONNECTED 1
#define FW_SELF_ID_PORT_NOT_EXISTS 0
-#if 0
+#if BYTE_ORDER == BIG_ENDIAN
+union fw_self_id {
+ struct {
+ u_int32_t id:2,
+ phy_id:6,
+ sequel:1,
+ link_active:1,
+ gap_count:6,
+ phy_speed:2,
+ phy_delay:2,
+ contender:1,
+ power_class:3,
+ port0:2,
+ port1:2,
+ port2:2,
+ initiated_reset:1,
+ more_packets:1;
+ } p0;
+ struct {
+ u_int32_t
+ id:2,
+ phy_id:6,
+ sequel:1,
+ sequence_num:3,
+ :2,
+ porta:2,
+ portb:2,
+ portc:2,
+ portd:2,
+ porte:2,
+ portf:2,
+ portg:2,
+ porth:2,
+ :1,
+ more_packets:1;
+ } p1;
+};
+#else
union fw_self_id {
struct {
u_int32_t more_packets:1,
@@ -388,42 +333,6 @@ union fw_self_id {
id:2;
} p1;
};
-#else
-union fw_self_id {
- struct {
- u_int8_t more_packets:1,
- initiated_reset:1,
- port2:2,
- port1:2,
- port0:2;
- u_int8_t power_class:3,
- contender:1,
- phy_delay:2,
- phy_speed:2;
- u_int8_t gap_count:6,
- link_active:1,
- sequel:1;
- u_int8_t phy_id:6,
- id:2;
- } p0;
- struct {
- u_int8_t more_packets:1,
- reserved1:1,
- porth:2,
- portg:2,
- portf:2;
- u_int8_t porte:2,
- portd:2,
- portc:2,
- portb:2;
- u_int8_t porta:2,
- reserved2:2,
- sequence_num:3,
- sequel:1;
- u_int8_t phy_id:6,
- id:2;
- } p1;
-};
#endif
@@ -449,13 +358,9 @@ struct fw_crom_buf {
void *ptr;
};
-#define FWSTMAXCHUNK 16
/*
* FireWire specific system requests.
*/
-#if 0
-#define FW_SSTDV _IOWR('S', 85, unsigned int)
-#endif
#define FW_SSTBUF _IOWR('S', 86, struct fw_isobufreq)
#define FW_GSTBUF _IOWR('S', 87, struct fw_isobufreq)
#define FW_SRSTREAM _IOWR('S', 88, struct fw_isochreq)
diff --git a/sys/dev/firewire/firewire_phy.h b/sys/dev/firewire/firewire_phy.h
index de30b22..02cda69 100644
--- a/sys/dev/firewire/firewire_phy.h
+++ b/sys/dev/firewire/firewire_phy.h
@@ -83,5 +83,3 @@
#define FW_PHY_EDEL_REG 0x03
#define FW_PHY_EDEL 15<<0
-
-
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
index 709f80a..ebe74f1 100644
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -42,15 +43,13 @@ typedef struct proc fw_proc;
#include <sys/select.h>
#endif
+#include <sys/uio.h>
+
#define splfw splimp
struct fw_device{
u_int16_t dst;
struct fw_eui64 eui;
-#if 0
- u_int32_t spec;
- u_int32_t ver;
-#endif
u_int8_t speed;
u_int8_t maxrec;
u_int8_t nport;
@@ -66,10 +65,6 @@ struct fw_device{
#define FWDEVATTACHED 2
#define FWDEVINVAL 3
STAILQ_ENTRY(fw_device) link;
-#if 0
- LIST_HEAD(, fw_xfer) txqueue;
- LIST_HEAD(, fw_xfer) rxqueue;
-#endif
};
struct firewire_softc {
@@ -88,6 +83,7 @@ struct firewire_softc {
struct firewire_dev_comm {
device_t dev;
struct firewire_comm *fc;
+ void (*post_busreset) __P((void *));
void (*post_explore) __P((void *));
};
@@ -136,14 +132,12 @@ struct firewire_comm{
#define FWBUSCOMPLETION 10
int nisodma;
struct fw_eui64 eui;
- STAILQ_HEAD(fw_queue, fw_xfer);
struct fw_xferq
*arq, *atq, *ars, *ats, *it[FW_MAX_DMACH],*ir[FW_MAX_DMACH];
STAILQ_HEAD(, tlabel) tlabels[0x40];
STAILQ_HEAD(, fw_bind) binds;
STAILQ_HEAD(, fw_device) devices;
STAILQ_HEAD(, fw_xfer) pending;
- volatile u_int32_t *sid_buf;
u_int sid_cnt;
#define CSRSIZE 0x4000
u_int32_t csr_arc[CSRSIZE/4];
@@ -169,6 +163,7 @@ struct firewire_comm{
void (*irx_post) __P((struct firewire_comm *, u_int32_t *));
void (*itx_post) __P((struct firewire_comm *, u_int32_t *));
struct tcode_info *tcode;
+ bus_dma_tag_t dmat;
};
#define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4])
@@ -184,11 +179,7 @@ struct fw_xferq {
#define FWXFERQ_RUNNING (1 << 8)
#define FWXFERQ_STREAM (1 << 9)
-#define FWXFERQ_PACKET (1 << 10)
#define FWXFERQ_BULK (1 << 11)
-#if 0 /* BROKEN */
-#define FWXFERQ_DV (1 << 12)
-#endif
#define FWXFERQ_MODEMASK (7 << 10)
#define FWXFERQ_EXTBUF (1 << 13)
@@ -198,14 +189,12 @@ struct fw_xferq {
#define FWXFERQ_WAKEUP (1 << 17)
void (*start) __P((struct firewire_comm*));
- void (*drain) __P((struct firewire_comm*, struct fw_xfer*));
- struct fw_queue q;
+ STAILQ_HEAD(, fw_xfer) q;
u_int queued;
u_int maxq;
u_int psize;
- u_int packets;
STAILQ_HEAD(, fw_bind) binds;
- caddr_t buf;
+ struct fwdma_alloc_multi *buf;
u_int bnchunk;
u_int bnpacket;
struct fw_bulkxfer *bulkxfer;
@@ -213,36 +202,20 @@ struct fw_xferq {
STAILQ_HEAD(, fw_bulkxfer) stfree;
STAILQ_HEAD(, fw_bulkxfer) stdma;
struct fw_bulkxfer *stproc;
-#ifdef FWXFERQ_DV
- int dvdbc, dvdiff, dvsync, dvoffset;
- struct fw_dvbuf *dvbuf;
- STAILQ_HEAD(, fw_dvbuf) dvvalid;
- STAILQ_HEAD(, fw_dvbuf) dvfree;
- struct fw_dvbuf *dvdma;
- struct fw_dvbuf *dvproc;
- u_int dvptr;
- u_int dvpacket;
-#endif
struct selinfo rsel;
caddr_t sc;
void (*hand) __P((struct fw_xferq *));
};
struct fw_bulkxfer{
- caddr_t buf;
+ int poffset;
struct mbuf *mbuf;
STAILQ_ENTRY(fw_bulkxfer) link;
caddr_t start;
caddr_t end;
- u_int npacket;
int resp;
};
-struct fw_dvbuf{
- caddr_t buf;
- STAILQ_ENTRY(fw_dvbuf) link;
-};
-
struct tlabel{
struct fw_xfer *xfer;
STAILQ_ENTRY(tlabel) link;
@@ -250,23 +223,25 @@ struct tlabel{
struct fw_bind{
u_int32_t start_hi, start_lo, addrlen;
- struct fw_xfer* xfer;
+ STAILQ_HEAD(, fw_xfer) xferlist;
STAILQ_ENTRY(fw_bind) fclist;
STAILQ_ENTRY(fw_bind) chlist;
+#define FWACT_NULL 0
+#define FWACT_XFER 2
+#define FWACT_CH 3
+ u_int8_t act_type;
+ u_int8_t sub;
};
struct fw_xfer{
caddr_t sc;
struct firewire_comm *fc;
struct fw_xferq *q;
-#ifdef XFER_TIMEOUT
- struct callout_handle ch;
-#endif
struct timeval tv;
- struct fw_tlabel *tlabel;
+ /* XXX should be removed */
+ u_int32_t dst; /* XXX for if_fwe */
u_int8_t spd;
- u_int8_t tcode;
- int resp;
+ int8_t resp;
#define FWXF_INIT 0
#define FWXF_INQ 1
#define FWXF_START 2
@@ -274,48 +249,30 @@ struct fw_xfer{
#define FWXF_SENTERR 4
#define FWXF_BUSY 8
#define FWXF_RCVD 10
- int state;
+ u_int8_t state;
u_int8_t retry;
u_int8_t tl;
- int sub;
- int32_t dst;
- u_int8_t act_type;
-#define FWACT_NULL 0
-#define FWACT_XFER 2
-#define FWACT_CH 3
void (*retry_req) __P((struct fw_xfer *));
union{
void (*hand) __P((struct fw_xfer *));
} act;
-#if 0
- union{
- struct {
- struct fw_device *device;
- } req;
- struct {
- struct stch *channel;
- } stream;
- } mode;
-#endif
struct {
- u_int16_t len, off;
+ int len;
caddr_t buf;
} send, recv;
struct mbuf *mbuf;
STAILQ_ENTRY(fw_xfer) link;
struct malloc_type *malloc;
};
-void fw_sidrcv __P((struct firewire_comm *, caddr_t, u_int, u_int));
-void fw_rcv __P((struct firewire_comm *, caddr_t, u_int, u_int, u_int, u_int));
+void fw_sidrcv __P((struct firewire_comm *, u_int32_t *, u_int));
+void fw_rcv __P((struct firewire_comm *, struct iovec *, int, u_int, u_int));
+void fw_xfer_unload __P(( struct fw_xfer*));
void fw_xfer_free __P(( struct fw_xfer*));
struct fw_xfer *fw_xfer_alloc __P((struct malloc_type *));
+struct fw_xfer *fw_xfer_alloc_buf __P((struct malloc_type *, int, int));
void fw_init __P((struct firewire_comm *));
int fw_tbuf_update __P((struct firewire_comm *, int, int));
int fw_rbuf_update __P((struct firewire_comm *, int, int));
-int fw_readreqq __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t *));
-int fw_writereqb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t *));
-int fw_readresb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t*));
-int fw_writeres __P((struct firewire_comm *, u_int32_t, u_int32_t));
u_int32_t getcsrdata __P((struct fw_device *, u_int8_t));
void fw_asybusy __P((struct fw_xfer *));
int fw_bindadd __P((struct firewire_comm *, struct fw_bind *));
@@ -365,11 +322,6 @@ extern devclass_t firewire_devclass;
#define FWPRI ((PZERO+8)|PCATCH)
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
-#endif /* __alpha__ */
-
#if __FreeBSD_version >= 500000
#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
#else
diff --git a/sys/dev/firewire/fwcrom.c b/sys/dev/firewire/fwcrom.c
index d58be50..282a7fd 100644
--- a/sys/dev/firewire/fwcrom.c
+++ b/sys/dev/firewire/fwcrom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,9 @@
*/
#include <sys/param.h>
-#include <dev/firewire/firewire.h>
-#include <dev/firewire/iec13213.h>
+#if defined(_KERNEL) || defined(TEST)
+#include <sys/queue.h>
+#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -48,6 +49,8 @@
#include <stdlib.h>
#include <string.h>
#endif
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
void
crom_init_context(struct crom_context *cc, u_int32_t *p)
@@ -179,20 +182,28 @@ crom_desc(struct crom_context *cc, char *buf, int len)
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
+ u_int16_t crc;
reg = crom_get(cc);
switch (reg->key & CSRTYPE_MASK) {
case CSRTYPE_I:
snprintf(buf, len, "%d", reg->val);
break;
- case CSRTYPE_L:
case CSRTYPE_C:
snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
break;
+ case CSRTYPE_L:
+ /* XXX fall through */
case CSRTYPE_D:
dir = (struct csrdirectory *) (reg + reg->val);
- snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
- dir->crc_len, dir->crc_len, dir->crc);
+ crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
+ len -= snprintf(buf, len, "len=%d crc=0x%04x",
+ dir->crc_len, dir->crc);
+ if (crc == dir->crc)
+ strncat(buf, "(OK) ", len);
+ else
+ strncat(buf, "(NG) ", len);
+ len -= 5;
}
switch (reg->key) {
case 0x03:
@@ -239,7 +250,7 @@ crom_desc(struct crom_context *cc, char *buf, int len)
break;
case 0x81:
desc = "text_leaf";
- crom_parse_text(cc, buf, len);
+ crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
@@ -253,3 +264,243 @@ crom_desc(struct crom_context *cc, char *buf, int len)
return desc;
}
#endif
+
+#if defined(_KERNEL) || defined(TEST)
+
+int
+crom_add_quad(struct crom_chunk *chunk, u_int32_t entry)
+{
+ int index;
+
+ index = chunk->data.crc_len;
+ if (index >= CROM_MAX_CHUNK_LEN - 1) {
+ printf("too large chunk %d\n", index);
+ return(-1);
+ }
+ chunk->data.buf[index] = entry;
+ chunk->data.crc_len++;
+ return(index);
+}
+
+int
+crom_add_entry(struct crom_chunk *chunk, int key, int val)
+{
+ struct csrreg *reg;
+ u_int32_t i;
+
+ reg = (struct csrreg *)&i;
+ reg->key = key;
+ reg->val = val;
+ return(crom_add_quad(chunk, (u_int32_t) i));
+}
+
+int
+crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *child, int key)
+{
+ int index;
+
+ if (parent == NULL) {
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(0);
+ }
+
+ index = crom_add_entry(parent, key, 0);
+ if (index < 0) {
+ return(-1);
+ }
+ child->ref_chunk = parent;
+ child->ref_index = index;
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(index);
+}
+
+int
+crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *chunk, char *buf)
+{
+ struct csrtext *tl;
+ u_int32_t *p;
+ int len, i;
+
+ len = strlen(buf);
+#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
+ if (len > MAX_TEXT) {
+#if __FreeBSD_version < 500000
+ printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
+#else
+ printf("text(%d) trancated to %td.\n", len, MAX_TEXT);
+#endif
+ len = MAX_TEXT;
+ }
+
+ tl = (struct csrtext *) &chunk->data;
+ tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t));
+ tl->spec_id = 0;
+ tl->spec_type = 0;
+ tl->lang_id = 0;
+ p = (u_int32_t *) buf;
+ for (i = 0; i < howmany(len, sizeof(u_int32_t)) / 4; i ++)
+ tl->text[i] = ntohl(*p++);
+ return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
+}
+
+static int
+crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen)
+{
+ if (*offset + len > maxlen) {
+ printf("Config. ROM is too large for the buffer\n");
+ return(-1);
+ }
+ bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t));
+ *offset += len;
+ return(0);
+}
+
+int
+crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
+{
+ struct crom_chunk *chunk, *parent;
+ struct csrhdr *hdr;
+#if 0
+ u_int32_t *ptr;
+#endif
+ int count, offset;
+ int len;
+
+ offset = 0;
+ /* Determine offset */
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->offset = offset;
+ /* Assume the offset of the parent is already known */
+ parent = chunk->ref_chunk;
+ if (parent != NULL) {
+ struct csrreg *reg;
+ reg = (struct csrreg *)
+ &parent->data.buf[chunk->ref_index];
+ reg->val = offset -
+ (parent->offset + 1 + chunk->ref_index);
+ }
+ offset += 1 + chunk->data.crc_len;
+ }
+
+ /* Calculate CRC and dump to the buffer */
+ len = 1 + src->hdr.info_len;
+ count = 0;
+ if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
+ return(-1);
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->data.crc =
+ crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
+
+ len = 1 + chunk->data.crc_len;
+ if (crom_copy((u_int32_t *)&chunk->data, buf,
+ &count, len, maxlen) < 0)
+ return(-1);
+ }
+ hdr = (struct csrhdr *)buf;
+ hdr->crc_len = count - 1;
+ hdr->crc = crom_crc(buf + 1, hdr->crc_len);
+
+#if 0
+ /* byte swap */
+ ptr = buf;
+ for (i = 0; i < count; i ++) {
+ *ptr = htonl(*ptr);
+ ptr++;
+ }
+#endif
+
+ return(count);
+}
+#endif
+
+#ifdef TEST
+int
+main () {
+ struct crom_src src;
+ struct crom_chunk root,unit1,unit2,unit3;
+ struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
+ u_int32_t buf[256], *p;
+ int i;
+
+ bzero(&src, sizeof(src));
+ bzero(&root, sizeof(root));
+ bzero(&unit1, sizeof(unit1));
+ bzero(&unit2, sizeof(unit2));
+ bzero(&unit3, sizeof(unit3));
+ bzero(&text1, sizeof(text1));
+ bzero(&text2, sizeof(text2));
+ bzero(&text3, sizeof(text3));
+ bzero(&text3, sizeof(text4));
+ bzero(&text3, sizeof(text5));
+ bzero(&text3, sizeof(text6));
+ bzero(&text3, sizeof(text7));
+ bzero(buf, sizeof(buf));
+
+ /* BUS info sample */
+ src.hdr.info_len = 4;
+ src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
+ src.businfo.eui64.hi = 0x11223344;
+ src.businfo.eui64.lo = 0x55667788;
+ src.businfo.link_spd = FWSPD_S400;
+ src.businfo.generation = 0;
+ src.businfo.max_rom = MAXROM_4;
+ src.businfo.max_rec = 10;
+ src.businfo.cyc_clk_acc = 100;
+ src.businfo.pmc = 0;
+ src.businfo.bmc = 1;
+ src.businfo.isc = 1;
+ src.businfo.cmc = 1;
+ src.businfo.irmc = 1;
+ STAILQ_INIT(&src.chunk_list);
+
+ /* Root directory */
+ crom_add_chunk(&src, NULL, &root, 0);
+ crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
+ /* private company_id */
+ crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
+
+ crom_add_simple_text(&src, &root, &text1, "FreeBSD");
+ crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
+ crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
+
+ /* SBP unit directory */
+ crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
+ crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
+ crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
+ /* management_agent */
+ crom_add_entry(&unit1, CROM_MGM, 0x1000);
+ crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
+ /* Device type and LUN */
+ crom_add_entry(&unit1, CROM_LUN, 0);
+ crom_add_entry(&unit1, CSRKEY_MODEL, 1);
+ crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
+
+ /* RFC2734 IPv4 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
+ crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit2, &text4, "IANA");
+ crom_add_entry(&unit2, CSRKEY_VER, 1);
+ crom_add_simple_text(&src, &unit2, &text5, "IPv4");
+
+ /* RFC3146 IPv6 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
+ crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit3, &text6, "IANA");
+ crom_add_entry(&unit3, CSRKEY_VER, 2);
+ crom_add_simple_text(&src, &unit3, &text7, "IPv6");
+
+ crom_load(&src, buf, 256);
+ p = buf;
+#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
+ for (i = 0; i < 256/8; i ++) {
+ printf(DUMP_FORMAT,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ return(0);
+}
+#endif
diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c
index e590edc..13168b6 100644
--- a/sys/dev/firewire/fwdev.c
+++ b/sys/dev/firewire/fwdev.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -42,15 +43,16 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
-#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/bus.h>
+#include <machine/bus.h>
#include <sys/ioccom.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
#include <dev/firewire/fwmem.h>
#include <dev/firewire/iec68113.h>
@@ -112,7 +114,6 @@ fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
/* Default is per packet mode */
sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
- sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
return err;
}
@@ -148,32 +149,9 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
sc->fc->itx_disable(sc->fc, sub);
}
-#ifdef FWXFERQ_DV
- if(sc->fc->it[sub]->flag & FWXFERQ_DV){
- struct fw_dvbuf *dvbuf;
-
- if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
- free(dvbuf->buf, M_FW);
- sc->fc->it[sub]->dvproc = NULL;
- }
- if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
- free(dvbuf->buf, M_FW);
- sc->fc->it[sub]->dvdma = NULL;
- }
- while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
- STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
- free(dvbuf->buf, M_FW);
- }
- while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
- STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
- free(dvbuf->buf, M_FW);
- }
- free(sc->fc->it[sub]->dvbuf, M_FW);
- sc->fc->it[sub]->dvbuf = NULL;
- }
-#endif
if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
- free(sc->fc->ir[sub]->buf, M_FW);
+ if (sc->fc->ir[sub]->buf != NULL)
+ fwdma_free_multiseg(sc->fc->ir[sub]->buf);
sc->fc->ir[sub]->buf = NULL;
free(sc->fc->ir[sub]->bulkxfer, M_FW);
sc->fc->ir[sub]->bulkxfer = NULL;
@@ -182,13 +160,11 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
sc->fc->ir[sub]->maxq = FWMAXQUEUE;
}
if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
- free(sc->fc->it[sub]->buf, M_FW);
+ if (sc->fc->it[sub]->buf != NULL)
+ fwdma_free_multiseg(sc->fc->it[sub]->buf);
sc->fc->it[sub]->buf = NULL;
free(sc->fc->it[sub]->bulkxfer, M_FW);
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;
@@ -199,14 +175,7 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
xfer->resp = 0;
- switch(xfer->act_type){
- case FWACT_XFER:
- fw_xfer_done(xfer);
- break;
- default:
- break;
- }
- fw_xfer_free(xfer);
+ fw_xfer_done(xfer);
}
for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
@@ -214,8 +183,8 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
free(fwb, M_FW);
}
- sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
- sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
+ sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
+ sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
return err;
}
@@ -240,12 +209,9 @@ fw_read (dev_t dev, struct uio *uio, int ioflag)
ir = sc->fc->ir[sub];
- if (ir->flag & FWXFERQ_PACKET) {
- ir->stproc = NULL;
- }
readloop:
xfer = STAILQ_FIRST(&ir->q);
- if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) {
+ if (ir->stproc == NULL) {
/* iso bulkxfer */
ir->stproc = STAILQ_FIRST(&ir->stvalid);
if (ir->stproc != NULL) {
@@ -259,12 +225,6 @@ readloop:
/* no data avaliable */
if (slept == 0) {
slept = 1;
- if ((ir->flag & FWXFERQ_RUNNING) == 0
- && (ir->flag & FWXFERQ_PACKET)) {
- err = sc->fc->irx_enable(sc->fc, sub);
- if (err)
- return err;
- }
ir->flag |= FWXFERQ_WAKEUP;
err = tsleep(ir, FWPRI, "fw_read", hz);
ir->flag &= ~FWXFERQ_WAKEUP;
@@ -274,30 +234,29 @@ readloop:
err = EIO;
return err;
} else if(xfer != NULL) {
- /* per packet mode */
+ /* per packet mode or FWACT_CH bind?*/
s = splfw();
ir->queued --;
STAILQ_REMOVE_HEAD(&ir->q, link);
splx(s);
- fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
+ fp = (struct fw_pkt *)xfer->recv.buf;
if(sc->fc->irx_post != NULL)
sc->fc->irx_post(sc->fc, fp->mode.ld);
- err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
+ err = uiomove(xfer->recv.buf, xfer->recv.len, uio);
+ /* XXX we should recycle this xfer */
fw_xfer_free( xfer);
} else if(ir->stproc != NULL) {
/* iso bulkxfer */
- fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
+ fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
+ ir->stproc->poffset + ir->queued);
if(sc->fc->irx_post != NULL)
sc->fc->irx_post(sc->fc, fp->mode.ld);
- if(ntohs(fp->mode.stream.len) == 0){
+ if(fp->mode.stream.len == 0){
err = EIO;
return err;
}
err = uiomove((caddr_t)fp,
- ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
-#if 0
- fp->mode.stream.len = 0;
-#endif
+ fp->mode.stream.len + sizeof(u_int32_t), uio);
ir->queued ++;
if(ir->queued >= ir->bnpacket){
s = splfw();
@@ -335,34 +294,7 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
fc = sc->fc;
it = sc->fc->it[sub];
- fp = (struct fw_pkt *)uio->uio_iov->iov_base;
- switch(fp->mode.common.tcode){
- case FWTCODE_RREQQ:
- case FWTCODE_RREQB:
- case FWTCODE_LREQ:
- err = EINVAL;
- return err;
- case FWTCODE_WREQQ:
- case FWTCODE_WREQB:
- xferq = fc->atq;
- break;
- case FWTCODE_STREAM:
- if(it->flag & FWXFERQ_PACKET){
- xferq = fc->atq;
- }else{
- xferq = NULL;
- }
- break;
- case FWTCODE_WRES:
- case FWTCODE_RRESQ:
- case FWTCODE_RRESB:
- case FWTCODE_LRES:
- xferq = fc->ats;
- break;
- default:
- err = EINVAL;
- return err;
- }
+ xferq = NULL;
/* Discard unsent buffered stream packet, when sending Asyrequrst */
if(xferq != NULL && it->stproc != NULL){
s = splfw();
@@ -370,11 +302,7 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
splx(s);
it->stproc = NULL;
}
-#ifdef FWXFERQ_DV
- if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
-#else
if (xferq == NULL) {
-#endif
isoloop:
if (it->stproc == NULL) {
it->stproc = STAILQ_FIRST(&it->stfree);
@@ -398,11 +326,11 @@ isoloop:
return err;
}
}
- fp = (struct fw_pkt *)
- (it->stproc->buf + it->queued * it->psize);
+ fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
+ it->stproc->poffset + it->queued);
err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
err = uiomove((caddr_t)fp->mode.stream.payload,
- ntohs(fp->mode.stream.len), uio);
+ fp->mode.stream.len, uio);
it->queued ++;
if (it->queued >= it->bnpacket) {
s = splfw();
@@ -417,92 +345,14 @@ isoloop:
}
return err;
}
-#ifdef FWXFERQ_DV
- if(xferq == NULL && it->flag & FWXFERQ_DV){
-dvloop:
- if(it->dvproc == NULL){
- it->dvproc = STAILQ_FIRST(&it->dvfree);
- if(it->dvproc != NULL){
- s = splfw();
- STAILQ_REMOVE_HEAD(&it->dvfree, link);
- splx(s);
- it->dvptr = 0;
- }else if(slept == 0){
- slept = 1;
- err = sc->fc->itx_enable(sc->fc, sub);
- if(err){
- return err;
- }
- err = tsleep(it, FWPRI, "fw_write", hz);
- if(err){
- return err;
- }
- goto dvloop;
- }else{
- err = EIO;
- return err;
- }
- }
-#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
- fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
- fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
-#endif
- err = uiomove(it->dvproc->buf + it->dvptr,
- uio->uio_resid, uio);
- it->dvptr += it->psize;
- if(err){
- return err;
- }
- if(it->dvptr >= it->psize * it->dvpacket){
- s = splfw();
- STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
- splx(s);
- it->dvproc = NULL;
- err = fw_tbuf_update(sc->fc, sub, 0);
- if(err){
- return err;
- }
- err = sc->fc->itx_enable(sc->fc, sub);
- }
- return err;
- }
-#endif
- if(xferq != NULL){
- xfer = fw_xfer_alloc(M_FWXFER);
+ if (xferq != NULL) {
+ xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 12);
if(xfer == NULL){
err = ENOMEM;
return err;
}
- xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- fw_xfer_free( xfer);
- err = ENOBUFS;
- return err;
- }
- xfer->dst = ntohs(fp->mode.hdr.dst);
-#if 0
- switch(fp->mode.common.tcode){
- case FWTCODE_WREQQ:
- case FWTCODE_WREQB:
- if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
- fw_xfer_free( xfer);
- err = EAGAIN;
- return err;
- }
- fp->mode.hdr.tlrt = tl << 2;
- default:
- break;
- }
-
- xfer->tl = fp->mode.hdr.tlrt >> 2;
- xfer->tcode = fp->mode.common.tcode;
- xfer->fc = fc;
- xfer->q = xferq;
- xfer->act_type = FWACT_XFER;
- xfer->retry_req = fw_asybusy;
-#endif
+ xfer->dst = fp->mode.hdr.dst;
xfer->send.len = uio->uio_resid;
- xfer->send.off = 0;
xfer->spd = 0;/* XXX: how to setup it */
xfer->act.hand = fw_asy_callback;
@@ -511,11 +361,7 @@ dvloop:
fw_xfer_free( xfer);
return err;
}
-#if 0
- fw_asystart(xfer);
-#else
fw_asyreq(fc, -1, xfer);
-#endif
err = tsleep(xfer, FWPRI, "fw_write", hz);
if(xfer->resp == EBUSY)
return EBUSY;
@@ -534,7 +380,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
struct firewire_softc *sc;
int unit = DEV2UNIT(dev);
int sub = DEV2DMACH(dev);
- int i, len, err = 0;
+ int s, i, len, err = 0;
struct fw_device *fwdev;
struct fw_bind *fwb;
struct fw_xferq *ir, *it;
@@ -579,50 +425,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
err = 0;
break;
-#ifdef FWXFERQ_DV
- case FW_SSTDV:
- ibufreq = (struct fw_isobufreq *)
- malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT);
- if(ibufreq == NULL){
- err = ENOMEM;
- break;
- }
-#if DV_PAL
-#define FWDVPACKET 300
-#else
-#define FWDVPACKET 250
-#endif
-#define FWDVPMAX 512
- ibufreq->rx.nchunk = 8;
- ibufreq->rx.npacket = 50;
- ibufreq->rx.psize = FWDVPMAX;
-
- ibufreq->tx.nchunk = 5;
- ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */
- ibufreq->tx.psize = FWDVPMAX;
-
- err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
- sc->fc->it[sub]->dvpacket = FWDVPACKET;
- free(ibufreq, M_FW);
-/* reserve a buffer space */
-#define NDVCHUNK 8
- sc->fc->it[sub]->dvproc = NULL;
- sc->fc->it[sub]->dvdma = NULL;
- sc->fc->it[sub]->flag |= FWXFERQ_DV;
- /* XXX check malloc failure */
- sc->fc->it[sub]->dvbuf
- = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT);
- STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
- STAILQ_INIT(&sc->fc->it[sub]->dvfree);
- for( i = 0 ; i < NDVCHUNK ; i++){
- /* XXX check malloc failure */
- sc->fc->it[sub]->dvbuf[i].buf
- = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT);
- STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
- &sc->fc->it[sub]->dvbuf[i], link);
- }
- break;
-#endif
case FW_SSTBUF:
ir = sc->fc->ir[sub];
it = sc->fc->it[sub];
@@ -639,48 +441,52 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
return(EINVAL);
}
- if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
- ibufreq->tx.nchunk > FWSTMAXCHUNK){
- return(EINVAL);
- }
ir->bulkxfer
- = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0);
+ = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK);
if(ir->bulkxfer == NULL){
return(ENOMEM);
}
it->bulkxfer
- = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0);
+ = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK);
if(it->bulkxfer == NULL){
return(ENOMEM);
}
- ir->buf = malloc(
- ibufreq->rx.nchunk * ibufreq->rx.npacket
- /* XXX psize must be 2^n and less or
- equal to PAGE_SIZE */
- * ((ibufreq->rx.psize + 3) &~3),
- M_FW, 0);
- if(ir->buf == NULL){
- free(ir->bulkxfer, M_FW);
- free(it->bulkxfer, M_FW);
- ir->bulkxfer = NULL;
- it->bulkxfer = NULL;
- it->buf = NULL;
- return(ENOMEM);
+ if (ibufreq->rx.psize > 0) {
+ ibufreq->rx.psize = roundup2(ibufreq->rx.psize,
+ sizeof(u_int32_t));
+ ir->buf = fwdma_malloc_multiseg(
+ sc->fc, sizeof(u_int32_t),
+ ibufreq->rx.psize,
+ ibufreq->rx.nchunk * ibufreq->rx.npacket,
+ BUS_DMA_WAITOK);
+
+ if(ir->buf == NULL){
+ free(ir->bulkxfer, M_FW);
+ free(it->bulkxfer, M_FW);
+ ir->bulkxfer = NULL;
+ it->bulkxfer = NULL;
+ it->buf = NULL;
+ return(ENOMEM);
+ }
}
- it->buf = malloc(
- ibufreq->tx.nchunk * ibufreq->tx.npacket
- /* XXX psize must be 2^n and less or
- equal to PAGE_SIZE */
- * ((ibufreq->tx.psize + 3) &~3),
- M_FW, 0);
- if(it->buf == NULL){
- free(ir->bulkxfer, M_FW);
- free(it->bulkxfer, M_FW);
- free(ir->buf, M_FW);
- ir->bulkxfer = NULL;
- it->bulkxfer = NULL;
- it->buf = NULL;
- return(ENOMEM);
+ if (ibufreq->tx.psize > 0) {
+ ibufreq->tx.psize = roundup2(ibufreq->tx.psize,
+ sizeof(u_int32_t));
+ it->buf = fwdma_malloc_multiseg(
+ sc->fc, sizeof(u_int32_t),
+ ibufreq->tx.psize,
+ ibufreq->tx.nchunk * ibufreq->tx.npacket,
+ BUS_DMA_WAITOK);
+
+ if(it->buf == NULL){
+ free(ir->bulkxfer, M_FW);
+ free(it->bulkxfer, M_FW);
+ fwdma_free_multiseg(ir->buf);
+ ir->bulkxfer = NULL;
+ it->bulkxfer = NULL;
+ it->buf = NULL;
+ return(ENOMEM);
+ }
}
ir->bnchunk = ibufreq->rx.nchunk;
@@ -693,13 +499,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->psize = (ibufreq->tx.psize + 3) & ~3;
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);
STAILQ_INIT(&ir->stdma);
@@ -711,18 +510,16 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->stproc = NULL;
for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
- ir->bulkxfer[i].buf =
- ir->buf + i * ir->bnpacket * ir->psize;
+ ir->bulkxfer[i].poffset = i * ir->bnpacket;
+ ir->bulkxfer[i].mbuf = NULL;
STAILQ_INSERT_TAIL(&ir->stfree,
&ir->bulkxfer[i], link);
- ir->bulkxfer[i].npacket = ir->bnpacket;
}
for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
- it->bulkxfer[i].buf =
- it->buf + i * it->bnpacket * it->psize;
+ it->bulkxfer[i].poffset = i * it->bnpacket;
+ it->bulkxfer[i].mbuf = NULL;
STAILQ_INSERT_TAIL(&it->stfree,
&it->bulkxfer[i], link);
- it->bulkxfer[i].npacket = it->bnpacket;
}
ir->flag &= ~FWXFERQ_MODEMASK;
ir->flag |= FWXFERQ_STREAM;
@@ -743,7 +540,8 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ibufreq->tx.psize = sc->fc->it[sub]->psize;
break;
case FW_ASYREQ:
- xfer = fw_xfer_alloc(M_FWXFER);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len,
+ PAGE_SIZE /* XXX */);
if(xfer == NULL){
err = ENOMEM;
return err;
@@ -751,7 +549,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
fp = &asyreq->pkt;
switch (asyreq->req.type) {
case FWASREQNODE:
- xfer->dst = ntohs(fp->mode.hdr.dst);
+ xfer->dst = fp->mode.hdr.dst;
break;
case FWASREQEUI:
fwdev = fw_noderesolve_eui64(sc->fc,
@@ -763,7 +561,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
goto error;
}
xfer->dst = fwdev->dst;
- fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
+ fp->mode.hdr.dst = FWLOCALBUS | xfer->dst;
break;
case FWASRESTL:
/* XXX what's this? */
@@ -773,12 +571,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
break;
}
xfer->spd = asyreq->req.sped;
- xfer->send.len = asyreq->req.len;
- xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- return ENOMEM;
- }
- xfer->send.off = 0;
bcopy(fp, xfer->send.buf, xfer->send.len);
xfer->act.hand = fw_asy_callback;
err = fw_asyreq(sc->fc, sub, xfer);
@@ -793,7 +585,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
}else{
err = EINVAL;
}
- bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
+ bcopy(xfer->recv.buf, fp, asyreq->req.len);
}
error:
fw_xfer_free( xfer);
@@ -829,17 +621,21 @@ error:
fwb->start_hi = bindreq->start.hi;
fwb->start_lo = bindreq->start.lo;
fwb->addrlen = bindreq->len;
+ fwb->sub = sub;
+ fwb->act_type = FWACT_CH;
xfer = fw_xfer_alloc(M_FWXFER);
if(xfer == NULL){
err = ENOMEM;
return err;
}
- xfer->act_type = FWACT_CH;
- xfer->sub = sub;
xfer->fc = sc->fc;
- fwb->xfer = xfer;
+ s = splfw();
+ /* XXX broken. need multiple xfer */
+ STAILQ_INIT(&fwb->xferlist);
+ STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
+ splx(s);
err = fw_bindadd(sc->fc, fwb);
break;
case FW_GDEVLST:
@@ -876,17 +672,10 @@ error:
err = FWNODE_INVAL;
break;
}
-#if 0
- if (fwdev->csrrom[0] >> 24 == 1)
- len = 4;
- else
- len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
-#else
if (fwdev->rommax < CSRROMOFF)
len = 0;
else
len = fwdev->rommax - CSRROMOFF + 4;
-#endif
if (crom_buf->len < len)
len = crom_buf->len;
else
@@ -930,17 +719,17 @@ fw_poll(dev_t dev, int events, fw_proc *td)
}
static int
-#if __FreeBSD_version < 500000
+#if __FreeBSD_version < 500102
fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
#else
-fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
+fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
#endif
{
struct firewire_softc *fc;
int unit = DEV2UNIT(dev);
if (DEV_FWMEM(dev))
-#if __FreeBSD_version < 500000
+#if __FreeBSD_version < 500102
return fwmem_mmap(dev, offset, nproto);
#else
return fwmem_mmap(dev, offset, paddr, nproto);
diff --git a/sys/dev/firewire/fwdma.c b/sys/dev/firewire/fwdma.c
new file mode 100644
index 0000000..14b4903
--- /dev/null
+++ b/sys/dev/firewire/fwdma.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2003
+ * Hidetoshi Shimokawa. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *
+ * This product includes software developed by Hidetoshi Shimokawa.
+ *
+ * 4. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
+
+static void
+fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ bus_addr_t *baddr;
+
+ if (error)
+ printf("fwdma_map_cb: error=%d\n", error);
+ baddr = (bus_addr_t *)arg;
+ *baddr = segs->ds_addr;
+}
+
+void *
+fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
+ struct fwdma_alloc *dma, int flag)
+{
+ int err;
+
+ dma->v_addr = NULL;
+ err = bus_dma_tag_create(
+ /*parent*/ fc->dmat,
+ /*alignment*/ alignment,
+ /*boundary*/ 0,
+ /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/ BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/ size,
+ /*nsegments*/ 1,
+ /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
+ /*flags*/ BUS_DMA_ALLOCNOW, &dma->dma_tag);
+ if (err) {
+ printf("fwdma_malloc: failed(1)\n");
+ return(NULL);
+ }
+
+ err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr,
+ flag, &dma->dma_map);
+ if (err) {
+ printf("fwdma_malloc: failed(2)\n");
+ /* XXX destory tag */
+ return(NULL);
+ }
+
+ bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr,
+ size, fwdma_map_cb, &dma->bus_addr, /*flags*/0);
+
+ return(dma->v_addr);
+}
+
+void
+fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma)
+{
+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+ bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map);
+ bus_dma_tag_destroy(dma->dma_tag);
+}
+
+
+void *
+fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
+ bus_size_t size, bus_addr_t *bus_addr, int flag)
+{
+ void *v_addr;
+
+ if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) {
+ printf("fwdma_malloc_size: failed(1)\n");
+ return(NULL);
+ }
+ bus_dmamap_load(dmat, *dmamap, v_addr, size,
+ fwdma_map_cb, bus_addr, /*flags*/0);
+ return(v_addr);
+}
+
+void
+fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap,
+ void *vaddr, bus_size_t size)
+{
+ bus_dmamap_unload(dmat, dmamap);
+ bus_dmamem_free(dmat, vaddr, dmamap);
+}
+
+/*
+ * Allocate multisegment dma buffers
+ * each segment size is eqaul to ssize except last segment.
+ */
+struct fwdma_alloc_multi *
+fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
+ int esize, int n, int flag)
+{
+ struct fwdma_alloc_multi *am;
+ struct fwdma_seg *seg;
+ bus_size_t ssize;
+ int nseg;
+
+ if (esize > PAGE_SIZE) {
+ /* round up to PAGE_SIZE */
+ esize = ssize = roundup2(esize, PAGE_SIZE);
+ nseg = n;
+ } else {
+ /* allocate PAGE_SIZE segment for small elements */
+ ssize = rounddown(PAGE_SIZE, esize);
+ nseg = howmany(n, ssize / esize);
+ }
+ am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi)
+ + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK);
+ if (am == NULL) {
+ printf("fwdma_malloc_multiseg: malloc failed\n");
+ return(NULL);
+ }
+ am->ssize = ssize;
+ am->esize = esize;
+ am->nseg = 0;
+ if (bus_dma_tag_create(
+ /*parent*/ fc->dmat,
+ /*alignment*/ alignment,
+ /*boundary*/ 0,
+ /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/ BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/ ssize,
+ /*nsegments*/ 1,
+ /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
+ /*flags*/ BUS_DMA_ALLOCNOW, &am->dma_tag)) {
+ printf("fwdma_malloc_multiseg: tag_create failed\n");
+ free(am, M_FW);
+ return(NULL);
+ }
+
+#if 0
+#if __FreeBSD_version < 500000
+ printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg);
+#else
+ printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg);
+#endif
+#endif
+ for (seg = &am->seg[0]; nseg --; seg ++) {
+ seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map,
+ ssize, &seg->bus_addr, flag);
+ if (seg->v_addr == NULL) {
+ printf("fwdma_malloc_multi: malloc_size failed %d\n",
+ am->nseg);
+ fwdma_free_multiseg(am);
+ return(NULL);
+ }
+ am->nseg++;
+ }
+ return(am);
+}
+
+void
+fwdma_free_multiseg(struct fwdma_alloc_multi *am)
+{
+ struct fwdma_seg *seg;
+
+ for (seg = &am->seg[0]; am->nseg --; seg ++) {
+ fwdma_free_size(am->dma_tag, seg->dma_map,
+ seg->v_addr, am->ssize);
+ }
+ bus_dma_tag_destroy(am->dma_tag);
+ free(am, M_FW);
+}
diff --git a/sys/dev/firewire/fwdma.h b/sys/dev/firewire/fwdma.h
new file mode 100644
index 0000000..5d3375a
--- /dev/null
+++ b/sys/dev/firewire/fwdma.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2003
+ * Hidetoshi Shimokawa. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *
+ * This product includes software developed by Hidetoshi Shimokawa.
+ *
+ * 4. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#if __FreeBSD_version >= 500111
+typedef int bus_dmasync_op_t;
+#endif
+
+struct fwdma_alloc {
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ void * v_addr;
+ bus_addr_t bus_addr;
+};
+
+struct fwdma_seg {
+ bus_dmamap_t dma_map;
+ void * v_addr;
+ bus_addr_t bus_addr;
+};
+
+struct fwdma_alloc_multi {
+ bus_size_t ssize;
+ bus_size_t esize;
+ int nseg;
+ bus_dma_tag_t dma_tag;
+ struct fwdma_seg seg[0];
+};
+
+static __inline void *
+fwdma_v_addr(struct fwdma_alloc_multi *am, int index)
+{
+ bus_size_t ssize = am->ssize;
+ int offset = am->esize * index;
+
+ return ((caddr_t)am->seg[offset / ssize].v_addr + (offset % ssize));
+}
+
+static __inline bus_addr_t
+fwdma_bus_addr(struct fwdma_alloc_multi *am, int index)
+{
+ bus_size_t ssize = am->ssize;
+ int offset = am->esize * index;
+
+ return (am->seg[offset / ssize].bus_addr + (offset % ssize));
+}
+
+static __inline void
+fwdma_sync(struct fwdma_alloc *dma, bus_dmasync_op_t op)
+{
+ bus_dmamap_sync(dma->dma_tag, dma->dma_map, op);
+}
+
+static __inline void
+fwdma_sync_multiseg(struct fwdma_alloc_multi *am,
+ int start, int end, bus_dmasync_op_t op)
+{
+ struct fwdma_seg *seg, *eseg;
+
+ seg = &am->seg[am->esize * start / am->ssize];
+ eseg = &am->seg[am->esize * end / am->ssize];
+ for (; seg <= eseg; seg ++)
+ bus_dmamap_sync(am->dma_tag, seg->dma_map, op);
+}
+
+static __inline void
+fwdma_sync_multiseg_all(struct fwdma_alloc_multi *am, bus_dmasync_op_t op)
+{
+ struct fwdma_seg *seg;
+ int i;
+
+ seg = &am->seg[0];
+ for (i = 0; i < am->nseg; i++, seg++)
+ bus_dmamap_sync(am->dma_tag, seg->dma_map, op);
+}
+
+void *fwdma_malloc(struct firewire_comm *, int, bus_size_t, struct fwdma_alloc *, int);
+void fwdma_free(struct firewire_comm *, struct fwdma_alloc *);
+void *fwdma_malloc_size(bus_dma_tag_t, bus_dmamap_t *, bus_size_t, bus_addr_t *, int);
+void fwdma_free_size(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t);
+struct fwdma_alloc_multi *fwdma_malloc_multiseg(struct firewire_comm *,
+ int, int, int, int);
+void fwdma_free_multiseg(struct fwdma_alloc_multi *);
+
diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c
index 13bd092..5471687 100644
--- a/sys/dev/firewire/fwmem.c
+++ b/sys/dev/firewire/fwmem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,10 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
-#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
+#include <machine/bus.h>
#include <sys/signal.h>
#include <sys/mman.h>
@@ -68,20 +68,18 @@ SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
"Fwmem driver debug flag");
-static struct fw_xfer *fwmem_xfer_req(struct fw_device *, caddr_t,
- int, int, void *);
-
static struct fw_xfer *
fwmem_xfer_req(
struct fw_device *fwdev,
caddr_t sc,
int spd,
- int len,
+ int slen,
+ int rlen,
void *hand)
{
struct fw_xfer *xfer;
- xfer = fw_xfer_alloc(M_FWXFER);
+ xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
if (xfer == NULL)
return NULL;
@@ -91,15 +89,6 @@ fwmem_xfer_req(
xfer->spd = fwdev->speed;
else
xfer->spd = min(spd, fwdev->speed);
- xfer->send.len = len;
- xfer->send.buf = malloc(len, M_FW, M_NOWAIT | M_ZERO);
-
- if (xfer->send.buf == NULL) {
- fw_xfer_free(xfer);
- return NULL;
- }
-
- xfer->send.off = 0;
xfer->act.hand = hand;
xfer->retry_req = fw_asybusy;
xfer->sc = sc;
@@ -119,15 +108,15 @@ fwmem_read_quad(
struct fw_xfer *xfer;
struct fw_pkt *fp;
- xfer = fwmem_xfer_req(fwdev, sc, spd, 12, hand);
+ xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqq.tcode = FWTCODE_RREQQ;
- fp->mode.rreqq.dst = htons(xfer->dst);
- fp->mode.rreqq.dest_hi = htons(dst_hi);
- fp->mode.rreqq.dest_lo = htonl(dst_lo);
+ fp->mode.rreqq.dst = xfer->dst;
+ fp->mode.rreqq.dest_hi = dst_hi;
+ fp->mode.rreqq.dest_lo = dst_lo;
if (fwmem_debug)
printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
@@ -153,15 +142,15 @@ fwmem_write_quad(
struct fw_xfer *xfer;
struct fw_pkt *fp;
- xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
+ xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.wreqq.tcode = FWTCODE_WREQQ;
- fp->mode.wreqq.dst = htons(xfer->dst);
- fp->mode.wreqq.dest_hi = htons(dst_hi);
- fp->mode.wreqq.dest_lo = htonl(dst_lo);
+ fp->mode.wreqq.dst = xfer->dst;
+ fp->mode.wreqq.dest_hi = dst_hi;
+ fp->mode.wreqq.dest_lo = dst_lo;
fp->mode.wreqq.data = data;
@@ -189,16 +178,16 @@ fwmem_read_block(
struct fw_xfer *xfer;
struct fw_pkt *fp;
- xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
+ xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqb.tcode = FWTCODE_RREQB;
- fp->mode.rreqb.dst = htons(xfer->dst);
- fp->mode.rreqb.dest_hi = htons(dst_hi);
- fp->mode.rreqb.dest_lo = htonl(dst_lo);
- fp->mode.rreqb.len = htons(len);
+ fp->mode.rreqb.dst = xfer->dst;
+ fp->mode.rreqb.dest_hi = dst_hi;
+ fp->mode.rreqb.dest_lo = dst_lo;
+ fp->mode.rreqb.len = len;
if (fwmem_debug)
printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
@@ -224,16 +213,16 @@ fwmem_write_block(
struct fw_xfer *xfer;
struct fw_pkt *fp;
- xfer = fwmem_xfer_req(fwdev, sc, spd, 16 + roundup(len, 4), hand);
+ xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.wreqb.tcode = FWTCODE_WREQB;
- fp->mode.wreqb.dst = htons(xfer->dst);
- fp->mode.wreqb.dest_hi = htons(dst_hi);
- fp->mode.wreqb.dest_lo = htonl(dst_lo);
- fp->mode.wreqb.len = htons(len);
+ fp->mode.wreqb.dst = xfer->dst;
+ fp->mode.wreqb.dest_hi = dst_hi;
+ fp->mode.wreqb.dest_lo = dst_lo;
+ fp->mode.wreqb.len = len;
bcopy(data, &fp->mode.wreqb.payload[0], len);
if (fwmem_debug)
@@ -252,7 +241,8 @@ fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
{
struct fw_eui64 *eui;
- eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64), M_FW, 0);
+ eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
+ M_FW, M_WAITOK);
if (eui == NULL)
return ENOMEM;
bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
@@ -310,8 +300,7 @@ fwmem_read (dev_t dev, struct uio *uio, int ioflag)
else if (xfer->resp != 0)
err = xfer->resp;
else if (err == 0)
- err = uiomove(xfer->recv.buf
- + xfer->recv.off + 4*3, 4, uio);
+ err = uiomove(xfer->recv.buf + 4*3, 4, uio);
} else {
if (len > MAXLEN)
len = MAXLEN;
@@ -327,8 +316,7 @@ fwmem_read (dev_t dev, struct uio *uio, int ioflag)
else if (xfer->resp != 0)
err = xfer->resp;
else if (err == 0)
- err = uiomove(xfer->recv.buf
- + xfer->recv.off + 4*4, len, uio);
+ err = uiomove(xfer->recv.buf + 4*4, len, uio);
}
fw_xfer_free(xfer);
}
@@ -357,7 +345,7 @@ fwmem_write (dev_t dev, struct uio *uio, int ioflag)
return EINVAL;
}
- data = malloc(MAXLEN, M_FW, 0);
+ data = malloc(MAXLEN, M_FW, M_WAITOK);
if (data == NULL)
return ENOMEM;
@@ -421,10 +409,10 @@ fwmem_poll (dev_t dev, int events, fw_proc *td)
return EINVAL;
}
int
-#if __FreeBSD_version < 500000
+#if __FreeBSD_version < 500102
fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
#else
-fwmem_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
+fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
#endif
{
return EINVAL;
diff --git a/sys/dev/firewire/fwmem.h b/sys/dev/firewire/fwmem.h
index 0e2e83c..0567f81 100644
--- a/sys/dev/firewire/fwmem.h
+++ b/sys/dev/firewire/fwmem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (C) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c
index 1f45cb9..3d759f9 100644
--- a/sys/dev/firewire/fwohci.c
+++ b/sys/dev/firewire/fwohci.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -51,11 +52,11 @@
#include <sys/socketvar.h>
#include <sys/signalvar.h>
#include <sys/malloc.h>
-#include <sys/uio.h>
#include <sys/sockio.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/conf.h>
+#include <sys/endian.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -65,12 +66,10 @@
#include <machine/clock.h>
#include <pci/pcivar.h>
#include <pci/pcireg.h>
-#include <vm/vm.h>
-#include <vm/vm_extern.h>
-#include <vm/pmap.h> /* for vtophys proto */
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
#include <dev/firewire/fwohcireg.h>
#include <dev/firewire/fwohcivar.h>
#include <dev/firewire/firewire_phy.h>
@@ -81,8 +80,10 @@
static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL",
"STOR","LOAD","NOP ","STOP",};
+
static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3",
"UNDEF","REG","SYS","DEV"};
+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",
@@ -92,9 +93,9 @@ char fwohcicode[32][0x20]={
"ack busy_X","ack busy_A","ack busy_B","Undef",
"Undef","Undef","Undef","ack tardy",
"Undef","ack data_err","ack type_err",""};
+
#define MAX_SPEED 2
extern char linkspeed[MAX_SPEED+1][0x10];
-static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"};
u_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
static struct tcode_info tinfo[] = {
@@ -124,40 +125,40 @@ static struct tcode_info tinfo[] = {
#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r))
static void fwohci_ibr __P((struct firewire_comm *));
-static void fwohci_db_init __P((struct fwohci_dbch *));
+static void fwohci_db_init __P((struct fwohci_softc *, struct fwohci_dbch *));
static void fwohci_db_free __P((struct fwohci_dbch *));
static void fwohci_arcv __P((struct fwohci_softc *, struct fwohci_dbch *, int));
-static void fwohci_ircv __P((struct fwohci_softc *, struct fwohci_dbch *, int));
static void fwohci_txd __P((struct fwohci_softc *, struct fwohci_dbch *));
static void fwohci_start_atq __P((struct firewire_comm *));
static void fwohci_start_ats __P((struct firewire_comm *));
static void fwohci_start __P((struct fwohci_softc *, struct fwohci_dbch *));
-static void fwohci_drain_atq __P((struct firewire_comm *, struct fw_xfer *));
-static void fwohci_drain_ats __P((struct firewire_comm *, struct fw_xfer *));
-static void fwohci_drain __P((struct firewire_comm *, struct fw_xfer *, struct fwohci_dbch *));
static u_int32_t fwphy_wrdata __P(( struct fwohci_softc *, u_int32_t, u_int32_t));
static u_int32_t fwphy_rddata __P(( struct fwohci_softc *, u_int32_t));
static int fwohci_rx_enable __P((struct fwohci_softc *, struct fwohci_dbch *));
static int fwohci_tx_enable __P((struct fwohci_softc *, struct fwohci_dbch *));
static int fwohci_irx_enable __P((struct firewire_comm *, int));
-static int fwohci_irxpp_enable __P((struct firewire_comm *, int));
-static int fwohci_irxbuf_enable __P((struct firewire_comm *, int));
static int fwohci_irx_disable __P((struct firewire_comm *, int));
+#if BYTE_ORDER == BIG_ENDIAN
static void fwohci_irx_post __P((struct firewire_comm *, u_int32_t *));
+#endif
static int fwohci_itxbuf_enable __P((struct firewire_comm *, int));
static int fwohci_itx_disable __P((struct firewire_comm *, int));
static void fwohci_timeout __P((void *));
static void fwohci_poll __P((struct firewire_comm *, int, int));
static void fwohci_set_intr __P((struct firewire_comm *, int));
-static int fwohci_add_rx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *, void *));
-static int fwohci_add_tx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *));
+
+static int fwohci_add_rx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *));
+static int fwohci_add_tx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int));
static void dump_db __P((struct fwohci_softc *, u_int32_t));
-static void print_db __P((volatile struct fwohcidb *, u_int32_t , u_int32_t));
+static void print_db __P((struct fwohcidb_tr *, volatile struct fwohcidb *, u_int32_t , u_int32_t));
static void dump_dma __P((struct fwohci_softc *, u_int32_t));
static u_int32_t fwohci_cyctimer __P((struct firewire_comm *));
static void fwohci_rbuf_update __P((struct fwohci_softc *, int));
static void fwohci_tbuf_update __P((struct fwohci_softc *, int));
void fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *));
+#if FWOHCI_TASKQUEUE
+static void fwohci_complete(void *, int);
+#endif
/*
* memory allocated for DMA programs
@@ -198,6 +199,7 @@ void fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *));
#define OHCI_SID_BUF 0x64
#define OHCI_SID_CNT 0x68
+#define OHCI_SID_ERR (1 << 31)
#define OHCI_SID_CNT_MASK 0xffc
#define OHCI_IT_STAT 0x90
@@ -411,10 +413,6 @@ fwohci_probe_phy(struct fwohci_softc *sc, device_t dev)
* It is not actually available port on your PC .
*/
OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
-#if 0
- /* XXX wait for SCLK. */
- DELAY(100000);
-#endif
reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
if((reg >> 5) != 7 ){
@@ -533,10 +531,10 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev)
/* Initialize registers */
OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]);
- OWRITE(sc, OHCI_CROMPTR, vtophys(&sc->fc.config_rom[0]));
+ OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr);
OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND);
OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
- OWRITE(sc, OHCI_SID_BUF, vtophys(sc->fc.sid_buf));
+ OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
fw_busreset(&sc->fc);
@@ -583,6 +581,10 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
u_int32_t reg;
u_int8_t ui[8];
+#if FWOHCI_TASKQUEUE
+ TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
+#endif
+
reg = OREAD(sc, OHCI_VERSION);
device_printf(dev, "OHCI version %x.%x (ROM=%d)\n",
(reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1);
@@ -604,15 +606,20 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
sc->fc.atq = &sc->atrq.xferq;
sc->fc.ats = &sc->atrs.xferq;
+ sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
+ sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
+ sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
+ sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
+
sc->arrq.xferq.start = NULL;
sc->arrs.xferq.start = NULL;
sc->atrq.xferq.start = fwohci_start_atq;
sc->atrs.xferq.start = fwohci_start_ats;
- sc->arrq.xferq.drain = NULL;
- sc->arrs.xferq.drain = NULL;
- sc->atrq.xferq.drain = fwohci_drain_atq;
- sc->atrs.xferq.drain = fwohci_drain_ats;
+ sc->arrq.xferq.buf = NULL;
+ sc->arrs.xferq.buf = NULL;
+ sc->atrq.xferq.buf = NULL;
+ sc->atrs.xferq.buf = NULL;
sc->arrq.ndesc = 1;
sc->arrs.ndesc = 1;
@@ -624,10 +631,6 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
sc->atrq.ndb = NDB;
sc->atrs.ndb = NDB / 2;
- sc->arrq.dummy = NULL;
- sc->arrs.dummy = NULL;
- sc->atrq.dummy = NULL;
- sc->atrs.dummy = NULL;
for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
sc->fc.it[i] = &sc->it[i].xferq;
sc->fc.ir[i] = &sc->ir[i].xferq;
@@ -636,16 +639,16 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
}
sc->fc.tcode = tinfo;
+ sc->fc.dev = dev;
- sc->cromptr = (u_int32_t *) malloc(CROMSIZE * 2, M_FW, M_NOWAIT);
-
- if(sc->cromptr == NULL){
- device_printf(dev, "cromptr alloc failed.");
+ sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE,
+ &sc->crom_dma, BUS_DMA_WAITOK);
+ if(sc->fc.config_rom == NULL){
+ device_printf(dev, "config_rom alloc failed.");
return ENOMEM;
}
- sc->fc.dev = dev;
- sc->fc.config_rom = &(sc->cromptr[CROMSIZE/4]);
+#if 1
sc->fc.config_rom[1] = 0x31333934;
sc->fc.config_rom[2] = 0xf000a002;
sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
@@ -654,34 +657,39 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
sc->fc.config_rom[0] = (4 << 24) | (5 << 16);
sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4);
+#endif
/* SID recieve buffer must allign 2^11 */
#define OHCI_SIDSIZE (1 << 11)
- sc->fc.sid_buf = (u_int32_t *) malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
- if (sc->fc.sid_buf == NULL) {
- device_printf(dev, "sid_buf alloc failed.\n");
+ sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE,
+ &sc->sid_dma, BUS_DMA_WAITOK);
+ if (sc->sid_buf == NULL) {
+ device_printf(dev, "sid_buf alloc failed.");
return ENOMEM;
}
- if (((vm_offset_t) sc->fc.sid_buf & (OHCI_SIDSIZE - 1)) != 0) {
- device_printf(dev, "sid_buf(%p) not aligned.\n",
- sc->fc.sid_buf);
+
+ fwdma_malloc(&sc->fc, sizeof(u_int32_t), sizeof(u_int32_t),
+ &sc->dummy_dma, BUS_DMA_WAITOK);
+
+ if (sc->dummy_dma.v_addr == NULL) {
+ device_printf(dev, "dummy_dma alloc failed.");
return ENOMEM;
}
-
- fwohci_db_init(&sc->arrq);
+
+ fwohci_db_init(sc, &sc->arrq);
if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
- fwohci_db_init(&sc->arrs);
+ fwohci_db_init(sc, &sc->arrs);
if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
- fwohci_db_init(&sc->atrq);
+ fwohci_db_init(sc, &sc->atrq);
if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
- fwohci_db_init(&sc->atrs);
+ fwohci_db_init(sc, &sc->atrs);
if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
@@ -701,12 +709,18 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
sc->fc.itx_enable = fwohci_itxbuf_enable;
sc->fc.itx_disable = fwohci_itx_disable;
+#if BYTE_ORDER == BIG_ENDIAN
sc->fc.irx_post = fwohci_irx_post;
+#else
+ sc->fc.irx_post = NULL;
+#endif
sc->fc.itx_post = NULL;
sc->fc.timeout = fwohci_timeout;
sc->fc.poll = fwohci_poll;
sc->fc.set_intr = fwohci_set_intr;
+ sc->intmask = sc->irstat = sc->itstat = 0;
+
fw_init(&sc->fc);
fwohci_reset(sc, dev);
@@ -733,10 +747,10 @@ fwohci_detach(struct fwohci_softc *sc, device_t dev)
{
int i;
- if (sc->fc.sid_buf != NULL)
- free((void *)(uintptr_t)sc->fc.sid_buf, M_FW);
- if (sc->cromptr != NULL)
- free((void *)sc->cromptr, M_FW);
+ if (sc->sid_buf != NULL)
+ fwdma_free(&sc->fc, &sc->sid_dma);
+ if (sc->fc.config_rom != NULL)
+ fwdma_free(&sc->fc, &sc->crom_dma);
fwohci_db_free(&sc->arrq);
fwohci_db_free(&sc->arrs);
@@ -759,10 +773,42 @@ fwohci_detach(struct fwohci_softc *sc, device_t dev)
} while (0)
static void
+fwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct fwohcidb_tr *db_tr;
+ volatile struct fwohcidb *db;
+ bus_dma_segment_t *s;
+ int i;
+
+ db_tr = (struct fwohcidb_tr *)arg;
+ db = &db_tr->db[db_tr->dbcnt];
+ if (error) {
+ if (firewire_debug || error != EFBIG)
+ printf("fwohci_execute_db: error=%d\n", error);
+ return;
+ }
+ for (i = 0; i < nseg; i++) {
+ s = &segs[i];
+ FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr);
+ FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len);
+ FWOHCI_DMA_WRITE(db->db.desc.res, 0);
+ db++;
+ db_tr->dbcnt++;
+ }
+}
+
+static void
+fwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg,
+ bus_size_t size, int error)
+{
+ fwohci_execute_db(arg, segs, nseg, error);
+}
+
+static void
fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
{
int i, s;
- int tcode, hdr_len, hdr_off, len;
+ int tcode, hdr_len, pl_off, pl_len;
int fsegment = -1;
u_int32_t off;
struct fw_xfer *xfer;
@@ -770,7 +816,6 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
volatile struct fwohci_txpkthdr *ohcifp;
struct fwohcidb_tr *db_tr;
volatile struct fwohcidb *db;
- struct mbuf *m;
struct tcode_info *info;
static int maxdesc=0;
@@ -798,98 +843,96 @@ txloop:
STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
db_tr->xfer = xfer;
xfer->state = FWXF_START;
- dbch->xferq.packets++;
- fp = (struct fw_pkt *)(xfer->send.buf + xfer->send.off);
+ fp = (struct fw_pkt *)xfer->send.buf;
tcode = fp->mode.common.tcode;
ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
info = &tinfo[tcode];
- hdr_len = hdr_off = info->hdr_len;
- /* fw_asyreq must pass valid send.len */
- len = xfer->send.len;
- for( i = 0 ; i < hdr_off ; i+= 4){
- ohcifp->mode.ld[i/4] = ntohl(fp->mode.ld[i/4]);
- }
- /* XXX payload must be network byte order */
- if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ) {
- ohcifp->mode.ld[3] = htonl(ohcifp->mode.ld[3]);
+ hdr_len = pl_off = info->hdr_len;
+ for( i = 0 ; i < pl_off ; i+= 4){
+ ohcifp->mode.ld[i/4] = fp->mode.ld[i/4];
}
ohcifp->mode.common.spd = xfer->spd;
if (tcode == FWTCODE_STREAM ){
hdr_len = 8;
- ohcifp->mode.stream.len = ntohs(fp->mode.stream.len);
+ ohcifp->mode.stream.len = fp->mode.stream.len;
} else if (tcode == FWTCODE_PHY) {
hdr_len = 12;
- ohcifp->mode.ld[1] = ntohl(fp->mode.ld[1]);
- ohcifp->mode.ld[2] = ntohl(fp->mode.ld[2]);
+ ohcifp->mode.ld[1] = fp->mode.ld[1];
+ ohcifp->mode.ld[2] = fp->mode.ld[2];
ohcifp->mode.common.spd = 0;
ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
} else {
- ohcifp->mode.asycomm.dst = ntohs(fp->mode.hdr.dst);
+ ohcifp->mode.asycomm.dst = fp->mode.hdr.dst;
ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS;
ohcifp->mode.asycomm.tlrt |= FWRETRY_X;
}
db = &db_tr->db[0];
- db->db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2;
- db->db.desc.reqcount = hdr_len;
- db->db.desc.status = 0;
+ FWOHCI_DMA_WRITE(db->db.desc.cmd,
+ OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
+ FWOHCI_DMA_WRITE(db->db.desc.res, 0);
/* Specify bound timer of asy. responce */
if(&sc->atrs == dbch){
- db->db.desc.count
- = (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13);
+ FWOHCI_DMA_WRITE(db->db.desc.res,
+ (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13));
}
+#if BYTE_ORDER == BIG_ENDIAN
+ if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
+ hdr_len = 12;
+ for (i = 0; i < hdr_len/4; i ++)
+ FWOHCI_DMA_WRITE(ohcifp->mode.ld[i], ohcifp->mode.ld[i]);
+#endif
again:
db_tr->dbcnt = 2;
db = &db_tr->db[db_tr->dbcnt];
- if(len > hdr_off){
+ pl_len = xfer->send.len - pl_off;
+ if (pl_len > 0) {
+ int err;
+ /* handle payload */
if (xfer->mbuf == NULL) {
- db->db.desc.addr
- = vtophys(xfer->send.buf + xfer->send.off) + hdr_off;
- db->db.desc.control = OHCI_OUTPUT_MORE;
- db->db.desc.reqcount = len - hdr_off;
- db->db.desc.status = 0;
+ caddr_t pl_addr;
- db_tr->dbcnt++;
+ pl_addr = xfer->send.buf + pl_off;
+ err = bus_dmamap_load(dbch->dmat, db_tr->dma_map,
+ pl_addr, pl_len,
+ fwohci_execute_db, db_tr,
+ /*flags*/0);
} else {
- int mchain=0;
/* XXX we can handle only 6 (=8-2) mbuf chains */
- for (m = xfer->mbuf; m != NULL; m = m->m_next) {
- if (m->m_len == 0)
- /* unrecoverable error could occur. */
- continue;
- mchain++;
- if (db_tr->dbcnt >= dbch->ndesc)
- continue;
- db->db.desc.addr
- = vtophys(mtod(m, caddr_t));
- db->db.desc.control = OHCI_OUTPUT_MORE;
- db->db.desc.reqcount = m->m_len;
- db->db.desc.status = 0;
- db++;
- db_tr->dbcnt++;
- }
- if (mchain > dbch->ndesc - 2) {
- struct mbuf *m_new;
- if (bootverbose)
- device_printf(sc->fc.dev,
- "too long mbuf chain(%d)\n",
- mchain);
- m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- if (m_new != NULL) {
+ err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
+ xfer->mbuf,
+ fwohci_execute_db2, db_tr,
+ /* flags */0);
+ if (err == EFBIG) {
+ struct mbuf *m0;
+
+ if (firewire_debug)
+ device_printf(sc->fc.dev, "EFBIG.\n");
+ m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m0 != NULL) {
m_copydata(xfer->mbuf, 0,
xfer->mbuf->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len =
+ mtod(m0, caddr_t));
+ m0->m_len = m0->m_pkthdr.len =
xfer->mbuf->m_pkthdr.len;
m_freem(xfer->mbuf);
- xfer->mbuf = m_new;
+ xfer->mbuf = m0;
goto again;
}
device_printf(sc->fc.dev, "m_getcl failed.\n");
}
}
+ if (err)
+ printf("dmamap_load: err=%d\n", err);
+ bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
+ BUS_DMASYNC_PREWRITE);
+#if 0 /* OHCI_OUTPUT_MODE == 0 */
+ for (i = 2; i < db_tr->dbcnt; i++)
+ FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd,
+ OHCI_OUTPUT_MORE);
+#endif
}
if (maxdesc < db_tr->dbcnt) {
maxdesc = db_tr->dbcnt;
@@ -898,16 +941,16 @@ again:
}
/* last db */
LAST_DB(db_tr, db);
- db->db.desc.control |= OHCI_OUTPUT_LAST
- | OHCI_INTERRUPT_ALWAYS
- | OHCI_BRANCH_ALWAYS;
- db->db.desc.depend = vtophys(STAILQ_NEXT(db_tr, link)->db);
+ FWOHCI_DMA_SET(db->db.desc.cmd,
+ OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
+ FWOHCI_DMA_WRITE(db->db.desc.depend,
+ STAILQ_NEXT(db_tr, link)->bus_addr);
if(fsegment == -1 )
fsegment = db_tr->dbcnt;
if (dbch->pdb_tr != NULL) {
LAST_DB(dbch->pdb_tr, db);
- db->db.desc.depend |= db_tr->dbcnt;
+ FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
}
dbch->pdb_tr = db_tr;
db_tr = STAILQ_NEXT(db_tr, link);
@@ -919,6 +962,8 @@ again:
}
kick:
/* kick asy q */
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
if(dbch->xferq.flag & FWXFERQ_RUNNING) {
OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
@@ -926,7 +971,7 @@ kick:
if (bootverbose)
device_printf(sc->fc.dev, "start AT DMA status=%x\n",
OREAD(sc, OHCI_DMACTL(off)));
- OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | fsegment);
+ OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment);
OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
dbch->xferq.flag |= FWXFERQ_RUNNING;
}
@@ -937,22 +982,6 @@ kick:
}
static void
-fwohci_drain_atq(struct firewire_comm *fc, struct fw_xfer *xfer)
-{
- struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- fwohci_drain(&sc->fc, xfer, &(sc->atrq));
- return;
-}
-
-static void
-fwohci_drain_ats(struct firewire_comm *fc, struct fw_xfer *xfer)
-{
- struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- fwohci_drain(&sc->fc, xfer, &(sc->atrs));
- return;
-}
-
-static void
fwohci_start_atq(struct firewire_comm *fc)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
@@ -971,44 +1000,52 @@ fwohci_start_ats(struct firewire_comm *fc)
void
fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
{
- int s, err = 0;
+ int s, ch, err = 0;
struct fwohcidb_tr *tr;
volatile struct fwohcidb *db;
struct fw_xfer *xfer;
u_int32_t off;
- u_int stat;
+ u_int stat, status;
int packets;
struct firewire_comm *fc = (struct firewire_comm *)sc;
+
if(&sc->atrq == dbch){
off = OHCI_ATQOFF;
+ ch = ATRQ_CH;
}else if(&sc->atrs == dbch){
off = OHCI_ATSOFF;
+ ch = ATRS_CH;
}else{
return;
}
s = splfw();
tr = dbch->bottom;
packets = 0;
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
while(dbch->xferq.queued > 0){
LAST_DB(tr, db);
- if(!(db->db.desc.status & OHCI_CNTL_DMA_ACTIVE)){
+ status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
+ if(!(status & OHCI_CNTL_DMA_ACTIVE)){
if (fc->status != FWBUSRESET)
/* maybe out of order?? */
goto out;
}
- if(db->db.desc.status & OHCI_CNTL_DMA_DEAD) {
-#ifdef OHCI_DEBUG
- dump_dma(sc, ch);
- dump_db(sc, ch);
+ bus_dmamap_sync(dbch->dmat, tr->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(dbch->dmat, tr->dma_map);
+#if 0
+ dump_db(sc, ch);
#endif
-/* Stop DMA */
+ if(status & OHCI_CNTL_DMA_DEAD) {
+ /* Stop DMA */
OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
device_printf(sc->fc.dev, "force reset AT FIFO\n");
OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN);
OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN);
OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
}
- stat = db->db.desc.status & FWOHCIEV_MASK;
+ stat = status & FWOHCIEV_MASK;
switch(stat){
case FWOHCIEV_ACKPEND:
case FWOHCIEV_ACKCOMPL:
@@ -1043,36 +1080,32 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
}
if (tr->xfer != NULL) {
xfer = tr->xfer;
+ if (xfer->state == FWXF_RCVD) {
+ if (firewire_debug)
+ printf("already rcvd\n");
+ fw_xfer_done(xfer);
+ } else {
xfer->state = FWXF_SENT;
if (err == EBUSY && fc->status != FWBUSRESET) {
xfer->state = FWXF_BUSY;
- switch (xfer->act_type) {
- case FWACT_XFER:
- xfer->resp = err;
- if (xfer->retry_req != NULL)
- xfer->retry_req(xfer);
- else
- fw_xfer_done(xfer);
- break;
- default:
- break;
- }
+ xfer->resp = err;
+ if (xfer->retry_req != NULL)
+ xfer->retry_req(xfer);
+ else
+ fw_xfer_done(xfer);
} else if (stat != FWOHCIEV_ACKPEND) {
if (stat != FWOHCIEV_ACKCOMPL)
xfer->state = FWXF_SENTERR;
xfer->resp = err;
- switch (xfer->act_type) {
- case FWACT_XFER:
- fw_xfer_done(xfer);
- break;
- default:
- break;
- }
+ fw_xfer_done(xfer);
+ }
}
/*
* The watchdog timer takes care of split
* transcation timeout for ACKPEND case.
*/
+ } else {
+ printf("this shouldn't happen\n");
}
dbch->xferq.queued --;
tr->xfer = NULL;
@@ -1097,117 +1130,88 @@ out:
}
static void
-fwohci_drain(struct firewire_comm *fc, struct fw_xfer *xfer, struct fwohci_dbch *dbch)
-{
- int i, s, found=0;
- struct fwohcidb_tr *tr;
-
- if(xfer->state != FWXF_START) return;
-
- s = splfw();
- tr = dbch->bottom;
- for (i = 0; i < dbch->xferq.queued; i ++) {
- if(tr->xfer == xfer){
- tr->xfer = NULL;
-#if 0
- dbch->xferq.queued --;
- /* XXX */
- if (tr == dbch->bottom)
- dbch->bottom = STAILQ_NEXT(tr, link);
- if (dbch->flags & FWOHCI_DBCH_FULL) {
- printf("fwohci_drain: make slot\n");
- dbch->flags &= ~FWOHCI_DBCH_FULL;
- fwohci_start((struct fwohci_softc *)fc, dbch);
- }
-#endif
- found ++;
- break;
- }
- tr = STAILQ_NEXT(tr, link);
- }
- splx(s);
- if (!found)
- device_printf(fc->dev, "fwochi_drain: xfer not found\n");
- return;
-}
-
-static void
fwohci_db_free(struct fwohci_dbch *dbch)
{
struct fwohcidb_tr *db_tr;
- int idb, i;
+ int idb;
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
return;
- if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){
- for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0;
- idb < dbch->ndb;
+ for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb;
db_tr = STAILQ_NEXT(db_tr, link), idb++){
- if (db_tr->buf != NULL) {
- free(db_tr->buf, M_FW);
- db_tr->buf = NULL;
- }
- }
+ if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 &&
+ db_tr->buf != NULL) {
+ fwdma_free_size(dbch->dmat, db_tr->dma_map,
+ db_tr->buf, dbch->xferq.psize);
+ db_tr->buf = NULL;
+ } else if (db_tr->dma_map != NULL)
+ bus_dmamap_destroy(dbch->dmat, db_tr->dma_map);
}
dbch->ndb = 0;
db_tr = STAILQ_FIRST(&dbch->db_trq);
- for (i = 0; i < dbch->npages; i++)
- free(dbch->pages[i], M_FW);
+ fwdma_free_multiseg(dbch->am);
free(db_tr, M_FW);
STAILQ_INIT(&dbch->db_trq);
dbch->flags &= ~FWOHCI_DBCH_INIT;
}
static void
-fwohci_db_init(struct fwohci_dbch *dbch)
+fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
{
int idb;
struct fwohcidb_tr *db_tr;
- int ndbpp, i, j;
if ((dbch->flags & FWOHCI_DBCH_INIT) != 0)
goto out;
+ /* create dma_tag for buffers */
+#define MAX_REQCOUNT 0xffff
+ if (bus_dma_tag_create(/*parent*/ sc->fc.dmat,
+ /*alignment*/ 1, /*boundary*/ 0,
+ /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/ BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/ dbch->xferq.psize,
+ /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1,
+ /*maxsegsz*/ MAX_REQCOUNT,
+ /*flags*/ 0, &dbch->dmat))
+ return;
+
/* allocate DB entries and attach one to each DMA channels */
/* DB entry must start at 16 bytes bounary. */
STAILQ_INIT(&dbch->db_trq);
db_tr = (struct fwohcidb_tr *)
malloc(sizeof(struct fwohcidb_tr) * dbch->ndb,
- M_FW, M_ZERO);
+ M_FW, M_WAITOK | M_ZERO);
if(db_tr == NULL){
printf("fwohci_db_init: malloc(1) failed\n");
return;
}
- ndbpp = PAGE_SIZE / (sizeof(struct fwohcidb) * dbch->ndesc);
- dbch->npages = (dbch->ndb + ndbpp - 1)/ ndbpp;
- if (firewire_debug)
- printf("ndesc: %d, ndbpp: %d, ndb: %d, npages: %d\n",
- dbch->ndesc, ndbpp, dbch->ndb, dbch->npages);
- if (dbch->npages > FWOHCI_DBCH_MAX_PAGES) {
- printf("npages(%d) > DBCH_MAX_PAGES(%d)\n",
- dbch->npages, FWOHCI_DBCH_MAX_PAGES);
+#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc)
+ dbch->am = fwdma_malloc_multiseg(&sc->fc, DB_SIZE(dbch),
+ DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK);
+ if (dbch->am == NULL) {
+ printf("fwohci_db_init: fwdma_malloc_multiseg failed\n");
return;
}
- for (i = 0; i < dbch->npages; i++) {
- dbch->pages[i] = malloc(PAGE_SIZE, M_FW, M_ZERO);
- if (dbch->pages[i] == NULL) {
- printf("fwohci_db_init: malloc(2) failed\n");
- for (j = 0; j < i; j ++)
- free(dbch->pages[j], M_FW);
- free(db_tr, M_FW);
- return;
- }
- }
/* Attach DB to DMA ch. */
for(idb = 0 ; idb < dbch->ndb ; idb++){
db_tr->dbcnt = 0;
- db_tr->db = (struct fwohcidb *)dbch->pages[idb/ndbpp]
- + dbch->ndesc * (idb % ndbpp);
+ db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb);
+ db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb);
+ /* create dmamap for buffers */
+ /* XXX do we need 4bytes alignment tag? */
+ /* XXX don't alloc dma_map for AR */
+ if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) {
+ printf("bus_dmamap_create failed\n");
+ dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
+ fwohci_db_free(dbch);
+ return;
+ }
STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link);
- if (!(dbch->xferq.flag & FWXFERQ_PACKET) &&
- dbch->xferq.bnpacket != 0) {
+ if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
if (idb % dbch->xferq.bnpacket == 0)
dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
].start = (caddr_t)db_tr;
@@ -1220,9 +1224,6 @@ fwohci_db_init(struct fwohci_dbch *dbch)
STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next
= STAILQ_FIRST(&dbch->db_trq);
out:
- dbch->frag.buf = NULL;
- dbch->frag.len = 0;
- dbch->frag.plen = 0;
dbch->xferq.queued = 0;
dbch->pdb_tr = NULL;
dbch->top = STAILQ_FIRST(&dbch->db_trq);
@@ -1234,13 +1235,14 @@ static int
fwohci_itx_disable(struct firewire_comm *fc, int dmach)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- int dummy;
+ int sleepch;
- OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
+ OWRITE(sc, OHCI_ITCTLCLR(dmach),
+ OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
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);
+ tsleep((void *)&sleepch, FWPRI, "fwitxd", hz);
fwohci_db_free(&sc->it[dmach]);
sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
return 0;
@@ -1250,81 +1252,32 @@ static int
fwohci_irx_disable(struct firewire_comm *fc, int dmach)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- int dummy;
+ int sleepch;
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_FW);
- }
- sc->ir[dmach].dummy = NULL;
+ tsleep((void *)&sleepch, FWPRI, "fwirxd", hz);
fwohci_db_free(&sc->ir[dmach]);
sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
return 0;
}
+#if BYTE_ORDER == BIG_ENDIAN
static void
fwohci_irx_post (struct firewire_comm *fc , u_int32_t *qld)
{
- qld[0] = ntohl(qld[0]);
+ qld[0] = FWOHCI_DMA_READ(qld[0]);
return;
}
-
-static int
-fwohci_irxpp_enable(struct firewire_comm *fc, int dmach)
-{
- struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- int err = 0;
- unsigned short tag, ich;
-
- tag = (sc->ir[dmach].xferq.flag >> 6) & 3;
- ich = sc->ir[dmach].xferq.flag & 0x3f;
-
-#if 0
- if(STAILQ_FIRST(&fc->ir[dmach]->q) != NULL){
- wakeup(fc->ir[dmach]);
- return err;
- }
#endif
- OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich);
- if(!(sc->ir[dmach].xferq.flag & FWXFERQ_RUNNING)){
- sc->ir[dmach].xferq.queued = 0;
- sc->ir[dmach].ndb = NDB;
- sc->ir[dmach].xferq.psize = PAGE_SIZE;
- sc->ir[dmach].ndesc = 1;
- fwohci_db_init(&sc->ir[dmach]);
- if ((sc->ir[dmach].flags & FWOHCI_DBCH_INIT) == 0)
- return ENOMEM;
- err = fwohci_rx_enable(sc, &sc->ir[dmach]);
- }
- if(err){
- device_printf(sc->fc.dev, "err in IRX setting\n");
- return err;
- }
- if(!(OREAD(sc, OHCI_IRCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE)){
- 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), 0xf8000000);
- OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR);
- OWRITE(sc, OHCI_IRCMD(dmach),
- vtophys(sc->ir[dmach].top->db) | 1);
- OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
- OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
- }
- return err;
-}
-
static int
fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
{
int err = 0;
- int idb, z, i, dmach = 0;
+ int idb, z, i, dmach = 0, ldesc;
u_int32_t off = NULL;
struct fwohcidb_tr *db_tr;
volatile struct fwohcidb *db;
@@ -1351,31 +1304,31 @@ fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
}
db_tr = dbch->top;
- for( idb = 0 ; idb < dbch->ndb ; idb ++){
- fwohci_add_tx_buf(db_tr,
- dbch->xferq.psize, dbch->xferq.flag,
- dbch->xferq.buf + dbch->xferq.psize * idb);
+ for (idb = 0; idb < dbch->ndb; idb ++) {
+ fwohci_add_tx_buf(dbch, db_tr, idb);
if(STAILQ_NEXT(db_tr, link) == NULL){
break;
}
db = db_tr->db;
- db[0].db.desc.depend = db[db_tr->dbcnt - 1].db.desc.depend
- = vtophys(STAILQ_NEXT(db_tr, link)->db) | z;
+ ldesc = db_tr->dbcnt - 1;
+ FWOHCI_DMA_WRITE(db[0].db.desc.depend,
+ STAILQ_NEXT(db_tr, link)->bus_addr | z);
+ db[ldesc].db.desc.depend = db[0].db.desc.depend;
if(dbch->xferq.flag & FWXFERQ_EXTBUF){
if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
- db[db_tr->dbcnt - 1].db.desc.control
- |= OHCI_INTERRUPT_ALWAYS;
+ FWOHCI_DMA_SET(
+ db[ldesc].db.desc.cmd,
+ OHCI_INTERRUPT_ALWAYS);
/* OHCI 1.1 and above */
- db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
-#if 0
- db[0].db.desc.depend &= ~0xf;
- db[db_tr->dbcnt - 1].db.desc.depend &= ~0xf;
-#endif
+ FWOHCI_DMA_SET(
+ db[0].db.desc.cmd,
+ OHCI_INTERRUPT_ALWAYS);
}
}
db_tr = STAILQ_NEXT(db_tr, link);
}
- dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0;
+ FWOHCI_DMA_CLEAR(
+ dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf);
return err;
}
@@ -1420,61 +1373,59 @@ fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
}
db_tr = dbch->top;
- for( idb = 0 ; idb < dbch->ndb ; idb ++){
- if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){
- fwohci_add_rx_buf(db_tr,
- dbch->xferq.psize, dbch->xferq.flag, 0, NULL);
- }else{
- fwohci_add_rx_buf(db_tr,
- dbch->xferq.psize, dbch->xferq.flag,
- dbch->xferq.bulkxfer[idb
- / dbch->xferq.bnpacket].buf
- + dbch->xferq.psize *
- (idb % dbch->xferq.bnpacket),
- dbch->dummy + sizeof(u_int32_t) * idb);
- }
- if(STAILQ_NEXT(db_tr, link) == NULL){
+ for (idb = 0; idb < dbch->ndb; idb ++) {
+ fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma);
+ if (STAILQ_NEXT(db_tr, link) == NULL)
break;
- }
db = db_tr->db;
ldesc = db_tr->dbcnt - 1;
- db[ldesc].db.desc.depend
- = vtophys(STAILQ_NEXT(db_tr, link)->db) | z;
+ FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend,
+ STAILQ_NEXT(db_tr, link)->bus_addr | z);
if(dbch->xferq.flag & FWXFERQ_EXTBUF){
if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
- db[ldesc].db.desc.control
- |= OHCI_INTERRUPT_ALWAYS;
- db[ldesc].db.desc.depend &= ~0xf;
+ FWOHCI_DMA_SET(
+ db[ldesc].db.desc.cmd,
+ OHCI_INTERRUPT_ALWAYS);
+ FWOHCI_DMA_CLEAR(
+ db[ldesc].db.desc.depend,
+ 0xf);
}
}
db_tr = STAILQ_NEXT(db_tr, link);
}
- dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0;
+ FWOHCI_DMA_CLEAR(
+ dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf);
dbch->buf_offset = 0;
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
if(dbch->xferq.flag & FWXFERQ_STREAM){
return err;
}else{
- OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | z);
+ OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z);
}
OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
return err;
}
static int
-fwochi_next_cycle(struct firewire_comm *fc, int cycle_now)
+fwohci_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
+#if 1
#define CYCLE_DELAY 8 /* min delay to start DMA */
+#else
+#define CYCLE_DELAY 7000 /* min delay to start DMA */
+#endif
cycle = cycle + CYCLE_DELAY;
if (cycle >= 8000) {
sec ++;
cycle -= 8000;
}
- cycle = ((cycle + CYCLE_MOD - 1) / CYCLE_MOD) * CYCLE_MOD;
+ cycle = roundup2(cycle, CYCLE_MOD);
if (cycle >= 8000) {
sec ++;
if (cycle == 8000)
@@ -1507,7 +1458,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
dbch->ndb = it->bnpacket * it->bnchunk;
dbch->ndesc = 3;
- fwohci_db_init(dbch);
+ fwohci_db_init(sc, dbch);
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
err = fwohci_tx_enable(sc, dbch);
@@ -1521,94 +1472,99 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
volatile struct fwohcidb *db;
+ fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
+ BUS_DMASYNC_PREWRITE);
fwohci_txbufdb(sc, dmach, chunk);
-#if 0
- 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;
-#endif
if (prev != NULL) {
db = ((struct fwohcidb_tr *)(prev->end))->db;
- db[ldesc].db.desc.control |= OHCI_BRANCH_ALWAYS;
+#if 0 /* XXX necessary? */
+ FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
+ OHCI_BRANCH_ALWAYS);
+#endif
#if 0 /* if bulkxfer->npacket changes */
db[ldesc].db.desc.depend = db[0].db.desc.depend =
- vtophys(((struct fwohcidb_tr *)
- (chunk->start))->db) | dbch->ndesc;
+ ((struct fwohcidb_tr *)
+ (chunk->start))->bus_addr | dbch->ndesc;
#else
- db[0].db.desc.depend |= dbch->ndesc;
- db[ldesc].db.desc.depend |= dbch->ndesc;
+ FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
+ FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
#endif
}
STAILQ_REMOVE_HEAD(&it->stvalid, link);
STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
prev = chunk;
}
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
splx(s);
stat = OREAD(sc, OHCI_ITCTL(dmach));
+ if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S))
+ printf("stat 0x%x\n", stat);
+
if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S))
return 0;
+#if 0
OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
+#endif
OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
OWRITE(sc, OHCI_IT_MASK, 1 << dmach);
+ OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT);
first = STAILQ_FIRST(&it->stdma);
- OWRITE(sc, OHCI_ITCMD(dmach), vtophys(((struct fwohcidb_tr *)
- (first->start))->db) | dbch->ndesc);
- if (firewire_debug)
+ OWRITE(sc, OHCI_ITCMD(dmach),
+ ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
+ if (firewire_debug) {
printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
+#if 1
+ dump_dma(sc, ITX_CH + dmach);
+#endif
+ }
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;
-
- db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start;
- fp = (struct fw_pkt *)db_tr->buf;
- dbch->xferq.dvoffset = CYCLE_OFFSET;
- fp->mode.ld[2] |= htonl(dbch->xferq.dvoffset << 12);
- }
-#endif
+#if 1
/* 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);
+ cycle_match = fwohci_next_cycle(fc, cycle_now);
OWRITE(sc, OHCI_ITCTL(dmach),
OHCI_CNTL_CYCMATCH_S | (cycle_match << 16)
| OHCI_CNTL_DMA_RUN);
- if (firewire_debug)
+#else
+ OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
+#endif
+ if (firewire_debug) {
printf("cycle_match: 0x%04x->0x%04x\n",
cycle_now, cycle_match);
+ dump_dma(sc, ITX_CH + dmach);
+ dump_db(sc, ITX_CH + dmach);
+ }
} else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) {
device_printf(sc->fc.dev,
"IT DMA underrun (0x%08x)\n", stat);
- OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
+ OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE);
}
out:
return err;
}
static int
-fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach)
+fwohci_irx_enable(struct firewire_comm *fc, int dmach)
{
struct fwohci_softc *sc = (struct fwohci_softc *)fc;
int err = 0, s, ldesc;
unsigned short tag, ich;
u_int32_t stat;
struct fwohci_dbch *dbch;
+ struct fwohcidb_tr *db_tr;
struct fw_bulkxfer *first, *prev, *chunk;
struct fw_xferq *ir;
@@ -1622,14 +1578,8 @@ fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach)
ir->queued = 0;
dbch->ndb = ir->bnpacket * ir->bnchunk;
- dbch->dummy = malloc(sizeof(u_int32_t) * dbch->ndb,
- M_FW, 0);
- if (dbch->dummy == NULL) {
- err = ENOMEM;
- return err;
- }
dbch->ndesc = 2;
- fwohci_db_init(dbch);
+ fwohci_db_init(sc, dbch);
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
return ENOMEM;
err = fwohci_rx_enable(sc, dbch);
@@ -1650,26 +1600,30 @@ fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach)
volatile struct fwohcidb *db;
#if 1 /* XXX for if_fwe */
- db = ((struct fwohcidb_tr *)(chunk->start))->db;
- db[ldesc].db.desc.addr = vtophys(chunk->buf);
+ if (chunk->mbuf != NULL) {
+ db_tr = (struct fwohcidb_tr *)(chunk->start);
+ db_tr->dbcnt = 1;
+ err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
+ chunk->mbuf, fwohci_execute_db2, db_tr,
+ /* flags */0);
+ FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd,
+ OHCI_UPDATE | OHCI_INPUT_LAST |
+ OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
+ }
#endif
db = ((struct fwohcidb_tr *)(chunk->end))->db;
- db[ldesc].db.desc.status = db[ldesc].db.desc.count = 0;
- db[ldesc].db.desc.depend &= ~0xf;
+ FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0);
+ FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
if (prev != NULL) {
db = ((struct fwohcidb_tr *)(prev->end))->db;
-#if 0
- db[ldesc].db.desc.depend =
- vtophys(((struct fwohcidb_tr *)
- (chunk->start))->db) | dbch->ndesc;
-#else
- db[ldesc].db.desc.depend |= dbch->ndesc;
-#endif
+ FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
}
STAILQ_REMOVE_HEAD(&ir->stfree, link);
STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
prev = chunk;
}
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
splx(s);
stat = OREAD(sc, OHCI_IRCTL(dmach));
if (stat & OHCI_CNTL_DMA_ACTIVE)
@@ -1679,34 +1633,24 @@ fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach)
device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat);
}
+ if (firewire_debug)
+ printf("start IR DMA 0x%x\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)
+ ((struct fwohcidb_tr *)(first->start))->bus_addr
| dbch->ndesc);
OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
+#if 0
+ dump_db(sc, IRX_CH + dmach);
+#endif
return err;
}
-static int
-fwohci_irx_enable(struct firewire_comm *fc, int dmach)
-{
- struct fwohci_softc *sc = (struct fwohci_softc *)fc;
- int err = 0;
-
- if(sc->ir[dmach].xferq.flag & FWXFERQ_PACKET){
- err = fwohci_irxpp_enable(fc, dmach);
- return err;
- }else{
- err = fwohci_irxbuf_enable(fc, dmach);
- return err;
- }
-}
-
int
fwohci_stop(struct fwohci_softc *sc, device_t dev)
{
@@ -1820,8 +1764,12 @@ busresetout:
#ifndef ACK_ALL
OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR);
#endif
- irstat = OREAD(sc, OHCI_IR_STAT);
- OWRITE(sc, OHCI_IR_STATCLR, irstat);
+#if __FreeBSD_version >= 500000
+ irstat = atomic_readandclear_int(&sc->irstat);
+#else
+ irstat = sc->irstat;
+ sc->irstat = 0;
+#endif
for(i = 0; i < fc->nisodma ; i++){
struct fwohci_dbch *dbch;
@@ -1832,11 +1780,7 @@ busresetout:
"dma(%d) not active\n", i);
continue;
}
- if (dbch->xferq.flag & FWXFERQ_PACKET) {
- fwohci_ircv(sc, dbch, count);
- } else {
- fwohci_rbuf_update(sc, i);
- }
+ fwohci_rbuf_update(sc, i);
}
}
}
@@ -1844,8 +1788,12 @@ busresetout:
#ifndef ACK_ALL
OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT);
#endif
- itstat = OREAD(sc, OHCI_IT_STAT);
- OWRITE(sc, OHCI_IT_STATCLR, itstat);
+#if __FreeBSD_version >= 500000
+ itstat = atomic_readandclear_int(&sc->itstat);
+#else
+ itstat = sc->itstat;
+ sc->itstat = 0;
+#endif
for(i = 0; i < fc->nisodma ; i++){
if((itstat & (1 << i)) != 0){
fwohci_tbuf_update(sc, i);
@@ -1873,7 +1821,7 @@ busresetout:
fwohci_arcv(sc, &sc->arrq, count);
}
if(stat & OHCI_INT_PHY_SID){
- caddr_t buf;
+ u_int32_t *buf, node_id;
int plen;
#ifndef ACK_ALL
@@ -1893,32 +1841,43 @@ busresetout:
** Checking whether the node is root or not. If root, turn on
** cycle master.
*/
- device_printf(fc->dev, "node_id = 0x%08x, ", OREAD(sc, FWOHCI_NODEID));
- if(!(OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_VALID)){
+ 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;
}
- if( OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_ROOT ){
+ if (node_id & OHCI_NODE_ROOT) {
printf("CYCLEMASTER mode\n");
OWRITE(sc, OHCI_LNKCTL,
OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
- }else{
+ } else {
printf("non CYCLEMASTER mode\n");
OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
}
- fc->nodeid = OREAD(sc, FWOHCI_NODEID) & 0x3f;
+ fc->nodeid = node_id & 0x3f;
- plen = OREAD(sc, OHCI_SID_CNT) & OHCI_SID_CNT_MASK;
+ 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 = malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
- if(buf == NULL) goto sidout;
- bcopy((void *)(uintptr_t)(volatile void *)(fc->sid_buf + 1),
- buf, plen);
+ buf = (u_int32_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
/* pending all pre-bus_reset packets */
fwohci_txd(sc, &sc->atrq);
@@ -1927,7 +1886,8 @@ busresetout:
fwohci_arcv(sc, &sc->arrq, -1);
fw_drain_txq(fc);
#endif
- fw_sidrcv(fc, buf, plen, 0);
+ fw_sidrcv(fc, buf, plen);
+ free(buf, M_FW);
}
sidout:
if((stat & OHCI_INT_DMA_ATRQ )){
@@ -1964,32 +1924,84 @@ sidout:
return;
}
+#if FWOHCI_TASKQUEUE
+static void
+fwohci_complete(void *arg, int pending)
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)arg;
+ u_int32_t stat;
+
+again:
+ stat = atomic_readandclear_int(&sc->intstat);
+ if (stat)
+ fwohci_intr_body(sc, stat, -1);
+ else
+ return;
+ goto again;
+}
+#endif
+
+static u_int32_t
+fwochi_check_stat(struct fwohci_softc *sc)
+{
+ u_int32_t stat, irstat, itstat;
+
+ stat = OREAD(sc, FWOHCI_INTSTAT);
+ if (stat == 0xffffffff) {
+ device_printf(sc->fc.dev,
+ "device physically ejected?\n");
+ return(stat);
+ }
+#ifdef ACK_ALL
+ if (stat)
+ OWRITE(sc, FWOHCI_INTSTATCLR, stat);
+#endif
+ if (stat & OHCI_INT_DMA_IR) {
+ irstat = OREAD(sc, OHCI_IR_STAT);
+ OWRITE(sc, OHCI_IR_STATCLR, irstat);
+ atomic_set_int(&sc->irstat, irstat);
+ }
+ if (stat & OHCI_INT_DMA_IT) {
+ itstat = OREAD(sc, OHCI_IT_STAT);
+ OWRITE(sc, OHCI_IT_STATCLR, itstat);
+ atomic_set_int(&sc->itstat, itstat);
+ }
+ return(stat);
+}
+
void
fwohci_intr(void *arg)
{
struct fwohci_softc *sc = (struct fwohci_softc *)arg;
- u_int32_t stat, bus_reset = 0;
+ u_int32_t stat;
+#if !FWOHCI_TASKQUEUE
+ u_int32_t bus_reset = 0;
+#endif
if (!(sc->intmask & OHCI_INT_EN)) {
/* polling mode */
return;
}
- while ((stat = OREAD(sc, FWOHCI_INTSTAT)) != 0) {
- if (stat == 0xffffffff) {
- device_printf(sc->fc.dev,
- "device physically ejected?\n");
- return;
- }
-#ifdef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, stat);
+#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
- /* 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);
- }
}
static void
@@ -2009,17 +2021,9 @@ fwohci_poll(struct firewire_comm *fc, int quick, int count)
#else
if (1) {
#endif
- stat = OREAD(sc, FWOHCI_INTSTAT);
- if (stat == 0)
- return;
- if (stat == 0xffffffff) {
- device_printf(sc->fc.dev,
- "device physically ejected?\n");
+ stat = fwochi_check_stat(sc);
+ if (stat == 0 || stat == 0xffffffff)
return;
- }
-#ifdef ACK_ALL
- OWRITE(sc, FWOHCI_INTSTATCLR, stat);
-#endif
}
s = splfw();
fwohci_intr_body(sc, stat, count);
@@ -2051,15 +2055,19 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
struct fw_bulkxfer *chunk;
struct fw_xferq *it;
u_int32_t stat, count;
- int s, w=0;
+ int s, w=0, ldesc;
it = fc->it[dmach];
+ ldesc = sc->it[dmach].ndesc - 1;
s = splfw(); /* unnecessary ? */
+ fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
db = ((struct fwohcidb_tr *)(chunk->end))->db;
- stat = db[sc->it[dmach].ndesc - 1].db.desc.status;
+ stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
+ >> OHCI_STATUS_SHIFT;
db = ((struct fwohcidb_tr *)(chunk->start))->db;
- count = db[sc->it[dmach].ndesc - 1].db.desc.count;
+ count = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
+ & OHCI_COUNT_MASK;
if (stat == 0)
break;
STAILQ_REMOVE_HEAD(&it->stdma, link);
@@ -2071,7 +2079,8 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
break;
default:
device_printf(fc->dev,
- "Isochronous transmit err %02x\n", stat);
+ "Isochronous transmit err %02x(%s)\n",
+ stat, fwohcicode[stat & 0x1f]);
}
STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
w++;
@@ -2085,19 +2094,38 @@ static void
fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
{
struct firewire_comm *fc = &sc->fc;
- volatile struct fwohcidb *db;
+ volatile struct fwohcidb_tr *db_tr;
struct fw_bulkxfer *chunk;
struct fw_xferq *ir;
u_int32_t stat;
- int s, w=0;
+ int s, w=0, ldesc;
ir = fc->ir[dmach];
+ ldesc = sc->ir[dmach].ndesc - 1;
+#if 0
+ dump_db(sc, dmach);
+#endif
s = splfw();
+ fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
- db = ((struct fwohcidb_tr *)(chunk->end))->db;
- stat = db[sc->ir[dmach].ndesc - 1].db.desc.status;
+ db_tr = (struct fwohcidb_tr *)chunk->end;
+ stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res)
+ >> OHCI_STATUS_SHIFT;
if (stat == 0)
break;
+
+ if (chunk->mbuf != NULL) {
+ bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map);
+ } else if (ir->buf != NULL) {
+ fwdma_sync_multiseg(ir->buf, chunk->poffset,
+ ir->bnpacket, BUS_DMASYNC_POSTREAD);
+ } else {
+ /* XXX */
+ printf("fwohci_rbuf_update: this shouldn't happend\n");
+ }
+
STAILQ_REMOVE_HEAD(&ir->stdma, link);
STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link);
switch (stat & FWOHCIEV_MASK) {
@@ -2107,7 +2135,8 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
default:
chunk->resp = EINVAL;
device_printf(fc->dev,
- "Isochronous receive err %02x\n", stat);
+ "Isochronous receive err %02x(%s)\n",
+ stat, fwohcicode[stat & 0x1f]);
}
w++;
}
@@ -2142,14 +2171,13 @@ dump_dma(struct fwohci_softc *sc, u_int32_t ch)
cmd = OREAD(sc, off + 0xc);
match = OREAD(sc, off + 0x10);
- device_printf(sc->fc.dev, "dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x \n",
+ device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n",
ch,
cntl,
- stat,
cmd,
match);
stat &= 0xffff ;
- if(stat & 0xff00){
+ if (stat) {
device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n",
ch,
stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
@@ -2170,7 +2198,7 @@ void
dump_db(struct fwohci_softc *sc, u_int32_t ch)
{
struct fwohci_dbch *dbch;
- struct fwohcidb_tr *cp = NULL, *pp, *np;
+ struct fwohcidb_tr *cp = NULL, *pp, *np = NULL;
volatile struct fwohcidb *curr = NULL, *prev, *next = NULL;
int idb, jdb;
u_int32_t cmd, off;
@@ -2212,10 +2240,8 @@ dump_db(struct fwohci_softc *sc, u_int32_t ch)
goto outdb;
}
np = STAILQ_NEXT(cp, link);
- if(cp == NULL) break;
for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){
- if((cmd & 0xfffffff0)
- == vtophys(&(cp->db[jdb]))){
+ if ((cmd & 0xfffffff0) == cp->bus_addr) {
curr = cp->db;
if(np != NULL){
next = np->db;
@@ -2230,12 +2256,16 @@ dump_db(struct fwohci_softc *sc, u_int32_t ch)
}
outdb:
if( curr != NULL){
+#if 0
printf("Prev DB %d\n", ch);
- print_db(prev, ch, dbch->ndesc);
+ print_db(pp, prev, ch, dbch->ndesc);
+#endif
printf("Current DB %d\n", ch);
- print_db(curr, ch, dbch->ndesc);
+ print_db(cp, curr, ch, dbch->ndesc);
+#if 0
printf("Next DB %d\n", ch);
- print_db(next, ch, dbch->ndesc);
+ print_db(np, next, ch, dbch->ndesc);
+#endif
}else{
printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd);
}
@@ -2243,10 +2273,12 @@ outdb:
}
void
-print_db(volatile struct fwohcidb *db, u_int32_t ch, u_int32_t max)
+print_db(struct fwohcidb_tr *db_tr, volatile struct fwohcidb *db,
+ u_int32_t ch, u_int32_t max)
{
fwohcireg_t stat;
int i, key;
+ u_int32_t cmd, res;
if(db == NULL){
printf("No Descriptor is found\n");
@@ -2266,23 +2298,25 @@ print_db(volatile struct fwohcidb *db, u_int32_t ch, u_int32_t max)
"Stat",
"Cnt");
for( i = 0 ; i <= max ; i ++){
- key = db[i].db.desc.control & OHCI_KEY_MASK;
+ cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd);
+ res = FWOHCI_DMA_READ(db[i].db.desc.res);
+ key = cmd & OHCI_KEY_MASK;
+ stat = res >> OHCI_STATUS_SHIFT;
#if __FreeBSD_version >= 500000
printf("%08tx %s %s %s %s %5d %08x %08x %04x:%04x",
#else
printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x",
#endif
- vtophys(&db[i]),
- dbcode[(db[i].db.desc.control >> 12) & 0xf],
- dbkey[(db[i].db.desc.control >> 8) & 0x7],
- dbcond[(db[i].db.desc.control >> 4) & 0x3],
- dbcond[(db[i].db.desc.control >> 2) & 0x3],
- db[i].db.desc.reqcount,
- db[i].db.desc.addr,
- db[i].db.desc.depend,
- db[i].db.desc.status,
- db[i].db.desc.count);
- stat = db[i].db.desc.status;
+ db_tr->bus_addr,
+ dbcode[(cmd >> 28) & 0xf],
+ dbkey[(cmd >> 24) & 0x7],
+ dbcond[(cmd >> 20) & 0x3],
+ dbcond[(cmd >> 18) & 0x3],
+ cmd & OHCI_COUNT_MASK,
+ FWOHCI_DMA_READ(db[i].db.desc.addr),
+ FWOHCI_DMA_READ(db[i].db.desc.depend),
+ stat,
+ res & OHCI_COUNT_MASK);
if(stat & 0xff00){
printf(" %s%s%s%s%s%s %s(%x)\n",
stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
@@ -2299,23 +2333,23 @@ print_db(volatile struct fwohcidb *db, u_int32_t ch, u_int32_t max)
}
if(key == OHCI_KEY_ST2 ){
printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
- db[i+1].db.immed[0],
- db[i+1].db.immed[1],
- db[i+1].db.immed[2],
- db[i+1].db.immed[3]);
+ FWOHCI_DMA_READ(db[i+1].db.immed[0]),
+ FWOHCI_DMA_READ(db[i+1].db.immed[1]),
+ FWOHCI_DMA_READ(db[i+1].db.immed[2]),
+ FWOHCI_DMA_READ(db[i+1].db.immed[3]));
}
if(key == OHCI_KEY_DEVICE){
return;
}
- if((db[i].db.desc.control & OHCI_BRANCH_MASK)
+ if((cmd & OHCI_BRANCH_MASK)
== OHCI_BRANCH_ALWAYS){
return;
}
- if((db[i].db.desc.control & OHCI_CMD_MASK)
+ if((cmd & OHCI_CMD_MASK)
== OHCI_OUTPUT_LAST){
return;
}
- if((db[i].db.desc.control & OHCI_CMD_MASK)
+ if((cmd & OHCI_CMD_MASK)
== OHCI_INPUT_LAST){
return;
}
@@ -2367,43 +2401,42 @@ fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
db_tr = (struct fwohcidb_tr *)(bulkxfer->start);
fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end);
/*
-device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), vtophys(fdb_tr->db));
+device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr);
*/
- for( idb = 0 ; idb < bulkxfer->npacket ; idb ++){
+ for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) {
db = db_tr->db;
-#if 0
- db[0].db.desc.control
- = OHCI_OUTPUT_MORE | OHCI_KEY_ST2;
- db[0].db.desc.reqcount = 8;
-#endif
fp = (struct fw_pkt *)db_tr->buf;
ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed;
- ohcifp->mode.ld[0] = ntohl(fp->mode.ld[0]);
- ohcifp->mode.stream.len = ntohs(fp->mode.stream.len);
+ ohcifp->mode.ld[0] = fp->mode.ld[0];
+ ohcifp->mode.stream.len = fp->mode.stream.len;
ohcifp->mode.stream.chtag = chtag;
ohcifp->mode.stream.tcode = 0xa;
ohcifp->mode.stream.spd = 0;
+#if BYTE_ORDER == BIG_ENDIAN
+ FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]);
+ FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]);
+#endif
- db[2].db.desc.reqcount = ntohs(fp->mode.stream.len);
- db[2].db.desc.status = 0;
- db[2].db.desc.count = 0;
+ FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK);
+ FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len);
+ FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
#if 0 /* if bulkxfer->npackets changes */
- db[2].db.desc.control = OHCI_OUTPUT_LAST
+ db[2].db.desc.cmd = OHCI_OUTPUT_LAST
| OHCI_UPDATE
| OHCI_BRANCH_ALWAYS;
db[0].db.desc.depend =
= db[dbch->ndesc - 1].db.desc.depend
- = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc;
+ = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc;
#else
- db[0].db.desc.depend |= dbch->ndesc;
- db[dbch->ndesc - 1].db.desc.depend |= dbch->ndesc;
+ FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
+ FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc);
#endif
bulkxfer->end = (caddr_t)db_tr;
db_tr = STAILQ_NEXT(db_tr, link);
}
db = ((struct fwohcidb_tr *)bulkxfer->end)->db;
- db[0].db.desc.depend &= ~0xf;
- db[dbch->ndesc - 1].db.desc.depend &= ~0xf;
+ FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf);
+ FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf);
#if 0 /* if bulkxfer->npackets changes */
db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
/* OHCI 1.1 and above */
@@ -2412,201 +2445,142 @@ device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), v
/*
db_tr = (struct fwohcidb_tr *)bulkxfer->start;
fdb_tr = (struct fwohcidb_tr *)bulkxfer->end;
-device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, vtophys(db_tr->db), vtophys(fdb_tr->db));
+device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr);
*/
return;
}
static int
-fwohci_add_tx_buf(struct fwohcidb_tr *db_tr, unsigned short size,
- int mode, void *buf)
+fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
+ int poffset)
{
volatile struct fwohcidb *db = db_tr->db;
+ struct fw_xferq *it;
int err = 0;
- if(buf == 0){
+
+ it = &dbch->xferq;
+ if(it->buf == 0){
err = EINVAL;
return err;
}
- db_tr->buf = buf;
+ db_tr->buf = fwdma_v_addr(it->buf, poffset);
db_tr->dbcnt = 3;
- db_tr->dummy = NULL;
- db[0].db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2;
- db[0].db.desc.reqcount = 8;
- db[2].db.desc.addr = vtophys(buf) + sizeof(u_int32_t);
- db[2].db.desc.control =
- OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS;
+ FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
+ OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
+ FWOHCI_DMA_WRITE(db[2].db.desc.addr,
+ fwdma_bus_addr(it->buf, poffset) + sizeof(u_int32_t));
+
+ FWOHCI_DMA_WRITE(db[2].db.desc.cmd,
+ OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS);
#if 1
- db[0].db.desc.status = 0;
- db[0].db.desc.count = 0;
- db[2].db.desc.status = 0;
- db[2].db.desc.count = 0;
+ FWOHCI_DMA_WRITE(db[0].db.desc.res, 0);
+ FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
#endif
- if( mode & FWXFERQ_STREAM ){
- if(mode & FWXFERQ_PACKET ){
- db[2].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
- }
- } else {
- printf("fwohci_add_tx_buf: who calls me?");
- }
- return 1;
+ return 0;
}
int
-fwohci_add_rx_buf(struct fwohcidb_tr *db_tr, unsigned short size, int mode,
- void *buf, void *dummy)
+fwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
+ int poffset, struct fwdma_alloc *dummy_dma)
{
volatile struct fwohcidb *db = db_tr->db;
- int i;
- void *dbuf[2];
+ struct fw_xferq *ir;
+ int i, ldesc;
+ bus_addr_t dbuf[2];
int dsiz[2];
- if(buf == 0){
- buf = malloc(size, M_FW, M_NOWAIT);
- if(buf == NULL) return 0;
- db_tr->buf = buf;
- db_tr->dbcnt = 1;
- db_tr->dummy = NULL;
- dsiz[0] = size;
- dbuf[0] = buf;
- }else if(dummy == NULL){
- db_tr->buf = buf;
+ ir = &dbch->xferq;
+ if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) {
+ db_tr->buf = fwdma_malloc_size(dbch->dmat, &db_tr->dma_map,
+ ir->psize, &dbuf[0], BUS_DMA_NOWAIT);
+ if (db_tr->buf == NULL)
+ return(ENOMEM);
db_tr->dbcnt = 1;
- db_tr->dummy = NULL;
- dsiz[0] = size;
- dbuf[0] = buf;
- }else{
- db_tr->buf = buf;
- db_tr->dbcnt = 2;
- db_tr->dummy = dummy;
- dsiz[0] = sizeof(u_int32_t);
- dsiz[1] = size;
- dbuf[0] = dummy;
- dbuf[1] = buf;
+ dsiz[0] = ir->psize;
+ bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ db_tr->dbcnt = 0;
+ if (dummy_dma != NULL) {
+ dsiz[db_tr->dbcnt] = sizeof(u_int32_t);
+ dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr;
+ }
+ dsiz[db_tr->dbcnt] = ir->psize;
+ if (ir->buf != NULL) {
+ db_tr->buf = fwdma_v_addr(ir->buf, poffset);
+ dbuf[db_tr->dbcnt] = fwdma_bus_addr( ir->buf, poffset);
+ }
+ db_tr->dbcnt++;
}
for(i = 0 ; i < db_tr->dbcnt ; i++){
- db[i].db.desc.addr = vtophys(dbuf[i]) ;
- db[i].db.desc.control = OHCI_INPUT_MORE;
- db[i].db.desc.reqcount = dsiz[i];
- if( mode & FWXFERQ_STREAM ){
- db[i].db.desc.control |= OHCI_UPDATE;
- }
- db[i].db.desc.status = 0;
- db[i].db.desc.count = dsiz[i];
- }
- if( mode & FWXFERQ_STREAM ){
- db[db_tr->dbcnt - 1].db.desc.control |= OHCI_INPUT_LAST;
- if(mode & FWXFERQ_PACKET ){
- db[db_tr->dbcnt - 1].db.desc.control
- |= OHCI_INTERRUPT_ALWAYS;
+ FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]);
+ FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]);
+ if (ir->flag & FWXFERQ_STREAM) {
+ FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE);
}
+ FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]);
}
- db[db_tr->dbcnt - 1].db.desc.control |= OHCI_BRANCH_ALWAYS;
- return 1;
+ ldesc = db_tr->dbcnt - 1;
+ if (ir->flag & FWXFERQ_STREAM) {
+ FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST);
+ }
+ FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS);
+ return 0;
}
-static void
-fwohci_ircv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
+
+static int
+fwohci_arcv_swap(struct fw_pkt *fp, int len)
{
- struct fwohcidb_tr *db_tr = dbch->top, *odb_tr;
- struct firewire_comm *fc = (struct firewire_comm *)sc;
- int z = 1;
- struct fw_pkt *fp;
- u_int8_t *ld;
- u_int32_t off = NULL;
- u_int32_t stat;
- u_int32_t *qld;
- u_int32_t reg;
- u_int spd;
- u_int dmach;
- int len, i, plen;
- caddr_t buf;
+ struct fw_pkt *fp0;
+ u_int32_t ld0;
+ int slen;
+#if BYTE_ORDER == BIG_ENDIAN
+ int i;
+#endif
- for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){
- if( &sc->ir[dmach] == dbch){
- off = OHCI_IROFF(dmach);
- break;
- }
- }
- if(off == NULL){
- return;
- }
- if(!(dbch->xferq.flag & FWXFERQ_RUNNING)){
- fwohci_irx_disable(&sc->fc, dmach);
- return;
+ ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]);
+#if 0
+ printf("ld0: x%08x\n", ld0);
+#endif
+ fp0 = (struct fw_pkt *)&ld0;
+ switch (fp0->mode.common.tcode) {
+ case FWTCODE_RREQQ:
+ case FWTCODE_WRES:
+ case FWTCODE_WREQQ:
+ case FWTCODE_RRESQ:
+ case FWOHCITCODE_PHY:
+ slen = 12;
+ break;
+ case FWTCODE_RREQB:
+ case FWTCODE_WREQB:
+ case FWTCODE_LREQ:
+ case FWTCODE_RRESB:
+ case FWTCODE_LRES:
+ slen = 16;
+ break;
+ default:
+ printf("Unknown tcode %d\n", fp0->mode.common.tcode);
+ return(0);
}
-
- odb_tr = NULL;
- db_tr = dbch->top;
- i = 0;
- while ((reg = db_tr->db[0].db.desc.status) & 0x1f) {
- if (count >= 0 && count-- == 0)
- break;
- ld = (u_int8_t *)db_tr->buf;
- if (dbch->xferq.flag & FWXFERQ_PACKET) {
- /* skip timeStamp */
- ld += sizeof(struct fwohci_trailer);
- }
- qld = (u_int32_t *)ld;
- len = dbch->xferq.psize - (db_tr->db[0].db.desc.count);
-/*
-{
-device_printf(sc->fc.dev, "%04x %2x 0x%08x 0x%08x 0x%08x 0x%08x\n", len,
- db_tr->db[0].db.desc.status & 0x1f, qld[0],qld[1],qld[2],qld[3]);
-}
-*/
- fp=(struct fw_pkt *)ld;
- qld[0] = htonl(qld[0]);
- plen = sizeof(struct fw_isohdr)
- + ntohs(fp->mode.stream.len) + sizeof(u_int32_t);
- ld += plen;
- len -= plen;
- buf = db_tr->buf;
- db_tr->buf = NULL;
- stat = reg & 0x1f;
- spd = reg & 0x3;
- switch(stat){
- case FWOHCIEV_ACKCOMPL:
- case FWOHCIEV_ACKPEND:
- fw_rcv(&sc->fc, buf, plen - sizeof(u_int32_t), dmach, sizeof(u_int32_t), spd);
- break;
- default:
- free(buf, M_FW);
- device_printf(sc->fc.dev, "Isochronous receive err %02x\n", stat);
- break;
- }
- i++;
- fwohci_add_rx_buf(db_tr, dbch->xferq.psize,
- dbch->xferq.flag, 0, NULL);
- db_tr->db[0].db.desc.depend &= ~0xf;
- if(dbch->pdb_tr != NULL){
- dbch->pdb_tr->db[0].db.desc.depend |= z;
- } else {
- /* XXX should be rewritten in better way */
- dbch->bottom->db[0].db.desc.depend |= z;
- }
- dbch->pdb_tr = db_tr;
- db_tr = STAILQ_NEXT(db_tr, link);
+ if (slen > len) {
+ if (firewire_debug)
+ printf("splitted header\n");
+ return(-slen);
}
- dbch->top = db_tr;
- reg = OREAD(sc, OHCI_DMACTL(off));
- if (reg & OHCI_CNTL_DMA_ACTIVE)
- return;
- device_printf(sc->fc.dev, "IR DMA %d stopped at %x status=%x (%d)\n",
- dmach, OREAD(sc, OHCI_DMACMD(off)), reg, i);
- dbch->top = db_tr;
- fwohci_irx_enable(fc, dmach);
+#if BYTE_ORDER == BIG_ENDIAN
+ for(i = 0; i < slen/4; i ++)
+ fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
+#endif
+ return(slen);
}
-#define PLEN(x) roundup2(ntohs(x), sizeof(u_int32_t))
+#define PLEN(x) roundup2(x, sizeof(u_int32_t))
static int
-fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp, int hlen)
+fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp)
{
- int i, r;
-
- for( i = 4; i < hlen ; i+=4){
- fp->mode.ld[i/4] = htonl(fp->mode.ld[i/4]);
- }
+ int r;
switch(fp->mode.common.tcode){
case FWTCODE_RREQQ:
@@ -2656,15 +2630,29 @@ 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)
+{
+ volatile struct fwohcidb *db = &db_tr->db[0];
+
+ FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
+ FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
+ FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
+ dbch->bottom = db_tr;
+}
+
+static void
fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
{
struct fwohcidb_tr *db_tr;
- int z = 1;
+ struct iovec vec[2];
+ struct fw_pkt pktbuf;
+ int nvec;
struct fw_pkt *fp;
u_int8_t *ld;
- u_int32_t stat, off;
+ u_int32_t stat, off, status;
u_int spd;
- int len, plen, hlen, pcnt, poff = 0, rlen;
+ int len, plen, hlen, pcnt, offset;
int s;
caddr_t buf;
int resCount;
@@ -2681,160 +2669,169 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
db_tr = dbch->top;
pcnt = 0;
/* XXX we cannot handle a packet which lies in more than two buf */
- while (db_tr->db[0].db.desc.status & OHCI_CNTL_DMA_ACTIVE) {
- ld = (u_int8_t *)db_tr->buf + dbch->buf_offset;
- resCount = db_tr->db[0].db.desc.count;
- len = dbch->xferq.psize - resCount
- - dbch->buf_offset;
+ fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
+ 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;
+#if 0
+ printf("status 0x%04x, resCount 0x%04x\n", status, resCount);
+#endif
+ while (status & OHCI_CNTL_DMA_ACTIVE) {
+ len = dbch->xferq.psize - resCount;
+ ld = (u_int8_t *)db_tr->buf;
+ if (dbch->pdb_tr == NULL) {
+ len -= dbch->buf_offset;
+ ld += dbch->buf_offset;
+ }
+ if (len > 0)
+ bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
+ BUS_DMASYNC_POSTREAD);
while (len > 0 ) {
if (count >= 0 && count-- == 0)
goto out;
- if(dbch->frag.buf != NULL){
- buf = dbch->frag.buf;
- if (dbch->frag.plen < 0) {
- /* incomplete header */
- int hlen;
-
- hlen = - dbch->frag.plen;
- rlen = hlen - dbch->frag.len;
- bcopy(ld, dbch->frag.buf + dbch->frag.len, rlen);
+ if(dbch->pdb_tr != NULL){
+ /* we have a fragment in previous buffer */
+ int rlen;
+
+ offset = dbch->buf_offset;
+ if (offset < 0)
+ offset = - offset;
+ buf = dbch->pdb_tr->buf + offset;
+ rlen = dbch->xferq.psize - offset;
+ if (firewire_debug)
+ printf("rlen=%d, offset=%d\n",
+ rlen, dbch->buf_offset);
+ if (dbch->buf_offset < 0) {
+ /* splitted in header, pull up */
+ char *p;
+
+ p = (char *)&pktbuf;
+ bcopy(buf, p, rlen);
+ p += rlen;
+ /* this must be too long but harmless */
+ rlen = sizeof(pktbuf) - rlen;
+ if (rlen < 0)
+ printf("why rlen < 0\n");
+ bcopy(db_tr->buf, p, rlen);
ld += rlen;
len -= rlen;
- dbch->frag.len += rlen;
-#if 0
- printf("(1)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len);
-#endif
- fp=(struct fw_pkt *)dbch->frag.buf;
- dbch->frag.plen
- = fwohci_get_plen(sc,
- dbch, fp, hlen);
- if (dbch->frag.plen == 0)
- goto out;
+ hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
+ if (hlen < 0) {
+ printf("hlen < 0 shouldn't happen");
+ }
+ offset = sizeof(pktbuf);
+ vec[0].iov_base = (char *)&pktbuf;
+ vec[0].iov_len = offset;
+ } else {
+ /* splitted in payload */
+ offset = rlen;
+ vec[0].iov_base = buf;
+ vec[0].iov_len = rlen;
}
- rlen = dbch->frag.plen - dbch->frag.len;
-#if 0
- printf("(2)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len);
-#endif
- bcopy(ld, dbch->frag.buf + dbch->frag.len,
- rlen);
- ld += rlen;
- len -= rlen;
- plen = dbch->frag.plen;
- dbch->frag.buf = NULL;
- dbch->frag.plen = 0;
- dbch->frag.len = 0;
- poff = 0;
- }else{
+ fp=(struct fw_pkt *)vec[0].iov_base;
+ nvec = 1;
+ } else {
+ /* no fragment in previous buffer */
fp=(struct fw_pkt *)ld;
- fp->mode.ld[0] = htonl(fp->mode.ld[0]);
- switch(fp->mode.common.tcode){
- case FWTCODE_RREQQ:
- case FWTCODE_WRES:
- case FWTCODE_WREQQ:
- case FWTCODE_RRESQ:
- case FWOHCITCODE_PHY:
- hlen = 12;
- break;
- case FWTCODE_RREQB:
- case FWTCODE_WREQB:
- case FWTCODE_LREQ:
- case FWTCODE_RRESB:
- case FWTCODE_LRES:
- hlen = 16;
- break;
- default:
- device_printf(sc->fc.dev, "Unknown tcode %d\n", fp->mode.common.tcode);
+ hlen = fwohci_arcv_swap(fp, len);
+ if (hlen == 0)
+ /* XXX need reset */
+ goto out;
+ if (hlen < 0) {
+ dbch->pdb_tr = db_tr;
+ dbch->buf_offset = - dbch->buf_offset;
+ /* sanity check */
+ if (resCount != 0)
+ printf("resCount != 0 !?\n");
goto out;
}
- if (len >= hlen) {
- plen = fwohci_get_plen(sc,
- dbch, fp, hlen);
- if (plen == 0)
- goto out;
- plen = (plen + 3) & ~3;
- len -= plen;
- } else {
- plen = -hlen;
- len -= hlen;
- }
- if(resCount > 0 || len > 0){
- buf = malloc(plen, M_FW, M_NOWAIT);
- if(buf == NULL){
- printf("cannot malloc!\n");
- free(db_tr->buf, M_FW);
- goto out;
- }
- bcopy(ld, buf, plen);
- poff = 0;
- dbch->frag.buf = NULL;
- dbch->frag.plen = 0;
- dbch->frag.len = 0;
- }else if(len < 0){
- dbch->frag.buf = db_tr->buf;
- if (plen < 0) {
-#if 0
- printf("plen < 0:"
- "hlen: %d len: %d\n",
- hlen, len);
-#endif
- dbch->frag.len = hlen + len;
- dbch->frag.plen = -hlen;
- } else {
- dbch->frag.len = plen + len;
- dbch->frag.plen = plen;
- }
- bcopy(ld, db_tr->buf, dbch->frag.len);
- buf = NULL;
- }else{
- buf = db_tr->buf;
- poff = ld - (u_int8_t *)buf;
- dbch->frag.buf = NULL;
- dbch->frag.plen = 0;
- dbch->frag.len = 0;
+ offset = 0;
+ nvec = 0;
+ }
+ plen = fwohci_get_plen(sc, dbch, fp) - offset;
+ if (plen < 0) {
+ /* minimum header size + trailer
+ = sizeof(fw_pkt) so this shouldn't happens */
+ printf("plen is negative! offset=%d\n", offset);
+ goto out;
+ }
+ if (plen > 0) {
+ len -= plen;
+ if (len < 0) {
+ dbch->pdb_tr = db_tr;
+ if (firewire_debug)
+ printf("splitted payload\n");
+ /* sanity check */
+ if (resCount != 0)
+ printf("resCount != 0 !?\n");
+ goto out;
}
+ vec[nvec].iov_base = ld;
+ vec[nvec].iov_len = plen;
+ nvec ++;
ld += plen;
}
- if( buf != NULL){
+ dbch->buf_offset = ld - (u_int8_t *)db_tr->buf;
+ if (nvec == 0)
+ printf("nvec == 0\n");
+
/* DMA result-code will be written at the tail of packet */
- stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
- spd = (stat >> 5) & 0x3;
- stat &= 0x1f;
- switch(stat){
- case FWOHCIEV_ACKPEND:
+#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
#if 0
- printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
+ printf("plen: %d, stat %x\n", plen ,stat);
#endif
- /* fall through */
- case FWOHCIEV_ACKCOMPL:
- if( poff != 0 )
- bcopy(buf+poff, buf, plen - 4);
- fw_rcv(&sc->fc, buf, plen - sizeof(struct fwohci_trailer), 0, 0, spd);
- break;
- case FWOHCIEV_BUSRST:
- free(buf, M_FW);
- if (sc->fc.status != FWBUSRESET)
- printf("got BUSRST packet!?\n");
+ spd = (stat >> 5) & 0x3;
+ stat &= 0x1f;
+ switch(stat){
+ case FWOHCIEV_ACKPEND:
+#if 0
+ printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
+#endif
+ /* fall through */
+ case FWOHCIEV_ACKCOMPL:
+ if ((vec[nvec-1].iov_len -=
+ sizeof(struct fwohci_trailer)) == 0)
+ nvec--;
+ fw_rcv(&sc->fc, vec, nvec, 0, spd);
break;
- default:
- device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]);
+ case FWOHCIEV_BUSRST:
+ if (sc->fc.status != FWBUSRESET)
+ 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;
+ goto out;
#endif
- break;
- }
+ break;
}
pcnt ++;
- };
+ if (dbch->pdb_tr != NULL) {
+ fwohci_arcv_free_buf(dbch, dbch->pdb_tr);
+ dbch->pdb_tr = NULL;
+ }
+
+ }
out:
if (resCount == 0) {
/* done on this buffer */
- fwohci_add_rx_buf(db_tr, dbch->xferq.psize,
- dbch->xferq.flag, 0, NULL);
- dbch->bottom->db[0].db.desc.depend |= z;
- dbch->bottom = db_tr;
+ if (dbch->pdb_tr == NULL) {
+ fwohci_arcv_free_buf(dbch, db_tr);
+ dbch->buf_offset = 0;
+ } else
+ if (dbch->pdb_tr != db_tr)
+ printf("pdb_tr != db_tr\n");
db_tr = STAILQ_NEXT(db_tr, link);
+ 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;
+ /* XXX check buffer overrun */
dbch->top = db_tr;
- dbch->buf_offset = 0;
} else {
dbch->buf_offset = dbch->xferq.psize - resCount;
break;
diff --git a/sys/dev/firewire/fwohci_pci.c b/sys/dev/firewire/fwohci_pci.c
index 2498720..14fb1ce 100644
--- a/sys/dev/firewire/fwohci_pci.c
+++ b/sys/dev/firewire/fwohci_pci.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -33,6 +34,8 @@
* $FreeBSD$
*/
+#define BOUNCE_BUFFER_TEST 0
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -50,6 +53,7 @@
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
#include <dev/firewire/fwohcireg.h>
#include <dev/firewire/fwohcivar.h>
@@ -103,7 +107,7 @@ fwohci_pci_probe( device_t dev )
return 0;
}
if (id == (FW_VENDORID_SONY | FW_DEVICE_CX3022)) {
- device_set_desc(dev, "SONY CX3022");
+ device_set_desc(dev, "Sony CX3022");
return 0;
}
if (id == (FW_VENDORID_VIA | FW_DEVICE_VT6306)) {
@@ -150,7 +154,7 @@ fwohci_dummy_intr(void *arg)
static int
fwohci_pci_init(device_t self)
{
- int latency, cache_line;
+ int olatency, latency, ocache_line, cache_line;
u_int16_t cmd;
cmd = pci_read_config(self, PCIR_COMMAND, 2);
@@ -161,25 +165,26 @@ fwohci_pci_init(device_t self)
#endif
pci_write_config(self, PCIR_COMMAND, cmd, 2);
- latency = pci_read_config(self, PCIR_LATTIMER, 1);
+ latency = olatency = pci_read_config(self, PCIR_LATTIMER, 1);
#define DEF_LATENCY 0x20
- if( latency < DEF_LATENCY ) {
+ if (olatency < DEF_LATENCY) {
latency = DEF_LATENCY;
- device_printf(self, "PCI bus latency was changing to");
- pci_write_config(self, PCIR_LATTIMER,latency, 1);
- } else
- {
- device_printf(self, "PCI bus latency is");
+ pci_write_config(self, PCIR_LATTIMER, latency, 1);
+ }
+
+ cache_line = ocache_line = pci_read_config(self, PCIR_CACHELNSZ, 1);
+#define DEF_CACHE_LINE 8
+ if (ocache_line < DEF_CACHE_LINE) {
+ cache_line = DEF_CACHE_LINE;
+ pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1);
+ }
+
+ if (firewire_debug) {
+ device_printf(self, "latency timer %d -> %d.\n",
+ olatency, latency);
+ device_printf(self, "cache size %d -> %d.\n",
+ ocache_line, cache_line);
}
- printf(" %d.\n", (int) latency);
- cache_line = pci_read_config(self, PCIR_CACHELNSZ, 1);
-#if 0
-#define DEF_CACHE_LINE 0xc
- cache_line = DEF_CACHE_LINE;
- pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1);
-#endif
- if (bootverbose)
- device_printf(self, "cache size %d.\n", (int) cache_line);
return 0;
}
@@ -199,12 +204,12 @@ fwohci_pci_attach(device_t self)
#ifdef __i386__
device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n");
#endif
-#if 0
- return ENXIO;
-#endif
}
#endif
+ if (bootverbose)
+ firewire_debug = bootverbose;
+
fwohci_pci_init(self);
rid = PCI_CBMEM;
@@ -235,7 +240,12 @@ fwohci_pci_attach(device_t self)
}
device_set_ivars(sc->fc.bdev, sc);
- err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_NET,
+ err = bus_setup_intr(self, sc->irq_res,
+#if FWOHCI_TASKQUEUE
+ INTR_TYPE_NET | INTR_MPSAFE,
+#else
+ INTR_TYPE_NET,
+#endif
(driver_intr_t *) fwohci_intr, sc, &sc->ih);
#if __FreeBSD_version < 500000
/* XXX splcam() should mask this irq for sbp.c*/
@@ -248,6 +258,26 @@ fwohci_pci_attach(device_t self)
return ENXIO;
}
+ err = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
+ /*boundary*/0,
+#if BOUNCE_BUFFER_TEST
+ /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
+#else
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+#endif
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/0x100000,
+ /*nsegments*/0x20,
+ /*maxsegsz*/0x8000,
+ /*flags*/BUS_DMA_ALLOCNOW,
+ &sc->fc.dmat);
+ if (err != 0) {
+ printf("fwohci_pci_attach: Could not allocate DMA tag "
+ "- error %d\n", err);
+ return (ENOMEM);
+ }
+
err = fwohci_init(sc, self);
if (!err)
@@ -263,9 +293,6 @@ fwohci_pci_attach(device_t self)
* Clear the bus reset event flag to start transactions even when
* interrupt is disabled during the boot process.
*/
-#if 0
- DELAY(100);
-#endif
s = splfw();
fwohci_intr((void *)sc);
splx(s);
diff --git a/sys/dev/firewire/fwohcireg.h b/sys/dev/firewire/fwohcireg.h
index 58b3422..4bb891c 100644
--- a/sys/dev/firewire/fwohcireg.h
+++ b/sys/dev/firewire/fwohcireg.h
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi Shimokawa
+ * Copyright (c) 2003 Hidetoshi Shimokawa
+ * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,55 +72,68 @@
typedef volatile u_int32_t fwohcireg_t;
+/* for PCI */
+#if BYTE_ORDER == BIG_ENDIAN
+#define FWOHCI_DMA_WRITE(x, y) ((x) = htole32(y))
+#define FWOHCI_DMA_READ(x) le32toh(x)
+#define FWOHCI_DMA_SET(x, y) ((x) |= htole32(y))
+#define FWOHCI_DMA_CLEAR(x, y) ((x) &= htole32(~(y)))
+#else
+#define FWOHCI_DMA_WRITE(x, y) ((x) = (y))
+#define FWOHCI_DMA_READ(x) (x)
+#define FWOHCI_DMA_SET(x, y) ((x) |= (y))
+#define FWOHCI_DMA_CLEAR(x, y) ((x) &= ~(y))
+#endif
+
struct fwohcidb {
union {
struct {
- volatile u_int32_t reqcount:16,
- control:16;
+ volatile u_int32_t cmd;
volatile u_int32_t addr;
volatile u_int32_t depend;
- volatile u_int32_t count:16,
- status:16;
+ volatile u_int32_t res;
} desc;
volatile u_int32_t immed[4];
} db;
-#define OHCI_OUTPUT_MORE (0 << 12)
-#define OHCI_OUTPUT_LAST (1 << 12)
-#define OHCI_INPUT_MORE (2 << 12)
-#define OHCI_INPUT_LAST (3 << 12)
-#define OHCI_STORE_QUAD (4 << 12)
-#define OHCI_LOAD_QUAD (5 << 12)
-#define OHCI_NOP (6 << 12)
-#define OHCI_STOP (7 << 12)
-#define OHCI_STORE (8 << 12)
-#define OHCI_CMD_MASK (0xf << 12)
-
-#define OHCI_UPDATE (1 << 11)
-
-#define OHCI_KEY_ST0 (0 << 8)
-#define OHCI_KEY_ST1 (1 << 8)
-#define OHCI_KEY_ST2 (2 << 8)
-#define OHCI_KEY_ST3 (3 << 8)
-#define OHCI_KEY_REGS (5 << 8)
-#define OHCI_KEY_SYS (6 << 8)
-#define OHCI_KEY_DEVICE (7 << 8)
-#define OHCI_KEY_MASK (7 << 8)
-
-#define OHCI_INTERRUPT_NEVER (0 << 4)
-#define OHCI_INTERRUPT_TRUE (1 << 4)
-#define OHCI_INTERRUPT_FALSE (2 << 4)
-#define OHCI_INTERRUPT_ALWAYS (3 << 4)
-
-#define OHCI_BRANCH_NEVER (0 << 2)
-#define OHCI_BRANCH_TRUE (1 << 2)
-#define OHCI_BRANCH_FALSE (2 << 2)
-#define OHCI_BRANCH_ALWAYS (3 << 2)
-#define OHCI_BRANCH_MASK (3 << 2)
-
-#define OHCI_WAIT_NEVER (0)
-#define OHCI_WAIT_TRUE (1)
-#define OHCI_WAIT_FALSE (2)
-#define OHCI_WAIT_ALWAYS (3)
+#define OHCI_STATUS_SHIFT 16
+#define OHCI_COUNT_MASK 0xffff
+#define OHCI_OUTPUT_MORE (0 << 28)
+#define OHCI_OUTPUT_LAST (1 << 28)
+#define OHCI_INPUT_MORE (2 << 28)
+#define OHCI_INPUT_LAST (3 << 28)
+#define OHCI_STORE_QUAD (4 << 28)
+#define OHCI_LOAD_QUAD (5 << 28)
+#define OHCI_NOP (6 << 28)
+#define OHCI_STOP (7 << 28)
+#define OHCI_STORE (8 << 28)
+#define OHCI_CMD_MASK (0xf << 28)
+
+#define OHCI_UPDATE (1 << 27)
+
+#define OHCI_KEY_ST0 (0 << 24)
+#define OHCI_KEY_ST1 (1 << 24)
+#define OHCI_KEY_ST2 (2 << 24)
+#define OHCI_KEY_ST3 (3 << 24)
+#define OHCI_KEY_REGS (5 << 24)
+#define OHCI_KEY_SYS (6 << 24)
+#define OHCI_KEY_DEVICE (7 << 24)
+#define OHCI_KEY_MASK (7 << 24)
+
+#define OHCI_INTERRUPT_NEVER (0 << 20)
+#define OHCI_INTERRUPT_TRUE (1 << 20)
+#define OHCI_INTERRUPT_FALSE (2 << 20)
+#define OHCI_INTERRUPT_ALWAYS (3 << 20)
+
+#define OHCI_BRANCH_NEVER (0 << 18)
+#define OHCI_BRANCH_TRUE (1 << 18)
+#define OHCI_BRANCH_FALSE (2 << 18)
+#define OHCI_BRANCH_ALWAYS (3 << 18)
+#define OHCI_BRANCH_MASK (3 << 18)
+
+#define OHCI_WAIT_NEVER (0 << 16)
+#define OHCI_WAIT_TRUE (1 << 16)
+#define OHCI_WAIT_FALSE (2 << 16)
+#define OHCI_WAIT_ALWAYS (3 << 16)
};
#define OHCI_SPD_S100 0x4
@@ -298,8 +312,9 @@ struct fwohcidb_tr{
STAILQ_ENTRY(fwohcidb_tr) link;
struct fw_xfer *xfer;
volatile struct fwohcidb *db;
+ bus_dmamap_t dma_map;
caddr_t buf;
- caddr_t dummy;
+ bus_addr_t bus_addr;
int dbcnt;
};
@@ -310,31 +325,55 @@ struct fwohci_txpkthdr{
union{
u_int32_t ld[4];
struct {
- u_int32_t res3:4,
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t :13,
+ spd:3,
+ :8,
+ tcode:4,
+ :4;
+#else
+ u_int32_t :4,
tcode:4,
- res2:8,
+ :8,
spd:3,
- res1:13;
+ :13;
+#endif
}common;
struct {
- u_int32_t res3:4,
- tcode:4,
- tlrt:8,
- spd:3,
- res2:4,
- srcbus:1,
- res1:8;
- u_int32_t res4:16,
- dst:16;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t :8,
+ srcbus:1,
+ :4,
+ spd:3,
+ tlrt:8,
+ tcode:4,
+ :4;
+#else
+ u_int32_t :4,
+ tcode:4,
+ tlrt:8,
+ spd:3,
+ :4,
+ srcbus:1,
+ :8;
+#endif
+ BIT16x2(dst, );
}asycomm;
struct {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t :13,
+ spd:3,
+ chtag:8,
+ tcode:4,
+ sy:4;
+#else
u_int32_t sy:4,
tcode:4,
chtag:8,
spd:3,
- res1:13;
- u_int32_t res2:16,
- len:16;
+ :13;
+#endif
+ BIT16x2(len, );
}stream;
}mode;
};
diff --git a/sys/dev/firewire/fwohcivar.h b/sys/dev/firewire/fwohcivar.h
index 643c0de..b68e9e2 100644
--- a/sys/dev/firewire/fwohcivar.h
+++ b/sys/dev/firewire/fwohcivar.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi SHimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi SHimokawa
* All rights reserved.
*
@@ -33,6 +34,16 @@
* $FreeBSD$
*
*/
+
+#if __FreeBSD_version >= 500000
+#define FWOHCI_TASKQUEUE 1
+#else
+#define FWOHCI_TASKQUEUE 0
+#endif
+#if FWOHCI_TASKQUEUE
+#include <sys/taskqueue.h>
+#endif
+
typedef struct fwohci_softc {
struct firewire_comm fc;
bus_space_tag_t bst;
@@ -41,34 +52,36 @@ typedef struct fwohci_softc {
#if __FreeBSD_version < 500000
void *ih_cam;
#endif
-
struct resource *bsr;
struct resource *irq_res;
struct fwohci_dbch{
u_int ndb;
u_int ndesc;
- caddr_t dummy;
STAILQ_HEAD(, fwohcidb_tr) db_trq;
struct fwohcidb_tr *top, *bottom, *pdb_tr;
struct fw_xferq xferq;
- struct {
- int len;
- int hlen;
- int plen;
- caddr_t buf;
- } frag;
int flags;
#define FWOHCI_DBCH_INIT (1<<0)
#define FWOHCI_DBCH_FULL (1<<1)
- int buf_offset;
+ /* used only in receive context */
+ int buf_offset; /* signed */
#define FWOHCI_DBCH_MAX_PAGES 32
- int npages;
- void *pages[FWOHCI_DBCH_MAX_PAGES];
+ /* Context programs buffer */
+ struct fwdma_alloc_multi *am;
+ bus_dma_tag_t dmat;
} arrq, arrs, atrq, atrs, it[OHCI_DMA_ITCH], ir[OHCI_DMA_IRCH];
u_int maxrec;
- u_int32_t *cromptr;
- u_int32_t intmask;
+ u_int32_t *sid_buf;
+ struct fwdma_alloc sid_dma;
+ struct fwdma_alloc crom_dma;
+ struct fwdma_alloc dummy_dma;
+ u_int32_t intmask, irstat, itstat;
+#if FWOHCI_TASKQUEUE
+ u_int32_t intstat;
+ struct task fwohci_task_complete;
+#endif
} fwohci_softc_t;
+
void fwohci_intr __P((void *arg));
int fwohci_init __P((struct fwohci_softc *, device_t));
void fwohci_reset __P((struct fwohci_softc *, device_t));
diff --git a/sys/dev/firewire/iec13213.h b/sys/dev/firewire/iec13213.h
index 1e4e8cd..efd51aa 100644
--- a/sys/dev/firewire/iec13213.h
+++ b/sys/dev/firewire/iec13213.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@@ -66,65 +67,90 @@
#define CSRKEY_DID 0x20 /* Directory_ID */
#define CSRKEY_REV 0x21 /* Revision */
-#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 */
-#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 */
+#define CSRKEY_FIRM_VER 0x3c /* Firemware version */
+#define CSRKEY_UNIT_CH 0x3a /* Unit characteristics */
+#define CSRKEY_COM_SPEC 0x38 /* Command set revision */
+#define CSRKEY_COM_SET 0x39 /* Command set */
-/* ???
-#define CSRKEY_MVID 0x3
-#define CSRKEY_NUNQ 0x8d
-#define CSRKEY_NPWR 0x30
-*/
+#define CROM_UDIR (CSRTYPE_D | CSRKEY_UNIT) /* 0x81 Unit directory */
+#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 Text leaf */
+#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 Logical unit num. */
+#define CROM_MGM (CSRTYPE_C | CSRKEY_DINFO) /* 0x54 Management agent */
-#define CSRVAL_1394TA 0x00a02d
-#define CSRVAL_ANSIT10 0x00609e
-#define CSR_PROTAVC 0x010001
-#define CSR_PROTCAL 0x010002
-#define CSR_PROTEHS 0x010004
-#define CSR_PROTHAVI 0x010008
-#define CSR_PROTCAM104 0x000100
-#define CSR_PROTCAM120 0x000101
-#define CSR_PROTCAM130 0x000102
-#define CSR_PROTDPP 0x0a6be2
-#define CSR_PROTIICP 0x4b661f
+#define CSRVAL_1394TA 0x00a02d
+#define CSRVAL_ANSIT10 0x00609e
+#define CSRVAL_IETF 0x00005e
-#define CSRVAL_T10SBP2 0x010483
+#define CSR_PROTAVC 0x010001
+#define CSR_PROTCAL 0x010002
+#define CSR_PROTEHS 0x010004
+#define CSR_PROTHAVI 0x010008
+#define CSR_PROTCAM104 0x000100
+#define CSR_PROTCAM120 0x000101
+#define CSR_PROTCAM130 0x000102
+#define CSR_PROTDPP 0x0a6be2
+#define CSR_PROTIICP 0x4b661f
+
+#define CSRVAL_T10SBP2 0x010483
+#define CSRVAL_SCSI 0x0104d8
struct csrreg {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t key:8,
+ val:24;
+#else
u_int32_t val:24,
key:8;
+#endif
};
struct csrhdr {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t info_len:8,
+ crc_len:8,
+ crc:16;
+#else
u_int32_t crc:16,
crc_len:8,
info_len:8;
+#endif
};
struct csrdirectory {
- u_int32_t crc:16,
- crc_len:16;
+ BIT16x2(crc_len, crc);
struct csrreg entry[0];
};
struct csrtext {
- u_int32_t crc:16,
- crc_len:16;
+ BIT16x2(crc_len, crc);
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t spec_type:8,
+ spec_id:24;
+#else
u_int32_t spec_id:24,
spec_type:8;
+#endif
u_int32_t lang_id;
u_int32_t text[0];
};
-struct businfo {
- u_int32_t crc:16,
- crc_len:8,
- :12,
- max_rec:4,
- clk_acc:8,
- :4,
- bmc:1,
- isc:1,
- cmc:1,
- irmc:1;
- u_int32_t c_id_hi:8,
- v_id:24;
- u_int32_t c_id_lo;
+
+struct bus_info {
+#define CSR_BUS_NAME_IEEE1394 0x31333934
+ u_int32_t bus_name;
+ u_int32_t link_spd:3,
+ :1,
+ generation:4,
+#define MAXROM_4 0
+#define MAXROM_64 1
+#define MAXROM_1024 2
+ max_rom:2,
+ :2,
+ max_rec:4, /* (2 << max_rec) bytes */
+ cyc_clk_acc:8, /* 0 <= ppm <= 100 */
+ :3,
+ pmc:1, /* power manager capable */
+ bmc:1, /* bus manager capable */
+ isc:1, /* iso. operation support */
+ cmc:1, /* cycle master capable */
+ irmc:1; /* iso. resource manager capable */
+ struct fw_eui64 eui64;
};
#define CROM_MAX_DEPTH 10
@@ -147,3 +173,33 @@ struct csrreg *crom_search_key(struct crom_context *, u_int8_t);
#ifndef _KERNEL
char *crom_desc(struct crom_context *, char *, int);
#endif
+
+/* For CROM build */
+#if defined(_KERNEL) || defined(TEST)
+#define CROM_MAX_CHUNK_LEN 20
+struct crom_src {
+ struct csrhdr hdr;
+ struct bus_info businfo;
+ STAILQ_HEAD(, crom_chunk) chunk_list;
+};
+
+struct crom_chunk {
+ STAILQ_ENTRY(crom_chunk) link;
+ struct crom_chunk *ref_chunk;
+ int ref_index;
+ int offset;
+ struct {
+ u_int32_t crc:16,
+ crc_len:16;
+ u_int32_t buf[CROM_MAX_CHUNK_LEN];
+ } data;
+};
+
+extern int crom_add_quad(struct crom_chunk *, u_int32_t);
+extern int crom_add_entry(struct crom_chunk *, int, int);
+extern int crom_add_chunk(struct crom_src *src, struct crom_chunk *,
+ struct crom_chunk *, int);
+extern int crom_add_simple_text(struct crom_src *src, struct crom_chunk *,
+ struct crom_chunk *, char *);
+extern int crom_load(struct crom_src *, u_int32_t *, int);
+#endif
diff --git a/sys/dev/firewire/iec68113.h b/sys/dev/firewire/iec68113.h
index 52a4270..2e47aab 100644
--- a/sys/dev/firewire/iec68113.h
+++ b/sys/dev/firewire/iec68113.h
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi Shimokawa
+ * Copyright (c) 2003 Hidetoshi Shimokawa
+ * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,29 +35,55 @@
*
*/
struct ciphdr {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t eoh0:1, /* 0 */
+ form0:1, /* 0 */
+ src:6;
+#else
u_int8_t src:6,
form0:1, /* 0 */
eoh0:1; /* 0 */
+#endif
u_int8_t len;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t fn:2,
+ qpc:3,
+ sph:1,
+ :2;
+#else
u_int8_t :2,
sph:1,
qpc:3,
fn:2;
+#endif
u_int8_t dbc;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t eoh1:1, /* 1 */
+ form1:1, /* 0 */
+ fmt:6;
+#else
u_int8_t fmt:6,
-#define CIP_FMT_DVCR 0
-#define CIP_FMT_MPEG (1<<5)
form1:1, /* 0 */
eoh1:1; /* 1 */
+#endif
+#define CIP_FMT_DVCR 0
+#define CIP_FMT_MPEG (1<<5)
union {
struct {
- u_int8_t :2,
- stype:5,
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t fs:1, /* 50/60 field system
+ NTSC/PAL */
+ stype:5,
+ :2;
+#else
+ u_int8_t :2,
+ stype:5,
+ fs:1; /* 50/60 field system
+ NTSC/PAL */
+#endif
#define CIP_STYPE_SD 0
#define CIP_STYPE_SDL 1
#define CIP_STYPE_HD 2
- fs:1; /* 50/60 field system
- NTSC/PAL */
u_int16_t cyc:16; /* take care of byte order! */
} __attribute__ ((packed)) dv;
u_int8_t bytes[3];
@@ -64,17 +91,29 @@ struct ciphdr {
};
struct dvdbc{
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t sct:3, /* Section type */
+ :1, /* Reserved */
+ arb:4; /* Arbitrary bit */
+#else
u_int8_t arb:4, /* Arbitrary bit */
:1, /* Reserved */
sct:3; /* Section type */
+#endif
#define DV_SCT_HEADER 0
#define DV_SCT_SUBCODE 1
#define DV_SCT_VAUX 2
#define DV_SCT_AUDIO 3
#define DV_SCT_VIDEO 4
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t dseq:4, /* DIF sequence number */
+ fsc:1, /* ID of a DIF block in each channel */
+ :3;
+#else
u_int8_t :3,
fsc:1, /* ID of a DIF block in each channel */
dseq:4; /* DIF sequence number */
+#endif
u_int8_t dbn; /* DIF block number */
u_int8_t payload[77];
#define DV_DSF_12 0x80 /* PAL: payload[0] in Header DIF */
diff --git a/sys/dev/firewire/if_fwe.c b/sys/dev/firewire/if_fwe.c
index 2f54add..92b27f3 100644
--- a/sys/dev/firewire/if_fwe.c
+++ b/sys/dev/firewire/if_fwe.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,7 @@
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/bus.h>
+#include <machine/bus.h>
#include <net/bpf.h>
#include <net/ethernet.h>
@@ -234,8 +235,8 @@ fwe_stop(struct fwe_softc *fwe)
if (xferq->flag & FWXFERQ_RUNNING)
fc->irx_disable(fc, fwe->dma_ch);
xferq->flag &=
- ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN |
- FWXFERQ_EXTBUF | FWXFERQ_HANDLER);
+ ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
+ FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
xferq->hand = NULL;
for (i = 0; i < xferq->bnchunk; i ++)
@@ -284,6 +285,7 @@ fwe_init(void *arg)
struct ifnet *ifp = &fwe->fwe_if;
struct fw_xferq *xferq;
struct fw_xfer *xfer;
+ struct mbuf *m;
int i;
FWEDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
@@ -309,19 +311,21 @@ fwe_init(void *arg)
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;
+ xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
+ FWXFERQ_HANDLER | FWXFERQ_STREAM;
xferq->flag &= ~0xff;
xferq->flag |= fwe->stream_ch & 0xff;
/* register fwe_input handler */
xferq->sc = (caddr_t) fwe;
xferq->hand = fwe_as_input;
- xferq->flag |= FWXFERQ_HANDLER;
xferq->bnchunk = RX_MAX_QUEUE;
xferq->bnpacket = 1;
xferq->psize = MCLBYTES;
xferq->queued = 0;
+ xferq->buf = NULL;
xferq->bulkxfer = (struct fw_bulkxfer *) malloc(
- sizeof(struct fw_bulkxfer) * xferq->bnchunk, M_FWE, 0);
+ sizeof(struct fw_bulkxfer) * xferq->bnchunk,
+ M_FWE, M_WAITOK);
if (xferq->bulkxfer == NULL) {
printf("if_fwe: malloc failed\n");
return;
@@ -331,23 +335,25 @@ fwe_init(void *arg)
STAILQ_INIT(&xferq->stdma);
xferq->stproc = NULL;
for (i = 0; i < xferq->bnchunk; i ++) {
- xferq->bulkxfer[i].mbuf =
+ m =
#if __FreeBSD_version >= 500000
m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR);
#else
m_getcl(M_WAIT, MT_DATA, M_PKTHDR);
#endif
- xferq->bulkxfer[i].buf =
- mtod(xferq->bulkxfer[i].mbuf, char *);
- STAILQ_INSERT_TAIL(&xferq->stfree,
- &xferq->bulkxfer[i], link);
+ xferq->bulkxfer[i].mbuf = m;
+ if (m != NULL) {
+ m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
+ STAILQ_INSERT_TAIL(&xferq->stfree,
+ &xferq->bulkxfer[i], link);
+ } else
+ printf("fwe_as_input: m_getcl failed\n");
}
STAILQ_INIT(&fwe->xferlist);
for (i = 0; i < TX_MAX_QUEUE; i++) {
xfer = fw_xfer_alloc(M_FWE);
if (xfer == NULL)
break;
- xfer->send.off = 0;
xfer->spd = 2;
xfer->fc = fwe->fd.fc;
xfer->retry_req = fw_asybusy;
@@ -446,21 +452,15 @@ fwe_output_callback(struct fw_xfer *xfer)
m_freem(xfer->mbuf);
xfer->send.buf = NULL;
-#if 0
fw_xfer_unload(xfer);
-#else
- xfer->state = FWXF_INIT;
- xfer->resp = 0;
- xfer->retry = 0;
-#endif
+
s = splimp();
STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
splx(s);
-#if 1
- /* XXX for queue full */
+
+ /* for queue full */
if (ifp->if_snd.ifq_head != NULL)
fwe_start(ifp);
-#endif
}
static void
@@ -469,7 +469,6 @@ fwe_start(struct ifnet *ifp)
struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
int s;
-#if 1
FWEDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
if (fwe->dma_ch < 0) {
@@ -489,7 +488,6 @@ fwe_start(struct ifnet *ifp)
return;
}
-#endif
s = splimp();
ifp->if_flags |= IFF_OACTIVE;
@@ -537,7 +535,7 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT);
fp = (struct fw_pkt *)&xfer->dst; /* XXX */
xfer->dst = *((int32_t *)&fwe->pkt_hdr);
- fp->mode.stream.len = htons(m->m_pkthdr.len);
+ fp->mode.stream.len = m->m_pkthdr.len;
xfer->send.buf = (caddr_t) fp;
xfer->mbuf = m;
xfer->send.len = m->m_pkthdr.len + HDR_LEN;
@@ -560,44 +558,11 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
xferq->start(fwe->fd.fc);
}
-#if 0
-#if __FreeBSD_version >= 500000
-static void
-fwe_free(void *buf, void *args)
-{
- FWEDEBUG("fwe_free:\n");
- free(buf, M_FW);
-}
-
-#else
-static void
-fwe_free(caddr_t buf, u_int size)
-{
- int *p;
- FWEDEBUG("fwe_free:\n");
- p = (int *)buf;
- (*p) --;
- if (*p < 1)
- free(buf, M_FW);
-}
-
-static void
-fwe_ref(caddr_t buf, u_int size)
-{
- int *p;
-
- FWEDEBUG("fwe_ref: called\n");
- p = (int *)buf;
- (*p) ++;
-}
-#endif
-#endif
-
/* Async. stream output */
static void
fwe_as_input(struct fw_xferq *xferq)
{
- struct mbuf *m;
+ struct mbuf *m, *m0;
struct ifnet *ifp;
struct fwe_softc *fwe;
struct fw_bulkxfer *sxfer;
@@ -614,21 +579,21 @@ fwe_as_input(struct fw_xferq *xferq)
#endif
while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
-#if 0
- xferq->queued --;
-#endif
if (sxfer->resp != 0)
ifp->if_ierrors ++;
- fp = (struct fw_pkt *)sxfer->buf;
+ fp = mtod(sxfer->mbuf, struct fw_pkt *);
/* XXX */
if (fwe->fd.fc->irx_post != NULL)
fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
m = sxfer->mbuf;
/* insert rbuf */
- sxfer->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- sxfer->buf = mtod(sxfer->mbuf, char *);
- STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
+ sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m0 != NULL) {
+ 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");
m->m_data += HDR_LEN + ETHER_ALIGN;
c = mtod(m, char *);
@@ -637,7 +602,7 @@ fwe_as_input(struct fw_xferq *xferq)
m->m_data += sizeof(struct ether_header);
#endif
m->m_len = m->m_pkthdr.len =
- ntohs(fp->mode.stream.len) - ETHER_ALIGN;
+ fp->mode.stream.len - ETHER_ALIGN;
m->m_pkthdr.rcvif = ifp;
#if 0
FWEDEBUG("%02x %02x %02x %02x %02x %02x\n"
diff --git a/sys/dev/firewire/if_fwevar.h b/sys/dev/firewire/if_fwevar.h
index 6eb6ff7..9742216 100644
--- a/sys/dev/firewire/if_fwevar.h
+++ b/sys/dev/firewire/if_fwevar.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c
index 307b466..90783cf 100644
--- a/sys/dev/firewire/sbp.c
+++ b/sys/dev/firewire/sbp.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998,1999,2000,2001 Katsushi Kobayashi and Hidetosh Shimokawa
+ * Copyright (c) 2003 Hidetosh Shimokawa
+ * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetosh Shimokawa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,11 +61,9 @@
#include <sys/kernel.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
#include <dev/firewire/iec13213.h>
#define ccb_sdev_ptr spriv_ptr0
@@ -72,8 +71,11 @@
#define SBP_NUM_TARGETS 8 /* MAX 64 */
#define SBP_NUM_LUNS 8 /* limited by CAM_SCSI2_MAXLUN in cam_xpt.c */
-#define SBP_QUEUE_LEN 4
+#define SBP_DMA_SIZE PAGE_SIZE
+#define SBP_LOGIN_SIZE sizeof(struct sbp_login_res)
+#define SBP_QUEUE_LEN ((SBP_DMA_SIZE - SBP_LOGIN_SIZE) / sizeof(struct sbp_ocb))
#define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS)
+
#define SBP_INITIATOR 7
#define LOGIN_DELAY 2
@@ -168,20 +170,29 @@ SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, max_speed, CTLFLAG_RW, &max_speed, 0,
struct ind_ptr {
u_int32_t hi,lo;
};
-#define SBP_IND_MAX 0x20
+#define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE)
+#ifdef __sparc64__ /* iommu */
+#define SBP_IND_MAX howmany(MAXPHYS, SBP_SEG_MAX)
+#else
+#define SBP_IND_MAX howmany(MAXPHYS, PAGE_SIZE)
+#endif
struct sbp_ocb {
STAILQ_ENTRY(sbp_ocb) ocb;
union ccb *ccb;
+ bus_addr_t bus_addr;
volatile u_int32_t orb[8];
+#define IND_PTR_OFFSET (8*sizeof(u_int32_t))
volatile struct ind_ptr ind_ptr[SBP_IND_MAX];
struct sbp_dev *sdev;
- int flags;
+ int flags; /* XXX should be removed */
bus_dmamap_t dmamap;
};
+
#define OCB_ACT_MGM 0
#define OCB_ACT_CMD 1
-#define OCB_MATCH(o,s) (vtophys(&(o)->orb[0]) == ntohl((s)->orb_lo))
+#define OCB_MATCH(o,s) ((o)->bus_addr == ntohl((s)->orb_lo))
+#define SBP_RECV_LEN (16 + 32) /* header + payload */
struct sbp_login_res{
u_int16_t len;
@@ -193,11 +204,18 @@ struct sbp_login_res{
u_int16_t recon_hold;
};
struct sbp_status{
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t src:2,
+ resp:2,
+ dead:1,
+ len:3;
+#else
u_int8_t len:3,
dead:1,
resp:2,
src:2;
- u_int8_t status:8;
+#endif
+ u_int8_t status;
u_int16_t orb_hi;
u_int32_t orb_lo;
u_int32_t data[6];
@@ -205,6 +223,15 @@ struct sbp_status{
struct sbp_cmd_status{
#define SBP_SFMT_CURR 0
#define SBP_SFMT_DEFER 1
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t sfmt:2,
+ status:6;
+ u_int8_t valid:1,
+ mark:1,
+ eom:1,
+ ill_len:1,
+ s_key:4;
+#else
u_int8_t status:6,
sfmt:2;
u_int8_t s_key:4,
@@ -212,13 +239,21 @@ struct sbp_cmd_status{
eom:1,
mark:1,
valid:1;
+#endif
u_int8_t s_code;
u_int8_t s_qlfr;
u_int32_t info;
u_int32_t cdb;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t s_keydep:24,
+ fru:8;
+#else
u_int32_t fru:8,
s_keydep:24;
+#endif
u_int32_t vend[2];
+
};
struct sbp_dev{
@@ -240,9 +275,12 @@ struct sbp_dev{
int freeze;
struct cam_path *path;
struct sbp_target *target;
- struct sbp_login_res login;
+ struct fwdma_alloc dma;
+ struct sbp_login_res *login;
struct callout login_callout;
+ struct sbp_ocb *ocb;
STAILQ_HEAD(, sbp_ocb) ocbs;
+ STAILQ_HEAD(, sbp_ocb) free_ocbs;
char vendor[32];
char product[32];
char revision[10];
@@ -260,6 +298,8 @@ struct sbp_target {
struct callout mgm_ocb_timeout;
#define SCAN_DELAY 2
struct callout scan_callout;
+ STAILQ_HEAD(, fw_xfer) xferlist;
+ int n_xfer;
};
struct sbp_softc {
@@ -268,8 +308,6 @@ struct sbp_softc {
struct cam_path *path;
struct sbp_target targets[SBP_NUM_TARGETS];
struct fw_bind fwb;
- STAILQ_HEAD(, sbp_ocb) free_ocbs;
- struct sbp_ocb *ocb;
bus_dma_tag_t dmat;
#define SBP_RESOURCE_SHORTAGE 0x10
unsigned char flags;
@@ -280,11 +318,11 @@ static void sbp_login_callback __P((struct fw_xfer *));
static void sbp_cmd_callback __P((struct fw_xfer *));
static void sbp_orb_pointer __P((struct sbp_dev *, struct sbp_ocb *));
static void sbp_execute_ocb __P((void *, bus_dma_segment_t *, int, int));
-static void sbp_free_ocb __P((struct sbp_softc *, struct sbp_ocb *));
+static void sbp_free_ocb __P((struct sbp_dev *, struct sbp_ocb *));
static void sbp_abort_ocb __P((struct sbp_ocb *, int));
static void sbp_abort_all_ocbs __P((struct sbp_dev *, int));
static struct fw_xfer * sbp_write_cmd __P((struct sbp_dev *, int, int));
-static struct sbp_ocb * sbp_get_ocb __P((struct sbp_softc *));
+static struct sbp_ocb * sbp_get_ocb __P((struct sbp_dev *));
static struct sbp_ocb * sbp_enqueue_ocb __P((struct sbp_dev *, struct sbp_ocb *));
static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, struct sbp_status *));
static void sbp_cam_detach_target __P((struct sbp_target *));
@@ -500,6 +538,8 @@ END_DEBUG
SBP_DEBUG(1)
printf("target:%d mgm_port: %x\n", i, target->mgm_lo);
END_DEBUG
+ STAILQ_INIT(&target->xferlist);
+ target->n_xfer = 0;
STAILQ_INIT(&target->mgm_ocb_queue);
CALLOUT_INIT(&target->mgm_ocb_timeout);
CALLOUT_INIT(&target->scan_callout);
@@ -546,8 +586,38 @@ END_DEBUG
printf("too large lun %d\n", lun);
continue;
}
- target->luns[lun].status = SBP_DEV_RESET;
- target->luns[lun].type = (reg->val & 0xf0000) >> 16;
+ sdev = &target->luns[lun];
+ sdev->status = SBP_DEV_RESET;
+ sdev->type = (reg->val & 0xf0000) >> 16;
+
+ fwdma_malloc(sbp->fd.fc,
+ /* alignment */ sizeof(u_int32_t),
+ SBP_DMA_SIZE, &sdev->dma, BUS_DMA_NOWAIT);
+ if (sdev->dma.v_addr == NULL) {
+ printf("%s: dma space allocation failed\n",
+ __FUNCTION__);
+ return (NULL);
+ }
+ sdev->login = (struct sbp_login_res *) sdev->dma.v_addr;
+ sdev->ocb = (struct sbp_ocb *)
+ ((char *)sdev->dma.v_addr + SBP_LOGIN_SIZE);
+ bzero((char *)sdev->ocb,
+ sizeof (struct sbp_ocb) * SBP_QUEUE_LEN);
+
+ STAILQ_INIT(&sdev->free_ocbs);
+ for (i = 0; i < SBP_QUEUE_LEN; i++) {
+ struct sbp_ocb *ocb;
+ ocb = &sdev->ocb[i];
+ ocb->bus_addr = sdev->dma.bus_addr
+ + SBP_LOGIN_SIZE
+ + sizeof(struct sbp_ocb) * i
+ + offsetof(struct sbp_ocb, orb[0]);
+ if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) {
+ printf("sbp_attach: cannot create dmamap\n");
+ return (NULL);
+ }
+ sbp_free_ocb(sdev, ocb);
+ }
crom_next(&cc);
}
return target;
@@ -644,23 +714,15 @@ END_DEBUG
sbp_probe_lun(sdev);
SBP_DEBUG(0)
sbp_show_sdev_info(sdev,
-#if 0
- (sdev->status == SBP_DEV_TOATTACH));
-#else
(sdev->status == SBP_DEV_RESET));
-#endif
END_DEBUG
sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
switch (sdev->status) {
case SBP_DEV_RESET:
/* new or revived target */
- if (auto_login) {
-#if 0
- sdev->status = SBP_DEV_TOATTACH;
-#endif
+ if (auto_login)
sbp_login(sdev);
- }
break;
case SBP_DEV_TOATTACH:
case SBP_DEV_PROBE:
@@ -699,6 +761,17 @@ END_DEBUG
}
static void
+sbp_post_busreset(void *arg)
+{
+ struct sbp_softc *sbp;
+
+ sbp = (struct sbp_softc *)arg;
+SBP_DEBUG(0)
+ printf("sbp_post_busreset\n");
+END_DEBUG
+}
+
+static void
sbp_post_explore(void *arg)
{
struct sbp_softc *sbp = (struct sbp_softc *)arg;
@@ -767,25 +840,39 @@ END_DEBUG
}
sbp_probe_target((void *)target);
}
-#if 0
- timeout(sbp_release_queue, (caddr_t)sbp, bus_reset_rest * hz / 1000);
-#endif
}
#if NEED_RESPONSE
static void
sbp_loginres_callback(struct fw_xfer *xfer){
-SBP_DEBUG(1)
+ int s;
struct sbp_dev *sdev;
sdev = (struct sbp_dev *)xfer->sc;
+SBP_DEBUG(1)
sbp_show_sdev_info(sdev, 2);
printf("sbp_loginres_callback\n");
END_DEBUG
- fw_xfer_free(xfer);
+ /* recycle */
+ s = splfw();
+ STAILQ_INSERT_TAIL(&sdev->target->sbp->fwb.xferlist, xfer, link);
+ splx(s);
return;
}
#endif
+static __inline void
+sbp_xfer_free(struct fw_xfer *xfer)
+{
+ struct sbp_dev *sdev;
+ int s;
+
+ sdev = (struct sbp_dev *)xfer->sc;
+ fw_xfer_unload(xfer);
+ s = splfw();
+ STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link);
+ splx(s);
+}
+
static void
sbp_login_callback(struct fw_xfer *xfer)
{
@@ -795,7 +882,7 @@ SBP_DEBUG(1)
sbp_show_sdev_info(sdev, 2);
printf("sbp_login_callback\n");
END_DEBUG
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
return;
}
@@ -808,7 +895,7 @@ SBP_DEBUG(2)
sbp_show_sdev_info(sdev, 2);
printf("sbp_cmd_callback\n");
END_DEBUG
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
return;
}
@@ -895,101 +982,6 @@ END_DEBUG
sdev->freeze = 1;
}
-
-#if 0
-static void
-sbp_ping_unit_callback(struct cam_periph *periph, union ccb *ccb)
-{
- struct sbp_dev *sdev;
- sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
-SBP_DEBUG(0)
- sbp_show_sdev_info(sdev, 2);
- printf("sbp_ping_unit_callback\n");
-END_DEBUG
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- if (--ccb->ccb_h.retry_count == 0) {
- sbp_show_sdev_info(sdev, 2);
- printf("sbp_ping_unit_callback: "
- "retry count exceeded\n");
- sdev->status = SBP_DEV_RETRY;
- free(ccb, M_SBP);
- } else {
- /* requeue */
- xpt_action(ccb);
- xpt_release_devq(sdev->path, sdev->freeze, TRUE);
- sdev->freeze = 1; /* we will freeze */
- }
- } else {
- free(ccb->csio.data_ptr, M_SBP);
- free(ccb, M_SBP);
- sdev->status = SBP_DEV_ATTACHED;
- xpt_release_devq(sdev->path, sdev->freeze, TRUE);
- sdev->freeze = 0;
- }
-}
-
-/*
- * XXX Some devices need to execute inquiry or read_capacity
- * after bus_rest during busy transfer.
- * Otherwise they return incorrect result for READ(and WRITE?)
- * command without any SBP-II/SCSI error.
- *
- * e.g. Maxtor 3000XT, Yano A-dish.
- */
-static void
-sbp_ping_unit(struct sbp_dev *sdev)
-{
- union ccb *ccb;
- struct scsi_inquiry_data *inq_buf;
-
-
- ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO);
- if (ccb == NULL) {
- printf("sbp_ping_unit: malloc failed\n");
- return;
- }
-
- inq_buf = (struct scsi_inquiry_data *)
- malloc(sizeof(*inq_buf), M_SBP, M_NOWAIT);
- if (inq_buf == NULL) {
- free(ccb, M_SBP);
- printf("sbp_ping_unit: malloc failed\n");
- return;
- }
-
-SBP_DEBUG(0)
- sbp_show_sdev_info(sdev, 2);
- printf("sbp_ping_unit\n");
-END_DEBUG
-
- /*
- * We need to execute this command before any other queued command.
- * Make priority 0 and freeze the queue after execution for retry.
- * cam's scan_lun command doesn't provide this feature.
- */
- xpt_setup_ccb(&ccb->ccb_h, sdev->path, 0/*priority (high)*/);
- scsi_inquiry(
- &ccb->csio,
- /*retries*/ 5,
- sbp_ping_unit_callback,
- MSG_SIMPLE_Q_TAG,
- (u_int8_t *)inq_buf,
- SHORT_INQUIRY_LENGTH,
- /*evpd*/FALSE,
- /*page_code*/0,
- SSD_MIN_SIZE,
- /*timeout*/60000
- );
- ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
- ccb->ccb_h.ccb_sdev_ptr = sdev;
- xpt_action(ccb);
- if (sdev->status != SBP_DEV_ATTACHED)
- sdev->status = SBP_DEV_PROBE;
- xpt_release_devq(sdev->path, sdev->freeze, TRUE);
- sdev->freeze = 1; /* We will freeze the queue */
-}
-#endif
-
static __inline void
sbp_scan_dev(struct sbp_dev *sdev)
{
@@ -1012,7 +1004,7 @@ SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("sbp_do_attach\n");
END_DEBUG
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
if (sdev->path == NULL)
xpt_create_path(&sdev->path, xpt_periph,
@@ -1043,7 +1035,7 @@ SBP_DEBUG(1)
sbp_show_sdev_info(sdev, 2);
printf("sbp_cmd_callback\n");
END_DEBUG
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
if (sdev->path) {
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
sdev->freeze = 0;
@@ -1083,7 +1075,7 @@ SBP_DEBUG(1)
sbp_show_sdev_info(sdev, 2);
printf("sbp_busy_timeout_callback\n");
END_DEBUG
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
sbp_agent_reset(sdev);
}
@@ -1100,8 +1092,8 @@ END_DEBUG
xfer->act.hand = sbp_busy_timeout_callback;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.wreqq.dest_hi = htons(0xffff);
- fp->mode.wreqq.dest_lo = htonl(0xf0000000 | BUSY_TIMEOUT);
+ fp->mode.wreqq.dest_hi = 0xffff;
+ fp->mode.wreqq.dest_lo = 0xf0000000 | BUSY_TIMEOUT;
fp->mode.wreqq.data = htonl((1 << (13+12)) | 0xf);
fw_asyreq(xfer->fc, -1, xfer);
}
@@ -1121,8 +1113,8 @@ END_DEBUG
xfer->act.hand = sbp_busy_timeout;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.wreqq.dest_hi = htons(0xffff);
- fp->mode.wreqq.dest_lo = htonl(0xf0000000 | RESET_START);
+ fp->mode.wreqq.dest_hi = 0xffff;
+ fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
fp->mode.wreqq.data = htonl(0xf);
fw_asyreq(xfer->fc, -1, xfer);
}
@@ -1144,14 +1136,14 @@ END_DEBUG
xfer->act.hand = sbp_cmd_callback;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.wreqb.len = htons(8);
+ fp->mode.wreqb.len = 8;
fp->mode.wreqb.extcode = 0;
fp->mode.wreqb.payload[0] =
htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16));
- fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0]));
+ fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr);
if(fw_asyreq(xfer->fc, -1, xfer) != 0){
- fw_xfer_free(xfer);
+ sbp_xfer_free(xfer);
ocb->ccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(ocb->ccb);
}
@@ -1183,36 +1175,55 @@ sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
{
struct fw_xfer *xfer;
struct fw_pkt *fp;
+ struct sbp_target *target;
+ int s, new = 0;
- xfer = fw_xfer_alloc(M_SBP);
- if(xfer == NULL){
- return NULL;
+ target = sdev->target;
+ s = splfw();
+ xfer = STAILQ_FIRST(&target->xferlist);
+ if (xfer == NULL) {
+ if (target->n_xfer > 5 /* XXX */) {
+ printf("sbp: no more xfer for this target\n");
+ splx(s);
+ return(NULL);
+ }
+ xfer = fw_xfer_alloc_buf(M_SBP, 24, 12);
+ if(xfer == NULL){
+ printf("sbp: fw_xfer_alloc_buf failed\n");
+ splx(s);
+ return NULL;
+ }
+ target->n_xfer ++;
+ if (debug)
+ printf("sbp: alloc %d xfer\n", target->n_xfer);
+ new = 1;
+ } else {
+ STAILQ_REMOVE_HEAD(&target->xferlist, link);
}
+ splx(s);
+
+ microtime(&xfer->tv);
+
if (tcode == FWTCODE_WREQQ)
xfer->send.len = 16;
else
xfer->send.len = 24;
+ xfer->recv.len = 12;
- xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
- if(xfer->send.buf == NULL){
- fw_xfer_free(xfer);
- return NULL;
+ if (new) {
+ xfer->spd = min(sdev->target->fwdev->speed, max_speed);
+ xfer->fc = sdev->target->sbp->fd.fc;
+ xfer->retry_req = fw_asybusy;
}
-
- xfer->send.off = 0;
- xfer->spd = min(sdev->target->fwdev->speed, max_speed);
xfer->sc = (caddr_t)sdev;
- xfer->fc = sdev->target->sbp->fd.fc;
- xfer->retry_req = fw_asybusy;
-
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.wreqq.dest_hi = htons(sdev->login.cmd_hi);
- fp->mode.wreqq.dest_lo = htonl(sdev->login.cmd_lo + offset);
+ fp->mode.wreqq.dest_hi = sdev->login->cmd_hi;
+ fp->mode.wreqq.dest_lo = sdev->login->cmd_lo + offset;
fp->mode.wreqq.tlrt = 0;
fp->mode.wreqq.tcode = tcode;
fp->mode.wreqq.pri = 0;
xfer->dst = FWLOCALBUS | sdev->target->fwdev->dst;
- fp->mode.wreqq.dst = htons(xfer->dst);
+ fp->mode.wreqq.dst = xfer->dst;
return xfer;
@@ -1240,8 +1251,7 @@ sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb);
goto start;
}
- if ((ocb = sbp_get_ocb(target->sbp)) == NULL) {
- target->sbp->flags |= SBP_RESOURCE_SHORTAGE;
+ if ((ocb = sbp_get_ocb(sdev)) == NULL) {
splx(s);
return;
}
@@ -1262,20 +1272,21 @@ END_DEBUG
switch (func) {
case ORB_FUN_LGI:
ocb->orb[2] = htonl(nid << 16);
- ocb->orb[3] = htonl(vtophys(&sdev->login));
+ ocb->orb[3] = htonl(sdev->dma.bus_addr);
ocb->orb[4] = htonl(ORB_NOTIFY | ORB_EXV | sdev->lun_id);
- ocb->orb[5] = htonl(sizeof(struct sbp_login_res));
+ ocb->orb[5] = htonl(SBP_LOGIN_SIZE);
+ fwdma_sync(&sdev->dma, BUS_DMASYNC_PREREAD);
break;
case ORB_FUN_ATA:
ocb->orb[0] = htonl((0 << 16) | 0);
- ocb->orb[1] = htonl(vtophys(&aocb->orb[0]));
+ ocb->orb[1] = htonl(aocb->bus_addr & 0xffffffff);
/* fall through */
case ORB_FUN_RCN:
case ORB_FUN_LGO:
case ORB_FUN_LUR:
case ORB_FUN_RST:
case ORB_FUN_ATS:
- ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login.id);
+ ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login->id);
break;
}
@@ -1298,12 +1309,12 @@ start:
xfer->act.hand = sbp_login_callback;
fp = (struct fw_pkt *)xfer->send.buf;
- fp->mode.wreqb.dest_hi = htons(sdev->target->mgm_hi);
- fp->mode.wreqb.dest_lo = htonl(sdev->target->mgm_lo);
- fp->mode.wreqb.len = htons(8);
+ fp->mode.wreqb.dest_hi = sdev->target->mgm_hi;
+ fp->mode.wreqb.dest_lo = sdev->target->mgm_lo;
+ fp->mode.wreqb.len = 8;
fp->mode.wreqb.extcode = 0;
fp->mode.wreqb.payload[0] = htonl(nid << 16);
- fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0]));
+ fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr);
fw_asyreq(xfer->fc, -1, xfer);
}
@@ -1348,7 +1359,7 @@ SBP_DEBUG(0)
sbp_print_scsi_cmd(ocb);
/* XXX need decode status */
sbp_show_sdev_info(ocb->sdev, 2);
- printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d",
+ printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d\n",
sbp_cmd_status->status,
sbp_cmd_status->sfmt,
sbp_cmd_status->valid,
@@ -1357,20 +1368,6 @@ SBP_DEBUG(0)
sbp_cmd_status->s_qlfr,
sbp_status->len
);
-#if 0 /* XXX */
- if (sbp_cmd_status->status == SCSI_STATUS_CHECK_COND) {
- printf(" %s\n", scsi_sense_key_text[sbp_cmd_status->s_key]);
- scsi_sense_desc(
- sbp_cmd_status->s_code,
- sbp_cmd_status->s_qlfr,
- ocb->ccb->ccb_h.path->device->inq_data
- )
- } else {
- printf("\n");
- }
-#else
- printf("\n");
-#endif
END_DEBUG
switch (sbp_cmd_status->status) {
@@ -1485,7 +1482,8 @@ END_DEBUG
}
static void
-sbp_recv1(struct fw_xfer *xfer){
+sbp_recv1(struct fw_xfer *xfer)
+{
struct fw_pkt *rfp;
#if NEED_RESPONSE
struct fw_pkt *sfp;
@@ -1506,25 +1504,24 @@ printf("sbp %x %d %d %08x %08x %08x %08x\n",
printf("sbp %08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
printf("sbp %08x %08x %08x %08x\n", ntohl(ld[8]), ntohl(ld[9]), ntohl(ld[10]), ntohl(ld[11]));
*/
+
+ sbp = (struct sbp_softc *)xfer->sc;
if(xfer->resp != 0){
printf("sbp_recv: xfer->resp != 0\n");
- fw_xfer_free( xfer);
- return;
+ goto done0;
}
if(xfer->recv.buf == NULL){
printf("sbp_recv: xfer->recv.buf == NULL\n");
- fw_xfer_free( xfer);
- return;
+ goto done0;
}
sbp = (struct sbp_softc *)xfer->sc;
rfp = (struct fw_pkt *)xfer->recv.buf;
if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){
printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode);
- fw_xfer_free( xfer);
- return;
+ goto done0;
}
sbp_status = (struct sbp_status *)rfp->mode.wreqb.payload;
- addr = ntohl(rfp->mode.wreqb.dest_lo);
+ addr = rfp->mode.wreqb.dest_lo;
SBP_DEBUG(2)
printf("received address 0x%x\n", addr);
END_DEBUG
@@ -1532,16 +1529,14 @@ END_DEBUG
if (t >= SBP_NUM_TARGETS) {
device_printf(sbp->fd.dev,
"sbp_recv1: invalid target %d\n", t);
- fw_xfer_free(xfer);
- return;
+ goto done0;
}
target = &sbp->targets[t];
l = SBP_ADDR2LUN(addr);
if (l >= target->num_lun) {
device_printf(sbp->fd.dev,
"sbp_recv1: invalid lun %d (target=%d)\n", l, t);
- fw_xfer_free(xfer);
- return;
+ goto done0;
}
sdev = &target->luns[l];
@@ -1648,7 +1643,8 @@ END_DEBUG
orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK;
switch(orb_fun) {
case ORB_FUN_LGI:
- login_res = &sdev->login;
+ fwdma_sync(&sdev->dma, BUS_DMASYNC_POSTREAD);
+ login_res = sdev->login;
login_res->len = ntohs(login_res->len);
login_res->id = ntohs(login_res->id);
login_res->cmd_hi = ntohs(login_res->cmd_hi);
@@ -1658,14 +1654,7 @@ SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo, ntohs(login_res->recon_hold));
END_DEBUG
-#if 0
- sdev->status = SBP_DEV_TOATTACH;
-#endif
-#if 1
sbp_busy_timeout(sdev);
-#else
- sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL);
-#endif
} else {
/* forgot logout? */
sbp_show_sdev_info(sdev, 2);
@@ -1674,7 +1663,7 @@ END_DEBUG
}
break;
case ORB_FUN_RCN:
- login_res = &sdev->login;
+ login_res = sdev->login;
if (status_valid) {
SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
@@ -1749,11 +1738,12 @@ printf("len %d\n", sbp_status->len);
}
}
- sbp_free_ocb(sbp, ocb);
+ sbp_free_ocb(sdev, ocb);
done:
if (reset_agent)
sbp_agent_reset(sdev);
+done0:
/* The received packet is usually small enough to be stored within
* the buffer. In that case, the controller return ack_complete and
* no respose is necessary.
@@ -1762,12 +1752,10 @@ done:
* ack_complete or ack_pending to upper driver.
*/
#if NEED_RESPONSE
- xfer->send.buf = malloc(12, M_SBP, M_NOWAIT | M_ZERO);
- xfer->send.len = 12;
xfer->send.off = 0;
sfp = (struct fw_pkt *)xfer->send.buf;
sfp->mode.wres.dst = rfp->mode.wreqb.src;
- xfer->dst = ntohs(sfp->mode.wres.dst);
+ xfer->dst = sfp->mode.wres.dst;
xfer->spd = min(sdev->target->fwdev->speed, max_speed);
xfer->act.hand = sbp_loginres_callback;
xfer->retry_req = fw_asybusy;
@@ -1779,7 +1767,9 @@ done:
fw_asyreq(xfer->fc, -1, xfer);
#else
- fw_xfer_free(xfer);
+ /* recycle */
+ xfer->recv.len = SBP_RECV_LEN;
+ STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
#endif
return;
@@ -1816,8 +1806,9 @@ END_DEBUG
bzero(sbp, sizeof(struct sbp_softc));
sbp->fd.dev = dev;
sbp->fd.fc = device_get_ivars(dev);
-#define SBP_SEG_MAX 0x8000
- error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
+ error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat,
+ /* XXX shoud be 4 for sane backend? */
+ /*alignment*/1,
/*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
@@ -1852,20 +1843,6 @@ END_DEBUG
return (ENXIO);
}
- sbp->ocb = (struct sbp_ocb *) contigmalloc(
- sizeof (struct sbp_ocb) * SBP_NUM_OCB,
- M_SBP, M_NOWAIT, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
- bzero(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB);
-
- if (sbp->ocb == NULL) {
- printf("sbp0: ocb alloction failure\n");
- return (ENOMEM);
- }
-
- STAILQ_INIT(&sbp->free_ocbs);
- for (i = 0; i < SBP_NUM_OCB; i++) {
- sbp_free_ocb(sbp, &sbp->ocb[i]);
- }
if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS)
goto fail;
@@ -1874,21 +1851,31 @@ END_DEBUG
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
goto fail;
- xfer = fw_xfer_alloc(M_SBP);
- xfer->act.hand = sbp_recv;
- xfer->act_type = FWACT_XFER;
-#if NEED_RESPONSE
- xfer->fc = sbp->fd.fc;
-#endif
- xfer->sc = (caddr_t)sbp;
-
sbp->fwb.start_hi = SBP_BIND_HI;
sbp->fwb.start_lo = SBP_DEV2ADDR(device_get_unit(sbp->fd.dev), 0, 0);
/* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
sbp->fwb.addrlen = 0xffff;
- sbp->fwb.xfer = xfer;
+ sbp->fwb.act_type = FWACT_XFER;
+ /* pre-allocate xfer */
+ STAILQ_INIT(&sbp->fwb.xferlist);
+ for (i = 0; i < SBP_NUM_OCB/2; i ++) {
+ xfer = fw_xfer_alloc_buf(M_SBP,
+#if NEED_RESPONSE
+ /* send */12,
+#else
+ /* send */0,
+#endif
+ /* recv */SBP_RECV_LEN);
+ xfer->act.hand = sbp_recv;
+#if NEED_RESPONSE
+ xfer->fc = sbp->fd.fc;
+#endif
+ xfer->sc = (caddr_t)sbp;
+ STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
+ }
fw_bindadd(sbp->fd.fc, &sbp->fwb);
+ sbp->fd.post_busreset = sbp_post_busreset;
sbp->fd.post_explore = sbp_post_explore;
if (sbp->fd.fc->status != -1) {
@@ -1900,7 +1887,6 @@ END_DEBUG
return (0);
fail:
cam_sim_free(sbp->sim, /*free_devq*/TRUE);
- contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP);
return (ENXIO);
}
@@ -1920,11 +1906,13 @@ END_DEBUG
continue;
for (j = 0; j < target->num_lun; j++) {
sdev = &target->luns[j];
+ callout_stop(&sdev->login_callout);
if (sdev->status >= SBP_DEV_TOATTACH &&
sdev->status <= SBP_DEV_ATTACHED)
sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL);
}
}
+
return 0;
}
@@ -1942,33 +1930,56 @@ sbp_detach(device_t dev)
{
struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
struct firewire_comm *fc = sbp->fd.fc;
- int i;
+ struct sbp_target *target;
+ struct sbp_dev *sdev;
+ struct fw_xfer *xfer, *next;
+ int i, j;
SBP_DEBUG(0)
printf("sbp_detach\n");
END_DEBUG
-#if 0
- /* bus reset for logout */
- sbp->fd.post_explore = NULL;
- fc->ibr(fc);
-#endif
-
+
for (i = 0; i < SBP_NUM_TARGETS; i ++)
sbp_cam_detach_target(&sbp->targets[i]);
xpt_free_path(sbp->path);
xpt_bus_deregister(cam_sim_path(sbp->sim));
sbp_logout_all(sbp);
+
/* XXX wait for logout completion */
tsleep(&i, FWPRI, "sbpdtc", hz/2);
+ for (i = 0 ; i < SBP_NUM_TARGETS ; i ++) {
+ target = &sbp->targets[i];
+ if (target->luns == NULL)
+ continue;
+ callout_stop(&target->mgm_ocb_timeout);
+ for (j = 0; j < target->num_lun; j++) {
+ sdev = &target->luns[j];
+ if (sdev->status != SBP_DEV_DEAD) {
+ for (i = 0; i < SBP_QUEUE_LEN; i++)
+ bus_dmamap_destroy(sbp->dmat,
+ sdev->ocb[i].dmamap);
+ fwdma_free(sbp->fd.fc, &sdev->dma);
+ }
+ }
+ for (xfer = STAILQ_FIRST(&target->xferlist);
+ xfer != NULL; xfer = next) {
+ next = STAILQ_NEXT(xfer, link);
+ fw_xfer_free(xfer);
+ }
+ free(target->luns, M_SBP);
+ }
+
+ for (xfer = STAILQ_FIRST(&sbp->fwb.xferlist);
+ xfer != NULL; xfer = next) {
+ next = STAILQ_NEXT(xfer, link);
+ fw_xfer_free(xfer);
+ }
+ STAILQ_INIT(&sbp->fwb.xferlist);
fw_bindremove(fc, &sbp->fwb);
- contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP);
- bus_dma_tag_destroy(sbp->dmat);
- for (i = 0; i < SBP_NUM_TARGETS; i ++)
- if (sbp->targets[i].luns != NULL)
- free(sbp->targets[i].luns, M_SBP);
+ bus_dma_tag_destroy(sbp->dmat);
return (0);
}
@@ -1976,20 +1987,19 @@ END_DEBUG
static void
sbp_cam_detach_target(struct sbp_target *target)
{
- int i;
struct sbp_dev *sdev;
+ int i;
if (target->luns != NULL) {
SBP_DEBUG(0)
printf("sbp_detach_target %d\n", target->target_id);
END_DEBUG
callout_stop(&target->scan_callout);
- callout_stop(&target->mgm_ocb_timeout);
for (i = 0; i < target->num_lun; i++) {
sdev = &target->luns[i];
- callout_stop(&sdev->login_callout);
- if (sdev->status == SBP_DEV_RESET ||
- sdev->status == SBP_DEV_DEAD)
+ if (sdev->status == SBP_DEV_DEAD)
+ continue;
+ if (sdev->status == SBP_DEV_RESET)
continue;
if (sdev->path) {
xpt_async(AC_LOST_DEVICE, sdev->path, NULL);
@@ -2014,7 +2024,7 @@ sbp_timeout(void *arg)
printf("management ORB\n");
/* XXX just ignore for now */
sdev->target->mgm_ocb_cur = NULL;
- sbp_free_ocb(sdev->target->sbp, ocb);
+ sbp_free_ocb(sdev, ocb);
sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
return;
}
@@ -2023,17 +2033,8 @@ sbp_timeout(void *arg)
sdev->freeze ++;
sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
if (sdev->flags & SBP_DEV_TIMEOUT) {
-#if 0
- struct firewire_comm *fc;
-
- printf("bus reset\n");
- fc = sdev->target->sbp->fd.fc;
- fc->ibr(fc);
- sdev->status == SBP_DEV_RETRY;
-#else
printf("target reset\n");
sbp_mgm_orb(sdev, ORB_FUN_RST, NULL);
-#endif
sdev->flags &= ~SBP_DEV_TIMEOUT;
} else {
printf("agent reset\n");
@@ -2122,7 +2123,7 @@ END_DEBUG
{
struct ccb_scsiio *csio;
struct sbp_ocb *ocb;
- int s, speed;
+ int speed;
void *cdb;
csio = &ccb->csio;
@@ -2166,12 +2167,9 @@ END_DEBUG
}
}
#endif
- if ((ocb = sbp_get_ocb(sbp)) == NULL) {
- s = splfw();
- sbp->flags |= SBP_RESOURCE_SHORTAGE;
- splx(s);
+ if ((ocb = sbp_get_ocb(sdev)) == NULL)
return;
- }
+
ocb->flags = OCB_ACT_CMD;
ocb->sdev = sdev;
ocb->ccb = ccb;
@@ -2179,7 +2177,7 @@ END_DEBUG
ocb->orb[0] = htonl(1 << 31);
ocb->orb[1] = 0;
ocb->orb[2] = htonl(((sbp->fd.fc->nodeid | FWLOCALBUS )<< 16) );
- ocb->orb[3] = htonl(vtophys(ocb->ind_ptr));
+ ocb->orb[3] = htonl(ocb->bus_addr + IND_PTR_OFFSET);
speed = min(target->fwdev->speed, max_speed);
ocb->orb[4] = htonl(ORB_NOTIFY | ORB_CMD_SPD(speed)
| ORB_CMD_MAXP(speed + 7));
@@ -2204,15 +2202,10 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntoh
printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7]));
*/
if (ccb->csio.dxfer_len > 0) {
- int s;
-
- if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) {
- printf("sbp_action1: cannot create dmamap\n");
- break;
- }
+ int s, error;
s = splsoftvm();
- bus_dmamap_load(/*dma tag*/sbp->dmat,
+ error = bus_dmamap_load(/*dma tag*/sbp->dmat,
/*dma map*/ocb->dmamap,
ccb->csio.data_ptr,
ccb->csio.dxfer_len,
@@ -2220,6 +2213,8 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntoh
ocb,
/*flags*/0);
splx(s);
+ if (error)
+ printf("sbp: bus_dmamap_load error %d\n", error);
} else
sbp_execute_ocb(ocb, NULL, 0, 0);
break;
@@ -2348,13 +2343,25 @@ sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error)
int i;
struct sbp_ocb *ocb;
struct sbp_ocb *prev;
- union ccb *ccb;
bus_dma_segment_t *s;
if (error)
printf("sbp_execute_ocb: error=%d\n", error);
ocb = (struct sbp_ocb *)arg;
+
+SBP_DEBUG(1)
+ printf("sbp_execute_ocb: seg %d", seg);
+ for (i = 0; i < seg; i++)
+#if __FreeBSD_version >= 500000
+ printf(", %tx:%zd", segments[i].ds_addr,
+#else
+ printf(", %x:%d", segments[i].ds_addr,
+#endif
+ segments[i].ds_len);
+ printf("\n");
+END_DEBUG
+
if (seg == 1) {
/* direct pointer */
s = &segments[0];
@@ -2364,17 +2371,6 @@ sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error)
ocb->orb[4] |= htonl(s->ds_len);
} else if(seg > 1) {
/* page table */
-SBP_DEBUG(1)
- printf("sbp_execute_ocb: seg %d", seg);
- for (i = 0; i < seg; i++)
-#if __FreeBSD_version >= 500000
- printf(", %tx:%zd", segments[i].ds_addr,
-#else
- printf(", %x:%d", segments[i].ds_addr,
-#endif
- segments[i].ds_len);
- printf("\n");
-END_DEBUG
for (i = 0; i < seg; i++) {
s = &segments[i];
SBP_DEBUG(0)
@@ -2396,8 +2392,12 @@ END_DEBUG
ocb->orb[4] |= htonl(ORB_CMD_PTBL | seg);
}
- ccb = ocb->ccb;
+ if (seg > 0)
+ bus_dmamap_sync(ocb->sdev->target->sbp->dmat, ocb->dmamap,
+ (ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
prev = sbp_enqueue_ocb(ocb->sdev, ocb);
+ fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE);
if (prev == NULL)
sbp_orb_pointer(ocb->sdev, ocb);
}
@@ -2426,7 +2426,7 @@ SBP_DEBUG(1)
#else
printf("orb: 0x%x next: 0x%lx, flags %x\n",
#endif
- vtophys(&ocb->orb[0]), ntohl(ocb->orb[1]), flags);
+ ocb->bus_addr, ntohl(ocb->orb[1]), flags);
END_DEBUG
if (OCB_MATCH(ocb, sbp_status)) {
/* found */
@@ -2434,10 +2434,14 @@ END_DEBUG
if (ocb->ccb != NULL)
untimeout(sbp_timeout, (caddr_t)ocb,
ocb->ccb->ccb_h.timeout_ch);
- if (ocb->dmamap != NULL) {
- bus_dmamap_destroy(sdev->target->sbp->dmat,
- ocb->dmamap);
- ocb->dmamap = NULL;
+ if (ntohl(ocb->orb[4]) & 0xffff) {
+ bus_dmamap_sync(sdev->target->sbp->dmat,
+ ocb->dmamap,
+ (ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
+ BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sdev->target->sbp->dmat,
+ ocb->dmamap);
}
if (next != NULL && sbp_status->src == 1)
sbp_orb_pointer(sdev, next);
@@ -2464,9 +2468,9 @@ sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
SBP_DEBUG(2)
sbp_show_sdev_info(sdev, 2);
#if __FreeBSD_version >= 500000
- printf("sbp_enqueue_ocb orb=0x%tx in physical memory\n", vtophys(&ocb->orb[0]));
+ printf("sbp_enqueue_ocb orb=0x%tx in physical memory\n", ocb->bus_addr);
#else
- printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", vtophys(&ocb->orb[0]));
+ printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", ocb->bus_addr);
#endif
END_DEBUG
prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb);
@@ -2479,13 +2483,13 @@ END_DEBUG
if (prev != NULL ) {
SBP_DEBUG(1)
#if __FreeBSD_version >= 500000
- printf("linking chain 0x%tx -> 0x%tx\n", vtophys(&prev->orb[0]),
+ printf("linking chain 0x%tx -> 0x%tx\n", prev->bus_addr,
#else
- printf("linking chain 0x%x -> 0x%x\n", vtophys(&prev->orb[0]),
+ printf("linking chain 0x%x -> 0x%x\n", prev->bus_addr,
#endif
- vtophys(&ocb->orb[0]));
+ ocb->bus_addr);
END_DEBUG
- prev->orb[1] = htonl(vtophys(&ocb->orb[0]));
+ prev->orb[1] = htonl(ocb->bus_addr);
prev->orb[0] = 0;
}
splx(s);
@@ -2494,37 +2498,27 @@ END_DEBUG
}
static struct sbp_ocb *
-sbp_get_ocb(struct sbp_softc *sbp)
+sbp_get_ocb(struct sbp_dev *sdev)
{
struct sbp_ocb *ocb;
int s = splfw();
- ocb = STAILQ_FIRST(&sbp->free_ocbs);
+ ocb = STAILQ_FIRST(&sdev->free_ocbs);
if (ocb == NULL) {
printf("ocb shortage!!!\n");
return NULL;
}
- STAILQ_REMOVE_HEAD(&sbp->free_ocbs, ocb);
+ STAILQ_REMOVE_HEAD(&sdev->free_ocbs, ocb);
splx(s);
ocb->ccb = NULL;
return (ocb);
}
static void
-sbp_free_ocb(struct sbp_softc *sbp, struct sbp_ocb *ocb)
+sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
{
-#if 0 /* XXX make sure that ocb has ccb */
- if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0 &&
- (ocb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
- ocb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
- sbp->flags &= ~SBP_RESOURCE_SHORTAGE;
- }
-#else
- if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0)
- sbp->flags &= ~SBP_RESOURCE_SHORTAGE;
-#endif
ocb->flags = 0;
ocb->ccb = NULL;
- STAILQ_INSERT_TAIL(&sbp->free_ocbs, ocb, ocb);
+ STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb);
}
static void
@@ -2533,28 +2527,32 @@ sbp_abort_ocb(struct sbp_ocb *ocb, int status)
struct sbp_dev *sdev;
sdev = ocb->sdev;
-SBP_DEBUG(1)
+SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
#if __FreeBSD_version >= 500000
printf("sbp_abort_ocb 0x%tx\n",
#else
printf("sbp_abort_ocb 0x%x\n",
#endif
- vtophys(&ocb->orb[0]));
+ ocb->bus_addr);
+END_DEBUG
+SBP_DEBUG(1)
if (ocb->ccb != NULL)
sbp_print_scsi_cmd(ocb);
END_DEBUG
+ if (ntohl(ocb->orb[4]) & 0xffff) {
+ bus_dmamap_sync(sdev->target->sbp->dmat, ocb->dmamap,
+ (ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap);
+ }
if (ocb->ccb != NULL) {
untimeout(sbp_timeout, (caddr_t)ocb,
ocb->ccb->ccb_h.timeout_ch);
ocb->ccb->ccb_h.status = status;
xpt_done(ocb->ccb);
}
- if (ocb->dmamap != NULL) {
- bus_dmamap_destroy(sdev->target->sbp->dmat, ocb->dmamap);
- ocb->dmamap = NULL;
- }
- sbp_free_ocb(sdev->target->sbp, ocb);
+ sbp_free_ocb(sdev, ocb);
}
static void
diff --git a/sys/modules/firewire/Makefile.inc b/sys/modules/firewire/Makefile.inc
index 265f86d..4b82370 100644
--- a/sys/modules/firewire/Makefile.inc
+++ b/sys/modules/firewire/Makefile.inc
@@ -1,3 +1,4 @@
# $FreeBSD$
+#CFLAGS+=-g
.include "../Makefile.inc"
diff --git a/sys/modules/firewire/firewire/Makefile b/sys/modules/firewire/firewire/Makefile
index 5d76615..8e4e06f 100644
--- a/sys/modules/firewire/firewire/Makefile
+++ b/sys/modules/firewire/firewire/Makefile
@@ -9,7 +9,7 @@ SRCS = bus_if.h device_if.h pci_if.h \
firewire.c firewire.h firewire_phy.h firewirereg.h \
fwohci.c fwohci_pci.c fwohcireg.h fwohcivar.h \
iec13213.h iec68113.h \
- fwcrom.c fwdev.c fwmem.c fwmem.h
+ fwcrom.c fwdev.c fwmem.c fwmem.h fwdma.c fwdma.h
.include <bsd.kmod.mk>
diff --git a/sys/modules/firewire/fwe/Makefile b/sys/modules/firewire/fwe/Makefile
index d3e1630..6b26606 100644
--- a/sys/modules/firewire/fwe/Makefile
+++ b/sys/modules/firewire/fwe/Makefile
@@ -9,6 +9,7 @@ SRCS = bus_if.h device_if.h \
opt_inet.h \
if_fwe.c if_fwevar.h \
firewire.h firewirereg.h
+#CFLAGS += -DDEVICE_POLLING
.include <bsd.kmod.mk>
diff --git a/usr.sbin/fwcontrol/fwcontrol.c b/usr.sbin/fwcontrol/fwcontrol.c
index 6044ece..3ac3814 100644
--- a/usr.sbin/fwcontrol/fwcontrol.c
+++ b/usr.sbin/fwcontrol/fwcontrol.c
@@ -127,8 +127,8 @@ read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int3
else
asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
- asyreq->pkt.mode.rreqq.dest_hi = htons(0xffff);
- asyreq->pkt.mode.rreqq.dest_lo = htonl(addr_lo);
+ asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
+ asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
qld = (u_int32_t *)&asyreq->pkt;
if (!read)
@@ -157,9 +157,9 @@ send_phy_config(int fd, int root_node, int gap_count)
asyreq->pkt.mode.ld[1] = 0;
asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
if (root_node >= 0)
- asyreq->pkt.mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
+ asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
if (gap_count >= 0)
- asyreq->pkt.mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
+ asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
printf("send phy_config root_node=%d gap_count=%d\n",
@@ -251,8 +251,9 @@ show_crom(u_int32_t *crom_buf)
struct csrreg *reg;
struct csrdirectory *dir;
struct csrhdr *hdr;
+ u_int16_t crc;
- printf("first quad: 0x%08x\n", *crom_buf);
+ printf("first quad: 0x%08x ", *crom_buf);
hdr = (struct csrhdr *)crom_buf;
if (hdr->info_len == 1) {
/* minimum ROM */
@@ -261,13 +262,24 @@ show_crom(u_int32_t *crom_buf)
printf("verndor ID: 0x%06x\n", reg->val);
return;
}
- printf("len: %d\n", hdr->crc_len);
+ printf("info_len=%d crc_len=%d crc=0x%04x",
+ hdr->info_len, hdr->crc_len, hdr->crc);
+ crc = crom_crc(crom_buf+1, hdr->crc_len);
+ if (crc == hdr->crc)
+ printf("(OK)\n");
+ else
+ printf("(NG)\n");
parse_bus_info_block(crom_buf+1, hdr->info_len);
crom_init_context(&cc, crom_buf);
dir = cc.stack[0].dir;
- printf("root_directory: len=0x%04x(%d) crc=0x%04x\n",
+ printf("root_directory: len=0x%04x(%d) crc=0x%04x",
dir->crc_len, dir->crc_len, dir->crc);
+ crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
+ if (crc == dir->crc)
+ printf("(OK)\n");
+ else
+ printf("(NG)\n");
if (dir->crc_len < 1)
return;
while (cc.depth >= 0) {
diff --git a/usr.sbin/fwcontrol/fwcrom.c b/usr.sbin/fwcontrol/fwcrom.c
index d58be50..af57c8e 100644
--- a/usr.sbin/fwcontrol/fwcrom.c
+++ b/usr.sbin/fwcontrol/fwcrom.c
@@ -35,8 +35,9 @@
*/
#include <sys/param.h>
-#include <dev/firewire/firewire.h>
-#include <dev/firewire/iec13213.h>
+#if defined(_KERNEL) || defined(TEST)
+#include <sys/queue.h>
+#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -48,6 +49,8 @@
#include <stdlib.h>
#include <string.h>
#endif
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
void
crom_init_context(struct crom_context *cc, u_int32_t *p)
@@ -179,20 +182,28 @@ crom_desc(struct crom_context *cc, char *buf, int len)
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
+ u_int16_t crc;
reg = crom_get(cc);
switch (reg->key & CSRTYPE_MASK) {
case CSRTYPE_I:
snprintf(buf, len, "%d", reg->val);
break;
- case CSRTYPE_L:
case CSRTYPE_C:
snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
break;
+ case CSRTYPE_L:
+ /* XXX fall through */
case CSRTYPE_D:
dir = (struct csrdirectory *) (reg + reg->val);
- snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
- dir->crc_len, dir->crc_len, dir->crc);
+ crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
+ len -= snprintf(buf, len, "len=%d crc=0x%04x",
+ dir->crc_len, dir->crc);
+ if (crc == dir->crc)
+ strncat(buf, "(OK) ", len);
+ else
+ strncat(buf, "(NG) ", len);
+ len -= 5;
}
switch (reg->key) {
case 0x03:
@@ -239,7 +250,7 @@ crom_desc(struct crom_context *cc, char *buf, int len)
break;
case 0x81:
desc = "text_leaf";
- crom_parse_text(cc, buf, len);
+ crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
@@ -253,3 +264,239 @@ crom_desc(struct crom_context *cc, char *buf, int len)
return desc;
}
#endif
+
+#if defined(_KERNEL) || defined(TEST)
+
+int
+crom_add_quad(struct crom_chunk *chunk, u_int32_t entry)
+{
+ int index;
+
+ index = chunk->data.crc_len;
+ if (index >= CROM_MAX_CHUNK_LEN - 1) {
+ printf("too large chunk %d\n", index);
+ return(-1);
+ }
+ chunk->data.buf[index] = entry;
+ chunk->data.crc_len++;
+ return(index);
+}
+
+int
+crom_add_entry(struct crom_chunk *chunk, int key, int val)
+{
+ struct csrreg *reg;
+ u_int32_t i;
+
+ reg = (struct csrreg *)&i;
+ reg->key = key;
+ reg->val = val;
+ return(crom_add_quad(chunk, (u_int32_t) i));
+}
+
+int
+crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *child, int key)
+{
+ int index;
+
+ if (parent == NULL) {
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(0);
+ }
+
+ index = crom_add_entry(parent, key, 0);
+ if (index < 0) {
+ return(-1);
+ }
+ child->ref_chunk = parent;
+ child->ref_index = index;
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(index);
+}
+
+int
+crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *chunk, char *buf)
+{
+ struct csrtext *tl;
+ u_int32_t *p;
+ int len, i;
+
+ len = strlen(buf);
+#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
+ if (len > MAX_TEXT) {
+ printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
+ len = MAX_TEXT;
+ }
+
+ tl = (struct csrtext *) &chunk->data;
+ tl->crc_len = roundup2(sizeof(struct csrtext) + len, 4) / 4;
+ tl->spec_id = 0;
+ tl->spec_type = 0;
+ tl->lang_id = 0;
+ p = (u_int32_t *) buf;
+ for (i = 0; i < roundup2(len, 4) / 4; i ++)
+ tl->text[i] = ntohl(*p++);
+ return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
+}
+
+static int
+crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen)
+{
+ if (*offset + len > maxlen) {
+ printf("Config. ROM is too large for the buffer\n");
+ return(-1);
+ }
+ bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t));
+ *offset += len;
+ return(0);
+}
+
+int
+crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
+{
+ struct crom_chunk *chunk, *parent;
+ struct csrhdr *hdr;
+#if 0
+ u_int32_t *ptr;
+#endif
+ int count, offset;
+ int len;
+
+ offset = 0;
+ /* Determine offset */
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->offset = offset;
+ /* Assume the offset of the parent is already known */
+ parent = chunk->ref_chunk;
+ if (parent != NULL) {
+ struct csrreg *reg;
+ reg = (struct csrreg *)
+ &parent->data.buf[chunk->ref_index];
+ reg->val = offset -
+ (parent->offset + 1 + chunk->ref_index);
+ }
+ offset += 1 + chunk->data.crc_len;
+ }
+
+ /* Calculate CRC and dump to the buffer */
+ len = 1 + src->hdr.info_len;
+ count = 0;
+ if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
+ return(-1);
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->data.crc =
+ crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
+
+ len = 1 + chunk->data.crc_len;
+ if (crom_copy((u_int32_t *)&chunk->data, buf,
+ &count, len, maxlen) < 0)
+ return(-1);
+ }
+ hdr = (struct csrhdr *)buf;
+ hdr->crc_len = count - 1;
+ hdr->crc = crom_crc(buf + 1, hdr->crc_len);
+
+#if 0
+ /* byte swap */
+ ptr = buf;
+ for (i = 0; i < count; i ++) {
+ *ptr = htonl(*ptr);
+ ptr++;
+ }
+#endif
+
+ return(count);
+}
+#endif
+
+#ifdef TEST
+int
+main () {
+ struct crom_src src;
+ struct crom_chunk root,unit1,unit2,unit3;
+ struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
+ u_int32_t buf[256], *p;
+ int i;
+
+ bzero(&src, sizeof(src));
+ bzero(&root, sizeof(root));
+ bzero(&unit1, sizeof(unit1));
+ bzero(&unit2, sizeof(unit2));
+ bzero(&unit3, sizeof(unit3));
+ bzero(&text1, sizeof(text1));
+ bzero(&text2, sizeof(text2));
+ bzero(&text3, sizeof(text3));
+ bzero(&text3, sizeof(text4));
+ bzero(&text3, sizeof(text5));
+ bzero(&text3, sizeof(text6));
+ bzero(&text3, sizeof(text7));
+ bzero(buf, sizeof(buf));
+
+ /* BUS info sample */
+ src.hdr.info_len = 4;
+ src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
+ src.businfo.eui64.hi = 0x11223344;
+ src.businfo.eui64.lo = 0x55667788;
+ src.businfo.link_spd = FWSPD_S400;
+ src.businfo.generation = 0;
+ src.businfo.max_rom = MAXROM_4;
+ src.businfo.max_rec = 10;
+ src.businfo.cyc_clk_acc = 100;
+ src.businfo.pmc = 0;
+ src.businfo.bmc = 1;
+ src.businfo.isc = 1;
+ src.businfo.cmc = 1;
+ src.businfo.irmc = 1;
+ STAILQ_INIT(&src.chunk_list);
+
+ /* Root directory */
+ crom_add_chunk(&src, NULL, &root, 0);
+ crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
+ /* private company_id */
+ crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
+
+ crom_add_simple_text(&src, &root, &text1, "FreeBSD");
+ crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
+ crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
+
+ /* SBP unit directory */
+ crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
+ crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
+ crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
+ /* management_agent */
+ crom_add_entry(&unit1, CROM_MGM, 0x1000);
+ crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
+ /* Device type and LUN */
+ crom_add_entry(&unit1, CROM_LUN, 0);
+ crom_add_entry(&unit1, CSRKEY_MODEL, 1);
+ crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
+
+ /* RFC2734 IPv4 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
+ crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit2, &text4, "IANA");
+ crom_add_entry(&unit2, CSRKEY_VER, 1);
+ crom_add_simple_text(&src, &unit2, &text5, "IPv4");
+
+ /* RFC3146 IPv6 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
+ crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit3, &text6, "IANA");
+ crom_add_entry(&unit3, CSRKEY_VER, 2);
+ crom_add_simple_text(&src, &unit3, &text7, "IPv6");
+
+ crom_load(&src, buf, 256);
+ p = buf;
+#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
+ for (i = 0; i < 256/8; i ++) {
+ printf(DUMP_FORMAT,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ return(0);
+}
+#endif
diff --git a/usr.sbin/fwcontrol/fwdv.c b/usr.sbin/fwcontrol/fwdv.c
index 432625a..43f5a98 100644
--- a/usr.sbin/fwcontrol/fwdv.c
+++ b/usr.sbin/fwcontrol/fwdv.c
@@ -173,7 +173,7 @@ again:
fprintf(stderr, "0x%04x\n", ntohs(ciph->fdf.dv.cyc));
}
#endif
- if (ntohs(pkt->mode.stream.len) <= sizeof(struct ciphdr))
+ if (pkt->mode.stream.len <= sizeof(struct ciphdr))
/* no payload */
goto next;
for (dv = (struct dvdbc *)ptr;
@@ -281,13 +281,13 @@ dvsend(int d, char *filename, char ich, int count)
iso_data = 0;
pkt = (struct fw_pkt *) &iso_data;
- pkt->mode.stream.len = htons(DSIZE + sizeof(struct ciphdr));
+ pkt->mode.stream.len = DSIZE + sizeof(struct ciphdr);
pkt->mode.stream.sy = 0;
pkt->mode.stream.tcode = FWTCODE_STREAM;
pkt->mode.stream.chtag = ich;
iso_empty = iso_data;
pkt = (struct fw_pkt *) &iso_empty;
- pkt->mode.stream.len = htons(sizeof(struct ciphdr));
+ pkt->mode.stream.len = sizeof(struct ciphdr);
bzero(hdr[0], sizeof(hdr[0]));
hdr[0][0] = iso_data;
OpenPOWER on IntegriCloud