diff options
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; |