diff options
| author | Hidetoshi Shimokawa <simokawa@FreeBSD.org> | 2003-02-03 08:12:28 +0000 |
|---|---|---|
| committer | Hidetoshi Shimokawa <simokawa@FreeBSD.org> | 2003-02-03 08:12:28 +0000 |
| commit | 12e737f158d043eba31e616a58eee9efbbad177f (patch) | |
| tree | c25d3c2bfcbaf36b183127c73dd33de55142c8b9 /sys/dev/firewire/firewire.c | |
| parent | e3b89c356b79c931cc823742b2ab695233f970ac (diff) | |
Notes
Diffstat (limited to 'sys/dev/firewire/firewire.c')
| -rw-r--r-- | sys/dev/firewire/firewire.c | 240 |
1 files changed, 147 insertions, 93 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 0b93285f8456..6b509c049f1b 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -54,6 +54,7 @@ #include <dev/firewire/firewire.h> #include <dev/firewire/firewirereg.h> +#include <dev/firewire/fwmem.h> #include <dev/firewire/iec13213.h> #include <dev/firewire/iec68113.h> @@ -64,6 +65,9 @@ SYSCTL_NODE(_hw, OID_AUTO, firewire, CTLFLAG_RD, 0, "FireWire Subsystem"); SYSCTL_INT(_hw_firewire, OID_AUTO, try_bmr, CTLFLAG_RW, &try_bmr, 0, "Try to be a bus manager"); +MALLOC_DEFINE(M_FW, "firewire", "FireWire"); +MALLOC_DEFINE(M_FWXFER, "fw_xfer", "XFER/FireWire"); + #define FW_MAXASYRTY 4 #define FW_MAXDEVRCNT 4 @@ -91,6 +95,7 @@ static void fw_vmaccess __P((struct fw_xfer *)); #endif struct fw_xfer *asyreqq __P((struct firewire_comm *, u_int8_t, u_int8_t, u_int8_t, u_int32_t, u_int32_t, void (*)__P((struct fw_xfer *)))); +static int fw_bmr __P((struct firewire_comm *)); static device_method_t firewire_methods[] = { /* Device interface */ @@ -122,18 +127,40 @@ static driver_t firewire_driver = { }; /* - * To lookup node id. from EUI64. + * Lookup fwdev by node id. */ struct fw_device * -fw_noderesolve(struct firewire_comm *fc, struct fw_eui64 eui) +fw_noderesolve_nodeid(struct firewire_comm *fc, int dst) { struct fw_device *fwdev; - for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL; - fwdev = TAILQ_NEXT(fwdev, link)){ - if(fwdev->eui.hi == eui.hi && fwdev->eui.lo == eui.lo){ + int s; + + s = splfw(); + STAILQ_FOREACH(fwdev, &fc->devices, link) + if (fwdev->dst == dst) break; - } - } + splx(s); + + if(fwdev == NULL) return NULL; + if(fwdev->status == FWDEVINVAL) return NULL; + return fwdev; +} + +/* + * Lookup fwdev by EUI64. + */ +struct fw_device * +fw_noderesolve_eui64(struct firewire_comm *fc, struct fw_eui64 eui) +{ + struct fw_device *fwdev; + int s; + + s = splfw(); + STAILQ_FOREACH(fwdev, &fc->devices, link) + if (FW_EUI64_EQUAL(fwdev->eui, eui)) + break; + splx(s); + if(fwdev == NULL) return NULL; if(fwdev->status == FWDEVINVAL) return NULL; return fwdev; @@ -342,14 +369,18 @@ firewire_attach( device_t dev ) #else sc->dev[i] = d; #endif - sc->fc->timeouthandle = timeout((timeout_t *)sc->fc->timeout, (void *)sc->fc, hz * 10); - - callout_init(&sc->fc->busprobe_callout #if __FreeBSD_version >= 500000 - , /* mpsafe? */ 0); +#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */) #else - ); +#define CALLOUT_INIT(x) callout_init(x) #endif + CALLOUT_INIT(&sc->fc->timeout_callout); + CALLOUT_INIT(&sc->fc->bmr_callout); + CALLOUT_INIT(&sc->fc->retry_probe_callout); + CALLOUT_INIT(&sc->fc->busprobe_callout); + + callout_reset(&sc->fc->timeout_callout, hz * 10, + (void *)sc->fc->timeout, (void *)sc->fc); /* Locate our children */ bus_generic_probe(dev); @@ -402,9 +433,12 @@ firewire_detach( device_t dev ) } #endif /* XXX xfree_free and untimeout on all xfers */ - untimeout((timeout_t *)sc->fc->timeout, sc->fc, sc->fc->timeouthandle); - free(sc->fc->topology_map, M_DEVBUF); - free(sc->fc->speed_map, M_DEVBUF); + callout_stop(&sc->fc->timeout_callout); + callout_stop(&sc->fc->bmr_callout); + callout_stop(&sc->fc->retry_probe_callout); + callout_stop(&sc->fc->busprobe_callout); + free(sc->fc->topology_map, M_FW); + free(sc->fc->speed_map, M_FW); bus_generic_detach(dev); return(0); } @@ -427,7 +461,7 @@ fw_busreset(struct firewire_comm *fc) switch(fc->status){ case FWBUSMGRELECT: - untimeout((timeout_t *)fw_try_bmr, (void *)fc, fc->bmrhandle); + callout_stop(&fc->bmr_callout); break; default: break; @@ -579,23 +613,23 @@ void fw_init(struct firewire_comm *fc) /* Initialize csr registers */ fc->topology_map = (struct fw_topology_map *)malloc( sizeof(struct fw_topology_map), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_FW, M_NOWAIT | M_ZERO); fc->speed_map = (struct fw_speed_map *)malloc( sizeof(struct fw_speed_map), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_FW, M_NOWAIT | M_ZERO); CSRARC(fc, TOPO_MAP) = 0x3f1 << 16; CSRARC(fc, TOPO_MAP + 4) = 1; CSRARC(fc, SPED_MAP) = 0x3f1 << 16; CSRARC(fc, SPED_MAP + 4) = 1; - TAILQ_INIT(&fc->devices); + STAILQ_INIT(&fc->devices); STAILQ_INIT(&fc->pending); /* Initialize csr ROM work space */ SLIST_INIT(&fc->ongocsr); SLIST_INIT(&fc->csrfree); for( i = 0 ; i < FWMAXCSRDIR ; i++){ - csrd = (struct csrdir *) malloc(sizeof(struct csrdir), M_DEVBUF,M_NOWAIT); + csrd = (struct csrdir *) malloc(sizeof(struct csrdir), M_FW,M_NOWAIT); if(csrd == NULL) break; SLIST_INSERT_HEAD(&fc->csrfree, csrd, link); } @@ -626,7 +660,7 @@ void fw_init(struct firewire_comm *fc) xfer = fw_xfer_alloc(); if(xfer == NULL) return; - fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_NOWAIT); + fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); if(fwb == NULL){ fw_xfer_free(xfer); } @@ -741,7 +775,7 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) tl = STAILQ_NEXT(tl, link)){ if(tl->xfer == xfer){ STAILQ_REMOVE(&fc->tlabels[xfer->tl], tl, tlabel, link); - free(tl, M_DEVBUF); + free(tl, M_FW); splx(s); return; } @@ -776,16 +810,17 @@ fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel) * To allocate IEEE1394 XFER structure. */ struct fw_xfer * -fw_xfer_alloc() +fw_xfer_alloc(struct malloc_type *type) { struct fw_xfer *xfer; - xfer = malloc(sizeof(struct fw_xfer), M_DEVBUF, M_NOWAIT | M_ZERO); + xfer = malloc(sizeof(struct fw_xfer), type, M_NOWAIT | M_ZERO); if (xfer == NULL) return xfer; xfer->time = time_second; xfer->sub = -1; + xfer->malloc = type; return xfer; } @@ -840,30 +875,25 @@ fw_xfer_free( struct fw_xfer* xfer) } } if(xfer->send.buf != NULL){ - free(xfer->send.buf, M_DEVBUF); + free(xfer->send.buf, M_FW); } if(xfer->recv.buf != NULL){ - free(xfer->recv.buf, M_DEVBUF); + free(xfer->recv.buf, M_FW); } if(xfer->fc != NULL){ fw_tl_free(xfer->fc, xfer); } - free(xfer, M_DEVBUF); + free(xfer, xfer->malloc); } -/* - * Callback for PHY configuration. - */ static void -fw_phy_config_callback(struct fw_xfer *xfer) +fw_asy_callback_free(struct fw_xfer *xfer) { #if 0 - printf("phy_config done state=%d resp=%d\n", + printf("asyreq done state=%d resp=%d\n", xfer->state, xfer->resp); #endif fw_xfer_free(xfer); - /* XXX need bus reset ?? */ - /* sc->fc->ibr(xfer->fc); LOOP */ } /* @@ -880,15 +910,15 @@ fw_phy_config(struct firewire_comm *fc, int root_node, int gap_count) #if 0 DELAY(100000); #endif - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); xfer->send.len = 12; xfer->send.off = 0; xfer->fc = fc; xfer->retry_req = fw_asybusy; - xfer->act.hand = fw_phy_config_callback; + xfer->act.hand = fw_asy_callback_free; xfer->send.buf = malloc(sizeof(u_int32_t), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_FW, M_NOWAIT | M_ZERO); fp = (struct fw_pkt *)xfer->send.buf; fp->mode.ld[1] = 0; if (root_node >= 0) @@ -1030,8 +1060,8 @@ void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off) CSRARC(fc, BUS_MGR_ID) = fc->set_bmr(fc, fc->irm); } else { fc->status = FWBUSMGRELECT; - fc->bmrhandle = timeout((timeout_t *)fw_try_bmr, - (void *)fc, hz / 8); + callout_reset(&fc->bmr_callout, hz/8, + (void *)fw_try_bmr, (void *)fc); } } else { fc->status = FWBUSMGRDONE; @@ -1040,10 +1070,10 @@ 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_DEVBUF); - /* Optimize gap_count, if I am BMGR */ + free(buf, M_FW); if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){ - fw_phy_config(fc, -1, gap_cnt[fc->max_hop]); + /* I am BMGR */ + fw_bmr(fc); } callout_reset(&fc->busprobe_callout, hz/4, (void *)fw_bus_probe, (void *)fc); @@ -1066,16 +1096,16 @@ fw_bus_probe(struct firewire_comm *fc) * Invalidate all devices, just after bus reset. Devices * to be removed has not been seen longer time. */ - for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL; fwdev = next) { - next = TAILQ_NEXT(fwdev, link); - if(fwdev->status != FWDEVINVAL){ + for (fwdev = STAILQ_FIRST(&fc->devices); fwdev != NULL; fwdev = next) { + next = STAILQ_NEXT(fwdev, link); + if (fwdev->status != FWDEVINVAL) { fwdev->status = FWDEVINVAL; fwdev->rcnt = 0; - }else if(fwdev->rcnt < FW_MAXDEVRCNT){ + } else if(fwdev->rcnt < FW_MAXDEVRCNT) { fwdev->rcnt ++; - }else{ - TAILQ_REMOVE(&fc->devices, fwdev, link); - free(fwdev, M_DEVBUF); + } else { + STAILQ_REMOVE(&fc->devices, fwdev, fw_device, link); + free(fwdev, M_FW); } } fc->ongonode = 0; @@ -1093,7 +1123,7 @@ static void fw_bus_explore(struct firewire_comm *fc ) { int err = 0; - struct fw_device *fwdev, *tfwdev; + struct fw_device *fwdev, *pfwdev, *tfwdev; u_int32_t addr; struct fw_xfer *xfer; struct fw_pkt *fp; @@ -1127,12 +1157,9 @@ loop: fc->ongoaddr = CSRROMOFF + 0x10; addr = 0xf0000000 | fc->ongoaddr; }else if(fc->ongodev == NULL){ - for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL; - fwdev = TAILQ_NEXT(fwdev, link)){ - if(fwdev->eui.hi == fc->ongoeui.hi && fwdev->eui.lo == fc->ongoeui.lo){ + STAILQ_FOREACH(fwdev, &fc->devices, link) + if (FW_EUI64_EQUAL(fwdev->eui, fc->ongoeui)) break; - } - } if(fwdev != NULL){ fwdev->dst = fc->ongonode; fwdev->status = FWDEVATTACHED; @@ -1142,7 +1169,7 @@ loop: fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff; goto loop; } - fwdev = malloc(sizeof(struct fw_device), M_DEVBUF, M_NOWAIT); + fwdev = malloc(sizeof(struct fw_device), M_FW, M_NOWAIT); if(fwdev == NULL) return; fwdev->fc = fc; @@ -1157,18 +1184,18 @@ loop: fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode]; #endif - tfwdev = TAILQ_FIRST(&fc->devices); - while( tfwdev != NULL && - (tfwdev->eui.hi > fwdev->eui.hi) && - ((tfwdev->eui.hi == fwdev->eui.hi) && - tfwdev->eui.lo > fwdev->eui.lo)){ - tfwdev = TAILQ_NEXT( tfwdev, link); - } - if(tfwdev == NULL){ - TAILQ_INSERT_TAIL(&fc->devices, fwdev, link); - }else{ - TAILQ_INSERT_BEFORE(tfwdev, fwdev, link); + pfwdev = NULL; + STAILQ_FOREACH(tfwdev, &fc->devices, link) { + if (tfwdev->eui.hi > fwdev->eui.hi || + (tfwdev->eui.hi == fwdev->eui.hi && + tfwdev->eui.lo > fwdev->eui.lo)) + break; + pfwdev = tfwdev; } + if (pfwdev == NULL) + STAILQ_INSERT_HEAD(&fc->devices, fwdev, link); + else + STAILQ_INSERT_AFTER(&fc->devices, pfwdev, fwdev, link); device_printf(fc->bdev, "New %s device ID:%08x%08x\n", linkspeed[fwdev->speed], @@ -1186,13 +1213,13 @@ loop: fw_bus_explore_callback); if(xfer == NULL) goto done; #else - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL){ goto done; } xfer->send.len = 16; xfer->spd = 0; - xfer->send.buf = malloc(16, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(16, M_FW, M_NOWAIT); if(xfer->send.buf == NULL){ fw_xfer_free( xfer); return; @@ -1237,13 +1264,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(); + 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_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(16, M_FW, M_NOWAIT); if(xfer->send.buf == NULL){ fw_xfer_free( xfer); return NULL; @@ -1460,8 +1487,7 @@ fw_attach_dev(struct firewire_comm *fc) struct firewire_dev_comm *fdc; u_int32_t spec, ver; - for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL; - fwdev = TAILQ_NEXT(fwdev, link)){ + STAILQ_FOREACH(fwdev, &fc->devices, link) { if(fwdev->status == FWDEVINIT){ spec = getcsrdata(fwdev, CSRKEY_SPEC); if(spec == 0) @@ -1548,8 +1574,8 @@ fw_attach_dev(struct firewire_comm *fc) printf("fw_attach_dev: %d pending handlers called\n", i); if (fc->retry_count > 0) { printf("retry_count = %d\n", fc->retry_count); - fc->retry_probe_handle = timeout((timeout_t *)fc->ibr, - (void *)fc, hz*2); + callout_reset(&fc->retry_probe_callout, hz*2, + (void *)fc->ibr, (void *)fc); } return; } @@ -1573,7 +1599,7 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer) if(tmptl->xfer->dst == xfer->dst) break; } if(tmptl == NULL) { - tl = malloc(sizeof(struct tlabel),M_DEVBUF,M_NOWAIT); + tl = malloc(sizeof(struct tlabel),M_FW,M_NOWAIT); if (tl == NULL) { splx(s); return (-1); @@ -1683,12 +1709,12 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u printf("fw_rcv: cannot response(bus reset)!\n"); goto err; } - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL){ return; } xfer->spd = spd; - xfer->send.buf = malloc(16, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(16, M_FW, M_NOWAIT); resfp = (struct fw_pkt *)xfer->send.buf; switch(fp->mode.common.tcode){ case FWTCODE_WREQQ: @@ -1727,7 +1753,7 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u } switch(bind->xfer->act_type){ case FWACT_XFER: - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL) goto err; xfer->fc = bind->xfer->fc; xfer->sc = bind->xfer->sc; @@ -1751,7 +1777,7 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u fc->ir[bind->xfer->sub]->queued); goto err; } - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL) goto err; xfer->recv.buf = buf; xfer->recv.len = len; @@ -1784,7 +1810,7 @@ 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(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL) goto err; xfer->recv.buf = buf; xfer->recv.len = len; @@ -1816,7 +1842,7 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u break; } err: - free(buf, M_DEVBUF); + free(buf, M_FW); } /* @@ -1851,10 +1877,7 @@ fw_try_bmr_callback(struct fw_xfer *xfer) CSRARC(fc, BUS_MGR_ID)); if(bmr == fc->nodeid){ printf("(me)\n"); -/* If I am bus manager, optimize gapcount */ - if(fc->max_hop <= MAX_GAPHOP ){ - fw_phy_config(fc, -1, gap_cnt[fc->max_hop]); - } + fw_bmr(fc); }else{ printf("\n"); } @@ -1865,7 +1888,7 @@ error: /* * To candidate Bus Manager election process. */ -void +static void fw_try_bmr(void *arg) { struct fw_xfer *xfer; @@ -1873,13 +1896,13 @@ fw_try_bmr(void *arg) struct fw_pkt *fp; int err = 0; - xfer = fw_xfer_alloc(); + xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL){ return; } xfer->send.len = 24; xfer->spd = 0; - xfer->send.buf = malloc(24, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(24, M_FW, M_NOWAIT); if(xfer->send.buf == NULL){ fw_xfer_free( xfer); return; @@ -1937,7 +1960,7 @@ fw_vmaccess(struct fw_xfer *xfer){ switch(rfp->mode.hdr.tcode){ /* XXX need fix for 64bit arch */ case FWTCODE_WREQB: - xfer->send.buf = malloc(12, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(12, M_FW, M_NOWAIT); xfer->send.len = 12; sfp = (struct fw_pkt *)xfer->send.buf; bcopy(rfp->mode.wreqb.payload, @@ -1946,14 +1969,14 @@ fw_vmaccess(struct fw_xfer *xfer){ sfp->mode.wres.rtcode = 0; break; case FWTCODE_WREQQ: - xfer->send.buf = malloc(12, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(12, M_FW, M_NOWAIT); xfer->send.len = 12; sfp->mode.wres.tcode = FWTCODE_WRES; *((u_int32_t *)(ntohl(rfp->mode.wreqb.dest_lo))) = rfp->mode.wreqq.data; sfp->mode.wres.rtcode = 0; break; case FWTCODE_RREQB: - xfer->send.buf = malloc(16 + rfp->mode.rreqb.len, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(16 + rfp->mode.rreqb.len, M_FW, M_NOWAIT); xfer->send.len = 16 + ntohs(rfp->mode.rreqb.len); sfp = (struct fw_pkt *)xfer->send.buf; bcopy((caddr_t)ntohl(rfp->mode.rreqb.dest_lo), @@ -1964,7 +1987,7 @@ fw_vmaccess(struct fw_xfer *xfer){ sfp->mode.rresb.extcode = 0; break; case FWTCODE_RREQQ: - xfer->send.buf = malloc(16, M_DEVBUF, M_NOWAIT); + xfer->send.buf = malloc(16, M_FW, M_NOWAIT); xfer->send.len = 16; sfp = (struct fw_pkt *)xfer->send.buf; sfp->mode.rresq.data = *(u_int32_t *)(ntohl(rfp->mode.rreqq.dest_lo)); @@ -2008,5 +2031,36 @@ fw_crc16(u_int32_t *ptr, u_int32_t len){ return((u_int16_t) crc); } +static int +fw_bmr(struct firewire_comm *fc) +{ + struct fw_device fwdev; + int cmstr; + + /* XXX Assume that the current root node is cycle master capable */ + cmstr = fc->max_node; + /* 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 we are the cycle master, nothing to do */ + if (cmstr == fc->nodeid) + return 0; + /* Bus probe has not finished, make dummy fwdev for cmstr */ + bzero(&fwdev, sizeof(fwdev)); + fwdev.fc = fc; + fwdev.dst = cmstr; + fwdev.speed = 0; + fwdev.maxrec = 8; /* 512 */ + fwdev.status = FWDEVINIT; + /* Set cmstr bit on the cycle master */ + fwmem_write_quad(&fwdev, NULL, 0/*spd*/, + 0xffff, 0xf0000000 | STATE_SET, 1 << 16, + fw_asy_callback_free); + + return 0; +} + DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,0,0); MODULE_VERSION(firewire, 1); |
