1098ca2bdSWarner Losh /*- 277ee030bSHidetoshi Shimokawa * Copyright (c) 2003 Hidetoshi Shimokawa 33c60ba66SKatsushi Kobayashi * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 43c60ba66SKatsushi Kobayashi * All rights reserved. 53c60ba66SKatsushi Kobayashi * 63c60ba66SKatsushi Kobayashi * Redistribution and use in source and binary forms, with or without 73c60ba66SKatsushi Kobayashi * modification, are permitted provided that the following conditions 83c60ba66SKatsushi Kobayashi * are met: 93c60ba66SKatsushi Kobayashi * 1. Redistributions of source code must retain the above copyright 103c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer. 113c60ba66SKatsushi Kobayashi * 2. Redistributions in binary form must reproduce the above copyright 123c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer in the 133c60ba66SKatsushi Kobayashi * documentation and/or other materials provided with the distribution. 143c60ba66SKatsushi Kobayashi * 3. All advertising materials mentioning features or use of this software 153c60ba66SKatsushi Kobayashi * must display the acknowledgement as bellow: 163c60ba66SKatsushi Kobayashi * 178da326fdSHidetoshi Shimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 183c60ba66SKatsushi Kobayashi * 193c60ba66SKatsushi Kobayashi * 4. The name of the author may not be used to endorse or promote products 203c60ba66SKatsushi Kobayashi * derived from this software without specific prior written permission. 213c60ba66SKatsushi Kobayashi * 223c60ba66SKatsushi Kobayashi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 233c60ba66SKatsushi Kobayashi * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 243c60ba66SKatsushi Kobayashi * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 253c60ba66SKatsushi Kobayashi * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 263c60ba66SKatsushi Kobayashi * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 273c60ba66SKatsushi Kobayashi * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 283c60ba66SKatsushi Kobayashi * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 293c60ba66SKatsushi Kobayashi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 303c60ba66SKatsushi Kobayashi * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 313c60ba66SKatsushi Kobayashi * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 323c60ba66SKatsushi Kobayashi * POSSIBILITY OF SUCH DAMAGE. 333c60ba66SKatsushi Kobayashi * 343c60ba66SKatsushi Kobayashi * $FreeBSD$ 353c60ba66SKatsushi Kobayashi * 363c60ba66SKatsushi Kobayashi */ 378da326fdSHidetoshi Shimokawa 383c60ba66SKatsushi Kobayashi #include <sys/param.h> 393c60ba66SKatsushi Kobayashi #include <sys/systm.h> 403c60ba66SKatsushi Kobayashi #include <sys/mbuf.h> 413c60ba66SKatsushi Kobayashi #include <sys/malloc.h> 423c60ba66SKatsushi Kobayashi #include <sys/sockio.h> 436b3ecf71SHidetoshi Shimokawa #include <sys/sysctl.h> 443c60ba66SKatsushi Kobayashi #include <sys/bus.h> 453c60ba66SKatsushi Kobayashi #include <sys/kernel.h> 463c60ba66SKatsushi Kobayashi #include <sys/conf.h> 4777ee030bSHidetoshi Shimokawa #include <sys/endian.h> 489950b741SHidetoshi Shimokawa #include <sys/kdb.h> 493c60ba66SKatsushi Kobayashi 503c60ba66SKatsushi Kobayashi #include <machine/bus.h> 513c60ba66SKatsushi Kobayashi 523c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire.h> 533c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirereg.h> 5477ee030bSHidetoshi Shimokawa #include <dev/firewire/fwdma.h> 553c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcireg.h> 563c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcivar.h> 573c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire_phy.h> 583c60ba66SKatsushi Kobayashi 593c60ba66SKatsushi Kobayashi #undef OHCI_DEBUG 608da326fdSHidetoshi Shimokawa 61af3b2549SHans Petter Selasky static int nocyclemaster; 62ac2d2894SHidetoshi Shimokawa int firewire_phydma_enable = 1; 636b3ecf71SHidetoshi Shimokawa SYSCTL_DECL(_hw_firewire); 64af3b2549SHans Petter Selasky SYSCTL_INT(_hw_firewire, OID_AUTO, nocyclemaster, CTLFLAG_RWTUN, 65af3b2549SHans Petter Selasky &nocyclemaster, 0, "Do not send cycle start packets"); 66af3b2549SHans Petter Selasky SYSCTL_INT(_hw_firewire, OID_AUTO, phydma_enable, CTLFLAG_RWTUN, 67af3b2549SHans Petter Selasky &firewire_phydma_enable, 0, "Allow physical request DMA from firewire"); 686b3ecf71SHidetoshi Shimokawa 693c60ba66SKatsushi Kobayashi static char dbcode[16][0x10] = {"OUTM", "OUTL", "INPM", "INPL", 703c60ba66SKatsushi Kobayashi "STOR", "LOAD", "NOP ", "STOP",}; 7177ee030bSHidetoshi Shimokawa 723c60ba66SKatsushi Kobayashi static char dbkey[8][0x10] = {"ST0", "ST1", "ST2", "ST3", 733c60ba66SKatsushi Kobayashi "UNDEF", "REG", "SYS", "DEV"}; 7477ee030bSHidetoshi Shimokawa static char dbcond[4][0x10] = {"NEV", "C=1", "C=0", "ALL"}; 753c60ba66SKatsushi Kobayashi char fwohcicode[32][0x20]= { 763c60ba66SKatsushi Kobayashi "No stat", "Undef", "long", "miss Ack err", 779950b741SHidetoshi Shimokawa "FIFO underrun", "FIFO overrun", "desc err", "data read err", 783c60ba66SKatsushi Kobayashi "data write err", "bus reset", "timeout", "tcode err", 793c60ba66SKatsushi Kobayashi "Undef", "Undef", "unknown event", "flushed", 803c60ba66SKatsushi Kobayashi "Undef" ,"ack complete", "ack pend", "Undef", 813c60ba66SKatsushi Kobayashi "ack busy_X", "ack busy_A", "ack busy_B", "Undef", 823c60ba66SKatsushi Kobayashi "Undef", "Undef", "Undef", "ack tardy", 833c60ba66SKatsushi Kobayashi "Undef", "ack data_err", "ack type_err", ""}; 8477ee030bSHidetoshi Shimokawa 850bc666e0SHidetoshi Shimokawa #define MAX_SPEED 3 8648087829SHidetoshi Shimokawa extern char *linkspeed[]; 8703161bbcSDoug Rabson uint32_t tagbit[4] = {1 << 28, 1 << 29, 1 << 30, 1 << 31}; 883c60ba66SKatsushi Kobayashi 893c60ba66SKatsushi Kobayashi static struct tcode_info tinfo[] = { 909950b741SHidetoshi Shimokawa /* hdr_len block flag valid_response */ 919950b741SHidetoshi Shimokawa /* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_WRES}, 929950b741SHidetoshi Shimokawa /* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES}, 939950b741SHidetoshi Shimokawa /* 2 WRES */ {12, FWTI_RES, 0xff}, 949950b741SHidetoshi Shimokawa /* 3 XXX */ { 0, 0, 0xff}, 959950b741SHidetoshi Shimokawa /* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ}, 969950b741SHidetoshi Shimokawa /* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB}, 979950b741SHidetoshi Shimokawa /* 6 RRESQ */ {16, FWTI_RES, 0xff}, 989950b741SHidetoshi Shimokawa /* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, 999950b741SHidetoshi Shimokawa /* 8 CYCS */ { 0, 0, 0xff}, 1009950b741SHidetoshi Shimokawa /* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES}, 1019950b741SHidetoshi Shimokawa /* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR, 0xff}, 1029950b741SHidetoshi Shimokawa /* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, 1039950b741SHidetoshi Shimokawa /* c XXX */ { 0, 0, 0xff}, 1049950b741SHidetoshi Shimokawa /* d XXX */ { 0, 0, 0xff}, 1059950b741SHidetoshi Shimokawa /* e PHY */ {12, FWTI_REQ, 0xff}, 1069950b741SHidetoshi Shimokawa /* f XXX */ { 0, 0, 0xff} 1073c60ba66SKatsushi Kobayashi }; 1083c60ba66SKatsushi Kobayashi 10923667f08SAlexander Kabaev #define ATRQ_CH 0 11023667f08SAlexander Kabaev #define ATRS_CH 1 11123667f08SAlexander Kabaev #define ARRQ_CH 2 11223667f08SAlexander Kabaev #define ARRS_CH 3 11323667f08SAlexander Kabaev #define ITX_CH 4 11423667f08SAlexander Kabaev #define IRX_CH 0x24 11523667f08SAlexander Kabaev 1163c60ba66SKatsushi Kobayashi #define OHCI_WRITE_SIGMASK 0xffff0000 1173c60ba66SKatsushi Kobayashi #define OHCI_READ_SIGMASK 0xffff0000 1183c60ba66SKatsushi Kobayashi 1193c60ba66SKatsushi Kobayashi #define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x)) 1203c60ba66SKatsushi Kobayashi #define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r)) 1213c60ba66SKatsushi Kobayashi 122d09a5d6fSHidetoshi Shimokawa static void fwohci_ibr (struct firewire_comm *); 123d09a5d6fSHidetoshi Shimokawa static void fwohci_db_init (struct fwohci_softc *, struct fwohci_dbch *); 124d09a5d6fSHidetoshi Shimokawa static void fwohci_db_free (struct fwohci_dbch *); 125d09a5d6fSHidetoshi Shimokawa static void fwohci_arcv (struct fwohci_softc *, struct fwohci_dbch *, int); 126d09a5d6fSHidetoshi Shimokawa static void fwohci_txd (struct fwohci_softc *, struct fwohci_dbch *); 127d09a5d6fSHidetoshi Shimokawa static void fwohci_start_atq (struct firewire_comm *); 128d09a5d6fSHidetoshi Shimokawa static void fwohci_start_ats (struct firewire_comm *); 129d09a5d6fSHidetoshi Shimokawa static void fwohci_start (struct fwohci_softc *, struct fwohci_dbch *); 13003161bbcSDoug Rabson static uint32_t fwphy_wrdata (struct fwohci_softc *, uint32_t, uint32_t); 13103161bbcSDoug Rabson static uint32_t fwphy_rddata (struct fwohci_softc *, uint32_t); 132d09a5d6fSHidetoshi Shimokawa static int fwohci_rx_enable (struct fwohci_softc *, struct fwohci_dbch *); 133d09a5d6fSHidetoshi Shimokawa static int fwohci_tx_enable (struct fwohci_softc *, struct fwohci_dbch *); 134d09a5d6fSHidetoshi Shimokawa static int fwohci_irx_enable (struct firewire_comm *, int); 135d09a5d6fSHidetoshi Shimokawa static int fwohci_irx_disable (struct firewire_comm *, int); 13677ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 13703161bbcSDoug Rabson static void fwohci_irx_post (struct firewire_comm *, uint32_t *); 13877ee030bSHidetoshi Shimokawa #endif 139d09a5d6fSHidetoshi Shimokawa static int fwohci_itxbuf_enable (struct firewire_comm *, int); 140d09a5d6fSHidetoshi Shimokawa static int fwohci_itx_disable (struct firewire_comm *, int); 141d09a5d6fSHidetoshi Shimokawa static void fwohci_timeout (void *); 142d09a5d6fSHidetoshi Shimokawa static void fwohci_set_intr (struct firewire_comm *, int); 14377ee030bSHidetoshi Shimokawa 144d09a5d6fSHidetoshi Shimokawa static int fwohci_add_rx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *); 145d09a5d6fSHidetoshi Shimokawa static int fwohci_add_tx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int); 14603161bbcSDoug Rabson static void dump_db (struct fwohci_softc *, uint32_t); 14703161bbcSDoug Rabson static void print_db (struct fwohcidb_tr *, struct fwohcidb *, uint32_t , uint32_t); 14803161bbcSDoug Rabson static void dump_dma (struct fwohci_softc *, uint32_t); 14903161bbcSDoug Rabson static uint32_t fwohci_cyctimer (struct firewire_comm *); 150d09a5d6fSHidetoshi Shimokawa static void fwohci_rbuf_update (struct fwohci_softc *, int); 151d09a5d6fSHidetoshi Shimokawa static void fwohci_tbuf_update (struct fwohci_softc *, int); 152d09a5d6fSHidetoshi Shimokawa void fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *); 1539950b741SHidetoshi Shimokawa static void fwohci_task_busreset(void *, int); 1549950b741SHidetoshi Shimokawa static void fwohci_task_sid(void *, int); 1559950b741SHidetoshi Shimokawa static void fwohci_task_dma(void *, int); 1563c60ba66SKatsushi Kobayashi 1573c60ba66SKatsushi Kobayashi /* 1583c60ba66SKatsushi Kobayashi * memory allocated for DMA programs 1593c60ba66SKatsushi Kobayashi */ 1603c60ba66SKatsushi Kobayashi #define DMA_PROG_ALLOC (8 * PAGE_SIZE) 1613c60ba66SKatsushi Kobayashi 1623c60ba66SKatsushi Kobayashi #define NDB FWMAXQUEUE 1633c60ba66SKatsushi Kobayashi 1643c60ba66SKatsushi Kobayashi #define OHCI_VERSION 0x00 16573aa55baSHidetoshi Shimokawa #define OHCI_ATRETRY 0x08 1663c60ba66SKatsushi Kobayashi #define OHCI_CROMHDR 0x18 1673c60ba66SKatsushi Kobayashi #define OHCI_BUS_OPT 0x20 1687a22215cSEitan Adler #define OHCI_BUSIRMC (1U << 31) 1693c60ba66SKatsushi Kobayashi #define OHCI_BUSCMC (1 << 30) 1703c60ba66SKatsushi Kobayashi #define OHCI_BUSISC (1 << 29) 1713c60ba66SKatsushi Kobayashi #define OHCI_BUSBMC (1 << 28) 1723c60ba66SKatsushi Kobayashi #define OHCI_BUSPMC (1 << 27) 1733c60ba66SKatsushi Kobayashi #define OHCI_BUSFNC OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\ 1743c60ba66SKatsushi Kobayashi OHCI_BUSBMC | OHCI_BUSPMC 1753c60ba66SKatsushi Kobayashi 1763c60ba66SKatsushi Kobayashi #define OHCI_EUID_HI 0x24 1773c60ba66SKatsushi Kobayashi #define OHCI_EUID_LO 0x28 1783c60ba66SKatsushi Kobayashi 1793c60ba66SKatsushi Kobayashi #define OHCI_CROMPTR 0x34 1803c60ba66SKatsushi Kobayashi #define OHCI_HCCCTL 0x50 1813c60ba66SKatsushi Kobayashi #define OHCI_HCCCTLCLR 0x54 1823c60ba66SKatsushi Kobayashi #define OHCI_AREQHI 0x100 1833c60ba66SKatsushi Kobayashi #define OHCI_AREQHICLR 0x104 1843c60ba66SKatsushi Kobayashi #define OHCI_AREQLO 0x108 1853c60ba66SKatsushi Kobayashi #define OHCI_AREQLOCLR 0x10c 1863c60ba66SKatsushi Kobayashi #define OHCI_PREQHI 0x110 1873c60ba66SKatsushi Kobayashi #define OHCI_PREQHICLR 0x114 1883c60ba66SKatsushi Kobayashi #define OHCI_PREQLO 0x118 1893c60ba66SKatsushi Kobayashi #define OHCI_PREQLOCLR 0x11c 1903c60ba66SKatsushi Kobayashi #define OHCI_PREQUPPER 0x120 1913c60ba66SKatsushi Kobayashi 1923c60ba66SKatsushi Kobayashi #define OHCI_SID_BUF 0x64 1933c60ba66SKatsushi Kobayashi #define OHCI_SID_CNT 0x68 1947a22215cSEitan Adler #define OHCI_SID_ERR (1U << 31) 1953c60ba66SKatsushi Kobayashi #define OHCI_SID_CNT_MASK 0xffc 1963c60ba66SKatsushi Kobayashi 1973c60ba66SKatsushi Kobayashi #define OHCI_IT_STAT 0x90 1983c60ba66SKatsushi Kobayashi #define OHCI_IT_STATCLR 0x94 1993c60ba66SKatsushi Kobayashi #define OHCI_IT_MASK 0x98 2003c60ba66SKatsushi Kobayashi #define OHCI_IT_MASKCLR 0x9c 2013c60ba66SKatsushi Kobayashi 2023c60ba66SKatsushi Kobayashi #define OHCI_IR_STAT 0xa0 2033c60ba66SKatsushi Kobayashi #define OHCI_IR_STATCLR 0xa4 2043c60ba66SKatsushi Kobayashi #define OHCI_IR_MASK 0xa8 2053c60ba66SKatsushi Kobayashi #define OHCI_IR_MASKCLR 0xac 2063c60ba66SKatsushi Kobayashi 2073c60ba66SKatsushi Kobayashi #define OHCI_LNKCTL 0xe0 2083c60ba66SKatsushi Kobayashi #define OHCI_LNKCTLCLR 0xe4 2093c60ba66SKatsushi Kobayashi 2103c60ba66SKatsushi Kobayashi #define OHCI_PHYACCESS 0xec 2113c60ba66SKatsushi Kobayashi #define OHCI_CYCLETIMER 0xf0 2123c60ba66SKatsushi Kobayashi 2133c60ba66SKatsushi Kobayashi #define OHCI_DMACTL(off) (off) 2143c60ba66SKatsushi Kobayashi #define OHCI_DMACTLCLR(off) (off + 4) 2153c60ba66SKatsushi Kobayashi #define OHCI_DMACMD(off) (off + 0xc) 2163c60ba66SKatsushi Kobayashi #define OHCI_DMAMATCH(off) (off + 0x10) 2173c60ba66SKatsushi Kobayashi 2183c60ba66SKatsushi Kobayashi #define OHCI_ATQOFF 0x180 2193c60ba66SKatsushi Kobayashi #define OHCI_ATQCTL OHCI_ATQOFF 2203c60ba66SKatsushi Kobayashi #define OHCI_ATQCTLCLR (OHCI_ATQOFF + 4) 2213c60ba66SKatsushi Kobayashi #define OHCI_ATQCMD (OHCI_ATQOFF + 0xc) 2223c60ba66SKatsushi Kobayashi #define OHCI_ATQMATCH (OHCI_ATQOFF + 0x10) 2233c60ba66SKatsushi Kobayashi 2243c60ba66SKatsushi Kobayashi #define OHCI_ATSOFF 0x1a0 2253c60ba66SKatsushi Kobayashi #define OHCI_ATSCTL OHCI_ATSOFF 2263c60ba66SKatsushi Kobayashi #define OHCI_ATSCTLCLR (OHCI_ATSOFF + 4) 2273c60ba66SKatsushi Kobayashi #define OHCI_ATSCMD (OHCI_ATSOFF + 0xc) 2283c60ba66SKatsushi Kobayashi #define OHCI_ATSMATCH (OHCI_ATSOFF + 0x10) 2293c60ba66SKatsushi Kobayashi 2303c60ba66SKatsushi Kobayashi #define OHCI_ARQOFF 0x1c0 2313c60ba66SKatsushi Kobayashi #define OHCI_ARQCTL OHCI_ARQOFF 2323c60ba66SKatsushi Kobayashi #define OHCI_ARQCTLCLR (OHCI_ARQOFF + 4) 2333c60ba66SKatsushi Kobayashi #define OHCI_ARQCMD (OHCI_ARQOFF + 0xc) 2343c60ba66SKatsushi Kobayashi #define OHCI_ARQMATCH (OHCI_ARQOFF + 0x10) 2353c60ba66SKatsushi Kobayashi 2363c60ba66SKatsushi Kobayashi #define OHCI_ARSOFF 0x1e0 2373c60ba66SKatsushi Kobayashi #define OHCI_ARSCTL OHCI_ARSOFF 2383c60ba66SKatsushi Kobayashi #define OHCI_ARSCTLCLR (OHCI_ARSOFF + 4) 2393c60ba66SKatsushi Kobayashi #define OHCI_ARSCMD (OHCI_ARSOFF + 0xc) 2403c60ba66SKatsushi Kobayashi #define OHCI_ARSMATCH (OHCI_ARSOFF + 0x10) 2413c60ba66SKatsushi Kobayashi 2423c60ba66SKatsushi Kobayashi #define OHCI_ITOFF(CH) (0x200 + 0x10 * (CH)) 2433c60ba66SKatsushi Kobayashi #define OHCI_ITCTL(CH) (OHCI_ITOFF(CH)) 2443c60ba66SKatsushi Kobayashi #define OHCI_ITCTLCLR(CH) (OHCI_ITOFF(CH) + 4) 2453c60ba66SKatsushi Kobayashi #define OHCI_ITCMD(CH) (OHCI_ITOFF(CH) + 0xc) 2463c60ba66SKatsushi Kobayashi 2473c60ba66SKatsushi Kobayashi #define OHCI_IROFF(CH) (0x400 + 0x20 * (CH)) 2483c60ba66SKatsushi Kobayashi #define OHCI_IRCTL(CH) (OHCI_IROFF(CH)) 2493c60ba66SKatsushi Kobayashi #define OHCI_IRCTLCLR(CH) (OHCI_IROFF(CH) + 4) 2503c60ba66SKatsushi Kobayashi #define OHCI_IRCMD(CH) (OHCI_IROFF(CH) + 0xc) 2513c60ba66SKatsushi Kobayashi #define OHCI_IRMATCH(CH) (OHCI_IROFF(CH) + 0x10) 2523c60ba66SKatsushi Kobayashi 2533c60ba66SKatsushi Kobayashi d_ioctl_t fwohci_ioctl; 2543c60ba66SKatsushi Kobayashi 2553c60ba66SKatsushi Kobayashi /* 2563c60ba66SKatsushi Kobayashi * Communication with PHY device 2573c60ba66SKatsushi Kobayashi */ 2589950b741SHidetoshi Shimokawa /* XXX need lock for phy access */ 25903161bbcSDoug Rabson static uint32_t 26003161bbcSDoug Rabson fwphy_wrdata(struct fwohci_softc *sc, uint32_t addr, uint32_t data) 2613c60ba66SKatsushi Kobayashi { 26203161bbcSDoug Rabson uint32_t fun; 2633c60ba66SKatsushi Kobayashi 2643c60ba66SKatsushi Kobayashi addr &= 0xf; 2653c60ba66SKatsushi Kobayashi data &= 0xff; 2663c60ba66SKatsushi Kobayashi 26723667f08SAlexander Kabaev fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | 26823667f08SAlexander Kabaev (data << PHYDEV_WRDATA)); 2693c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PHYACCESS, fun); 2703c60ba66SKatsushi Kobayashi DELAY(100); 2713c60ba66SKatsushi Kobayashi 2723c60ba66SKatsushi Kobayashi return (fwphy_rddata(sc, addr)); 2733c60ba66SKatsushi Kobayashi } 2743c60ba66SKatsushi Kobayashi 27503161bbcSDoug Rabson static uint32_t 2763c60ba66SKatsushi Kobayashi fwohci_set_bus_manager(struct firewire_comm *fc, u_int node) 2773c60ba66SKatsushi Kobayashi { 2783c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 2793c60ba66SKatsushi Kobayashi int i; 28003161bbcSDoug Rabson uint32_t bm; 2813c60ba66SKatsushi Kobayashi 2823c60ba66SKatsushi Kobayashi #define OHCI_CSR_DATA 0x0c 2833c60ba66SKatsushi Kobayashi #define OHCI_CSR_COMP 0x10 2843c60ba66SKatsushi Kobayashi #define OHCI_CSR_CONT 0x14 2853c60ba66SKatsushi Kobayashi #define OHCI_BUS_MANAGER_ID 0 2863c60ba66SKatsushi Kobayashi 2873c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_DATA, node); 2883c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_COMP, 0x3f); 2893c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID); 2903c60ba66SKatsushi Kobayashi for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++) 2914ed65ce9SHidetoshi Shimokawa DELAY(10); 2923c60ba66SKatsushi Kobayashi bm = OREAD(sc, OHCI_CSR_DATA); 29317c3d42cSHidetoshi Shimokawa if ((bm & 0x3f) == 0x3f) 2943c60ba66SKatsushi Kobayashi bm = node; 295f9d9941fSHidetoshi Shimokawa if (firewire_debug) 296373d9227SSean Bruno device_printf(sc->fc.dev, "%s: %d->%d (loop=%d)\n", 297373d9227SSean Bruno __func__, bm, node, i); 2983c60ba66SKatsushi Kobayashi return (bm); 2993c60ba66SKatsushi Kobayashi } 3003c60ba66SKatsushi Kobayashi 30103161bbcSDoug Rabson static uint32_t 302c572b810SHidetoshi Shimokawa fwphy_rddata(struct fwohci_softc *sc, u_int addr) 3033c60ba66SKatsushi Kobayashi { 30403161bbcSDoug Rabson uint32_t fun, stat; 305e4b13179SHidetoshi Shimokawa u_int i, retry = 0; 3063c60ba66SKatsushi Kobayashi 3073c60ba66SKatsushi Kobayashi addr &= 0xf; 308e4b13179SHidetoshi Shimokawa #define MAX_RETRY 100 309e4b13179SHidetoshi Shimokawa again: 310e4b13179SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL); 3113c60ba66SKatsushi Kobayashi fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR); 3123c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_PHYACCESS, fun); 313e4b13179SHidetoshi Shimokawa for (i = 0; i < MAX_RETRY; i++) { 3143c60ba66SKatsushi Kobayashi fun = OREAD(sc, OHCI_PHYACCESS); 3153c60ba66SKatsushi Kobayashi if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0) 3163c60ba66SKatsushi Kobayashi break; 3174ed65ce9SHidetoshi Shimokawa DELAY(100); 3183c60ba66SKatsushi Kobayashi } 319e4b13179SHidetoshi Shimokawa if (i >= MAX_RETRY) { 320f9d9941fSHidetoshi Shimokawa if (firewire_debug) 321373d9227SSean Bruno device_printf(sc->fc.dev, "%s: failed(1).\n", __func__); 3221f2361f8SHidetoshi Shimokawa if (++retry < MAX_RETRY) { 3234ed65ce9SHidetoshi Shimokawa DELAY(100); 3241f2361f8SHidetoshi Shimokawa goto again; 3251f2361f8SHidetoshi Shimokawa } 326e4b13179SHidetoshi Shimokawa } 327e4b13179SHidetoshi Shimokawa /* Make sure that SCLK is started */ 328e4b13179SHidetoshi Shimokawa stat = OREAD(sc, FWOHCI_INTSTAT); 329e4b13179SHidetoshi Shimokawa if ((stat & OHCI_INT_REG_FAIL) != 0 || 330e4b13179SHidetoshi Shimokawa ((fun >> PHYDEV_REGADDR) & 0xf) != addr) { 331f9d9941fSHidetoshi Shimokawa if (firewire_debug) 332373d9227SSean Bruno device_printf(sc->fc.dev, "%s: failed(2).\n", __func__); 333e4b13179SHidetoshi Shimokawa if (++retry < MAX_RETRY) { 3344ed65ce9SHidetoshi Shimokawa DELAY(100); 335e4b13179SHidetoshi Shimokawa goto again; 336e4b13179SHidetoshi Shimokawa } 337e4b13179SHidetoshi Shimokawa } 338373d9227SSean Bruno if (firewire_debug > 1 || retry >= MAX_RETRY) 339e4b13179SHidetoshi Shimokawa device_printf(sc->fc.dev, 340373d9227SSean Bruno "%s:: 0x%x loop=%d, retry=%d\n", 341373d9227SSean Bruno __func__, addr, i, retry); 342e4b13179SHidetoshi Shimokawa #undef MAX_RETRY 3433c60ba66SKatsushi Kobayashi return ((fun >> PHYDEV_RDDATA) & 0xff); 3443c60ba66SKatsushi Kobayashi } 34523667f08SAlexander Kabaev 3463c60ba66SKatsushi Kobayashi /* Device specific ioctl. */ 3473c60ba66SKatsushi Kobayashi int 34889c9c53dSPoul-Henning Kamp fwohci_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 3493c60ba66SKatsushi Kobayashi { 3503c60ba66SKatsushi Kobayashi struct firewire_softc *sc; 3513c60ba66SKatsushi Kobayashi struct fwohci_softc *fc; 3523c60ba66SKatsushi Kobayashi int unit = DEV2UNIT(dev); 3533c60ba66SKatsushi Kobayashi int err = 0; 3543c60ba66SKatsushi Kobayashi struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data; 35503161bbcSDoug Rabson uint32_t *dmach = (uint32_t *) data; 3563c60ba66SKatsushi Kobayashi 3573c60ba66SKatsushi Kobayashi sc = devclass_get_softc(firewire_devclass, unit); 35823667f08SAlexander Kabaev if (sc == NULL) 3593c60ba66SKatsushi Kobayashi return (EINVAL); 36023667f08SAlexander Kabaev 3613c60ba66SKatsushi Kobayashi fc = (struct fwohci_softc *)sc->fc; 3623c60ba66SKatsushi Kobayashi 3633c60ba66SKatsushi Kobayashi if (!data) 3643c60ba66SKatsushi Kobayashi return (EINVAL); 3653c60ba66SKatsushi Kobayashi 3663c60ba66SKatsushi Kobayashi switch (cmd) { 3673c60ba66SKatsushi Kobayashi case FWOHCI_WRREG: 3683c60ba66SKatsushi Kobayashi #define OHCI_MAX_REG 0x800 3693c60ba66SKatsushi Kobayashi if (reg->addr <= OHCI_MAX_REG) { 3703c60ba66SKatsushi Kobayashi OWRITE(fc, reg->addr, reg->data); 3713c60ba66SKatsushi Kobayashi reg->data = OREAD(fc, reg->addr); 3723c60ba66SKatsushi Kobayashi } else { 3733c60ba66SKatsushi Kobayashi err = EINVAL; 3743c60ba66SKatsushi Kobayashi } 3753c60ba66SKatsushi Kobayashi break; 3763c60ba66SKatsushi Kobayashi case FWOHCI_RDREG: 3773c60ba66SKatsushi Kobayashi if (reg->addr <= OHCI_MAX_REG) { 3783c60ba66SKatsushi Kobayashi reg->data = OREAD(fc, reg->addr); 3793c60ba66SKatsushi Kobayashi } else { 3803c60ba66SKatsushi Kobayashi err = EINVAL; 3813c60ba66SKatsushi Kobayashi } 3823c60ba66SKatsushi Kobayashi break; 3833c60ba66SKatsushi Kobayashi /* Read DMA descriptors for debug */ 3843c60ba66SKatsushi Kobayashi case DUMPDMA: 3853c60ba66SKatsushi Kobayashi if (*dmach <= OHCI_MAX_DMA_CH) { 3863c60ba66SKatsushi Kobayashi dump_dma(fc, *dmach); 3873c60ba66SKatsushi Kobayashi dump_db(fc, *dmach); 3883c60ba66SKatsushi Kobayashi } else { 3893c60ba66SKatsushi Kobayashi err = EINVAL; 3903c60ba66SKatsushi Kobayashi } 3913c60ba66SKatsushi Kobayashi break; 392f9c8c31dSHidetoshi Shimokawa /* Read/Write Phy registers */ 393f9c8c31dSHidetoshi Shimokawa #define OHCI_MAX_PHY_REG 0xf 394f9c8c31dSHidetoshi Shimokawa case FWOHCI_RDPHYREG: 395f9c8c31dSHidetoshi Shimokawa if (reg->addr <= OHCI_MAX_PHY_REG) 396f9c8c31dSHidetoshi Shimokawa reg->data = fwphy_rddata(fc, reg->addr); 397f9c8c31dSHidetoshi Shimokawa else 398f9c8c31dSHidetoshi Shimokawa err = EINVAL; 399f9c8c31dSHidetoshi Shimokawa break; 400f9c8c31dSHidetoshi Shimokawa case FWOHCI_WRPHYREG: 401f9c8c31dSHidetoshi Shimokawa if (reg->addr <= OHCI_MAX_PHY_REG) 402f9c8c31dSHidetoshi Shimokawa reg->data = fwphy_wrdata(fc, reg->addr, reg->data); 403f9c8c31dSHidetoshi Shimokawa else 404f9c8c31dSHidetoshi Shimokawa err = EINVAL; 405f9c8c31dSHidetoshi Shimokawa break; 4063c60ba66SKatsushi Kobayashi default: 407f9c8c31dSHidetoshi Shimokawa err = EINVAL; 4083c60ba66SKatsushi Kobayashi break; 4093c60ba66SKatsushi Kobayashi } 4103c60ba66SKatsushi Kobayashi return err; 4113c60ba66SKatsushi Kobayashi } 412c572b810SHidetoshi Shimokawa 413d0fd7bc6SHidetoshi Shimokawa static int 414d0fd7bc6SHidetoshi Shimokawa fwohci_probe_phy(struct fwohci_softc *sc, device_t dev) 4153c60ba66SKatsushi Kobayashi { 41603161bbcSDoug Rabson uint32_t reg, reg2; 417d0fd7bc6SHidetoshi Shimokawa int e1394a = 1; 41823667f08SAlexander Kabaev 419d0fd7bc6SHidetoshi Shimokawa /* 420d0fd7bc6SHidetoshi Shimokawa * probe PHY parameters 421d0fd7bc6SHidetoshi Shimokawa * 0. to prove PHY version, whether compliance of 1394a. 422d0fd7bc6SHidetoshi Shimokawa * 1. to probe maximum speed supported by the PHY and 423d0fd7bc6SHidetoshi Shimokawa * number of port supported by core-logic. 424d0fd7bc6SHidetoshi Shimokawa * It is not actually available port on your PC . 425d0fd7bc6SHidetoshi Shimokawa */ 426d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS); 42733662e36SHidetoshi Shimokawa DELAY(500); 42833662e36SHidetoshi Shimokawa 429d0fd7bc6SHidetoshi Shimokawa reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 430d0fd7bc6SHidetoshi Shimokawa 431d0fd7bc6SHidetoshi Shimokawa if ((reg >> 5) != 7) { 432d0fd7bc6SHidetoshi Shimokawa sc->fc.mode &= ~FWPHYASYST; 433d0fd7bc6SHidetoshi Shimokawa sc->fc.nport = reg & FW_PHY_NP; 434d0fd7bc6SHidetoshi Shimokawa sc->fc.speed = reg & FW_PHY_SPD >> 6; 435d0fd7bc6SHidetoshi Shimokawa if (sc->fc.speed > MAX_SPEED) { 436d0fd7bc6SHidetoshi Shimokawa device_printf(dev, "invalid speed %d (fixed to %d).\n", 437d0fd7bc6SHidetoshi Shimokawa sc->fc.speed, MAX_SPEED); 438d0fd7bc6SHidetoshi Shimokawa sc->fc.speed = MAX_SPEED; 439d0fd7bc6SHidetoshi Shimokawa } 440d0fd7bc6SHidetoshi Shimokawa device_printf(dev, 44194b6f028SHidetoshi Shimokawa "Phy 1394 only %s, %d ports.\n", 44294b6f028SHidetoshi Shimokawa linkspeed[sc->fc.speed], sc->fc.nport); 443d0fd7bc6SHidetoshi Shimokawa } else { 444d0fd7bc6SHidetoshi Shimokawa reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG); 445d0fd7bc6SHidetoshi Shimokawa sc->fc.mode |= FWPHYASYST; 446d0fd7bc6SHidetoshi Shimokawa sc->fc.nport = reg & FW_PHY_NP; 447d0fd7bc6SHidetoshi Shimokawa sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5; 448d0fd7bc6SHidetoshi Shimokawa if (sc->fc.speed > MAX_SPEED) { 449d0fd7bc6SHidetoshi Shimokawa device_printf(dev, "invalid speed %d (fixed to %d).\n", 450d0fd7bc6SHidetoshi Shimokawa sc->fc.speed, MAX_SPEED); 451d0fd7bc6SHidetoshi Shimokawa sc->fc.speed = MAX_SPEED; 452d0fd7bc6SHidetoshi Shimokawa } 453d0fd7bc6SHidetoshi Shimokawa device_printf(dev, 45494b6f028SHidetoshi Shimokawa "Phy 1394a available %s, %d ports.\n", 45594b6f028SHidetoshi Shimokawa linkspeed[sc->fc.speed], sc->fc.nport); 456d0fd7bc6SHidetoshi Shimokawa 457d0fd7bc6SHidetoshi Shimokawa /* check programPhyEnable */ 458d0fd7bc6SHidetoshi Shimokawa reg2 = fwphy_rddata(sc, 5); 459d0fd7bc6SHidetoshi Shimokawa #if 0 460d0fd7bc6SHidetoshi Shimokawa if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) { 461d0fd7bc6SHidetoshi Shimokawa #else /* XXX force to enable 1394a */ 462d0fd7bc6SHidetoshi Shimokawa if (e1394a) { 463d0fd7bc6SHidetoshi Shimokawa #endif 464f9d9941fSHidetoshi Shimokawa if (firewire_debug) 465d0fd7bc6SHidetoshi Shimokawa device_printf(dev, 466d0fd7bc6SHidetoshi Shimokawa "Enable 1394a Enhancements\n"); 467d0fd7bc6SHidetoshi Shimokawa /* enable EAA EMC */ 468d0fd7bc6SHidetoshi Shimokawa reg2 |= 0x03; 469d0fd7bc6SHidetoshi Shimokawa /* set aPhyEnhanceEnable */ 470d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN); 471d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY); 472d0fd7bc6SHidetoshi Shimokawa } else { 473d0fd7bc6SHidetoshi Shimokawa /* for safe */ 474d0fd7bc6SHidetoshi Shimokawa reg2 &= ~0x83; 475d0fd7bc6SHidetoshi Shimokawa } 476d0fd7bc6SHidetoshi Shimokawa reg2 = fwphy_wrdata(sc, 5, reg2); 477d0fd7bc6SHidetoshi Shimokawa } 478d0fd7bc6SHidetoshi Shimokawa 479d0fd7bc6SHidetoshi Shimokawa reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 480d0fd7bc6SHidetoshi Shimokawa if ((reg >> 5) == 7) { 481d0fd7bc6SHidetoshi Shimokawa reg = fwphy_rddata(sc, 4); 482d0fd7bc6SHidetoshi Shimokawa reg |= 1 << 6; 483d0fd7bc6SHidetoshi Shimokawa fwphy_wrdata(sc, 4, reg); 484d0fd7bc6SHidetoshi Shimokawa reg = fwphy_rddata(sc, 4); 485d0fd7bc6SHidetoshi Shimokawa } 486d0fd7bc6SHidetoshi Shimokawa return 0; 487d0fd7bc6SHidetoshi Shimokawa } 488d0fd7bc6SHidetoshi Shimokawa 489d0fd7bc6SHidetoshi Shimokawa 490d0fd7bc6SHidetoshi Shimokawa void 491d0fd7bc6SHidetoshi Shimokawa fwohci_reset(struct fwohci_softc *sc, device_t dev) 492d0fd7bc6SHidetoshi Shimokawa { 49394b6f028SHidetoshi Shimokawa int i, max_rec, speed; 49403161bbcSDoug Rabson uint32_t reg, reg2; 4953c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 496d0fd7bc6SHidetoshi Shimokawa 49795a24954SDoug Rabson /* Disable interrupts */ 498d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASKCLR, ~0); 499d0fd7bc6SHidetoshi Shimokawa 50095a24954SDoug Rabson /* Now stopping all DMA channels */ 501d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 502d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 503d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 504d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 505d0fd7bc6SHidetoshi Shimokawa 506d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_IR_MASKCLR, ~0); 507d0fd7bc6SHidetoshi Shimokawa for (i = 0; i < sc->fc.nisodma; i++) { 508d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 509d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 510d0fd7bc6SHidetoshi Shimokawa } 511d0fd7bc6SHidetoshi Shimokawa 512d0fd7bc6SHidetoshi Shimokawa /* FLUSH FIFO and reset Transmitter/Reciever */ 513d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 514f9d9941fSHidetoshi Shimokawa if (firewire_debug) 515d0fd7bc6SHidetoshi Shimokawa device_printf(dev, "resetting OHCI..."); 516d0fd7bc6SHidetoshi Shimokawa i = 0; 517d0fd7bc6SHidetoshi Shimokawa while (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) { 518d0fd7bc6SHidetoshi Shimokawa if (i++ > 100) break; 519d0fd7bc6SHidetoshi Shimokawa DELAY(1000); 520d0fd7bc6SHidetoshi Shimokawa } 521f9d9941fSHidetoshi Shimokawa if (firewire_debug) 522d0fd7bc6SHidetoshi Shimokawa printf("done (loop=%d)\n", i); 523d0fd7bc6SHidetoshi Shimokawa 52494b6f028SHidetoshi Shimokawa /* Probe phy */ 52594b6f028SHidetoshi Shimokawa fwohci_probe_phy(sc, dev); 52694b6f028SHidetoshi Shimokawa 52794b6f028SHidetoshi Shimokawa /* Probe link */ 528d0fd7bc6SHidetoshi Shimokawa reg = OREAD(sc, OHCI_BUS_OPT); 529d0fd7bc6SHidetoshi Shimokawa reg2 = reg | OHCI_BUSFNC; 53094b6f028SHidetoshi Shimokawa max_rec = (reg & 0x0000f000) >> 12; 53194b6f028SHidetoshi Shimokawa speed = (reg & 0x00000007); 53294b6f028SHidetoshi Shimokawa device_printf(dev, "Link %s, max_rec %d bytes.\n", 53394b6f028SHidetoshi Shimokawa linkspeed[speed], MAXREC(max_rec)); 53494b6f028SHidetoshi Shimokawa /* XXX fix max_rec */ 53594b6f028SHidetoshi Shimokawa sc->fc.maxrec = sc->fc.speed + 8; 53694b6f028SHidetoshi Shimokawa if (max_rec != sc->fc.maxrec) { 53794b6f028SHidetoshi Shimokawa reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12); 53894b6f028SHidetoshi Shimokawa device_printf(dev, "max_rec %d -> %d\n", 53994b6f028SHidetoshi Shimokawa MAXREC(max_rec), MAXREC(sc->fc.maxrec)); 54094b6f028SHidetoshi Shimokawa } 541f9d9941fSHidetoshi Shimokawa if (firewire_debug) 542d0fd7bc6SHidetoshi Shimokawa device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2); 543d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_BUS_OPT, reg2); 544d0fd7bc6SHidetoshi Shimokawa 54594b6f028SHidetoshi Shimokawa /* Initialize registers */ 546d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]); 54777ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr); 548d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND); 549d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR); 55077ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr); 551d0fd7bc6SHidetoshi Shimokawa OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID); 5529339321dSHidetoshi Shimokawa 55394b6f028SHidetoshi Shimokawa /* Enable link */ 55494b6f028SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN); 55594b6f028SHidetoshi Shimokawa 55694b6f028SHidetoshi Shimokawa /* Force to start async RX DMA */ 5579339321dSHidetoshi Shimokawa sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING; 5589339321dSHidetoshi Shimokawa sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING; 559d0fd7bc6SHidetoshi Shimokawa fwohci_rx_enable(sc, &sc->arrq); 560d0fd7bc6SHidetoshi Shimokawa fwohci_rx_enable(sc, &sc->arrs); 561d0fd7bc6SHidetoshi Shimokawa 56294b6f028SHidetoshi Shimokawa /* Initialize async TX */ 56394b6f028SHidetoshi Shimokawa OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 56494b6f028SHidetoshi Shimokawa OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 565630529adSHidetoshi Shimokawa 56694b6f028SHidetoshi Shimokawa /* AT Retries */ 56794b6f028SHidetoshi Shimokawa OWRITE(sc, FWOHCI_RETRY, 56894b6f028SHidetoshi Shimokawa /* CycleLimit PhyRespRetries ATRespRetries ATReqRetries */ 56994b6f028SHidetoshi Shimokawa (0xffff << 16) | (0x0f << 8) | (0x0f << 4) | 0x0f); 570630529adSHidetoshi Shimokawa 571630529adSHidetoshi Shimokawa sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq); 572630529adSHidetoshi Shimokawa sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq); 573630529adSHidetoshi Shimokawa sc->atrq.bottom = sc->atrq.top; 574630529adSHidetoshi Shimokawa sc->atrs.bottom = sc->atrs.top; 575630529adSHidetoshi Shimokawa 576d0fd7bc6SHidetoshi Shimokawa for (i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb; 577d0fd7bc6SHidetoshi Shimokawa i++, db_tr = STAILQ_NEXT(db_tr, link)) { 578d0fd7bc6SHidetoshi Shimokawa db_tr->xfer = NULL; 579d0fd7bc6SHidetoshi Shimokawa } 580d0fd7bc6SHidetoshi Shimokawa for (i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb; 581d0fd7bc6SHidetoshi Shimokawa i++, db_tr = STAILQ_NEXT(db_tr, link)) { 582d0fd7bc6SHidetoshi Shimokawa db_tr->xfer = NULL; 583d0fd7bc6SHidetoshi Shimokawa } 584d0fd7bc6SHidetoshi Shimokawa 58595a24954SDoug Rabson /* Enable interrupts */ 5869950b741SHidetoshi Shimokawa sc->intmask = (OHCI_INT_ERR | OHCI_INT_PHY_SID 587d0fd7bc6SHidetoshi Shimokawa | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 588d0fd7bc6SHidetoshi Shimokawa | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 589d0fd7bc6SHidetoshi Shimokawa | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); 5909950b741SHidetoshi Shimokawa sc->intmask |= OHCI_INT_DMA_IR | OHCI_INT_DMA_IT; 5919950b741SHidetoshi Shimokawa sc->intmask |= OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT; 5929950b741SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASK, sc->intmask); 593d0fd7bc6SHidetoshi Shimokawa fwohci_set_intr(&sc->fc, 1); 594d0fd7bc6SHidetoshi Shimokawa } 595d0fd7bc6SHidetoshi Shimokawa 596d0fd7bc6SHidetoshi Shimokawa int 597d0fd7bc6SHidetoshi Shimokawa fwohci_init(struct fwohci_softc *sc, device_t dev) 598d0fd7bc6SHidetoshi Shimokawa { 599ff04511eSHidetoshi Shimokawa int i, mver; 60003161bbcSDoug Rabson uint32_t reg; 60103161bbcSDoug Rabson uint8_t ui[8]; 6023c60ba66SKatsushi Kobayashi 603ff04511eSHidetoshi Shimokawa /* OHCI version */ 6043c60ba66SKatsushi Kobayashi reg = OREAD(sc, OHCI_VERSION); 605ff04511eSHidetoshi Shimokawa mver = (reg >> 16) & 0xff; 6063c60ba66SKatsushi Kobayashi device_printf(dev, "OHCI version %x.%x (ROM=%d)\n", 607ff04511eSHidetoshi Shimokawa mver, reg & 0xff, (reg >> 24) & 1); 608ff04511eSHidetoshi Shimokawa if (mver < 1 || mver > 9) { 60918349893SHidetoshi Shimokawa device_printf(dev, "invalid OHCI version\n"); 61018349893SHidetoshi Shimokawa return (ENXIO); 61118349893SHidetoshi Shimokawa } 61218349893SHidetoshi Shimokawa 61395a24954SDoug Rabson /* Available Isochronous DMA channel probe */ 6147054e848SHidetoshi Shimokawa OWRITE(sc, OHCI_IT_MASK, 0xffffffff); 6157054e848SHidetoshi Shimokawa OWRITE(sc, OHCI_IR_MASK, 0xffffffff); 6167054e848SHidetoshi Shimokawa reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK); 6177054e848SHidetoshi Shimokawa OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff); 6187054e848SHidetoshi Shimokawa OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff); 6197054e848SHidetoshi Shimokawa for (i = 0; i < 0x20; i++) 6207054e848SHidetoshi Shimokawa if ((reg & (1 << i)) == 0) 6217054e848SHidetoshi Shimokawa break; 6223c60ba66SKatsushi Kobayashi sc->fc.nisodma = i; 62395a24954SDoug Rabson device_printf(dev, "No. of Isochronous channels is %d.\n", i); 624f40a2915SHidetoshi Shimokawa if (i == 0) 625f40a2915SHidetoshi Shimokawa return (ENXIO); 6263c60ba66SKatsushi Kobayashi 6273c60ba66SKatsushi Kobayashi sc->fc.arq = &sc->arrq.xferq; 6283c60ba66SKatsushi Kobayashi sc->fc.ars = &sc->arrs.xferq; 6293c60ba66SKatsushi Kobayashi sc->fc.atq = &sc->atrq.xferq; 6303c60ba66SKatsushi Kobayashi sc->fc.ats = &sc->atrs.xferq; 6313c60ba66SKatsushi Kobayashi 63277ee030bSHidetoshi Shimokawa sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 63377ee030bSHidetoshi Shimokawa sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 63477ee030bSHidetoshi Shimokawa sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 63577ee030bSHidetoshi Shimokawa sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 63677ee030bSHidetoshi Shimokawa 6373c60ba66SKatsushi Kobayashi sc->arrq.xferq.start = NULL; 6383c60ba66SKatsushi Kobayashi sc->arrs.xferq.start = NULL; 6393c60ba66SKatsushi Kobayashi sc->atrq.xferq.start = fwohci_start_atq; 6403c60ba66SKatsushi Kobayashi sc->atrs.xferq.start = fwohci_start_ats; 6413c60ba66SKatsushi Kobayashi 64277ee030bSHidetoshi Shimokawa sc->arrq.xferq.buf = NULL; 64377ee030bSHidetoshi Shimokawa sc->arrs.xferq.buf = NULL; 64477ee030bSHidetoshi Shimokawa sc->atrq.xferq.buf = NULL; 64577ee030bSHidetoshi Shimokawa sc->atrs.xferq.buf = NULL; 6463c60ba66SKatsushi Kobayashi 6476cada79aSHidetoshi Shimokawa sc->arrq.xferq.dmach = -1; 6486cada79aSHidetoshi Shimokawa sc->arrs.xferq.dmach = -1; 6496cada79aSHidetoshi Shimokawa sc->atrq.xferq.dmach = -1; 6506cada79aSHidetoshi Shimokawa sc->atrs.xferq.dmach = -1; 6516cada79aSHidetoshi Shimokawa 6523c60ba66SKatsushi Kobayashi sc->arrq.ndesc = 1; 6533c60ba66SKatsushi Kobayashi sc->arrs.ndesc = 1; 654645394e6SHidetoshi Shimokawa sc->atrq.ndesc = 8; /* equal to maximum of mbuf chains */ 655645394e6SHidetoshi Shimokawa sc->atrs.ndesc = 2; 6563c60ba66SKatsushi Kobayashi 6573c60ba66SKatsushi Kobayashi sc->arrq.ndb = NDB; 6583c60ba66SKatsushi Kobayashi sc->arrs.ndb = NDB / 2; 6593c60ba66SKatsushi Kobayashi sc->atrq.ndb = NDB; 6603c60ba66SKatsushi Kobayashi sc->atrs.ndb = NDB / 2; 6613c60ba66SKatsushi Kobayashi 6623c60ba66SKatsushi Kobayashi for (i = 0; i < sc->fc.nisodma; i++) { 6633c60ba66SKatsushi Kobayashi sc->fc.it[i] = &sc->it[i].xferq; 6643c60ba66SKatsushi Kobayashi sc->fc.ir[i] = &sc->ir[i].xferq; 6656cada79aSHidetoshi Shimokawa sc->it[i].xferq.dmach = i; 6666cada79aSHidetoshi Shimokawa sc->ir[i].xferq.dmach = i; 6673c60ba66SKatsushi Kobayashi sc->it[i].ndb = 0; 6683c60ba66SKatsushi Kobayashi sc->ir[i].ndb = 0; 6693c60ba66SKatsushi Kobayashi } 6703c60ba66SKatsushi Kobayashi 6713c60ba66SKatsushi Kobayashi sc->fc.tcode = tinfo; 67277ee030bSHidetoshi Shimokawa sc->fc.dev = dev; 6733c60ba66SKatsushi Kobayashi 67477ee030bSHidetoshi Shimokawa sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE, 6750752b99dSMarius Strobl &sc->crom_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 67677ee030bSHidetoshi Shimokawa if (sc->fc.config_rom == NULL) { 67777ee030bSHidetoshi Shimokawa device_printf(dev, "config_rom alloc failed."); 6783c60ba66SKatsushi Kobayashi return ENOMEM; 6793c60ba66SKatsushi Kobayashi } 6803c60ba66SKatsushi Kobayashi 6810bc666e0SHidetoshi Shimokawa #if 0 6820bc666e0SHidetoshi Shimokawa bzero(&sc->fc.config_rom[0], CROMSIZE); 6833c60ba66SKatsushi Kobayashi sc->fc.config_rom[1] = 0x31333934; 6843c60ba66SKatsushi Kobayashi sc->fc.config_rom[2] = 0xf000a002; 6853c60ba66SKatsushi Kobayashi sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI); 6863c60ba66SKatsushi Kobayashi sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO); 6873c60ba66SKatsushi Kobayashi sc->fc.config_rom[5] = 0; 6883c60ba66SKatsushi Kobayashi sc->fc.config_rom[0] = (4 << 24) | (5 << 16); 6893c60ba66SKatsushi Kobayashi 6903c60ba66SKatsushi Kobayashi sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4); 69177ee030bSHidetoshi Shimokawa #endif 6923c60ba66SKatsushi Kobayashi 69395a24954SDoug Rabson /* SID recieve buffer must align 2^11 */ 6943c60ba66SKatsushi Kobayashi #define OHCI_SIDSIZE (1 << 11) 69577ee030bSHidetoshi Shimokawa sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE, 6960752b99dSMarius Strobl &sc->sid_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 69777ee030bSHidetoshi Shimokawa if (sc->sid_buf == NULL) { 69877ee030bSHidetoshi Shimokawa device_printf(dev, "sid_buf alloc failed."); 69916e0f484SHidetoshi Shimokawa return ENOMEM; 70016e0f484SHidetoshi Shimokawa } 7013c60ba66SKatsushi Kobayashi 70203161bbcSDoug Rabson fwdma_malloc(&sc->fc, sizeof(uint32_t), sizeof(uint32_t), 70377ee030bSHidetoshi Shimokawa &sc->dummy_dma, BUS_DMA_WAITOK); 70477ee030bSHidetoshi Shimokawa 70577ee030bSHidetoshi Shimokawa if (sc->dummy_dma.v_addr == NULL) { 70677ee030bSHidetoshi Shimokawa device_printf(dev, "dummy_dma alloc failed."); 70777ee030bSHidetoshi Shimokawa return ENOMEM; 70877ee030bSHidetoshi Shimokawa } 70977ee030bSHidetoshi Shimokawa 71077ee030bSHidetoshi Shimokawa fwohci_db_init(sc, &sc->arrq); 7111f2361f8SHidetoshi Shimokawa if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0) 7121f2361f8SHidetoshi Shimokawa return ENOMEM; 7131f2361f8SHidetoshi Shimokawa 71477ee030bSHidetoshi Shimokawa fwohci_db_init(sc, &sc->arrs); 7151f2361f8SHidetoshi Shimokawa if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0) 7161f2361f8SHidetoshi Shimokawa return ENOMEM; 7173c60ba66SKatsushi Kobayashi 71877ee030bSHidetoshi Shimokawa fwohci_db_init(sc, &sc->atrq); 7191f2361f8SHidetoshi Shimokawa if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0) 7201f2361f8SHidetoshi Shimokawa return ENOMEM; 7211f2361f8SHidetoshi Shimokawa 72277ee030bSHidetoshi Shimokawa fwohci_db_init(sc, &sc->atrs); 7231f2361f8SHidetoshi Shimokawa if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0) 7241f2361f8SHidetoshi Shimokawa return ENOMEM; 7253c60ba66SKatsushi Kobayashi 726c547b896SHidetoshi Shimokawa sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H); 727c547b896SHidetoshi Shimokawa sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L); 728c547b896SHidetoshi Shimokawa for (i = 0; i < 8; i++) 729c547b896SHidetoshi Shimokawa ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i); 7303c60ba66SKatsushi Kobayashi device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 731c547b896SHidetoshi Shimokawa ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]); 732c547b896SHidetoshi Shimokawa 7333c60ba66SKatsushi Kobayashi sc->fc.ioctl = fwohci_ioctl; 7343c60ba66SKatsushi Kobayashi sc->fc.cyctimer = fwohci_cyctimer; 7353c60ba66SKatsushi Kobayashi sc->fc.set_bmr = fwohci_set_bus_manager; 7363c60ba66SKatsushi Kobayashi sc->fc.ibr = fwohci_ibr; 7373c60ba66SKatsushi Kobayashi sc->fc.irx_enable = fwohci_irx_enable; 7383c60ba66SKatsushi Kobayashi sc->fc.irx_disable = fwohci_irx_disable; 7393c60ba66SKatsushi Kobayashi 7403c60ba66SKatsushi Kobayashi sc->fc.itx_enable = fwohci_itxbuf_enable; 7413c60ba66SKatsushi Kobayashi sc->fc.itx_disable = fwohci_itx_disable; 74277ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 7433c60ba66SKatsushi Kobayashi sc->fc.irx_post = fwohci_irx_post; 74477ee030bSHidetoshi Shimokawa #else 74577ee030bSHidetoshi Shimokawa sc->fc.irx_post = NULL; 74677ee030bSHidetoshi Shimokawa #endif 7473c60ba66SKatsushi Kobayashi sc->fc.itx_post = NULL; 7483c60ba66SKatsushi Kobayashi sc->fc.timeout = fwohci_timeout; 7493c60ba66SKatsushi Kobayashi sc->fc.poll = fwohci_poll; 7503c60ba66SKatsushi Kobayashi sc->fc.set_intr = fwohci_set_intr; 751c572b810SHidetoshi Shimokawa 75277ee030bSHidetoshi Shimokawa sc->intmask = sc->irstat = sc->itstat = 0; 75377ee030bSHidetoshi Shimokawa 7549950b741SHidetoshi Shimokawa /* Init task queue */ 7559950b741SHidetoshi Shimokawa sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK, 7569950b741SHidetoshi Shimokawa taskqueue_thread_enqueue, &sc->fc.taskqueue); 7579950b741SHidetoshi Shimokawa taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq", 7589950b741SHidetoshi Shimokawa device_get_unit(dev)); 7599950b741SHidetoshi Shimokawa TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc); 7609950b741SHidetoshi Shimokawa TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc); 7619950b741SHidetoshi Shimokawa TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc); 7629950b741SHidetoshi Shimokawa 763d0fd7bc6SHidetoshi Shimokawa fw_init(&sc->fc); 764d0fd7bc6SHidetoshi Shimokawa fwohci_reset(sc, dev); 7653c60ba66SKatsushi Kobayashi 766d0fd7bc6SHidetoshi Shimokawa return 0; 7673c60ba66SKatsushi Kobayashi } 768c572b810SHidetoshi Shimokawa 769c572b810SHidetoshi Shimokawa void 770c572b810SHidetoshi Shimokawa fwohci_timeout(void *arg) 7713c60ba66SKatsushi Kobayashi { 7723c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 7733c60ba66SKatsushi Kobayashi 7743c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)arg; 7753c60ba66SKatsushi Kobayashi } 776c572b810SHidetoshi Shimokawa 77703161bbcSDoug Rabson uint32_t 778c572b810SHidetoshi Shimokawa fwohci_cyctimer(struct firewire_comm *fc) 7793c60ba66SKatsushi Kobayashi { 7803c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 7813c60ba66SKatsushi Kobayashi return (OREAD(sc, OHCI_CYCLETIMER)); 7823c60ba66SKatsushi Kobayashi } 7833c60ba66SKatsushi Kobayashi 7841f2361f8SHidetoshi Shimokawa int 7851f2361f8SHidetoshi Shimokawa fwohci_detach(struct fwohci_softc *sc, device_t dev) 7861f2361f8SHidetoshi Shimokawa { 7871f2361f8SHidetoshi Shimokawa int i; 7881f2361f8SHidetoshi Shimokawa 78977ee030bSHidetoshi Shimokawa if (sc->sid_buf != NULL) 79077ee030bSHidetoshi Shimokawa fwdma_free(&sc->fc, &sc->sid_dma); 79177ee030bSHidetoshi Shimokawa if (sc->fc.config_rom != NULL) 79277ee030bSHidetoshi Shimokawa fwdma_free(&sc->fc, &sc->crom_dma); 7931f2361f8SHidetoshi Shimokawa 7941f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->arrq); 7951f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->arrs); 7961f2361f8SHidetoshi Shimokawa 7971f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->atrq); 7981f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->atrs); 7991f2361f8SHidetoshi Shimokawa 8001f2361f8SHidetoshi Shimokawa for (i = 0; i < sc->fc.nisodma; i++) { 8011f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->it[i]); 8021f2361f8SHidetoshi Shimokawa fwohci_db_free(&sc->ir[i]); 8031f2361f8SHidetoshi Shimokawa } 8049950b741SHidetoshi Shimokawa if (sc->fc.taskqueue != NULL) { 8059950b741SHidetoshi Shimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset); 8069950b741SHidetoshi Shimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid); 8079950b741SHidetoshi Shimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma); 8089950b741SHidetoshi Shimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout); 8099950b741SHidetoshi Shimokawa taskqueue_free(sc->fc.taskqueue); 8109950b741SHidetoshi Shimokawa sc->fc.taskqueue = NULL; 8119950b741SHidetoshi Shimokawa } 8121f2361f8SHidetoshi Shimokawa 8131f2361f8SHidetoshi Shimokawa return 0; 8141f2361f8SHidetoshi Shimokawa } 8151f2361f8SHidetoshi Shimokawa 816d6105b60SHidetoshi Shimokawa #define LAST_DB(dbtr, db) do { \ 817d6105b60SHidetoshi Shimokawa struct fwohcidb_tr *_dbtr = (dbtr); \ 818d6105b60SHidetoshi Shimokawa int _cnt = _dbtr->dbcnt; \ 819d6105b60SHidetoshi Shimokawa db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0]; \ 820d6105b60SHidetoshi Shimokawa } while (0) 821d6105b60SHidetoshi Shimokawa 822c572b810SHidetoshi Shimokawa static void 82377ee030bSHidetoshi Shimokawa fwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error) 82477ee030bSHidetoshi Shimokawa { 82577ee030bSHidetoshi Shimokawa struct fwohcidb_tr *db_tr; 826c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 82777ee030bSHidetoshi Shimokawa bus_dma_segment_t *s; 82877ee030bSHidetoshi Shimokawa int i; 82977ee030bSHidetoshi Shimokawa 83077ee030bSHidetoshi Shimokawa db_tr = (struct fwohcidb_tr *)arg; 83177ee030bSHidetoshi Shimokawa db = &db_tr->db[db_tr->dbcnt]; 83277ee030bSHidetoshi Shimokawa if (error) { 83377ee030bSHidetoshi Shimokawa if (firewire_debug || error != EFBIG) 83477ee030bSHidetoshi Shimokawa printf("fwohci_execute_db: error=%d\n", error); 83577ee030bSHidetoshi Shimokawa return; 83677ee030bSHidetoshi Shimokawa } 83777ee030bSHidetoshi Shimokawa for (i = 0; i < nseg; i++) { 83877ee030bSHidetoshi Shimokawa s = &segs[i]; 83977ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr); 84077ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len); 84177ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 0); 84277ee030bSHidetoshi Shimokawa db++; 84377ee030bSHidetoshi Shimokawa db_tr->dbcnt++; 84477ee030bSHidetoshi Shimokawa } 84577ee030bSHidetoshi Shimokawa } 84677ee030bSHidetoshi Shimokawa 84777ee030bSHidetoshi Shimokawa static void 84877ee030bSHidetoshi Shimokawa fwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg, 84977ee030bSHidetoshi Shimokawa bus_size_t size, int error) 85077ee030bSHidetoshi Shimokawa { 85177ee030bSHidetoshi Shimokawa fwohci_execute_db(arg, segs, nseg, error); 85277ee030bSHidetoshi Shimokawa } 85377ee030bSHidetoshi Shimokawa 85477ee030bSHidetoshi Shimokawa static void 855c572b810SHidetoshi Shimokawa fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 8563c60ba66SKatsushi Kobayashi { 8573c60ba66SKatsushi Kobayashi int i, s; 858c4778b5dSHidetoshi Shimokawa int tcode, hdr_len, pl_off; 8593c60ba66SKatsushi Kobayashi int fsegment = -1; 86003161bbcSDoug Rabson uint32_t off; 8613c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 8623c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 863c4778b5dSHidetoshi Shimokawa struct fwohci_txpkthdr *ohcifp; 8643c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 865c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 86603161bbcSDoug Rabson uint32_t *ld; 8673c60ba66SKatsushi Kobayashi struct tcode_info *info; 868d6105b60SHidetoshi Shimokawa static int maxdesc=0; 8693c60ba66SKatsushi Kobayashi 8709950b741SHidetoshi Shimokawa FW_GLOCK_ASSERT(&sc->fc); 8719950b741SHidetoshi Shimokawa 8723c60ba66SKatsushi Kobayashi if (&sc->atrq == dbch) { 8733c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 8743c60ba66SKatsushi Kobayashi } else if (&sc->atrs == dbch) { 8753c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 8763c60ba66SKatsushi Kobayashi } else { 8773c60ba66SKatsushi Kobayashi return; 8783c60ba66SKatsushi Kobayashi } 8793c60ba66SKatsushi Kobayashi 8803c60ba66SKatsushi Kobayashi if (dbch->flags & FWOHCI_DBCH_FULL) 8813c60ba66SKatsushi Kobayashi return; 8823c60ba66SKatsushi Kobayashi 8833c60ba66SKatsushi Kobayashi s = splfw(); 8843c60ba66SKatsushi Kobayashi db_tr = dbch->top; 8853c60ba66SKatsushi Kobayashi txloop: 8863c60ba66SKatsushi Kobayashi xfer = STAILQ_FIRST(&dbch->xferq.q); 8873c60ba66SKatsushi Kobayashi if (xfer == NULL) { 8883c60ba66SKatsushi Kobayashi goto kick; 8893c60ba66SKatsushi Kobayashi } 8909950b741SHidetoshi Shimokawa #if 0 8913c60ba66SKatsushi Kobayashi if (dbch->xferq.queued == 0) { 8923c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "TX queue empty\n"); 8933c60ba66SKatsushi Kobayashi } 8949950b741SHidetoshi Shimokawa #endif 8953c60ba66SKatsushi Kobayashi STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); 8963c60ba66SKatsushi Kobayashi db_tr->xfer = xfer; 8979950b741SHidetoshi Shimokawa xfer->flag = FWXF_START; 8983c60ba66SKatsushi Kobayashi 899c4778b5dSHidetoshi Shimokawa fp = &xfer->send.hdr; 9003c60ba66SKatsushi Kobayashi tcode = fp->mode.common.tcode; 9013c60ba66SKatsushi Kobayashi 902c4778b5dSHidetoshi Shimokawa ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed; 9033c60ba66SKatsushi Kobayashi info = &tinfo[tcode]; 90477ee030bSHidetoshi Shimokawa hdr_len = pl_off = info->hdr_len; 905a1c9e73aSHidetoshi Shimokawa 906a1c9e73aSHidetoshi Shimokawa ld = &ohcifp->mode.ld[0]; 907a1c9e73aSHidetoshi Shimokawa ld[0] = ld[1] = ld[2] = ld[3] = 0; 908a1c9e73aSHidetoshi Shimokawa for (i = 0; i < pl_off; i+= 4) 909a1c9e73aSHidetoshi Shimokawa ld[i/4] = fp->mode.ld[i/4]; 910a1c9e73aSHidetoshi Shimokawa 911c4778b5dSHidetoshi Shimokawa ohcifp->mode.common.spd = xfer->send.spd & 0x7; 9123c60ba66SKatsushi Kobayashi if (tcode == FWTCODE_STREAM) { 9133c60ba66SKatsushi Kobayashi hdr_len = 8; 91477ee030bSHidetoshi Shimokawa ohcifp->mode.stream.len = fp->mode.stream.len; 9153c60ba66SKatsushi Kobayashi } else if (tcode == FWTCODE_PHY) { 9163c60ba66SKatsushi Kobayashi hdr_len = 12; 917a1c9e73aSHidetoshi Shimokawa ld[1] = fp->mode.ld[1]; 918a1c9e73aSHidetoshi Shimokawa ld[2] = fp->mode.ld[2]; 9193c60ba66SKatsushi Kobayashi ohcifp->mode.common.spd = 0; 9203c60ba66SKatsushi Kobayashi ohcifp->mode.common.tcode = FWOHCITCODE_PHY; 9213c60ba66SKatsushi Kobayashi } else { 92277ee030bSHidetoshi Shimokawa ohcifp->mode.asycomm.dst = fp->mode.hdr.dst; 9233c60ba66SKatsushi Kobayashi ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; 9243c60ba66SKatsushi Kobayashi ohcifp->mode.asycomm.tlrt |= FWRETRY_X; 9253c60ba66SKatsushi Kobayashi } 9263c60ba66SKatsushi Kobayashi db = &db_tr->db[0]; 92777ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.cmd, 92877ee030bSHidetoshi Shimokawa OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len); 929a1c9e73aSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.addr, 0); 93077ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 0); 9313c60ba66SKatsushi Kobayashi /* Specify bound timer of asy. responce */ 9323c60ba66SKatsushi Kobayashi if (&sc->atrs == dbch) { 93377ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 93477ee030bSHidetoshi Shimokawa (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13)); 9353c60ba66SKatsushi Kobayashi } 93677ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 93777ee030bSHidetoshi Shimokawa if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ) 93877ee030bSHidetoshi Shimokawa hdr_len = 12; 93977ee030bSHidetoshi Shimokawa for (i = 0; i < hdr_len/4; i++) 940a1c9e73aSHidetoshi Shimokawa FWOHCI_DMA_WRITE(ld[i], ld[i]); 94177ee030bSHidetoshi Shimokawa #endif 9423c60ba66SKatsushi Kobayashi 9432b4601d1SHidetoshi Shimokawa again: 9443c60ba66SKatsushi Kobayashi db_tr->dbcnt = 2; 9453c60ba66SKatsushi Kobayashi db = &db_tr->db[db_tr->dbcnt]; 946c4778b5dSHidetoshi Shimokawa if (xfer->send.pay_len > 0) { 94777ee030bSHidetoshi Shimokawa int err; 94877ee030bSHidetoshi Shimokawa /* handle payload */ 9493c60ba66SKatsushi Kobayashi if (xfer->mbuf == NULL) { 95077ee030bSHidetoshi Shimokawa err = bus_dmamap_load(dbch->dmat, db_tr->dma_map, 951c4778b5dSHidetoshi Shimokawa &xfer->send.payload[0], xfer->send.pay_len, 95277ee030bSHidetoshi Shimokawa fwohci_execute_db, db_tr, 95377ee030bSHidetoshi Shimokawa /*flags*/0); 9543c60ba66SKatsushi Kobayashi } else { 9552b4601d1SHidetoshi Shimokawa /* XXX we can handle only 6 (=8-2) mbuf chains */ 95677ee030bSHidetoshi Shimokawa err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 95777ee030bSHidetoshi Shimokawa xfer->mbuf, 95877ee030bSHidetoshi Shimokawa fwohci_execute_db2, db_tr, 95977ee030bSHidetoshi Shimokawa /* flags */0); 96077ee030bSHidetoshi Shimokawa if (err == EFBIG) { 96177ee030bSHidetoshi Shimokawa struct mbuf *m0; 96277ee030bSHidetoshi Shimokawa 96377ee030bSHidetoshi Shimokawa if (firewire_debug) 96477ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "EFBIG.\n"); 965c6499eccSGleb Smirnoff m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 96677ee030bSHidetoshi Shimokawa if (m0 != NULL) { 9672b4601d1SHidetoshi Shimokawa m_copydata(xfer->mbuf, 0, 9682b4601d1SHidetoshi Shimokawa xfer->mbuf->m_pkthdr.len, 96977ee030bSHidetoshi Shimokawa mtod(m0, caddr_t)); 97077ee030bSHidetoshi Shimokawa m0->m_len = m0->m_pkthdr.len = 9712b4601d1SHidetoshi Shimokawa xfer->mbuf->m_pkthdr.len; 9722b4601d1SHidetoshi Shimokawa m_freem(xfer->mbuf); 97377ee030bSHidetoshi Shimokawa xfer->mbuf = m0; 9742b4601d1SHidetoshi Shimokawa goto again; 9752b4601d1SHidetoshi Shimokawa } 9762b4601d1SHidetoshi Shimokawa device_printf(sc->fc.dev, "m_getcl failed.\n"); 9772b4601d1SHidetoshi Shimokawa } 9783c60ba66SKatsushi Kobayashi } 97977ee030bSHidetoshi Shimokawa if (err) 98077ee030bSHidetoshi Shimokawa printf("dmamap_load: err=%d\n", err); 98177ee030bSHidetoshi Shimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 98277ee030bSHidetoshi Shimokawa BUS_DMASYNC_PREWRITE); 98377ee030bSHidetoshi Shimokawa #if 0 /* OHCI_OUTPUT_MODE == 0 */ 98477ee030bSHidetoshi Shimokawa for (i = 2; i < db_tr->dbcnt; i++) 98577ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd, 98677ee030bSHidetoshi Shimokawa OHCI_OUTPUT_MORE); 98777ee030bSHidetoshi Shimokawa #endif 988d6105b60SHidetoshi Shimokawa } 989d6105b60SHidetoshi Shimokawa if (maxdesc < db_tr->dbcnt) { 990d6105b60SHidetoshi Shimokawa maxdesc = db_tr->dbcnt; 991f9d9941fSHidetoshi Shimokawa if (firewire_debug) 9923042cc43SSean Bruno device_printf(sc->fc.dev, "%s: maxdesc %d\n", __func__, maxdesc); 993d6105b60SHidetoshi Shimokawa } 9943c60ba66SKatsushi Kobayashi /* last db */ 9953c60ba66SKatsushi Kobayashi LAST_DB(db_tr, db); 99677ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db->db.desc.cmd, 99777ee030bSHidetoshi Shimokawa OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 99877ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.depend, 99977ee030bSHidetoshi Shimokawa STAILQ_NEXT(db_tr, link)->bus_addr); 10003c60ba66SKatsushi Kobayashi 10013c60ba66SKatsushi Kobayashi if (fsegment == -1) 10023c60ba66SKatsushi Kobayashi fsegment = db_tr->dbcnt; 10033c60ba66SKatsushi Kobayashi if (dbch->pdb_tr != NULL) { 10043c60ba66SKatsushi Kobayashi LAST_DB(dbch->pdb_tr, db); 100577ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt); 10063c60ba66SKatsushi Kobayashi } 10079950b741SHidetoshi Shimokawa dbch->xferq.queued++; 10083c60ba66SKatsushi Kobayashi dbch->pdb_tr = db_tr; 10093c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 10103c60ba66SKatsushi Kobayashi if (db_tr != dbch->bottom) { 10113c60ba66SKatsushi Kobayashi goto txloop; 10123c60ba66SKatsushi Kobayashi } else { 101317c3d42cSHidetoshi Shimokawa device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n"); 10143c60ba66SKatsushi Kobayashi dbch->flags |= FWOHCI_DBCH_FULL; 10153c60ba66SKatsushi Kobayashi } 10163c60ba66SKatsushi Kobayashi kick: 10173c60ba66SKatsushi Kobayashi /* kick asy q */ 101877ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 101977ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 10203c60ba66SKatsushi Kobayashi 10213c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_RUNNING) { 10223c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 10233c60ba66SKatsushi Kobayashi } else { 1024f9d9941fSHidetoshi Shimokawa if (firewire_debug) 102517c3d42cSHidetoshi Shimokawa device_printf(sc->fc.dev, "start AT DMA status=%x\n", 10263c60ba66SKatsushi Kobayashi OREAD(sc, OHCI_DMACTL(off))); 102777ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment); 10283c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 10293c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 10303c60ba66SKatsushi Kobayashi } 1031c572b810SHidetoshi Shimokawa 10323c60ba66SKatsushi Kobayashi dbch->top = db_tr; 10333c60ba66SKatsushi Kobayashi splx(s); 10343c60ba66SKatsushi Kobayashi return; 10353c60ba66SKatsushi Kobayashi } 1036c572b810SHidetoshi Shimokawa 1037c572b810SHidetoshi Shimokawa static void 1038c572b810SHidetoshi Shimokawa fwohci_start_atq(struct firewire_comm *fc) 10393c60ba66SKatsushi Kobayashi { 10403c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 10419950b741SHidetoshi Shimokawa FW_GLOCK(&sc->fc); 10423c60ba66SKatsushi Kobayashi fwohci_start(sc, &(sc->atrq)); 10439950b741SHidetoshi Shimokawa FW_GUNLOCK(&sc->fc); 10443c60ba66SKatsushi Kobayashi return; 10453c60ba66SKatsushi Kobayashi } 1046c572b810SHidetoshi Shimokawa 1047c572b810SHidetoshi Shimokawa static void 1048c572b810SHidetoshi Shimokawa fwohci_start_ats(struct firewire_comm *fc) 10493c60ba66SKatsushi Kobayashi { 10503c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 10519950b741SHidetoshi Shimokawa FW_GLOCK(&sc->fc); 10523c60ba66SKatsushi Kobayashi fwohci_start(sc, &(sc->atrs)); 10539950b741SHidetoshi Shimokawa FW_GUNLOCK(&sc->fc); 10543c60ba66SKatsushi Kobayashi return; 10553c60ba66SKatsushi Kobayashi } 1056c572b810SHidetoshi Shimokawa 1057c572b810SHidetoshi Shimokawa void 1058c572b810SHidetoshi Shimokawa fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 10593c60ba66SKatsushi Kobayashi { 106077ee030bSHidetoshi Shimokawa int s, ch, err = 0; 10613c60ba66SKatsushi Kobayashi struct fwohcidb_tr *tr; 1062c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 10633c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 106403161bbcSDoug Rabson uint32_t off; 106577ee030bSHidetoshi Shimokawa u_int stat, status; 10663c60ba66SKatsushi Kobayashi int packets; 10673c60ba66SKatsushi Kobayashi struct firewire_comm *fc = (struct firewire_comm *)sc; 106877ee030bSHidetoshi Shimokawa 10693c60ba66SKatsushi Kobayashi if (&sc->atrq == dbch) { 10703c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 107177ee030bSHidetoshi Shimokawa ch = ATRQ_CH; 10723c60ba66SKatsushi Kobayashi } else if (&sc->atrs == dbch) { 10733c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 107477ee030bSHidetoshi Shimokawa ch = ATRS_CH; 10753c60ba66SKatsushi Kobayashi } else { 10763c60ba66SKatsushi Kobayashi return; 10773c60ba66SKatsushi Kobayashi } 10783c60ba66SKatsushi Kobayashi s = splfw(); 10793c60ba66SKatsushi Kobayashi tr = dbch->bottom; 10803c60ba66SKatsushi Kobayashi packets = 0; 108177ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 108277ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 10833c60ba66SKatsushi Kobayashi while (dbch->xferq.queued > 0) { 10843c60ba66SKatsushi Kobayashi LAST_DB(tr, db); 108577ee030bSHidetoshi Shimokawa status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT; 108677ee030bSHidetoshi Shimokawa if (!(status & OHCI_CNTL_DMA_ACTIVE)) { 10877acf6963SHidetoshi Shimokawa if (fc->status != FWBUSINIT) 10883c60ba66SKatsushi Kobayashi /* maybe out of order?? */ 10893c60ba66SKatsushi Kobayashi goto out; 10903c60ba66SKatsushi Kobayashi } 109177ee030bSHidetoshi Shimokawa bus_dmamap_sync(dbch->dmat, tr->dma_map, 109277ee030bSHidetoshi Shimokawa BUS_DMASYNC_POSTWRITE); 109377ee030bSHidetoshi Shimokawa bus_dmamap_unload(dbch->dmat, tr->dma_map); 1094a1c9e73aSHidetoshi Shimokawa #if 1 1095ac447782SHidetoshi Shimokawa if (firewire_debug > 1) 10963c60ba66SKatsushi Kobayashi dump_db(sc, ch); 10973c60ba66SKatsushi Kobayashi #endif 109877ee030bSHidetoshi Shimokawa if (status & OHCI_CNTL_DMA_DEAD) { 10993c60ba66SKatsushi Kobayashi /* Stop DMA */ 11003c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 11013c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "force reset AT FIFO\n"); 11023c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN); 11033c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN); 11043c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 11053c60ba66SKatsushi Kobayashi } 110677ee030bSHidetoshi Shimokawa stat = status & FWOHCIEV_MASK; 11073c60ba66SKatsushi Kobayashi switch (stat) { 11083c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKPEND: 1109864d7e72SHidetoshi Shimokawa case FWOHCIEV_ACKCOMPL: 11103c60ba66SKatsushi Kobayashi err = 0; 11113c60ba66SKatsushi Kobayashi break; 11123c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSA: 11133c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSB: 11143c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKBSX: 11153c60ba66SKatsushi Kobayashi err = EBUSY; 11163c60ba66SKatsushi Kobayashi break; 11173c60ba66SKatsushi Kobayashi case FWOHCIEV_FLUSHED: 11183c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKTARD: 11193c60ba66SKatsushi Kobayashi err = EAGAIN; 11203c60ba66SKatsushi Kobayashi break; 11213c60ba66SKatsushi Kobayashi case FWOHCIEV_MISSACK: 11223c60ba66SKatsushi Kobayashi case FWOHCIEV_UNDRRUN: 11233c60ba66SKatsushi Kobayashi case FWOHCIEV_OVRRUN: 11243c60ba66SKatsushi Kobayashi case FWOHCIEV_DESCERR: 11253c60ba66SKatsushi Kobayashi case FWOHCIEV_DTRDERR: 11263c60ba66SKatsushi Kobayashi case FWOHCIEV_TIMEOUT: 11273c60ba66SKatsushi Kobayashi case FWOHCIEV_TCODERR: 11283c60ba66SKatsushi Kobayashi case FWOHCIEV_UNKNOWN: 11293c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKDERR: 11303c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKTERR: 11313c60ba66SKatsushi Kobayashi default: 11323c60ba66SKatsushi Kobayashi err = EINVAL; 11333c60ba66SKatsushi Kobayashi break; 11343c60ba66SKatsushi Kobayashi } 11353c60ba66SKatsushi Kobayashi if (tr->xfer != NULL) { 11363c60ba66SKatsushi Kobayashi xfer = tr->xfer; 11379950b741SHidetoshi Shimokawa if (xfer->flag & FWXF_RCVD) { 11381a753700SHidetoshi Shimokawa #if 0 113977ee030bSHidetoshi Shimokawa if (firewire_debug) 114077ee030bSHidetoshi Shimokawa printf("already rcvd\n"); 11411a753700SHidetoshi Shimokawa #endif 114277ee030bSHidetoshi Shimokawa fw_xfer_done(xfer); 114377ee030bSHidetoshi Shimokawa } else { 1144c59557f5SHidetoshi Shimokawa microtime(&xfer->tv); 11459950b741SHidetoshi Shimokawa xfer->flag = FWXF_SENT; 11467acf6963SHidetoshi Shimokawa if (err == EBUSY) { 11479950b741SHidetoshi Shimokawa xfer->flag = FWXF_BUSY; 11483c60ba66SKatsushi Kobayashi xfer->resp = err; 1149c4778b5dSHidetoshi Shimokawa xfer->recv.pay_len = 0; 1150864d7e72SHidetoshi Shimokawa fw_xfer_done(xfer); 11513c60ba66SKatsushi Kobayashi } else if (stat != FWOHCIEV_ACKPEND) { 11523c60ba66SKatsushi Kobayashi if (stat != FWOHCIEV_ACKCOMPL) 11539950b741SHidetoshi Shimokawa xfer->flag = FWXF_SENTERR; 11543c60ba66SKatsushi Kobayashi xfer->resp = err; 1155c4778b5dSHidetoshi Shimokawa xfer->recv.pay_len = 0; 11563c60ba66SKatsushi Kobayashi fw_xfer_done(xfer); 11573c60ba66SKatsushi Kobayashi } 11583c60ba66SKatsushi Kobayashi } 1159864d7e72SHidetoshi Shimokawa /* 1160864d7e72SHidetoshi Shimokawa * The watchdog timer takes care of split 116123667f08SAlexander Kabaev * transaction timeout for ACKPEND case. 1162864d7e72SHidetoshi Shimokawa */ 116377ee030bSHidetoshi Shimokawa } else { 116477ee030bSHidetoshi Shimokawa printf("this shouldn't happen\n"); 11653c60ba66SKatsushi Kobayashi } 11669950b741SHidetoshi Shimokawa FW_GLOCK(fc); 116748249fe0SHidetoshi Shimokawa dbch->xferq.queued--; 11689950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 11693c60ba66SKatsushi Kobayashi tr->xfer = NULL; 11703c60ba66SKatsushi Kobayashi 11713c60ba66SKatsushi Kobayashi packets++; 11723c60ba66SKatsushi Kobayashi tr = STAILQ_NEXT(tr, link); 11733c60ba66SKatsushi Kobayashi dbch->bottom = tr; 11743b79dd16SHidetoshi Shimokawa if (dbch->bottom == dbch->top) { 11753b79dd16SHidetoshi Shimokawa /* we reaches the end of context program */ 11763b79dd16SHidetoshi Shimokawa if (firewire_debug && dbch->xferq.queued > 0) 11773b79dd16SHidetoshi Shimokawa printf("queued > 0\n"); 11783b79dd16SHidetoshi Shimokawa break; 11793b79dd16SHidetoshi Shimokawa } 11803c60ba66SKatsushi Kobayashi } 11813c60ba66SKatsushi Kobayashi out: 11823c60ba66SKatsushi Kobayashi if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { 11833c60ba66SKatsushi Kobayashi printf("make free slot\n"); 11843c60ba66SKatsushi Kobayashi dbch->flags &= ~FWOHCI_DBCH_FULL; 11859950b741SHidetoshi Shimokawa FW_GLOCK(fc); 11863c60ba66SKatsushi Kobayashi fwohci_start(sc, dbch); 11879950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 11883c60ba66SKatsushi Kobayashi } 11893c60ba66SKatsushi Kobayashi splx(s); 11903c60ba66SKatsushi Kobayashi } 1191c572b810SHidetoshi Shimokawa 1192c572b810SHidetoshi Shimokawa static void 1193c572b810SHidetoshi Shimokawa fwohci_db_free(struct fwohci_dbch *dbch) 11943c60ba66SKatsushi Kobayashi { 11953c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 119677ee030bSHidetoshi Shimokawa int idb; 11973c60ba66SKatsushi Kobayashi 11981f2361f8SHidetoshi Shimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 11991f2361f8SHidetoshi Shimokawa return; 12001f2361f8SHidetoshi Shimokawa 120177ee030bSHidetoshi Shimokawa for (db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb; 12023c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link), idb++) { 120377ee030bSHidetoshi Shimokawa if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 && 120477ee030bSHidetoshi Shimokawa db_tr->buf != NULL) { 120577ee030bSHidetoshi Shimokawa fwdma_free_size(dbch->dmat, db_tr->dma_map, 120677ee030bSHidetoshi Shimokawa db_tr->buf, dbch->xferq.psize); 12073c60ba66SKatsushi Kobayashi db_tr->buf = NULL; 120877ee030bSHidetoshi Shimokawa } else if (db_tr->dma_map != NULL) 120977ee030bSHidetoshi Shimokawa bus_dmamap_destroy(dbch->dmat, db_tr->dma_map); 12101f2361f8SHidetoshi Shimokawa } 12113c60ba66SKatsushi Kobayashi dbch->ndb = 0; 12123c60ba66SKatsushi Kobayashi db_tr = STAILQ_FIRST(&dbch->db_trq); 121377ee030bSHidetoshi Shimokawa fwdma_free_multiseg(dbch->am); 12145166f1dfSHidetoshi Shimokawa free(db_tr, M_FW); 12153c60ba66SKatsushi Kobayashi STAILQ_INIT(&dbch->db_trq); 12161f2361f8SHidetoshi Shimokawa dbch->flags &= ~FWOHCI_DBCH_INIT; 12173c60ba66SKatsushi Kobayashi } 1218c572b810SHidetoshi Shimokawa 1219c572b810SHidetoshi Shimokawa static void 122077ee030bSHidetoshi Shimokawa fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 12213c60ba66SKatsushi Kobayashi { 12223c60ba66SKatsushi Kobayashi int idb; 12233c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 12249339321dSHidetoshi Shimokawa 12259339321dSHidetoshi Shimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) != 0) 12269339321dSHidetoshi Shimokawa goto out; 12279339321dSHidetoshi Shimokawa 122877ee030bSHidetoshi Shimokawa /* create dma_tag for buffers */ 122977ee030bSHidetoshi Shimokawa #define MAX_REQCOUNT 0xffff 123077ee030bSHidetoshi Shimokawa if (bus_dma_tag_create(/*parent*/ sc->fc.dmat, 123177ee030bSHidetoshi Shimokawa /*alignment*/ 1, /*boundary*/ 0, 123277ee030bSHidetoshi Shimokawa /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 123377ee030bSHidetoshi Shimokawa /*highaddr*/ BUS_SPACE_MAXADDR, 123477ee030bSHidetoshi Shimokawa /*filter*/NULL, /*filterarg*/NULL, 123577ee030bSHidetoshi Shimokawa /*maxsize*/ dbch->xferq.psize, 123677ee030bSHidetoshi Shimokawa /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1, 123777ee030bSHidetoshi Shimokawa /*maxsegsz*/ MAX_REQCOUNT, 1238f6b1c44dSScott Long /*flags*/ 0, 1239f6b1c44dSScott Long /*lockfunc*/busdma_lock_mutex, 12409950b741SHidetoshi Shimokawa /*lockarg*/FW_GMTX(&sc->fc), 12414f933468SHidetoshi Shimokawa &dbch->dmat)) 124277ee030bSHidetoshi Shimokawa return; 124377ee030bSHidetoshi Shimokawa 12443c60ba66SKatsushi Kobayashi /* allocate DB entries and attach one to each DMA channels */ 12453c60ba66SKatsushi Kobayashi /* DB entry must start at 16 bytes bounary. */ 12463c60ba66SKatsushi Kobayashi STAILQ_INIT(&dbch->db_trq); 12473c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *) 12483c60ba66SKatsushi Kobayashi malloc(sizeof(struct fwohcidb_tr) * dbch->ndb, 124977ee030bSHidetoshi Shimokawa M_FW, M_WAITOK | M_ZERO); 12503c60ba66SKatsushi Kobayashi if (db_tr == NULL) { 1251e2ad5d6eSHidetoshi Shimokawa printf("fwohci_db_init: malloc(1) failed\n"); 12523c60ba66SKatsushi Kobayashi return; 12533c60ba66SKatsushi Kobayashi } 1254e2ad5d6eSHidetoshi Shimokawa 125577ee030bSHidetoshi Shimokawa #define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc) 1256*1ade5ec7SAlexander Kabaev dbch->am = fwdma_malloc_multiseg(&sc->fc, sizeof(struct fwohcidb), 125777ee030bSHidetoshi Shimokawa DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK); 125877ee030bSHidetoshi Shimokawa if (dbch->am == NULL) { 125977ee030bSHidetoshi Shimokawa printf("fwohci_db_init: fwdma_malloc_multiseg failed\n"); 12604c790222SHidetoshi Shimokawa free(db_tr, M_FW); 1261e2ad5d6eSHidetoshi Shimokawa return; 1262e2ad5d6eSHidetoshi Shimokawa } 12633c60ba66SKatsushi Kobayashi /* Attach DB to DMA ch. */ 12643c60ba66SKatsushi Kobayashi for (idb = 0; idb < dbch->ndb; idb++) { 12653c60ba66SKatsushi Kobayashi db_tr->dbcnt = 0; 126677ee030bSHidetoshi Shimokawa db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb); 126777ee030bSHidetoshi Shimokawa db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb); 126877ee030bSHidetoshi Shimokawa /* create dmamap for buffers */ 126977ee030bSHidetoshi Shimokawa /* XXX do we need 4bytes alignment tag? */ 127077ee030bSHidetoshi Shimokawa /* XXX don't alloc dma_map for AR */ 127177ee030bSHidetoshi Shimokawa if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) { 127277ee030bSHidetoshi Shimokawa printf("bus_dmamap_create failed\n"); 127377ee030bSHidetoshi Shimokawa dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */ 127477ee030bSHidetoshi Shimokawa fwohci_db_free(dbch); 127577ee030bSHidetoshi Shimokawa return; 127677ee030bSHidetoshi Shimokawa } 12773c60ba66SKatsushi Kobayashi STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); 127877ee030bSHidetoshi Shimokawa if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1279d0fd7bc6SHidetoshi Shimokawa if (idb % dbch->xferq.bnpacket == 0) 1280d0fd7bc6SHidetoshi Shimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1281d0fd7bc6SHidetoshi Shimokawa ].start = (caddr_t)db_tr; 1282d0fd7bc6SHidetoshi Shimokawa if ((idb + 1) % dbch->xferq.bnpacket == 0) 1283d0fd7bc6SHidetoshi Shimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1284d0fd7bc6SHidetoshi Shimokawa ].end = (caddr_t)db_tr; 12853c60ba66SKatsushi Kobayashi } 12863c60ba66SKatsushi Kobayashi db_tr++; 12873c60ba66SKatsushi Kobayashi } 12883c60ba66SKatsushi Kobayashi STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next 12893c60ba66SKatsushi Kobayashi = STAILQ_FIRST(&dbch->db_trq); 12909339321dSHidetoshi Shimokawa out: 12919339321dSHidetoshi Shimokawa dbch->xferq.queued = 0; 12929339321dSHidetoshi Shimokawa dbch->pdb_tr = NULL; 12933c60ba66SKatsushi Kobayashi dbch->top = STAILQ_FIRST(&dbch->db_trq); 12943c60ba66SKatsushi Kobayashi dbch->bottom = dbch->top; 12951f2361f8SHidetoshi Shimokawa dbch->flags = FWOHCI_DBCH_INIT; 12963c60ba66SKatsushi Kobayashi } 1297c572b810SHidetoshi Shimokawa 1298c572b810SHidetoshi Shimokawa static int 1299c572b810SHidetoshi Shimokawa fwohci_itx_disable(struct firewire_comm *fc, int dmach) 13003c60ba66SKatsushi Kobayashi { 13013c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 13025a7ba74dSHidetoshi Shimokawa 130377ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), 130477ee030bSHidetoshi Shimokawa OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S); 13053c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 13063c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 13075a7ba74dSHidetoshi Shimokawa /* XXX we cannot free buffers until the DMA really stops */ 13084d70511aSJohn Baldwin pause("fwitxd", hz); 13093c60ba66SKatsushi Kobayashi fwohci_db_free(&sc->it[dmach]); 13103c60ba66SKatsushi Kobayashi sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 13113c60ba66SKatsushi Kobayashi return 0; 13123c60ba66SKatsushi Kobayashi } 1313c572b810SHidetoshi Shimokawa 1314c572b810SHidetoshi Shimokawa static int 1315c572b810SHidetoshi Shimokawa fwohci_irx_disable(struct firewire_comm *fc, int dmach) 13163c60ba66SKatsushi Kobayashi { 13173c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 13183c60ba66SKatsushi Kobayashi 13193c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 13203c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 13213c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 13225a7ba74dSHidetoshi Shimokawa /* XXX we cannot free buffers until the DMA really stops */ 13234d70511aSJohn Baldwin pause("fwirxd", hz); 13243c60ba66SKatsushi Kobayashi fwohci_db_free(&sc->ir[dmach]); 13253c60ba66SKatsushi Kobayashi sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 13263c60ba66SKatsushi Kobayashi return 0; 13273c60ba66SKatsushi Kobayashi } 1328c572b810SHidetoshi Shimokawa 132977ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 1330c572b810SHidetoshi Shimokawa static void 133103161bbcSDoug Rabson fwohci_irx_post (struct firewire_comm *fc , uint32_t *qld) 13323c60ba66SKatsushi Kobayashi { 133377ee030bSHidetoshi Shimokawa qld[0] = FWOHCI_DMA_READ(qld[0]); 13343c60ba66SKatsushi Kobayashi return; 13353c60ba66SKatsushi Kobayashi } 13363c60ba66SKatsushi Kobayashi #endif 13373c60ba66SKatsushi Kobayashi 1338c572b810SHidetoshi Shimokawa static int 1339c572b810SHidetoshi Shimokawa fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 13403c60ba66SKatsushi Kobayashi { 13413c60ba66SKatsushi Kobayashi int err = 0; 134277ee030bSHidetoshi Shimokawa int idb, z, i, dmach = 0, ldesc; 134303161bbcSDoug Rabson uint32_t off = 0; 13443c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 1345c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 13463c60ba66SKatsushi Kobayashi 13473c60ba66SKatsushi Kobayashi if (!(dbch->xferq.flag & FWXFERQ_EXTBUF)) { 13483c60ba66SKatsushi Kobayashi err = EINVAL; 13493c60ba66SKatsushi Kobayashi return err; 13503c60ba66SKatsushi Kobayashi } 13513c60ba66SKatsushi Kobayashi z = dbch->ndesc; 13523c60ba66SKatsushi Kobayashi for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 13533c60ba66SKatsushi Kobayashi if (&sc->it[dmach] == dbch) { 13543c60ba66SKatsushi Kobayashi off = OHCI_ITOFF(dmach); 13553c60ba66SKatsushi Kobayashi break; 13563c60ba66SKatsushi Kobayashi } 13573c60ba66SKatsushi Kobayashi } 1358a89ec05eSPeter Wemm if (off == 0) { 13593c60ba66SKatsushi Kobayashi err = EINVAL; 13603c60ba66SKatsushi Kobayashi return err; 13613c60ba66SKatsushi Kobayashi } 13623c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_RUNNING) 13633c60ba66SKatsushi Kobayashi return err; 13643c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 13653c60ba66SKatsushi Kobayashi for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 13663c60ba66SKatsushi Kobayashi dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 13673c60ba66SKatsushi Kobayashi } 13683c60ba66SKatsushi Kobayashi db_tr = dbch->top; 13693c60ba66SKatsushi Kobayashi for (idb = 0; idb < dbch->ndb; idb++) { 137077ee030bSHidetoshi Shimokawa fwohci_add_tx_buf(dbch, db_tr, idb); 13713c60ba66SKatsushi Kobayashi if (STAILQ_NEXT(db_tr, link) == NULL) { 13723c60ba66SKatsushi Kobayashi break; 13733c60ba66SKatsushi Kobayashi } 137453f1eb86SHidetoshi Shimokawa db = db_tr->db; 137577ee030bSHidetoshi Shimokawa ldesc = db_tr->dbcnt - 1; 137677ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[0].db.desc.depend, 137777ee030bSHidetoshi Shimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 137877ee030bSHidetoshi Shimokawa db[ldesc].db.desc.depend = db[0].db.desc.depend; 13793c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 13803c60ba66SKatsushi Kobayashi if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 138177ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET( 138277ee030bSHidetoshi Shimokawa db[ldesc].db.desc.cmd, 138377ee030bSHidetoshi Shimokawa OHCI_INTERRUPT_ALWAYS); 13844ed65ce9SHidetoshi Shimokawa /* OHCI 1.1 and above */ 138577ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET( 138677ee030bSHidetoshi Shimokawa db[0].db.desc.cmd, 138777ee030bSHidetoshi Shimokawa OHCI_INTERRUPT_ALWAYS); 13883c60ba66SKatsushi Kobayashi } 13893c60ba66SKatsushi Kobayashi } 13903c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 13913c60ba66SKatsushi Kobayashi } 139277ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR( 139377ee030bSHidetoshi Shimokawa dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf); 13943c60ba66SKatsushi Kobayashi return err; 13953c60ba66SKatsushi Kobayashi } 1396c572b810SHidetoshi Shimokawa 1397c572b810SHidetoshi Shimokawa static int 1398c572b810SHidetoshi Shimokawa fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 13993c60ba66SKatsushi Kobayashi { 14003c60ba66SKatsushi Kobayashi int err = 0; 140153f1eb86SHidetoshi Shimokawa int idb, z, i, dmach = 0, ldesc; 140203161bbcSDoug Rabson uint32_t off = 0; 14033c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 1404c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 14053c60ba66SKatsushi Kobayashi 14063c60ba66SKatsushi Kobayashi z = dbch->ndesc; 14073c60ba66SKatsushi Kobayashi if (&sc->arrq == dbch) { 14083c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 14093c60ba66SKatsushi Kobayashi } else if (&sc->arrs == dbch) { 14103c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 14113c60ba66SKatsushi Kobayashi } else { 14123c60ba66SKatsushi Kobayashi for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 14133c60ba66SKatsushi Kobayashi if (&sc->ir[dmach] == dbch) { 14143c60ba66SKatsushi Kobayashi off = OHCI_IROFF(dmach); 14153c60ba66SKatsushi Kobayashi break; 14163c60ba66SKatsushi Kobayashi } 14173c60ba66SKatsushi Kobayashi } 14183c60ba66SKatsushi Kobayashi } 1419a89ec05eSPeter Wemm if (off == 0) { 14203c60ba66SKatsushi Kobayashi err = EINVAL; 14213c60ba66SKatsushi Kobayashi return err; 14223c60ba66SKatsushi Kobayashi } 14233c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_STREAM) { 14243c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_RUNNING) 14253c60ba66SKatsushi Kobayashi return err; 14263c60ba66SKatsushi Kobayashi } else { 14273c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_RUNNING) { 14283c60ba66SKatsushi Kobayashi err = EBUSY; 14293c60ba66SKatsushi Kobayashi return err; 14303c60ba66SKatsushi Kobayashi } 14313c60ba66SKatsushi Kobayashi } 14323c60ba66SKatsushi Kobayashi dbch->xferq.flag |= FWXFERQ_RUNNING; 14339339321dSHidetoshi Shimokawa dbch->top = STAILQ_FIRST(&dbch->db_trq); 14343c60ba66SKatsushi Kobayashi for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 14353c60ba66SKatsushi Kobayashi dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 14363c60ba66SKatsushi Kobayashi } 14373c60ba66SKatsushi Kobayashi db_tr = dbch->top; 14383c60ba66SKatsushi Kobayashi for (idb = 0; idb < dbch->ndb; idb++) { 143977ee030bSHidetoshi Shimokawa fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma); 144077ee030bSHidetoshi Shimokawa if (STAILQ_NEXT(db_tr, link) == NULL) 14413c60ba66SKatsushi Kobayashi break; 144253f1eb86SHidetoshi Shimokawa db = db_tr->db; 144353f1eb86SHidetoshi Shimokawa ldesc = db_tr->dbcnt - 1; 144477ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend, 144577ee030bSHidetoshi Shimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 14463c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 14473c60ba66SKatsushi Kobayashi if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 144877ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET( 144977ee030bSHidetoshi Shimokawa db[ldesc].db.desc.cmd, 145077ee030bSHidetoshi Shimokawa OHCI_INTERRUPT_ALWAYS); 145177ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR( 145277ee030bSHidetoshi Shimokawa db[ldesc].db.desc.depend, 145377ee030bSHidetoshi Shimokawa 0xf); 14543c60ba66SKatsushi Kobayashi } 14553c60ba66SKatsushi Kobayashi } 14563c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 14573c60ba66SKatsushi Kobayashi } 145877ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR( 145977ee030bSHidetoshi Shimokawa dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf); 14603c60ba66SKatsushi Kobayashi dbch->buf_offset = 0; 146177ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 146277ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 14633c60ba66SKatsushi Kobayashi if (dbch->xferq.flag & FWXFERQ_STREAM) { 14643c60ba66SKatsushi Kobayashi return err; 14653c60ba66SKatsushi Kobayashi } else { 146677ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z); 14673c60ba66SKatsushi Kobayashi } 14683c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 14693c60ba66SKatsushi Kobayashi return err; 14703c60ba66SKatsushi Kobayashi } 1471c572b810SHidetoshi Shimokawa 1472c572b810SHidetoshi Shimokawa static int 147377ee030bSHidetoshi Shimokawa fwohci_next_cycle(struct firewire_comm *fc, int cycle_now) 14743c60ba66SKatsushi Kobayashi { 14755a7ba74dSHidetoshi Shimokawa int sec, cycle, cycle_match; 14763c60ba66SKatsushi Kobayashi 147797ae6c1fSHidetoshi Shimokawa cycle = cycle_now & 0x1fff; 147897ae6c1fSHidetoshi Shimokawa sec = cycle_now >> 13; 147997ae6c1fSHidetoshi Shimokawa #define CYCLE_MOD 0x10 148077ee030bSHidetoshi Shimokawa #if 1 148197ae6c1fSHidetoshi Shimokawa #define CYCLE_DELAY 8 /* min delay to start DMA */ 148277ee030bSHidetoshi Shimokawa #else 148377ee030bSHidetoshi Shimokawa #define CYCLE_DELAY 7000 /* min delay to start DMA */ 148477ee030bSHidetoshi Shimokawa #endif 148597ae6c1fSHidetoshi Shimokawa cycle = cycle + CYCLE_DELAY; 148697ae6c1fSHidetoshi Shimokawa if (cycle >= 8000) { 148797ae6c1fSHidetoshi Shimokawa sec++; 148897ae6c1fSHidetoshi Shimokawa cycle -= 8000; 148997ae6c1fSHidetoshi Shimokawa } 149077ee030bSHidetoshi Shimokawa cycle = roundup2(cycle, CYCLE_MOD); 149197ae6c1fSHidetoshi Shimokawa if (cycle >= 8000) { 149297ae6c1fSHidetoshi Shimokawa sec++; 149397ae6c1fSHidetoshi Shimokawa if (cycle == 8000) 149497ae6c1fSHidetoshi Shimokawa cycle = 0; 149597ae6c1fSHidetoshi Shimokawa else 149697ae6c1fSHidetoshi Shimokawa cycle = CYCLE_MOD; 149797ae6c1fSHidetoshi Shimokawa } 149897ae6c1fSHidetoshi Shimokawa cycle_match = ((sec << 13) | cycle) & 0x7ffff; 14995a7ba74dSHidetoshi Shimokawa 15005a7ba74dSHidetoshi Shimokawa return (cycle_match); 15015a7ba74dSHidetoshi Shimokawa } 15025a7ba74dSHidetoshi Shimokawa 15035a7ba74dSHidetoshi Shimokawa static int 15045a7ba74dSHidetoshi Shimokawa fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) 15055a7ba74dSHidetoshi Shimokawa { 15065a7ba74dSHidetoshi Shimokawa struct fwohci_softc *sc = (struct fwohci_softc *)fc; 15075a7ba74dSHidetoshi Shimokawa int err = 0; 15085a7ba74dSHidetoshi Shimokawa unsigned short tag, ich; 15095a7ba74dSHidetoshi Shimokawa struct fwohci_dbch *dbch; 15105a7ba74dSHidetoshi Shimokawa int cycle_match, cycle_now, s, ldesc; 151103161bbcSDoug Rabson uint32_t stat; 15125a7ba74dSHidetoshi Shimokawa struct fw_bulkxfer *first, *chunk, *prev; 15135a7ba74dSHidetoshi Shimokawa struct fw_xferq *it; 15145a7ba74dSHidetoshi Shimokawa 15155a7ba74dSHidetoshi Shimokawa dbch = &sc->it[dmach]; 15165a7ba74dSHidetoshi Shimokawa it = &dbch->xferq; 15175a7ba74dSHidetoshi Shimokawa 15185a7ba74dSHidetoshi Shimokawa tag = (it->flag >> 6) & 3; 15195a7ba74dSHidetoshi Shimokawa ich = it->flag & 0x3f; 15205a7ba74dSHidetoshi Shimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { 15215a7ba74dSHidetoshi Shimokawa dbch->ndb = it->bnpacket * it->bnchunk; 15225a7ba74dSHidetoshi Shimokawa dbch->ndesc = 3; 152377ee030bSHidetoshi Shimokawa fwohci_db_init(sc, dbch); 15245a7ba74dSHidetoshi Shimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 15255a7ba74dSHidetoshi Shimokawa return ENOMEM; 15269950b741SHidetoshi Shimokawa 15275a7ba74dSHidetoshi Shimokawa err = fwohci_tx_enable(sc, dbch); 15285a7ba74dSHidetoshi Shimokawa } 15295a7ba74dSHidetoshi Shimokawa if (err) 15305a7ba74dSHidetoshi Shimokawa return err; 15315a7ba74dSHidetoshi Shimokawa 153253f1eb86SHidetoshi Shimokawa ldesc = dbch->ndesc - 1; 15335a7ba74dSHidetoshi Shimokawa s = splfw(); 15349950b741SHidetoshi Shimokawa FW_GLOCK(fc); 15355a7ba74dSHidetoshi Shimokawa prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); 15365a7ba74dSHidetoshi Shimokawa while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { 1537c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 15385a7ba74dSHidetoshi Shimokawa 153977ee030bSHidetoshi Shimokawa fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket, 154077ee030bSHidetoshi Shimokawa BUS_DMASYNC_PREWRITE); 15415a7ba74dSHidetoshi Shimokawa fwohci_txbufdb(sc, dmach, chunk); 15425a7ba74dSHidetoshi Shimokawa if (prev != NULL) { 15435a7ba74dSHidetoshi Shimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 154477ee030bSHidetoshi Shimokawa #if 0 /* XXX necessary? */ 154577ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, 154677ee030bSHidetoshi Shimokawa OHCI_BRANCH_ALWAYS); 154777ee030bSHidetoshi Shimokawa #endif 154853f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npacket changes */ 15495a7ba74dSHidetoshi Shimokawa db[ldesc].db.desc.depend = db[0].db.desc.depend = 155077ee030bSHidetoshi Shimokawa ((struct fwohcidb_tr *) 155177ee030bSHidetoshi Shimokawa (chunk->start))->bus_addr | dbch->ndesc; 155253f1eb86SHidetoshi Shimokawa #else 155377ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 155477ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 155553f1eb86SHidetoshi Shimokawa #endif 15565a7ba74dSHidetoshi Shimokawa } 15575a7ba74dSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&it->stvalid, link); 15585a7ba74dSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&it->stdma, chunk, link); 15595a7ba74dSHidetoshi Shimokawa prev = chunk; 15605a7ba74dSHidetoshi Shimokawa } 15619950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 156277ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 156377ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 15645a7ba74dSHidetoshi Shimokawa splx(s); 15655a7ba74dSHidetoshi Shimokawa stat = OREAD(sc, OHCI_ITCTL(dmach)); 156677ee030bSHidetoshi Shimokawa if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S)) 156777ee030bSHidetoshi Shimokawa printf("stat 0x%x\n", stat); 156877ee030bSHidetoshi Shimokawa 15695a7ba74dSHidetoshi Shimokawa if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) 15705a7ba74dSHidetoshi Shimokawa return 0; 15715a7ba74dSHidetoshi Shimokawa 157277ee030bSHidetoshi Shimokawa #if 0 15735a7ba74dSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 157477ee030bSHidetoshi Shimokawa #endif 15755a7ba74dSHidetoshi Shimokawa OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 15765a7ba74dSHidetoshi Shimokawa OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 15775a7ba74dSHidetoshi Shimokawa OWRITE(sc, OHCI_IT_MASK, 1 << dmach); 157877ee030bSHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); 15795a7ba74dSHidetoshi Shimokawa 15805a7ba74dSHidetoshi Shimokawa first = STAILQ_FIRST(&it->stdma); 158177ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCMD(dmach), 158277ee030bSHidetoshi Shimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); 1583ac447782SHidetoshi Shimokawa if (firewire_debug > 1) { 15845a7ba74dSHidetoshi Shimokawa printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); 158577ee030bSHidetoshi Shimokawa #if 1 158677ee030bSHidetoshi Shimokawa dump_dma(sc, ITX_CH + dmach); 158777ee030bSHidetoshi Shimokawa #endif 158877ee030bSHidetoshi Shimokawa } 15895a7ba74dSHidetoshi Shimokawa if ((stat & OHCI_CNTL_DMA_RUN) == 0) { 15905a7ba74dSHidetoshi Shimokawa #if 1 15915a7ba74dSHidetoshi Shimokawa /* Don't start until all chunks are buffered */ 15925a7ba74dSHidetoshi Shimokawa if (STAILQ_FIRST(&it->stfree) != NULL) 15935a7ba74dSHidetoshi Shimokawa goto out; 15945a7ba74dSHidetoshi Shimokawa #endif 159577ee030bSHidetoshi Shimokawa #if 1 159697ae6c1fSHidetoshi Shimokawa /* Clear cycle match counter bits */ 159797ae6c1fSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); 15985a7ba74dSHidetoshi Shimokawa 15995a7ba74dSHidetoshi Shimokawa /* 2bit second + 13bit cycle */ 16005a7ba74dSHidetoshi Shimokawa cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; 160177ee030bSHidetoshi Shimokawa cycle_match = fwohci_next_cycle(fc, cycle_now); 16025a7ba74dSHidetoshi Shimokawa 160397ae6c1fSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTL(dmach), 160497ae6c1fSHidetoshi Shimokawa OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) 160597ae6c1fSHidetoshi Shimokawa | OHCI_CNTL_DMA_RUN); 160677ee030bSHidetoshi Shimokawa #else 160777ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); 160877ee030bSHidetoshi Shimokawa #endif 1609ac447782SHidetoshi Shimokawa if (firewire_debug > 1) { 16107643dc18SHidetoshi Shimokawa printf("cycle_match: 0x%04x->0x%04x\n", 16117643dc18SHidetoshi Shimokawa cycle_now, cycle_match); 161277ee030bSHidetoshi Shimokawa dump_dma(sc, ITX_CH + dmach); 161377ee030bSHidetoshi Shimokawa dump_db(sc, ITX_CH + dmach); 161477ee030bSHidetoshi Shimokawa } 16157643dc18SHidetoshi Shimokawa } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { 16165a7ba74dSHidetoshi Shimokawa device_printf(sc->fc.dev, 16175a7ba74dSHidetoshi Shimokawa "IT DMA underrun (0x%08x)\n", stat); 161877ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE); 16193c60ba66SKatsushi Kobayashi } 16205a7ba74dSHidetoshi Shimokawa out: 16213c60ba66SKatsushi Kobayashi return err; 16223c60ba66SKatsushi Kobayashi } 1623c572b810SHidetoshi Shimokawa 1624c572b810SHidetoshi Shimokawa static int 162577ee030bSHidetoshi Shimokawa fwohci_irx_enable(struct firewire_comm *fc, int dmach) 16263c60ba66SKatsushi Kobayashi { 16273c60ba66SKatsushi Kobayashi struct fwohci_softc *sc = (struct fwohci_softc *)fc; 16285a7ba74dSHidetoshi Shimokawa int err = 0, s, ldesc; 16293c60ba66SKatsushi Kobayashi unsigned short tag, ich; 163003161bbcSDoug Rabson uint32_t stat; 16315a7ba74dSHidetoshi Shimokawa struct fwohci_dbch *dbch; 163277ee030bSHidetoshi Shimokawa struct fwohcidb_tr *db_tr; 16335a7ba74dSHidetoshi Shimokawa struct fw_bulkxfer *first, *prev, *chunk; 16345a7ba74dSHidetoshi Shimokawa struct fw_xferq *ir; 1635435dd29bSHidetoshi Shimokawa 16365a7ba74dSHidetoshi Shimokawa dbch = &sc->ir[dmach]; 16375a7ba74dSHidetoshi Shimokawa ir = &dbch->xferq; 16385a7ba74dSHidetoshi Shimokawa 16395a7ba74dSHidetoshi Shimokawa if ((ir->flag & FWXFERQ_RUNNING) == 0) { 16405a7ba74dSHidetoshi Shimokawa tag = (ir->flag >> 6) & 3; 16415a7ba74dSHidetoshi Shimokawa ich = ir->flag & 0x3f; 16423c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 16433c60ba66SKatsushi Kobayashi 16445a7ba74dSHidetoshi Shimokawa ir->queued = 0; 16455a7ba74dSHidetoshi Shimokawa dbch->ndb = ir->bnpacket * ir->bnchunk; 16465a7ba74dSHidetoshi Shimokawa dbch->ndesc = 2; 164777ee030bSHidetoshi Shimokawa fwohci_db_init(sc, dbch); 16485a7ba74dSHidetoshi Shimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 16490aaa9a23SHidetoshi Shimokawa return ENOMEM; 16505a7ba74dSHidetoshi Shimokawa err = fwohci_rx_enable(sc, dbch); 16513c60ba66SKatsushi Kobayashi } 16523c60ba66SKatsushi Kobayashi if (err) 16533c60ba66SKatsushi Kobayashi return err; 16543c60ba66SKatsushi Kobayashi 16555a7ba74dSHidetoshi Shimokawa first = STAILQ_FIRST(&ir->stfree); 16565a7ba74dSHidetoshi Shimokawa if (first == NULL) { 16575a7ba74dSHidetoshi Shimokawa device_printf(fc->dev, "IR DMA no free chunk\n"); 16585a7ba74dSHidetoshi Shimokawa return 0; 16595a7ba74dSHidetoshi Shimokawa } 16605a7ba74dSHidetoshi Shimokawa 16619ca8add3SHidetoshi Shimokawa ldesc = dbch->ndesc - 1; 16629ca8add3SHidetoshi Shimokawa s = splfw(); 16639950b741SHidetoshi Shimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 16649950b741SHidetoshi Shimokawa FW_GLOCK(fc); 16655a7ba74dSHidetoshi Shimokawa prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); 16665a7ba74dSHidetoshi Shimokawa while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { 1667c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 16685a7ba74dSHidetoshi Shimokawa 16692b4601d1SHidetoshi Shimokawa #if 1 /* XXX for if_fwe */ 167077ee030bSHidetoshi Shimokawa if (chunk->mbuf != NULL) { 167177ee030bSHidetoshi Shimokawa db_tr = (struct fwohcidb_tr *)(chunk->start); 167277ee030bSHidetoshi Shimokawa db_tr->dbcnt = 1; 167377ee030bSHidetoshi Shimokawa err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 167477ee030bSHidetoshi Shimokawa chunk->mbuf, fwohci_execute_db2, db_tr, 167577ee030bSHidetoshi Shimokawa /* flags */0); 167677ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd, 167777ee030bSHidetoshi Shimokawa OHCI_UPDATE | OHCI_INPUT_LAST | 167877ee030bSHidetoshi Shimokawa OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 167977ee030bSHidetoshi Shimokawa } 16802b4601d1SHidetoshi Shimokawa #endif 16815a7ba74dSHidetoshi Shimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 168277ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0); 168377ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf); 16845a7ba74dSHidetoshi Shimokawa if (prev != NULL) { 16855a7ba74dSHidetoshi Shimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 168677ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 16875a7ba74dSHidetoshi Shimokawa } 16885a7ba74dSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&ir->stfree, link); 16895a7ba74dSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); 16905a7ba74dSHidetoshi Shimokawa prev = chunk; 16915a7ba74dSHidetoshi Shimokawa } 16929950b741SHidetoshi Shimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 16939950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 169477ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 169577ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 16965a7ba74dSHidetoshi Shimokawa splx(s); 16975a7ba74dSHidetoshi Shimokawa stat = OREAD(sc, OHCI_IRCTL(dmach)); 16985a7ba74dSHidetoshi Shimokawa if (stat & OHCI_CNTL_DMA_ACTIVE) 16995a7ba74dSHidetoshi Shimokawa return 0; 17005a7ba74dSHidetoshi Shimokawa if (stat & OHCI_CNTL_DMA_RUN) { 17013c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 17025a7ba74dSHidetoshi Shimokawa device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); 17035a7ba74dSHidetoshi Shimokawa } 17045a7ba74dSHidetoshi Shimokawa 170577ee030bSHidetoshi Shimokawa if (firewire_debug) 170677ee030bSHidetoshi Shimokawa printf("start IR DMA 0x%x\n", stat); 17073c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 17083c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 17093c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 17103c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); 17113c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 17123c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCMD(dmach), 171377ee030bSHidetoshi Shimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr 17145a7ba74dSHidetoshi Shimokawa | dbch->ndesc); 17153c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 17163c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 171777ee030bSHidetoshi Shimokawa #if 0 171877ee030bSHidetoshi Shimokawa dump_db(sc, IRX_CH + dmach); 171977ee030bSHidetoshi Shimokawa #endif 17203c60ba66SKatsushi Kobayashi return err; 17213c60ba66SKatsushi Kobayashi } 1722c572b810SHidetoshi Shimokawa 1723c572b810SHidetoshi Shimokawa int 172464cf5240SHidetoshi Shimokawa fwohci_stop(struct fwohci_softc *sc, device_t dev) 17253c60ba66SKatsushi Kobayashi { 17263c60ba66SKatsushi Kobayashi u_int i; 17273c60ba66SKatsushi Kobayashi 17285f3fa234SHidetoshi Shimokawa fwohci_set_intr(&sc->fc, 0); 17295f3fa234SHidetoshi Shimokawa 17303c60ba66SKatsushi Kobayashi /* Now stopping all DMA channel */ 17313c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 17323c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 17333c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 17343c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 17353c60ba66SKatsushi Kobayashi 17363c60ba66SKatsushi Kobayashi for (i = 0; i < sc->fc.nisodma; i++) { 17373c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 17383c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 17393c60ba66SKatsushi Kobayashi } 17403c60ba66SKatsushi Kobayashi 17419950b741SHidetoshi Shimokawa #if 0 /* Let dcons(4) be accessed */ 17423c60ba66SKatsushi Kobayashi /* Stop interrupt */ 17433c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, 17443c60ba66SKatsushi Kobayashi OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID 17453c60ba66SKatsushi Kobayashi | OHCI_INT_PHY_INT 17463c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 17473c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 17483c60ba66SKatsushi Kobayashi | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 17493c60ba66SKatsushi Kobayashi | OHCI_INT_PHY_BUS_R); 1750630529adSHidetoshi Shimokawa 17519950b741SHidetoshi Shimokawa /* FLUSH FIFO and reset Transmitter/Reciever */ 17529950b741SHidetoshi Shimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 17539950b741SHidetoshi Shimokawa #endif 1754630529adSHidetoshi Shimokawa 17559339321dSHidetoshi Shimokawa /* XXX Link down? Bus reset? */ 17569339321dSHidetoshi Shimokawa return 0; 17579339321dSHidetoshi Shimokawa } 17589339321dSHidetoshi Shimokawa 17599339321dSHidetoshi Shimokawa int 17609339321dSHidetoshi Shimokawa fwohci_resume(struct fwohci_softc *sc, device_t dev) 17619339321dSHidetoshi Shimokawa { 17629339321dSHidetoshi Shimokawa int i; 1763630529adSHidetoshi Shimokawa struct fw_xferq *ir; 1764630529adSHidetoshi Shimokawa struct fw_bulkxfer *chunk; 17659339321dSHidetoshi Shimokawa 17669339321dSHidetoshi Shimokawa fwohci_reset(sc, dev); 176795a24954SDoug Rabson /* XXX resume isochronous receive automatically. (how about TX?) */ 17689339321dSHidetoshi Shimokawa for (i = 0; i < sc->fc.nisodma; i++) { 1769630529adSHidetoshi Shimokawa ir = &sc->ir[i].xferq; 1770630529adSHidetoshi Shimokawa if ((ir->flag & FWXFERQ_RUNNING) != 0) { 17719339321dSHidetoshi Shimokawa device_printf(sc->fc.dev, 17729339321dSHidetoshi Shimokawa "resume iso receive ch: %d\n", i); 1773630529adSHidetoshi Shimokawa ir->flag &= ~FWXFERQ_RUNNING; 1774630529adSHidetoshi Shimokawa /* requeue stdma to stfree */ 1775630529adSHidetoshi Shimokawa while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 1776630529adSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 1777630529adSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&ir->stfree, chunk, link); 1778630529adSHidetoshi Shimokawa } 17799339321dSHidetoshi Shimokawa sc->fc.irx_enable(&sc->fc, i); 17809339321dSHidetoshi Shimokawa } 17819339321dSHidetoshi Shimokawa } 17829339321dSHidetoshi Shimokawa 17839339321dSHidetoshi Shimokawa bus_generic_resume(dev); 17849339321dSHidetoshi Shimokawa sc->fc.ibr(&sc->fc); 17853c60ba66SKatsushi Kobayashi return 0; 17863c60ba66SKatsushi Kobayashi } 17873c60ba66SKatsushi Kobayashi 17883c60ba66SKatsushi Kobayashi #ifdef OHCI_DEBUG 17899950b741SHidetoshi Shimokawa static void 17909950b741SHidetoshi Shimokawa fwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat) 17919950b741SHidetoshi Shimokawa { 17923c60ba66SKatsushi Kobayashi if (stat & OREAD(sc, FWOHCI_INTMASK)) 17933c60ba66SKatsushi 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", 17943c60ba66SKatsushi Kobayashi stat & OHCI_INT_EN ? "DMA_EN ":"", 17953c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", 17963c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", 17973c60ba66SKatsushi Kobayashi stat & OHCI_INT_ERR ? "INT_ERR ":"", 17983c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", 17993c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", 18003c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", 18013c60ba66SKatsushi Kobayashi stat & OHCI_INT_CYC_START ? "CYC_START ":"", 18023c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", 18033c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", 18043c60ba66SKatsushi Kobayashi stat & OHCI_INT_PHY_SID ? "SID ":"", 18053c60ba66SKatsushi Kobayashi stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", 18063c60ba66SKatsushi Kobayashi stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", 18073c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", 18083c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", 18093c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", 18103c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", 18113c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", 18123c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", 18133c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", 18143c60ba66SKatsushi Kobayashi stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", 18153c60ba66SKatsushi Kobayashi stat, OREAD(sc, FWOHCI_INTMASK) 18163c60ba66SKatsushi Kobayashi ); 18179950b741SHidetoshi Shimokawa } 18183c60ba66SKatsushi Kobayashi #endif 181923667f08SAlexander Kabaev 18209950b741SHidetoshi Shimokawa static void 18219950b741SHidetoshi Shimokawa fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) 18229950b741SHidetoshi Shimokawa { 18239950b741SHidetoshi Shimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 18249950b741SHidetoshi Shimokawa uint32_t node_id, plen; 18259950b741SHidetoshi Shimokawa 18263042cc43SSean Bruno FW_GLOCK_ASSERT(fc); 18279950b741SHidetoshi Shimokawa if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) { 18289950b741SHidetoshi Shimokawa fc->status = FWBUSRESET; 18291adf6842SHidetoshi Shimokawa /* Disable bus reset interrupt until sid recv. */ 18301adf6842SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); 18311adf6842SHidetoshi Shimokawa 1832373d9227SSean Bruno device_printf(fc->dev, "%s: BUS reset\n", __func__); 18333c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 18343c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); 18353c60ba66SKatsushi Kobayashi 18363c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 18373c60ba66SKatsushi Kobayashi sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; 18383c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 18393c60ba66SKatsushi Kobayashi sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; 18403c60ba66SKatsushi Kobayashi 18419950b741SHidetoshi Shimokawa if (!kdb_active) 18429950b741SHidetoshi Shimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset); 1843d0581de8SHidetoshi Shimokawa } 18443c60ba66SKatsushi Kobayashi if (stat & OHCI_INT_PHY_SID) { 18451adf6842SHidetoshi Shimokawa /* Enable bus reset interrupt */ 18469950b741SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); 18471adf6842SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); 18489950b741SHidetoshi Shimokawa 1849dcae7539SHidetoshi Shimokawa /* Allow async. request to us */ 1850dcae7539SHidetoshi Shimokawa OWRITE(sc, OHCI_AREQHI, 1 << 31); 1851ac2d2894SHidetoshi Shimokawa if (firewire_phydma_enable) { 18526b3ecf71SHidetoshi Shimokawa /* allow from all nodes */ 1853dcae7539SHidetoshi Shimokawa OWRITE(sc, OHCI_PREQHI, 0x7fffffff); 1854dcae7539SHidetoshi Shimokawa OWRITE(sc, OHCI_PREQLO, 0xffffffff); 1855ac2d2894SHidetoshi Shimokawa /* 0 to 4GB region */ 1856dcae7539SHidetoshi Shimokawa OWRITE(sc, OHCI_PREQUPPER, 0x10000); 1857ac2d2894SHidetoshi Shimokawa } 185873aa55baSHidetoshi Shimokawa /* Set ATRetries register */ 185973aa55baSHidetoshi Shimokawa OWRITE(sc, OHCI_ATRETRY, 1<<(13 + 16) | 0xfff); 18609950b741SHidetoshi Shimokawa 18613c60ba66SKatsushi Kobayashi /* 18629950b741SHidetoshi Shimokawa * Checking whether the node is root or not. If root, turn on 18639950b741SHidetoshi Shimokawa * cycle master. 18643c60ba66SKatsushi Kobayashi */ 186577ee030bSHidetoshi Shimokawa node_id = OREAD(sc, FWOHCI_NODEID); 186677ee030bSHidetoshi Shimokawa plen = OREAD(sc, OHCI_SID_CNT); 186777ee030bSHidetoshi Shimokawa 18689950b741SHidetoshi Shimokawa fc->nodeid = node_id & 0x3f; 1869373d9227SSean Bruno device_printf(fc->dev, "%s: node_id=0x%08x, SelfID Count=%d, ", 1870373d9227SSean Bruno __func__, fc->nodeid, (plen >> 16) & 0xff); 187177ee030bSHidetoshi Shimokawa if (!(node_id & OHCI_NODE_VALID)) { 1872373d9227SSean Bruno device_printf(fc->dev, "%s: Bus reset failure\n", 1873373d9227SSean Bruno __func__); 18743c60ba66SKatsushi Kobayashi goto sidout; 18753c60ba66SKatsushi Kobayashi } 1876d0581de8SHidetoshi Shimokawa 1877d0581de8SHidetoshi Shimokawa /* cycle timer */ 1878d0581de8SHidetoshi Shimokawa sc->cycle_lost = 0; 1879d0581de8SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST); 18806b3ecf71SHidetoshi Shimokawa if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) { 18813c60ba66SKatsushi Kobayashi printf("CYCLEMASTER mode\n"); 18823c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTL, 18833c60ba66SKatsushi Kobayashi OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); 18843c60ba66SKatsushi Kobayashi } else { 18853c60ba66SKatsushi Kobayashi printf("non CYCLEMASTER mode\n"); 18863c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); 18873c60ba66SKatsushi Kobayashi OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); 18883c60ba66SKatsushi Kobayashi } 1889d0581de8SHidetoshi Shimokawa 18909950b741SHidetoshi Shimokawa fc->status = FWBUSINIT; 18919950b741SHidetoshi Shimokawa 18929950b741SHidetoshi Shimokawa if (!kdb_active) 18939950b741SHidetoshi Shimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid); 18949950b741SHidetoshi Shimokawa } 18959950b741SHidetoshi Shimokawa sidout: 18969950b741SHidetoshi Shimokawa if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active)) 18979950b741SHidetoshi Shimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma); 18989950b741SHidetoshi Shimokawa } 18999950b741SHidetoshi Shimokawa 19009950b741SHidetoshi Shimokawa static void 19019950b741SHidetoshi Shimokawa fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count) 19029950b741SHidetoshi Shimokawa { 19039950b741SHidetoshi Shimokawa uint32_t irstat, itstat; 19049950b741SHidetoshi Shimokawa u_int i; 19059950b741SHidetoshi Shimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 19069950b741SHidetoshi Shimokawa 19079950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_IR) { 19089950b741SHidetoshi Shimokawa irstat = atomic_readandclear_int(&sc->irstat); 19099950b741SHidetoshi Shimokawa for (i = 0; i < fc->nisodma; i++) { 19109950b741SHidetoshi Shimokawa struct fwohci_dbch *dbch; 19119950b741SHidetoshi Shimokawa 19129950b741SHidetoshi Shimokawa if ((irstat & (1 << i)) != 0) { 19139950b741SHidetoshi Shimokawa dbch = &sc->ir[i]; 19149950b741SHidetoshi Shimokawa if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) { 19159950b741SHidetoshi Shimokawa device_printf(sc->fc.dev, 19169950b741SHidetoshi Shimokawa "dma(%d) not active\n", i); 19179950b741SHidetoshi Shimokawa continue; 19189950b741SHidetoshi Shimokawa } 19199950b741SHidetoshi Shimokawa fwohci_rbuf_update(sc, i); 19209950b741SHidetoshi Shimokawa } 19219950b741SHidetoshi Shimokawa } 19229950b741SHidetoshi Shimokawa } 19239950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_IT) { 19249950b741SHidetoshi Shimokawa itstat = atomic_readandclear_int(&sc->itstat); 19259950b741SHidetoshi Shimokawa for (i = 0; i < fc->nisodma; i++) { 19269950b741SHidetoshi Shimokawa if ((itstat & (1 << i)) != 0) { 19279950b741SHidetoshi Shimokawa fwohci_tbuf_update(sc, i); 19289950b741SHidetoshi Shimokawa } 19299950b741SHidetoshi Shimokawa } 19309950b741SHidetoshi Shimokawa } 19319950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_PRRS) { 19329950b741SHidetoshi Shimokawa #if 0 19339950b741SHidetoshi Shimokawa dump_dma(sc, ARRS_CH); 19349950b741SHidetoshi Shimokawa dump_db(sc, ARRS_CH); 19359950b741SHidetoshi Shimokawa #endif 19369950b741SHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrs, count); 19379950b741SHidetoshi Shimokawa } 19389950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_PRRQ) { 19399950b741SHidetoshi Shimokawa #if 0 19409950b741SHidetoshi Shimokawa dump_dma(sc, ARRQ_CH); 19419950b741SHidetoshi Shimokawa dump_db(sc, ARRQ_CH); 19429950b741SHidetoshi Shimokawa #endif 19439950b741SHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrq, count); 19449950b741SHidetoshi Shimokawa } 19459950b741SHidetoshi Shimokawa if (stat & OHCI_INT_CYC_LOST) { 19469950b741SHidetoshi Shimokawa if (sc->cycle_lost >= 0) 19479950b741SHidetoshi Shimokawa sc->cycle_lost++; 19489950b741SHidetoshi Shimokawa if (sc->cycle_lost > 10) { 19499950b741SHidetoshi Shimokawa sc->cycle_lost = -1; 19509950b741SHidetoshi Shimokawa #if 0 19519950b741SHidetoshi Shimokawa OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); 19529950b741SHidetoshi Shimokawa #endif 19539950b741SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 19548834bc52SRebecca Cran device_printf(fc->dev, "too many cycles lost, " 19558834bc52SRebecca Cran "no cycle master present?\n"); 19569950b741SHidetoshi Shimokawa } 19579950b741SHidetoshi Shimokawa } 19589950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_ATRQ) { 19599950b741SHidetoshi Shimokawa fwohci_txd(sc, &(sc->atrq)); 19609950b741SHidetoshi Shimokawa } 19619950b741SHidetoshi Shimokawa if (stat & OHCI_INT_DMA_ATRS) { 19629950b741SHidetoshi Shimokawa fwohci_txd(sc, &(sc->atrs)); 19639950b741SHidetoshi Shimokawa } 19649950b741SHidetoshi Shimokawa if (stat & OHCI_INT_PW_ERR) { 19659950b741SHidetoshi Shimokawa device_printf(fc->dev, "posted write error\n"); 19669950b741SHidetoshi Shimokawa } 19679950b741SHidetoshi Shimokawa if (stat & OHCI_INT_ERR) { 19689950b741SHidetoshi Shimokawa device_printf(fc->dev, "unrecoverable error\n"); 19699950b741SHidetoshi Shimokawa } 19709950b741SHidetoshi Shimokawa if (stat & OHCI_INT_PHY_INT) { 19719950b741SHidetoshi Shimokawa device_printf(fc->dev, "phy int\n"); 19729950b741SHidetoshi Shimokawa } 19739950b741SHidetoshi Shimokawa } 19749950b741SHidetoshi Shimokawa 19759950b741SHidetoshi Shimokawa static void 19769950b741SHidetoshi Shimokawa fwohci_task_busreset(void *arg, int pending) 19779950b741SHidetoshi Shimokawa { 19789950b741SHidetoshi Shimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 19799950b741SHidetoshi Shimokawa 19803042cc43SSean Bruno FW_GLOCK(&sc->fc); 19819950b741SHidetoshi Shimokawa fw_busreset(&sc->fc, FWBUSRESET); 19829950b741SHidetoshi Shimokawa OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 19839950b741SHidetoshi Shimokawa OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 19843042cc43SSean Bruno FW_GUNLOCK(&sc->fc); 19859950b741SHidetoshi Shimokawa } 19869950b741SHidetoshi Shimokawa 19879950b741SHidetoshi Shimokawa static void 19889950b741SHidetoshi Shimokawa fwohci_task_sid(void *arg, int pending) 19899950b741SHidetoshi Shimokawa { 19909950b741SHidetoshi Shimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 19919950b741SHidetoshi Shimokawa struct firewire_comm *fc = &sc->fc; 19929950b741SHidetoshi Shimokawa uint32_t *buf; 19939950b741SHidetoshi Shimokawa int i, plen; 19949950b741SHidetoshi Shimokawa 19959950b741SHidetoshi Shimokawa 19963042cc43SSean Bruno /* 19973042cc43SSean Bruno * We really should have locking 19983042cc43SSean Bruno * here. Not sure why it's not 19993042cc43SSean Bruno */ 20009950b741SHidetoshi Shimokawa plen = OREAD(sc, OHCI_SID_CNT); 20013c60ba66SKatsushi Kobayashi 200277ee030bSHidetoshi Shimokawa if (plen & OHCI_SID_ERR) { 200377ee030bSHidetoshi Shimokawa device_printf(fc->dev, "SID Error\n"); 20049950b741SHidetoshi Shimokawa return; 200577ee030bSHidetoshi Shimokawa } 200677ee030bSHidetoshi Shimokawa plen &= OHCI_SID_CNT_MASK; 200716e0f484SHidetoshi Shimokawa if (plen < 4 || plen > OHCI_SIDSIZE) { 200816e0f484SHidetoshi Shimokawa device_printf(fc->dev, "invalid SID len = %d\n", plen); 20099950b741SHidetoshi Shimokawa return; 201016e0f484SHidetoshi Shimokawa } 20113c60ba66SKatsushi Kobayashi plen -= 4; /* chop control info */ 201203161bbcSDoug Rabson buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); 201377ee030bSHidetoshi Shimokawa if (buf == NULL) { 201477ee030bSHidetoshi Shimokawa device_printf(fc->dev, "malloc failed\n"); 20159950b741SHidetoshi Shimokawa return; 201677ee030bSHidetoshi Shimokawa } 201777ee030bSHidetoshi Shimokawa for (i = 0; i < plen / 4; i++) 201877ee030bSHidetoshi Shimokawa buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i + 1]); 20193042cc43SSean Bruno 202048249fe0SHidetoshi Shimokawa /* pending all pre-bus_reset packets */ 202148249fe0SHidetoshi Shimokawa fwohci_txd(sc, &sc->atrq); 202248249fe0SHidetoshi Shimokawa fwohci_txd(sc, &sc->atrs); 202348249fe0SHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrs, -1); 202448249fe0SHidetoshi Shimokawa fwohci_arcv(sc, &sc->arrq, -1); 2025627d85fbSHidetoshi Shimokawa fw_drain_txq(fc); 202677ee030bSHidetoshi Shimokawa fw_sidrcv(fc, buf, plen); 202777ee030bSHidetoshi Shimokawa free(buf, M_FW); 20283c60ba66SKatsushi Kobayashi } 20293c60ba66SKatsushi Kobayashi 203077ee030bSHidetoshi Shimokawa static void 20319950b741SHidetoshi Shimokawa fwohci_task_dma(void *arg, int pending) 203277ee030bSHidetoshi Shimokawa { 203377ee030bSHidetoshi Shimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 203403161bbcSDoug Rabson uint32_t stat; 203577ee030bSHidetoshi Shimokawa 203677ee030bSHidetoshi Shimokawa again: 203777ee030bSHidetoshi Shimokawa stat = atomic_readandclear_int(&sc->intstat); 203877ee030bSHidetoshi Shimokawa if (stat) 20399950b741SHidetoshi Shimokawa fwohci_intr_dma(sc, stat, -1); 204077ee030bSHidetoshi Shimokawa else 204177ee030bSHidetoshi Shimokawa return; 204277ee030bSHidetoshi Shimokawa goto again; 204377ee030bSHidetoshi Shimokawa } 204477ee030bSHidetoshi Shimokawa 20459950b741SHidetoshi Shimokawa static int 20469950b741SHidetoshi Shimokawa fwohci_check_stat(struct fwohci_softc *sc) 204777ee030bSHidetoshi Shimokawa { 204803161bbcSDoug Rabson uint32_t stat, irstat, itstat; 204977ee030bSHidetoshi Shimokawa 20503042cc43SSean Bruno FW_GLOCK_ASSERT(&sc->fc); 205177ee030bSHidetoshi Shimokawa stat = OREAD(sc, FWOHCI_INTSTAT); 205277ee030bSHidetoshi Shimokawa if (stat == 0xffffffff) { 205324c02d2fSWarner Losh if (!bus_child_present(sc->fc.dev)) 205424c02d2fSWarner Losh return (FILTER_HANDLED); 205524c02d2fSWarner Losh device_printf(sc->fc.dev, "device physically ejected?\n"); 20569950b741SHidetoshi Shimokawa return (FILTER_STRAY); 205777ee030bSHidetoshi Shimokawa } 205877ee030bSHidetoshi Shimokawa if (stat) 20599950b741SHidetoshi Shimokawa OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R); 20609950b741SHidetoshi Shimokawa 20619950b741SHidetoshi Shimokawa stat &= sc->intmask; 20629950b741SHidetoshi Shimokawa if (stat == 0) 20639950b741SHidetoshi Shimokawa return (FILTER_STRAY); 20649950b741SHidetoshi Shimokawa 20659950b741SHidetoshi Shimokawa atomic_set_int(&sc->intstat, stat); 206677ee030bSHidetoshi Shimokawa if (stat & OHCI_INT_DMA_IR) { 206777ee030bSHidetoshi Shimokawa irstat = OREAD(sc, OHCI_IR_STAT); 206877ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_IR_STATCLR, irstat); 206977ee030bSHidetoshi Shimokawa atomic_set_int(&sc->irstat, irstat); 207077ee030bSHidetoshi Shimokawa } 207177ee030bSHidetoshi Shimokawa if (stat & OHCI_INT_DMA_IT) { 207277ee030bSHidetoshi Shimokawa itstat = OREAD(sc, OHCI_IT_STAT); 207377ee030bSHidetoshi Shimokawa OWRITE(sc, OHCI_IT_STATCLR, itstat); 207477ee030bSHidetoshi Shimokawa atomic_set_int(&sc->itstat, itstat); 207577ee030bSHidetoshi Shimokawa } 20769950b741SHidetoshi Shimokawa 20779950b741SHidetoshi Shimokawa fwohci_intr_core(sc, stat, -1); 20789950b741SHidetoshi Shimokawa return (FILTER_HANDLED); 20799950b741SHidetoshi Shimokawa } 20809950b741SHidetoshi Shimokawa 20813c60ba66SKatsushi Kobayashi void 20823c60ba66SKatsushi Kobayashi fwohci_intr(void *arg) 20833c60ba66SKatsushi Kobayashi { 20843042cc43SSean Bruno struct fwohci_softc *sc = (struct fwohci_softc *)arg; 20853042cc43SSean Bruno 20863042cc43SSean Bruno FW_GLOCK(&sc->fc); 20873042cc43SSean Bruno fwohci_check_stat(sc); 20883042cc43SSean Bruno FW_GUNLOCK(&sc->fc); 20893c60ba66SKatsushi Kobayashi } 20903c60ba66SKatsushi Kobayashi 2091740b10aaSHidetoshi Shimokawa void 20923c60ba66SKatsushi Kobayashi fwohci_poll(struct firewire_comm *fc, int quick, int count) 20933c60ba66SKatsushi Kobayashi { 20949950b741SHidetoshi Shimokawa struct fwohci_softc *sc = (struct fwohci_softc *)fc; 20953042cc43SSean Bruno 20963042cc43SSean Bruno FW_GLOCK(fc); 20979950b741SHidetoshi Shimokawa fwohci_check_stat(sc); 20983042cc43SSean Bruno FW_GUNLOCK(fc); 20993c60ba66SKatsushi Kobayashi } 21003c60ba66SKatsushi Kobayashi 21013c60ba66SKatsushi Kobayashi static void 21023c60ba66SKatsushi Kobayashi fwohci_set_intr(struct firewire_comm *fc, int enable) 21033c60ba66SKatsushi Kobayashi { 21043c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 21053c60ba66SKatsushi Kobayashi 21063c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)fc; 2107f9d9941fSHidetoshi Shimokawa if (firewire_debug) 21089339321dSHidetoshi Shimokawa device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable); 21093c60ba66SKatsushi Kobayashi if (enable) { 21103c60ba66SKatsushi Kobayashi sc->intmask |= OHCI_INT_EN; 21113c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); 21123c60ba66SKatsushi Kobayashi } else { 21133c60ba66SKatsushi Kobayashi sc->intmask &= ~OHCI_INT_EN; 21143c60ba66SKatsushi Kobayashi OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); 21153c60ba66SKatsushi Kobayashi } 21163c60ba66SKatsushi Kobayashi } 21173c60ba66SKatsushi Kobayashi 2118c572b810SHidetoshi Shimokawa static void 2119c572b810SHidetoshi Shimokawa fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) 21203c60ba66SKatsushi Kobayashi { 21213c60ba66SKatsushi Kobayashi struct firewire_comm *fc = &sc->fc; 2122c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 21235a7ba74dSHidetoshi Shimokawa struct fw_bulkxfer *chunk; 21245a7ba74dSHidetoshi Shimokawa struct fw_xferq *it; 212503161bbcSDoug Rabson uint32_t stat, count; 212677ee030bSHidetoshi Shimokawa int s, w=0, ldesc; 21273c60ba66SKatsushi Kobayashi 21285a7ba74dSHidetoshi Shimokawa it = fc->it[dmach]; 212977ee030bSHidetoshi Shimokawa ldesc = sc->it[dmach].ndesc - 1; 21305a7ba74dSHidetoshi Shimokawa s = splfw(); /* unnecessary ? */ 21319950b741SHidetoshi Shimokawa FW_GLOCK(fc); 213277ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); 2133a1c9e73aSHidetoshi Shimokawa if (firewire_debug) 2134a1c9e73aSHidetoshi Shimokawa dump_db(sc, ITX_CH + dmach); 21355a7ba74dSHidetoshi Shimokawa while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { 21365a7ba74dSHidetoshi Shimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 213777ee030bSHidetoshi Shimokawa stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 213877ee030bSHidetoshi Shimokawa >> OHCI_STATUS_SHIFT; 21395a7ba74dSHidetoshi Shimokawa db = ((struct fwohcidb_tr *)(chunk->start))->db; 2140a1c9e73aSHidetoshi Shimokawa /* timestamp */ 214177ee030bSHidetoshi Shimokawa count = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 214277ee030bSHidetoshi Shimokawa & OHCI_COUNT_MASK; 21435a7ba74dSHidetoshi Shimokawa if (stat == 0) 21445a7ba74dSHidetoshi Shimokawa break; 21455a7ba74dSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&it->stdma, link); 21465a7ba74dSHidetoshi Shimokawa switch (stat & FWOHCIEV_MASK) { 21473c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 21485a7ba74dSHidetoshi Shimokawa #if 0 21495a7ba74dSHidetoshi Shimokawa device_printf(fc->dev, "0x%08x\n", count); 21500aaa9a23SHidetoshi Shimokawa #endif 21513c60ba66SKatsushi Kobayashi break; 21523c60ba66SKatsushi Kobayashi default: 21535a7ba74dSHidetoshi Shimokawa device_printf(fc->dev, 215477ee030bSHidetoshi Shimokawa "Isochronous transmit err %02x(%s)\n", 215577ee030bSHidetoshi Shimokawa stat, fwohcicode[stat & 0x1f]); 21563c60ba66SKatsushi Kobayashi } 21575a7ba74dSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&it->stfree, chunk, link); 21585a7ba74dSHidetoshi Shimokawa w++; 21595a7ba74dSHidetoshi Shimokawa } 21609950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 21615a7ba74dSHidetoshi Shimokawa splx(s); 21625a7ba74dSHidetoshi Shimokawa if (w) 21635a7ba74dSHidetoshi Shimokawa wakeup(it); 21643c60ba66SKatsushi Kobayashi } 2165c572b810SHidetoshi Shimokawa 2166c572b810SHidetoshi Shimokawa static void 2167c572b810SHidetoshi Shimokawa fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) 21683c60ba66SKatsushi Kobayashi { 21690aaa9a23SHidetoshi Shimokawa struct firewire_comm *fc = &sc->fc; 2170c4778b5dSHidetoshi Shimokawa struct fwohcidb_tr *db_tr; 21715a7ba74dSHidetoshi Shimokawa struct fw_bulkxfer *chunk; 21725a7ba74dSHidetoshi Shimokawa struct fw_xferq *ir; 217303161bbcSDoug Rabson uint32_t stat; 217477ee030bSHidetoshi Shimokawa int s, w = 0, ldesc; 21750aaa9a23SHidetoshi Shimokawa 21765a7ba74dSHidetoshi Shimokawa ir = fc->ir[dmach]; 217777ee030bSHidetoshi Shimokawa ldesc = sc->ir[dmach].ndesc - 1; 21789950b741SHidetoshi Shimokawa 217977ee030bSHidetoshi Shimokawa #if 0 218077ee030bSHidetoshi Shimokawa dump_db(sc, dmach); 218177ee030bSHidetoshi Shimokawa #endif 21825a7ba74dSHidetoshi Shimokawa s = splfw(); 21839950b741SHidetoshi Shimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 21849950b741SHidetoshi Shimokawa FW_GLOCK(fc); 218577ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); 21865a7ba74dSHidetoshi Shimokawa while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 218777ee030bSHidetoshi Shimokawa db_tr = (struct fwohcidb_tr *)chunk->end; 218877ee030bSHidetoshi Shimokawa stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) 218977ee030bSHidetoshi Shimokawa >> OHCI_STATUS_SHIFT; 21905a7ba74dSHidetoshi Shimokawa if (stat == 0) 21915a7ba74dSHidetoshi Shimokawa break; 219277ee030bSHidetoshi Shimokawa 219377ee030bSHidetoshi Shimokawa if (chunk->mbuf != NULL) { 219477ee030bSHidetoshi Shimokawa bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map, 219577ee030bSHidetoshi Shimokawa BUS_DMASYNC_POSTREAD); 219677ee030bSHidetoshi Shimokawa bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map); 219777ee030bSHidetoshi Shimokawa } else if (ir->buf != NULL) { 219877ee030bSHidetoshi Shimokawa fwdma_sync_multiseg(ir->buf, chunk->poffset, 219977ee030bSHidetoshi Shimokawa ir->bnpacket, BUS_DMASYNC_POSTREAD); 220077ee030bSHidetoshi Shimokawa } else { 220177ee030bSHidetoshi Shimokawa /* XXX */ 220277ee030bSHidetoshi Shimokawa printf("fwohci_rbuf_update: this shouldn't happend\n"); 220377ee030bSHidetoshi Shimokawa } 220477ee030bSHidetoshi Shimokawa 22055a7ba74dSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 22065a7ba74dSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); 22075a7ba74dSHidetoshi Shimokawa switch (stat & FWOHCIEV_MASK) { 22083c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 22092b4601d1SHidetoshi Shimokawa chunk->resp = 0; 22103c60ba66SKatsushi Kobayashi break; 22113c60ba66SKatsushi Kobayashi default: 22122b4601d1SHidetoshi Shimokawa chunk->resp = EINVAL; 22135a7ba74dSHidetoshi Shimokawa device_printf(fc->dev, 221477ee030bSHidetoshi Shimokawa "Isochronous receive err %02x(%s)\n", 221577ee030bSHidetoshi Shimokawa stat, fwohcicode[stat & 0x1f]); 22163c60ba66SKatsushi Kobayashi } 22175a7ba74dSHidetoshi Shimokawa w++; 22185a7ba74dSHidetoshi Shimokawa } 22199950b741SHidetoshi Shimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 22209950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 22215a7ba74dSHidetoshi Shimokawa splx(s); 22229950b741SHidetoshi Shimokawa if (w == 0) 22239950b741SHidetoshi Shimokawa return; 22249950b741SHidetoshi Shimokawa 22252b4601d1SHidetoshi Shimokawa if (ir->flag & FWXFERQ_HANDLER) 22262b4601d1SHidetoshi Shimokawa ir->hand(ir); 22272b4601d1SHidetoshi Shimokawa else 22285a7ba74dSHidetoshi Shimokawa wakeup(ir); 22293c60ba66SKatsushi Kobayashi } 2230c572b810SHidetoshi Shimokawa 2231c572b810SHidetoshi Shimokawa void 223203161bbcSDoug Rabson dump_dma(struct fwohci_softc *sc, uint32_t ch) 2233c572b810SHidetoshi Shimokawa { 223403161bbcSDoug Rabson uint32_t off, cntl, stat, cmd, match; 22353c60ba66SKatsushi Kobayashi 22363c60ba66SKatsushi Kobayashi if (ch == 0) { 22373c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 22383c60ba66SKatsushi Kobayashi } else if (ch == 1) { 22393c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 22403c60ba66SKatsushi Kobayashi } else if (ch == 2) { 22413c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 22423c60ba66SKatsushi Kobayashi } else if (ch == 3) { 22433c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 22443c60ba66SKatsushi Kobayashi } else if (ch < IRX_CH) { 22453c60ba66SKatsushi Kobayashi off = OHCI_ITCTL(ch - ITX_CH); 22463c60ba66SKatsushi Kobayashi } else { 22473c60ba66SKatsushi Kobayashi off = OHCI_IRCTL(ch - IRX_CH); 22483c60ba66SKatsushi Kobayashi } 22493c60ba66SKatsushi Kobayashi cntl = stat = OREAD(sc, off); 22503c60ba66SKatsushi Kobayashi cmd = OREAD(sc, off + 0xc); 22513c60ba66SKatsushi Kobayashi match = OREAD(sc, off + 0x10); 22523c60ba66SKatsushi Kobayashi 225377ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n", 22543c60ba66SKatsushi Kobayashi ch, 22553c60ba66SKatsushi Kobayashi cntl, 22563c60ba66SKatsushi Kobayashi cmd, 22573c60ba66SKatsushi Kobayashi match); 22583c60ba66SKatsushi Kobayashi stat &= 0xffff; 225977ee030bSHidetoshi Shimokawa if (stat) { 22603c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", 22613c60ba66SKatsushi Kobayashi ch, 22623c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 22633c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 22643c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 22653c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 22663c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 22673c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 22683c60ba66SKatsushi Kobayashi fwohcicode[stat & 0x1f], 22693c60ba66SKatsushi Kobayashi stat & 0x1f 22703c60ba66SKatsushi Kobayashi ); 22713c60ba66SKatsushi Kobayashi } else { 22723c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); 22733c60ba66SKatsushi Kobayashi } 22743c60ba66SKatsushi Kobayashi } 2275c572b810SHidetoshi Shimokawa 2276c572b810SHidetoshi Shimokawa void 227703161bbcSDoug Rabson dump_db(struct fwohci_softc *sc, uint32_t ch) 2278c572b810SHidetoshi Shimokawa { 22793c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 228077ee030bSHidetoshi Shimokawa struct fwohcidb_tr *cp = NULL, *pp, *np = NULL; 2281c4778b5dSHidetoshi Shimokawa struct fwohcidb *curr = NULL, *prev, *next = NULL; 22823c60ba66SKatsushi Kobayashi int idb, jdb; 228303161bbcSDoug Rabson uint32_t cmd, off; 228423667f08SAlexander Kabaev 22853c60ba66SKatsushi Kobayashi if (ch == 0) { 22863c60ba66SKatsushi Kobayashi off = OHCI_ATQOFF; 22873c60ba66SKatsushi Kobayashi dbch = &sc->atrq; 22883c60ba66SKatsushi Kobayashi } else if (ch == 1) { 22893c60ba66SKatsushi Kobayashi off = OHCI_ATSOFF; 22903c60ba66SKatsushi Kobayashi dbch = &sc->atrs; 22913c60ba66SKatsushi Kobayashi } else if (ch == 2) { 22923c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 22933c60ba66SKatsushi Kobayashi dbch = &sc->arrq; 22943c60ba66SKatsushi Kobayashi } else if (ch == 3) { 22953c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 22963c60ba66SKatsushi Kobayashi dbch = &sc->arrs; 22973c60ba66SKatsushi Kobayashi } else if (ch < IRX_CH) { 22983c60ba66SKatsushi Kobayashi off = OHCI_ITCTL(ch - ITX_CH); 22993c60ba66SKatsushi Kobayashi dbch = &sc->it[ch - ITX_CH]; 23003c60ba66SKatsushi Kobayashi } else { 23013c60ba66SKatsushi Kobayashi off = OHCI_IRCTL(ch - IRX_CH); 23023c60ba66SKatsushi Kobayashi dbch = &sc->ir[ch - IRX_CH]; 23033c60ba66SKatsushi Kobayashi } 23043c60ba66SKatsushi Kobayashi cmd = OREAD(sc, off + 0xc); 23053c60ba66SKatsushi Kobayashi 23063c60ba66SKatsushi Kobayashi if (dbch->ndb == 0) { 23073c60ba66SKatsushi Kobayashi device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); 23083c60ba66SKatsushi Kobayashi return; 23093c60ba66SKatsushi Kobayashi } 23103c60ba66SKatsushi Kobayashi pp = dbch->top; 23113c60ba66SKatsushi Kobayashi prev = pp->db; 23123c60ba66SKatsushi Kobayashi for (idb = 0; idb < dbch->ndb; idb++) { 23133c60ba66SKatsushi Kobayashi cp = STAILQ_NEXT(pp, link); 23143c60ba66SKatsushi Kobayashi if (cp == NULL) { 23153c60ba66SKatsushi Kobayashi curr = NULL; 23163c60ba66SKatsushi Kobayashi goto outdb; 23173c60ba66SKatsushi Kobayashi } 23183c60ba66SKatsushi Kobayashi np = STAILQ_NEXT(cp, link); 23193c60ba66SKatsushi Kobayashi for (jdb = 0; jdb < dbch->ndesc; jdb++) { 232077ee030bSHidetoshi Shimokawa if ((cmd & 0xfffffff0) == cp->bus_addr) { 23213c60ba66SKatsushi Kobayashi curr = cp->db; 23223c60ba66SKatsushi Kobayashi if (np != NULL) { 23233c60ba66SKatsushi Kobayashi next = np->db; 23243c60ba66SKatsushi Kobayashi } else { 23253c60ba66SKatsushi Kobayashi next = NULL; 23263c60ba66SKatsushi Kobayashi } 23273c60ba66SKatsushi Kobayashi goto outdb; 23283c60ba66SKatsushi Kobayashi } 23293c60ba66SKatsushi Kobayashi } 23303c60ba66SKatsushi Kobayashi pp = STAILQ_NEXT(pp, link); 2331b083b7c9SSam Leffler if (pp == NULL) { 2332b083b7c9SSam Leffler curr = NULL; 2333b083b7c9SSam Leffler goto outdb; 2334b083b7c9SSam Leffler } 23353c60ba66SKatsushi Kobayashi prev = pp->db; 23363c60ba66SKatsushi Kobayashi } 23373c60ba66SKatsushi Kobayashi outdb: 23383c60ba66SKatsushi Kobayashi if (curr != NULL) { 233977ee030bSHidetoshi Shimokawa #if 0 23403c60ba66SKatsushi Kobayashi printf("Prev DB %d\n", ch); 234177ee030bSHidetoshi Shimokawa print_db(pp, prev, ch, dbch->ndesc); 234277ee030bSHidetoshi Shimokawa #endif 23433c60ba66SKatsushi Kobayashi printf("Current DB %d\n", ch); 234477ee030bSHidetoshi Shimokawa print_db(cp, curr, ch, dbch->ndesc); 234577ee030bSHidetoshi Shimokawa #if 0 23463c60ba66SKatsushi Kobayashi printf("Next DB %d\n", ch); 234777ee030bSHidetoshi Shimokawa print_db(np, next, ch, dbch->ndesc); 234877ee030bSHidetoshi Shimokawa #endif 23493c60ba66SKatsushi Kobayashi } else { 23503c60ba66SKatsushi Kobayashi printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); 23513c60ba66SKatsushi Kobayashi } 23523c60ba66SKatsushi Kobayashi return; 23533c60ba66SKatsushi Kobayashi } 2354c572b810SHidetoshi Shimokawa 2355c572b810SHidetoshi Shimokawa void 2356c4778b5dSHidetoshi Shimokawa print_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db, 235703161bbcSDoug Rabson uint32_t ch, uint32_t max) 2358c572b810SHidetoshi Shimokawa { 23593c60ba66SKatsushi Kobayashi fwohcireg_t stat; 23603c60ba66SKatsushi Kobayashi int i, key; 236103161bbcSDoug Rabson uint32_t cmd, res; 23623c60ba66SKatsushi Kobayashi 23633c60ba66SKatsushi Kobayashi if (db == NULL) { 23643c60ba66SKatsushi Kobayashi printf("No Descriptor is found\n"); 23653c60ba66SKatsushi Kobayashi return; 23663c60ba66SKatsushi Kobayashi } 23673c60ba66SKatsushi Kobayashi 23683c60ba66SKatsushi Kobayashi printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", 23693c60ba66SKatsushi Kobayashi ch, 23703c60ba66SKatsushi Kobayashi "Current", 23713c60ba66SKatsushi Kobayashi "OP ", 23723c60ba66SKatsushi Kobayashi "KEY", 23733c60ba66SKatsushi Kobayashi "INT", 23743c60ba66SKatsushi Kobayashi "BR ", 23753c60ba66SKatsushi Kobayashi "len", 23763c60ba66SKatsushi Kobayashi "Addr", 23773c60ba66SKatsushi Kobayashi "Depend", 23783c60ba66SKatsushi Kobayashi "Stat", 23793c60ba66SKatsushi Kobayashi "Cnt"); 23803c60ba66SKatsushi Kobayashi for (i = 0; i <= max; i++) { 238177ee030bSHidetoshi Shimokawa cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd); 238277ee030bSHidetoshi Shimokawa res = FWOHCI_DMA_READ(db[i].db.desc.res); 238377ee030bSHidetoshi Shimokawa key = cmd & OHCI_KEY_MASK; 238477ee030bSHidetoshi Shimokawa stat = res >> OHCI_STATUS_SHIFT; 238510d3ed64SHidetoshi Shimokawa printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x", 238610d3ed64SHidetoshi Shimokawa (uintmax_t)db_tr->bus_addr, 238777ee030bSHidetoshi Shimokawa dbcode[(cmd >> 28) & 0xf], 238877ee030bSHidetoshi Shimokawa dbkey[(cmd >> 24) & 0x7], 238977ee030bSHidetoshi Shimokawa dbcond[(cmd >> 20) & 0x3], 239077ee030bSHidetoshi Shimokawa dbcond[(cmd >> 18) & 0x3], 239177ee030bSHidetoshi Shimokawa cmd & OHCI_COUNT_MASK, 239277ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i].db.desc.addr), 239377ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i].db.desc.depend), 239477ee030bSHidetoshi Shimokawa stat, 239577ee030bSHidetoshi Shimokawa res & OHCI_COUNT_MASK); 23963c60ba66SKatsushi Kobayashi if (stat & 0xff00) { 23973c60ba66SKatsushi Kobayashi printf(" %s%s%s%s%s%s %s(%x)\n", 23983c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 23993c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 24003c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 24013c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 24023c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 24033c60ba66SKatsushi Kobayashi stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 24043c60ba66SKatsushi Kobayashi fwohcicode[stat & 0x1f], 24053c60ba66SKatsushi Kobayashi stat & 0x1f 24063c60ba66SKatsushi Kobayashi ); 24073c60ba66SKatsushi Kobayashi } else { 24083c60ba66SKatsushi Kobayashi printf(" Nostat\n"); 24093c60ba66SKatsushi Kobayashi } 24103c60ba66SKatsushi Kobayashi if (key == OHCI_KEY_ST2) { 24113c60ba66SKatsushi Kobayashi printf("0x%08x 0x%08x 0x%08x 0x%08x\n", 241277ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i + 1].db.immed[0]), 241377ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i + 1].db.immed[1]), 241477ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i + 1].db.immed[2]), 241577ee030bSHidetoshi Shimokawa FWOHCI_DMA_READ(db[i + 1].db.immed[3])); 24163c60ba66SKatsushi Kobayashi } 24173c60ba66SKatsushi Kobayashi if (key == OHCI_KEY_DEVICE) { 24183c60ba66SKatsushi Kobayashi return; 24193c60ba66SKatsushi Kobayashi } 242077ee030bSHidetoshi Shimokawa if ((cmd & OHCI_BRANCH_MASK) 24213c60ba66SKatsushi Kobayashi == OHCI_BRANCH_ALWAYS) { 24223c60ba66SKatsushi Kobayashi return; 24233c60ba66SKatsushi Kobayashi } 242477ee030bSHidetoshi Shimokawa if ((cmd & OHCI_CMD_MASK) 24253c60ba66SKatsushi Kobayashi == OHCI_OUTPUT_LAST) { 24263c60ba66SKatsushi Kobayashi return; 24273c60ba66SKatsushi Kobayashi } 242877ee030bSHidetoshi Shimokawa if ((cmd & OHCI_CMD_MASK) 24293c60ba66SKatsushi Kobayashi == OHCI_INPUT_LAST) { 24303c60ba66SKatsushi Kobayashi return; 24313c60ba66SKatsushi Kobayashi } 24323c60ba66SKatsushi Kobayashi if (key == OHCI_KEY_ST2) { 24333c60ba66SKatsushi Kobayashi i++; 24343c60ba66SKatsushi Kobayashi } 24353c60ba66SKatsushi Kobayashi } 24363c60ba66SKatsushi Kobayashi return; 24373c60ba66SKatsushi Kobayashi } 2438c572b810SHidetoshi Shimokawa 2439c572b810SHidetoshi Shimokawa void 2440c572b810SHidetoshi Shimokawa fwohci_ibr(struct firewire_comm *fc) 24413c60ba66SKatsushi Kobayashi { 24423c60ba66SKatsushi Kobayashi struct fwohci_softc *sc; 244303161bbcSDoug Rabson uint32_t fun; 24443c60ba66SKatsushi Kobayashi 2445864d7e72SHidetoshi Shimokawa device_printf(fc->dev, "Initiate bus reset\n"); 24463c60ba66SKatsushi Kobayashi sc = (struct fwohci_softc *)fc; 2447ac9f6692SHidetoshi Shimokawa 24483042cc43SSean Bruno FW_GLOCK(fc); 2449ac9f6692SHidetoshi Shimokawa /* 2450c0e9efacSDoug Rabson * Make sure our cached values from the config rom are 2451c0e9efacSDoug Rabson * initialised. 2452c0e9efacSDoug Rabson */ 2453c0e9efacSDoug Rabson OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 2454c0e9efacSDoug Rabson OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 2455c0e9efacSDoug Rabson 2456c0e9efacSDoug Rabson /* 2457ac9f6692SHidetoshi Shimokawa * Set root hold-off bit so that non cyclemaster capable node 2458ac9f6692SHidetoshi Shimokawa * shouldn't became the root node. 2459ac9f6692SHidetoshi Shimokawa */ 24603c60ba66SKatsushi Kobayashi #if 1 24613c60ba66SKatsushi Kobayashi fun = fwphy_rddata(sc, FW_PHY_IBR_REG); 24624ed65ce9SHidetoshi Shimokawa fun |= FW_PHY_IBR | FW_PHY_RHB; 24633c60ba66SKatsushi Kobayashi fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); 24644ed65ce9SHidetoshi Shimokawa #else /* Short bus reset */ 24653c60ba66SKatsushi Kobayashi fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); 24664ed65ce9SHidetoshi Shimokawa fun |= FW_PHY_ISBR | FW_PHY_RHB; 24673c60ba66SKatsushi Kobayashi fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); 24683c60ba66SKatsushi Kobayashi #endif 24693042cc43SSean Bruno FW_GUNLOCK(fc); 24703c60ba66SKatsushi Kobayashi } 2471c572b810SHidetoshi Shimokawa 2472c572b810SHidetoshi Shimokawa void 2473c572b810SHidetoshi Shimokawa fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 24743c60ba66SKatsushi Kobayashi { 24753c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr, *fdb_tr; 24763c60ba66SKatsushi Kobayashi struct fwohci_dbch *dbch; 2477c4778b5dSHidetoshi Shimokawa struct fwohcidb *db; 24783c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 2479c4778b5dSHidetoshi Shimokawa struct fwohci_txpkthdr *ohcifp; 24803c60ba66SKatsushi Kobayashi unsigned short chtag; 24813c60ba66SKatsushi Kobayashi int idb; 24823c60ba66SKatsushi Kobayashi 24839950b741SHidetoshi Shimokawa FW_GLOCK_ASSERT(&sc->fc); 24849950b741SHidetoshi Shimokawa 24853c60ba66SKatsushi Kobayashi dbch = &sc->it[dmach]; 24863c60ba66SKatsushi Kobayashi chtag = sc->it[dmach].xferq.flag & 0xff; 24873c60ba66SKatsushi Kobayashi 24883c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 24893c60ba66SKatsushi Kobayashi fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 24903c60ba66SKatsushi Kobayashi /* 249177ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr); 24923c60ba66SKatsushi Kobayashi */ 249377ee030bSHidetoshi Shimokawa for (idb = 0; idb < dbch->xferq.bnpacket; idb++) { 249453f1eb86SHidetoshi Shimokawa db = db_tr->db; 24953c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)db_tr->buf; 2496c4778b5dSHidetoshi Shimokawa ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed; 249777ee030bSHidetoshi Shimokawa ohcifp->mode.ld[0] = fp->mode.ld[0]; 2498a1c9e73aSHidetoshi Shimokawa ohcifp->mode.common.spd = 0 & 0x7; 249977ee030bSHidetoshi Shimokawa ohcifp->mode.stream.len = fp->mode.stream.len; 25003c60ba66SKatsushi Kobayashi ohcifp->mode.stream.chtag = chtag; 25013c60ba66SKatsushi Kobayashi ohcifp->mode.stream.tcode = 0xa; 250277ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 250377ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]); 250477ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]); 250577ee030bSHidetoshi Shimokawa #endif 25063c60ba66SKatsushi Kobayashi 250777ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK); 250877ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len); 250977ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 251053f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npackets changes */ 251177ee030bSHidetoshi Shimokawa db[2].db.desc.cmd = OHCI_OUTPUT_LAST 25123c60ba66SKatsushi Kobayashi | OHCI_UPDATE 251353f1eb86SHidetoshi Shimokawa | OHCI_BRANCH_ALWAYS; 251453f1eb86SHidetoshi Shimokawa db[0].db.desc.depend = 251553f1eb86SHidetoshi Shimokawa = db[dbch->ndesc - 1].db.desc.depend 251677ee030bSHidetoshi Shimokawa = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc; 251753f1eb86SHidetoshi Shimokawa #else 251877ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 251977ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc); 252053f1eb86SHidetoshi Shimokawa #endif 25213c60ba66SKatsushi Kobayashi bulkxfer->end = (caddr_t)db_tr; 25223c60ba66SKatsushi Kobayashi db_tr = STAILQ_NEXT(db_tr, link); 25233c60ba66SKatsushi Kobayashi } 252453f1eb86SHidetoshi Shimokawa db = ((struct fwohcidb_tr *)bulkxfer->end)->db; 252577ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf); 252677ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf); 252753f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npackets changes */ 252853f1eb86SHidetoshi Shimokawa db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 25294ed65ce9SHidetoshi Shimokawa /* OHCI 1.1 and above */ 253053f1eb86SHidetoshi Shimokawa db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 253153f1eb86SHidetoshi Shimokawa #endif 253253f1eb86SHidetoshi Shimokawa /* 25333c60ba66SKatsushi Kobayashi db_tr = (struct fwohcidb_tr *)bulkxfer->start; 25343c60ba66SKatsushi Kobayashi fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; 253577ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr); 25363c60ba66SKatsushi Kobayashi */ 25373c60ba66SKatsushi Kobayashi return; 25383c60ba66SKatsushi Kobayashi } 2539c572b810SHidetoshi Shimokawa 2540c572b810SHidetoshi Shimokawa static int 254177ee030bSHidetoshi Shimokawa fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 254277ee030bSHidetoshi Shimokawa int poffset) 25433c60ba66SKatsushi Kobayashi { 2544c4778b5dSHidetoshi Shimokawa struct fwohcidb *db = db_tr->db; 254577ee030bSHidetoshi Shimokawa struct fw_xferq *it; 25463c60ba66SKatsushi Kobayashi int err = 0; 254777ee030bSHidetoshi Shimokawa 254877ee030bSHidetoshi Shimokawa it = &dbch->xferq; 254977ee030bSHidetoshi Shimokawa if (it->buf == 0) { 25503c60ba66SKatsushi Kobayashi err = EINVAL; 25513c60ba66SKatsushi Kobayashi return err; 25523c60ba66SKatsushi Kobayashi } 255377ee030bSHidetoshi Shimokawa db_tr->buf = fwdma_v_addr(it->buf, poffset); 25543c60ba66SKatsushi Kobayashi db_tr->dbcnt = 3; 25553c60ba66SKatsushi Kobayashi 255677ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[0].db.desc.cmd, 255777ee030bSHidetoshi Shimokawa OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8); 2558a1c9e73aSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0); 2559c4778b5dSHidetoshi Shimokawa bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed)); 256077ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[2].db.desc.addr, 256103161bbcSDoug Rabson fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t)); 256277ee030bSHidetoshi Shimokawa 256377ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[2].db.desc.cmd, 256477ee030bSHidetoshi Shimokawa OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS); 256553f1eb86SHidetoshi Shimokawa #if 1 256677ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[0].db.desc.res, 0); 256777ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 256853f1eb86SHidetoshi Shimokawa #endif 256977ee030bSHidetoshi Shimokawa return 0; 25703c60ba66SKatsushi Kobayashi } 2571c572b810SHidetoshi Shimokawa 2572c572b810SHidetoshi Shimokawa int 257377ee030bSHidetoshi Shimokawa fwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 257477ee030bSHidetoshi Shimokawa int poffset, struct fwdma_alloc *dummy_dma) 25753c60ba66SKatsushi Kobayashi { 2576c4778b5dSHidetoshi Shimokawa struct fwohcidb *db = db_tr->db; 257777ee030bSHidetoshi Shimokawa struct fw_xferq *ir; 257877ee030bSHidetoshi Shimokawa int i, ldesc; 257977ee030bSHidetoshi Shimokawa bus_addr_t dbuf[2]; 25803c60ba66SKatsushi Kobayashi int dsiz[2]; 25813c60ba66SKatsushi Kobayashi 258277ee030bSHidetoshi Shimokawa ir = &dbch->xferq; 258377ee030bSHidetoshi Shimokawa if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) { 25845f3fa234SHidetoshi Shimokawa if (db_tr->buf == NULL) { 25855f3fa234SHidetoshi Shimokawa db_tr->buf = fwdma_malloc_size(dbch->dmat, 25865f3fa234SHidetoshi Shimokawa &db_tr->dma_map, ir->psize, &dbuf[0], 25875f3fa234SHidetoshi Shimokawa BUS_DMA_NOWAIT); 258877ee030bSHidetoshi Shimokawa if (db_tr->buf == NULL) 258977ee030bSHidetoshi Shimokawa return (ENOMEM); 25905f3fa234SHidetoshi Shimokawa } 25913c60ba66SKatsushi Kobayashi db_tr->dbcnt = 1; 259277ee030bSHidetoshi Shimokawa dsiz[0] = ir->psize; 259377ee030bSHidetoshi Shimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 259477ee030bSHidetoshi Shimokawa BUS_DMASYNC_PREREAD); 25953c60ba66SKatsushi Kobayashi } else { 259677ee030bSHidetoshi Shimokawa db_tr->dbcnt = 0; 259777ee030bSHidetoshi Shimokawa if (dummy_dma != NULL) { 259803161bbcSDoug Rabson dsiz[db_tr->dbcnt] = sizeof(uint32_t); 259977ee030bSHidetoshi Shimokawa dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr; 260077ee030bSHidetoshi Shimokawa } 260177ee030bSHidetoshi Shimokawa dsiz[db_tr->dbcnt] = ir->psize; 260277ee030bSHidetoshi Shimokawa if (ir->buf != NULL) { 260377ee030bSHidetoshi Shimokawa db_tr->buf = fwdma_v_addr(ir->buf, poffset); 260477ee030bSHidetoshi Shimokawa dbuf[db_tr->dbcnt] = fwdma_bus_addr(ir->buf, poffset); 260577ee030bSHidetoshi Shimokawa } 260677ee030bSHidetoshi Shimokawa db_tr->dbcnt++; 26073c60ba66SKatsushi Kobayashi } 26083c60ba66SKatsushi Kobayashi for (i = 0; i < db_tr->dbcnt; i++) { 260977ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]); 261077ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]); 261177ee030bSHidetoshi Shimokawa if (ir->flag & FWXFERQ_STREAM) { 261277ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE); 26133c60ba66SKatsushi Kobayashi } 261477ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]); 26153c60ba66SKatsushi Kobayashi } 261677ee030bSHidetoshi Shimokawa ldesc = db_tr->dbcnt - 1; 261777ee030bSHidetoshi Shimokawa if (ir->flag & FWXFERQ_STREAM) { 261877ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST); 26193c60ba66SKatsushi Kobayashi } 262077ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS); 262177ee030bSHidetoshi Shimokawa return 0; 26223c60ba66SKatsushi Kobayashi } 2623c572b810SHidetoshi Shimokawa 262477ee030bSHidetoshi Shimokawa 262577ee030bSHidetoshi Shimokawa static int 262677ee030bSHidetoshi Shimokawa fwohci_arcv_swap(struct fw_pkt *fp, int len) 26273c60ba66SKatsushi Kobayashi { 262877ee030bSHidetoshi Shimokawa struct fw_pkt *fp0; 262903161bbcSDoug Rabson uint32_t ld0; 2630c4778b5dSHidetoshi Shimokawa int slen, hlen; 263177ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 263277ee030bSHidetoshi Shimokawa int i; 263377ee030bSHidetoshi Shimokawa #endif 26343c60ba66SKatsushi Kobayashi 263577ee030bSHidetoshi Shimokawa ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]); 263677ee030bSHidetoshi Shimokawa #if 0 263777ee030bSHidetoshi Shimokawa printf("ld0: x%08x\n", ld0); 263877ee030bSHidetoshi Shimokawa #endif 263977ee030bSHidetoshi Shimokawa fp0 = (struct fw_pkt *)&ld0; 2640c4778b5dSHidetoshi Shimokawa /* determine length to swap */ 264177ee030bSHidetoshi Shimokawa switch (fp0->mode.common.tcode) { 264277ee030bSHidetoshi Shimokawa case FWTCODE_RREQQ: 264377ee030bSHidetoshi Shimokawa case FWTCODE_WRES: 264477ee030bSHidetoshi Shimokawa case FWTCODE_WREQQ: 264577ee030bSHidetoshi Shimokawa case FWTCODE_RRESQ: 264677ee030bSHidetoshi Shimokawa case FWOHCITCODE_PHY: 264777ee030bSHidetoshi Shimokawa slen = 12; 26483c60ba66SKatsushi Kobayashi break; 264977ee030bSHidetoshi Shimokawa case FWTCODE_RREQB: 265077ee030bSHidetoshi Shimokawa case FWTCODE_WREQB: 265177ee030bSHidetoshi Shimokawa case FWTCODE_LREQ: 265277ee030bSHidetoshi Shimokawa case FWTCODE_RRESB: 265377ee030bSHidetoshi Shimokawa case FWTCODE_LRES: 265477ee030bSHidetoshi Shimokawa slen = 16; 26553c60ba66SKatsushi Kobayashi break; 26563c60ba66SKatsushi Kobayashi default: 265777ee030bSHidetoshi Shimokawa printf("Unknown tcode %d\n", fp0->mode.common.tcode); 265877ee030bSHidetoshi Shimokawa return (0); 26593c60ba66SKatsushi Kobayashi } 2660c4778b5dSHidetoshi Shimokawa hlen = tinfo[fp0->mode.common.tcode].hdr_len; 2661c4778b5dSHidetoshi Shimokawa if (hlen > len) { 266277ee030bSHidetoshi Shimokawa if (firewire_debug) 266377ee030bSHidetoshi Shimokawa printf("splitted header\n"); 2664c4778b5dSHidetoshi Shimokawa return (-hlen); 26653c60ba66SKatsushi Kobayashi } 266677ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 266777ee030bSHidetoshi Shimokawa for (i = 0; i < slen/4; i++) 266877ee030bSHidetoshi Shimokawa fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]); 266977ee030bSHidetoshi Shimokawa #endif 2670c4778b5dSHidetoshi Shimokawa return (hlen); 26713c60ba66SKatsushi Kobayashi } 26723c60ba66SKatsushi Kobayashi 26733c60ba66SKatsushi Kobayashi static int 267477ee030bSHidetoshi Shimokawa fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp) 26753c60ba66SKatsushi Kobayashi { 2676c4778b5dSHidetoshi Shimokawa struct tcode_info *info; 267777ee030bSHidetoshi Shimokawa int r; 26783c60ba66SKatsushi Kobayashi 2679c4778b5dSHidetoshi Shimokawa info = &tinfo[fp->mode.common.tcode]; 268003161bbcSDoug Rabson r = info->hdr_len + sizeof(uint32_t); 2681c4778b5dSHidetoshi Shimokawa if ((info->flag & FWTI_BLOCK_ASY) != 0) 268203161bbcSDoug Rabson r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t)); 2683c4778b5dSHidetoshi Shimokawa 26840cf4488aSHidetoshi Shimokawa if (r == sizeof(uint32_t)) { 2685c4778b5dSHidetoshi Shimokawa /* XXX */ 2686627d85fbSHidetoshi Shimokawa device_printf(sc->fc.dev, "Unknown tcode %d\n", 2687627d85fbSHidetoshi Shimokawa fp->mode.common.tcode); 26880cf4488aSHidetoshi Shimokawa return (-1); 26890cf4488aSHidetoshi Shimokawa } 2690c4778b5dSHidetoshi Shimokawa 2691627d85fbSHidetoshi Shimokawa if (r > dbch->xferq.psize) { 2692627d85fbSHidetoshi Shimokawa device_printf(sc->fc.dev, "Invalid packet length %d\n", r); 26930cf4488aSHidetoshi Shimokawa return (-1); 2694627d85fbSHidetoshi Shimokawa /* panic ? */ 2695627d85fbSHidetoshi Shimokawa } 2696c4778b5dSHidetoshi Shimokawa 2697627d85fbSHidetoshi Shimokawa return r; 26983c60ba66SKatsushi Kobayashi } 26993c60ba66SKatsushi Kobayashi 2700c572b810SHidetoshi Shimokawa static void 27010cf4488aSHidetoshi Shimokawa fwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch, 27020cf4488aSHidetoshi Shimokawa struct fwohcidb_tr *db_tr, uint32_t off, int wake) 270377ee030bSHidetoshi Shimokawa { 2704c4778b5dSHidetoshi Shimokawa struct fwohcidb *db = &db_tr->db[0]; 270577ee030bSHidetoshi Shimokawa 270677ee030bSHidetoshi Shimokawa FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf); 270777ee030bSHidetoshi Shimokawa FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize); 270877ee030bSHidetoshi Shimokawa FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1); 270977ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 271077ee030bSHidetoshi Shimokawa dbch->bottom = db_tr; 27110cf4488aSHidetoshi Shimokawa 27120cf4488aSHidetoshi Shimokawa if (wake) 27130cf4488aSHidetoshi Shimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 271477ee030bSHidetoshi Shimokawa } 271577ee030bSHidetoshi Shimokawa 271677ee030bSHidetoshi Shimokawa static void 2717c572b810SHidetoshi Shimokawa fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 27183c60ba66SKatsushi Kobayashi { 27193c60ba66SKatsushi Kobayashi struct fwohcidb_tr *db_tr; 272077ee030bSHidetoshi Shimokawa struct iovec vec[2]; 272177ee030bSHidetoshi Shimokawa struct fw_pkt pktbuf; 272277ee030bSHidetoshi Shimokawa int nvec; 27233c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 272403161bbcSDoug Rabson uint8_t *ld; 27250cf4488aSHidetoshi Shimokawa uint32_t stat, off, status, event; 27263c60ba66SKatsushi Kobayashi u_int spd; 272777ee030bSHidetoshi Shimokawa int len, plen, hlen, pcnt, offset; 27283c60ba66SKatsushi Kobayashi int s; 27293c60ba66SKatsushi Kobayashi caddr_t buf; 27303c60ba66SKatsushi Kobayashi int resCount; 27313c60ba66SKatsushi Kobayashi 27323c60ba66SKatsushi Kobayashi if (&sc->arrq == dbch) { 27333c60ba66SKatsushi Kobayashi off = OHCI_ARQOFF; 27343c60ba66SKatsushi Kobayashi } else if (&sc->arrs == dbch) { 27353c60ba66SKatsushi Kobayashi off = OHCI_ARSOFF; 27363c60ba66SKatsushi Kobayashi } else { 27373c60ba66SKatsushi Kobayashi return; 27383c60ba66SKatsushi Kobayashi } 27393c60ba66SKatsushi Kobayashi 27403c60ba66SKatsushi Kobayashi s = splfw(); 27413c60ba66SKatsushi Kobayashi db_tr = dbch->top; 27423c60ba66SKatsushi Kobayashi pcnt = 0; 27433c60ba66SKatsushi Kobayashi /* XXX we cannot handle a packet which lies in more than two buf */ 274477ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 274577ee030bSHidetoshi Shimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 274677ee030bSHidetoshi Shimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT; 274777ee030bSHidetoshi Shimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK; 274877ee030bSHidetoshi Shimokawa while (status & OHCI_CNTL_DMA_ACTIVE) { 27490cf4488aSHidetoshi Shimokawa #if 0 27500cf4488aSHidetoshi Shimokawa 27510cf4488aSHidetoshi Shimokawa if (off == OHCI_ARQOFF) 27520cf4488aSHidetoshi Shimokawa printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n", 27530cf4488aSHidetoshi Shimokawa db_tr->bus_addr, status, resCount); 27540cf4488aSHidetoshi Shimokawa #endif 275577ee030bSHidetoshi Shimokawa len = dbch->xferq.psize - resCount; 275603161bbcSDoug Rabson ld = (uint8_t *)db_tr->buf; 275777ee030bSHidetoshi Shimokawa if (dbch->pdb_tr == NULL) { 275877ee030bSHidetoshi Shimokawa len -= dbch->buf_offset; 275977ee030bSHidetoshi Shimokawa ld += dbch->buf_offset; 276077ee030bSHidetoshi Shimokawa } 276177ee030bSHidetoshi Shimokawa if (len > 0) 276277ee030bSHidetoshi Shimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 276377ee030bSHidetoshi Shimokawa BUS_DMASYNC_POSTREAD); 27643c60ba66SKatsushi Kobayashi while (len > 0) { 2765783058faSHidetoshi Shimokawa if (count >= 0 && count-- == 0) 2766783058faSHidetoshi Shimokawa goto out; 276777ee030bSHidetoshi Shimokawa if (dbch->pdb_tr != NULL) { 276877ee030bSHidetoshi Shimokawa /* we have a fragment in previous buffer */ 276977ee030bSHidetoshi Shimokawa int rlen; 27703c60ba66SKatsushi Kobayashi 277177ee030bSHidetoshi Shimokawa offset = dbch->buf_offset; 277277ee030bSHidetoshi Shimokawa if (offset < 0) 277377ee030bSHidetoshi Shimokawa offset = - offset; 277477ee030bSHidetoshi Shimokawa buf = dbch->pdb_tr->buf + offset; 277577ee030bSHidetoshi Shimokawa rlen = dbch->xferq.psize - offset; 277677ee030bSHidetoshi Shimokawa if (firewire_debug) 277777ee030bSHidetoshi Shimokawa printf("rlen=%d, offset=%d\n", 277877ee030bSHidetoshi Shimokawa rlen, dbch->buf_offset); 277977ee030bSHidetoshi Shimokawa if (dbch->buf_offset < 0) { 278077ee030bSHidetoshi Shimokawa /* splitted in header, pull up */ 278177ee030bSHidetoshi Shimokawa char *p; 278277ee030bSHidetoshi Shimokawa 278377ee030bSHidetoshi Shimokawa p = (char *)&pktbuf; 278477ee030bSHidetoshi Shimokawa bcopy(buf, p, rlen); 278577ee030bSHidetoshi Shimokawa p += rlen; 278677ee030bSHidetoshi Shimokawa /* this must be too long but harmless */ 278777ee030bSHidetoshi Shimokawa rlen = sizeof(pktbuf) - rlen; 278877ee030bSHidetoshi Shimokawa if (rlen < 0) 278977ee030bSHidetoshi Shimokawa printf("why rlen < 0\n"); 279077ee030bSHidetoshi Shimokawa bcopy(db_tr->buf, p, rlen); 27913c60ba66SKatsushi Kobayashi ld += rlen; 27923c60ba66SKatsushi Kobayashi len -= rlen; 279377ee030bSHidetoshi Shimokawa hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf)); 27940cf4488aSHidetoshi Shimokawa if (hlen <= 0) { 27950cf4488aSHidetoshi Shimokawa printf("hlen should be positive."); 27960cf4488aSHidetoshi Shimokawa goto err; 27973c60ba66SKatsushi Kobayashi } 279877ee030bSHidetoshi Shimokawa offset = sizeof(pktbuf); 279977ee030bSHidetoshi Shimokawa vec[0].iov_base = (char *)&pktbuf; 280077ee030bSHidetoshi Shimokawa vec[0].iov_len = offset; 28013c60ba66SKatsushi Kobayashi } else { 280277ee030bSHidetoshi Shimokawa /* splitted in payload */ 280377ee030bSHidetoshi Shimokawa offset = rlen; 280477ee030bSHidetoshi Shimokawa vec[0].iov_base = buf; 280577ee030bSHidetoshi Shimokawa vec[0].iov_len = rlen; 280677ee030bSHidetoshi Shimokawa } 280777ee030bSHidetoshi Shimokawa fp=(struct fw_pkt *)vec[0].iov_base; 280877ee030bSHidetoshi Shimokawa nvec = 1; 280977ee030bSHidetoshi Shimokawa } else { 281077ee030bSHidetoshi Shimokawa /* no fragment in previous buffer */ 28113c60ba66SKatsushi Kobayashi fp=(struct fw_pkt *)ld; 281277ee030bSHidetoshi Shimokawa hlen = fwohci_arcv_swap(fp, len); 281377ee030bSHidetoshi Shimokawa if (hlen == 0) 28140cf4488aSHidetoshi Shimokawa goto err; 281577ee030bSHidetoshi Shimokawa if (hlen < 0) { 281677ee030bSHidetoshi Shimokawa dbch->pdb_tr = db_tr; 281777ee030bSHidetoshi Shimokawa dbch->buf_offset = - dbch->buf_offset; 281877ee030bSHidetoshi Shimokawa /* sanity check */ 28190cf4488aSHidetoshi Shimokawa if (resCount != 0) { 28200cf4488aSHidetoshi Shimokawa printf("resCount=%d hlen=%d\n", 28210cf4488aSHidetoshi Shimokawa resCount, hlen); 28220cf4488aSHidetoshi Shimokawa goto err; 28230cf4488aSHidetoshi Shimokawa } 28243c60ba66SKatsushi Kobayashi goto out; 28253c60ba66SKatsushi Kobayashi } 282677ee030bSHidetoshi Shimokawa offset = 0; 282777ee030bSHidetoshi Shimokawa nvec = 0; 28283c60ba66SKatsushi Kobayashi } 282977ee030bSHidetoshi Shimokawa plen = fwohci_get_plen(sc, dbch, fp) - offset; 28303c60ba66SKatsushi Kobayashi if (plen < 0) { 283177ee030bSHidetoshi Shimokawa /* minimum header size + trailer 283277ee030bSHidetoshi Shimokawa = sizeof(fw_pkt) so this shouldn't happens */ 2833c4778b5dSHidetoshi Shimokawa printf("plen(%d) is negative! offset=%d\n", 2834c4778b5dSHidetoshi Shimokawa plen, offset); 28350cf4488aSHidetoshi Shimokawa goto err; 28363c60ba66SKatsushi Kobayashi } 283777ee030bSHidetoshi Shimokawa if (plen > 0) { 283877ee030bSHidetoshi Shimokawa len -= plen; 283977ee030bSHidetoshi Shimokawa if (len < 0) { 284077ee030bSHidetoshi Shimokawa dbch->pdb_tr = db_tr; 284177ee030bSHidetoshi Shimokawa if (firewire_debug) 284277ee030bSHidetoshi Shimokawa printf("splitted payload\n"); 284377ee030bSHidetoshi Shimokawa /* sanity check */ 28440cf4488aSHidetoshi Shimokawa if (resCount != 0) { 28450cf4488aSHidetoshi Shimokawa printf("resCount=%d plen=%d" 28460cf4488aSHidetoshi Shimokawa " len=%d\n", 28470cf4488aSHidetoshi Shimokawa resCount, plen, len); 28480cf4488aSHidetoshi Shimokawa goto err; 28490cf4488aSHidetoshi Shimokawa } 285077ee030bSHidetoshi Shimokawa goto out; 28513c60ba66SKatsushi Kobayashi } 285277ee030bSHidetoshi Shimokawa vec[nvec].iov_base = ld; 285377ee030bSHidetoshi Shimokawa vec[nvec].iov_len = plen; 285477ee030bSHidetoshi Shimokawa nvec++; 28553c60ba66SKatsushi Kobayashi ld += plen; 28563c60ba66SKatsushi Kobayashi } 285703161bbcSDoug Rabson dbch->buf_offset = ld - (uint8_t *)db_tr->buf; 285877ee030bSHidetoshi Shimokawa if (nvec == 0) 285977ee030bSHidetoshi Shimokawa printf("nvec == 0\n"); 286077ee030bSHidetoshi Shimokawa 28613c60ba66SKatsushi Kobayashi /* DMA result-code will be written at the tail of packet */ 28620cf4488aSHidetoshi Shimokawa stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer))); 286377ee030bSHidetoshi Shimokawa #if 0 2864c4778b5dSHidetoshi Shimokawa printf("plen: %d, stat %x\n", 2865c4778b5dSHidetoshi Shimokawa plen ,stat); 286677ee030bSHidetoshi Shimokawa #endif 28670cf4488aSHidetoshi Shimokawa spd = (stat >> 21) & 0x3; 28680cf4488aSHidetoshi Shimokawa event = (stat >> 16) & 0x1f; 28690cf4488aSHidetoshi Shimokawa switch (event) { 28703c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKPEND: 2871864d7e72SHidetoshi Shimokawa #if 0 287273aa55baSHidetoshi Shimokawa printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); 28733c60ba66SKatsushi Kobayashi #endif 28743c60ba66SKatsushi Kobayashi /* fall through */ 28753c60ba66SKatsushi Kobayashi case FWOHCIEV_ACKCOMPL: 2876c4778b5dSHidetoshi Shimokawa { 2877c4778b5dSHidetoshi Shimokawa struct fw_rcv_buf rb; 2878c4778b5dSHidetoshi Shimokawa 287977ee030bSHidetoshi Shimokawa if ((vec[nvec-1].iov_len -= 288077ee030bSHidetoshi Shimokawa sizeof(struct fwohci_trailer)) == 0) 288177ee030bSHidetoshi Shimokawa nvec--; 2882c4778b5dSHidetoshi Shimokawa rb.fc = &sc->fc; 2883c4778b5dSHidetoshi Shimokawa rb.vec = vec; 2884c4778b5dSHidetoshi Shimokawa rb.nvec = nvec; 2885c4778b5dSHidetoshi Shimokawa rb.spd = spd; 2886c4778b5dSHidetoshi Shimokawa fw_rcv(&rb); 28873c60ba66SKatsushi Kobayashi break; 2888c4778b5dSHidetoshi Shimokawa } 28893c60ba66SKatsushi Kobayashi case FWOHCIEV_BUSRST: 28907acf6963SHidetoshi Shimokawa if ((sc->fc.status != FWBUSRESET) && 28917acf6963SHidetoshi Shimokawa (sc->fc.status != FWBUSINIT)) 28923c60ba66SKatsushi Kobayashi printf("got BUSRST packet!?\n"); 28933c60ba66SKatsushi Kobayashi break; 28943c60ba66SKatsushi Kobayashi default: 28950cf4488aSHidetoshi Shimokawa device_printf(sc->fc.dev, 28960cf4488aSHidetoshi Shimokawa "Async DMA Receive error err=%02x %s" 28970cf4488aSHidetoshi Shimokawa " plen=%d offset=%d len=%d status=0x%08x" 28980cf4488aSHidetoshi Shimokawa " tcode=0x%x, stat=0x%08x\n", 28990cf4488aSHidetoshi Shimokawa event, fwohcicode[event], plen, 29000cf4488aSHidetoshi Shimokawa dbch->buf_offset, len, 29010cf4488aSHidetoshi Shimokawa OREAD(sc, OHCI_DMACTL(off)), 29020cf4488aSHidetoshi Shimokawa fp->mode.common.tcode, stat); 29030cf4488aSHidetoshi Shimokawa #if 1 /* XXX */ 29040cf4488aSHidetoshi Shimokawa goto err; 29053c60ba66SKatsushi Kobayashi #endif 29063c60ba66SKatsushi Kobayashi break; 29073c60ba66SKatsushi Kobayashi } 29083c60ba66SKatsushi Kobayashi pcnt++; 290977ee030bSHidetoshi Shimokawa if (dbch->pdb_tr != NULL) { 29100cf4488aSHidetoshi Shimokawa fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr, 29110cf4488aSHidetoshi Shimokawa off, 1); 291277ee030bSHidetoshi Shimokawa dbch->pdb_tr = NULL; 291377ee030bSHidetoshi Shimokawa } 291477ee030bSHidetoshi Shimokawa 291577ee030bSHidetoshi Shimokawa } 29163c60ba66SKatsushi Kobayashi out: 29173c60ba66SKatsushi Kobayashi if (resCount == 0) { 29183c60ba66SKatsushi Kobayashi /* done on this buffer */ 291977ee030bSHidetoshi Shimokawa if (dbch->pdb_tr == NULL) { 29200cf4488aSHidetoshi Shimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1); 29213c60ba66SKatsushi Kobayashi dbch->buf_offset = 0; 292277ee030bSHidetoshi Shimokawa } else 292377ee030bSHidetoshi Shimokawa if (dbch->pdb_tr != db_tr) 292477ee030bSHidetoshi Shimokawa printf("pdb_tr != db_tr\n"); 292577ee030bSHidetoshi Shimokawa db_tr = STAILQ_NEXT(db_tr, link); 292677ee030bSHidetoshi Shimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 292777ee030bSHidetoshi Shimokawa >> OHCI_STATUS_SHIFT; 292877ee030bSHidetoshi Shimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 292977ee030bSHidetoshi Shimokawa & OHCI_COUNT_MASK; 293077ee030bSHidetoshi Shimokawa /* XXX check buffer overrun */ 293177ee030bSHidetoshi Shimokawa dbch->top = db_tr; 29323c60ba66SKatsushi Kobayashi } else { 29333c60ba66SKatsushi Kobayashi dbch->buf_offset = dbch->xferq.psize - resCount; 29343c60ba66SKatsushi Kobayashi break; 29353c60ba66SKatsushi Kobayashi } 29363c60ba66SKatsushi Kobayashi /* XXX make sure DMA is not dead */ 29373c60ba66SKatsushi Kobayashi } 29383c60ba66SKatsushi Kobayashi #if 0 29393c60ba66SKatsushi Kobayashi if (pcnt < 1) 29403c60ba66SKatsushi Kobayashi printf("fwohci_arcv: no packets\n"); 29413c60ba66SKatsushi Kobayashi #endif 29423c60ba66SKatsushi Kobayashi splx(s); 29430cf4488aSHidetoshi Shimokawa return; 29440cf4488aSHidetoshi Shimokawa 29450cf4488aSHidetoshi Shimokawa err: 29460cf4488aSHidetoshi Shimokawa device_printf(sc->fc.dev, "AR DMA status=%x, ", 29470cf4488aSHidetoshi Shimokawa OREAD(sc, OHCI_DMACTL(off))); 29480cf4488aSHidetoshi Shimokawa dbch->pdb_tr = NULL; 29490cf4488aSHidetoshi Shimokawa /* skip until resCount != 0 */ 29500cf4488aSHidetoshi Shimokawa printf(" skip buffer"); 29510cf4488aSHidetoshi Shimokawa while (resCount == 0) { 29520cf4488aSHidetoshi Shimokawa printf(" #"); 29530cf4488aSHidetoshi Shimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0); 29540cf4488aSHidetoshi Shimokawa db_tr = STAILQ_NEXT(db_tr, link); 29550cf4488aSHidetoshi Shimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 29560cf4488aSHidetoshi Shimokawa & OHCI_COUNT_MASK; 295701f31278SSean Bruno } 29580cf4488aSHidetoshi Shimokawa printf(" done\n"); 29590cf4488aSHidetoshi Shimokawa dbch->top = db_tr; 29600cf4488aSHidetoshi Shimokawa dbch->buf_offset = dbch->xferq.psize - resCount; 29610cf4488aSHidetoshi Shimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 29620cf4488aSHidetoshi Shimokawa splx(s); 29633c60ba66SKatsushi Kobayashi } 2964