summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2003-04-17 03:38:03 +0000
committersimokawa <simokawa@FreeBSD.org>2003-04-17 03:38:03 +0000
commit29b43e58e396537013e1057229debf865e3901e1 (patch)
tree11114a8420b3e8fd28f1d77e46ddae593b132e23 /sys
parentf946ac101075e1f9e524d40e1cccc51f674b7f5a (diff)
downloadFreeBSD-src-29b43e58e396537013e1057229debf865e3901e1.zip
FreeBSD-src-29b43e58e396537013e1057229debf865e3901e1.tar.gz
MFp4(simokawa_firewire):
Many internal structure changes for the FireWire driver. - Compute CRC in CROM parsing. - Add support for configuration ROM build. - Simplify dummy buffer handling. - busdma conversion - Use swi_taskqueue_giant for -current. Mark the interrupt routine as MPSAFE. - AR buffer handling. Don't reallocate AR buffer but just recycle it. Don't malloc and copy per packet in fwohci_arcv(). Pass packet to fw_rcv() using iovec. Application must prepare receiving buffer in advance. - Change fw_bind API so that application should pre-allocate xfer structure. - Add fw_xfer_unload() for recycling struct fw_xfer. - Add post_busreset hook - Remove unused 'sub' and 'act_type' in struct fw_xfer. - Remove npacket from struct fw_bulkxfer. - Don't call back handlers in fwochi_arcv() if the packet has not drained in AT queue - Make firewire works on big endian platform. - Use native endian for packet header and remove unnecessary ntohX/htonX. - Remove FWXFERQ_PACKET mode. We don't use it anymore. - Remove unnecessary restriction of FWSTMAXCHUNK. - Don't set root node for phy config packet if the root node is not cycle master capable but set myself for root node. We should be the root node after next bus reset. Spotted by: Yoshihiro Tabira <tabira@scd.mei.co.jp> - Improve self id handling Tested on: i386, sparc64 and i386 with forced bounce buffer
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/firewire/firewire.c467
-rw-r--r--sys/dev/firewire/firewire.h263
-rw-r--r--sys/dev/firewire/firewire_phy.h2
-rw-r--r--sys/dev/firewire/firewirereg.h94
-rw-r--r--sys/dev/firewire/fwcrom.c265
-rw-r--r--sys/dev/firewire/fwdev.c377
-rw-r--r--sys/dev/firewire/fwdma.c208
-rw-r--r--sys/dev/firewire/fwdma.h116
-rw-r--r--sys/dev/firewire/fwmem.c72
-rw-r--r--sys/dev/firewire/fwmem.h2
-rw-r--r--sys/dev/firewire/fwohci.c1565
-rw-r--r--sys/dev/firewire/fwohci_pci.c77
-rw-r--r--sys/dev/firewire/fwohcireg.h155
-rw-r--r--sys/dev/firewire/fwohcivar.h39
-rw-r--r--sys/dev/firewire/iec13213.h130
-rw-r--r--sys/dev/firewire/iec68113.h53
-rw-r--r--sys/dev/firewire/if_fwe.c97
-rw-r--r--sys/dev/firewire/if_fwevar.h2
-rw-r--r--sys/dev/firewire/sbp.c632
-rw-r--r--sys/modules/firewire/Makefile.inc1
-rw-r--r--sys/modules/firewire/firewire/Makefile2
-rw-r--r--sys/modules/firewire/fwe/Makefile1
22 files changed, 2480 insertions, 2140 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>
OpenPOWER on IntegriCloud