13c60ba66SKatsushi Kobayashi /* 23c60ba66SKatsushi Kobayashi * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 33c60ba66SKatsushi Kobayashi * All rights reserved. 43c60ba66SKatsushi Kobayashi * 53c60ba66SKatsushi Kobayashi * Redistribution and use in source and binary forms, with or without 63c60ba66SKatsushi Kobayashi * modification, are permitted provided that the following conditions 73c60ba66SKatsushi Kobayashi * are met: 83c60ba66SKatsushi Kobayashi * 1. Redistributions of source code must retain the above copyright 93c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer. 103c60ba66SKatsushi Kobayashi * 2. Redistributions in binary form must reproduce the above copyright 113c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer in the 123c60ba66SKatsushi Kobayashi * documentation and/or other materials provided with the distribution. 133c60ba66SKatsushi Kobayashi * 3. All advertising materials mentioning features or use of this software 143c60ba66SKatsushi Kobayashi * must display the acknowledgement as bellow: 153c60ba66SKatsushi Kobayashi * 163c60ba66SKatsushi Kobayashi * This product includes software developed by K. Kobayashi and H. SHimokawa 173c60ba66SKatsushi Kobayashi * 183c60ba66SKatsushi Kobayashi * 4. The name of the author may not be used to endorse or promote products 193c60ba66SKatsushi Kobayashi * derived from this software without specific prior written permission. 203c60ba66SKatsushi Kobayashi * 213c60ba66SKatsushi Kobayashi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 223c60ba66SKatsushi Kobayashi * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 233c60ba66SKatsushi Kobayashi * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 243c60ba66SKatsushi Kobayashi * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 253c60ba66SKatsushi Kobayashi * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 263c60ba66SKatsushi Kobayashi * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 273c60ba66SKatsushi Kobayashi * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 283c60ba66SKatsushi Kobayashi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 293c60ba66SKatsushi Kobayashi * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 303c60ba66SKatsushi Kobayashi * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 313c60ba66SKatsushi Kobayashi * POSSIBILITY OF SUCH DAMAGE. 323c60ba66SKatsushi Kobayashi * 333c60ba66SKatsushi Kobayashi * $FreeBSD$ 343c60ba66SKatsushi Kobayashi * 353c60ba66SKatsushi Kobayashi */ 363c60ba66SKatsushi Kobayashi extern int nxfer; 373c60ba66SKatsushi Kobayashi #define DEBUG_PACKET 383c60ba66SKatsushi Kobayashi #undef DEBUG_PACKET 393c60ba66SKatsushi Kobayashi #define ATRQ_CH 0 403c60ba66SKatsushi Kobayashi #define ATRS_CH 1 413c60ba66SKatsushi Kobayashi #define ARRQ_CH 2 423c60ba66SKatsushi Kobayashi #define ARRS_CH 3 433c60ba66SKatsushi Kobayashi #define ITX_CH 4 443c60ba66SKatsushi Kobayashi #define IRX_CH 0x24 453c60ba66SKatsushi Kobayashi 463c60ba66SKatsushi Kobayashi #include <sys/param.h> 473c60ba66SKatsushi Kobayashi #include <sys/systm.h> 483c60ba66SKatsushi Kobayashi #include <sys/types.h> 493c60ba66SKatsushi Kobayashi #include <sys/mbuf.h> 503c60ba66SKatsushi Kobayashi #include <sys/mman.h> 513c60ba66SKatsushi Kobayashi #include <sys/socket.h> 523c60ba66SKatsushi Kobayashi #include <sys/socketvar.h> 533c60ba66SKatsushi Kobayashi #include <sys/signalvar.h> 543c60ba66SKatsushi Kobayashi #include <sys/malloc.h> 553c60ba66SKatsushi Kobayashi #include <sys/uio.h> 563c60ba66SKatsushi Kobayashi #include <sys/sockio.h> 573c60ba66SKatsushi Kobayashi #include <sys/bus.h> 583c60ba66SKatsushi Kobayashi #include <sys/kernel.h> 593c60ba66SKatsushi Kobayashi #include <sys/conf.h> 603c60ba66SKatsushi Kobayashi 613c60ba66SKatsushi Kobayashi #include <machine/bus.h> 623c60ba66SKatsushi Kobayashi #include <machine/resource.h> 633c60ba66SKatsushi Kobayashi #include <sys/rman.h> 643c60ba66SKatsushi Kobayashi 653c60ba66SKatsushi Kobayashi #ifdef __FreeBSD__ 663c60ba66SKatsushi Kobayashi #include <machine/cpufunc.h> /* for rdtsc proto for clock.h below */ 673c60ba66SKatsushi Kobayashi #include <machine/clock.h> 683c60ba66SKatsushi Kobayashi #include <pci/pcivar.h> 693c60ba66SKatsushi Kobayashi #include <pci/pcireg.h> 703c60ba66SKatsushi Kobayashi #include <vm/vm.h> 713c60ba66SKatsushi Kobayashi #include <vm/vm_extern.h> 723c60ba66SKatsushi Kobayashi #include <vm/pmap.h> /* for vtophys proto */ 733c60ba66SKatsushi Kobayashi 743c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire.h> 753c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirebusreg.h> 763c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirereg.h> 773c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcireg.h> 783c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcivar.h> 793c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire_phy.h> 803c60ba66SKatsushi Kobayashi 813c60ba66SKatsushi Kobayashi #define OHCI_DEBUG 823c60ba66SKatsushi Kobayashi #undef OHCI_DEBUG 833c60ba66SKatsushi Kobayashi /* 843c60ba66SKatsushi Kobayashi #define OHCI_DEBUG 853c60ba66SKatsushi Kobayashi */ 863c60ba66SKatsushi Kobayashi static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL", 873c60ba66SKatsushi Kobayashi "STOR","LOAD","NOP ","STOP",}; 883c60ba66SKatsushi Kobayashi static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", 893c60ba66SKatsushi Kobayashi "UNDEF","REG","SYS","DEV"}; 903c60ba66SKatsushi Kobayashi char fwohcicode[32][0x20]={ 913c60ba66SKatsushi Kobayashi "No stat","Undef","long","miss Ack err", 923c60ba66SKatsushi Kobayashi "underrun","overrun","desc err", "data read err", 933c60ba66SKatsushi Kobayashi "data write err","bus reset","timeout","tcode err", 943c60ba66SKatsushi Kobayashi "Undef","Undef","unknown event","flushed", 953c60ba66SKatsushi Kobayashi "Undef","ack complete","ack pend","Undef", 963c60ba66SKatsushi Kobayashi "ack busy_X","ack busy_A","ack busy_B","Undef", 973c60ba66SKatsushi Kobayashi "Undef","Undef","Undef","ack tardy", 983c60ba66SKatsushi Kobayashi "Undef","ack data_err","ack type_err",""}; 993c60ba66SKatsushi Kobayashi #define MAX_SPEED 2 1003c60ba66SKatsushi Kobayashi extern char linkspeed[MAX_SPEED+1][0x10]; 1013c60ba66SKatsushi Kobayashi extern int maxrec[MAX_SPEED+1]; 1023c60ba66SKatsushi Kobayashi static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; 1033c60ba66SKatsushi Kobayashi u_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31}; 1043c60ba66SKatsushi Kobayashi 1053c60ba66SKatsushi Kobayashi static struct tcode_info tinfo[] = { 1063c60ba66SKatsushi Kobayashi /* hdr_len block flag*/ 1073c60ba66SKatsushi Kobayashi /* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL}, 1083c60ba66SKatsushi Kobayashi /* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, 1093c60ba66SKatsushi Kobayashi /* 2 WRES */ {12, FWTI_RES}, 1103c60ba66SKatsushi Kobayashi /* 3 XXX */ { 0, 0}, 1113c60ba66SKatsushi Kobayashi /* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL}, 1123c60ba66SKatsushi Kobayashi /* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL}, 1133c60ba66SKatsushi Kobayashi /* 6 RRESQ */ {16, FWTI_RES}, 1143c60ba66SKatsushi Kobayashi /* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY}, 1153c60ba66SKatsushi Kobayashi /* 8 CYCS */ { 0, 0}, 1163c60ba66SKatsushi Kobayashi /* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, 1173c60ba66SKatsushi Kobayashi /* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR}, 1183c60ba66SKatsushi Kobayashi /* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY}, 1193c60ba66SKatsushi Kobayashi /* c XXX */ { 0, 0}, 1203c60ba66SKatsushi Kobayashi /* d XXX */ { 0, 0}, 1213c60ba66SKatsushi Kobayashi /* e PHY */ {12, FWTI_REQ}, 1223c60ba66SKatsushi Kobayashi /* f XXX */ { 0, 0} 1233c60ba66SKatsushi Kobayashi }; 1243c60ba66SKatsushi Kobayashi 1253c60ba66SKatsushi Kobayashi #define OHCI_WRITE_SIGMASK 0xffff0000 1263c60ba66SKatsushi Kobayashi #define OHCI_READ_SIGMASK 0xffff0000 1273c60ba66SKatsushi Kobayashi 1283c60ba66SKatsushi Kobayashi #define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x)) 1293c60ba66SKatsushi Kobayashi #define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r)) 1303c60ba66SKatsushi Kobayashi 1313c60ba66SKatsushi Kobayashi #endif /* __FreeBSD__ */ 1323c60ba66SKatsushi Kobayashi 1333c60ba66SKatsushi Kobayashi #define senderr(e) { error = (e); goto bad;} 1343c60ba66SKatsushi Kobayashi 1353c60ba66SKatsushi Kobayashi static void fwohci_ibr __P((struct firewire_comm *)); 1363c60ba66SKatsushi Kobayashi static void fwohci_db_init __P((struct fwohci_dbch *)); 1373c60ba66SKatsushi Kobayashi static void fwohci_db_free __P((struct fwohci_dbch *)); 138783058faSHidetoshi Shimokawa static void fwohci_arcv __P((struct fwohci_softc *, struct fwohci_dbch *, int)); 139783058faSHidetoshi Shimokawa static void fwohci_ircv __P((struct fwohci_softc *, struct fwohci_dbch *, int)); 1403c60ba66SKatsushi Kobayashi static void fwohci_txd __P((struct fwohci_softc *, struct fwohci_dbch *)); 1413c60ba66SKatsushi Kobayashi static void fwohci_start_atq __P((struct firewire_comm *)); 1423c60ba66SKatsushi Kobayashi static void fwohci_start_ats __P((struct firewire_comm *)); 1433c60ba66SKatsushi Kobayashi static void fwohci_start __P((struct fwohci_softc *, struct fwohci_dbch *)); 1443c60ba66SKatsushi Kobayashi static void fwohci_drain_atq __P((struct firewire_comm *, struct fw_xfer *)); 1453c60ba66SKatsushi Kobayashi static void fwohci_drain_ats __P((struct firewire_comm *, struct fw_xfer *)); 1463c60ba66SKatsushi Kobayashi static void fwohci_drain __P((struct firewire_comm *, struct fw_xfer *, struct fwohci_dbch *)); 1473c60ba66SKatsushi Kobayashi static u_int32_t fwphy_wrdata __P(( struct fwohci_softc *, u_int32_t, u_int32_t)); 1483c60ba66SKatsushi Kobayashi static u_int32_t fwphy_rddata __P(( struct fwohci_softc *, u_int32_t)); 1493c60ba66SKatsushi Kobayashi static int fwohci_rx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); 1503c60ba66SKatsushi Kobayashi static int fwohci_tx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); 1513c60ba66SKatsushi Kobayashi static int fwohci_irx_enable __P((struct firewire_comm *, int)); 1523c60ba66SKatsushi Kobayashi static int fwohci_irxpp_enable __P((struct firewire_comm *, int)); 1533c60ba66SKatsushi Kobayashi static int fwohci_irxbuf_enable __P((struct firewire_comm *, int)); 1543c60ba66SKatsushi Kobayashi static int fwohci_irx_disable __P((struct firewire_comm *, int)); 1553c60ba66SKatsushi Kobayashi static void fwohci_irx_post __P((struct firewire_comm *, u_int32_t *)); 1563c60ba66SKatsushi Kobayashi static int fwohci_itxbuf_enable __P((struct firewire_comm *, int)); 1573c60ba66SKatsushi Kobayashi static int fwohci_itx_disable __P((struct firewire_comm *, int)); 1583c60ba66SKatsushi Kobayashi static void fwohci_timeout __P((void *)); 1593c60ba66SKatsushi Kobayashi static void fwohci_poll __P((struct firewire_comm *, int, int)); 1603c60ba66SKatsushi Kobayashi static void fwohci_set_intr __P((struct firewire_comm *, int)); 1613c60ba66SKatsushi Kobayashi static int fwohci_add_rx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *, void *)); 1623c60ba66SKatsushi Kobayashi static int fwohci_add_tx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *)); 1633c60ba66SKatsushi Kobayashi static void dump_db __P((struct fwohci_softc *, u_int32_t)); 1643c60ba66SKatsushi Kobayashi static void print_db __P((volatile struct fwohcidb *, u_int32_t , u_int32_t)); 1653c60ba66SKatsushi Kobayashi static void dump_dma __P((struct fwohci_softc *, u_int32_t)); 1663c60ba66SKatsushi Kobayashi static u_int32_t fwohci_cyctimer __P((struct firewire_comm *)); 1673c60ba66SKatsushi Kobayashi static void fwohci_rbuf_update __P((struct fwohci_softc *, int)); 1683c60ba66SKatsushi Kobayashi static void fwohci_tbuf_update __P((struct fwohci_softc *, int)); 1693c60ba66SKatsushi Kobayashi void fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *)); 1703c60ba66SKatsushi Kobayashi 1713c60ba66SKatsushi Kobayashi /* 1723c60ba66SKatsushi Kobayashi * memory allocated for DMA programs 1733c60ba66SKatsushi Kobayashi */ 1743c60ba66SKatsushi Kobayashi #define DMA_PROG_ALLOC (8 * PAGE_SIZE) 1753c60ba66SKatsushi Kobayashi 1763c60ba66SKatsushi Kobayashi /* #define NDB 1024 */ 1773c60ba66SKatsushi Kobayashi #define NDB FWMAXQUEUE 1783c60ba66SKatsushi Kobayashi #define NDVDB (DVBUF * NDB) 1793c60ba66SKatsushi Kobayashi 1803c60ba66SKatsushi Kobayashi #define OHCI_VERSION 0x00 1813c60ba66SKatsushi Kobayashi #define OHCI_CROMHDR 0x18 1823c60ba66SKatsushi Kobayashi #define OHCI_BUS_OPT 0x20 1833c60ba66SKatsushi Kobayashi #define OHCI_BUSIRMC (1 << 31) 1843c60ba66SKatsushi Kobayashi #define OHCI_BUSCMC (1 << 30) 1853c60ba66SKatsushi Kobayashi #define OHCI_BUSISC (1 << 29) 1863c60ba66SKatsushi Kobayashi #define OHCI_BUSBMC (1 << 28) 1873c60ba66SKatsushi Kobayashi #define OHCI_BUSPMC (1 << 27) 1883c60ba66SKatsushi Kobayashi #define OHCI_BUSFNC OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\ 1893c60ba66SKatsushi Kobayashi OHCI_BUSBMC | OHCI_BUSPMC 1903c60ba66SKatsushi Kobayashi 1913c60ba66SKatsushi Kobayashi #define OHCI_EUID_HI 0x24 1923c60ba66SKatsushi Kobayashi #define OHCI_EUID_LO 0x28 1933c60ba66SKatsushi Kobayashi 1943c60ba66SKatsushi Kobayashi #define OHCI_CROMPTR 0x34 1953c60ba66SKatsushi Kobayashi #define OHCI_HCCCTL 0x50 1963c60ba66SKatsushi Kobayashi #define OHCI_HCCCTLCLR 0x54 1973c60ba66SKatsushi Kobayashi #define OHCI_AREQHI 0x100 1983c60ba66SKatsushi Kobayashi #define OHCI_AREQHICLR 0x104 1993c60ba66SKatsushi Kobayashi #define OHCI_AREQLO 0x108 2003c60ba66SKatsushi Kobayashi #define OHCI_AREQLOCLR 0x10c 2013c60ba66SKatsushi Kobayashi #define OHCI_PREQHI 0x110 2023c60ba66SKatsushi Kobayashi #define OHCI_PREQHICLR 0x114 2033c60ba66SKatsushi Kobayashi #define OHCI_PREQLO 0x118 2043c60ba66SKatsushi Kobayashi #define OHCI_PREQLOCLR 0x11c 2053c60ba66SKatsushi Kobayashi #define OHCI_PREQUPPER 0x120 2063c60ba66SKatsushi Kobayashi 2073c60ba66SKatsushi Kobayashi #define OHCI_SID_BUF 0x64 2083c60ba66SKatsushi Kobayashi #define OHCI_SID_CNT 0x68 2093c60ba66SKatsushi Kobayashi #define OHCI_SID_CNT_MASK 0xffc 2103c60ba66SKatsushi Kobayashi 2113c60ba66SKatsushi Kobayashi #define OHCI_IT_STAT 0x90 2123c60ba66SKatsushi Kobayashi #define OHCI_IT_STATCLR 0x94 2133c60ba66SKatsushi Kobayashi #define OHCI_IT_MASK 0x98 2143c60ba66SKatsushi Kobayashi #define OHCI_IT_MASKCLR 0x9c 2153c60ba66SKatsushi Kobayashi 2163c60ba66SKatsushi Kobayashi #define OHCI_IR_STAT 0xa0 2173c60ba66SKatsushi Kobayashi #define OHCI_IR_STATCLR 0xa4 2183c60ba66SKatsushi Kobayashi #define OHCI_IR_MASK 0xa8 2193c60ba66SKatsushi Kobayashi #define OHCI_IR_MASKCLR 0xac 2203c60ba66SKatsushi Kobayashi 2213c60ba66SKatsushi Kobayashi #define OHCI_LNKCTL 0xe0 2223c60ba66SKatsushi Kobayashi #define OHCI_LNKCTLCLR 0xe4 2233c60ba66SKatsushi Kobayashi 2243c60ba66SKatsushi Kobayashi #define OHCI_PHYACCESS 0xec 2253c60ba66SKatsushi Kobayashi #define OHCI_CYCLETIMER 0xf0 2263c60ba66SKatsushi Kobayashi 2273c60ba66SKatsushi Kobayashi #define OHCI_DMACTL(off) (off) 2283c60ba66SKatsushi Kobayashi #define OHCI_DMACTLCLR(off) (off + 4) 2293c60ba66SKatsushi Kobayashi #define OHCI_DMACMD(off) (off + 0xc) 2303c60ba66SKatsushi Kobayashi #define OHCI_DMAMATCH(off) (off + 0x10) 2313c60ba66SKatsushi Kobayashi 2323c60ba66SKatsushi Kobayashi #define OHCI_ATQOFF 0x180 2333c60ba66SKatsushi Kobayashi #define OHCI_ATQCTL OHCI_ATQOFF 2343c60ba66SKatsushi Kobayashi #define OHCI_ATQCTLCLR (OHCI_ATQOFF + 4) 2353c60ba66SKatsushi Kobayashi #define OHCI_ATQCMD (OHCI_ATQOFF + 0xc) 2363c60ba66SKatsushi Kobayashi #define OHCI_ATQMATCH (OHCI_ATQOFF + 0x10) 2373c60ba66SKatsushi Kobayashi 2383c60ba66SKatsushi Kobayashi #define OHCI_ATSOFF 0x1a0 2393c60ba66SKatsushi Kobayashi #define OHCI_ATSCTL OHCI_ATSOFF 2403c60ba66SKatsushi Kobayashi #define OHCI_ATSCTLCLR (OHCI_ATSOFF + 4) 2413c60ba66SKatsushi Kobayashi #define OHCI_ATSCMD (OHCI_ATSOFF + 0xc) 2423c60ba66SKatsushi Kobayashi #define OHCI_ATSMATCH (OHCI_ATSOFF + 0x10) 2433c60ba66SKatsushi Kobayashi 2443c60ba66SKatsushi Kobayashi #define OHCI_ARQOFF 0x1c0 2453c60ba66SKatsushi Kobayashi #define OHCI_ARQCTL OHCI_ARQOFF 2463c60ba66SKatsushi Kobayashi #define OHCI_ARQCTLCLR (OHCI_ARQOFF + 4) 2473c60ba66SKatsushi Kobayashi #define OHCI_ARQCMD (OHCI_ARQOFF + 0xc) 2483c60ba66SKatsushi Kobayashi #define OHCI_ARQMATCH (OHCI_ARQOFF + 0x10) 2493c60ba66SKatsushi Kobayashi 2503c60ba66SKatsushi Kobayashi #define OHCI_ARSOFF 0x1e0 2513c60ba66SKatsushi Kobayashi #define OHCI_ARSCTL OHCI_ARSOFF 2523c60ba66SKatsushi Kobayashi #define OHCI_ARSCTLCLR (OHCI_ARSOFF + 4) 2533c60ba66SKatsushi Kobayashi #define OHCI_ARSCMD (OHCI_ARSOFF + 0xc) 2543c60ba66SKatsushi Kobayashi #define OHCI_ARSMATCH (OHCI_ARSOFF + 0x10) 2553c60ba66SKatsushi Kobayashi 2563c60ba66SKatsushi Kobayashi #define OHCI_ITOFF(CH) (0x200 + 0x10 * (CH)) 2573c60ba66SKatsushi Kobayashi #define OHCI_ITCTL(CH) (OHCI_ITOFF(CH)) 2583c60ba66SKatsushi Kobayashi #define OHCI_ITCTLCLR(CH) (OHCI_ITOFF(CH) + 4) 2593c60ba66SKatsushi Kobayashi #define OHCI_ITCMD(CH) (OHCI_ITOFF(CH) + 0xc) 2603c60ba66SKatsushi Kobayashi 2613c60ba66SKatsushi Kobayashi #define OHCI_IROFF(CH) (0x400 + 0x20 * (CH)) 2623c60ba66SKatsushi Kobayashi #define OHCI_IRCTL(CH) (OHCI_IROFF(CH)) 2633c60ba66SKatsushi Kobayashi #define OHCI_IRCTLCLR(CH) (OHCI_IROFF(CH) + 4) 2643c60ba66SKatsushi Kobayashi #define OHCI_IRCMD(CH) (OHCI_IROFF(CH) + 0xc) 2653c60ba66SKatsushi Kobayashi #define OHCI_IRMATCH(CH) (OHCI_IROFF(CH) + 0x10) 2663c60ba66SKatsushi Kobayashi 2673c60ba66SKatsushi Kobayashi d_ioctl_t fwohci_ioctl; 2683c60ba66SKatsushi Kobayashi 2693c60ba66SKatsushi Kobayashi /* 2703c60ba66SKatsushi Kobayashi * Communication with PHY device 2713c60ba66SKatsushi Kobayashi */ 272c572b810SHidetoshi Shimokawa static u_int32_t 273c572b810SHidetoshi Shimokawa fwphy_wrdata( struct fwohci_softc *sc, u_int32_t addr, u_int32_t data) 2743c60ba66SKatsushi Kobayashi { 2753c60ba66SKatsushi Kobayashi u_int32_t fun; 2763c60ba66SKatsushi Kobayashi 2773c60ba66SKatsushi Kobayashi addr &= 0xf; 2783c60ba66SKatsushi Kobayashi data &= 0xff; 2793c60ba66SKatsushi Kobayashi 2803c60ba66SKatsushi Kobayashi fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA)); 2813c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PHYACCESS, fun); 2823c60ba66SKatsushi Kobayashi DELAY(100); 2833c60ba66SKatsushi Kobayashi 2843c60ba66SKatsushi Kobayashi return(fwphy_rddata( sc, addr)); 2853c60ba66SKatsushi Kobayashi } 2863c60ba66SKatsushi Kobayashi 2873c60ba66SKatsushi Kobayashi static u_int32_t 2883c60ba66SKatsushi Kobayashi fwohci_set_bus_manager(struct firewire_comm *fc, u_int node) 2893c60ba66SKatsushi Kobayashi { 2903c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 2913c60ba66SKatsushi Kobayashi int i; 2923c60ba66SKatsushi Kobayashi u_int32_t bm; 2933c60ba66SKatsushi Kobayashi 2943c60ba66SKatsushi Kobayashi #define OHCI_CSR_DATA 0x0c 2953c60ba66SKatsushi Kobayashi #define OHCI_CSR_COMP 0x10 2963c60ba66SKatsushi Kobayashi #define OHCI_CSR_CONT 0x14 2973c60ba66SKatsushi Kobayashi #define OHCI_BUS_MANAGER_ID 0 2983c60ba66SKatsushi Kobayashi 2993c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_DATA, node); 3003c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_COMP, 0x3f); 3013c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID); 3023c60ba66SKatsushi Kobayashi for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++) 3033c60ba66SKatsushi Kobayashi DELAY(100); 3043c60ba66SKatsushi Kobayashi bm = OREAD(sc, OHCI_CSR_DATA); 3053c60ba66SKatsushi Kobayashi if((bm & 0x3f) == 0x3f){ 3063c60ba66SKatsushi Kobayashi printf("fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i); 3073c60ba66SKatsushi Kobayashi bm = node; 3083c60ba66SKatsushi Kobayashi }else{ 3093c60ba66SKatsushi Kobayashi printf("fw_set_bus_manager: %d-X%d (loop=%d)\n", bm, node, i); 3103c60ba66SKatsushi Kobayashi } 3113c60ba66SKatsushi Kobayashi 3123c60ba66SKatsushi Kobayashi return(bm); 3133c60ba66SKatsushi Kobayashi } 3143c60ba66SKatsushi Kobayashi 315c572b810SHidetoshi Shimokawa static u_int32_t 316c572b810SHidetoshi Shimokawa fwphy_rddata(struct fwohci_softc *sc, u_int addr) 3173c60ba66SKatsushi Kobayashi { 3183c60ba66SKatsushi Kobayashi u_int32_t fun; 3193c60ba66SKatsushi Kobayashi u_int i; 3203c60ba66SKatsushi Kobayashi 3213c60ba66SKatsushi Kobayashi addr &= 0xf; 3223c60ba66SKatsushi Kobayashi fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR); 3233c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PHYACCESS, fun); 3243c60ba66SKatsushi Kobayashi for ( i = 0 ; i < 1000 ; i ++ ){ 3253c60ba66SKatsushi Kobayashi fun = OREAD(sc, OHCI_PHYACCESS); 3263c60ba66SKatsushi Kobayashi if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0) 3273c60ba66SKatsushi Kobayashi break; 3283c60ba66SKatsushi Kobayashi DELAY(1000); 3293c60ba66SKatsushi Kobayashi } 3303c60ba66SKatsushi Kobayashi if( i >= 1000) 3313c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "cannot read phy\n"); 3323c60ba66SKatsushi Kobayashi return((fun >> PHYDEV_RDDATA )& 0xff); 3333c60ba66SKatsushi Kobayashi } 3343c60ba66SKatsushi Kobayashi /* Device specific ioctl. */ 3353c60ba66SKatsushi Kobayashi int 3363c60ba66SKatsushi Kobayashi fwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 3373c60ba66SKatsushi Kobayashi { 3383c60ba66SKatsushi Kobayashi struct firewire_softc *sc; 3393c60ba66SKatsushi Kobayashi struct fwohci_softc *fc; 3403c60ba66SKatsushi Kobayashi int unit = DEV2UNIT(dev); 3413c60ba66SKatsushi Kobayashi int err = 0; 3423c60ba66SKatsushi Kobayashi struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data; 3433c60ba66SKatsushi Kobayashi u_int32_t *dmach = (u_int32_t *) data; 3443c60ba66SKatsushi Kobayashi 3453c60ba66SKatsushi Kobayashi sc = devclass_get_softc(firewire_devclass, unit); 3463c60ba66SKatsushi Kobayashi if(sc == NULL){ 3473c60ba66SKatsushi Kobayashi return(EINVAL); 3483c60ba66SKatsushi Kobayashi } 3493c60ba66SKatsushi Kobayashi fc = (struct fwohci_softc *)sc->fc; 3503c60ba66SKatsushi Kobayashi 3513c60ba66SKatsushi Kobayashi if (!data) 3523c60ba66SKatsushi Kobayashi return(EINVAL); 3533c60ba66SKatsushi Kobayashi 3543c60ba66SKatsushi Kobayashi switch (cmd) { 3553c60ba66SKatsushi Kobayashi case FWOHCI_WRREG: 3563c60ba66SKatsushi Kobayashi #define OHCI_MAX_REG 0x800 3573c60ba66SKatsushi Kobayashi if(reg->addr <= OHCI_MAX_REG){ 3583c60ba66SKatsushi Kobayashi OWRITE(fc, reg->addr, reg->data); 3593c60ba66SKatsushi Kobayashi reg->data = OREAD(fc, reg->addr); 3603c60ba66SKatsushi Kobayashi }else{ 3613c60ba66SKatsushi Kobayashi err = EINVAL; 3623c60ba66SKatsushi Kobayashi } 3633c60ba66SKatsushi Kobayashi break; 3643c60ba66SKatsushi Kobayashi case FWOHCI_RDREG: 3653c60ba66SKatsushi Kobayashi if(reg->addr <= OHCI_MAX_REG){ 3663c60ba66SKatsushi Kobayashi reg->data = OREAD(fc, reg->addr); 3673c60ba66SKatsushi Kobayashi }else{ 3683c60ba66SKatsushi Kobayashi err = EINVAL; 3693c60ba66SKatsushi Kobayashi } 3703c60ba66SKatsushi Kobayashi break; 3713c60ba66SKatsushi Kobayashi /* Read DMA descriptors for debug */ 3723c60ba66SKatsushi Kobayashi case DUMPDMA: 3733c60ba66SKatsushi Kobayashi if(*dmach <= OHCI_MAX_DMA_CH ){ 3743c60ba66SKatsushi Kobayashi dump_dma(fc, *dmach); 3753c60ba66SKatsushi Kobayashi dump_db(fc, *dmach); 3763c60ba66SKatsushi Kobayashi }else{ 3773c60ba66SKatsushi Kobayashi err = EINVAL; 3783c60ba66SKatsushi Kobayashi } 3793c60ba66SKatsushi Kobayashi break; 3803c60ba66SKatsushi Kobayashi default: 3813c60ba66SKatsushi Kobayashi break; 3823c60ba66SKatsushi Kobayashi } 3833c60ba66SKatsushi Kobayashi return err; 3843c60ba66SKatsushi Kobayashi } 385c572b810SHidetoshi Shimokawa 386c572b810SHidetoshi Shimokawa int 387c572b810SHidetoshi Shimokawa fwohci_init(struct fwohci_softc *sc, device_t dev) 3883c60ba66SKatsushi Kobayashi { 3893c60ba66SKatsushi Kobayashi int err = 0; 3903c60ba66SKatsushi Kobayashi int i; 3913c60ba66SKatsushi Kobayashi u_int32_t reg, reg2; 3923c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 3933c60ba66SKatsushi Kobayashi int e1394a = 1; 3943c60ba66SKatsushi Kobayashi 3953c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_VERSION); 3963c60ba66SKatsushi Kobayashi device_printf(dev, "OHCI version %x.%x (ROM=%d)\n", 3973c60ba66SKatsushi Kobayashi (reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1); 3983c60ba66SKatsushi Kobayashi 3993c60ba66SKatsushi Kobayashi /* XXX: Available Isochrounous DMA channel probe */ 4003c60ba66SKatsushi Kobayashi for( i = 0 ; i < 0x20 ; i ++ ){ 4013c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(i), OHCI_CNTL_DMA_RUN); 4023c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_IRCTL(i)); 4033c60ba66SKatsushi Kobayashi if(!(reg & OHCI_CNTL_DMA_RUN)) break; 4043c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTL(i), OHCI_CNTL_DMA_RUN); 4053c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_ITCTL(i)); 4063c60ba66SKatsushi Kobayashi if(!(reg & OHCI_CNTL_DMA_RUN)) break; 4073c60ba66SKatsushi Kobayashi } 4083c60ba66SKatsushi Kobayashi sc->fc.nisodma = i; 4093c60ba66SKatsushi Kobayashi device_printf(dev, "No. of Isochronous channel is %d.\n", i); 4103c60ba66SKatsushi Kobayashi 4113c60ba66SKatsushi Kobayashi sc->fc.arq = &sc->arrq.xferq; 4123c60ba66SKatsushi Kobayashi sc->fc.ars = &sc->arrs.xferq; 4133c60ba66SKatsushi Kobayashi sc->fc.atq = &sc->atrq.xferq; 4143c60ba66SKatsushi Kobayashi sc->fc.ats = &sc->atrs.xferq; 4153c60ba66SKatsushi Kobayashi 4163c60ba66SKatsushi Kobayashi sc->arrq.xferq.start = NULL; 4173c60ba66SKatsushi Kobayashi sc->arrs.xferq.start = NULL; 4183c60ba66SKatsushi Kobayashi sc->atrq.xferq.start = fwohci_start_atq; 4193c60ba66SKatsushi Kobayashi sc->atrs.xferq.start = fwohci_start_ats; 4203c60ba66SKatsushi Kobayashi 4213c60ba66SKatsushi Kobayashi sc->arrq.xferq.drain = NULL; 4223c60ba66SKatsushi Kobayashi sc->arrs.xferq.drain = NULL; 4233c60ba66SKatsushi Kobayashi sc->atrq.xferq.drain = fwohci_drain_atq; 4243c60ba66SKatsushi Kobayashi sc->atrs.xferq.drain = fwohci_drain_ats; 4253c60ba66SKatsushi Kobayashi 4263c60ba66SKatsushi Kobayashi sc->arrq.ndesc = 1; 4273c60ba66SKatsushi Kobayashi sc->arrs.ndesc = 1; 4283c60ba66SKatsushi Kobayashi sc->atrq.ndesc = 10; 4293c60ba66SKatsushi Kobayashi sc->atrs.ndesc = 10 / 2; 4303c60ba66SKatsushi Kobayashi 4313c60ba66SKatsushi Kobayashi sc->arrq.ndb = NDB; 4323c60ba66SKatsushi Kobayashi sc->arrs.ndb = NDB / 2; 4333c60ba66SKatsushi Kobayashi sc->atrq.ndb = NDB; 4343c60ba66SKatsushi Kobayashi sc->atrs.ndb = NDB / 2; 4353c60ba66SKatsushi Kobayashi 4363c60ba66SKatsushi Kobayashi sc->arrq.dummy = NULL; 4373c60ba66SKatsushi Kobayashi sc->arrs.dummy = NULL; 4383c60ba66SKatsushi Kobayashi sc->atrq.dummy = NULL; 4393c60ba66SKatsushi Kobayashi sc->atrs.dummy = NULL; 4403c60ba66SKatsushi Kobayashi for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 4413c60ba66SKatsushi Kobayashi sc->fc.it[i] = &sc->it[i].xferq; 4423c60ba66SKatsushi Kobayashi sc->fc.ir[i] = &sc->ir[i].xferq; 4433c60ba66SKatsushi Kobayashi sc->it[i].ndb = 0; 4443c60ba66SKatsushi Kobayashi sc->ir[i].ndb = 0; 4453c60ba66SKatsushi Kobayashi } 4463c60ba66SKatsushi Kobayashi 4473c60ba66SKatsushi Kobayashi sc->fc.tcode = tinfo; 4483c60ba66SKatsushi Kobayashi 4493c60ba66SKatsushi Kobayashi sc->cromptr = (u_int32_t *) 4503c60ba66SKatsushi Kobayashi contigmalloc(CROMSIZE * 2, M_DEVBUF, M_NOWAIT, 0, ~0, 1<<10, 0); 4513c60ba66SKatsushi Kobayashi 4523c60ba66SKatsushi Kobayashi if(sc->cromptr == NULL){ 4533c60ba66SKatsushi Kobayashi return ENOMEM; 4543c60ba66SKatsushi Kobayashi } 4553c60ba66SKatsushi Kobayashi sc->fc.dev = dev; 4563c60ba66SKatsushi Kobayashi sc->fc.config_rom = &(sc->cromptr[CROMSIZE/4]); 4573c60ba66SKatsushi Kobayashi 4583c60ba66SKatsushi Kobayashi sc->fc.config_rom[1] = 0x31333934; 4593c60ba66SKatsushi Kobayashi sc->fc.config_rom[2] = 0xf000a002; 4603c60ba66SKatsushi Kobayashi sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI); 4613c60ba66SKatsushi Kobayashi sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO); 4623c60ba66SKatsushi Kobayashi sc->fc.config_rom[5] = 0; 4633c60ba66SKatsushi Kobayashi sc->fc.config_rom[0] = (4 << 24) | (5 << 16); 4643c60ba66SKatsushi Kobayashi 4653c60ba66SKatsushi Kobayashi sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4); 4663c60ba66SKatsushi Kobayashi 4673c60ba66SKatsushi Kobayashi 4683c60ba66SKatsushi Kobayashi fw_init(&sc->fc); 4693c60ba66SKatsushi Kobayashi 4703c60ba66SKatsushi Kobayashi /* Now stopping all DMA channel */ 4713c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 4723c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 4733c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 4743c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 4753c60ba66SKatsushi Kobayashi 4763c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, ~0); 4773c60ba66SKatsushi Kobayashi for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 4783c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 4793c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 4803c60ba66SKatsushi Kobayashi } 4813c60ba66SKatsushi Kobayashi 4823c60ba66SKatsushi Kobayashi /* FLUSH FIFO and reset Transmitter/Reciever */ 4833c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 4843c60ba66SKatsushi Kobayashi device_printf(dev, "resetting OHCI..."); 4853c60ba66SKatsushi Kobayashi i = 0; 4863c60ba66SKatsushi Kobayashi while(OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) { 4873c60ba66SKatsushi Kobayashi if (i++ > 100) break; 4883c60ba66SKatsushi Kobayashi DELAY(1000); 4893c60ba66SKatsushi Kobayashi } 4903c60ba66SKatsushi Kobayashi printf("done (%d)\n", i); 4913c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS); 4923c60ba66SKatsushi Kobayashi /* XXX wait for SCLK. */ 493851c3ad0SHidetoshi Shimokawa DELAY(100000); 4943c60ba66SKatsushi Kobayashi 4953c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_BUS_OPT); 4963c60ba66SKatsushi Kobayashi reg2 = reg | OHCI_BUSFNC; 4973c60ba66SKatsushi Kobayashi /* XXX */ 4983c60ba66SKatsushi Kobayashi if (((reg & 0x0000f000) >> 12) < 10) 4993c60ba66SKatsushi Kobayashi reg2 = (reg2 & 0xffff0fff) | (10 << 12); 5003c60ba66SKatsushi Kobayashi device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2); 5013c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_BUS_OPT, reg2); 5023c60ba66SKatsushi Kobayashi 5033c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]); 5043c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CROMPTR, vtophys(&sc->fc.config_rom[0])); 5053c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND); 5063c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR); 5073c60ba66SKatsushi Kobayashi 5083c60ba66SKatsushi Kobayashi /* 5093c60ba66SKatsushi Kobayashi * probe PHY parameters 5103c60ba66SKatsushi Kobayashi * 0. to prove PHY version, whether compliance of 1394a. 5113c60ba66SKatsushi Kobayashi * 1. to probe maximum speed supported by the PHY and 5123c60ba66SKatsushi Kobayashi * number of port supported by core-logic. 5133c60ba66SKatsushi Kobayashi * It is not actually available port on your PC . 5143c60ba66SKatsushi Kobayashi */ 5153c60ba66SKatsushi Kobayashi /* Wait a while */ 5163c60ba66SKatsushi Kobayashi reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 5173c60ba66SKatsushi Kobayashi #if 0 5183c60ba66SKatsushi Kobayashi /* try again */ 5193c60ba66SKatsushi Kobayashi DELAY(1000); 5203c60ba66SKatsushi Kobayashi reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 5213c60ba66SKatsushi Kobayashi #endif 5223c60ba66SKatsushi Kobayashi if((reg >> 5) != 7 ){ 5233c60ba66SKatsushi Kobayashi sc->fc.mode &= ~FWPHYASYST; 5243c60ba66SKatsushi Kobayashi sc->fc.nport = reg & FW_PHY_NP; 5253c60ba66SKatsushi Kobayashi sc->fc.speed = reg & FW_PHY_SPD >> 6; 5263c60ba66SKatsushi Kobayashi if (sc->fc.speed > MAX_SPEED) { 5273c60ba66SKatsushi Kobayashi device_printf(dev, "invalid speed %d (fixed to %d).\n", 5283c60ba66SKatsushi Kobayashi sc->fc.speed, MAX_SPEED); 5293c60ba66SKatsushi Kobayashi sc->fc.speed = MAX_SPEED; 5303c60ba66SKatsushi Kobayashi } 5313c60ba66SKatsushi Kobayashi sc->fc.maxrec = maxrec[sc->fc.speed]; 5323c60ba66SKatsushi Kobayashi device_printf(dev, 5333c60ba66SKatsushi Kobayashi "Link 1394 only %s, %d ports, maxrec %d bytes.\n", 5343c60ba66SKatsushi Kobayashi linkspeed[sc->fc.speed], sc->fc.nport, sc->fc.maxrec); 5353c60ba66SKatsushi Kobayashi }else{ 5363c60ba66SKatsushi Kobayashi reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG); 5373c60ba66SKatsushi Kobayashi sc->fc.mode |= FWPHYASYST; 5383c60ba66SKatsushi Kobayashi sc->fc.nport = reg & FW_PHY_NP; 5393c60ba66SKatsushi Kobayashi sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5; 5403c60ba66SKatsushi Kobayashi if (sc->fc.speed > MAX_SPEED) { 5413c60ba66SKatsushi Kobayashi device_printf(dev, "invalid speed %d (fixed to %d).\n", 5423c60ba66SKatsushi Kobayashi sc->fc.speed, MAX_SPEED); 5433c60ba66SKatsushi Kobayashi sc->fc.speed = MAX_SPEED; 5443c60ba66SKatsushi Kobayashi } 5453c60ba66SKatsushi Kobayashi sc->fc.maxrec = maxrec[sc->fc.speed]; 5463c60ba66SKatsushi Kobayashi device_printf(dev, 5473c60ba66SKatsushi Kobayashi "Link 1394a available %s, %d ports, maxrec %d bytes.\n", 5483c60ba66SKatsushi Kobayashi linkspeed[sc->fc.speed], sc->fc.nport, sc->fc.maxrec); 5493c60ba66SKatsushi Kobayashi 5503c60ba66SKatsushi Kobayashi /* check programPhyEnable */ 5513c60ba66SKatsushi Kobayashi reg2 = fwphy_rddata(sc, 5); 5523c60ba66SKatsushi Kobayashi #if 0 5533c60ba66SKatsushi Kobayashi if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) { 554c572b810SHidetoshi Shimokawa #else /* XXX force to enable 1394a */ 5553c60ba66SKatsushi Kobayashi if (e1394a) { 5563c60ba66SKatsushi Kobayashi #endif 5573c60ba66SKatsushi Kobayashi device_printf(dev, "Enable 1394a Enhancements\n"); 5583c60ba66SKatsushi Kobayashi /* enable EAA EMC */ 5593c60ba66SKatsushi Kobayashi reg2 |= 0x03; 5603c60ba66SKatsushi Kobayashi /* set aPhyEnhanceEnable */ 5613c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN); 5623c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY); 5633c60ba66SKatsushi Kobayashi } else { 5643c60ba66SKatsushi Kobayashi /* for safe */ 5653c60ba66SKatsushi Kobayashi reg2 &= ~0x83; 5663c60ba66SKatsushi Kobayashi } 5673c60ba66SKatsushi Kobayashi reg2 = fwphy_wrdata(sc, 5, reg2); 5683c60ba66SKatsushi Kobayashi } 5693c60ba66SKatsushi Kobayashi 5703c60ba66SKatsushi Kobayashi reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 5713c60ba66SKatsushi Kobayashi if((reg >> 5) == 7 ){ 5723c60ba66SKatsushi Kobayashi reg = fwphy_rddata(sc, 4); 5733c60ba66SKatsushi Kobayashi reg |= 1 << 6; 5743c60ba66SKatsushi Kobayashi fwphy_wrdata(sc, 4, reg); 5753c60ba66SKatsushi Kobayashi reg = fwphy_rddata(sc, 4); 5763c60ba66SKatsushi Kobayashi } 5773c60ba66SKatsushi Kobayashi 5783c60ba66SKatsushi Kobayashi /* SID recieve buffer must allign 2^11 */ 5793c60ba66SKatsushi Kobayashi #define OHCI_SIDSIZE (1 << 11) 5803c60ba66SKatsushi Kobayashi sc->fc.sid_buf = (u_int32_t *) vm_page_alloc_contig( OHCI_SIDSIZE, 5813c60ba66SKatsushi Kobayashi 0x10000, 0xffffffff, OHCI_SIDSIZE); 5823c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_SID_BUF, vtophys(sc->fc.sid_buf)); 5833c60ba66SKatsushi Kobayashi sc->fc.sid_buf++; 5843c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID); 5853c60ba66SKatsushi Kobayashi 5863c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->arrq); 5873c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->arrs); 5883c60ba66SKatsushi Kobayashi 5893c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->atrq); 5903c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->atrs); 5913c60ba66SKatsushi Kobayashi 5923c60ba66SKatsushi Kobayashi reg = OREAD(sc, FWOHCIGUID_H); 5933c60ba66SKatsushi Kobayashi for( i = 0 ; i < 4 ; i ++){ 5943c60ba66SKatsushi Kobayashi sc->fc.eui[3 - i] = reg & 0xff; 5953c60ba66SKatsushi Kobayashi reg = reg >> 8; 5963c60ba66SKatsushi Kobayashi } 5973c60ba66SKatsushi Kobayashi reg = OREAD(sc, FWOHCIGUID_L); 5983c60ba66SKatsushi Kobayashi for( i = 0 ; i < 4 ; i ++){ 5993c60ba66SKatsushi Kobayashi sc->fc.eui[7 - i] = reg & 0xff; 6003c60ba66SKatsushi Kobayashi reg = reg >> 8; 6013c60ba66SKatsushi Kobayashi } 6023c60ba66SKatsushi Kobayashi device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 6033c60ba66SKatsushi Kobayashi sc->fc.eui[0], sc->fc.eui[1], sc->fc.eui[2], sc->fc.eui[3], 6043c60ba66SKatsushi Kobayashi sc->fc.eui[4], sc->fc.eui[5], sc->fc.eui[6], sc->fc.eui[7]); 6053c60ba66SKatsushi Kobayashi sc->fc.ioctl = fwohci_ioctl; 6063c60ba66SKatsushi Kobayashi sc->fc.cyctimer = fwohci_cyctimer; 6073c60ba66SKatsushi Kobayashi sc->fc.set_bmr = fwohci_set_bus_manager; 6083c60ba66SKatsushi Kobayashi sc->fc.ibr = fwohci_ibr; 6093c60ba66SKatsushi Kobayashi sc->fc.irx_enable = fwohci_irx_enable; 6103c60ba66SKatsushi Kobayashi sc->fc.irx_disable = fwohci_irx_disable; 6113c60ba66SKatsushi Kobayashi 6123c60ba66SKatsushi Kobayashi sc->fc.itx_enable = fwohci_itxbuf_enable; 6133c60ba66SKatsushi Kobayashi sc->fc.itx_disable = fwohci_itx_disable; 6143c60ba66SKatsushi Kobayashi sc->fc.irx_post = fwohci_irx_post; 6153c60ba66SKatsushi Kobayashi sc->fc.itx_post = NULL; 6163c60ba66SKatsushi Kobayashi sc->fc.timeout = fwohci_timeout; 6173c60ba66SKatsushi Kobayashi sc->fc.poll = fwohci_poll; 6183c60ba66SKatsushi Kobayashi sc->fc.set_intr = fwohci_set_intr; 619c572b810SHidetoshi Shimokawa 6203c60ba66SKatsushi Kobayashi /* enable link */ 6213c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN); 6223c60ba66SKatsushi Kobayashi fw_busreset(&sc->fc); 6233c60ba66SKatsushi Kobayashi fwohci_rx_enable(sc, &sc->arrq); 6243c60ba66SKatsushi Kobayashi fwohci_rx_enable(sc, &sc->arrs); 6253c60ba66SKatsushi Kobayashi 6263c60ba66SKatsushi Kobayashi for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ; 6273c60ba66SKatsushi Kobayashi i ++, db_tr = STAILQ_NEXT(db_tr, link)){ 6283c60ba66SKatsushi Kobayashi db_tr->xfer = NULL; 6293c60ba66SKatsushi Kobayashi } 6303c60ba66SKatsushi Kobayashi for( i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb ; 6313c60ba66SKatsushi Kobayashi i ++, db_tr = STAILQ_NEXT(db_tr, link)){ 6323c60ba66SKatsushi Kobayashi db_tr->xfer = NULL; 6333c60ba66SKatsushi Kobayashi } 6343c60ba66SKatsushi Kobayashi sc->atrq.flags = sc->atrs.flags = 0; 6353c60ba66SKatsushi Kobayashi 6363c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_RETRY, 6373c60ba66SKatsushi Kobayashi (0xffff << 16 )| (0x0f << 8) | (0x0f << 4) | 0x0f) ; 6383c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, ~0); 6393c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, 6403c60ba66SKatsushi Kobayashi OHCI_INT_ERR | OHCI_INT_PHY_SID 6413c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 6423c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 6433c60ba66SKatsushi Kobayashi | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); 6443c60ba66SKatsushi Kobayashi fwohci_set_intr(&sc->fc, 1); 6453c60ba66SKatsushi Kobayashi 6463c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 6473c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 6483c60ba66SKatsushi Kobayashi 6493c60ba66SKatsushi Kobayashi return err; 6503c60ba66SKatsushi Kobayashi } 651c572b810SHidetoshi Shimokawa 652c572b810SHidetoshi Shimokawa void 653c572b810SHidetoshi Shimokawa fwohci_timeout(void *arg) 6543c60ba66SKatsushi Kobayashi { 6553c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 6563c60ba66SKatsushi Kobayashi 6573c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)arg; 6583c60ba66SKatsushi Kobayashi sc->fc.timeouthandle = timeout(fwohci_timeout, 6593c60ba66SKatsushi Kobayashi (void *)sc, FW_XFERTIMEOUT * hz * 10); 6603c60ba66SKatsushi Kobayashi } 661c572b810SHidetoshi Shimokawa 662c572b810SHidetoshi Shimokawa u_int32_t 663c572b810SHidetoshi Shimokawa fwohci_cyctimer(struct firewire_comm *fc) 6643c60ba66SKatsushi Kobayashi { 6653c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 6663c60ba66SKatsushi Kobayashi return(OREAD(sc, OHCI_CYCLETIMER)); 6673c60ba66SKatsushi Kobayashi } 6683c60ba66SKatsushi Kobayashi 6693c60ba66SKatsushi Kobayashi #define LAST_DB(dbtr, db) do { \ 6703c60ba66SKatsushi Kobayashi struct fwohcidb_tr *_dbtr = (dbtr); \ 6713c60ba66SKatsushi Kobayashi int _cnt = _dbtr->dbcnt; \ 6723c60ba66SKatsushi Kobayashi db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0]; \ 6733c60ba66SKatsushi Kobayashi } while (0) 6743c60ba66SKatsushi Kobayashi 675c572b810SHidetoshi Shimokawa static void 676c572b810SHidetoshi Shimokawa fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 6773c60ba66SKatsushi Kobayashi { 6783c60ba66SKatsushi Kobayashi int i, s; 6793c60ba66SKatsushi Kobayashi int tcode, hdr_len, hdr_off, len; 6803c60ba66SKatsushi Kobayashi int fsegment = -1; 6813c60ba66SKatsushi Kobayashi u_int32_t off; 6823c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 6833c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 6843c60ba66SKatsushi Kobayashi volatile struct fwohci_txpkthdr *ohcifp; 6853c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 6863c60ba66SKatsushi Kobayashi volatile struct fwohcidb *db; 6873c60ba66SKatsushi Kobayashi struct mbuf *m; 6883c60ba66SKatsushi Kobayashi struct tcode_info *info; 6893c60ba66SKatsushi Kobayashi 6903c60ba66SKatsushi Kobayashi if(&sc->atrq == dbch){ 6913c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 6923c60ba66SKatsushi Kobayashi }else if(&sc->atrs == dbch){ 6933c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 6943c60ba66SKatsushi Kobayashi }else{ 6953c60ba66SKatsushi Kobayashi return; 6963c60ba66SKatsushi Kobayashi } 6973c60ba66SKatsushi Kobayashi 6983c60ba66SKatsushi Kobayashi if (dbch->flags & FWOHCI_DBCH_FULL) 6993c60ba66SKatsushi Kobayashi return; 7003c60ba66SKatsushi Kobayashi 7013c60ba66SKatsushi Kobayashi s = splfw(); 7023c60ba66SKatsushi Kobayashi db_tr = dbch->top; 7033c60ba66SKatsushi Kobayashi txloop: 7043c60ba66SKatsushi Kobayashi xfer = STAILQ_FIRST(&dbch->xferq.q); 7053c60ba66SKatsushi Kobayashi if(xfer == NULL){ 7063c60ba66SKatsushi Kobayashi goto kick; 7073c60ba66SKatsushi Kobayashi } 7083c60ba66SKatsushi Kobayashi if(dbch->xferq.queued == 0 ){ 7093c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "TX queue empty\n"); 7103c60ba66SKatsushi Kobayashi } 7113c60ba66SKatsushi Kobayashi STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); 7123c60ba66SKatsushi Kobayashi db_tr->xfer = xfer; 7133c60ba66SKatsushi Kobayashi xfer->state = FWXF_START; 7143c60ba66SKatsushi Kobayashi dbch->xferq.packets++; 7153c60ba66SKatsushi Kobayashi 7163c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)(xfer->send.buf + xfer->send.off); 7173c60ba66SKatsushi Kobayashi tcode = fp->mode.common.tcode; 7183c60ba66SKatsushi Kobayashi 7193c60ba66SKatsushi Kobayashi ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed; 7203c60ba66SKatsushi Kobayashi info = &tinfo[tcode]; 7213c60ba66SKatsushi Kobayashi hdr_len = hdr_off = info->hdr_len; 7223c60ba66SKatsushi Kobayashi /* fw_asyreq must pass valid send.len */ 7233c60ba66SKatsushi Kobayashi len = xfer->send.len; 7243c60ba66SKatsushi Kobayashi for( i = 0 ; i < hdr_off ; i+= 4){ 7253c60ba66SKatsushi Kobayashi ohcifp->mode.ld[i/4] = ntohl(fp->mode.ld[i/4]); 7263c60ba66SKatsushi Kobayashi } 7273c60ba66SKatsushi Kobayashi ohcifp->mode.common.spd = xfer->spd; 7283c60ba66SKatsushi Kobayashi if (tcode == FWTCODE_STREAM ){ 7293c60ba66SKatsushi Kobayashi hdr_len = 8; 7303c60ba66SKatsushi Kobayashi ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); 7313c60ba66SKatsushi Kobayashi } else if (tcode == FWTCODE_PHY) { 7323c60ba66SKatsushi Kobayashi hdr_len = 12; 7333c60ba66SKatsushi Kobayashi ohcifp->mode.ld[1] = ntohl(fp->mode.ld[1]); 7343c60ba66SKatsushi Kobayashi ohcifp->mode.ld[2] = ntohl(fp->mode.ld[2]); 7353c60ba66SKatsushi Kobayashi ohcifp->mode.common.spd = 0; 7363c60ba66SKatsushi Kobayashi ohcifp->mode.common.tcode = FWOHCITCODE_PHY; 7373c60ba66SKatsushi Kobayashi } else { 7383c60ba66SKatsushi Kobayashi ohcifp->mode.asycomm.dst = ntohs(fp->mode.hdr.dst); 7393c60ba66SKatsushi Kobayashi ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; 7403c60ba66SKatsushi Kobayashi ohcifp->mode.asycomm.tlrt |= FWRETRY_X; 7413c60ba66SKatsushi Kobayashi } 7423c60ba66SKatsushi Kobayashi db = &db_tr->db[0]; 7433c60ba66SKatsushi Kobayashi db->db.desc.cmd = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len; 7443c60ba66SKatsushi Kobayashi db->db.desc.status = 0; 7453c60ba66SKatsushi Kobayashi /* Specify bound timer of asy. responce */ 7463c60ba66SKatsushi Kobayashi if(&sc->atrs == dbch){ 7473c60ba66SKatsushi Kobayashi db->db.desc.count 7483c60ba66SKatsushi Kobayashi = (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13); 7493c60ba66SKatsushi Kobayashi } 7503c60ba66SKatsushi Kobayashi 7513c60ba66SKatsushi Kobayashi db_tr->dbcnt = 2; 7523c60ba66SKatsushi Kobayashi db = &db_tr->db[db_tr->dbcnt]; 7533c60ba66SKatsushi Kobayashi if(len > hdr_off){ 7543c60ba66SKatsushi Kobayashi if (xfer->mbuf == NULL) { 7553c60ba66SKatsushi Kobayashi db->db.desc.addr 7563c60ba66SKatsushi Kobayashi = vtophys(xfer->send.buf + xfer->send.off) + hdr_off; 7573c60ba66SKatsushi Kobayashi db->db.desc.cmd 7583c60ba66SKatsushi Kobayashi = OHCI_OUTPUT_MORE | ((len - hdr_off) & 0xffff); 7593c60ba66SKatsushi Kobayashi db->db.desc.status = 0; 7603c60ba66SKatsushi Kobayashi 7613c60ba66SKatsushi Kobayashi db_tr->dbcnt++; 7623c60ba66SKatsushi Kobayashi } else { 7633c60ba66SKatsushi Kobayashi /* XXX we assume mbuf chain is shorter than ndesc */ 7643c60ba66SKatsushi Kobayashi m = xfer->mbuf; 7653c60ba66SKatsushi Kobayashi do { 7663c60ba66SKatsushi Kobayashi db->db.desc.addr 7673c60ba66SKatsushi Kobayashi = vtophys(mtod(m, caddr_t)); 7683c60ba66SKatsushi Kobayashi db->db.desc.cmd = OHCI_OUTPUT_MORE | m->m_len; 7693c60ba66SKatsushi Kobayashi db->db.desc.status = 0; 7703c60ba66SKatsushi Kobayashi db++; 7713c60ba66SKatsushi Kobayashi db_tr->dbcnt++; 7723c60ba66SKatsushi Kobayashi m = m->m_next; 7733c60ba66SKatsushi Kobayashi } while (m != NULL); 7743c60ba66SKatsushi Kobayashi } 7753c60ba66SKatsushi Kobayashi } 7763c60ba66SKatsushi Kobayashi /* last db */ 7773c60ba66SKatsushi Kobayashi LAST_DB(db_tr, db); 7783c60ba66SKatsushi Kobayashi db->db.desc.cmd |= OHCI_OUTPUT_LAST 7793c60ba66SKatsushi Kobayashi | OHCI_INTERRUPT_ALWAYS 7803c60ba66SKatsushi Kobayashi | OHCI_BRANCH_ALWAYS; 7813c60ba66SKatsushi Kobayashi db->db.desc.depend = vtophys(STAILQ_NEXT(db_tr, link)->db); 7823c60ba66SKatsushi Kobayashi 7833c60ba66SKatsushi Kobayashi if(fsegment == -1 ) 7843c60ba66SKatsushi Kobayashi fsegment = db_tr->dbcnt; 7853c60ba66SKatsushi Kobayashi if (dbch->pdb_tr != NULL) { 7863c60ba66SKatsushi Kobayashi LAST_DB(dbch->pdb_tr, db); 7873c60ba66SKatsushi Kobayashi db->db.desc.depend |= db_tr->dbcnt; 7883c60ba66SKatsushi Kobayashi } 7893c60ba66SKatsushi Kobayashi dbch->pdb_tr = db_tr; 7903c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 7913c60ba66SKatsushi Kobayashi if(db_tr != dbch->bottom){ 7923c60ba66SKatsushi Kobayashi goto txloop; 7933c60ba66SKatsushi Kobayashi } else { 7943c60ba66SKatsushi Kobayashi printf("fwohci_start: lack of db_trq\n"); 7953c60ba66SKatsushi Kobayashi dbch->flags |= FWOHCI_DBCH_FULL; 7963c60ba66SKatsushi Kobayashi } 7973c60ba66SKatsushi Kobayashi kick: 7983c60ba66SKatsushi Kobayashi if (firewire_debug) printf("kick\n"); 7993c60ba66SKatsushi Kobayashi /* kick asy q */ 8003c60ba66SKatsushi Kobayashi 8013c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_RUNNING) { 8023c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 8033c60ba66SKatsushi Kobayashi } else { 8043c60ba66SKatsushi Kobayashi printf("start AT DMA status=%x\n", 8053c60ba66SKatsushi Kobayashi OREAD(sc, OHCI_DMACTL(off))); 8063c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | fsegment); 8073c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 8083c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 8093c60ba66SKatsushi Kobayashi } 810c572b810SHidetoshi Shimokawa 8113c60ba66SKatsushi Kobayashi dbch->top = db_tr; 8123c60ba66SKatsushi Kobayashi splx(s); 8133c60ba66SKatsushi Kobayashi return; 8143c60ba66SKatsushi Kobayashi } 815c572b810SHidetoshi Shimokawa 816c572b810SHidetoshi Shimokawa static void 817c572b810SHidetoshi Shimokawa fwohci_drain_atq(struct firewire_comm *fc, struct fw_xfer *xfer) 8183c60ba66SKatsushi Kobayashi { 8193c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 8203c60ba66SKatsushi Kobayashi fwohci_drain(&sc->fc, xfer, &(sc->atrq)); 8213c60ba66SKatsushi Kobayashi return; 8223c60ba66SKatsushi Kobayashi } 823c572b810SHidetoshi Shimokawa 824c572b810SHidetoshi Shimokawa static void 825c572b810SHidetoshi Shimokawa fwohci_drain_ats(struct firewire_comm *fc, struct fw_xfer *xfer) 8263c60ba66SKatsushi Kobayashi { 8273c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 8283c60ba66SKatsushi Kobayashi fwohci_drain(&sc->fc, xfer, &(sc->atrs)); 8293c60ba66SKatsushi Kobayashi return; 8303c60ba66SKatsushi Kobayashi } 831c572b810SHidetoshi Shimokawa 832c572b810SHidetoshi Shimokawa static void 833c572b810SHidetoshi Shimokawa fwohci_start_atq(struct firewire_comm *fc) 8343c60ba66SKatsushi Kobayashi { 8353c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 8363c60ba66SKatsushi Kobayashi fwohci_start( sc, &(sc->atrq)); 8373c60ba66SKatsushi Kobayashi return; 8383c60ba66SKatsushi Kobayashi } 839c572b810SHidetoshi Shimokawa 840c572b810SHidetoshi Shimokawa static void 841c572b810SHidetoshi Shimokawa fwohci_start_ats(struct firewire_comm *fc) 8423c60ba66SKatsushi Kobayashi { 8433c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 8443c60ba66SKatsushi Kobayashi fwohci_start( sc, &(sc->atrs)); 8453c60ba66SKatsushi Kobayashi return; 8463c60ba66SKatsushi Kobayashi } 847c572b810SHidetoshi Shimokawa 848c572b810SHidetoshi Shimokawa void 849c572b810SHidetoshi Shimokawa fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 8503c60ba66SKatsushi Kobayashi { 8513c60ba66SKatsushi Kobayashi int s, err = 0; 8523c60ba66SKatsushi Kobayashi struct fwohcidb_tr *tr; 8533c60ba66SKatsushi Kobayashi volatile struct fwohcidb *db; 8543c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 8553c60ba66SKatsushi Kobayashi u_int32_t off; 8563c60ba66SKatsushi Kobayashi u_int stat; 8573c60ba66SKatsushi Kobayashi int packets; 8583c60ba66SKatsushi Kobayashi struct firewire_comm *fc = (struct firewire_comm *)sc; 8593c60ba66SKatsushi Kobayashi if(&sc->atrq == dbch){ 8603c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 8613c60ba66SKatsushi Kobayashi }else if(&sc->atrs == dbch){ 8623c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 8633c60ba66SKatsushi Kobayashi }else{ 8643c60ba66SKatsushi Kobayashi return; 8653c60ba66SKatsushi Kobayashi } 8663c60ba66SKatsushi Kobayashi s = splfw(); 8673c60ba66SKatsushi Kobayashi tr = dbch->bottom; 8683c60ba66SKatsushi Kobayashi packets = 0; 8693c60ba66SKatsushi Kobayashi while(dbch->xferq.queued > 0){ 8703c60ba66SKatsushi Kobayashi LAST_DB(tr, db); 8713c60ba66SKatsushi Kobayashi if(!(db->db.desc.status & OHCI_CNTL_DMA_ACTIVE)){ 8723c60ba66SKatsushi Kobayashi if (fc->status != FWBUSRESET) 8733c60ba66SKatsushi Kobayashi /* maybe out of order?? */ 8743c60ba66SKatsushi Kobayashi goto out; 8753c60ba66SKatsushi Kobayashi } 8763c60ba66SKatsushi Kobayashi if(db->db.desc.status & OHCI_CNTL_DMA_DEAD) { 8773c60ba66SKatsushi Kobayashi #ifdef OHCI_DEBUG 8783c60ba66SKatsushi Kobayashi dump_dma(sc, ch); 8793c60ba66SKatsushi Kobayashi dump_db(sc, ch); 8803c60ba66SKatsushi Kobayashi #endif 8813c60ba66SKatsushi Kobayashi /* Stop DMA */ 8823c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 8833c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "force reset AT FIFO\n"); 8843c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN); 8853c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN); 8863c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 8873c60ba66SKatsushi Kobayashi } 8883c60ba66SKatsushi Kobayashi stat = db->db.desc.status & FWOHCIEV_MASK; 8893c60ba66SKatsushi Kobayashi switch(stat){ 8903c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 8913c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKPEND: 8923c60ba66SKatsushi Kobayashi err = 0; 8933c60ba66SKatsushi Kobayashi break; 8943c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSA: 8953c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSB: 8963c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); 8973c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSX: 8983c60ba66SKatsushi Kobayashi err = EBUSY; 8993c60ba66SKatsushi Kobayashi break; 9003c60ba66SKatsushi Kobayashi case FWOHCIEV_FLUSHED: 9013c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKTARD: 9023c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); 9033c60ba66SKatsushi Kobayashi err = EAGAIN; 9043c60ba66SKatsushi Kobayashi break; 9053c60ba66SKatsushi Kobayashi case FWOHCIEV_MISSACK: 9063c60ba66SKatsushi Kobayashi case FWOHCIEV_UNDRRUN: 9073c60ba66SKatsushi Kobayashi case FWOHCIEV_OVRRUN: 9083c60ba66SKatsushi Kobayashi case FWOHCIEV_DESCERR: 9093c60ba66SKatsushi Kobayashi case FWOHCIEV_DTRDERR: 9103c60ba66SKatsushi Kobayashi case FWOHCIEV_TIMEOUT: 9113c60ba66SKatsushi Kobayashi case FWOHCIEV_TCODERR: 9123c60ba66SKatsushi Kobayashi case FWOHCIEV_UNKNOWN: 9133c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKDERR: 9143c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKTERR: 9153c60ba66SKatsushi Kobayashi default: 9163c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "txd err=%2x %s\n", 9173c60ba66SKatsushi Kobayashi stat, fwohcicode[stat]); 9183c60ba66SKatsushi Kobayashi err = EINVAL; 9193c60ba66SKatsushi Kobayashi break; 9203c60ba66SKatsushi Kobayashi } 9213c60ba66SKatsushi Kobayashi if(tr->xfer != NULL){ 9223c60ba66SKatsushi Kobayashi xfer = tr->xfer; 9233c60ba66SKatsushi Kobayashi xfer->state = FWXF_SENT; 9243c60ba66SKatsushi Kobayashi if(err == EBUSY && fc->status != FWBUSRESET){ 9253c60ba66SKatsushi Kobayashi xfer->state = FWXF_BUSY; 9263c60ba66SKatsushi Kobayashi switch(xfer->act_type){ 9273c60ba66SKatsushi Kobayashi case FWACT_XFER: 9283c60ba66SKatsushi Kobayashi xfer->resp = err; 9293c60ba66SKatsushi Kobayashi if(xfer->retry_req != NULL){ 9303c60ba66SKatsushi Kobayashi xfer->retry_req(xfer); 9313c60ba66SKatsushi Kobayashi } 9323c60ba66SKatsushi Kobayashi break; 9333c60ba66SKatsushi Kobayashi default: 9343c60ba66SKatsushi Kobayashi break; 9353c60ba66SKatsushi Kobayashi } 9363c60ba66SKatsushi Kobayashi } else if( stat != FWOHCIEV_ACKPEND){ 9373c60ba66SKatsushi Kobayashi if (stat != FWOHCIEV_ACKCOMPL) 9383c60ba66SKatsushi Kobayashi xfer->state = FWXF_SENTERR; 9393c60ba66SKatsushi Kobayashi xfer->resp = err; 9403c60ba66SKatsushi Kobayashi switch(xfer->act_type){ 9413c60ba66SKatsushi Kobayashi case FWACT_XFER: 9423c60ba66SKatsushi Kobayashi fw_xfer_done(xfer); 9433c60ba66SKatsushi Kobayashi break; 9443c60ba66SKatsushi Kobayashi default: 9453c60ba66SKatsushi Kobayashi break; 9463c60ba66SKatsushi Kobayashi } 9473c60ba66SKatsushi Kobayashi } 9483c60ba66SKatsushi Kobayashi dbch->xferq.queued --; 9493c60ba66SKatsushi Kobayashi } 9503c60ba66SKatsushi Kobayashi tr->xfer = NULL; 9513c60ba66SKatsushi Kobayashi 9523c60ba66SKatsushi Kobayashi packets ++; 9533c60ba66SKatsushi Kobayashi tr = STAILQ_NEXT(tr, link); 9543c60ba66SKatsushi Kobayashi dbch->bottom = tr; 9553c60ba66SKatsushi Kobayashi } 9563c60ba66SKatsushi Kobayashi out: 9573c60ba66SKatsushi Kobayashi if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { 9583c60ba66SKatsushi Kobayashi printf("make free slot\n"); 9593c60ba66SKatsushi Kobayashi dbch->flags &= ~FWOHCI_DBCH_FULL; 9603c60ba66SKatsushi Kobayashi fwohci_start(sc, dbch); 9613c60ba66SKatsushi Kobayashi } 9623c60ba66SKatsushi Kobayashi splx(s); 9633c60ba66SKatsushi Kobayashi } 964c572b810SHidetoshi Shimokawa 965c572b810SHidetoshi Shimokawa static void 966c572b810SHidetoshi Shimokawa fwohci_drain(struct firewire_comm *fc, struct fw_xfer *xfer, struct fwohci_dbch *dbch) 9673c60ba66SKatsushi Kobayashi { 9683c60ba66SKatsushi Kobayashi int i, s; 9693c60ba66SKatsushi Kobayashi struct fwohcidb_tr *tr; 9703c60ba66SKatsushi Kobayashi 9713c60ba66SKatsushi Kobayashi if(xfer->state != FWXF_START) return; 9723c60ba66SKatsushi Kobayashi 9733c60ba66SKatsushi Kobayashi s = splfw(); 9743c60ba66SKatsushi Kobayashi tr = dbch->bottom; 9753c60ba66SKatsushi Kobayashi for( i = 0 ; i <= dbch->xferq.queued ; i ++){ 9763c60ba66SKatsushi Kobayashi if(tr->xfer == xfer){ 9773c60ba66SKatsushi Kobayashi s = splfw(); 9783c60ba66SKatsushi Kobayashi tr->xfer = NULL; 9793c60ba66SKatsushi Kobayashi dbch->xferq.queued --; 9803c60ba66SKatsushi Kobayashi #if 1 9813c60ba66SKatsushi Kobayashi /* XXX */ 9823c60ba66SKatsushi Kobayashi if (tr == dbch->bottom) 9833c60ba66SKatsushi Kobayashi dbch->bottom = STAILQ_NEXT(tr, link); 9843c60ba66SKatsushi Kobayashi #endif 9853c60ba66SKatsushi Kobayashi if (dbch->flags & FWOHCI_DBCH_FULL) { 9863c60ba66SKatsushi Kobayashi printf("fwohci_drain: make slot\n"); 9873c60ba66SKatsushi Kobayashi dbch->flags &= ~FWOHCI_DBCH_FULL; 9883c60ba66SKatsushi Kobayashi fwohci_start((struct fwohci_softc *)fc, dbch); 9893c60ba66SKatsushi Kobayashi } 9903c60ba66SKatsushi Kobayashi 9913c60ba66SKatsushi Kobayashi splx(s); 9923c60ba66SKatsushi Kobayashi break; 9933c60ba66SKatsushi Kobayashi } 9943c60ba66SKatsushi Kobayashi tr = STAILQ_NEXT(tr, link); 9953c60ba66SKatsushi Kobayashi } 9963c60ba66SKatsushi Kobayashi splx(s); 9973c60ba66SKatsushi Kobayashi return; 9983c60ba66SKatsushi Kobayashi } 9993c60ba66SKatsushi Kobayashi 1000c572b810SHidetoshi Shimokawa static void 1001c572b810SHidetoshi Shimokawa fwohci_db_free(struct fwohci_dbch *dbch) 10023c60ba66SKatsushi Kobayashi { 10033c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 10043c60ba66SKatsushi Kobayashi int idb; 10053c60ba66SKatsushi Kobayashi 10063c60ba66SKatsushi Kobayashi if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ 10073c60ba66SKatsushi Kobayashi for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; 10083c60ba66SKatsushi Kobayashi idb < dbch->ndb; 10093c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link), idb++){ 10103c60ba66SKatsushi Kobayashi free(db_tr->buf, M_DEVBUF); 10113c60ba66SKatsushi Kobayashi db_tr->buf = NULL; 10123c60ba66SKatsushi Kobayashi } 10133c60ba66SKatsushi Kobayashi } 10143c60ba66SKatsushi Kobayashi dbch->ndb = 0; 10153c60ba66SKatsushi Kobayashi db_tr = STAILQ_FIRST(&dbch->db_trq); 10163c60ba66SKatsushi Kobayashi contigfree((void *)(uintptr_t)(volatile void *)db_tr->db, 10173c60ba66SKatsushi Kobayashi sizeof(struct fwohcidb) * dbch->ndesc * dbch->ndb, M_DEVBUF); 10183c60ba66SKatsushi Kobayashi /* Attach DB to DMA ch. */ 10193c60ba66SKatsushi Kobayashi free(db_tr, M_DEVBUF); 10203c60ba66SKatsushi Kobayashi STAILQ_INIT(&dbch->db_trq); 10213c60ba66SKatsushi Kobayashi } 1022c572b810SHidetoshi Shimokawa 1023c572b810SHidetoshi Shimokawa static void 1024c572b810SHidetoshi Shimokawa fwohci_db_init(struct fwohci_dbch *dbch) 10253c60ba66SKatsushi Kobayashi { 10263c60ba66SKatsushi Kobayashi int idb; 10273c60ba66SKatsushi Kobayashi struct fwohcidb *db; 10283c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 10293c60ba66SKatsushi Kobayashi /* allocate DB entries and attach one to each DMA channels */ 10303c60ba66SKatsushi Kobayashi /* DB entry must start at 16 bytes bounary. */ 10313c60ba66SKatsushi Kobayashi dbch->frag.buf = NULL; 10323c60ba66SKatsushi Kobayashi dbch->frag.len = 0; 10333c60ba66SKatsushi Kobayashi dbch->frag.plen = 0; 10343c60ba66SKatsushi Kobayashi dbch->xferq.queued = 0; 10353c60ba66SKatsushi Kobayashi dbch->pdb_tr = NULL; 10363c60ba66SKatsushi Kobayashi 10373c60ba66SKatsushi Kobayashi STAILQ_INIT(&dbch->db_trq); 10383c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *) 10393c60ba66SKatsushi Kobayashi malloc(sizeof(struct fwohcidb_tr) * dbch->ndb, 10403c60ba66SKatsushi Kobayashi M_DEVBUF, M_DONTWAIT); 10413c60ba66SKatsushi Kobayashi if(db_tr == NULL){ 10423c60ba66SKatsushi Kobayashi return; 10433c60ba66SKatsushi Kobayashi } 10443c60ba66SKatsushi Kobayashi db = (struct fwohcidb *) 10453c60ba66SKatsushi Kobayashi contigmalloc(sizeof (struct fwohcidb) * dbch->ndesc * dbch->ndb, 10463c60ba66SKatsushi Kobayashi M_DEVBUF, M_DONTWAIT, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); 10473c60ba66SKatsushi Kobayashi if(db == NULL){ 10483c60ba66SKatsushi Kobayashi printf("fwochi_db_init: contigmalloc failed\n"); 10493c60ba66SKatsushi Kobayashi return; 10503c60ba66SKatsushi Kobayashi } 10513c60ba66SKatsushi Kobayashi bzero(db, sizeof (struct fwohcidb) * dbch->ndesc * dbch->ndb); 10523c60ba66SKatsushi Kobayashi /* Attach DB to DMA ch. */ 10533c60ba66SKatsushi Kobayashi for(idb = 0 ; idb < dbch->ndb ; idb++){ 10543c60ba66SKatsushi Kobayashi db_tr->dbcnt = 0; 10553c60ba66SKatsushi Kobayashi db_tr->db = &db[idb * dbch->ndesc]; 10563c60ba66SKatsushi Kobayashi STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); 10573c60ba66SKatsushi Kobayashi if(!(dbch->xferq.flag & FWXFERQ_PACKET) && 10583c60ba66SKatsushi Kobayashi (idb % dbch->xferq.bnpacket == 0)){ 10593c60ba66SKatsushi Kobayashi dbch->xferq.bulkxfer[idb/dbch->xferq.bnpacket].start 10603c60ba66SKatsushi Kobayashi = (caddr_t)db_tr; 10613c60ba66SKatsushi Kobayashi } 10623c60ba66SKatsushi Kobayashi if((!(dbch->xferq.flag & FWXFERQ_PACKET)) && 10633c60ba66SKatsushi Kobayashi ((idb + 1)% dbch->xferq.bnpacket == 0)){ 10643c60ba66SKatsushi Kobayashi dbch->xferq.bulkxfer[idb/dbch->xferq.bnpacket].end 10653c60ba66SKatsushi Kobayashi = (caddr_t)db_tr; 10663c60ba66SKatsushi Kobayashi } 10673c60ba66SKatsushi Kobayashi db_tr++; 10683c60ba66SKatsushi Kobayashi } 10693c60ba66SKatsushi Kobayashi STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next 10703c60ba66SKatsushi Kobayashi = STAILQ_FIRST(&dbch->db_trq); 10713c60ba66SKatsushi Kobayashi dbch->top = STAILQ_FIRST(&dbch->db_trq); 10723c60ba66SKatsushi Kobayashi dbch->bottom = dbch->top; 10733c60ba66SKatsushi Kobayashi } 1074c572b810SHidetoshi Shimokawa 1075c572b810SHidetoshi Shimokawa static int 1076c572b810SHidetoshi Shimokawa fwohci_itx_disable(struct firewire_comm *fc, int dmach) 10773c60ba66SKatsushi Kobayashi { 10783c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 10793c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 10803c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 10813c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 10823c60ba66SKatsushi Kobayashi fwohci_db_free(&sc->it[dmach]); 10833c60ba66SKatsushi Kobayashi sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 10843c60ba66SKatsushi Kobayashi return 0; 10853c60ba66SKatsushi Kobayashi } 1086c572b810SHidetoshi Shimokawa 1087c572b810SHidetoshi Shimokawa static int 1088c572b810SHidetoshi Shimokawa fwohci_irx_disable(struct firewire_comm *fc, int dmach) 10893c60ba66SKatsushi Kobayashi { 10903c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 10913c60ba66SKatsushi Kobayashi 10923c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 10933c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 10943c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 10953c60ba66SKatsushi Kobayashi if(sc->ir[dmach].dummy != NULL){ 10963c60ba66SKatsushi Kobayashi free(sc->ir[dmach].dummy, M_DEVBUF); 10973c60ba66SKatsushi Kobayashi } 10983c60ba66SKatsushi Kobayashi sc->ir[dmach].dummy = NULL; 10993c60ba66SKatsushi Kobayashi fwohci_db_free(&sc->ir[dmach]); 11003c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 11013c60ba66SKatsushi Kobayashi return 0; 11023c60ba66SKatsushi Kobayashi } 1103c572b810SHidetoshi Shimokawa 1104c572b810SHidetoshi Shimokawa static void 1105c572b810SHidetoshi Shimokawa fwohci_irx_post (struct firewire_comm *fc , u_int32_t *qld) 11063c60ba66SKatsushi Kobayashi { 11073c60ba66SKatsushi Kobayashi qld[0] = ntohl(qld[0]); 11083c60ba66SKatsushi Kobayashi return; 11093c60ba66SKatsushi Kobayashi } 1110c572b810SHidetoshi Shimokawa 1111c572b810SHidetoshi Shimokawa static int 1112c572b810SHidetoshi Shimokawa fwohci_irxpp_enable(struct firewire_comm *fc, int dmach) 11133c60ba66SKatsushi Kobayashi { 11143c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 11153c60ba66SKatsushi Kobayashi int err = 0; 11163c60ba66SKatsushi Kobayashi unsigned short tag, ich; 11173c60ba66SKatsushi Kobayashi 11183c60ba66SKatsushi Kobayashi tag = (sc->ir[dmach].xferq.flag >> 6) & 3; 11193c60ba66SKatsushi Kobayashi ich = sc->ir[dmach].xferq.flag & 0x3f; 11203c60ba66SKatsushi Kobayashi 11213c60ba66SKatsushi Kobayashi #if 0 11223c60ba66SKatsushi Kobayashi if(STAILQ_FIRST(&fc->ir[dmach]->q) != NULL){ 11233c60ba66SKatsushi Kobayashi wakeup(fc->ir[dmach]); 11243c60ba66SKatsushi Kobayashi return err; 11253c60ba66SKatsushi Kobayashi } 11263c60ba66SKatsushi Kobayashi #endif 11273c60ba66SKatsushi Kobayashi 11283c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 11293c60ba66SKatsushi Kobayashi if(!(sc->ir[dmach].xferq.flag & FWXFERQ_RUNNING)){ 11303c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.queued = 0; 11313c60ba66SKatsushi Kobayashi sc->ir[dmach].ndb = NDB; 11323c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.psize = FWPMAX_S400; 11333c60ba66SKatsushi Kobayashi sc->ir[dmach].ndesc = 1; 11343c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->ir[dmach]); 11353c60ba66SKatsushi Kobayashi err = fwohci_rx_enable(sc, &sc->ir[dmach]); 11363c60ba66SKatsushi Kobayashi } 11373c60ba66SKatsushi Kobayashi if(err){ 11383c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "err in IRX setting\n"); 11393c60ba66SKatsushi Kobayashi return err; 11403c60ba66SKatsushi Kobayashi } 11413c60ba66SKatsushi Kobayashi if(!(OREAD(sc, OHCI_IRCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE)){ 11423c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 11433c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 11443c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 11453c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 11463c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf8000000); 11473c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 11483c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCMD(dmach), 11493c60ba66SKatsushi Kobayashi vtophys(sc->ir[dmach].top->db) | 1); 11503c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 11513c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 11523c60ba66SKatsushi Kobayashi } 11533c60ba66SKatsushi Kobayashi return err; 11543c60ba66SKatsushi Kobayashi } 1155c572b810SHidetoshi Shimokawa 1156c572b810SHidetoshi Shimokawa static int 1157c572b810SHidetoshi Shimokawa fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 11583c60ba66SKatsushi Kobayashi { 11593c60ba66SKatsushi Kobayashi int err = 0; 11603c60ba66SKatsushi Kobayashi int idb, z, i, dmach = 0; 11613c60ba66SKatsushi Kobayashi u_int32_t off = NULL; 11623c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 11633c60ba66SKatsushi Kobayashi 11643c60ba66SKatsushi Kobayashi if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ 11653c60ba66SKatsushi Kobayashi err = EINVAL; 11663c60ba66SKatsushi Kobayashi return err; 11673c60ba66SKatsushi Kobayashi } 11683c60ba66SKatsushi Kobayashi z = dbch->ndesc; 11693c60ba66SKatsushi Kobayashi for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 11703c60ba66SKatsushi Kobayashi if( &sc->it[dmach] == dbch){ 11713c60ba66SKatsushi Kobayashi off = OHCI_ITOFF(dmach); 11723c60ba66SKatsushi Kobayashi break; 11733c60ba66SKatsushi Kobayashi } 11743c60ba66SKatsushi Kobayashi } 11753c60ba66SKatsushi Kobayashi if(off == NULL){ 11763c60ba66SKatsushi Kobayashi err = EINVAL; 11773c60ba66SKatsushi Kobayashi return err; 11783c60ba66SKatsushi Kobayashi } 11793c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_RUNNING) 11803c60ba66SKatsushi Kobayashi return err; 11813c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 11823c60ba66SKatsushi Kobayashi for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ 11833c60ba66SKatsushi Kobayashi dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 11843c60ba66SKatsushi Kobayashi } 11853c60ba66SKatsushi Kobayashi db_tr = dbch->top; 11863c60ba66SKatsushi Kobayashi for( idb = 0 ; idb < dbch->ndb ; idb ++){ 11873c60ba66SKatsushi Kobayashi fwohci_add_tx_buf(db_tr, 11883c60ba66SKatsushi Kobayashi dbch->xferq.psize, dbch->xferq.flag, 11893c60ba66SKatsushi Kobayashi dbch->xferq.buf + dbch->xferq.psize * idb); 11903c60ba66SKatsushi Kobayashi if(STAILQ_NEXT(db_tr, link) == NULL){ 11913c60ba66SKatsushi Kobayashi break; 11923c60ba66SKatsushi Kobayashi } 11933c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend 11943c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; 11953c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.depend 11963c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; 11973c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 11983c60ba66SKatsushi Kobayashi if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ 11993c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.cmd 12003c60ba66SKatsushi Kobayashi |= OHCI_INTERRUPT_ALWAYS; 12013c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend &= ~0xf; 12023c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.depend &= 12033c60ba66SKatsushi Kobayashi ~0xf; 12043c60ba66SKatsushi Kobayashi } 12053c60ba66SKatsushi Kobayashi } 12063c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 12073c60ba66SKatsushi Kobayashi } 12083c60ba66SKatsushi Kobayashi dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; 12093c60ba66SKatsushi Kobayashi return err; 12103c60ba66SKatsushi Kobayashi } 1211c572b810SHidetoshi Shimokawa 1212c572b810SHidetoshi Shimokawa static int 1213c572b810SHidetoshi Shimokawa fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 12143c60ba66SKatsushi Kobayashi { 12153c60ba66SKatsushi Kobayashi int err = 0; 12163c60ba66SKatsushi Kobayashi int idb, z, i, dmach = 0; 12173c60ba66SKatsushi Kobayashi u_int32_t off = NULL; 12183c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 12193c60ba66SKatsushi Kobayashi 12203c60ba66SKatsushi Kobayashi z = dbch->ndesc; 12213c60ba66SKatsushi Kobayashi if(&sc->arrq == dbch){ 12223c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 12233c60ba66SKatsushi Kobayashi }else if(&sc->arrs == dbch){ 12243c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 12253c60ba66SKatsushi Kobayashi }else{ 12263c60ba66SKatsushi Kobayashi for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 12273c60ba66SKatsushi Kobayashi if( &sc->ir[dmach] == dbch){ 12283c60ba66SKatsushi Kobayashi off = OHCI_IROFF(dmach); 12293c60ba66SKatsushi Kobayashi break; 12303c60ba66SKatsushi Kobayashi } 12313c60ba66SKatsushi Kobayashi } 12323c60ba66SKatsushi Kobayashi } 12333c60ba66SKatsushi Kobayashi if(off == NULL){ 12343c60ba66SKatsushi Kobayashi err = EINVAL; 12353c60ba66SKatsushi Kobayashi return err; 12363c60ba66SKatsushi Kobayashi } 12373c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_STREAM){ 12383c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_RUNNING) 12393c60ba66SKatsushi Kobayashi return err; 12403c60ba66SKatsushi Kobayashi }else{ 12413c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_RUNNING){ 12423c60ba66SKatsushi Kobayashi err = EBUSY; 12433c60ba66SKatsushi Kobayashi return err; 12443c60ba66SKatsushi Kobayashi } 12453c60ba66SKatsushi Kobayashi } 12463c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 12473c60ba66SKatsushi Kobayashi for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ 12483c60ba66SKatsushi Kobayashi dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 12493c60ba66SKatsushi Kobayashi } 12503c60ba66SKatsushi Kobayashi db_tr = dbch->top; 12513c60ba66SKatsushi Kobayashi for( idb = 0 ; idb < dbch->ndb ; idb ++){ 12523c60ba66SKatsushi Kobayashi if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ 12533c60ba66SKatsushi Kobayashi fwohci_add_rx_buf(db_tr, 12543c60ba66SKatsushi Kobayashi dbch->xferq.psize, dbch->xferq.flag, 0, NULL); 12553c60ba66SKatsushi Kobayashi }else{ 12563c60ba66SKatsushi Kobayashi fwohci_add_rx_buf(db_tr, 12573c60ba66SKatsushi Kobayashi dbch->xferq.psize, dbch->xferq.flag, 12583c60ba66SKatsushi Kobayashi dbch->xferq.buf + dbch->xferq.psize * idb, 12593c60ba66SKatsushi Kobayashi dbch->dummy + sizeof(u_int32_t) * idb); 12603c60ba66SKatsushi Kobayashi } 12613c60ba66SKatsushi Kobayashi if(STAILQ_NEXT(db_tr, link) == NULL){ 12623c60ba66SKatsushi Kobayashi break; 12633c60ba66SKatsushi Kobayashi } 12643c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.depend 12653c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; 12663c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 12673c60ba66SKatsushi Kobayashi if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ 12683c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.cmd 12693c60ba66SKatsushi Kobayashi |= OHCI_INTERRUPT_ALWAYS; 12703c60ba66SKatsushi Kobayashi db_tr->db[db_tr->dbcnt - 1].db.desc.depend &= 12713c60ba66SKatsushi Kobayashi ~0xf; 12723c60ba66SKatsushi Kobayashi } 12733c60ba66SKatsushi Kobayashi } 12743c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 12753c60ba66SKatsushi Kobayashi } 12763c60ba66SKatsushi Kobayashi dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; 12773c60ba66SKatsushi Kobayashi dbch->buf_offset = 0; 12783c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_STREAM){ 12793c60ba66SKatsushi Kobayashi return err; 12803c60ba66SKatsushi Kobayashi }else{ 12813c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | z); 12823c60ba66SKatsushi Kobayashi } 12833c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 12843c60ba66SKatsushi Kobayashi return err; 12853c60ba66SKatsushi Kobayashi } 1286c572b810SHidetoshi Shimokawa 1287c572b810SHidetoshi Shimokawa static int 1288c572b810SHidetoshi Shimokawa fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) 12893c60ba66SKatsushi Kobayashi { 12903c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 12913c60ba66SKatsushi Kobayashi int err = 0; 12923c60ba66SKatsushi Kobayashi unsigned short tag, ich; 12933c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 12943c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 12953c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 12963c60ba66SKatsushi Kobayashi 12973c60ba66SKatsushi Kobayashi tag = (sc->it[dmach].xferq.flag >> 6) & 3; 12983c60ba66SKatsushi Kobayashi ich = sc->it[dmach].xferq.flag & 0x3f; 12993c60ba66SKatsushi Kobayashi dbch = &sc->it[dmach]; 13003c60ba66SKatsushi Kobayashi if(dbch->ndb == 0){ 13013c60ba66SKatsushi Kobayashi dbch->xferq.queued = 0; 13023c60ba66SKatsushi Kobayashi dbch->ndb = dbch->xferq.bnpacket * dbch->xferq.bnchunk; 13033c60ba66SKatsushi Kobayashi dbch->ndesc = 3; 13043c60ba66SKatsushi Kobayashi fwohci_db_init(dbch); 13053c60ba66SKatsushi Kobayashi err = fwohci_tx_enable(sc, dbch); 13063c60ba66SKatsushi Kobayashi } 13073c60ba66SKatsushi Kobayashi if(err) 13083c60ba66SKatsushi Kobayashi return err; 13093c60ba66SKatsushi Kobayashi if(OREAD(sc, OHCI_ITCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE){ 13103c60ba66SKatsushi Kobayashi if(dbch->xferq.stdma2 != NULL){ 13113c60ba66SKatsushi Kobayashi fwohci_txbufdb(sc, dmach, dbch->xferq.stdma2); 13123c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) 13133c60ba66SKatsushi Kobayashi (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.cmd 13143c60ba66SKatsushi Kobayashi |= OHCI_BRANCH_ALWAYS; 13153c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) 13163c60ba66SKatsushi Kobayashi (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.depend = 13173c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; 13183c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[0].db.desc.depend = 13193c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; 13203c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; 13213c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; 13223c60ba66SKatsushi Kobayashi } 13233c60ba66SKatsushi Kobayashi }else if(!(OREAD(sc, OHCI_ITCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE)){ 13243c60ba66SKatsushi Kobayashi fw_tbuf_update(&sc->fc, dmach, 0); 13253c60ba66SKatsushi Kobayashi if(dbch->xferq.stdma == NULL){ 13263c60ba66SKatsushi Kobayashi return err; 13273c60ba66SKatsushi Kobayashi } 13283c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 13293c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 13303c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 13313c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_MASK, 1 << dmach); 13323c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xf0000000); 13333c60ba66SKatsushi Kobayashi fwohci_txbufdb(sc, dmach, dbch->xferq.stdma); 13343c60ba66SKatsushi Kobayashi if(dbch->xferq.stdma2 != NULL){ 13353c60ba66SKatsushi Kobayashi fwohci_txbufdb(sc, dmach, dbch->xferq.stdma2); 13363c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) 13373c60ba66SKatsushi Kobayashi (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.cmd 13383c60ba66SKatsushi Kobayashi |= OHCI_BRANCH_ALWAYS; 13393c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.depend = 13403c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; 13413c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma->end))->db[0].db.desc.depend = 13423c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(dbch->xferq.stdma2->start))->db) | dbch->ndesc; 13433c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(dbch->xferq.stdma2->end))->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; 13443c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) (dbch->xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; 13453c60ba66SKatsushi Kobayashi }else{ 13463c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) (dbch->xferq.stdma->end))->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; 13473c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *) (dbch->xferq.stdma->end))->db[0].db.desc.depend &= ~0xf; 13483c60ba66SKatsushi Kobayashi } 13493c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCMD(dmach), 13503c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *) 13513c60ba66SKatsushi Kobayashi (dbch->xferq.stdma->start))->db) | dbch->ndesc); 13523c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_DV){ 13533c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start; 13543c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)db_tr->buf; 13553c60ba66SKatsushi Kobayashi fp->mode.ld[2] = htonl(0x80000000 + 13563c60ba66SKatsushi Kobayashi ((fc->cyctimer(fc) + 0x3000) & 0xf000)); 13573c60ba66SKatsushi Kobayashi } 13583c60ba66SKatsushi Kobayashi 13593c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); 13603c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); 13613c60ba66SKatsushi Kobayashi } 13623c60ba66SKatsushi Kobayashi return err; 13633c60ba66SKatsushi Kobayashi } 1364c572b810SHidetoshi Shimokawa 1365c572b810SHidetoshi Shimokawa static int 1366c572b810SHidetoshi Shimokawa fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach) 13673c60ba66SKatsushi Kobayashi { 13683c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 13693c60ba66SKatsushi Kobayashi int err = 0; 13703c60ba66SKatsushi Kobayashi unsigned short tag, ich; 13713c60ba66SKatsushi Kobayashi tag = (sc->ir[dmach].xferq.flag >> 6) & 3; 13723c60ba66SKatsushi Kobayashi ich = sc->ir[dmach].xferq.flag & 0x3f; 13733c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 13743c60ba66SKatsushi Kobayashi 13753c60ba66SKatsushi Kobayashi if(!(sc->ir[dmach].xferq.flag & FWXFERQ_RUNNING)){ 13763c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.queued = 0; 13773c60ba66SKatsushi Kobayashi sc->ir[dmach].ndb = sc->ir[dmach].xferq.bnpacket * 13783c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.bnchunk; 13793c60ba66SKatsushi Kobayashi sc->ir[dmach].dummy = 13803c60ba66SKatsushi Kobayashi malloc(sizeof(u_int32_t) * sc->ir[dmach].ndb, 13813c60ba66SKatsushi Kobayashi M_DEVBUF, M_DONTWAIT); 13823c60ba66SKatsushi Kobayashi if(sc->ir[dmach].dummy == NULL){ 13833c60ba66SKatsushi Kobayashi err = ENOMEM; 13843c60ba66SKatsushi Kobayashi return err; 13853c60ba66SKatsushi Kobayashi } 13863c60ba66SKatsushi Kobayashi sc->ir[dmach].ndesc = 2; 13873c60ba66SKatsushi Kobayashi fwohci_db_init(&sc->ir[dmach]); 13883c60ba66SKatsushi Kobayashi err = fwohci_rx_enable(sc, &sc->ir[dmach]); 13893c60ba66SKatsushi Kobayashi } 13903c60ba66SKatsushi Kobayashi if(err) 13913c60ba66SKatsushi Kobayashi return err; 13923c60ba66SKatsushi Kobayashi 13933c60ba66SKatsushi Kobayashi if(OREAD(sc, OHCI_IRCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE){ 13943c60ba66SKatsushi Kobayashi if(sc->ir[dmach].xferq.stdma2 != NULL){ 13953c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend = 13963c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db) | sc->ir[dmach].ndesc; 13973c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend = 13983c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db); 13993c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; 14003c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[0].db.desc.depend &= ~0xf; 14013c60ba66SKatsushi Kobayashi } 14023c60ba66SKatsushi Kobayashi }else if(!(OREAD(sc, OHCI_IRCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE) 14033c60ba66SKatsushi Kobayashi && !(sc->ir[dmach].xferq.flag & FWXFERQ_PACKET)){ 14043c60ba66SKatsushi Kobayashi fw_rbuf_update(&sc->fc, dmach, 0); 14053c60ba66SKatsushi Kobayashi 14063c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 14073c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 14083c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 14093c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 14103c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); 14113c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 14123c60ba66SKatsushi Kobayashi if(sc->ir[dmach].xferq.stdma2 != NULL){ 14133c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend = 14143c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db) | sc->ir[dmach].ndesc; 14153c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend = 14163c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->start))->db); 14173c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma2->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; 14183c60ba66SKatsushi Kobayashi }else{ 14193c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[sc->ir[dmach].ndesc - 1].db.desc.depend &= ~0xf; 14203c60ba66SKatsushi Kobayashi ((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->end))->db[0].db.desc.depend &= ~0xf; 14213c60ba66SKatsushi Kobayashi } 14223c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCMD(dmach), 14233c60ba66SKatsushi Kobayashi vtophys(((struct fwohcidb_tr *)(sc->ir[dmach].xferq.stdma->start))->db) | sc->ir[dmach].ndesc); 14243c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 14253c60ba66SKatsushi Kobayashi } 14263c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 14273c60ba66SKatsushi Kobayashi return err; 14283c60ba66SKatsushi Kobayashi } 1429c572b810SHidetoshi Shimokawa 1430c572b810SHidetoshi Shimokawa static int 1431c572b810SHidetoshi Shimokawa fwohci_irx_enable(struct firewire_comm *fc, int dmach) 14323c60ba66SKatsushi Kobayashi { 14333c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 14343c60ba66SKatsushi Kobayashi int err = 0; 14353c60ba66SKatsushi Kobayashi 14363c60ba66SKatsushi Kobayashi if(sc->ir[dmach].xferq.flag & FWXFERQ_PACKET){ 14373c60ba66SKatsushi Kobayashi err = fwohci_irxpp_enable(fc, dmach); 14383c60ba66SKatsushi Kobayashi return err; 14393c60ba66SKatsushi Kobayashi }else{ 14403c60ba66SKatsushi Kobayashi err = fwohci_irxbuf_enable(fc, dmach); 14413c60ba66SKatsushi Kobayashi return err; 14423c60ba66SKatsushi Kobayashi } 14433c60ba66SKatsushi Kobayashi } 1444c572b810SHidetoshi Shimokawa 1445c572b810SHidetoshi Shimokawa int 1446c572b810SHidetoshi Shimokawa fwohci_shutdown(device_t dev) 14473c60ba66SKatsushi Kobayashi { 14483c60ba66SKatsushi Kobayashi u_int i; 14493c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = device_get_softc(dev); 14503c60ba66SKatsushi Kobayashi 14513c60ba66SKatsushi Kobayashi /* Now stopping all DMA channel */ 14523c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 14533c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 14543c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 14553c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 14563c60ba66SKatsushi Kobayashi 14573c60ba66SKatsushi Kobayashi for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 14583c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 14593c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 14603c60ba66SKatsushi Kobayashi } 14613c60ba66SKatsushi Kobayashi 14623c60ba66SKatsushi Kobayashi /* FLUSH FIFO and reset Transmitter/Reciever */ 14633c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 14643c60ba66SKatsushi Kobayashi 14653c60ba66SKatsushi Kobayashi /* Stop interrupt */ 14663c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, 14673c60ba66SKatsushi Kobayashi OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID 14683c60ba66SKatsushi Kobayashi | OHCI_INT_PHY_INT 14693c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 14703c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 14713c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 14723c60ba66SKatsushi Kobayashi | OHCI_INT_PHY_BUS_R); 14733c60ba66SKatsushi Kobayashi return 0; 14743c60ba66SKatsushi Kobayashi } 14753c60ba66SKatsushi Kobayashi 14763c60ba66SKatsushi Kobayashi #define ACK_ALL 14773c60ba66SKatsushi Kobayashi static void 1478783058faSHidetoshi Shimokawa fwohci_intr_body(struct fwohci_softc *sc, u_int32_t stat, int count) 14793c60ba66SKatsushi Kobayashi { 14803c60ba66SKatsushi Kobayashi u_int32_t irstat, itstat; 14813c60ba66SKatsushi Kobayashi u_int i; 14823c60ba66SKatsushi Kobayashi struct firewire_comm *fc = (struct firewire_comm *)sc; 14833c60ba66SKatsushi Kobayashi 14843c60ba66SKatsushi Kobayashi #define OHCI_DEBUG 14853c60ba66SKatsushi Kobayashi #undef OHCI_DEBUG 14863c60ba66SKatsushi Kobayashi #ifdef OHCI_DEBUG 14873c60ba66SKatsushi Kobayashi if(stat & OREAD(sc, FWOHCI_INTMASK)) 14883c60ba66SKatsushi Kobayashi device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n", 14893c60ba66SKatsushi Kobayashi stat & OHCI_INT_EN ? "DMA_EN ":"", 14903c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", 14913c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", 14923c60ba66SKatsushi Kobayashi stat & OHCI_INT_ERR ? "INT_ERR ":"", 14933c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", 14943c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", 14953c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", 14963c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_START ? "CYC_START ":"", 14973c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", 14983c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", 14993c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_SID ? "SID ":"", 15003c60ba66SKatsushi Kobayashi stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", 15013c60ba66SKatsushi Kobayashi stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", 15023c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", 15033c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", 15043c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", 15053c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", 15063c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", 15073c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", 15083c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", 15093c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", 15103c60ba66SKatsushi Kobayashi stat, OREAD(sc, FWOHCI_INTMASK) 15113c60ba66SKatsushi Kobayashi ); 15123c60ba66SKatsushi Kobayashi #endif 15133c60ba66SKatsushi Kobayashi /* Bus reset */ 15143c60ba66SKatsushi Kobayashi if(stat & OHCI_INT_PHY_BUS_R ){ 15153c60ba66SKatsushi Kobayashi device_printf(fc->dev, "BUS reset\n"); 15163c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 15173c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); 15183c60ba66SKatsushi Kobayashi 15193c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 15203c60ba66SKatsushi Kobayashi sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; 15213c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 15223c60ba66SKatsushi Kobayashi sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; 15233c60ba66SKatsushi Kobayashi 15243c60ba66SKatsushi Kobayashi #if 0 15253c60ba66SKatsushi Kobayashi for( i = 0 ; i < fc->nisodma ; i ++ ){ 15263c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 15273c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 15283c60ba66SKatsushi Kobayashi } 15293c60ba66SKatsushi Kobayashi 15303c60ba66SKatsushi Kobayashi #endif 15313c60ba66SKatsushi Kobayashi fw_busreset(fc); 15323c60ba66SKatsushi Kobayashi 15333c60ba66SKatsushi Kobayashi /* XXX need to wait DMA to stop */ 15343c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 15353c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); 15363c60ba66SKatsushi Kobayashi #endif 15373c60ba66SKatsushi Kobayashi #if 1 15383c60ba66SKatsushi Kobayashi /* pending all pre-bus_reset packets */ 15393c60ba66SKatsushi Kobayashi fwohci_txd(sc, &sc->atrq); 15403c60ba66SKatsushi Kobayashi fwohci_txd(sc, &sc->atrs); 1541783058faSHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrs, -1); 1542783058faSHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrq, -1); 15433c60ba66SKatsushi Kobayashi #endif 15443c60ba66SKatsushi Kobayashi 15453c60ba66SKatsushi Kobayashi 15463c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_AREQHI, 1 << 31); 15473c60ba66SKatsushi Kobayashi /* XXX insecure ?? */ 15483c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PREQHI, 0x7fffffff); 15493c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PREQLO, 0xffffffff); 15503c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PREQUPPER, 0x10000); 15513c60ba66SKatsushi Kobayashi 15523c60ba66SKatsushi Kobayashi } 15533c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_IR )){ 15543c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 15553c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR); 15563c60ba66SKatsushi Kobayashi #endif 15573c60ba66SKatsushi Kobayashi irstat = OREAD(sc, OHCI_IR_STAT); 15583c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, ~0); 15593c60ba66SKatsushi Kobayashi for(i = 0; i < fc->nisodma ; i++){ 15603c60ba66SKatsushi Kobayashi if((irstat & (1 << i)) != 0){ 15613c60ba66SKatsushi Kobayashi if(sc->ir[i].xferq.flag & FWXFERQ_PACKET){ 1562783058faSHidetoshi Shimokawa fwohci_ircv(sc, &sc->ir[i], count); 15633c60ba66SKatsushi Kobayashi }else{ 15643c60ba66SKatsushi Kobayashi fwohci_rbuf_update(sc, i); 15653c60ba66SKatsushi Kobayashi } 15663c60ba66SKatsushi Kobayashi } 15673c60ba66SKatsushi Kobayashi } 15683c60ba66SKatsushi Kobayashi } 15693c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_IT )){ 15703c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 15713c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT); 15723c60ba66SKatsushi Kobayashi #endif 15733c60ba66SKatsushi Kobayashi itstat = OREAD(sc, OHCI_IT_STAT); 15743c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_STATCLR, ~0); 15753c60ba66SKatsushi Kobayashi for(i = 0; i < fc->nisodma ; i++){ 15763c60ba66SKatsushi Kobayashi if((itstat & (1 << i)) != 0){ 15773c60ba66SKatsushi Kobayashi fwohci_tbuf_update(sc, i); 15783c60ba66SKatsushi Kobayashi } 15793c60ba66SKatsushi Kobayashi } 15803c60ba66SKatsushi Kobayashi } 15813c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_PRRS )){ 15823c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 15833c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS); 15843c60ba66SKatsushi Kobayashi #endif 15853c60ba66SKatsushi Kobayashi #if 0 15863c60ba66SKatsushi Kobayashi dump_dma(sc, ARRS_CH); 15873c60ba66SKatsushi Kobayashi dump_db(sc, ARRS_CH); 15883c60ba66SKatsushi Kobayashi #endif 1589783058faSHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrs, count); 15903c60ba66SKatsushi Kobayashi } 15913c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_PRRQ )){ 15923c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 15933c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ); 15943c60ba66SKatsushi Kobayashi #endif 15953c60ba66SKatsushi Kobayashi #if 0 15963c60ba66SKatsushi Kobayashi dump_dma(sc, ARRQ_CH); 15973c60ba66SKatsushi Kobayashi dump_db(sc, ARRQ_CH); 15983c60ba66SKatsushi Kobayashi #endif 1599783058faSHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrq, count); 16003c60ba66SKatsushi Kobayashi } 16013c60ba66SKatsushi Kobayashi if(stat & OHCI_INT_PHY_SID){ 16023c60ba66SKatsushi Kobayashi caddr_t buf; 16033c60ba66SKatsushi Kobayashi int plen; 16043c60ba66SKatsushi Kobayashi 16053c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16063c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID); 16073c60ba66SKatsushi Kobayashi #endif 16083c60ba66SKatsushi Kobayashi /* 16093c60ba66SKatsushi Kobayashi ** Checking whether the node is root or not. If root, turn on 16103c60ba66SKatsushi Kobayashi ** cycle master. 16113c60ba66SKatsushi Kobayashi */ 16123c60ba66SKatsushi Kobayashi device_printf(fc->dev, "node_id = 0x%08x, ", OREAD(sc, FWOHCI_NODEID)); 16133c60ba66SKatsushi Kobayashi if(!(OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_VALID)){ 16143c60ba66SKatsushi Kobayashi printf("Bus reset failure\n"); 16153c60ba66SKatsushi Kobayashi goto sidout; 16163c60ba66SKatsushi Kobayashi } 16173c60ba66SKatsushi Kobayashi if( OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_ROOT ){ 16183c60ba66SKatsushi Kobayashi printf("CYCLEMASTER mode\n"); 16193c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTL, 16203c60ba66SKatsushi Kobayashi OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); 16213c60ba66SKatsushi Kobayashi }else{ 16223c60ba66SKatsushi Kobayashi printf("non CYCLEMASTER mode\n"); 16233c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); 16243c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); 16253c60ba66SKatsushi Kobayashi } 16263c60ba66SKatsushi Kobayashi fc->nodeid = OREAD(sc, FWOHCI_NODEID) & 0x3f; 16273c60ba66SKatsushi Kobayashi 16283c60ba66SKatsushi Kobayashi plen = OREAD(sc, OHCI_SID_CNT) & OHCI_SID_CNT_MASK; 16293c60ba66SKatsushi Kobayashi plen -= 4; /* chop control info */ 16303c60ba66SKatsushi Kobayashi buf = malloc( FWPMAX_S400, M_DEVBUF, M_NOWAIT); 16313c60ba66SKatsushi Kobayashi if(buf == NULL) goto sidout; 16323c60ba66SKatsushi Kobayashi bcopy((void *)(uintptr_t)(volatile void *)fc->sid_buf, 16333c60ba66SKatsushi Kobayashi buf, plen); 16343c60ba66SKatsushi Kobayashi fw_sidrcv(fc, buf, plen, 0); 16353c60ba66SKatsushi Kobayashi } 16363c60ba66SKatsushi Kobayashi sidout: 16373c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_ATRQ )){ 16383c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16393c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ); 16403c60ba66SKatsushi Kobayashi #endif 16413c60ba66SKatsushi Kobayashi fwohci_txd(sc, &(sc->atrq)); 16423c60ba66SKatsushi Kobayashi } 16433c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_DMA_ATRS )){ 16443c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16453c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS); 16463c60ba66SKatsushi Kobayashi #endif 16473c60ba66SKatsushi Kobayashi fwohci_txd(sc, &(sc->atrs)); 16483c60ba66SKatsushi Kobayashi } 16493c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_PW_ERR )){ 16503c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16513c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR); 16523c60ba66SKatsushi Kobayashi #endif 16533c60ba66SKatsushi Kobayashi device_printf(fc->dev, "posted write error\n"); 16543c60ba66SKatsushi Kobayashi } 16553c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_ERR )){ 16563c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16573c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR); 16583c60ba66SKatsushi Kobayashi #endif 16593c60ba66SKatsushi Kobayashi device_printf(fc->dev, "unrecoverable error\n"); 16603c60ba66SKatsushi Kobayashi } 16613c60ba66SKatsushi Kobayashi if((stat & OHCI_INT_PHY_INT)) { 16623c60ba66SKatsushi Kobayashi #ifndef ACK_ALL 16633c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT); 16643c60ba66SKatsushi Kobayashi #endif 16653c60ba66SKatsushi Kobayashi device_printf(fc->dev, "phy int\n"); 16663c60ba66SKatsushi Kobayashi } 16673c60ba66SKatsushi Kobayashi 16683c60ba66SKatsushi Kobayashi return; 16693c60ba66SKatsushi Kobayashi } 16703c60ba66SKatsushi Kobayashi 16713c60ba66SKatsushi Kobayashi void 16723c60ba66SKatsushi Kobayashi fwohci_intr(void *arg) 16733c60ba66SKatsushi Kobayashi { 16743c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)arg; 16753c60ba66SKatsushi Kobayashi u_int32_t stat; 16763c60ba66SKatsushi Kobayashi 16773c60ba66SKatsushi Kobayashi if (!(sc->intmask & OHCI_INT_EN)) { 16783c60ba66SKatsushi Kobayashi /* polling mode */ 16793c60ba66SKatsushi Kobayashi return; 16803c60ba66SKatsushi Kobayashi } 16813c60ba66SKatsushi Kobayashi 16823c60ba66SKatsushi Kobayashi while ((stat = OREAD(sc, FWOHCI_INTSTAT)) != 0) { 16833c60ba66SKatsushi Kobayashi if (stat == 0xffffffff) { 16843c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, 16853c60ba66SKatsushi Kobayashi "device physically ejected?\n"); 16863c60ba66SKatsushi Kobayashi return; 16873c60ba66SKatsushi Kobayashi } 16883c60ba66SKatsushi Kobayashi #ifdef ACK_ALL 16893c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, stat); 16903c60ba66SKatsushi Kobayashi #endif 1691783058faSHidetoshi Shimokawa fwohci_intr_body(sc, stat, -1); 16923c60ba66SKatsushi Kobayashi } 16933c60ba66SKatsushi Kobayashi } 16943c60ba66SKatsushi Kobayashi 16953c60ba66SKatsushi Kobayashi static void 16963c60ba66SKatsushi Kobayashi fwohci_poll(struct firewire_comm *fc, int quick, int count) 16973c60ba66SKatsushi Kobayashi { 16983c60ba66SKatsushi Kobayashi int s; 16993c60ba66SKatsushi Kobayashi u_int32_t stat; 17003c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 17013c60ba66SKatsushi Kobayashi 17023c60ba66SKatsushi Kobayashi 17033c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)fc; 17043c60ba66SKatsushi Kobayashi stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT | 17053c60ba66SKatsushi Kobayashi OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ | 17063c60ba66SKatsushi Kobayashi OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS; 17073c60ba66SKatsushi Kobayashi #if 0 17083c60ba66SKatsushi Kobayashi if (!quick) { 17093c60ba66SKatsushi Kobayashi #else 17103c60ba66SKatsushi Kobayashi if (1) { 17113c60ba66SKatsushi Kobayashi #endif 17123c60ba66SKatsushi Kobayashi stat = OREAD(sc, FWOHCI_INTSTAT); 17133c60ba66SKatsushi Kobayashi if (stat == 0) 17143c60ba66SKatsushi Kobayashi return; 17153c60ba66SKatsushi Kobayashi if (stat == 0xffffffff) { 17163c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, 17173c60ba66SKatsushi Kobayashi "device physically ejected?\n"); 17183c60ba66SKatsushi Kobayashi return; 17193c60ba66SKatsushi Kobayashi } 17203c60ba66SKatsushi Kobayashi #ifdef ACK_ALL 17213c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTSTATCLR, stat); 17223c60ba66SKatsushi Kobayashi #endif 17233c60ba66SKatsushi Kobayashi } 17243c60ba66SKatsushi Kobayashi s = splfw(); 1725783058faSHidetoshi Shimokawa fwohci_intr_body(sc, stat, count); 17263c60ba66SKatsushi Kobayashi splx(s); 17273c60ba66SKatsushi Kobayashi } 17283c60ba66SKatsushi Kobayashi 17293c60ba66SKatsushi Kobayashi static void 17303c60ba66SKatsushi Kobayashi fwohci_set_intr(struct firewire_comm *fc, int enable) 17313c60ba66SKatsushi Kobayashi { 17323c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 17333c60ba66SKatsushi Kobayashi 17343c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)fc; 17353c60ba66SKatsushi Kobayashi printf("fwochi_set_intr: %d\n", enable); 17363c60ba66SKatsushi Kobayashi if (enable) { 17373c60ba66SKatsushi Kobayashi sc->intmask |= OHCI_INT_EN; 17383c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); 17393c60ba66SKatsushi Kobayashi } else { 17403c60ba66SKatsushi Kobayashi sc->intmask &= ~OHCI_INT_EN; 17413c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); 17423c60ba66SKatsushi Kobayashi } 17433c60ba66SKatsushi Kobayashi } 17443c60ba66SKatsushi Kobayashi 1745c572b810SHidetoshi Shimokawa static void 1746c572b810SHidetoshi Shimokawa fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) 17473c60ba66SKatsushi Kobayashi { 17483c60ba66SKatsushi Kobayashi int stat; 17493c60ba66SKatsushi Kobayashi struct firewire_comm *fc = &sc->fc; 17503c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 17513c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 17523c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 17533c60ba66SKatsushi Kobayashi 17543c60ba66SKatsushi Kobayashi dbch = &sc->it[dmach]; 17553c60ba66SKatsushi Kobayashi if((dbch->xferq.flag & FWXFERQ_DV) && (dbch->xferq.stdma2 != NULL)){ 17563c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma2->start; 17573c60ba66SKatsushi Kobayashi /* 17583c60ba66SKatsushi Kobayashi * Overwrite highest significant 4 bits timestamp information 17593c60ba66SKatsushi Kobayashi */ 17603c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)db_tr->buf; 17613c60ba66SKatsushi Kobayashi fp->mode.ld[2] |= htonl(0x80000000 | 17623c60ba66SKatsushi Kobayashi ((fc->cyctimer(fc) + 0x4000) & 0xf000)); 17633c60ba66SKatsushi Kobayashi } 17643c60ba66SKatsushi Kobayashi stat = OREAD(sc, OHCI_ITCTL(dmach)) & 0x1f; 17653c60ba66SKatsushi Kobayashi switch(stat){ 17663c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 17673c60ba66SKatsushi Kobayashi fw_tbuf_update(fc, dmach, 1); 17683c60ba66SKatsushi Kobayashi break; 17693c60ba66SKatsushi Kobayashi default: 17703c60ba66SKatsushi Kobayashi fw_tbuf_update(fc, dmach, 0); 17713c60ba66SKatsushi Kobayashi break; 17723c60ba66SKatsushi Kobayashi } 17733c60ba66SKatsushi Kobayashi fwohci_itxbuf_enable(&sc->fc, dmach); 17743c60ba66SKatsushi Kobayashi } 1775c572b810SHidetoshi Shimokawa 1776c572b810SHidetoshi Shimokawa static void 1777c572b810SHidetoshi Shimokawa fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) 17783c60ba66SKatsushi Kobayashi { 17793c60ba66SKatsushi Kobayashi int stat; 17803c60ba66SKatsushi Kobayashi stat = OREAD(sc, OHCI_IRCTL(dmach)) & 0x1f; 17813c60ba66SKatsushi Kobayashi switch(stat){ 17823c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 17833c60ba66SKatsushi Kobayashi fw_rbuf_update(&sc->fc, dmach, 1); 17843c60ba66SKatsushi Kobayashi wakeup(sc->fc.ir[dmach]); 17853c60ba66SKatsushi Kobayashi fwohci_irx_enable(&sc->fc, dmach); 17863c60ba66SKatsushi Kobayashi break; 17873c60ba66SKatsushi Kobayashi default: 17883c60ba66SKatsushi Kobayashi break; 17893c60ba66SKatsushi Kobayashi } 17903c60ba66SKatsushi Kobayashi } 1791c572b810SHidetoshi Shimokawa 1792c572b810SHidetoshi Shimokawa void 1793c572b810SHidetoshi Shimokawa dump_dma(struct fwohci_softc *sc, u_int32_t ch) 1794c572b810SHidetoshi Shimokawa { 17953c60ba66SKatsushi Kobayashi u_int32_t off, cntl, stat, cmd, match; 17963c60ba66SKatsushi Kobayashi 17973c60ba66SKatsushi Kobayashi if(ch == 0){ 17983c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 17993c60ba66SKatsushi Kobayashi }else if(ch == 1){ 18003c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 18013c60ba66SKatsushi Kobayashi }else if(ch == 2){ 18023c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 18033c60ba66SKatsushi Kobayashi }else if(ch == 3){ 18043c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 18053c60ba66SKatsushi Kobayashi }else if(ch < IRX_CH){ 18063c60ba66SKatsushi Kobayashi off = OHCI_ITCTL(ch - ITX_CH); 18073c60ba66SKatsushi Kobayashi }else{ 18083c60ba66SKatsushi Kobayashi off = OHCI_IRCTL(ch - IRX_CH); 18093c60ba66SKatsushi Kobayashi } 18103c60ba66SKatsushi Kobayashi cntl = stat = OREAD(sc, off); 18113c60ba66SKatsushi Kobayashi cmd = OREAD(sc, off + 0xc); 18123c60ba66SKatsushi Kobayashi match = OREAD(sc, off + 0x10); 18133c60ba66SKatsushi Kobayashi 18143c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x \n", 18153c60ba66SKatsushi Kobayashi ch, 18163c60ba66SKatsushi Kobayashi cntl, 18173c60ba66SKatsushi Kobayashi stat, 18183c60ba66SKatsushi Kobayashi cmd, 18193c60ba66SKatsushi Kobayashi match); 18203c60ba66SKatsushi Kobayashi stat &= 0xffff ; 18213c60ba66SKatsushi Kobayashi if(stat & 0xff00){ 18223c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", 18233c60ba66SKatsushi Kobayashi ch, 18243c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 18253c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 18263c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 18273c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 18283c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 18293c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 18303c60ba66SKatsushi Kobayashi fwohcicode[stat & 0x1f], 18313c60ba66SKatsushi Kobayashi stat & 0x1f 18323c60ba66SKatsushi Kobayashi ); 18333c60ba66SKatsushi Kobayashi }else{ 18343c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); 18353c60ba66SKatsushi Kobayashi } 18363c60ba66SKatsushi Kobayashi } 1837c572b810SHidetoshi Shimokawa 1838c572b810SHidetoshi Shimokawa void 1839c572b810SHidetoshi Shimokawa dump_db(struct fwohci_softc *sc, u_int32_t ch) 1840c572b810SHidetoshi Shimokawa { 18413c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 18423c60ba66SKatsushi Kobayashi struct fwohcidb_tr *cp = NULL, *pp, *np; 18433c60ba66SKatsushi Kobayashi volatile struct fwohcidb *curr = NULL, *prev, *next = NULL; 18443c60ba66SKatsushi Kobayashi int idb, jdb; 18453c60ba66SKatsushi Kobayashi u_int32_t cmd, off; 18463c60ba66SKatsushi Kobayashi if(ch == 0){ 18473c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 18483c60ba66SKatsushi Kobayashi dbch = &sc->atrq; 18493c60ba66SKatsushi Kobayashi }else if(ch == 1){ 18503c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 18513c60ba66SKatsushi Kobayashi dbch = &sc->atrs; 18523c60ba66SKatsushi Kobayashi }else if(ch == 2){ 18533c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 18543c60ba66SKatsushi Kobayashi dbch = &sc->arrq; 18553c60ba66SKatsushi Kobayashi }else if(ch == 3){ 18563c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 18573c60ba66SKatsushi Kobayashi dbch = &sc->arrs; 18583c60ba66SKatsushi Kobayashi }else if(ch < IRX_CH){ 18593c60ba66SKatsushi Kobayashi off = OHCI_ITCTL(ch - ITX_CH); 18603c60ba66SKatsushi Kobayashi dbch = &sc->it[ch - ITX_CH]; 18613c60ba66SKatsushi Kobayashi }else { 18623c60ba66SKatsushi Kobayashi off = OHCI_IRCTL(ch - IRX_CH); 18633c60ba66SKatsushi Kobayashi dbch = &sc->ir[ch - IRX_CH]; 18643c60ba66SKatsushi Kobayashi } 18653c60ba66SKatsushi Kobayashi cmd = OREAD(sc, off + 0xc); 18663c60ba66SKatsushi Kobayashi 18673c60ba66SKatsushi Kobayashi if( dbch->ndb == 0 ){ 18683c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); 18693c60ba66SKatsushi Kobayashi return; 18703c60ba66SKatsushi Kobayashi } 18713c60ba66SKatsushi Kobayashi pp = dbch->top; 18723c60ba66SKatsushi Kobayashi prev = pp->db; 18733c60ba66SKatsushi Kobayashi for(idb = 0 ; idb < dbch->ndb ; idb ++ ){ 18743c60ba66SKatsushi Kobayashi if(pp == NULL){ 18753c60ba66SKatsushi Kobayashi curr = NULL; 18763c60ba66SKatsushi Kobayashi goto outdb; 18773c60ba66SKatsushi Kobayashi } 18783c60ba66SKatsushi Kobayashi cp = STAILQ_NEXT(pp, link); 18793c60ba66SKatsushi Kobayashi if(cp == NULL){ 18803c60ba66SKatsushi Kobayashi curr = NULL; 18813c60ba66SKatsushi Kobayashi goto outdb; 18823c60ba66SKatsushi Kobayashi } 18833c60ba66SKatsushi Kobayashi np = STAILQ_NEXT(cp, link); 18843c60ba66SKatsushi Kobayashi if(cp == NULL) break; 18853c60ba66SKatsushi Kobayashi for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){ 18863c60ba66SKatsushi Kobayashi if((cmd & 0xfffffff0) 18873c60ba66SKatsushi Kobayashi == vtophys(&(cp->db[jdb]))){ 18883c60ba66SKatsushi Kobayashi curr = cp->db; 18893c60ba66SKatsushi Kobayashi if(np != NULL){ 18903c60ba66SKatsushi Kobayashi next = np->db; 18913c60ba66SKatsushi Kobayashi }else{ 18923c60ba66SKatsushi Kobayashi next = NULL; 18933c60ba66SKatsushi Kobayashi } 18943c60ba66SKatsushi Kobayashi goto outdb; 18953c60ba66SKatsushi Kobayashi } 18963c60ba66SKatsushi Kobayashi } 18973c60ba66SKatsushi Kobayashi pp = STAILQ_NEXT(pp, link); 18983c60ba66SKatsushi Kobayashi prev = pp->db; 18993c60ba66SKatsushi Kobayashi } 19003c60ba66SKatsushi Kobayashi outdb: 19013c60ba66SKatsushi Kobayashi if( curr != NULL){ 19023c60ba66SKatsushi Kobayashi printf("Prev DB %d\n", ch); 19033c60ba66SKatsushi Kobayashi print_db(prev, ch, dbch->ndesc); 19043c60ba66SKatsushi Kobayashi printf("Current DB %d\n", ch); 19053c60ba66SKatsushi Kobayashi print_db(curr, ch, dbch->ndesc); 19063c60ba66SKatsushi Kobayashi printf("Next DB %d\n", ch); 19073c60ba66SKatsushi Kobayashi print_db(next, ch, dbch->ndesc); 19083c60ba66SKatsushi Kobayashi }else{ 19093c60ba66SKatsushi Kobayashi printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); 19103c60ba66SKatsushi Kobayashi } 19113c60ba66SKatsushi Kobayashi return; 19123c60ba66SKatsushi Kobayashi } 1913c572b810SHidetoshi Shimokawa 1914c572b810SHidetoshi Shimokawa void 1915c572b810SHidetoshi Shimokawa print_db(volatile struct fwohcidb *db, u_int32_t ch, u_int32_t max) 1916c572b810SHidetoshi Shimokawa { 19173c60ba66SKatsushi Kobayashi fwohcireg_t stat; 19183c60ba66SKatsushi Kobayashi int i, key; 19193c60ba66SKatsushi Kobayashi 19203c60ba66SKatsushi Kobayashi if(db == NULL){ 19213c60ba66SKatsushi Kobayashi printf("No Descriptor is found\n"); 19223c60ba66SKatsushi Kobayashi return; 19233c60ba66SKatsushi Kobayashi } 19243c60ba66SKatsushi Kobayashi 19253c60ba66SKatsushi Kobayashi printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", 19263c60ba66SKatsushi Kobayashi ch, 19273c60ba66SKatsushi Kobayashi "Current", 19283c60ba66SKatsushi Kobayashi "OP ", 19293c60ba66SKatsushi Kobayashi "KEY", 19303c60ba66SKatsushi Kobayashi "INT", 19313c60ba66SKatsushi Kobayashi "BR ", 19323c60ba66SKatsushi Kobayashi "len", 19333c60ba66SKatsushi Kobayashi "Addr", 19343c60ba66SKatsushi Kobayashi "Depend", 19353c60ba66SKatsushi Kobayashi "Stat", 19363c60ba66SKatsushi Kobayashi "Cnt"); 19373c60ba66SKatsushi Kobayashi for( i = 0 ; i <= max ; i ++){ 19383c60ba66SKatsushi Kobayashi key = db[i].db.desc.cmd & OHCI_KEY_MASK; 193970ce30b5SHidetoshi Shimokawa printf("%08tx %s %s %s %s %5d %08x %08x %04x:%04x", 19403c60ba66SKatsushi Kobayashi vtophys(&db[i]), 19413c60ba66SKatsushi Kobayashi dbcode[(db[i].db.desc.cmd >> 28) & 0xf], 19423c60ba66SKatsushi Kobayashi dbkey[(db[i].db.desc.cmd >> 24) & 0x7], 19433c60ba66SKatsushi Kobayashi dbcond[(db[i].db.desc.cmd >> 20) & 0x3], 19443c60ba66SKatsushi Kobayashi dbcond[(db[i].db.desc.cmd >> 18) & 0x3], 19453c60ba66SKatsushi Kobayashi db[i].db.desc.cmd & 0xffff, 19463c60ba66SKatsushi Kobayashi db[i].db.desc.addr, 19473c60ba66SKatsushi Kobayashi db[i].db.desc.depend, 19483c60ba66SKatsushi Kobayashi db[i].db.desc.status, 19493c60ba66SKatsushi Kobayashi db[i].db.desc.count); 19503c60ba66SKatsushi Kobayashi stat = db[i].db.desc.status; 19513c60ba66SKatsushi Kobayashi if(stat & 0xff00){ 19523c60ba66SKatsushi Kobayashi printf(" %s%s%s%s%s%s %s(%x)\n", 19533c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 19543c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 19553c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 19563c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 19573c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 19583c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 19593c60ba66SKatsushi Kobayashi fwohcicode[stat & 0x1f], 19603c60ba66SKatsushi Kobayashi stat & 0x1f 19613c60ba66SKatsushi Kobayashi ); 19623c60ba66SKatsushi Kobayashi }else{ 19633c60ba66SKatsushi Kobayashi printf(" Nostat\n"); 19643c60ba66SKatsushi Kobayashi } 19653c60ba66SKatsushi Kobayashi if(key == OHCI_KEY_ST2 ){ 19663c60ba66SKatsushi Kobayashi printf("0x%08x 0x%08x 0x%08x 0x%08x\n", 19673c60ba66SKatsushi Kobayashi db[i+1].db.immed[0], 19683c60ba66SKatsushi Kobayashi db[i+1].db.immed[1], 19693c60ba66SKatsushi Kobayashi db[i+1].db.immed[2], 19703c60ba66SKatsushi Kobayashi db[i+1].db.immed[3]); 19713c60ba66SKatsushi Kobayashi } 19723c60ba66SKatsushi Kobayashi if(key == OHCI_KEY_DEVICE){ 19733c60ba66SKatsushi Kobayashi return; 19743c60ba66SKatsushi Kobayashi } 19753c60ba66SKatsushi Kobayashi if((db[i].db.desc.cmd & OHCI_BRANCH_MASK) 19763c60ba66SKatsushi Kobayashi == OHCI_BRANCH_ALWAYS){ 19773c60ba66SKatsushi Kobayashi return; 19783c60ba66SKatsushi Kobayashi } 19793c60ba66SKatsushi Kobayashi if((db[i].db.desc.cmd & OHCI_CMD_MASK) 19803c60ba66SKatsushi Kobayashi == OHCI_OUTPUT_LAST){ 19813c60ba66SKatsushi Kobayashi return; 19823c60ba66SKatsushi Kobayashi } 19833c60ba66SKatsushi Kobayashi if((db[i].db.desc.cmd & OHCI_CMD_MASK) 19843c60ba66SKatsushi Kobayashi == OHCI_INPUT_LAST){ 19853c60ba66SKatsushi Kobayashi return; 19863c60ba66SKatsushi Kobayashi } 19873c60ba66SKatsushi Kobayashi if(key == OHCI_KEY_ST2 ){ 19883c60ba66SKatsushi Kobayashi i++; 19893c60ba66SKatsushi Kobayashi } 19903c60ba66SKatsushi Kobayashi } 19913c60ba66SKatsushi Kobayashi return; 19923c60ba66SKatsushi Kobayashi } 1993c572b810SHidetoshi Shimokawa 1994c572b810SHidetoshi Shimokawa void 1995c572b810SHidetoshi Shimokawa fwohci_ibr(struct firewire_comm *fc) 19963c60ba66SKatsushi Kobayashi { 19973c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 19983c60ba66SKatsushi Kobayashi u_int32_t fun; 19993c60ba66SKatsushi Kobayashi 20003c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)fc; 20013c60ba66SKatsushi Kobayashi #if 1 20023c60ba66SKatsushi Kobayashi fun = fwphy_rddata(sc, FW_PHY_IBR_REG); 20033c60ba66SKatsushi Kobayashi fun |= FW_PHY_IBR; 20043c60ba66SKatsushi Kobayashi fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); 20053c60ba66SKatsushi Kobayashi #else 20063c60ba66SKatsushi Kobayashi fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); 20073c60ba66SKatsushi Kobayashi fun |= FW_PHY_ISBR; 20083c60ba66SKatsushi Kobayashi fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); 20093c60ba66SKatsushi Kobayashi #endif 20103c60ba66SKatsushi Kobayashi } 2011c572b810SHidetoshi Shimokawa 2012c572b810SHidetoshi Shimokawa void 2013c572b810SHidetoshi Shimokawa fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 20143c60ba66SKatsushi Kobayashi { 20153c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr, *fdb_tr; 20163c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 20173c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 20183c60ba66SKatsushi Kobayashi volatile struct fwohci_txpkthdr *ohcifp; 20193c60ba66SKatsushi Kobayashi unsigned short chtag; 20203c60ba66SKatsushi Kobayashi int idb; 20213c60ba66SKatsushi Kobayashi 20223c60ba66SKatsushi Kobayashi dbch = &sc->it[dmach]; 20233c60ba66SKatsushi Kobayashi chtag = sc->it[dmach].xferq.flag & 0xff; 20243c60ba66SKatsushi Kobayashi 20253c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 20263c60ba66SKatsushi Kobayashi fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 20273c60ba66SKatsushi Kobayashi /* 20283c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), vtophys(fdb_tr->db)); 20293c60ba66SKatsushi Kobayashi */ 20303c60ba66SKatsushi Kobayashi if(bulkxfer->flag != 0){ 20313c60ba66SKatsushi Kobayashi return; 20323c60ba66SKatsushi Kobayashi } 20333c60ba66SKatsushi Kobayashi bulkxfer->flag = 1; 20343c60ba66SKatsushi Kobayashi for( idb = 0 ; idb < bulkxfer->npacket ; idb ++){ 20353c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.cmd 20363c60ba66SKatsushi Kobayashi = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8; 20373c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)db_tr->buf; 20383c60ba66SKatsushi Kobayashi ohcifp = (volatile struct fwohci_txpkthdr *) 20393c60ba66SKatsushi Kobayashi db_tr->db[1].db.immed; 20403c60ba66SKatsushi Kobayashi ohcifp->mode.ld[0] = ntohl(fp->mode.ld[0]); 20413c60ba66SKatsushi Kobayashi ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); 20423c60ba66SKatsushi Kobayashi ohcifp->mode.stream.chtag = chtag; 20433c60ba66SKatsushi Kobayashi ohcifp->mode.stream.tcode = 0xa; 20443c60ba66SKatsushi Kobayashi ohcifp->mode.stream.spd = 4; 20453c60ba66SKatsushi Kobayashi ohcifp->mode.ld[2] = ntohl(fp->mode.ld[1]); 20463c60ba66SKatsushi Kobayashi ohcifp->mode.ld[3] = ntohl(fp->mode.ld[2]); 20473c60ba66SKatsushi Kobayashi 20483c60ba66SKatsushi Kobayashi db_tr->db[2].db.desc.cmd 20493c60ba66SKatsushi Kobayashi = OHCI_OUTPUT_LAST 20503c60ba66SKatsushi Kobayashi | OHCI_UPDATE 20513c60ba66SKatsushi Kobayashi | OHCI_BRANCH_ALWAYS 20523c60ba66SKatsushi Kobayashi | ((ntohs(fp->mode.stream.len) ) & 0xffff); 20533c60ba66SKatsushi Kobayashi db_tr->db[2].db.desc.status = 0; 20543c60ba66SKatsushi Kobayashi db_tr->db[2].db.desc.count = 0; 20553c60ba66SKatsushi Kobayashi if(dbch->xferq.flag & FWXFERQ_DV){ 20563c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend 20573c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; 20583c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.depend 20593c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; 20603c60ba66SKatsushi Kobayashi }else{ 20613c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend 20623c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; 20633c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.depend 20643c60ba66SKatsushi Kobayashi = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; 20653c60ba66SKatsushi Kobayashi } 20663c60ba66SKatsushi Kobayashi bulkxfer->end = (caddr_t)db_tr; 20673c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 20683c60ba66SKatsushi Kobayashi } 20693c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)bulkxfer->end; 20703c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend &= ~0xf; 20713c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.depend &= ~0xf; 20723c60ba66SKatsushi Kobayashi /**/ 20733c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.cmd &= ~OHCI_BRANCH_ALWAYS; 20743c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.cmd |= OHCI_BRANCH_NEVER; 20753c60ba66SKatsushi Kobayashi /**/ 20763c60ba66SKatsushi Kobayashi db_tr->db[dbch->ndesc - 1].db.desc.cmd |= OHCI_INTERRUPT_ALWAYS; 20773c60ba66SKatsushi Kobayashi 20783c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)bulkxfer->start; 20793c60ba66SKatsushi Kobayashi fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; 20803c60ba66SKatsushi Kobayashi /* 20813c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, vtophys(db_tr->db), vtophys(fdb_tr->db)); 20823c60ba66SKatsushi Kobayashi */ 20833c60ba66SKatsushi Kobayashi return; 20843c60ba66SKatsushi Kobayashi } 2085c572b810SHidetoshi Shimokawa 2086c572b810SHidetoshi Shimokawa static int 2087c572b810SHidetoshi Shimokawa fwohci_add_tx_buf(struct fwohcidb_tr *db_tr, unsigned short size, 2088c572b810SHidetoshi Shimokawa int mode, void *buf) 20893c60ba66SKatsushi Kobayashi { 20903c60ba66SKatsushi Kobayashi volatile struct fwohcidb *db = db_tr->db; 20913c60ba66SKatsushi Kobayashi int err = 0; 20923c60ba66SKatsushi Kobayashi if(buf == 0){ 20933c60ba66SKatsushi Kobayashi err = EINVAL; 20943c60ba66SKatsushi Kobayashi return err; 20953c60ba66SKatsushi Kobayashi } 20963c60ba66SKatsushi Kobayashi db_tr->buf = buf; 20973c60ba66SKatsushi Kobayashi db_tr->dbcnt = 3; 20983c60ba66SKatsushi Kobayashi db_tr->dummy = NULL; 20993c60ba66SKatsushi Kobayashi 21003c60ba66SKatsushi Kobayashi db[0].db.desc.cmd = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8; 21013c60ba66SKatsushi Kobayashi 21023c60ba66SKatsushi Kobayashi db[2].db.desc.depend = 0; 21033c60ba66SKatsushi Kobayashi db[2].db.desc.addr = vtophys(buf) + sizeof(u_int32_t); 21043c60ba66SKatsushi Kobayashi db[2].db.desc.cmd = OHCI_OUTPUT_MORE; 21053c60ba66SKatsushi Kobayashi 21063c60ba66SKatsushi Kobayashi db[0].db.desc.status = 0; 21073c60ba66SKatsushi Kobayashi db[0].db.desc.count = 0; 21083c60ba66SKatsushi Kobayashi 21093c60ba66SKatsushi Kobayashi db[2].db.desc.status = 0; 21103c60ba66SKatsushi Kobayashi db[2].db.desc.count = 0; 21113c60ba66SKatsushi Kobayashi if( mode & FWXFERQ_STREAM ){ 21123c60ba66SKatsushi Kobayashi db[2].db.desc.cmd |= OHCI_OUTPUT_LAST; 21133c60ba66SKatsushi Kobayashi if(mode & FWXFERQ_PACKET ){ 21143c60ba66SKatsushi Kobayashi db[2].db.desc.cmd 21153c60ba66SKatsushi Kobayashi |= OHCI_INTERRUPT_ALWAYS; 21163c60ba66SKatsushi Kobayashi } 21173c60ba66SKatsushi Kobayashi } 21183c60ba66SKatsushi Kobayashi db[2].db.desc.cmd |= OHCI_BRANCH_ALWAYS; 21193c60ba66SKatsushi Kobayashi return 1; 21203c60ba66SKatsushi Kobayashi } 2121c572b810SHidetoshi Shimokawa 2122c572b810SHidetoshi Shimokawa int 2123c572b810SHidetoshi Shimokawa fwohci_add_rx_buf(struct fwohcidb_tr *db_tr, unsigned short size, int mode, 2124c572b810SHidetoshi Shimokawa void *buf, void *dummy) 21253c60ba66SKatsushi Kobayashi { 21263c60ba66SKatsushi Kobayashi volatile struct fwohcidb *db = db_tr->db; 21273c60ba66SKatsushi Kobayashi int i; 21283c60ba66SKatsushi Kobayashi void *dbuf[2]; 21293c60ba66SKatsushi Kobayashi int dsiz[2]; 21303c60ba66SKatsushi Kobayashi 21313c60ba66SKatsushi Kobayashi if(buf == 0){ 21323c60ba66SKatsushi Kobayashi buf = malloc(size, M_DEVBUF, M_NOWAIT); 21333c60ba66SKatsushi Kobayashi if(buf == NULL) return 0; 21343c60ba66SKatsushi Kobayashi db_tr->buf = buf; 21353c60ba66SKatsushi Kobayashi db_tr->dbcnt = 1; 21363c60ba66SKatsushi Kobayashi db_tr->dummy = NULL; 21373c60ba66SKatsushi Kobayashi dsiz[0] = size; 21383c60ba66SKatsushi Kobayashi dbuf[0] = buf; 21393c60ba66SKatsushi Kobayashi }else if(dummy == NULL){ 21403c60ba66SKatsushi Kobayashi db_tr->buf = buf; 21413c60ba66SKatsushi Kobayashi db_tr->dbcnt = 1; 21423c60ba66SKatsushi Kobayashi db_tr->dummy = NULL; 21433c60ba66SKatsushi Kobayashi dsiz[0] = size; 21443c60ba66SKatsushi Kobayashi dbuf[0] = buf; 21453c60ba66SKatsushi Kobayashi }else{ 21463c60ba66SKatsushi Kobayashi db_tr->buf = buf; 21473c60ba66SKatsushi Kobayashi db_tr->dbcnt = 2; 21483c60ba66SKatsushi Kobayashi db_tr->dummy = dummy; 21493c60ba66SKatsushi Kobayashi dsiz[0] = sizeof(u_int32_t); 21503c60ba66SKatsushi Kobayashi dsiz[1] = size; 21513c60ba66SKatsushi Kobayashi dbuf[0] = dummy; 21523c60ba66SKatsushi Kobayashi dbuf[1] = buf; 21533c60ba66SKatsushi Kobayashi } 21543c60ba66SKatsushi Kobayashi for(i = 0 ; i < db_tr->dbcnt ; i++){ 21553c60ba66SKatsushi Kobayashi db[i].db.desc.addr = vtophys(dbuf[i]) ; 21563c60ba66SKatsushi Kobayashi db[i].db.desc.cmd = OHCI_INPUT_MORE | dsiz[i]; 21573c60ba66SKatsushi Kobayashi if( mode & FWXFERQ_STREAM ){ 21583c60ba66SKatsushi Kobayashi db[i].db.desc.cmd |= OHCI_UPDATE; 21593c60ba66SKatsushi Kobayashi } 21603c60ba66SKatsushi Kobayashi db[i].db.desc.status = 0; 21613c60ba66SKatsushi Kobayashi db[i].db.desc.count = dsiz[i]; 21623c60ba66SKatsushi Kobayashi } 21633c60ba66SKatsushi Kobayashi if( mode & FWXFERQ_STREAM ){ 21643c60ba66SKatsushi Kobayashi db[db_tr->dbcnt - 1].db.desc.cmd |= OHCI_INPUT_LAST; 21653c60ba66SKatsushi Kobayashi if(mode & FWXFERQ_PACKET ){ 21663c60ba66SKatsushi Kobayashi db[db_tr->dbcnt - 1].db.desc.cmd 21673c60ba66SKatsushi Kobayashi |= OHCI_INTERRUPT_ALWAYS; 21683c60ba66SKatsushi Kobayashi } 21693c60ba66SKatsushi Kobayashi } 21703c60ba66SKatsushi Kobayashi db[db_tr->dbcnt - 1].db.desc.cmd |= OHCI_BRANCH_ALWAYS; 21713c60ba66SKatsushi Kobayashi return 1; 21723c60ba66SKatsushi Kobayashi } 2173c572b810SHidetoshi Shimokawa 2174c572b810SHidetoshi Shimokawa static void 2175c572b810SHidetoshi Shimokawa fwohci_ircv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 21763c60ba66SKatsushi Kobayashi { 21773c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr = dbch->top, *odb_tr; 21783c60ba66SKatsushi Kobayashi struct firewire_comm *fc = (struct firewire_comm *)sc; 21793c60ba66SKatsushi Kobayashi int z = 1; 21803c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 21813c60ba66SKatsushi Kobayashi u_int8_t *ld; 21823c60ba66SKatsushi Kobayashi u_int32_t off = NULL; 21833c60ba66SKatsushi Kobayashi u_int32_t stat; 21843c60ba66SKatsushi Kobayashi u_int32_t *qld; 21853c60ba66SKatsushi Kobayashi u_int32_t reg; 21863c60ba66SKatsushi Kobayashi u_int spd; 21873c60ba66SKatsushi Kobayashi u_int dmach; 21883c60ba66SKatsushi Kobayashi int len, i, plen; 21893c60ba66SKatsushi Kobayashi caddr_t buf; 21903c60ba66SKatsushi Kobayashi 21913c60ba66SKatsushi Kobayashi for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 21923c60ba66SKatsushi Kobayashi if( &sc->ir[dmach] == dbch){ 21933c60ba66SKatsushi Kobayashi off = OHCI_IROFF(dmach); 21943c60ba66SKatsushi Kobayashi break; 21953c60ba66SKatsushi Kobayashi } 21963c60ba66SKatsushi Kobayashi } 21973c60ba66SKatsushi Kobayashi if(off == NULL){ 21983c60ba66SKatsushi Kobayashi return; 21993c60ba66SKatsushi Kobayashi } 22003c60ba66SKatsushi Kobayashi if(!(dbch->xferq.flag & FWXFERQ_RUNNING)){ 22013c60ba66SKatsushi Kobayashi fwohci_irx_disable(&sc->fc, dmach); 22023c60ba66SKatsushi Kobayashi return; 22033c60ba66SKatsushi Kobayashi } 22043c60ba66SKatsushi Kobayashi 22053c60ba66SKatsushi Kobayashi odb_tr = NULL; 22063c60ba66SKatsushi Kobayashi db_tr = dbch->top; 22073c60ba66SKatsushi Kobayashi i = 0; 22083c60ba66SKatsushi Kobayashi while ((reg = db_tr->db[0].db.desc.status) & 0x1f) { 2209783058faSHidetoshi Shimokawa if (count >= 0 && count-- == 0) 2210783058faSHidetoshi Shimokawa break; 22113c60ba66SKatsushi Kobayashi ld = (u_int8_t *)db_tr->buf; 22123c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_PACKET) { 22133c60ba66SKatsushi Kobayashi /* skip timeStamp */ 22143c60ba66SKatsushi Kobayashi ld += sizeof(struct fwohci_trailer); 22153c60ba66SKatsushi Kobayashi } 22163c60ba66SKatsushi Kobayashi qld = (u_int32_t *)ld; 22173c60ba66SKatsushi Kobayashi len = dbch->xferq.psize - (db_tr->db[0].db.desc.count); 22183c60ba66SKatsushi Kobayashi /* 22193c60ba66SKatsushi Kobayashi { 22203c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "%04x %2x 0x%08x 0x%08x 0x%08x 0x%08x\n", len, 22213c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.status & 0x1f, qld[0],qld[1],qld[2],qld[3]); 22223c60ba66SKatsushi Kobayashi } 22233c60ba66SKatsushi Kobayashi */ 22243c60ba66SKatsushi Kobayashi fp=(struct fw_pkt *)ld; 22253c60ba66SKatsushi Kobayashi qld[0] = htonl(qld[0]); 22263c60ba66SKatsushi Kobayashi plen = sizeof(struct fw_isohdr) 22273c60ba66SKatsushi Kobayashi + ntohs(fp->mode.stream.len) + sizeof(u_int32_t); 22283c60ba66SKatsushi Kobayashi ld += plen; 22293c60ba66SKatsushi Kobayashi len -= plen; 22303c60ba66SKatsushi Kobayashi buf = db_tr->buf; 22313c60ba66SKatsushi Kobayashi db_tr->buf = NULL; 22323c60ba66SKatsushi Kobayashi stat = reg & 0x1f; 22333c60ba66SKatsushi Kobayashi spd = reg & 0x3; 22343c60ba66SKatsushi Kobayashi switch(stat){ 22353c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 22363c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKPEND: 22373c60ba66SKatsushi Kobayashi fw_rcv(&sc->fc, buf, plen - sizeof(u_int32_t), dmach, sizeof(u_int32_t), spd); 22383c60ba66SKatsushi Kobayashi break; 22393c60ba66SKatsushi Kobayashi default: 22403c60ba66SKatsushi Kobayashi free(buf, M_DEVBUF); 22413c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "Isochronous receive err %02x\n", stat); 22423c60ba66SKatsushi Kobayashi break; 22433c60ba66SKatsushi Kobayashi } 22443c60ba66SKatsushi Kobayashi i++; 22453c60ba66SKatsushi Kobayashi fwohci_add_rx_buf(db_tr, dbch->xferq.psize, 22463c60ba66SKatsushi Kobayashi dbch->xferq.flag, 0, NULL); 22473c60ba66SKatsushi Kobayashi db_tr->db[0].db.desc.depend &= ~0xf; 22483c60ba66SKatsushi Kobayashi if(dbch->pdb_tr != NULL){ 22493c60ba66SKatsushi Kobayashi dbch->pdb_tr->db[0].db.desc.depend |= z; 22503c60ba66SKatsushi Kobayashi } else { 22513c60ba66SKatsushi Kobayashi /* XXX should be rewritten in better way */ 22523c60ba66SKatsushi Kobayashi dbch->bottom->db[0].db.desc.depend |= z; 22533c60ba66SKatsushi Kobayashi } 22543c60ba66SKatsushi Kobayashi dbch->pdb_tr = db_tr; 22553c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 22563c60ba66SKatsushi Kobayashi } 22573c60ba66SKatsushi Kobayashi dbch->top = db_tr; 22583c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_DMACTL(off)); 22593c60ba66SKatsushi Kobayashi if (reg & OHCI_CNTL_DMA_ACTIVE) 22603c60ba66SKatsushi Kobayashi return; 22613c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "IR DMA %d stopped at %x status=%x (%d)\n", 22623c60ba66SKatsushi Kobayashi dmach, OREAD(sc, OHCI_DMACMD(off)), reg, i); 22633c60ba66SKatsushi Kobayashi dbch->top = db_tr; 22643c60ba66SKatsushi Kobayashi fwohci_irx_enable(fc, dmach); 22653c60ba66SKatsushi Kobayashi } 22663c60ba66SKatsushi Kobayashi 22673c60ba66SKatsushi Kobayashi #define PLEN(x) (((ntohs(x))+0x3) & ~0x3) 22683c60ba66SKatsushi Kobayashi static int 22693c60ba66SKatsushi Kobayashi fwohci_get_plen(struct fwohci_softc *sc, struct fw_pkt *fp, int hlen) 22703c60ba66SKatsushi Kobayashi { 22713c60ba66SKatsushi Kobayashi int i; 22723c60ba66SKatsushi Kobayashi 22733c60ba66SKatsushi Kobayashi for( i = 4; i < hlen ; i+=4){ 22743c60ba66SKatsushi Kobayashi fp->mode.ld[i/4] = htonl(fp->mode.ld[i/4]); 22753c60ba66SKatsushi Kobayashi } 22763c60ba66SKatsushi Kobayashi 22773c60ba66SKatsushi Kobayashi switch(fp->mode.common.tcode){ 22783c60ba66SKatsushi Kobayashi case FWTCODE_RREQQ: 22793c60ba66SKatsushi Kobayashi return sizeof(fp->mode.rreqq) + sizeof(u_int32_t); 22803c60ba66SKatsushi Kobayashi case FWTCODE_WRES: 22813c60ba66SKatsushi Kobayashi return sizeof(fp->mode.wres) + sizeof(u_int32_t); 22823c60ba66SKatsushi Kobayashi case FWTCODE_WREQQ: 22833c60ba66SKatsushi Kobayashi return sizeof(fp->mode.wreqq) + sizeof(u_int32_t); 22843c60ba66SKatsushi Kobayashi case FWTCODE_RREQB: 22853c60ba66SKatsushi Kobayashi return sizeof(fp->mode.rreqb) + sizeof(u_int32_t); 22863c60ba66SKatsushi Kobayashi case FWTCODE_RRESQ: 22873c60ba66SKatsushi Kobayashi return sizeof(fp->mode.rresq) + sizeof(u_int32_t); 22883c60ba66SKatsushi Kobayashi case FWTCODE_WREQB: 22893c60ba66SKatsushi Kobayashi return sizeof(struct fw_asyhdr) + PLEN(fp->mode.wreqb.len) 22903c60ba66SKatsushi Kobayashi + sizeof(u_int32_t); 22913c60ba66SKatsushi Kobayashi case FWTCODE_LREQ: 22923c60ba66SKatsushi Kobayashi return sizeof(struct fw_asyhdr) + PLEN(fp->mode.lreq.len) 22933c60ba66SKatsushi Kobayashi + sizeof(u_int32_t); 22943c60ba66SKatsushi Kobayashi case FWTCODE_RRESB: 22953c60ba66SKatsushi Kobayashi return sizeof(struct fw_asyhdr) + PLEN(fp->mode.rresb.len) 22963c60ba66SKatsushi Kobayashi + sizeof(u_int32_t); 22973c60ba66SKatsushi Kobayashi case FWTCODE_LRES: 22983c60ba66SKatsushi Kobayashi return sizeof(struct fw_asyhdr) + PLEN(fp->mode.lres.len) 22993c60ba66SKatsushi Kobayashi + sizeof(u_int32_t); 23003c60ba66SKatsushi Kobayashi case FWOHCITCODE_PHY: 23013c60ba66SKatsushi Kobayashi return 16; 23023c60ba66SKatsushi Kobayashi } 23033c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "Unknown tcode %d\n", fp->mode.common.tcode); 23043c60ba66SKatsushi Kobayashi return 0; 23053c60ba66SKatsushi Kobayashi } 23063c60ba66SKatsushi Kobayashi 2307c572b810SHidetoshi Shimokawa static void 2308c572b810SHidetoshi Shimokawa fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 23093c60ba66SKatsushi Kobayashi { 23103c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 23113c60ba66SKatsushi Kobayashi int z = 1; 23123c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 23133c60ba66SKatsushi Kobayashi u_int8_t *ld; 23143c60ba66SKatsushi Kobayashi u_int32_t stat, off; 23153c60ba66SKatsushi Kobayashi u_int spd; 23163c60ba66SKatsushi Kobayashi int len, plen, hlen, pcnt, poff = 0, rlen; 23173c60ba66SKatsushi Kobayashi int s; 23183c60ba66SKatsushi Kobayashi caddr_t buf; 23193c60ba66SKatsushi Kobayashi int resCount; 23203c60ba66SKatsushi Kobayashi 23213c60ba66SKatsushi Kobayashi if(&sc->arrq == dbch){ 23223c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 23233c60ba66SKatsushi Kobayashi }else if(&sc->arrs == dbch){ 23243c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 23253c60ba66SKatsushi Kobayashi }else{ 23263c60ba66SKatsushi Kobayashi return; 23273c60ba66SKatsushi Kobayashi } 23283c60ba66SKatsushi Kobayashi 23293c60ba66SKatsushi Kobayashi s = splfw(); 23303c60ba66SKatsushi Kobayashi db_tr = dbch->top; 23313c60ba66SKatsushi Kobayashi pcnt = 0; 23323c60ba66SKatsushi Kobayashi /* XXX we cannot handle a packet which lies in more than two buf */ 23333c60ba66SKatsushi Kobayashi while (db_tr->db[0].db.desc.status & OHCI_CNTL_DMA_ACTIVE) { 23343c60ba66SKatsushi Kobayashi ld = (u_int8_t *)db_tr->buf + dbch->buf_offset; 23353c60ba66SKatsushi Kobayashi resCount = db_tr->db[0].db.desc.count; 23363c60ba66SKatsushi Kobayashi len = dbch->xferq.psize - resCount 23373c60ba66SKatsushi Kobayashi - dbch->buf_offset; 23383c60ba66SKatsushi Kobayashi while (len > 0 ) { 2339783058faSHidetoshi Shimokawa if (count >= 0 && count-- == 0) 2340783058faSHidetoshi Shimokawa goto out; 23413c60ba66SKatsushi Kobayashi if(dbch->frag.buf != NULL){ 23423c60ba66SKatsushi Kobayashi buf = dbch->frag.buf; 23433c60ba66SKatsushi Kobayashi if (dbch->frag.plen < 0) { 23443c60ba66SKatsushi Kobayashi /* incomplete header */ 23453c60ba66SKatsushi Kobayashi int hlen; 23463c60ba66SKatsushi Kobayashi 23473c60ba66SKatsushi Kobayashi hlen = - dbch->frag.plen; 23483c60ba66SKatsushi Kobayashi rlen = hlen - dbch->frag.len; 23493c60ba66SKatsushi Kobayashi bcopy(ld, dbch->frag.buf + dbch->frag.len, rlen); 23503c60ba66SKatsushi Kobayashi ld += rlen; 23513c60ba66SKatsushi Kobayashi len -= rlen; 23523c60ba66SKatsushi Kobayashi dbch->frag.len += rlen; 23533c60ba66SKatsushi Kobayashi #if 0 23543c60ba66SKatsushi Kobayashi printf("(1)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len); 23553c60ba66SKatsushi Kobayashi #endif 23563c60ba66SKatsushi Kobayashi fp=(struct fw_pkt *)dbch->frag.buf; 23573c60ba66SKatsushi Kobayashi dbch->frag.plen 23583c60ba66SKatsushi Kobayashi = fwohci_get_plen(sc, fp, hlen); 23593c60ba66SKatsushi Kobayashi if (dbch->frag.plen == 0) 23603c60ba66SKatsushi Kobayashi goto out; 23613c60ba66SKatsushi Kobayashi } 23623c60ba66SKatsushi Kobayashi rlen = dbch->frag.plen - dbch->frag.len; 23633c60ba66SKatsushi Kobayashi #if 0 23643c60ba66SKatsushi Kobayashi printf("(2)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len); 23653c60ba66SKatsushi Kobayashi #endif 23663c60ba66SKatsushi Kobayashi bcopy(ld, dbch->frag.buf + dbch->frag.len, 23673c60ba66SKatsushi Kobayashi rlen); 23683c60ba66SKatsushi Kobayashi ld += rlen; 23693c60ba66SKatsushi Kobayashi len -= rlen; 23703c60ba66SKatsushi Kobayashi plen = dbch->frag.plen; 23713c60ba66SKatsushi Kobayashi dbch->frag.buf = NULL; 23723c60ba66SKatsushi Kobayashi dbch->frag.plen = 0; 23733c60ba66SKatsushi Kobayashi dbch->frag.len = 0; 23743c60ba66SKatsushi Kobayashi poff = 0; 23753c60ba66SKatsushi Kobayashi }else{ 23763c60ba66SKatsushi Kobayashi fp=(struct fw_pkt *)ld; 23773c60ba66SKatsushi Kobayashi fp->mode.ld[0] = htonl(fp->mode.ld[0]); 23783c60ba66SKatsushi Kobayashi switch(fp->mode.common.tcode){ 23793c60ba66SKatsushi Kobayashi case FWTCODE_RREQQ: 23803c60ba66SKatsushi Kobayashi case FWTCODE_WRES: 23813c60ba66SKatsushi Kobayashi case FWTCODE_WREQQ: 23823c60ba66SKatsushi Kobayashi case FWTCODE_RRESQ: 23833c60ba66SKatsushi Kobayashi case FWOHCITCODE_PHY: 23843c60ba66SKatsushi Kobayashi hlen = 12; 23853c60ba66SKatsushi Kobayashi break; 23863c60ba66SKatsushi Kobayashi case FWTCODE_RREQB: 23873c60ba66SKatsushi Kobayashi case FWTCODE_WREQB: 23883c60ba66SKatsushi Kobayashi case FWTCODE_LREQ: 23893c60ba66SKatsushi Kobayashi case FWTCODE_RRESB: 23903c60ba66SKatsushi Kobayashi case FWTCODE_LRES: 23913c60ba66SKatsushi Kobayashi hlen = 16; 23923c60ba66SKatsushi Kobayashi break; 23933c60ba66SKatsushi Kobayashi default: 23943c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "Unknown tcode %d\n", fp->mode.common.tcode); 23953c60ba66SKatsushi Kobayashi goto out; 23963c60ba66SKatsushi Kobayashi } 23973c60ba66SKatsushi Kobayashi if (len >= hlen) { 23983c60ba66SKatsushi Kobayashi plen = fwohci_get_plen(sc, fp, hlen); 23993c60ba66SKatsushi Kobayashi if (plen == 0) 24003c60ba66SKatsushi Kobayashi goto out; 24013c60ba66SKatsushi Kobayashi plen = (plen + 3) & ~3; 24023c60ba66SKatsushi Kobayashi len -= plen; 24033c60ba66SKatsushi Kobayashi } else { 24043c60ba66SKatsushi Kobayashi plen = -hlen; 24053c60ba66SKatsushi Kobayashi len -= hlen; 24063c60ba66SKatsushi Kobayashi } 24073c60ba66SKatsushi Kobayashi if(resCount > 0 || len > 0){ 24083c60ba66SKatsushi Kobayashi buf = malloc( dbch->xferq.psize, 24093c60ba66SKatsushi Kobayashi M_DEVBUF, M_NOWAIT); 24103c60ba66SKatsushi Kobayashi if(buf == NULL){ 24113c60ba66SKatsushi Kobayashi printf("cannot malloc!\n"); 24123c60ba66SKatsushi Kobayashi free(db_tr->buf, M_DEVBUF); 24133c60ba66SKatsushi Kobayashi goto out; 24143c60ba66SKatsushi Kobayashi } 24153c60ba66SKatsushi Kobayashi bcopy(ld, buf, plen); 24163c60ba66SKatsushi Kobayashi poff = 0; 24173c60ba66SKatsushi Kobayashi dbch->frag.buf = NULL; 24183c60ba66SKatsushi Kobayashi dbch->frag.plen = 0; 24193c60ba66SKatsushi Kobayashi dbch->frag.len = 0; 24203c60ba66SKatsushi Kobayashi }else if(len < 0){ 24213c60ba66SKatsushi Kobayashi dbch->frag.buf = db_tr->buf; 24223c60ba66SKatsushi Kobayashi if (plen < 0) { 24233c60ba66SKatsushi Kobayashi #if 0 24243c60ba66SKatsushi Kobayashi printf("plen < 0:" 24253c60ba66SKatsushi Kobayashi "hlen: %d len: %d\n", 24263c60ba66SKatsushi Kobayashi hlen, len); 24273c60ba66SKatsushi Kobayashi #endif 24283c60ba66SKatsushi Kobayashi dbch->frag.len = hlen + len; 24293c60ba66SKatsushi Kobayashi dbch->frag.plen = -hlen; 24303c60ba66SKatsushi Kobayashi } else { 24313c60ba66SKatsushi Kobayashi dbch->frag.len = plen + len; 24323c60ba66SKatsushi Kobayashi dbch->frag.plen = plen; 24333c60ba66SKatsushi Kobayashi } 24343c60ba66SKatsushi Kobayashi bcopy(ld, db_tr->buf, dbch->frag.len); 24353c60ba66SKatsushi Kobayashi buf = NULL; 24363c60ba66SKatsushi Kobayashi }else{ 24373c60ba66SKatsushi Kobayashi buf = db_tr->buf; 24383c60ba66SKatsushi Kobayashi poff = ld - (u_int8_t *)buf; 24393c60ba66SKatsushi Kobayashi dbch->frag.buf = NULL; 24403c60ba66SKatsushi Kobayashi dbch->frag.plen = 0; 24413c60ba66SKatsushi Kobayashi dbch->frag.len = 0; 24423c60ba66SKatsushi Kobayashi } 24433c60ba66SKatsushi Kobayashi ld += plen; 24443c60ba66SKatsushi Kobayashi } 24453c60ba66SKatsushi Kobayashi if( buf != NULL){ 24463c60ba66SKatsushi Kobayashi /* DMA result-code will be written at the tail of packet */ 24473c60ba66SKatsushi Kobayashi stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat; 24483c60ba66SKatsushi Kobayashi spd = (stat >> 5) & 0x3; 24493c60ba66SKatsushi Kobayashi stat &= 0x1f; 24503c60ba66SKatsushi Kobayashi switch(stat){ 24513c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKPEND: 24523c60ba66SKatsushi Kobayashi #if 0 24533c60ba66SKatsushi Kobayashi printf("fwohci_arcv: ack pending..\n"); 24543c60ba66SKatsushi Kobayashi #endif 24553c60ba66SKatsushi Kobayashi /* fall through */ 24563c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 24573c60ba66SKatsushi Kobayashi if( poff != 0 ) 24583c60ba66SKatsushi Kobayashi bcopy(buf+poff, buf, plen - 4); 24593c60ba66SKatsushi Kobayashi fw_rcv(&sc->fc, buf, plen - sizeof(struct fwohci_trailer), 0, 0, spd); 24603c60ba66SKatsushi Kobayashi break; 24613c60ba66SKatsushi Kobayashi case FWOHCIEV_BUSRST: 24623c60ba66SKatsushi Kobayashi free(buf, M_DEVBUF); 24633c60ba66SKatsushi Kobayashi if (sc->fc.status != FWBUSRESET) 24643c60ba66SKatsushi Kobayashi printf("got BUSRST packet!?\n"); 24653c60ba66SKatsushi Kobayashi break; 24663c60ba66SKatsushi Kobayashi default: 24673c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]); 24683c60ba66SKatsushi Kobayashi #if 0 /* XXX */ 24693c60ba66SKatsushi Kobayashi goto out; 24703c60ba66SKatsushi Kobayashi #endif 24713c60ba66SKatsushi Kobayashi break; 24723c60ba66SKatsushi Kobayashi } 24733c60ba66SKatsushi Kobayashi } 24743c60ba66SKatsushi Kobayashi pcnt ++; 24753c60ba66SKatsushi Kobayashi }; 24763c60ba66SKatsushi Kobayashi out: 24773c60ba66SKatsushi Kobayashi if (resCount == 0) { 24783c60ba66SKatsushi Kobayashi /* done on this buffer */ 24793c60ba66SKatsushi Kobayashi fwohci_add_rx_buf(db_tr, dbch->xferq.psize, 24803c60ba66SKatsushi Kobayashi dbch->xferq.flag, 0, NULL); 24813c60ba66SKatsushi Kobayashi dbch->bottom->db[0].db.desc.depend |= z; 24823c60ba66SKatsushi Kobayashi dbch->bottom = db_tr; 24833c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 24843c60ba66SKatsushi Kobayashi dbch->top = db_tr; 24853c60ba66SKatsushi Kobayashi dbch->buf_offset = 0; 24863c60ba66SKatsushi Kobayashi } else { 24873c60ba66SKatsushi Kobayashi dbch->buf_offset = dbch->xferq.psize - resCount; 24883c60ba66SKatsushi Kobayashi break; 24893c60ba66SKatsushi Kobayashi } 24903c60ba66SKatsushi Kobayashi /* XXX make sure DMA is not dead */ 24913c60ba66SKatsushi Kobayashi } 24923c60ba66SKatsushi Kobayashi #if 0 24933c60ba66SKatsushi Kobayashi if (pcnt < 1) 24943c60ba66SKatsushi Kobayashi printf("fwohci_arcv: no packets\n"); 24953c60ba66SKatsushi Kobayashi #endif 24963c60ba66SKatsushi Kobayashi splx(s); 24973c60ba66SKatsushi Kobayashi } 2498