The patch contains a little more then just to get my SIIG cardbus OHCI/VIATECH VT6306 card to work. The extras is a chardev that you can use to extract some info from the fwochi device. Its not really ready for including. Its in there since it partly got included in the patch. I want to extract the all the nodes on the bus, the speed, power map, etc to a userland tool. The things from the patch you want to keep is: - Wait on LPS and LinkEnable, remove duplicate LPS enable (I removed the first one). This is little verbose, and its probably as the linux driver claims for the viatech chip, its just turns LPS on. This is somewhat bogus since it doesn't improve the sitution. - Improved detach, now it no longer crashes, there was waiting events in the at queue that needed to be killed. I modified fwohci_at_done() so it can avoid to write to the extracted hardware. - A gross hack that waits a second before doing the busreset. Now, this is wrong, waiting 2 seconds make it never work and wait shorter make it work somewhat more, but not if you wait shorter then 1/2 second. It most be something else that should be done, I just don't know what. This at least make me able to attach to the SBP2 disk I have in 1 of 4 tries. w/o the patch I crash and burn. The diff is to the fwochi/cardbus stuff before Ichiro patch. Love Index: ieee1394/files.ieee1394 =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/files.ieee1394,v retrieving revision 1.5 diff -w -u -r1.5 files.ieee1394 --- files.ieee1394 2001/05/13 05:01:43 1.5 +++ files.ieee1394 2001/12/30 17:34:41 @@ -3,6 +3,11 @@ file dev/ieee1394/fwlynx.c fwlynx file dev/ieee1394/fwohci.c fwohci +device fwctl { } +attach fwctl at fwbus + +file dev/ieee1394/fwctldev.c fwctl + device fwnode { } attach fwnode at fwbus Index: ieee1394/fwohci.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwohci.c,v retrieving revision 1.46 diff -w -u -r1.46 fwohci.c --- fwohci.c 2001/11/15 09:48:08 1.46 +++ fwohci.c 2001/12/30 17:28:38 @@ -120,7 +120,7 @@ static u_int8_t fwohci_phy_read(struct fwohci_softc *, u_int8_t); static void fwohci_phy_write(struct fwohci_softc *, u_int8_t, u_int8_t); -static void fwohci_phy_busreset(struct fwohci_softc *); +void fwohci_phy_busreset(struct fwohci_softc *); static void fwohci_phy_input(struct fwohci_softc *, struct fwohci_pkt *); static int fwohci_handler_set(struct fwohci_softc *, int, u_int32_t, u_int32_t, @@ -133,6 +133,8 @@ static int fwohci_at_output(struct fwohci_softc *, struct fwohci_ctx *, struct fwohci_pkt *); static void fwohci_at_done(struct fwohci_softc *, struct fwohci_ctx *, int); +#define FWOHCI_AT_DONE_FORCE 0x1 +#define FWOHCI_AT_DONE_NO_WRITE 0x2 static void fwohci_atrs_output(struct fwohci_softc *, int, struct fwohci_pkt *, struct fwohci_pkt *); @@ -181,7 +183,7 @@ #define DPRINTF(x) if (fwdebug) printf x #define DPRINTFN(n,x) if (fwdebug>(n)) printf x -int fwdebug = 0; +int fwdebug = 1; #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -281,6 +283,50 @@ return 0; } +int +fwohci_detach(struct fwohci_softc *sc) +{ + struct ieee1394_softc *iea; + + sc->sc_dying = 1; + wakeup(fwohci_event_thread); + if (tsleep(sc, PWAIT, "fwohcidet", hz * 60)) + printf("%s: fw event thread didn't die\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + + callout_stop(&sc->sc_selfid_callout); + + LIST_FOREACH(iea, &sc->sc_nodelist, sc1394_node) + iea->sc1394_node_id = 0xffff; + fwohci_check_nodes(sc); + + fwohci_at_done(sc, sc->sc_ctx_atrq, + FWOHCI_AT_DONE_FORCE|FWOHCI_AT_DONE_NO_WRITE); + fwohci_at_done(sc, sc->sc_ctx_atrs, + FWOHCI_AT_DONE_FORCE|FWOHCI_AT_DONE_NO_WRITE); + + config_detach(sc->sc_sc1394.sc1394_if, 0); + config_detach(sc->sc_sc1394.sc1394_ctl, 0); + + fwohci_ctx_free(sc, sc->sc_ctx_arrq); + fwohci_ctx_free(sc, sc->sc_ctx_arrs); + fwohci_ctx_free(sc, sc->sc_ctx_atrq); + fwohci_ctx_free(sc, sc->sc_ctx_atrs); + free(sc->sc_ctx_ir, M_DEVBUF); + + fwohci_buf_free(sc, &sc->sc_buf_cnfrom); + fwohci_buf_free(sc, &sc->sc_buf_selfid); + + shutdownhook_disestablish(sc->sc_shutdownhook); + powerhook_disestablish(sc->sc_powerhook); + + evcnt_detach(&sc->sc_intrcnt); + evcnt_detach(&sc->sc_isocnt); + evcnt_detach(&sc->sc_isopktcnt); + + return 0; +} + static int fwohci_if_setiso(struct device *self, u_int32_t channel, u_int32_t tag, u_int32_t direction, void (*handler)(struct device *, struct mbuf *)) @@ -319,6 +365,9 @@ for (;;) { intmask = OHCI_CSR_READ(sc, OHCI_REG_IntEventClear); + if (intmask == 0xffffffff) /* XXX card removed */ + return 1; + /* * On a bus reset, everything except bus reset gets * cleared. That can't get cleared until the selfid @@ -434,12 +483,6 @@ } /* - * Enable Link Power - */ - - OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS); - - /* * Allocate DMA Context */ fwohci_ctx_alloc(sc, &sc->sc_ctx_arrq, OHCI_BUF_ARRQ_CNT, @@ -476,13 +519,23 @@ sc->sc_sc1394.sc1394_if = config_found(&sc->sc_sc1394.sc1394_dev, "fw", fwohci_print); + sc->sc_sc1394.sc1394_ctl = config_found(&sc->sc_sc1394.sc1394_dev, + "fwctl", fwohci_print); + /* Main loop. It's not coming back normally. */ fwohci_event_thread(sc); + /* Wakeup parent if needed */ + wakeup(sc); + kthread_exit(0); } +#ifndef FWOHCI_DELAY +#define FWOHCI_DELAY 1 +#endif + static void fwohci_event_thread(struct fwohci_softc *sc) { @@ -496,10 +549,21 @@ */ fwohci_hw_init(sc); + splx(s); + + if (sc->sc_quirks & FWOHCI_QUIRK_WAIT_SETTLE) { + printf("%s: waiting %d seconds for device to settle\n", + sc->sc_sc1394.sc1394_dev.dv_xname, FWOHCI_DELAY); + tsleep(fwohci_event_thread, PRIBIO, "fwohciset", + FWOHCI_DELAY * hz); + /* we sleep and the hardware went away under our feet */ + if (sc->sc_dying) + return; + } + /* Initial Bus Reset */ fwohci_phy_busreset(sc); - splx(s); while (!sc->sc_dying) { s = splbio(); @@ -632,7 +696,35 @@ DELAY(10); } +#ifdef FW_DEBUG + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LPS) + printf("%s: HCControl_LPS is there after reset\n", + sc->sc_sc1394.sc1394_dev.dv_xname); +#endif + + /* + * Wait for LPS turns on, this means the SCLK from the phy is + * present (OHCI1.1: sec 4). Linux driver claims that some + * turn on LPS directly (apprently without waiting for + * SCLK/readyness). If this is the case with your chip, a + * quirk should be added for it. + */ + OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS); + /* wait up to 2 seconds for LPS to wake up */ + for (i = 0; i < OHCI_LOOP_LONG; i++) { + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LPS) + break; + DELAY(100); + } + if (i == OHCI_LOOP_LONG) + printf("%s: waited forever for LPS\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + else + printf("%s: waited %d interations for LPS\n", + sc->sc_sc1394.sc1394_dev.dv_xname, i); /* * First, initilize CSRs with undefined value to default settings. @@ -690,6 +782,19 @@ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_MasterEnable); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LinkEnable); + /* wait up to 2 seconds for LinkEnable to wake up */ + for (i = 0; i < OHCI_LOOP_LONG; i++) { + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LinkEnable) + break; + DELAY(100); + } + if (i == OHCI_LOOP_LONG) + printf("%s: waited forever for LinkEnable\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + else + printf("%s: waited %d interations for LinkEnable\n", + sc->sc_sc1394.sc1394_dev.dv_xname, i); /* * Start the receivers @@ -737,6 +842,7 @@ OHCI_BusOptions_CMC | OHCI_BusOptions_IRMC); OHCI_CSR_WRITE(sc, OHCI_REG_BusOptions, val); fwohci_phy_busreset(sc); + /* XXX not permited to clear LPS or LinkEnable from software !!! */ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LinkEnable); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LPS); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_SoftReset); @@ -789,7 +895,7 @@ /* * Initiate Bus Reset */ -static void +void fwohci_phy_busreset(struct fwohci_softc *sc) { int s; @@ -1237,8 +1343,8 @@ /* * Initialize for Asynchronous Transmit Queue. */ - fwohci_at_done(sc, sc->sc_ctx_atrq, 1); - fwohci_at_done(sc, sc->sc_ctx_atrs, 1); + fwohci_at_done(sc, sc->sc_ctx_atrq, FWOHCI_AT_DONE_FORCE); + fwohci_at_done(sc, sc->sc_ctx_atrs, FWOHCI_AT_DONE_FORCE); } static void @@ -1984,7 +2090,7 @@ } static void -fwohci_at_done(struct fwohci_softc *sc, struct fwohci_ctx *fc, int force) +fwohci_at_done(struct fwohci_softc *sc, struct fwohci_ctx *fc, int flags) { struct fwohci_buf *fb; struct fwohci_desc *fd; @@ -1994,8 +2100,10 @@ while ((fb = TAILQ_FIRST(&fc->fc_buf)) != NULL) { fd = fb->fb_desc; #ifdef FW_DEBUG - DPRINTFN(1, ("fwohci_at_done: %sdesc %ld (%d)", - force ? "force " : "", (long)(fd - sc->sc_desc), + DPRINTFN(1, ("fwohci_at_done: %sdesc %s %ld (%d)", + (flags & FWOHCI_AT_DONE_FORCE) ? "force " : "", + (flags & FWOHCI_AT_DONE_NO_WRITE) ? "nowrite " : "", + (long)(fd - sc->sc_desc), fb->fb_nseg)); for (i = 0; i < fb->fb_nseg * 4; i++) DPRINTFN(2, ("%s%08x", i&7?" ":"\n ", @@ -2004,10 +2112,12 @@ #endif if (fb->fb_nseg > 2) fd += fb->fb_nseg - 1; - if (!force && !(fd->fd_status & OHCI_CTXCTL_ACTIVE)) + if ((flags & FWOHCI_AT_DONE_FORCE) == 0 && + !(fd->fd_status & OHCI_CTXCTL_ACTIVE)) break; TAILQ_REMOVE(&fc->fc_buf, fb, fb_list); - if (fc->fc_branch == &fd->fd_branch) { + if ((flags & FWOHCI_AT_DONE_NO_WRITE) == 0 && + (fc->fc_branch == &fd->fd_branch)) { OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx, OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN); fc->fc_branch = NULL; Index: ieee1394/fwohcivar.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwohcivar.h,v retrieving revision 1.15 diff -w -u -r1.15 fwohcivar.h --- fwohcivar.h 2001/07/17 11:01:04 1.15 +++ fwohcivar.h 2001/12/30 17:28:38 @@ -56,6 +56,7 @@ OHCI_BUF_ATRS_CNT + OHCI_BUF_IR_CNT + 1 + 1) #define OHCI_LOOP 1000 +#define OHCI_LOOP_LONG 20000 #define OHCI_SELFID_TIMEOUT (hz * 3) #define OHCI_ASYNC_STREAM 0x40 @@ -174,6 +175,9 @@ struct proc *sc_event_thread; int sc_dying; + u_int32_t sc_quirks; +#define FWOHCI_QUIRK_WAIT_SETTLE 0x00000001 + u_int32_t sc_intmask; u_int32_t sc_iso; @@ -189,6 +193,7 @@ }; int fwohci_init (struct fwohci_softc *, const struct evcnt *); +int fwohci_detach(struct fwohci_softc *); int fwohci_intr (void *); int fwohci_print (void *, const char *); Index: ieee1394/ieee1394var.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/ieee1394var.h,v retrieving revision 1.13 diff -w -u -r1.13 ieee1394var.h --- ieee1394var.h 2001/07/18 02:59:54 1.13 +++ ieee1394var.h 2001/12/30 17:28:38 @@ -80,6 +80,7 @@ struct ieee1394_softc { struct device sc1394_dev; struct device *sc1394_if; /* Move to fwohci level. */ + struct device *sc1394_ctl; const struct ieee1394_callbacks sc1394_callback; /* Nuke probably. */ u_int32_t *sc1394_configrom; Index: cardbus/fwohci_cardbus.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/cardbus/fwohci_cardbus.c,v retrieving revision 1.3 diff -w -u -r1.3 fwohci_cardbus.c --- fwohci_cardbus.c 2001/11/15 09:48:02 1.3 +++ fwohci_cardbus.c 2001/12/30 17:31:02 @@ -46,9 +46,7 @@ #include -#if defined pciinc #include -#endif #include #include @@ -64,16 +62,16 @@ cardbus_function_tag_t sc_cf; cardbus_devfunc_t sc_ct; void *sc_ih; + bus_addr_t sc_base_reg; }; static int fwohci_cardbus_match(struct device *, struct cfdata *, void *); static void fwohci_cardbus_attach(struct device *, struct device *, void *); +static int fwohci_cardbus_detach(struct device *, int); struct cfattach fwohci_cardbus_ca = { - sizeof(struct fwohci_cardbus_softc), fwohci_cardbus_match, fwohci_cardbus_attach, -#if 0 - fwohci_cardbus_detach, fwohci_activate -#endif + sizeof(struct fwohci_cardbus_softc), fwohci_cardbus_match, + fwohci_cardbus_attach, fwohci_cardbus_detach }; #define CARDBUS_OHCI_MAP_REGISTER PCI_OHCI_MAP_REGISTER @@ -114,7 +112,7 @@ if (Cardbus_mapreg_map(ct, CARDBUS_OHCI_MAP_REGISTER, CARDBUS_MAPREG_TYPE_MEM, 0, &sc->sc_sc.sc_memt, &sc->sc_sc.sc_memh, - NULL, &sc->sc_sc.sc_memsize)) { + &sc->sc_base_reg, &sc->sc_sc.sc_memsize)) { printf("%s: can't map OCHI register space\n", devname); return; } @@ -156,10 +154,36 @@ } printf("%s: interrupting at %d\n", devname, ca->ca_intrline); - /* XXX NULL should be replaced by some call to Cardbus coed */ + /* XXX this might be neccery for PCI card too ? */ + if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_VIATECH) { + switch (PCI_PRODUCT(ca->ca_id)) { + case PCI_PRODUCT_VIATECH_VT6306: + sc->sc_sc.sc_quirks |= FWOHCI_QUIRK_WAIT_SETTLE; + break; + } + } + + /* XXX NULL should be replaced by some call to Cardbus code */ if (fwohci_init(&sc->sc_sc, NULL) != 0) { cardbus_intr_disestablish(cc, cf, sc->sc_ih); - bus_space_unmap(sc->sc_sc.sc_memt, sc->sc_sc.sc_memh, + Cardbus_mapreg_unmap(sc->sc_ct, sc->sc_base_reg, + sc->sc_sc.sc_memt, sc->sc_sc.sc_memh, + sc->sc_sc.sc_memsize); + } +} + +static int +fwohci_cardbus_detach(struct device *self, int flags) +{ + struct fwohci_cardbus_softc *sc = (struct fwohci_cardbus_softc *)self; + int rv; + + if ((rv = fwohci_detach(&sc->sc_sc)) == 0) { + cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih); + Cardbus_mapreg_unmap(sc->sc_ct, sc->sc_base_reg, + sc->sc_sc.sc_memt, sc->sc_sc.sc_memh, sc->sc_sc.sc_memsize); } + + return rv; }