fwohci.c revision 277511
1139749Simp/*- 2113584Ssimokawa * Copyright (c) 2003 Hidetoshi Shimokawa 3103285Sikob * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4103285Sikob * All rights reserved. 5103285Sikob * 6103285Sikob * Redistribution and use in source and binary forms, with or without 7103285Sikob * modification, are permitted provided that the following conditions 8103285Sikob * are met: 9103285Sikob * 1. Redistributions of source code must retain the above copyright 10103285Sikob * notice, this list of conditions and the following disclaimer. 11103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 12103285Sikob * notice, this list of conditions and the following disclaimer in the 13103285Sikob * documentation and/or other materials provided with the distribution. 14103285Sikob * 3. All advertising materials mentioning features or use of this software 15103285Sikob * must display the acknowledgement as bellow: 16103285Sikob * 17106802Ssimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 18103285Sikob * 19103285Sikob * 4. The name of the author may not be used to endorse or promote products 20103285Sikob * derived from this software without specific prior written permission. 21103285Sikob * 22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23103285Sikob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24103285Sikob * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25103285Sikob * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26103285Sikob * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27103285Sikob * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28103285Sikob * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30103285Sikob * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31103285Sikob * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32103285Sikob * POSSIBILITY OF SUCH DAMAGE. 33272214Skan * 34103285Sikob * $FreeBSD: head/sys/dev/firewire/fwohci.c 277511 2015-01-21 20:08:24Z will $ 35103285Sikob * 36103285Sikob */ 37106802Ssimokawa 38103285Sikob#include <sys/param.h> 39103285Sikob#include <sys/systm.h> 40103285Sikob#include <sys/mbuf.h> 41103285Sikob#include <sys/malloc.h> 42103285Sikob#include <sys/sockio.h> 43169123Ssimokawa#include <sys/sysctl.h> 44103285Sikob#include <sys/bus.h> 45103285Sikob#include <sys/kernel.h> 46103285Sikob#include <sys/conf.h> 47113584Ssimokawa#include <sys/endian.h> 48170374Ssimokawa#include <sys/kdb.h> 49103285Sikob 50103285Sikob#include <machine/bus.h> 51277511Swill#include <machine/md_var.h> 52103285Sikob 53103285Sikob#include <dev/firewire/firewire.h> 54103285Sikob#include <dev/firewire/firewirereg.h> 55113584Ssimokawa#include <dev/firewire/fwdma.h> 56103285Sikob#include <dev/firewire/fwohcireg.h> 57103285Sikob#include <dev/firewire/fwohcivar.h> 58103285Sikob#include <dev/firewire/firewire_phy.h> 59103285Sikob 60103285Sikob#undef OHCI_DEBUG 61106802Ssimokawa 62267992Shselaskystatic int nocyclemaster; 63170400Ssimokawaint firewire_phydma_enable = 1; 64169123SsimokawaSYSCTL_DECL(_hw_firewire); 65267992ShselaskySYSCTL_INT(_hw_firewire, OID_AUTO, nocyclemaster, CTLFLAG_RWTUN, 66267992Shselasky &nocyclemaster, 0, "Do not send cycle start packets"); 67267992ShselaskySYSCTL_INT(_hw_firewire, OID_AUTO, phydma_enable, CTLFLAG_RWTUN, 68267992Shselasky &firewire_phydma_enable, 0, "Allow physical request DMA from firewire"); 69169123Ssimokawa 70272214Skanstatic char dbcode[16][0x10] = {"OUTM", "OUTL", "INPM", "INPL", 71272214Skan "STOR", "LOAD", "NOP ", "STOP",}; 72113584Ssimokawa 73272214Skanstatic char dbkey[8][0x10] = {"ST0", "ST1", "ST2", "ST3", 74272214Skan "UNDEF", "REG", "SYS", "DEV"}; 75272214Skanstatic char dbcond[4][0x10] = {"NEV", "C=1", "C=0", "ALL"}; 76272214Skanchar fwohcicode[32][0x20]= { 77272214Skan "No stat", "Undef", "long", "miss Ack err", 78272214Skan "FIFO underrun", "FIFO overrun", "desc err", "data read err", 79272214Skan "data write err", "bus reset", "timeout", "tcode err", 80272214Skan "Undef", "Undef", "unknown event", "flushed", 81272214Skan "Undef" ,"ack complete", "ack pend", "Undef", 82272214Skan "ack busy_X", "ack busy_A", "ack busy_B", "Undef", 83272214Skan "Undef", "Undef", "Undef", "ack tardy", 84272214Skan "Undef", "ack data_err", "ack type_err", ""}; 85113584Ssimokawa 86116376Ssimokawa#define MAX_SPEED 3 87124378Ssimokawaextern char *linkspeed[]; 88272214Skanuint32_t tagbit[4] = {1 << 28, 1 << 29, 1 << 30, 1 << 31}; 89103285Sikob 90103285Sikobstatic struct tcode_info tinfo[] = { 91170374Ssimokawa/* hdr_len block flag valid_response */ 92170374Ssimokawa/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_WRES}, 93170374Ssimokawa/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES}, 94170374Ssimokawa/* 2 WRES */ {12, FWTI_RES, 0xff}, 95170374Ssimokawa/* 3 XXX */ { 0, 0, 0xff}, 96170374Ssimokawa/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ}, 97170374Ssimokawa/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB}, 98170374Ssimokawa/* 6 RRESQ */ {16, FWTI_RES, 0xff}, 99170374Ssimokawa/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, 100170374Ssimokawa/* 8 CYCS */ { 0, 0, 0xff}, 101170374Ssimokawa/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES}, 102170374Ssimokawa/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR, 0xff}, 103170374Ssimokawa/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, 104170374Ssimokawa/* c XXX */ { 0, 0, 0xff}, 105170374Ssimokawa/* d XXX */ { 0, 0, 0xff}, 106170374Ssimokawa/* e PHY */ {12, FWTI_REQ, 0xff}, 107170374Ssimokawa/* f XXX */ { 0, 0, 0xff} 108103285Sikob}; 109103285Sikob 110272214Skan#define ATRQ_CH 0 111272214Skan#define ATRS_CH 1 112272214Skan#define ARRQ_CH 2 113272214Skan#define ARRS_CH 3 114272214Skan#define ITX_CH 4 115272214Skan#define IRX_CH 0x24 116272214Skan 117103285Sikob#define OHCI_WRITE_SIGMASK 0xffff0000 118103285Sikob#define OHCI_READ_SIGMASK 0xffff0000 119103285Sikob 120103285Sikob#define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x)) 121103285Sikob#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r)) 122103285Sikob 123124169Ssimokawastatic void fwohci_ibr (struct firewire_comm *); 124124169Ssimokawastatic void fwohci_db_init (struct fwohci_softc *, struct fwohci_dbch *); 125124169Ssimokawastatic void fwohci_db_free (struct fwohci_dbch *); 126124169Ssimokawastatic void fwohci_arcv (struct fwohci_softc *, struct fwohci_dbch *, int); 127124169Ssimokawastatic void fwohci_txd (struct fwohci_softc *, struct fwohci_dbch *); 128124169Ssimokawastatic void fwohci_start_atq (struct firewire_comm *); 129124169Ssimokawastatic void fwohci_start_ats (struct firewire_comm *); 130124169Ssimokawastatic void fwohci_start (struct fwohci_softc *, struct fwohci_dbch *); 131272214Skanstatic uint32_t fwphy_wrdata (struct fwohci_softc *, uint32_t, uint32_t); 132272214Skanstatic uint32_t fwphy_rddata (struct fwohci_softc *, uint32_t); 133124169Ssimokawastatic int fwohci_rx_enable (struct fwohci_softc *, struct fwohci_dbch *); 134124169Ssimokawastatic int fwohci_tx_enable (struct fwohci_softc *, struct fwohci_dbch *); 135124169Ssimokawastatic int fwohci_irx_enable (struct firewire_comm *, int); 136124169Ssimokawastatic int fwohci_irx_disable (struct firewire_comm *, int); 137113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 138129585Sdfrstatic void fwohci_irx_post (struct firewire_comm *, uint32_t *); 139113584Ssimokawa#endif 140124169Ssimokawastatic int fwohci_itxbuf_enable (struct firewire_comm *, int); 141124169Ssimokawastatic int fwohci_itx_disable (struct firewire_comm *, int); 142124169Ssimokawastatic void fwohci_timeout (void *); 143124169Ssimokawastatic void fwohci_set_intr (struct firewire_comm *, int); 144113584Ssimokawa 145124169Ssimokawastatic int fwohci_add_rx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *); 146124169Ssimokawastatic int fwohci_add_tx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int); 147272214Skanstatic void dump_db (struct fwohci_softc *, uint32_t); 148272214Skanstatic void print_db (struct fwohcidb_tr *, struct fwohcidb *, uint32_t , uint32_t); 149272214Skanstatic void dump_dma (struct fwohci_softc *, uint32_t); 150129585Sdfrstatic uint32_t fwohci_cyctimer (struct firewire_comm *); 151124169Ssimokawastatic void fwohci_rbuf_update (struct fwohci_softc *, int); 152124169Ssimokawastatic void fwohci_tbuf_update (struct fwohci_softc *, int); 153124169Ssimokawavoid fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *); 154170374Ssimokawastatic void fwohci_task_busreset(void *, int); 155170374Ssimokawastatic void fwohci_task_sid(void *, int); 156170374Ssimokawastatic void fwohci_task_dma(void *, int); 157103285Sikob 158103285Sikob/* 159103285Sikob * memory allocated for DMA programs 160103285Sikob */ 161103285Sikob#define DMA_PROG_ALLOC (8 * PAGE_SIZE) 162103285Sikob 163103285Sikob#define NDB FWMAXQUEUE 164103285Sikob 165103285Sikob#define OHCI_VERSION 0x00 166112523Ssimokawa#define OHCI_ATRETRY 0x08 167103285Sikob#define OHCI_CROMHDR 0x18 168103285Sikob#define OHCI_BUS_OPT 0x20 169258780Seadler#define OHCI_BUSIRMC (1U << 31) 170103285Sikob#define OHCI_BUSCMC (1 << 30) 171103285Sikob#define OHCI_BUSISC (1 << 29) 172103285Sikob#define OHCI_BUSBMC (1 << 28) 173103285Sikob#define OHCI_BUSPMC (1 << 27) 174103285Sikob#define OHCI_BUSFNC OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\ 175103285Sikob OHCI_BUSBMC | OHCI_BUSPMC 176103285Sikob 177103285Sikob#define OHCI_EUID_HI 0x24 178103285Sikob#define OHCI_EUID_LO 0x28 179103285Sikob 180103285Sikob#define OHCI_CROMPTR 0x34 181103285Sikob#define OHCI_HCCCTL 0x50 182103285Sikob#define OHCI_HCCCTLCLR 0x54 183103285Sikob#define OHCI_AREQHI 0x100 184103285Sikob#define OHCI_AREQHICLR 0x104 185103285Sikob#define OHCI_AREQLO 0x108 186103285Sikob#define OHCI_AREQLOCLR 0x10c 187103285Sikob#define OHCI_PREQHI 0x110 188103285Sikob#define OHCI_PREQHICLR 0x114 189103285Sikob#define OHCI_PREQLO 0x118 190103285Sikob#define OHCI_PREQLOCLR 0x11c 191103285Sikob#define OHCI_PREQUPPER 0x120 192277511Swill#define OHCI_PREQUPPER_MAX 0xffff0000 193103285Sikob 194103285Sikob#define OHCI_SID_BUF 0x64 195103285Sikob#define OHCI_SID_CNT 0x68 196258780Seadler#define OHCI_SID_ERR (1U << 31) 197103285Sikob#define OHCI_SID_CNT_MASK 0xffc 198103285Sikob 199103285Sikob#define OHCI_IT_STAT 0x90 200103285Sikob#define OHCI_IT_STATCLR 0x94 201103285Sikob#define OHCI_IT_MASK 0x98 202103285Sikob#define OHCI_IT_MASKCLR 0x9c 203103285Sikob 204103285Sikob#define OHCI_IR_STAT 0xa0 205103285Sikob#define OHCI_IR_STATCLR 0xa4 206103285Sikob#define OHCI_IR_MASK 0xa8 207103285Sikob#define OHCI_IR_MASKCLR 0xac 208103285Sikob 209103285Sikob#define OHCI_LNKCTL 0xe0 210103285Sikob#define OHCI_LNKCTLCLR 0xe4 211103285Sikob 212103285Sikob#define OHCI_PHYACCESS 0xec 213103285Sikob#define OHCI_CYCLETIMER 0xf0 214103285Sikob 215103285Sikob#define OHCI_DMACTL(off) (off) 216103285Sikob#define OHCI_DMACTLCLR(off) (off + 4) 217103285Sikob#define OHCI_DMACMD(off) (off + 0xc) 218103285Sikob#define OHCI_DMAMATCH(off) (off + 0x10) 219103285Sikob 220103285Sikob#define OHCI_ATQOFF 0x180 221103285Sikob#define OHCI_ATQCTL OHCI_ATQOFF 222103285Sikob#define OHCI_ATQCTLCLR (OHCI_ATQOFF + 4) 223103285Sikob#define OHCI_ATQCMD (OHCI_ATQOFF + 0xc) 224103285Sikob#define OHCI_ATQMATCH (OHCI_ATQOFF + 0x10) 225103285Sikob 226103285Sikob#define OHCI_ATSOFF 0x1a0 227103285Sikob#define OHCI_ATSCTL OHCI_ATSOFF 228103285Sikob#define OHCI_ATSCTLCLR (OHCI_ATSOFF + 4) 229103285Sikob#define OHCI_ATSCMD (OHCI_ATSOFF + 0xc) 230103285Sikob#define OHCI_ATSMATCH (OHCI_ATSOFF + 0x10) 231103285Sikob 232103285Sikob#define OHCI_ARQOFF 0x1c0 233103285Sikob#define OHCI_ARQCTL OHCI_ARQOFF 234103285Sikob#define OHCI_ARQCTLCLR (OHCI_ARQOFF + 4) 235103285Sikob#define OHCI_ARQCMD (OHCI_ARQOFF + 0xc) 236103285Sikob#define OHCI_ARQMATCH (OHCI_ARQOFF + 0x10) 237103285Sikob 238103285Sikob#define OHCI_ARSOFF 0x1e0 239103285Sikob#define OHCI_ARSCTL OHCI_ARSOFF 240103285Sikob#define OHCI_ARSCTLCLR (OHCI_ARSOFF + 4) 241103285Sikob#define OHCI_ARSCMD (OHCI_ARSOFF + 0xc) 242103285Sikob#define OHCI_ARSMATCH (OHCI_ARSOFF + 0x10) 243103285Sikob 244103285Sikob#define OHCI_ITOFF(CH) (0x200 + 0x10 * (CH)) 245103285Sikob#define OHCI_ITCTL(CH) (OHCI_ITOFF(CH)) 246103285Sikob#define OHCI_ITCTLCLR(CH) (OHCI_ITOFF(CH) + 4) 247103285Sikob#define OHCI_ITCMD(CH) (OHCI_ITOFF(CH) + 0xc) 248103285Sikob 249103285Sikob#define OHCI_IROFF(CH) (0x400 + 0x20 * (CH)) 250103285Sikob#define OHCI_IRCTL(CH) (OHCI_IROFF(CH)) 251103285Sikob#define OHCI_IRCTLCLR(CH) (OHCI_IROFF(CH) + 4) 252103285Sikob#define OHCI_IRCMD(CH) (OHCI_IROFF(CH) + 0xc) 253103285Sikob#define OHCI_IRMATCH(CH) (OHCI_IROFF(CH) + 0x10) 254103285Sikob 255103285Sikobd_ioctl_t fwohci_ioctl; 256103285Sikob 257103285Sikob/* 258103285Sikob * Communication with PHY device 259103285Sikob */ 260170374Ssimokawa/* XXX need lock for phy access */ 261129585Sdfrstatic uint32_t 262272214Skanfwphy_wrdata(struct fwohci_softc *sc, uint32_t addr, uint32_t data) 263103285Sikob{ 264129585Sdfr uint32_t fun; 265103285Sikob 266103285Sikob addr &= 0xf; 267103285Sikob data &= 0xff; 268103285Sikob 269272214Skan fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | 270272214Skan (data << PHYDEV_WRDATA)); 271103285Sikob OWRITE(sc, OHCI_PHYACCESS, fun); 272103285Sikob DELAY(100); 273103285Sikob 274272214Skan return (fwphy_rddata(sc, addr)); 275103285Sikob} 276103285Sikob 277129585Sdfrstatic uint32_t 278103285Sikobfwohci_set_bus_manager(struct firewire_comm *fc, u_int node) 279103285Sikob{ 280103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 281103285Sikob int i; 282129585Sdfr uint32_t bm; 283103285Sikob 284103285Sikob#define OHCI_CSR_DATA 0x0c 285103285Sikob#define OHCI_CSR_COMP 0x10 286103285Sikob#define OHCI_CSR_CONT 0x14 287103285Sikob#define OHCI_BUS_MANAGER_ID 0 288103285Sikob 289103285Sikob OWRITE(sc, OHCI_CSR_DATA, node); 290103285Sikob OWRITE(sc, OHCI_CSR_COMP, 0x3f); 291103285Sikob OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID); 292103285Sikob for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++) 293109280Ssimokawa DELAY(10); 294103285Sikob bm = OREAD(sc, OHCI_CSR_DATA); 295272214Skan if ((bm & 0x3f) == 0x3f) 296103285Sikob bm = node; 297132432Ssimokawa if (firewire_debug) 298188509Ssbruno device_printf(sc->fc.dev, "%s: %d->%d (loop=%d)\n", 299188509Ssbruno __func__, bm, node, i); 300272214Skan return (bm); 301103285Sikob} 302103285Sikob 303129585Sdfrstatic uint32_t 304272214Skanfwphy_rddata(struct fwohci_softc *sc, u_int addr) 305103285Sikob{ 306129585Sdfr uint32_t fun, stat; 307108500Ssimokawa u_int i, retry = 0; 308103285Sikob 309103285Sikob addr &= 0xf; 310108500Ssimokawa#define MAX_RETRY 100 311108500Ssimokawaagain: 312108500Ssimokawa OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL); 313103285Sikob fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR); 314103285Sikob OWRITE(sc, OHCI_PHYACCESS, fun); 315272214Skan for (i = 0; i < MAX_RETRY; i++) { 316103285Sikob fun = OREAD(sc, OHCI_PHYACCESS); 317103285Sikob if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0) 318103285Sikob break; 319109280Ssimokawa DELAY(100); 320103285Sikob } 321272214Skan if (i >= MAX_RETRY) { 322132432Ssimokawa if (firewire_debug) 323188509Ssbruno device_printf(sc->fc.dev, "%s: failed(1).\n", __func__); 324108527Ssimokawa if (++retry < MAX_RETRY) { 325109280Ssimokawa DELAY(100); 326108527Ssimokawa goto again; 327108527Ssimokawa } 328108500Ssimokawa } 329108500Ssimokawa /* Make sure that SCLK is started */ 330108500Ssimokawa stat = OREAD(sc, FWOHCI_INTSTAT); 331108500Ssimokawa if ((stat & OHCI_INT_REG_FAIL) != 0 || 332108500Ssimokawa ((fun >> PHYDEV_REGADDR) & 0xf) != addr) { 333132432Ssimokawa if (firewire_debug) 334188509Ssbruno device_printf(sc->fc.dev, "%s: failed(2).\n", __func__); 335108500Ssimokawa if (++retry < MAX_RETRY) { 336109280Ssimokawa DELAY(100); 337108500Ssimokawa goto again; 338108500Ssimokawa } 339108500Ssimokawa } 340188509Ssbruno if (firewire_debug > 1 || retry >= MAX_RETRY) 341272214Skan device_printf(sc->fc.dev, 342188509Ssbruno "%s:: 0x%x loop=%d, retry=%d\n", 343188509Ssbruno __func__, addr, i, retry); 344108500Ssimokawa#undef MAX_RETRY 345272214Skan return ((fun >> PHYDEV_RDDATA) & 0xff); 346103285Sikob} 347272214Skan 348103285Sikob/* Device specific ioctl. */ 349103285Sikobint 350130585Sphkfwohci_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 351103285Sikob{ 352103285Sikob struct firewire_softc *sc; 353103285Sikob struct fwohci_softc *fc; 354103285Sikob int unit = DEV2UNIT(dev); 355103285Sikob int err = 0; 356272214Skan struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data; 357129585Sdfr uint32_t *dmach = (uint32_t *) data; 358103285Sikob 359103285Sikob sc = devclass_get_softc(firewire_devclass, unit); 360272214Skan if (sc == NULL) 361272214Skan return (EINVAL); 362272214Skan 363103285Sikob fc = (struct fwohci_softc *)sc->fc; 364103285Sikob 365103285Sikob if (!data) 366272214Skan return (EINVAL); 367103285Sikob 368103285Sikob switch (cmd) { 369103285Sikob case FWOHCI_WRREG: 370103285Sikob#define OHCI_MAX_REG 0x800 371272214Skan if (reg->addr <= OHCI_MAX_REG) { 372103285Sikob OWRITE(fc, reg->addr, reg->data); 373103285Sikob reg->data = OREAD(fc, reg->addr); 374272214Skan } else { 375103285Sikob err = EINVAL; 376103285Sikob } 377103285Sikob break; 378103285Sikob case FWOHCI_RDREG: 379272214Skan if (reg->addr <= OHCI_MAX_REG) { 380103285Sikob reg->data = OREAD(fc, reg->addr); 381272214Skan } else { 382103285Sikob err = EINVAL; 383103285Sikob } 384103285Sikob break; 385103285Sikob/* Read DMA descriptors for debug */ 386103285Sikob case DUMPDMA: 387272214Skan if (*dmach <= OHCI_MAX_DMA_CH) { 388103285Sikob dump_dma(fc, *dmach); 389103285Sikob dump_db(fc, *dmach); 390272214Skan } else { 391103285Sikob err = EINVAL; 392103285Sikob } 393103285Sikob break; 394119118Ssimokawa/* Read/Write Phy registers */ 395119118Ssimokawa#define OHCI_MAX_PHY_REG 0xf 396119118Ssimokawa case FWOHCI_RDPHYREG: 397119118Ssimokawa if (reg->addr <= OHCI_MAX_PHY_REG) 398119118Ssimokawa reg->data = fwphy_rddata(fc, reg->addr); 399119118Ssimokawa else 400119118Ssimokawa err = EINVAL; 401119118Ssimokawa break; 402119118Ssimokawa case FWOHCI_WRPHYREG: 403119118Ssimokawa if (reg->addr <= OHCI_MAX_PHY_REG) 404119118Ssimokawa reg->data = fwphy_wrdata(fc, reg->addr, reg->data); 405119118Ssimokawa else 406119118Ssimokawa err = EINVAL; 407119118Ssimokawa break; 408103285Sikob default: 409119118Ssimokawa err = EINVAL; 410103285Sikob break; 411103285Sikob } 412103285Sikob return err; 413103285Sikob} 414106790Ssimokawa 415108530Ssimokawastatic int 416108530Ssimokawafwohci_probe_phy(struct fwohci_softc *sc, device_t dev) 417103285Sikob{ 418129585Sdfr uint32_t reg, reg2; 419108530Ssimokawa int e1394a = 1; 420272214Skan 421272214Skan /* 422272214Skan * probe PHY parameters 423272214Skan * 0. to prove PHY version, whether compliance of 1394a. 424272214Skan * 1. to probe maximum speed supported by the PHY and 425272214Skan * number of port supported by core-logic. 426272214Skan * It is not actually available port on your PC . 427272214Skan */ 428108530Ssimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS); 429167685Ssimokawa DELAY(500); 430167685Ssimokawa 431108530Ssimokawa reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 432108530Ssimokawa 433272214Skan if ((reg >> 5) != 7) { 434108530Ssimokawa sc->fc.mode &= ~FWPHYASYST; 435108530Ssimokawa sc->fc.nport = reg & FW_PHY_NP; 436108530Ssimokawa sc->fc.speed = reg & FW_PHY_SPD >> 6; 437108530Ssimokawa if (sc->fc.speed > MAX_SPEED) { 438108530Ssimokawa device_printf(dev, "invalid speed %d (fixed to %d).\n", 439108530Ssimokawa sc->fc.speed, MAX_SPEED); 440108530Ssimokawa sc->fc.speed = MAX_SPEED; 441108530Ssimokawa } 442108530Ssimokawa device_printf(dev, 443108701Ssimokawa "Phy 1394 only %s, %d ports.\n", 444108701Ssimokawa linkspeed[sc->fc.speed], sc->fc.nport); 445272214Skan } else { 446108530Ssimokawa reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG); 447108530Ssimokawa sc->fc.mode |= FWPHYASYST; 448108530Ssimokawa sc->fc.nport = reg & FW_PHY_NP; 449108530Ssimokawa sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5; 450108530Ssimokawa if (sc->fc.speed > MAX_SPEED) { 451108530Ssimokawa device_printf(dev, "invalid speed %d (fixed to %d).\n", 452108530Ssimokawa sc->fc.speed, MAX_SPEED); 453108530Ssimokawa sc->fc.speed = MAX_SPEED; 454108530Ssimokawa } 455108530Ssimokawa device_printf(dev, 456108701Ssimokawa "Phy 1394a available %s, %d ports.\n", 457108701Ssimokawa linkspeed[sc->fc.speed], sc->fc.nport); 458108530Ssimokawa 459108530Ssimokawa /* check programPhyEnable */ 460108530Ssimokawa reg2 = fwphy_rddata(sc, 5); 461108530Ssimokawa#if 0 462108530Ssimokawa if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) { 463108530Ssimokawa#else /* XXX force to enable 1394a */ 464108530Ssimokawa if (e1394a) { 465108530Ssimokawa#endif 466132432Ssimokawa if (firewire_debug) 467108530Ssimokawa device_printf(dev, 468108530Ssimokawa "Enable 1394a Enhancements\n"); 469108530Ssimokawa /* enable EAA EMC */ 470108530Ssimokawa reg2 |= 0x03; 471108530Ssimokawa /* set aPhyEnhanceEnable */ 472108530Ssimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN); 473108530Ssimokawa OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY); 474108530Ssimokawa } else { 475108530Ssimokawa /* for safe */ 476108530Ssimokawa reg2 &= ~0x83; 477108530Ssimokawa } 478108530Ssimokawa reg2 = fwphy_wrdata(sc, 5, reg2); 479108530Ssimokawa } 480108530Ssimokawa 481108530Ssimokawa reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 482272214Skan if ((reg >> 5) == 7) { 483108530Ssimokawa reg = fwphy_rddata(sc, 4); 484108530Ssimokawa reg |= 1 << 6; 485108530Ssimokawa fwphy_wrdata(sc, 4, reg); 486108530Ssimokawa reg = fwphy_rddata(sc, 4); 487108530Ssimokawa } 488108530Ssimokawa return 0; 489108530Ssimokawa} 490108530Ssimokawa 491108530Ssimokawa 492108530Ssimokawavoid 493108530Ssimokawafwohci_reset(struct fwohci_softc *sc, device_t dev) 494108530Ssimokawa{ 495108701Ssimokawa int i, max_rec, speed; 496129585Sdfr uint32_t reg, reg2; 497103285Sikob struct fwohcidb_tr *db_tr; 498103285Sikob 499272214Skan /* Disable interrupts */ 500108530Ssimokawa OWRITE(sc, FWOHCI_INTMASKCLR, ~0); 501108530Ssimokawa 502129541Sdfr /* Now stopping all DMA channels */ 503272214Skan OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 504272214Skan OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 505272214Skan OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 506272214Skan OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 507108530Ssimokawa 508272214Skan OWRITE(sc, OHCI_IR_MASKCLR, ~0); 509272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 510272214Skan OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 511272214Skan OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 512108530Ssimokawa } 513108530Ssimokawa 514108701Ssimokawa /* FLUSH FIFO and reset Transmitter/Reciever */ 515108530Ssimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 516132432Ssimokawa if (firewire_debug) 517108530Ssimokawa device_printf(dev, "resetting OHCI..."); 518108530Ssimokawa i = 0; 519272214Skan while (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) { 520108530Ssimokawa if (i++ > 100) break; 521108530Ssimokawa DELAY(1000); 522108530Ssimokawa } 523132432Ssimokawa if (firewire_debug) 524108530Ssimokawa printf("done (loop=%d)\n", i); 525108530Ssimokawa 526108701Ssimokawa /* Probe phy */ 527108701Ssimokawa fwohci_probe_phy(sc, dev); 528108701Ssimokawa 529108701Ssimokawa /* Probe link */ 530272214Skan reg = OREAD(sc, OHCI_BUS_OPT); 531108530Ssimokawa reg2 = reg | OHCI_BUSFNC; 532108701Ssimokawa max_rec = (reg & 0x0000f000) >> 12; 533108701Ssimokawa speed = (reg & 0x00000007); 534108701Ssimokawa device_printf(dev, "Link %s, max_rec %d bytes.\n", 535108701Ssimokawa linkspeed[speed], MAXREC(max_rec)); 536108701Ssimokawa /* XXX fix max_rec */ 537108701Ssimokawa sc->fc.maxrec = sc->fc.speed + 8; 538108701Ssimokawa if (max_rec != sc->fc.maxrec) { 539108701Ssimokawa reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12); 540108701Ssimokawa device_printf(dev, "max_rec %d -> %d\n", 541108701Ssimokawa MAXREC(max_rec), MAXREC(sc->fc.maxrec)); 542108701Ssimokawa } 543132432Ssimokawa if (firewire_debug) 544108530Ssimokawa device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2); 545272214Skan OWRITE(sc, OHCI_BUS_OPT, reg2); 546108530Ssimokawa 547108701Ssimokawa /* Initialize registers */ 548108530Ssimokawa OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]); 549113584Ssimokawa OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr); 550108530Ssimokawa OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND); 551108530Ssimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR); 552113584Ssimokawa OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr); 553108530Ssimokawa OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID); 554108530Ssimokawa 555108701Ssimokawa /* Enable link */ 556108530Ssimokawa OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN); 557108642Ssimokawa 558108701Ssimokawa /* Force to start async RX DMA */ 559108642Ssimokawa sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING; 560108642Ssimokawa sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING; 561108530Ssimokawa fwohci_rx_enable(sc, &sc->arrq); 562108530Ssimokawa fwohci_rx_enable(sc, &sc->arrs); 563108530Ssimokawa 564108701Ssimokawa /* Initialize async TX */ 565108701Ssimokawa OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 566108701Ssimokawa OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 567116978Ssimokawa 568108701Ssimokawa /* AT Retries */ 569108701Ssimokawa OWRITE(sc, FWOHCI_RETRY, 570108701Ssimokawa /* CycleLimit PhyRespRetries ATRespRetries ATReqRetries */ 571272214Skan (0xffff << 16) | (0x0f << 8) | (0x0f << 4) | 0x0f); 572116978Ssimokawa 573116978Ssimokawa sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq); 574116978Ssimokawa sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq); 575116978Ssimokawa sc->atrq.bottom = sc->atrq.top; 576116978Ssimokawa sc->atrs.bottom = sc->atrs.top; 577116978Ssimokawa 578272214Skan for (i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb; 579272214Skan i++, db_tr = STAILQ_NEXT(db_tr, link)) { 580108530Ssimokawa db_tr->xfer = NULL; 581108530Ssimokawa } 582272214Skan for (i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb; 583272214Skan i++, db_tr = STAILQ_NEXT(db_tr, link)) { 584108530Ssimokawa db_tr->xfer = NULL; 585108530Ssimokawa } 586108530Ssimokawa 587129541Sdfr /* Enable interrupts */ 588170374Ssimokawa sc->intmask = (OHCI_INT_ERR | OHCI_INT_PHY_SID 589272214Skan | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 590108530Ssimokawa | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 591108530Ssimokawa | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); 592170374Ssimokawa sc->intmask |= OHCI_INT_DMA_IR | OHCI_INT_DMA_IT; 593170374Ssimokawa sc->intmask |= OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT; 594170374Ssimokawa OWRITE(sc, FWOHCI_INTMASK, sc->intmask); 595108530Ssimokawa fwohci_set_intr(&sc->fc, 1); 596108530Ssimokawa} 597108530Ssimokawa 598108530Ssimokawaint 599108530Ssimokawafwohci_init(struct fwohci_softc *sc, device_t dev) 600108530Ssimokawa{ 601121781Ssimokawa int i, mver; 602129585Sdfr uint32_t reg; 603129585Sdfr uint8_t ui[8]; 604108530Ssimokawa 605121781Ssimokawa/* OHCI version */ 606103285Sikob reg = OREAD(sc, OHCI_VERSION); 607121781Ssimokawa mver = (reg >> 16) & 0xff; 608103285Sikob device_printf(dev, "OHCI version %x.%x (ROM=%d)\n", 609272214Skan mver, reg & 0xff, (reg >> 24) & 1); 610121781Ssimokawa if (mver < 1 || mver > 9) { 611118416Ssimokawa device_printf(dev, "invalid OHCI version\n"); 612118416Ssimokawa return (ENXIO); 613118416Ssimokawa } 614118416Ssimokawa 615129541Sdfr/* Available Isochronous DMA channel probe */ 616110045Ssimokawa OWRITE(sc, OHCI_IT_MASK, 0xffffffff); 617110045Ssimokawa OWRITE(sc, OHCI_IR_MASK, 0xffffffff); 618110045Ssimokawa reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK); 619110045Ssimokawa OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff); 620110045Ssimokawa OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff); 621110045Ssimokawa for (i = 0; i < 0x20; i++) 622110045Ssimokawa if ((reg & (1 << i)) == 0) 623110045Ssimokawa break; 624103285Sikob sc->fc.nisodma = i; 625129541Sdfr device_printf(dev, "No. of Isochronous channels is %d.\n", i); 626118820Ssimokawa if (i == 0) 627118820Ssimokawa return (ENXIO); 628103285Sikob 629103285Sikob sc->fc.arq = &sc->arrq.xferq; 630103285Sikob sc->fc.ars = &sc->arrs.xferq; 631103285Sikob sc->fc.atq = &sc->atrq.xferq; 632103285Sikob sc->fc.ats = &sc->atrs.xferq; 633103285Sikob 634113584Ssimokawa sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 635113584Ssimokawa sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 636113584Ssimokawa sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 637113584Ssimokawa sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 638113584Ssimokawa 639103285Sikob sc->arrq.xferq.start = NULL; 640103285Sikob sc->arrs.xferq.start = NULL; 641103285Sikob sc->atrq.xferq.start = fwohci_start_atq; 642103285Sikob sc->atrs.xferq.start = fwohci_start_ats; 643103285Sikob 644113584Ssimokawa sc->arrq.xferq.buf = NULL; 645113584Ssimokawa sc->arrs.xferq.buf = NULL; 646113584Ssimokawa sc->atrq.xferq.buf = NULL; 647113584Ssimokawa sc->atrs.xferq.buf = NULL; 648103285Sikob 649118293Ssimokawa sc->arrq.xferq.dmach = -1; 650118293Ssimokawa sc->arrs.xferq.dmach = -1; 651118293Ssimokawa sc->atrq.xferq.dmach = -1; 652118293Ssimokawa sc->atrs.xferq.dmach = -1; 653118293Ssimokawa 654103285Sikob sc->arrq.ndesc = 1; 655103285Sikob sc->arrs.ndesc = 1; 656110593Ssimokawa sc->atrq.ndesc = 8; /* equal to maximum of mbuf chains */ 657110593Ssimokawa sc->atrs.ndesc = 2; 658103285Sikob 659103285Sikob sc->arrq.ndb = NDB; 660103285Sikob sc->arrs.ndb = NDB / 2; 661103285Sikob sc->atrq.ndb = NDB; 662103285Sikob sc->atrs.ndb = NDB / 2; 663103285Sikob 664272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 665103285Sikob sc->fc.it[i] = &sc->it[i].xferq; 666103285Sikob sc->fc.ir[i] = &sc->ir[i].xferq; 667118293Ssimokawa sc->it[i].xferq.dmach = i; 668118293Ssimokawa sc->ir[i].xferq.dmach = i; 669103285Sikob sc->it[i].ndb = 0; 670103285Sikob sc->ir[i].ndb = 0; 671103285Sikob } 672103285Sikob 673103285Sikob sc->fc.tcode = tinfo; 674113584Ssimokawa sc->fc.dev = dev; 675103285Sikob 676113584Ssimokawa sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE, 677219543Smarius &sc->crom_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 678272214Skan if (sc->fc.config_rom == NULL) { 679113584Ssimokawa device_printf(dev, "config_rom alloc failed."); 680103285Sikob return ENOMEM; 681103285Sikob } 682103285Sikob 683116376Ssimokawa#if 0 684116376Ssimokawa bzero(&sc->fc.config_rom[0], CROMSIZE); 685103285Sikob sc->fc.config_rom[1] = 0x31333934; 686103285Sikob sc->fc.config_rom[2] = 0xf000a002; 687103285Sikob sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI); 688103285Sikob sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO); 689103285Sikob sc->fc.config_rom[5] = 0; 690103285Sikob sc->fc.config_rom[0] = (4 << 24) | (5 << 16); 691103285Sikob 692103285Sikob sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4); 693113584Ssimokawa#endif 694103285Sikob 695129541Sdfr/* SID recieve buffer must align 2^11 */ 696103285Sikob#define OHCI_SIDSIZE (1 << 11) 697113584Ssimokawa sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE, 698219543Smarius &sc->sid_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 699113584Ssimokawa if (sc->sid_buf == NULL) { 700113584Ssimokawa device_printf(dev, "sid_buf alloc failed."); 701108527Ssimokawa return ENOMEM; 702108527Ssimokawa } 703113584Ssimokawa 704129585Sdfr fwdma_malloc(&sc->fc, sizeof(uint32_t), sizeof(uint32_t), 705272214Skan &sc->dummy_dma, BUS_DMA_WAITOK); 706113584Ssimokawa 707113584Ssimokawa if (sc->dummy_dma.v_addr == NULL) { 708113584Ssimokawa device_printf(dev, "dummy_dma alloc failed."); 709109736Ssimokawa return ENOMEM; 710109736Ssimokawa } 711113584Ssimokawa 712113584Ssimokawa fwohci_db_init(sc, &sc->arrq); 713108527Ssimokawa if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0) 714108527Ssimokawa return ENOMEM; 715108527Ssimokawa 716113584Ssimokawa fwohci_db_init(sc, &sc->arrs); 717108527Ssimokawa if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0) 718108527Ssimokawa return ENOMEM; 719103285Sikob 720113584Ssimokawa fwohci_db_init(sc, &sc->atrq); 721108527Ssimokawa if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0) 722108527Ssimokawa return ENOMEM; 723108527Ssimokawa 724113584Ssimokawa fwohci_db_init(sc, &sc->atrs); 725108527Ssimokawa if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0) 726108527Ssimokawa return ENOMEM; 727103285Sikob 728109814Ssimokawa sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H); 729109814Ssimokawa sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L); 730272214Skan for (i = 0; i < 8; i++) 731109814Ssimokawa ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i); 732103285Sikob device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 733109814Ssimokawa ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]); 734109814Ssimokawa 735103285Sikob sc->fc.ioctl = fwohci_ioctl; 736103285Sikob sc->fc.cyctimer = fwohci_cyctimer; 737103285Sikob sc->fc.set_bmr = fwohci_set_bus_manager; 738103285Sikob sc->fc.ibr = fwohci_ibr; 739103285Sikob sc->fc.irx_enable = fwohci_irx_enable; 740103285Sikob sc->fc.irx_disable = fwohci_irx_disable; 741103285Sikob 742103285Sikob sc->fc.itx_enable = fwohci_itxbuf_enable; 743103285Sikob sc->fc.itx_disable = fwohci_itx_disable; 744113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 745103285Sikob sc->fc.irx_post = fwohci_irx_post; 746113584Ssimokawa#else 747113584Ssimokawa sc->fc.irx_post = NULL; 748113584Ssimokawa#endif 749103285Sikob sc->fc.itx_post = NULL; 750103285Sikob sc->fc.timeout = fwohci_timeout; 751103285Sikob sc->fc.poll = fwohci_poll; 752103285Sikob sc->fc.set_intr = fwohci_set_intr; 753106790Ssimokawa 754113584Ssimokawa sc->intmask = sc->irstat = sc->itstat = 0; 755113584Ssimokawa 756170374Ssimokawa /* Init task queue */ 757170374Ssimokawa sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK, 758170374Ssimokawa taskqueue_thread_enqueue, &sc->fc.taskqueue); 759170374Ssimokawa taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq", 760272214Skan device_get_unit(dev)); 761170374Ssimokawa TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc); 762170374Ssimokawa TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc); 763170374Ssimokawa TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc); 764170374Ssimokawa 765108530Ssimokawa fw_init(&sc->fc); 766108530Ssimokawa fwohci_reset(sc, dev); 767103285Sikob 768108530Ssimokawa return 0; 769103285Sikob} 770106790Ssimokawa 771106790Ssimokawavoid 772106790Ssimokawafwohci_timeout(void *arg) 773103285Sikob{ 774103285Sikob struct fwohci_softc *sc; 775103285Sikob 776103285Sikob sc = (struct fwohci_softc *)arg; 777103285Sikob} 778106790Ssimokawa 779129585Sdfruint32_t 780106790Ssimokawafwohci_cyctimer(struct firewire_comm *fc) 781103285Sikob{ 782103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 783272214Skan return (OREAD(sc, OHCI_CYCLETIMER)); 784103285Sikob} 785103285Sikob 786108527Ssimokawaint 787108527Ssimokawafwohci_detach(struct fwohci_softc *sc, device_t dev) 788108527Ssimokawa{ 789108527Ssimokawa int i; 790108527Ssimokawa 791113584Ssimokawa if (sc->sid_buf != NULL) 792113584Ssimokawa fwdma_free(&sc->fc, &sc->sid_dma); 793113584Ssimokawa if (sc->fc.config_rom != NULL) 794113584Ssimokawa fwdma_free(&sc->fc, &sc->crom_dma); 795108527Ssimokawa 796108527Ssimokawa fwohci_db_free(&sc->arrq); 797108527Ssimokawa fwohci_db_free(&sc->arrs); 798108527Ssimokawa 799108527Ssimokawa fwohci_db_free(&sc->atrq); 800108527Ssimokawa fwohci_db_free(&sc->atrs); 801108527Ssimokawa 802272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 803108527Ssimokawa fwohci_db_free(&sc->it[i]); 804108527Ssimokawa fwohci_db_free(&sc->ir[i]); 805108527Ssimokawa } 806170374Ssimokawa if (sc->fc.taskqueue != NULL) { 807170374Ssimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset); 808170374Ssimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid); 809170374Ssimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma); 810170374Ssimokawa taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout); 811170374Ssimokawa taskqueue_free(sc->fc.taskqueue); 812170374Ssimokawa sc->fc.taskqueue = NULL; 813170374Ssimokawa } 814108527Ssimokawa 815108527Ssimokawa return 0; 816108527Ssimokawa} 817108527Ssimokawa 818108655Ssimokawa#define LAST_DB(dbtr, db) do { \ 819108655Ssimokawa struct fwohcidb_tr *_dbtr = (dbtr); \ 820108655Ssimokawa int _cnt = _dbtr->dbcnt; \ 821108655Ssimokawa db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0]; \ 822108655Ssimokawa} while (0) 823272214Skan 824106790Ssimokawastatic void 825113584Ssimokawafwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error) 826113584Ssimokawa{ 827113584Ssimokawa struct fwohcidb_tr *db_tr; 828120660Ssimokawa struct fwohcidb *db; 829113584Ssimokawa bus_dma_segment_t *s; 830113584Ssimokawa int i; 831113584Ssimokawa 832113584Ssimokawa db_tr = (struct fwohcidb_tr *)arg; 833113584Ssimokawa db = &db_tr->db[db_tr->dbcnt]; 834113584Ssimokawa if (error) { 835113584Ssimokawa if (firewire_debug || error != EFBIG) 836113584Ssimokawa printf("fwohci_execute_db: error=%d\n", error); 837113584Ssimokawa return; 838113584Ssimokawa } 839113584Ssimokawa for (i = 0; i < nseg; i++) { 840113584Ssimokawa s = &segs[i]; 841113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr); 842113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len); 843113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 0); 844113584Ssimokawa db++; 845113584Ssimokawa db_tr->dbcnt++; 846113584Ssimokawa } 847113584Ssimokawa} 848113584Ssimokawa 849113584Ssimokawastatic void 850113584Ssimokawafwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg, 851272214Skan bus_size_t size, int error) 852113584Ssimokawa{ 853113584Ssimokawa fwohci_execute_db(arg, segs, nseg, error); 854113584Ssimokawa} 855113584Ssimokawa 856113584Ssimokawastatic void 857106790Ssimokawafwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 858103285Sikob{ 859277511Swill int i; 860120660Ssimokawa int tcode, hdr_len, pl_off; 861103285Sikob int fsegment = -1; 862129585Sdfr uint32_t off; 863103285Sikob struct fw_xfer *xfer; 864103285Sikob struct fw_pkt *fp; 865120660Ssimokawa struct fwohci_txpkthdr *ohcifp; 866103285Sikob struct fwohcidb_tr *db_tr; 867120660Ssimokawa struct fwohcidb *db; 868129585Sdfr uint32_t *ld; 869103285Sikob struct tcode_info *info; 870108655Ssimokawa static int maxdesc=0; 871103285Sikob 872170374Ssimokawa FW_GLOCK_ASSERT(&sc->fc); 873170374Ssimokawa 874272214Skan if (&sc->atrq == dbch) { 875103285Sikob off = OHCI_ATQOFF; 876272214Skan } else if (&sc->atrs == dbch) { 877103285Sikob off = OHCI_ATSOFF; 878272214Skan } else { 879103285Sikob return; 880103285Sikob } 881103285Sikob 882103285Sikob if (dbch->flags & FWOHCI_DBCH_FULL) 883103285Sikob return; 884103285Sikob 885103285Sikob db_tr = dbch->top; 886103285Sikobtxloop: 887103285Sikob xfer = STAILQ_FIRST(&dbch->xferq.q); 888272214Skan if (xfer == NULL) { 889103285Sikob goto kick; 890103285Sikob } 891170374Ssimokawa#if 0 892272214Skan if (dbch->xferq.queued == 0) { 893103285Sikob device_printf(sc->fc.dev, "TX queue empty\n"); 894103285Sikob } 895170374Ssimokawa#endif 896103285Sikob STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); 897103285Sikob db_tr->xfer = xfer; 898170374Ssimokawa xfer->flag = FWXF_START; 899103285Sikob 900120660Ssimokawa fp = &xfer->send.hdr; 901103285Sikob tcode = fp->mode.common.tcode; 902103285Sikob 903120660Ssimokawa ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed; 904103285Sikob info = &tinfo[tcode]; 905113584Ssimokawa hdr_len = pl_off = info->hdr_len; 906119155Ssimokawa 907119155Ssimokawa ld = &ohcifp->mode.ld[0]; 908119155Ssimokawa ld[0] = ld[1] = ld[2] = ld[3] = 0; 909272214Skan for (i = 0; i < pl_off; i+= 4) 910119155Ssimokawa ld[i/4] = fp->mode.ld[i/4]; 911119155Ssimokawa 912120660Ssimokawa ohcifp->mode.common.spd = xfer->send.spd & 0x7; 913272214Skan if (tcode == FWTCODE_STREAM) { 914103285Sikob hdr_len = 8; 915113584Ssimokawa ohcifp->mode.stream.len = fp->mode.stream.len; 916103285Sikob } else if (tcode == FWTCODE_PHY) { 917103285Sikob hdr_len = 12; 918119155Ssimokawa ld[1] = fp->mode.ld[1]; 919119155Ssimokawa ld[2] = fp->mode.ld[2]; 920103285Sikob ohcifp->mode.common.spd = 0; 921103285Sikob ohcifp->mode.common.tcode = FWOHCITCODE_PHY; 922103285Sikob } else { 923113584Ssimokawa ohcifp->mode.asycomm.dst = fp->mode.hdr.dst; 924103285Sikob ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; 925103285Sikob ohcifp->mode.asycomm.tlrt |= FWRETRY_X; 926103285Sikob } 927103285Sikob db = &db_tr->db[0]; 928113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.cmd, 929113584Ssimokawa OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len); 930119155Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.addr, 0); 931113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 0); 932103285Sikob/* Specify bound timer of asy. responce */ 933272214Skan if (&sc->atrs == dbch) { 934113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.res, 935113584Ssimokawa (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13)); 936103285Sikob } 937113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 938113584Ssimokawa if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ) 939113584Ssimokawa hdr_len = 12; 940272214Skan for (i = 0; i < hdr_len/4; i++) 941119155Ssimokawa FWOHCI_DMA_WRITE(ld[i], ld[i]); 942113584Ssimokawa#endif 943103285Sikob 944111942Ssimokawaagain: 945103285Sikob db_tr->dbcnt = 2; 946103285Sikob db = &db_tr->db[db_tr->dbcnt]; 947120660Ssimokawa if (xfer->send.pay_len > 0) { 948113584Ssimokawa int err; 949113584Ssimokawa /* handle payload */ 950103285Sikob if (xfer->mbuf == NULL) { 951113584Ssimokawa err = bus_dmamap_load(dbch->dmat, db_tr->dma_map, 952120660Ssimokawa &xfer->send.payload[0], xfer->send.pay_len, 953113584Ssimokawa fwohci_execute_db, db_tr, 954113584Ssimokawa /*flags*/0); 955103285Sikob } else { 956111942Ssimokawa /* XXX we can handle only 6 (=8-2) mbuf chains */ 957113584Ssimokawa err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 958113584Ssimokawa xfer->mbuf, 959113584Ssimokawa fwohci_execute_db2, db_tr, 960113584Ssimokawa /* flags */0); 961113584Ssimokawa if (err == EFBIG) { 962113584Ssimokawa struct mbuf *m0; 963113584Ssimokawa 964113584Ssimokawa if (firewire_debug) 965113584Ssimokawa device_printf(sc->fc.dev, "EFBIG.\n"); 966243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 967113584Ssimokawa if (m0 != NULL) { 968111942Ssimokawa m_copydata(xfer->mbuf, 0, 969111942Ssimokawa xfer->mbuf->m_pkthdr.len, 970113584Ssimokawa mtod(m0, caddr_t)); 971272214Skan m0->m_len = m0->m_pkthdr.len = 972111942Ssimokawa xfer->mbuf->m_pkthdr.len; 973111942Ssimokawa m_freem(xfer->mbuf); 974113584Ssimokawa xfer->mbuf = m0; 975111942Ssimokawa goto again; 976111942Ssimokawa } 977111942Ssimokawa device_printf(sc->fc.dev, "m_getcl failed.\n"); 978111942Ssimokawa } 979103285Sikob } 980113584Ssimokawa if (err) 981113584Ssimokawa printf("dmamap_load: err=%d\n", err); 982113584Ssimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 983113584Ssimokawa BUS_DMASYNC_PREWRITE); 984113584Ssimokawa#if 0 /* OHCI_OUTPUT_MODE == 0 */ 985113584Ssimokawa for (i = 2; i < db_tr->dbcnt; i++) 986113584Ssimokawa FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd, 987113584Ssimokawa OHCI_OUTPUT_MORE); 988113584Ssimokawa#endif 989103285Sikob } 990108655Ssimokawa if (maxdesc < db_tr->dbcnt) { 991108655Ssimokawa maxdesc = db_tr->dbcnt; 992132432Ssimokawa if (firewire_debug) 993187993Ssbruno device_printf(sc->fc.dev, "%s: maxdesc %d\n", __func__, maxdesc); 994108655Ssimokawa } 995103285Sikob /* last db */ 996103285Sikob LAST_DB(db_tr, db); 997113584Ssimokawa FWOHCI_DMA_SET(db->db.desc.cmd, 998113584Ssimokawa OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 999113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.depend, 1000113584Ssimokawa STAILQ_NEXT(db_tr, link)->bus_addr); 1001103285Sikob 1002272214Skan if (fsegment == -1) 1003103285Sikob fsegment = db_tr->dbcnt; 1004103285Sikob if (dbch->pdb_tr != NULL) { 1005103285Sikob LAST_DB(dbch->pdb_tr, db); 1006113584Ssimokawa FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt); 1007103285Sikob } 1008272214Skan dbch->xferq.queued++; 1009103285Sikob dbch->pdb_tr = db_tr; 1010103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 1011272214Skan if (db_tr != dbch->bottom) { 1012103285Sikob goto txloop; 1013103285Sikob } else { 1014107653Ssimokawa device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n"); 1015103285Sikob dbch->flags |= FWOHCI_DBCH_FULL; 1016103285Sikob } 1017103285Sikobkick: 1018103285Sikob /* kick asy q */ 1019113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1020113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1021103285Sikob 1022272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) { 1023103285Sikob OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 1024103285Sikob } else { 1025132432Ssimokawa if (firewire_debug) 1026107653Ssimokawa device_printf(sc->fc.dev, "start AT DMA status=%x\n", 1027103285Sikob OREAD(sc, OHCI_DMACTL(off))); 1028113584Ssimokawa OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment); 1029103285Sikob OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 1030103285Sikob dbch->xferq.flag |= FWXFERQ_RUNNING; 1031103285Sikob } 1032106790Ssimokawa 1033103285Sikob dbch->top = db_tr; 1034103285Sikob return; 1035103285Sikob} 1036106790Ssimokawa 1037106790Ssimokawastatic void 1038106790Ssimokawafwohci_start_atq(struct firewire_comm *fc) 1039103285Sikob{ 1040103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1041170374Ssimokawa FW_GLOCK(&sc->fc); 1042272214Skan fwohci_start(sc, &(sc->atrq)); 1043170374Ssimokawa FW_GUNLOCK(&sc->fc); 1044103285Sikob return; 1045103285Sikob} 1046106790Ssimokawa 1047106790Ssimokawastatic void 1048106790Ssimokawafwohci_start_ats(struct firewire_comm *fc) 1049103285Sikob{ 1050103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1051170374Ssimokawa FW_GLOCK(&sc->fc); 1052272214Skan fwohci_start(sc, &(sc->atrs)); 1053170374Ssimokawa FW_GUNLOCK(&sc->fc); 1054103285Sikob return; 1055103285Sikob} 1056106790Ssimokawa 1057106790Ssimokawavoid 1058106790Ssimokawafwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1059103285Sikob{ 1060113584Ssimokawa int s, ch, err = 0; 1061103285Sikob struct fwohcidb_tr *tr; 1062120660Ssimokawa struct fwohcidb *db; 1063103285Sikob struct fw_xfer *xfer; 1064129585Sdfr uint32_t off; 1065113584Ssimokawa u_int stat, status; 1066103285Sikob int packets; 1067103285Sikob struct firewire_comm *fc = (struct firewire_comm *)sc; 1068113584Ssimokawa 1069272214Skan if (&sc->atrq == dbch) { 1070103285Sikob off = OHCI_ATQOFF; 1071113584Ssimokawa ch = ATRQ_CH; 1072272214Skan } else if (&sc->atrs == dbch) { 1073103285Sikob off = OHCI_ATSOFF; 1074113584Ssimokawa ch = ATRS_CH; 1075272214Skan } else { 1076103285Sikob return; 1077103285Sikob } 1078103285Sikob s = splfw(); 1079103285Sikob tr = dbch->bottom; 1080103285Sikob packets = 0; 1081113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 1082113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 1083272214Skan while (dbch->xferq.queued > 0) { 1084103285Sikob LAST_DB(tr, db); 1085113584Ssimokawa status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT; 1086272214Skan if (!(status & OHCI_CNTL_DMA_ACTIVE)) { 1087272214Skan if (fc->status != FWBUSINIT) 1088103285Sikob /* maybe out of order?? */ 1089103285Sikob goto out; 1090103285Sikob } 1091113584Ssimokawa bus_dmamap_sync(dbch->dmat, tr->dma_map, 1092113584Ssimokawa BUS_DMASYNC_POSTWRITE); 1093113584Ssimokawa bus_dmamap_unload(dbch->dmat, tr->dma_map); 1094119155Ssimokawa#if 1 1095167629Ssimokawa if (firewire_debug > 1) 1096119155Ssimokawa dump_db(sc, ch); 1097103285Sikob#endif 1098272214Skan if (status & OHCI_CNTL_DMA_DEAD) { 1099113584Ssimokawa /* Stop DMA */ 1100103285Sikob OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 1101103285Sikob device_printf(sc->fc.dev, "force reset AT FIFO\n"); 1102103285Sikob OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN); 1103103285Sikob OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN); 1104103285Sikob OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 1105103285Sikob } 1106113584Ssimokawa stat = status & FWOHCIEV_MASK; 1107272214Skan switch (stat) { 1108110577Ssimokawa case FWOHCIEV_ACKPEND: 1109103285Sikob case FWOHCIEV_ACKCOMPL: 1110103285Sikob err = 0; 1111103285Sikob break; 1112103285Sikob case FWOHCIEV_ACKBSA: 1113103285Sikob case FWOHCIEV_ACKBSB: 1114110577Ssimokawa case FWOHCIEV_ACKBSX: 1115103285Sikob err = EBUSY; 1116103285Sikob break; 1117103285Sikob case FWOHCIEV_FLUSHED: 1118103285Sikob case FWOHCIEV_ACKTARD: 1119103285Sikob err = EAGAIN; 1120103285Sikob break; 1121103285Sikob case FWOHCIEV_MISSACK: 1122103285Sikob case FWOHCIEV_UNDRRUN: 1123103285Sikob case FWOHCIEV_OVRRUN: 1124103285Sikob case FWOHCIEV_DESCERR: 1125103285Sikob case FWOHCIEV_DTRDERR: 1126103285Sikob case FWOHCIEV_TIMEOUT: 1127103285Sikob case FWOHCIEV_TCODERR: 1128103285Sikob case FWOHCIEV_UNKNOWN: 1129103285Sikob case FWOHCIEV_ACKDERR: 1130103285Sikob case FWOHCIEV_ACKTERR: 1131103285Sikob default: 1132103285Sikob err = EINVAL; 1133103285Sikob break; 1134103285Sikob } 1135110577Ssimokawa if (tr->xfer != NULL) { 1136103285Sikob xfer = tr->xfer; 1137170374Ssimokawa if (xfer->flag & FWXF_RCVD) { 1138119289Ssimokawa#if 0 1139113584Ssimokawa if (firewire_debug) 1140113584Ssimokawa printf("already rcvd\n"); 1141119289Ssimokawa#endif 1142113584Ssimokawa fw_xfer_done(xfer); 1143113584Ssimokawa } else { 1144170427Ssimokawa microtime(&xfer->tv); 1145170374Ssimokawa xfer->flag = FWXF_SENT; 1146170425Ssimokawa if (err == EBUSY) { 1147170374Ssimokawa xfer->flag = FWXF_BUSY; 1148114218Ssimokawa xfer->resp = err; 1149167630Ssimokawa xfer->recv.pay_len = 0; 1150167630Ssimokawa fw_xfer_done(xfer); 1151114218Ssimokawa } else if (stat != FWOHCIEV_ACKPEND) { 1152114218Ssimokawa if (stat != FWOHCIEV_ACKCOMPL) 1153170374Ssimokawa xfer->flag = FWXF_SENTERR; 1154114218Ssimokawa xfer->resp = err; 1155120660Ssimokawa xfer->recv.pay_len = 0; 1156113584Ssimokawa fw_xfer_done(xfer); 1157114218Ssimokawa } 1158103285Sikob } 1159110577Ssimokawa /* 1160110577Ssimokawa * The watchdog timer takes care of split 1161272214Skan * transaction timeout for ACKPEND case. 1162110577Ssimokawa */ 1163113584Ssimokawa } else { 1164113584Ssimokawa printf("this shouldn't happen\n"); 1165103285Sikob } 1166170374Ssimokawa FW_GLOCK(fc); 1167272214Skan dbch->xferq.queued--; 1168170374Ssimokawa FW_GUNLOCK(fc); 1169103285Sikob tr->xfer = NULL; 1170103285Sikob 1171272214Skan packets++; 1172103285Sikob tr = STAILQ_NEXT(tr, link); 1173103285Sikob dbch->bottom = tr; 1174111956Ssimokawa if (dbch->bottom == dbch->top) { 1175111956Ssimokawa /* we reaches the end of context program */ 1176111956Ssimokawa if (firewire_debug && dbch->xferq.queued > 0) 1177111956Ssimokawa printf("queued > 0\n"); 1178111956Ssimokawa break; 1179111956Ssimokawa } 1180103285Sikob } 1181103285Sikobout: 1182103285Sikob if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { 1183103285Sikob printf("make free slot\n"); 1184103285Sikob dbch->flags &= ~FWOHCI_DBCH_FULL; 1185170374Ssimokawa FW_GLOCK(fc); 1186103285Sikob fwohci_start(sc, dbch); 1187170374Ssimokawa FW_GUNLOCK(fc); 1188103285Sikob } 1189103285Sikob splx(s); 1190103285Sikob} 1191106790Ssimokawa 1192106790Ssimokawastatic void 1193106790Ssimokawafwohci_db_free(struct fwohci_dbch *dbch) 1194103285Sikob{ 1195103285Sikob struct fwohcidb_tr *db_tr; 1196113584Ssimokawa int idb; 1197103285Sikob 1198108527Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1199108527Ssimokawa return; 1200108527Ssimokawa 1201272214Skan for (db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb; 1202272214Skan db_tr = STAILQ_NEXT(db_tr, link), idb++) { 1203113584Ssimokawa if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 && 1204272214Skan db_tr->buf != NULL) { 1205113584Ssimokawa fwdma_free_size(dbch->dmat, db_tr->dma_map, 1206113584Ssimokawa db_tr->buf, dbch->xferq.psize); 1207113584Ssimokawa db_tr->buf = NULL; 1208113584Ssimokawa } else if (db_tr->dma_map != NULL) 1209113584Ssimokawa bus_dmamap_destroy(dbch->dmat, db_tr->dma_map); 1210103285Sikob } 1211103285Sikob dbch->ndb = 0; 1212103285Sikob db_tr = STAILQ_FIRST(&dbch->db_trq); 1213113584Ssimokawa fwdma_free_multiseg(dbch->am); 1214110195Ssimokawa free(db_tr, M_FW); 1215103285Sikob STAILQ_INIT(&dbch->db_trq); 1216108527Ssimokawa dbch->flags &= ~FWOHCI_DBCH_INIT; 1217103285Sikob} 1218106790Ssimokawa 1219106790Ssimokawastatic void 1220113584Ssimokawafwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1221103285Sikob{ 1222103285Sikob int idb; 1223103285Sikob struct fwohcidb_tr *db_tr; 1224108642Ssimokawa 1225108642Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) != 0) 1226108642Ssimokawa goto out; 1227108642Ssimokawa 1228113584Ssimokawa /* create dma_tag for buffers */ 1229113584Ssimokawa#define MAX_REQCOUNT 0xffff 1230113584Ssimokawa if (bus_dma_tag_create(/*parent*/ sc->fc.dmat, 1231113584Ssimokawa /*alignment*/ 1, /*boundary*/ 0, 1232113584Ssimokawa /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 1233113584Ssimokawa /*highaddr*/ BUS_SPACE_MAXADDR, 1234113584Ssimokawa /*filter*/NULL, /*filterarg*/NULL, 1235113584Ssimokawa /*maxsize*/ dbch->xferq.psize, 1236113584Ssimokawa /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1, 1237113584Ssimokawa /*maxsegsz*/ MAX_REQCOUNT, 1238117126Sscottl /*flags*/ 0, 1239117126Sscottl /*lockfunc*/busdma_lock_mutex, 1240170374Ssimokawa /*lockarg*/FW_GMTX(&sc->fc), 1241117228Ssimokawa &dbch->dmat)) 1242113584Ssimokawa return; 1243113584Ssimokawa 1244103285Sikob /* allocate DB entries and attach one to each DMA channels */ 1245103285Sikob /* DB entry must start at 16 bytes bounary. */ 1246103285Sikob STAILQ_INIT(&dbch->db_trq); 1247103285Sikob db_tr = (struct fwohcidb_tr *) 1248103285Sikob malloc(sizeof(struct fwohcidb_tr) * dbch->ndb, 1249113584Ssimokawa M_FW, M_WAITOK | M_ZERO); 1250272214Skan if (db_tr == NULL) { 1251109379Ssimokawa printf("fwohci_db_init: malloc(1) failed\n"); 1252103285Sikob return; 1253103285Sikob } 1254109379Ssimokawa 1255113584Ssimokawa#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc) 1256272215Skan dbch->am = fwdma_malloc_multiseg(&sc->fc, sizeof(struct fwohcidb), 1257113584Ssimokawa DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK); 1258113584Ssimokawa if (dbch->am == NULL) { 1259113584Ssimokawa printf("fwohci_db_init: fwdma_malloc_multiseg failed\n"); 1260124836Ssimokawa free(db_tr, M_FW); 1261103285Sikob return; 1262103285Sikob } 1263103285Sikob /* Attach DB to DMA ch. */ 1264272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1265103285Sikob db_tr->dbcnt = 0; 1266113584Ssimokawa db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb); 1267113584Ssimokawa db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb); 1268113584Ssimokawa /* create dmamap for buffers */ 1269113584Ssimokawa /* XXX do we need 4bytes alignment tag? */ 1270113584Ssimokawa /* XXX don't alloc dma_map for AR */ 1271113584Ssimokawa if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) { 1272113584Ssimokawa printf("bus_dmamap_create failed\n"); 1273113584Ssimokawa dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */ 1274113584Ssimokawa fwohci_db_free(dbch); 1275113584Ssimokawa return; 1276113584Ssimokawa } 1277103285Sikob STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); 1278113584Ssimokawa if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1279108530Ssimokawa if (idb % dbch->xferq.bnpacket == 0) 1280108530Ssimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1281108530Ssimokawa ].start = (caddr_t)db_tr; 1282108530Ssimokawa if ((idb + 1) % dbch->xferq.bnpacket == 0) 1283108530Ssimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1284108530Ssimokawa ].end = (caddr_t)db_tr; 1285103285Sikob } 1286103285Sikob db_tr++; 1287103285Sikob } 1288103285Sikob STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next 1289103285Sikob = STAILQ_FIRST(&dbch->db_trq); 1290108642Ssimokawaout: 1291108642Ssimokawa dbch->xferq.queued = 0; 1292108642Ssimokawa dbch->pdb_tr = NULL; 1293103285Sikob dbch->top = STAILQ_FIRST(&dbch->db_trq); 1294103285Sikob dbch->bottom = dbch->top; 1295108527Ssimokawa dbch->flags = FWOHCI_DBCH_INIT; 1296103285Sikob} 1297106790Ssimokawa 1298106790Ssimokawastatic int 1299106790Ssimokawafwohci_itx_disable(struct firewire_comm *fc, int dmach) 1300103285Sikob{ 1301103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1302109890Ssimokawa 1303272214Skan OWRITE(sc, OHCI_ITCTLCLR(dmach), 1304113584Ssimokawa OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S); 1305103285Sikob OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1306103285Sikob OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1307109890Ssimokawa /* XXX we cannot free buffers until the DMA really stops */ 1308167086Sjhb pause("fwitxd", hz); 1309103285Sikob fwohci_db_free(&sc->it[dmach]); 1310103285Sikob sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1311103285Sikob return 0; 1312103285Sikob} 1313106790Ssimokawa 1314106790Ssimokawastatic int 1315106790Ssimokawafwohci_irx_disable(struct firewire_comm *fc, int dmach) 1316103285Sikob{ 1317103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1318103285Sikob 1319103285Sikob OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1320103285Sikob OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1321103285Sikob OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1322109890Ssimokawa /* XXX we cannot free buffers until the DMA really stops */ 1323167086Sjhb pause("fwirxd", hz); 1324103285Sikob fwohci_db_free(&sc->ir[dmach]); 1325103285Sikob sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1326103285Sikob return 0; 1327103285Sikob} 1328106790Ssimokawa 1329113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 1330106790Ssimokawastatic void 1331129585Sdfrfwohci_irx_post (struct firewire_comm *fc , uint32_t *qld) 1332103285Sikob{ 1333113584Ssimokawa qld[0] = FWOHCI_DMA_READ(qld[0]); 1334103285Sikob return; 1335103285Sikob} 1336103285Sikob#endif 1337103285Sikob 1338106790Ssimokawastatic int 1339106790Ssimokawafwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1340103285Sikob{ 1341103285Sikob int err = 0; 1342113584Ssimokawa int idb, z, i, dmach = 0, ldesc; 1343129585Sdfr uint32_t off = 0; 1344103285Sikob struct fwohcidb_tr *db_tr; 1345120660Ssimokawa struct fwohcidb *db; 1346103285Sikob 1347272214Skan if (!(dbch->xferq.flag & FWXFERQ_EXTBUF)) { 1348103285Sikob err = EINVAL; 1349103285Sikob return err; 1350103285Sikob } 1351103285Sikob z = dbch->ndesc; 1352272214Skan for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 1353272214Skan if (&sc->it[dmach] == dbch) { 1354103285Sikob off = OHCI_ITOFF(dmach); 1355103285Sikob break; 1356103285Sikob } 1357103285Sikob } 1358272214Skan if (off == 0) { 1359103285Sikob err = EINVAL; 1360103285Sikob return err; 1361103285Sikob } 1362272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) 1363103285Sikob return err; 1364103285Sikob dbch->xferq.flag |= FWXFERQ_RUNNING; 1365272214Skan for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 1366103285Sikob dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1367103285Sikob } 1368103285Sikob db_tr = dbch->top; 1369272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1370113584Ssimokawa fwohci_add_tx_buf(dbch, db_tr, idb); 1371272214Skan if (STAILQ_NEXT(db_tr, link) == NULL) { 1372103285Sikob break; 1373103285Sikob } 1374109892Ssimokawa db = db_tr->db; 1375113584Ssimokawa ldesc = db_tr->dbcnt - 1; 1376113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.depend, 1377113584Ssimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 1378113584Ssimokawa db[ldesc].db.desc.depend = db[0].db.desc.depend; 1379272214Skan if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1380272214Skan if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 1381113584Ssimokawa FWOHCI_DMA_SET( 1382113584Ssimokawa db[ldesc].db.desc.cmd, 1383113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1384109280Ssimokawa /* OHCI 1.1 and above */ 1385113584Ssimokawa FWOHCI_DMA_SET( 1386113584Ssimokawa db[0].db.desc.cmd, 1387113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1388103285Sikob } 1389103285Sikob } 1390103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 1391103285Sikob } 1392113584Ssimokawa FWOHCI_DMA_CLEAR( 1393113584Ssimokawa dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf); 1394103285Sikob return err; 1395103285Sikob} 1396106790Ssimokawa 1397106790Ssimokawastatic int 1398106790Ssimokawafwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1399103285Sikob{ 1400103285Sikob int err = 0; 1401109892Ssimokawa int idb, z, i, dmach = 0, ldesc; 1402129585Sdfr uint32_t off = 0; 1403103285Sikob struct fwohcidb_tr *db_tr; 1404120660Ssimokawa struct fwohcidb *db; 1405103285Sikob 1406103285Sikob z = dbch->ndesc; 1407272214Skan if (&sc->arrq == dbch) { 1408103285Sikob off = OHCI_ARQOFF; 1409272214Skan } else if (&sc->arrs == dbch) { 1410103285Sikob off = OHCI_ARSOFF; 1411272214Skan } else { 1412272214Skan for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 1413272214Skan if (&sc->ir[dmach] == dbch) { 1414103285Sikob off = OHCI_IROFF(dmach); 1415103285Sikob break; 1416103285Sikob } 1417103285Sikob } 1418103285Sikob } 1419272214Skan if (off == 0) { 1420103285Sikob err = EINVAL; 1421103285Sikob return err; 1422103285Sikob } 1423272214Skan if (dbch->xferq.flag & FWXFERQ_STREAM) { 1424272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) 1425103285Sikob return err; 1426272214Skan } else { 1427272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) { 1428103285Sikob err = EBUSY; 1429103285Sikob return err; 1430103285Sikob } 1431103285Sikob } 1432103285Sikob dbch->xferq.flag |= FWXFERQ_RUNNING; 1433108642Ssimokawa dbch->top = STAILQ_FIRST(&dbch->db_trq); 1434272214Skan for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 1435103285Sikob dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1436103285Sikob } 1437103285Sikob db_tr = dbch->top; 1438272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1439113584Ssimokawa fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma); 1440113584Ssimokawa if (STAILQ_NEXT(db_tr, link) == NULL) 1441103285Sikob break; 1442109892Ssimokawa db = db_tr->db; 1443109892Ssimokawa ldesc = db_tr->dbcnt - 1; 1444113584Ssimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend, 1445113584Ssimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 1446272214Skan if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1447272214Skan if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 1448113584Ssimokawa FWOHCI_DMA_SET( 1449113584Ssimokawa db[ldesc].db.desc.cmd, 1450113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1451113584Ssimokawa FWOHCI_DMA_CLEAR( 1452113584Ssimokawa db[ldesc].db.desc.depend, 1453113584Ssimokawa 0xf); 1454103285Sikob } 1455103285Sikob } 1456103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 1457103285Sikob } 1458113584Ssimokawa FWOHCI_DMA_CLEAR( 1459113584Ssimokawa dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf); 1460103285Sikob dbch->buf_offset = 0; 1461113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1462113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1463272214Skan if (dbch->xferq.flag & FWXFERQ_STREAM) { 1464103285Sikob return err; 1465272214Skan } else { 1466113584Ssimokawa OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z); 1467103285Sikob } 1468103285Sikob OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 1469103285Sikob return err; 1470103285Sikob} 1471106790Ssimokawa 1472106790Ssimokawastatic int 1473113584Ssimokawafwohci_next_cycle(struct firewire_comm *fc, int cycle_now) 1474109890Ssimokawa{ 1475109890Ssimokawa int sec, cycle, cycle_match; 1476109890Ssimokawa 1477109890Ssimokawa cycle = cycle_now & 0x1fff; 1478109890Ssimokawa sec = cycle_now >> 13; 1479109890Ssimokawa#define CYCLE_MOD 0x10 1480113584Ssimokawa#if 1 1481109890Ssimokawa#define CYCLE_DELAY 8 /* min delay to start DMA */ 1482113584Ssimokawa#else 1483113584Ssimokawa#define CYCLE_DELAY 7000 /* min delay to start DMA */ 1484113584Ssimokawa#endif 1485109890Ssimokawa cycle = cycle + CYCLE_DELAY; 1486109890Ssimokawa if (cycle >= 8000) { 1487272214Skan sec++; 1488109890Ssimokawa cycle -= 8000; 1489109890Ssimokawa } 1490113584Ssimokawa cycle = roundup2(cycle, CYCLE_MOD); 1491109890Ssimokawa if (cycle >= 8000) { 1492272214Skan sec++; 1493109890Ssimokawa if (cycle == 8000) 1494109890Ssimokawa cycle = 0; 1495109890Ssimokawa else 1496109890Ssimokawa cycle = CYCLE_MOD; 1497109890Ssimokawa } 1498109890Ssimokawa cycle_match = ((sec << 13) | cycle) & 0x7ffff; 1499109890Ssimokawa 1500272214Skan return (cycle_match); 1501109890Ssimokawa} 1502109890Ssimokawa 1503109890Ssimokawastatic int 1504106790Ssimokawafwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) 1505103285Sikob{ 1506103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1507103285Sikob int err = 0; 1508103285Sikob unsigned short tag, ich; 1509103285Sikob struct fwohci_dbch *dbch; 1510109890Ssimokawa int cycle_match, cycle_now, s, ldesc; 1511129585Sdfr uint32_t stat; 1512109890Ssimokawa struct fw_bulkxfer *first, *chunk, *prev; 1513109890Ssimokawa struct fw_xferq *it; 1514103285Sikob 1515103285Sikob dbch = &sc->it[dmach]; 1516109890Ssimokawa it = &dbch->xferq; 1517109890Ssimokawa 1518109890Ssimokawa tag = (it->flag >> 6) & 3; 1519109890Ssimokawa ich = it->flag & 0x3f; 1520109179Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { 1521109890Ssimokawa dbch->ndb = it->bnpacket * it->bnchunk; 1522103285Sikob dbch->ndesc = 3; 1523113584Ssimokawa fwohci_db_init(sc, dbch); 1524109179Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1525109179Ssimokawa return ENOMEM; 1526170374Ssimokawa 1527103285Sikob err = fwohci_tx_enable(sc, dbch); 1528103285Sikob } 1529272214Skan if (err) 1530103285Sikob return err; 1531109890Ssimokawa 1532109892Ssimokawa ldesc = dbch->ndesc - 1; 1533109890Ssimokawa s = splfw(); 1534170374Ssimokawa FW_GLOCK(fc); 1535109890Ssimokawa prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); 1536109890Ssimokawa while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { 1537120660Ssimokawa struct fwohcidb *db; 1538109890Ssimokawa 1539113584Ssimokawa fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket, 1540113584Ssimokawa BUS_DMASYNC_PREWRITE); 1541109890Ssimokawa fwohci_txbufdb(sc, dmach, chunk); 1542109890Ssimokawa if (prev != NULL) { 1543109890Ssimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 1544113584Ssimokawa#if 0 /* XXX necessary? */ 1545113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, 1546113584Ssimokawa OHCI_BRANCH_ALWAYS); 1547113584Ssimokawa#endif 1548109892Ssimokawa#if 0 /* if bulkxfer->npacket changes */ 1549272214Skan db[ldesc].db.desc.depend = db[0].db.desc.depend = 1550113584Ssimokawa ((struct fwohcidb_tr *) 1551113584Ssimokawa (chunk->start))->bus_addr | dbch->ndesc; 1552109892Ssimokawa#else 1553113584Ssimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 1554113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1555109892Ssimokawa#endif 1556103285Sikob } 1557109890Ssimokawa STAILQ_REMOVE_HEAD(&it->stvalid, link); 1558109890Ssimokawa STAILQ_INSERT_TAIL(&it->stdma, chunk, link); 1559109890Ssimokawa prev = chunk; 1560109403Ssimokawa } 1561170374Ssimokawa FW_GUNLOCK(fc); 1562113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1563113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1564109890Ssimokawa splx(s); 1565109890Ssimokawa stat = OREAD(sc, OHCI_ITCTL(dmach)); 1566113584Ssimokawa if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S)) 1567113584Ssimokawa printf("stat 0x%x\n", stat); 1568113584Ssimokawa 1569109890Ssimokawa if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) 1570109890Ssimokawa return 0; 1571109890Ssimokawa 1572113584Ssimokawa#if 0 1573109890Ssimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1574113584Ssimokawa#endif 1575109403Ssimokawa OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1576109403Ssimokawa OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1577109403Ssimokawa OWRITE(sc, OHCI_IT_MASK, 1 << dmach); 1578113584Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); 1579109890Ssimokawa 1580109890Ssimokawa first = STAILQ_FIRST(&it->stdma); 1581113584Ssimokawa OWRITE(sc, OHCI_ITCMD(dmach), 1582113584Ssimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); 1583167629Ssimokawa if (firewire_debug > 1) { 1584109890Ssimokawa printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); 1585113584Ssimokawa#if 1 1586113584Ssimokawa dump_dma(sc, ITX_CH + dmach); 1587113584Ssimokawa#endif 1588113584Ssimokawa } 1589109403Ssimokawa if ((stat & OHCI_CNTL_DMA_RUN) == 0) { 1590109890Ssimokawa#if 1 1591109890Ssimokawa /* Don't start until all chunks are buffered */ 1592109890Ssimokawa if (STAILQ_FIRST(&it->stfree) != NULL) 1593109890Ssimokawa goto out; 1594109890Ssimokawa#endif 1595113584Ssimokawa#if 1 1596109890Ssimokawa /* Clear cycle match counter bits */ 1597109890Ssimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); 1598109890Ssimokawa 1599109356Ssimokawa /* 2bit second + 13bit cycle */ 1600109356Ssimokawa cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; 1601113584Ssimokawa cycle_match = fwohci_next_cycle(fc, cycle_now); 1602109890Ssimokawa 1603109356Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), 1604109356Ssimokawa OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) 1605109356Ssimokawa | OHCI_CNTL_DMA_RUN); 1606113584Ssimokawa#else 1607113584Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); 1608113584Ssimokawa#endif 1609167629Ssimokawa if (firewire_debug > 1) { 1610109403Ssimokawa printf("cycle_match: 0x%04x->0x%04x\n", 1611109403Ssimokawa cycle_now, cycle_match); 1612113584Ssimokawa dump_dma(sc, ITX_CH + dmach); 1613113584Ssimokawa dump_db(sc, ITX_CH + dmach); 1614113584Ssimokawa } 1615109403Ssimokawa } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { 1616109890Ssimokawa device_printf(sc->fc.dev, 1617109890Ssimokawa "IT DMA underrun (0x%08x)\n", stat); 1618113584Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE); 1619103285Sikob } 1620109890Ssimokawaout: 1621103285Sikob return err; 1622103285Sikob} 1623106790Ssimokawa 1624106790Ssimokawastatic int 1625113584Ssimokawafwohci_irx_enable(struct firewire_comm *fc, int dmach) 1626103285Sikob{ 1627103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1628109890Ssimokawa int err = 0, s, ldesc; 1629103285Sikob unsigned short tag, ich; 1630129585Sdfr uint32_t stat; 1631109890Ssimokawa struct fwohci_dbch *dbch; 1632113584Ssimokawa struct fwohcidb_tr *db_tr; 1633109890Ssimokawa struct fw_bulkxfer *first, *prev, *chunk; 1634109890Ssimokawa struct fw_xferq *ir; 1635103285Sikob 1636109890Ssimokawa dbch = &sc->ir[dmach]; 1637109890Ssimokawa ir = &dbch->xferq; 1638109890Ssimokawa 1639109890Ssimokawa if ((ir->flag & FWXFERQ_RUNNING) == 0) { 1640109890Ssimokawa tag = (ir->flag >> 6) & 3; 1641109890Ssimokawa ich = ir->flag & 0x3f; 1642108995Ssimokawa OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 1643108995Ssimokawa 1644109890Ssimokawa ir->queued = 0; 1645109890Ssimokawa dbch->ndb = ir->bnpacket * ir->bnchunk; 1646109890Ssimokawa dbch->ndesc = 2; 1647113584Ssimokawa fwohci_db_init(sc, dbch); 1648109890Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1649109179Ssimokawa return ENOMEM; 1650109890Ssimokawa err = fwohci_rx_enable(sc, dbch); 1651103285Sikob } 1652272214Skan if (err) 1653103285Sikob return err; 1654103285Sikob 1655109890Ssimokawa first = STAILQ_FIRST(&ir->stfree); 1656109890Ssimokawa if (first == NULL) { 1657109890Ssimokawa device_printf(fc->dev, "IR DMA no free chunk\n"); 1658109890Ssimokawa return 0; 1659109890Ssimokawa } 1660109890Ssimokawa 1661111892Ssimokawa ldesc = dbch->ndesc - 1; 1662111892Ssimokawa s = splfw(); 1663170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 1664170374Ssimokawa FW_GLOCK(fc); 1665109890Ssimokawa prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); 1666109890Ssimokawa while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { 1667120660Ssimokawa struct fwohcidb *db; 1668109890Ssimokawa 1669111942Ssimokawa#if 1 /* XXX for if_fwe */ 1670113584Ssimokawa if (chunk->mbuf != NULL) { 1671113584Ssimokawa db_tr = (struct fwohcidb_tr *)(chunk->start); 1672113584Ssimokawa db_tr->dbcnt = 1; 1673113584Ssimokawa err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 1674113584Ssimokawa chunk->mbuf, fwohci_execute_db2, db_tr, 1675113584Ssimokawa /* flags */0); 1676113584Ssimokawa FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd, 1677113584Ssimokawa OHCI_UPDATE | OHCI_INPUT_LAST | 1678113584Ssimokawa OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 1679113584Ssimokawa } 1680111942Ssimokawa#endif 1681109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 1682113584Ssimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0); 1683113584Ssimokawa FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf); 1684109890Ssimokawa if (prev != NULL) { 1685109890Ssimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 1686113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1687103285Sikob } 1688109890Ssimokawa STAILQ_REMOVE_HEAD(&ir->stfree, link); 1689109890Ssimokawa STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); 1690109890Ssimokawa prev = chunk; 1691103285Sikob } 1692170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 1693170374Ssimokawa FW_GUNLOCK(fc); 1694113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1695113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1696109890Ssimokawa splx(s); 1697109890Ssimokawa stat = OREAD(sc, OHCI_IRCTL(dmach)); 1698109890Ssimokawa if (stat & OHCI_CNTL_DMA_ACTIVE) 1699109890Ssimokawa return 0; 1700109890Ssimokawa if (stat & OHCI_CNTL_DMA_RUN) { 1701109890Ssimokawa OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1702109890Ssimokawa device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); 1703109890Ssimokawa } 1704109890Ssimokawa 1705113584Ssimokawa if (firewire_debug) 1706113584Ssimokawa printf("start IR DMA 0x%x\n", stat); 1707109890Ssimokawa OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1708109890Ssimokawa OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1709109890Ssimokawa OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 1710109890Ssimokawa OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); 1711109890Ssimokawa OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 1712109890Ssimokawa OWRITE(sc, OHCI_IRCMD(dmach), 1713113584Ssimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr 1714109890Ssimokawa | dbch->ndesc); 1715109890Ssimokawa OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 1716109890Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 1717113584Ssimokawa#if 0 1718113584Ssimokawa dump_db(sc, IRX_CH + dmach); 1719113584Ssimokawa#endif 1720103285Sikob return err; 1721103285Sikob} 1722106790Ssimokawa 1723106790Ssimokawaint 1724110145Ssimokawafwohci_stop(struct fwohci_softc *sc, device_t dev) 1725103285Sikob{ 1726103285Sikob u_int i; 1727103285Sikob 1728178911Ssimokawa fwohci_set_intr(&sc->fc, 0); 1729178911Ssimokawa 1730103285Sikob/* Now stopping all DMA channel */ 1731272214Skan OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 1732272214Skan OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 1733272214Skan OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1734272214Skan OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1735103285Sikob 1736272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 1737272214Skan OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 1738272214Skan OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 1739103285Sikob } 1740103285Sikob 1741272214Skan#if 0 /* Let dcons(4) be accessed */ 1742103285Sikob/* Stop interrupt */ 1743103285Sikob OWRITE(sc, FWOHCI_INTMASKCLR, 1744103285Sikob OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID 1745103285Sikob | OHCI_INT_PHY_INT 1746272214Skan | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 1747103285Sikob | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 1748272214Skan | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 1749103285Sikob | OHCI_INT_PHY_BUS_R); 1750116978Ssimokawa 1751170374Ssimokawa/* FLUSH FIFO and reset Transmitter/Reciever */ 1752272214Skan OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 1753170374Ssimokawa#endif 1754116978Ssimokawa 1755108642Ssimokawa/* XXX Link down? Bus reset? */ 1756103285Sikob return 0; 1757103285Sikob} 1758103285Sikob 1759108642Ssimokawaint 1760108642Ssimokawafwohci_resume(struct fwohci_softc *sc, device_t dev) 1761108642Ssimokawa{ 1762108642Ssimokawa int i; 1763116978Ssimokawa struct fw_xferq *ir; 1764116978Ssimokawa struct fw_bulkxfer *chunk; 1765108642Ssimokawa 1766108642Ssimokawa fwohci_reset(sc, dev); 1767129541Sdfr /* XXX resume isochronous receive automatically. (how about TX?) */ 1768272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 1769116978Ssimokawa ir = &sc->ir[i].xferq; 1770272214Skan if ((ir->flag & FWXFERQ_RUNNING) != 0) { 1771108642Ssimokawa device_printf(sc->fc.dev, 1772108642Ssimokawa "resume iso receive ch: %d\n", i); 1773116978Ssimokawa ir->flag &= ~FWXFERQ_RUNNING; 1774116978Ssimokawa /* requeue stdma to stfree */ 1775272214Skan while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 1776116978Ssimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 1777116978Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, chunk, link); 1778116978Ssimokawa } 1779108642Ssimokawa sc->fc.irx_enable(&sc->fc, i); 1780108642Ssimokawa } 1781108642Ssimokawa } 1782108642Ssimokawa 1783108642Ssimokawa bus_generic_resume(dev); 1784108642Ssimokawa sc->fc.ibr(&sc->fc); 1785108642Ssimokawa return 0; 1786108642Ssimokawa} 1787108642Ssimokawa 1788170374Ssimokawa#ifdef OHCI_DEBUG 1789103285Sikobstatic void 1790170374Ssimokawafwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat) 1791103285Sikob{ 1792272214Skan if (stat & OREAD(sc, FWOHCI_INTMASK)) 1793103285Sikob 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", 1794103285Sikob stat & OHCI_INT_EN ? "DMA_EN ":"", 1795103285Sikob stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", 1796103285Sikob stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", 1797103285Sikob stat & OHCI_INT_ERR ? "INT_ERR ":"", 1798103285Sikob stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", 1799103285Sikob stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", 1800103285Sikob stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", 1801103285Sikob stat & OHCI_INT_CYC_START ? "CYC_START ":"", 1802103285Sikob stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", 1803103285Sikob stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", 1804103285Sikob stat & OHCI_INT_PHY_SID ? "SID ":"", 1805103285Sikob stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", 1806103285Sikob stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", 1807103285Sikob stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", 1808103285Sikob stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", 1809103285Sikob stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", 1810103285Sikob stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", 1811103285Sikob stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", 1812103285Sikob stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", 1813103285Sikob stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", 1814103285Sikob stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", 1815272214Skan stat, OREAD(sc, FWOHCI_INTMASK) 1816103285Sikob ); 1817170374Ssimokawa} 1818103285Sikob#endif 1819272214Skan 1820170374Ssimokawastatic void 1821170374Ssimokawafwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) 1822170374Ssimokawa{ 1823170374Ssimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 1824277511Swill uintmax_t prequpper; 1825170374Ssimokawa uint32_t node_id, plen; 1826170374Ssimokawa 1827187993Ssbruno FW_GLOCK_ASSERT(fc); 1828170374Ssimokawa if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) { 1829170374Ssimokawa fc->status = FWBUSRESET; 1830111074Ssimokawa /* Disable bus reset interrupt until sid recv. */ 1831272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); 1832272214Skan 1833188509Ssbruno device_printf(fc->dev, "%s: BUS reset\n", __func__); 1834272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 1835103285Sikob OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); 1836103285Sikob 1837272214Skan OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1838103285Sikob sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; 1839272214Skan OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1840103285Sikob sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; 1841103285Sikob 1842170374Ssimokawa if (!kdb_active) 1843170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset); 1844170374Ssimokawa } 1845170374Ssimokawa if (stat & OHCI_INT_PHY_SID) { 1846170374Ssimokawa /* Enable bus reset interrupt */ 1847103285Sikob OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); 1848170374Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); 1849170374Ssimokawa 1850170374Ssimokawa /* Allow async. request to us */ 1851170374Ssimokawa OWRITE(sc, OHCI_AREQHI, 1 << 31); 1852170400Ssimokawa if (firewire_phydma_enable) { 1853170400Ssimokawa /* allow from all nodes */ 1854170400Ssimokawa OWRITE(sc, OHCI_PREQHI, 0x7fffffff); 1855170400Ssimokawa OWRITE(sc, OHCI_PREQLO, 0xffffffff); 1856277511Swill prequpper = ((uintmax_t)Maxmem << PAGE_SHIFT) >> 16; 1857277511Swill if (prequpper > OHCI_PREQUPPER_MAX) { 1858277511Swill device_printf(fc->dev, 1859277511Swill "Physical memory size of 0x%jx exceeds " 1860277511Swill "fire wire address space. Limiting dma " 1861277511Swill "to memory below 0x%jx\n", 1862277511Swill (uintmax_t)Maxmem << PAGE_SHIFT, 1863277511Swill (uintmax_t)OHCI_PREQUPPER_MAX << 16); 1864277511Swill prequpper = OHCI_PREQUPPER_MAX; 1865277511Swill } 1866277511Swill OWRITE(sc, OHCI_PREQUPPER, prequpper & 0xffffffff); 1867170400Ssimokawa } 1868170374Ssimokawa /* Set ATRetries register */ 1869272214Skan OWRITE(sc, OHCI_ATRETRY, 1<<(13 + 16) | 0xfff); 1870170374Ssimokawa 1871170374Ssimokawa /* 1872272214Skan * Checking whether the node is root or not. If root, turn on 1873170374Ssimokawa * cycle master. 1874170374Ssimokawa */ 1875170374Ssimokawa node_id = OREAD(sc, FWOHCI_NODEID); 1876170374Ssimokawa plen = OREAD(sc, OHCI_SID_CNT); 1877170374Ssimokawa 1878170374Ssimokawa fc->nodeid = node_id & 0x3f; 1879188509Ssbruno device_printf(fc->dev, "%s: node_id=0x%08x, SelfID Count=%d, ", 1880188509Ssbruno __func__, fc->nodeid, (plen >> 16) & 0xff); 1881170374Ssimokawa if (!(node_id & OHCI_NODE_VALID)) { 1882188509Ssbruno device_printf(fc->dev, "%s: Bus reset failure\n", 1883188509Ssbruno __func__); 1884170374Ssimokawa goto sidout; 1885170374Ssimokawa } 1886170374Ssimokawa 1887170374Ssimokawa /* cycle timer */ 1888170374Ssimokawa sc->cycle_lost = 0; 1889272214Skan OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST); 1890170374Ssimokawa if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) { 1891170374Ssimokawa printf("CYCLEMASTER mode\n"); 1892170374Ssimokawa OWRITE(sc, OHCI_LNKCTL, 1893170374Ssimokawa OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); 1894170374Ssimokawa } else { 1895170374Ssimokawa printf("non CYCLEMASTER mode\n"); 1896170374Ssimokawa OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); 1897170374Ssimokawa OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); 1898170374Ssimokawa } 1899170374Ssimokawa 1900170374Ssimokawa fc->status = FWBUSINIT; 1901170374Ssimokawa 1902170374Ssimokawa if (!kdb_active) 1903170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid); 1904103285Sikob } 1905170374Ssimokawasidout: 1906170374Ssimokawa if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active)) 1907170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma); 1908170374Ssimokawa} 1909170374Ssimokawa 1910170374Ssimokawastatic void 1911170374Ssimokawafwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count) 1912170374Ssimokawa{ 1913170374Ssimokawa uint32_t irstat, itstat; 1914170374Ssimokawa u_int i; 1915170374Ssimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 1916170374Ssimokawa 1917170374Ssimokawa if (stat & OHCI_INT_DMA_IR) { 1918127468Ssimokawa irstat = atomic_readandclear_int(&sc->irstat); 1919272214Skan for (i = 0; i < fc->nisodma; i++) { 1920109644Ssimokawa struct fwohci_dbch *dbch; 1921109644Ssimokawa 1922272214Skan if ((irstat & (1 << i)) != 0) { 1923109644Ssimokawa dbch = &sc->ir[i]; 1924109644Ssimokawa if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) { 1925109644Ssimokawa device_printf(sc->fc.dev, 1926109644Ssimokawa "dma(%d) not active\n", i); 1927109644Ssimokawa continue; 1928109644Ssimokawa } 1929113584Ssimokawa fwohci_rbuf_update(sc, i); 1930103285Sikob } 1931103285Sikob } 1932103285Sikob } 1933170374Ssimokawa if (stat & OHCI_INT_DMA_IT) { 1934127468Ssimokawa itstat = atomic_readandclear_int(&sc->itstat); 1935272214Skan for (i = 0; i < fc->nisodma; i++) { 1936272214Skan if ((itstat & (1 << i)) != 0) { 1937103285Sikob fwohci_tbuf_update(sc, i); 1938103285Sikob } 1939103285Sikob } 1940103285Sikob } 1941170374Ssimokawa if (stat & OHCI_INT_DMA_PRRS) { 1942103285Sikob#if 0 1943103285Sikob dump_dma(sc, ARRS_CH); 1944103285Sikob dump_db(sc, ARRS_CH); 1945103285Sikob#endif 1946106789Ssimokawa fwohci_arcv(sc, &sc->arrs, count); 1947103285Sikob } 1948170374Ssimokawa if (stat & OHCI_INT_DMA_PRRQ) { 1949103285Sikob#if 0 1950103285Sikob dump_dma(sc, ARRQ_CH); 1951103285Sikob dump_db(sc, ARRQ_CH); 1952103285Sikob#endif 1953106789Ssimokawa fwohci_arcv(sc, &sc->arrq, count); 1954103285Sikob } 1955167628Ssimokawa if (stat & OHCI_INT_CYC_LOST) { 1956167628Ssimokawa if (sc->cycle_lost >= 0) 1957272214Skan sc->cycle_lost++; 1958167628Ssimokawa if (sc->cycle_lost > 10) { 1959167628Ssimokawa sc->cycle_lost = -1; 1960167628Ssimokawa#if 0 1961167628Ssimokawa OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); 1962167628Ssimokawa#endif 1963272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 1964214021Sbrucec device_printf(fc->dev, "too many cycles lost, " 1965214021Sbrucec "no cycle master present?\n"); 1966167628Ssimokawa } 1967167628Ssimokawa } 1968170374Ssimokawa if (stat & OHCI_INT_DMA_ATRQ) { 1969103285Sikob fwohci_txd(sc, &(sc->atrq)); 1970103285Sikob } 1971170374Ssimokawa if (stat & OHCI_INT_DMA_ATRS) { 1972103285Sikob fwohci_txd(sc, &(sc->atrs)); 1973103285Sikob } 1974170374Ssimokawa if (stat & OHCI_INT_PW_ERR) { 1975103285Sikob device_printf(fc->dev, "posted write error\n"); 1976103285Sikob } 1977170374Ssimokawa if (stat & OHCI_INT_ERR) { 1978103285Sikob device_printf(fc->dev, "unrecoverable error\n"); 1979103285Sikob } 1980170374Ssimokawa if (stat & OHCI_INT_PHY_INT) { 1981103285Sikob device_printf(fc->dev, "phy int\n"); 1982103285Sikob } 1983103285Sikob} 1984103285Sikob 1985113584Ssimokawastatic void 1986170374Ssimokawafwohci_task_busreset(void *arg, int pending) 1987113584Ssimokawa{ 1988113584Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 1989170374Ssimokawa 1990187993Ssbruno FW_GLOCK(&sc->fc); 1991170374Ssimokawa fw_busreset(&sc->fc, FWBUSRESET); 1992170374Ssimokawa OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 1993170374Ssimokawa OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 1994187993Ssbruno FW_GUNLOCK(&sc->fc); 1995170374Ssimokawa} 1996170374Ssimokawa 1997170374Ssimokawastatic void 1998170374Ssimokawafwohci_task_sid(void *arg, int pending) 1999170374Ssimokawa{ 2000170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2001170374Ssimokawa struct firewire_comm *fc = &sc->fc; 2002170374Ssimokawa uint32_t *buf; 2003170374Ssimokawa int i, plen; 2004170374Ssimokawa 2005170374Ssimokawa 2006187993Ssbruno /* 2007187993Ssbruno * We really should have locking 2008187993Ssbruno * here. Not sure why it's not 2009187993Ssbruno */ 2010170374Ssimokawa plen = OREAD(sc, OHCI_SID_CNT); 2011170374Ssimokawa 2012170374Ssimokawa if (plen & OHCI_SID_ERR) { 2013170374Ssimokawa device_printf(fc->dev, "SID Error\n"); 2014170374Ssimokawa return; 2015170374Ssimokawa } 2016170374Ssimokawa plen &= OHCI_SID_CNT_MASK; 2017170374Ssimokawa if (plen < 4 || plen > OHCI_SIDSIZE) { 2018170374Ssimokawa device_printf(fc->dev, "invalid SID len = %d\n", plen); 2019170374Ssimokawa return; 2020170374Ssimokawa } 2021170374Ssimokawa plen -= 4; /* chop control info */ 2022170374Ssimokawa buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); 2023170374Ssimokawa if (buf == NULL) { 2024170374Ssimokawa device_printf(fc->dev, "malloc failed\n"); 2025170374Ssimokawa return; 2026170374Ssimokawa } 2027272214Skan for (i = 0; i < plen / 4; i++) 2028272214Skan buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i + 1]); 2029187993Ssbruno 2030170374Ssimokawa /* pending all pre-bus_reset packets */ 2031170374Ssimokawa fwohci_txd(sc, &sc->atrq); 2032170374Ssimokawa fwohci_txd(sc, &sc->atrs); 2033170374Ssimokawa fwohci_arcv(sc, &sc->arrs, -1); 2034170374Ssimokawa fwohci_arcv(sc, &sc->arrq, -1); 2035170374Ssimokawa fw_drain_txq(fc); 2036170374Ssimokawa fw_sidrcv(fc, buf, plen); 2037170374Ssimokawa free(buf, M_FW); 2038170374Ssimokawa} 2039170374Ssimokawa 2040170374Ssimokawastatic void 2041170374Ssimokawafwohci_task_dma(void *arg, int pending) 2042170374Ssimokawa{ 2043170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2044129585Sdfr uint32_t stat; 2045113584Ssimokawa 2046113584Ssimokawaagain: 2047113584Ssimokawa stat = atomic_readandclear_int(&sc->intstat); 2048113584Ssimokawa if (stat) 2049170374Ssimokawa fwohci_intr_dma(sc, stat, -1); 2050113584Ssimokawa else 2051113584Ssimokawa return; 2052113584Ssimokawa goto again; 2053113584Ssimokawa} 2054113584Ssimokawa 2055170374Ssimokawastatic int 2056170374Ssimokawafwohci_check_stat(struct fwohci_softc *sc) 2057113584Ssimokawa{ 2058129585Sdfr uint32_t stat, irstat, itstat; 2059113584Ssimokawa 2060187993Ssbruno FW_GLOCK_ASSERT(&sc->fc); 2061113584Ssimokawa stat = OREAD(sc, FWOHCI_INTSTAT); 2062113584Ssimokawa if (stat == 0xffffffff) { 2063223353Simp if (!bus_child_present(sc->fc.dev)) 2064223353Simp return (FILTER_HANDLED); 2065223353Simp device_printf(sc->fc.dev, "device physically ejected?\n"); 2066170374Ssimokawa return (FILTER_STRAY); 2067113584Ssimokawa } 2068113584Ssimokawa if (stat) 2069170374Ssimokawa OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R); 2070170374Ssimokawa 2071170374Ssimokawa stat &= sc->intmask; 2072170374Ssimokawa if (stat == 0) 2073170374Ssimokawa return (FILTER_STRAY); 2074170374Ssimokawa 2075170374Ssimokawa atomic_set_int(&sc->intstat, stat); 2076113584Ssimokawa if (stat & OHCI_INT_DMA_IR) { 2077113584Ssimokawa irstat = OREAD(sc, OHCI_IR_STAT); 2078113584Ssimokawa OWRITE(sc, OHCI_IR_STATCLR, irstat); 2079113584Ssimokawa atomic_set_int(&sc->irstat, irstat); 2080113584Ssimokawa } 2081113584Ssimokawa if (stat & OHCI_INT_DMA_IT) { 2082113584Ssimokawa itstat = OREAD(sc, OHCI_IT_STAT); 2083113584Ssimokawa OWRITE(sc, OHCI_IT_STATCLR, itstat); 2084113584Ssimokawa atomic_set_int(&sc->itstat, itstat); 2085113584Ssimokawa } 2086170374Ssimokawa 2087170374Ssimokawa fwohci_intr_core(sc, stat, -1); 2088170374Ssimokawa return (FILTER_HANDLED); 2089113584Ssimokawa} 2090113584Ssimokawa 2091187993Ssbrunovoid 2092187993Ssbrunofwohci_intr(void *arg) 2093103285Sikob{ 2094103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2095103285Sikob 2096187993Ssbruno FW_GLOCK(&sc->fc); 2097187993Ssbruno fwohci_check_stat(sc); 2098187993Ssbruno FW_GUNLOCK(&sc->fc); 2099170374Ssimokawa} 2100103285Sikob 2101170374Ssimokawavoid 2102103285Sikobfwohci_poll(struct firewire_comm *fc, int quick, int count) 2103103285Sikob{ 2104170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)fc; 2105187993Ssbruno 2106187993Ssbruno FW_GLOCK(fc); 2107170374Ssimokawa fwohci_check_stat(sc); 2108187993Ssbruno FW_GUNLOCK(fc); 2109103285Sikob} 2110103285Sikob 2111103285Sikobstatic void 2112103285Sikobfwohci_set_intr(struct firewire_comm *fc, int enable) 2113103285Sikob{ 2114103285Sikob struct fwohci_softc *sc; 2115103285Sikob 2116103285Sikob sc = (struct fwohci_softc *)fc; 2117132432Ssimokawa if (firewire_debug) 2118108642Ssimokawa device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable); 2119103285Sikob if (enable) { 2120103285Sikob sc->intmask |= OHCI_INT_EN; 2121103285Sikob OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); 2122103285Sikob } else { 2123103285Sikob sc->intmask &= ~OHCI_INT_EN; 2124103285Sikob OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); 2125103285Sikob } 2126103285Sikob} 2127103285Sikob 2128106790Ssimokawastatic void 2129106790Ssimokawafwohci_tbuf_update(struct fwohci_softc *sc, int dmach) 2130103285Sikob{ 2131103285Sikob struct firewire_comm *fc = &sc->fc; 2132120660Ssimokawa struct fwohcidb *db; 2133109890Ssimokawa struct fw_bulkxfer *chunk; 2134109890Ssimokawa struct fw_xferq *it; 2135129585Sdfr uint32_t stat, count; 2136113584Ssimokawa int s, w=0, ldesc; 2137103285Sikob 2138109890Ssimokawa it = fc->it[dmach]; 2139113584Ssimokawa ldesc = sc->it[dmach].ndesc - 1; 2140109890Ssimokawa s = splfw(); /* unnecessary ? */ 2141170374Ssimokawa FW_GLOCK(fc); 2142113584Ssimokawa fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); 2143119155Ssimokawa if (firewire_debug) 2144119155Ssimokawa dump_db(sc, ITX_CH + dmach); 2145109890Ssimokawa while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { 2146109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 2147272214Skan stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2148113584Ssimokawa >> OHCI_STATUS_SHIFT; 2149109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->start))->db; 2150119155Ssimokawa /* timestamp */ 2151113584Ssimokawa count = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2152113584Ssimokawa & OHCI_COUNT_MASK; 2153109890Ssimokawa if (stat == 0) 2154109890Ssimokawa break; 2155109890Ssimokawa STAILQ_REMOVE_HEAD(&it->stdma, link); 2156272214Skan switch (stat & FWOHCIEV_MASK) { 2157109890Ssimokawa case FWOHCIEV_ACKCOMPL: 2158109890Ssimokawa#if 0 2159109890Ssimokawa device_printf(fc->dev, "0x%08x\n", count); 2160109179Ssimokawa#endif 2161109890Ssimokawa break; 2162109890Ssimokawa default: 2163109423Ssimokawa device_printf(fc->dev, 2164113584Ssimokawa "Isochronous transmit err %02x(%s)\n", 2165113584Ssimokawa stat, fwohcicode[stat & 0x1f]); 2166109890Ssimokawa } 2167109890Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, chunk, link); 2168109890Ssimokawa w++; 2169109403Ssimokawa } 2170170374Ssimokawa FW_GUNLOCK(fc); 2171109890Ssimokawa splx(s); 2172109890Ssimokawa if (w) 2173109890Ssimokawa wakeup(it); 2174103285Sikob} 2175106790Ssimokawa 2176106790Ssimokawastatic void 2177106790Ssimokawafwohci_rbuf_update(struct fwohci_softc *sc, int dmach) 2178103285Sikob{ 2179109179Ssimokawa struct firewire_comm *fc = &sc->fc; 2180120660Ssimokawa struct fwohcidb_tr *db_tr; 2181109890Ssimokawa struct fw_bulkxfer *chunk; 2182109890Ssimokawa struct fw_xferq *ir; 2183129585Sdfr uint32_t stat; 2184277511Swill int w = 0, ldesc; 2185109179Ssimokawa 2186109890Ssimokawa ir = fc->ir[dmach]; 2187113584Ssimokawa ldesc = sc->ir[dmach].ndesc - 1; 2188170374Ssimokawa 2189113584Ssimokawa#if 0 2190113584Ssimokawa dump_db(sc, dmach); 2191113584Ssimokawa#endif 2192170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 2193170374Ssimokawa FW_GLOCK(fc); 2194113584Ssimokawa fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); 2195109890Ssimokawa while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 2196113584Ssimokawa db_tr = (struct fwohcidb_tr *)chunk->end; 2197113584Ssimokawa stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) 2198113584Ssimokawa >> OHCI_STATUS_SHIFT; 2199109890Ssimokawa if (stat == 0) 2200109890Ssimokawa break; 2201113584Ssimokawa 2202113584Ssimokawa if (chunk->mbuf != NULL) { 2203113584Ssimokawa bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map, 2204113584Ssimokawa BUS_DMASYNC_POSTREAD); 2205113584Ssimokawa bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map); 2206113584Ssimokawa } else if (ir->buf != NULL) { 2207113584Ssimokawa fwdma_sync_multiseg(ir->buf, chunk->poffset, 2208113584Ssimokawa ir->bnpacket, BUS_DMASYNC_POSTREAD); 2209113584Ssimokawa } else { 2210113584Ssimokawa /* XXX */ 2211113584Ssimokawa printf("fwohci_rbuf_update: this shouldn't happend\n"); 2212113584Ssimokawa } 2213113584Ssimokawa 2214109890Ssimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 2215109890Ssimokawa STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); 2216109890Ssimokawa switch (stat & FWOHCIEV_MASK) { 2217109890Ssimokawa case FWOHCIEV_ACKCOMPL: 2218111942Ssimokawa chunk->resp = 0; 2219109890Ssimokawa break; 2220109890Ssimokawa default: 2221111942Ssimokawa chunk->resp = EINVAL; 2222109890Ssimokawa device_printf(fc->dev, 2223113584Ssimokawa "Isochronous receive err %02x(%s)\n", 2224113584Ssimokawa stat, fwohcicode[stat & 0x1f]); 2225109890Ssimokawa } 2226109890Ssimokawa w++; 2227103285Sikob } 2228170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 2229170374Ssimokawa FW_GUNLOCK(fc); 2230170374Ssimokawa if (w == 0) 2231170374Ssimokawa return; 2232170374Ssimokawa 2233272214Skan if (ir->flag & FWXFERQ_HANDLER) 2234170374Ssimokawa ir->hand(ir); 2235170374Ssimokawa else 2236170374Ssimokawa wakeup(ir); 2237103285Sikob} 2238106790Ssimokawa 2239106790Ssimokawavoid 2240129585Sdfrdump_dma(struct fwohci_softc *sc, uint32_t ch) 2241106790Ssimokawa{ 2242129585Sdfr uint32_t off, cntl, stat, cmd, match; 2243103285Sikob 2244272214Skan if (ch == 0) { 2245103285Sikob off = OHCI_ATQOFF; 2246272214Skan } else if (ch == 1) { 2247103285Sikob off = OHCI_ATSOFF; 2248272214Skan } else if (ch == 2) { 2249103285Sikob off = OHCI_ARQOFF; 2250272214Skan } else if (ch == 3) { 2251103285Sikob off = OHCI_ARSOFF; 2252272214Skan } else if (ch < IRX_CH) { 2253103285Sikob off = OHCI_ITCTL(ch - ITX_CH); 2254272214Skan } else { 2255103285Sikob off = OHCI_IRCTL(ch - IRX_CH); 2256103285Sikob } 2257103285Sikob cntl = stat = OREAD(sc, off); 2258103285Sikob cmd = OREAD(sc, off + 0xc); 2259103285Sikob match = OREAD(sc, off + 0x10); 2260103285Sikob 2261113584Ssimokawa device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n", 2262103285Sikob ch, 2263272214Skan cntl, 2264272214Skan cmd, 2265103285Sikob match); 2266272214Skan stat &= 0xffff; 2267113584Ssimokawa if (stat) { 2268103285Sikob device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", 2269103285Sikob ch, 2270103285Sikob stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2271103285Sikob stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2272103285Sikob stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2273103285Sikob stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2274103285Sikob stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2275103285Sikob stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2276103285Sikob fwohcicode[stat & 0x1f], 2277103285Sikob stat & 0x1f 2278103285Sikob ); 2279272214Skan } else { 2280103285Sikob device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); 2281103285Sikob } 2282103285Sikob} 2283106790Ssimokawa 2284106790Ssimokawavoid 2285129585Sdfrdump_db(struct fwohci_softc *sc, uint32_t ch) 2286106790Ssimokawa{ 2287103285Sikob struct fwohci_dbch *dbch; 2288113584Ssimokawa struct fwohcidb_tr *cp = NULL, *pp, *np = NULL; 2289120660Ssimokawa struct fwohcidb *curr = NULL, *prev, *next = NULL; 2290103285Sikob int idb, jdb; 2291129585Sdfr uint32_t cmd, off; 2292272214Skan 2293272214Skan if (ch == 0) { 2294103285Sikob off = OHCI_ATQOFF; 2295103285Sikob dbch = &sc->atrq; 2296272214Skan } else if (ch == 1) { 2297103285Sikob off = OHCI_ATSOFF; 2298103285Sikob dbch = &sc->atrs; 2299272214Skan } else if (ch == 2) { 2300103285Sikob off = OHCI_ARQOFF; 2301103285Sikob dbch = &sc->arrq; 2302272214Skan } else if (ch == 3) { 2303103285Sikob off = OHCI_ARSOFF; 2304103285Sikob dbch = &sc->arrs; 2305272214Skan } else if (ch < IRX_CH) { 2306103285Sikob off = OHCI_ITCTL(ch - ITX_CH); 2307103285Sikob dbch = &sc->it[ch - ITX_CH]; 2308272214Skan } else { 2309103285Sikob off = OHCI_IRCTL(ch - IRX_CH); 2310103285Sikob dbch = &sc->ir[ch - IRX_CH]; 2311103285Sikob } 2312103285Sikob cmd = OREAD(sc, off + 0xc); 2313103285Sikob 2314272214Skan if (dbch->ndb == 0) { 2315103285Sikob device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); 2316103285Sikob return; 2317103285Sikob } 2318103285Sikob pp = dbch->top; 2319103285Sikob prev = pp->db; 2320272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 2321103285Sikob cp = STAILQ_NEXT(pp, link); 2322272214Skan if (cp == NULL) { 2323103285Sikob curr = NULL; 2324103285Sikob goto outdb; 2325103285Sikob } 2326103285Sikob np = STAILQ_NEXT(cp, link); 2327272214Skan for (jdb = 0; jdb < dbch->ndesc; jdb++) { 2328113584Ssimokawa if ((cmd & 0xfffffff0) == cp->bus_addr) { 2329103285Sikob curr = cp->db; 2330272214Skan if (np != NULL) { 2331103285Sikob next = np->db; 2332272214Skan } else { 2333103285Sikob next = NULL; 2334103285Sikob } 2335103285Sikob goto outdb; 2336103285Sikob } 2337103285Sikob } 2338103285Sikob pp = STAILQ_NEXT(pp, link); 2339272214Skan if (pp == NULL) { 2340144263Ssam curr = NULL; 2341144263Ssam goto outdb; 2342144263Ssam } 2343103285Sikob prev = pp->db; 2344103285Sikob } 2345103285Sikoboutdb: 2346272214Skan if (curr != NULL) { 2347113584Ssimokawa#if 0 2348103285Sikob printf("Prev DB %d\n", ch); 2349113584Ssimokawa print_db(pp, prev, ch, dbch->ndesc); 2350113584Ssimokawa#endif 2351103285Sikob printf("Current DB %d\n", ch); 2352113584Ssimokawa print_db(cp, curr, ch, dbch->ndesc); 2353113584Ssimokawa#if 0 2354103285Sikob printf("Next DB %d\n", ch); 2355113584Ssimokawa print_db(np, next, ch, dbch->ndesc); 2356113584Ssimokawa#endif 2357272214Skan } else { 2358103285Sikob printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); 2359103285Sikob } 2360103285Sikob return; 2361103285Sikob} 2362106790Ssimokawa 2363106790Ssimokawavoid 2364120660Ssimokawaprint_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db, 2365129585Sdfr uint32_t ch, uint32_t max) 2366106790Ssimokawa{ 2367103285Sikob fwohcireg_t stat; 2368103285Sikob int i, key; 2369129585Sdfr uint32_t cmd, res; 2370103285Sikob 2371272214Skan if (db == NULL) { 2372103285Sikob printf("No Descriptor is found\n"); 2373103285Sikob return; 2374103285Sikob } 2375103285Sikob 2376103285Sikob printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", 2377103285Sikob ch, 2378103285Sikob "Current", 2379103285Sikob "OP ", 2380103285Sikob "KEY", 2381103285Sikob "INT", 2382103285Sikob "BR ", 2383103285Sikob "len", 2384103285Sikob "Addr", 2385103285Sikob "Depend", 2386103285Sikob "Stat", 2387103285Sikob "Cnt"); 2388272214Skan for (i = 0; i <= max; i++) { 2389113584Ssimokawa cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd); 2390113584Ssimokawa res = FWOHCI_DMA_READ(db[i].db.desc.res); 2391113584Ssimokawa key = cmd & OHCI_KEY_MASK; 2392113584Ssimokawa stat = res >> OHCI_STATUS_SHIFT; 2393113972Ssimokawa printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x", 2394114142Ssimokawa (uintmax_t)db_tr->bus_addr, 2395113584Ssimokawa dbcode[(cmd >> 28) & 0xf], 2396113584Ssimokawa dbkey[(cmd >> 24) & 0x7], 2397113584Ssimokawa dbcond[(cmd >> 20) & 0x3], 2398113584Ssimokawa dbcond[(cmd >> 18) & 0x3], 2399113584Ssimokawa cmd & OHCI_COUNT_MASK, 2400113584Ssimokawa FWOHCI_DMA_READ(db[i].db.desc.addr), 2401113584Ssimokawa FWOHCI_DMA_READ(db[i].db.desc.depend), 2402113584Ssimokawa stat, 2403113584Ssimokawa res & OHCI_COUNT_MASK); 2404272214Skan if (stat & 0xff00) { 2405103285Sikob printf(" %s%s%s%s%s%s %s(%x)\n", 2406103285Sikob stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2407103285Sikob stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2408103285Sikob stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2409103285Sikob stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2410103285Sikob stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2411103285Sikob stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2412103285Sikob fwohcicode[stat & 0x1f], 2413103285Sikob stat & 0x1f 2414103285Sikob ); 2415272214Skan } else { 2416103285Sikob printf(" Nostat\n"); 2417103285Sikob } 2418272214Skan if (key == OHCI_KEY_ST2) { 2419272214Skan printf("0x%08x 0x%08x 0x%08x 0x%08x\n", 2420272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[0]), 2421272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[1]), 2422272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[2]), 2423272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[3])); 2424103285Sikob } 2425272214Skan if (key == OHCI_KEY_DEVICE) { 2426103285Sikob return; 2427103285Sikob } 2428272214Skan if ((cmd & OHCI_BRANCH_MASK) 2429272214Skan == OHCI_BRANCH_ALWAYS) { 2430103285Sikob return; 2431103285Sikob } 2432272214Skan if ((cmd & OHCI_CMD_MASK) 2433272214Skan == OHCI_OUTPUT_LAST) { 2434103285Sikob return; 2435103285Sikob } 2436272214Skan if ((cmd & OHCI_CMD_MASK) 2437272214Skan == OHCI_INPUT_LAST) { 2438103285Sikob return; 2439103285Sikob } 2440272214Skan if (key == OHCI_KEY_ST2) { 2441103285Sikob i++; 2442103285Sikob } 2443103285Sikob } 2444103285Sikob return; 2445103285Sikob} 2446106790Ssimokawa 2447106790Ssimokawavoid 2448106790Ssimokawafwohci_ibr(struct firewire_comm *fc) 2449103285Sikob{ 2450103285Sikob struct fwohci_softc *sc; 2451129585Sdfr uint32_t fun; 2452103285Sikob 2453110577Ssimokawa device_printf(fc->dev, "Initiate bus reset\n"); 2454103285Sikob sc = (struct fwohci_softc *)fc; 2455108276Ssimokawa 2456187993Ssbruno FW_GLOCK(fc); 2457108276Ssimokawa /* 2458129611Sdfr * Make sure our cached values from the config rom are 2459129611Sdfr * initialised. 2460129611Sdfr */ 2461129611Sdfr OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 2462129611Sdfr OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 2463129611Sdfr 2464129611Sdfr /* 2465108276Ssimokawa * Set root hold-off bit so that non cyclemaster capable node 2466108276Ssimokawa * shouldn't became the root node. 2467108276Ssimokawa */ 2468103285Sikob#if 1 2469103285Sikob fun = fwphy_rddata(sc, FW_PHY_IBR_REG); 2470109280Ssimokawa fun |= FW_PHY_IBR | FW_PHY_RHB; 2471103285Sikob fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); 2472109280Ssimokawa#else /* Short bus reset */ 2473103285Sikob fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); 2474109280Ssimokawa fun |= FW_PHY_ISBR | FW_PHY_RHB; 2475103285Sikob fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); 2476103285Sikob#endif 2477187993Ssbruno FW_GUNLOCK(fc); 2478103285Sikob} 2479106790Ssimokawa 2480106790Ssimokawavoid 2481106790Ssimokawafwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 2482103285Sikob{ 2483103285Sikob struct fwohcidb_tr *db_tr, *fdb_tr; 2484103285Sikob struct fwohci_dbch *dbch; 2485120660Ssimokawa struct fwohcidb *db; 2486103285Sikob struct fw_pkt *fp; 2487120660Ssimokawa struct fwohci_txpkthdr *ohcifp; 2488103285Sikob unsigned short chtag; 2489103285Sikob int idb; 2490103285Sikob 2491170374Ssimokawa FW_GLOCK_ASSERT(&sc->fc); 2492170374Ssimokawa 2493103285Sikob dbch = &sc->it[dmach]; 2494103285Sikob chtag = sc->it[dmach].xferq.flag & 0xff; 2495103285Sikob 2496103285Sikob db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 2497103285Sikob fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 2498103285Sikob/* 2499113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr); 2500103285Sikob*/ 2501272214Skan for (idb = 0; idb < dbch->xferq.bnpacket; idb++) { 2502109892Ssimokawa db = db_tr->db; 2503103285Sikob fp = (struct fw_pkt *)db_tr->buf; 2504120660Ssimokawa ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed; 2505113584Ssimokawa ohcifp->mode.ld[0] = fp->mode.ld[0]; 2506119155Ssimokawa ohcifp->mode.common.spd = 0 & 0x7; 2507113584Ssimokawa ohcifp->mode.stream.len = fp->mode.stream.len; 2508103285Sikob ohcifp->mode.stream.chtag = chtag; 2509103285Sikob ohcifp->mode.stream.tcode = 0xa; 2510113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2511272214Skan FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]); 2512272214Skan FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]); 2513113584Ssimokawa#endif 2514103285Sikob 2515113584Ssimokawa FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK); 2516113584Ssimokawa FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len); 2517113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2518109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */ 2519113584Ssimokawa db[2].db.desc.cmd = OHCI_OUTPUT_LAST 2520103285Sikob | OHCI_UPDATE 2521109892Ssimokawa | OHCI_BRANCH_ALWAYS; 2522109892Ssimokawa db[0].db.desc.depend = 2523109892Ssimokawa = db[dbch->ndesc - 1].db.desc.depend 2524113584Ssimokawa = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc; 2525109892Ssimokawa#else 2526113584Ssimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 2527113584Ssimokawa FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc); 2528109892Ssimokawa#endif 2529103285Sikob bulkxfer->end = (caddr_t)db_tr; 2530103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 2531103285Sikob } 2532109892Ssimokawa db = ((struct fwohcidb_tr *)bulkxfer->end)->db; 2533113584Ssimokawa FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf); 2534113584Ssimokawa FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf); 2535109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */ 2536109892Ssimokawa db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2537109280Ssimokawa /* OHCI 1.1 and above */ 2538109892Ssimokawa db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2539109892Ssimokawa#endif 2540109892Ssimokawa/* 2541103285Sikob db_tr = (struct fwohcidb_tr *)bulkxfer->start; 2542103285Sikob fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; 2543113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr); 2544103285Sikob*/ 2545103285Sikob return; 2546103285Sikob} 2547106790Ssimokawa 2548106790Ssimokawastatic int 2549113584Ssimokawafwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2550113584Ssimokawa int poffset) 2551103285Sikob{ 2552120660Ssimokawa struct fwohcidb *db = db_tr->db; 2553113584Ssimokawa struct fw_xferq *it; 2554103285Sikob int err = 0; 2555113584Ssimokawa 2556113584Ssimokawa it = &dbch->xferq; 2557272214Skan if (it->buf == 0) { 2558103285Sikob err = EINVAL; 2559103285Sikob return err; 2560103285Sikob } 2561113584Ssimokawa db_tr->buf = fwdma_v_addr(it->buf, poffset); 2562103285Sikob db_tr->dbcnt = 3; 2563103285Sikob 2564113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.cmd, 2565113584Ssimokawa OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8); 2566119155Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0); 2567120660Ssimokawa bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed)); 2568113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.addr, 2569129585Sdfr fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t)); 2570113584Ssimokawa 2571113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.cmd, 2572113584Ssimokawa OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS); 2573109892Ssimokawa#if 1 2574113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.res, 0); 2575113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2576109892Ssimokawa#endif 2577113584Ssimokawa return 0; 2578103285Sikob} 2579106790Ssimokawa 2580106790Ssimokawaint 2581113584Ssimokawafwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2582113584Ssimokawa int poffset, struct fwdma_alloc *dummy_dma) 2583103285Sikob{ 2584120660Ssimokawa struct fwohcidb *db = db_tr->db; 2585113584Ssimokawa struct fw_xferq *ir; 2586113584Ssimokawa int i, ldesc; 2587113584Ssimokawa bus_addr_t dbuf[2]; 2588103285Sikob int dsiz[2]; 2589103285Sikob 2590113584Ssimokawa ir = &dbch->xferq; 2591113584Ssimokawa if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) { 2592178911Ssimokawa if (db_tr->buf == NULL) { 2593178911Ssimokawa db_tr->buf = fwdma_malloc_size(dbch->dmat, 2594178911Ssimokawa &db_tr->dma_map, ir->psize, &dbuf[0], 2595178911Ssimokawa BUS_DMA_NOWAIT); 2596178911Ssimokawa if (db_tr->buf == NULL) 2597272214Skan return (ENOMEM); 2598178911Ssimokawa } 2599103285Sikob db_tr->dbcnt = 1; 2600113584Ssimokawa dsiz[0] = ir->psize; 2601113584Ssimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2602113584Ssimokawa BUS_DMASYNC_PREREAD); 2603113584Ssimokawa } else { 2604113584Ssimokawa db_tr->dbcnt = 0; 2605113584Ssimokawa if (dummy_dma != NULL) { 2606129585Sdfr dsiz[db_tr->dbcnt] = sizeof(uint32_t); 2607113584Ssimokawa dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr; 2608113584Ssimokawa } 2609113584Ssimokawa dsiz[db_tr->dbcnt] = ir->psize; 2610113584Ssimokawa if (ir->buf != NULL) { 2611113584Ssimokawa db_tr->buf = fwdma_v_addr(ir->buf, poffset); 2612272214Skan dbuf[db_tr->dbcnt] = fwdma_bus_addr(ir->buf, poffset); 2613113584Ssimokawa } 2614113584Ssimokawa db_tr->dbcnt++; 2615103285Sikob } 2616272214Skan for (i = 0; i < db_tr->dbcnt; i++) { 2617113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]); 2618113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]); 2619113584Ssimokawa if (ir->flag & FWXFERQ_STREAM) { 2620113584Ssimokawa FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE); 2621103285Sikob } 2622113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]); 2623103285Sikob } 2624113584Ssimokawa ldesc = db_tr->dbcnt - 1; 2625113584Ssimokawa if (ir->flag & FWXFERQ_STREAM) { 2626113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST); 2627103285Sikob } 2628113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS); 2629113584Ssimokawa return 0; 2630103285Sikob} 2631106790Ssimokawa 2632113584Ssimokawa 2633113584Ssimokawastatic int 2634113584Ssimokawafwohci_arcv_swap(struct fw_pkt *fp, int len) 2635103285Sikob{ 2636113584Ssimokawa struct fw_pkt *fp0; 2637129585Sdfr uint32_t ld0; 2638120660Ssimokawa int slen, hlen; 2639113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2640113584Ssimokawa int i; 2641113584Ssimokawa#endif 2642103285Sikob 2643113584Ssimokawa ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]); 2644113584Ssimokawa#if 0 2645113584Ssimokawa printf("ld0: x%08x\n", ld0); 2646113584Ssimokawa#endif 2647113584Ssimokawa fp0 = (struct fw_pkt *)&ld0; 2648120660Ssimokawa /* determine length to swap */ 2649113584Ssimokawa switch (fp0->mode.common.tcode) { 2650113584Ssimokawa case FWTCODE_RREQQ: 2651113584Ssimokawa case FWTCODE_WRES: 2652113584Ssimokawa case FWTCODE_WREQQ: 2653113584Ssimokawa case FWTCODE_RRESQ: 2654113584Ssimokawa case FWOHCITCODE_PHY: 2655113584Ssimokawa slen = 12; 2656113584Ssimokawa break; 2657113584Ssimokawa case FWTCODE_RREQB: 2658113584Ssimokawa case FWTCODE_WREQB: 2659113584Ssimokawa case FWTCODE_LREQ: 2660113584Ssimokawa case FWTCODE_RRESB: 2661113584Ssimokawa case FWTCODE_LRES: 2662113584Ssimokawa slen = 16; 2663113584Ssimokawa break; 2664113584Ssimokawa default: 2665113584Ssimokawa printf("Unknown tcode %d\n", fp0->mode.common.tcode); 2666272214Skan return (0); 2667103285Sikob } 2668120660Ssimokawa hlen = tinfo[fp0->mode.common.tcode].hdr_len; 2669120660Ssimokawa if (hlen > len) { 2670113584Ssimokawa if (firewire_debug) 2671113584Ssimokawa printf("splitted header\n"); 2672272214Skan return (-hlen); 2673103285Sikob } 2674113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2675272214Skan for (i = 0; i < slen/4; i++) 2676113584Ssimokawa fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]); 2677113584Ssimokawa#endif 2678272214Skan return (hlen); 2679103285Sikob} 2680103285Sikob 2681103285Sikobstatic int 2682113584Ssimokawafwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp) 2683103285Sikob{ 2684120660Ssimokawa struct tcode_info *info; 2685113584Ssimokawa int r; 2686103285Sikob 2687120660Ssimokawa info = &tinfo[fp->mode.common.tcode]; 2688129585Sdfr r = info->hdr_len + sizeof(uint32_t); 2689120660Ssimokawa if ((info->flag & FWTI_BLOCK_ASY) != 0) 2690129585Sdfr r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t)); 2691120660Ssimokawa 2692169132Ssimokawa if (r == sizeof(uint32_t)) { 2693120660Ssimokawa /* XXX */ 2694110798Ssimokawa device_printf(sc->fc.dev, "Unknown tcode %d\n", 2695110798Ssimokawa fp->mode.common.tcode); 2696169132Ssimokawa return (-1); 2697169132Ssimokawa } 2698120660Ssimokawa 2699110798Ssimokawa if (r > dbch->xferq.psize) { 2700110798Ssimokawa device_printf(sc->fc.dev, "Invalid packet length %d\n", r); 2701169132Ssimokawa return (-1); 2702110798Ssimokawa /* panic ? */ 2703110798Ssimokawa } 2704120660Ssimokawa 2705110798Ssimokawa return r; 2706103285Sikob} 2707103285Sikob 2708106790Ssimokawastatic void 2709169132Ssimokawafwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch, 2710169132Ssimokawa struct fwohcidb_tr *db_tr, uint32_t off, int wake) 2711113584Ssimokawa{ 2712120660Ssimokawa struct fwohcidb *db = &db_tr->db[0]; 2713113584Ssimokawa 2714113584Ssimokawa FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf); 2715113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize); 2716113584Ssimokawa FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1); 2717113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 2718113584Ssimokawa dbch->bottom = db_tr; 2719169132Ssimokawa 2720169132Ssimokawa if (wake) 2721169132Ssimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 2722113584Ssimokawa} 2723113584Ssimokawa 2724113584Ssimokawastatic void 2725106790Ssimokawafwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 2726103285Sikob{ 2727103285Sikob struct fwohcidb_tr *db_tr; 2728113584Ssimokawa struct iovec vec[2]; 2729113584Ssimokawa struct fw_pkt pktbuf; 2730113584Ssimokawa int nvec; 2731103285Sikob struct fw_pkt *fp; 2732129585Sdfr uint8_t *ld; 2733169132Ssimokawa uint32_t stat, off, status, event; 2734103285Sikob u_int spd; 2735113584Ssimokawa int len, plen, hlen, pcnt, offset; 2736103285Sikob int s; 2737103285Sikob caddr_t buf; 2738103285Sikob int resCount; 2739103285Sikob 2740272214Skan if (&sc->arrq == dbch) { 2741103285Sikob off = OHCI_ARQOFF; 2742272214Skan } else if (&sc->arrs == dbch) { 2743103285Sikob off = OHCI_ARSOFF; 2744272214Skan } else { 2745103285Sikob return; 2746103285Sikob } 2747103285Sikob 2748103285Sikob s = splfw(); 2749103285Sikob db_tr = dbch->top; 2750103285Sikob pcnt = 0; 2751103285Sikob /* XXX we cannot handle a packet which lies in more than two buf */ 2752113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 2753113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 2754113584Ssimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT; 2755113584Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK; 2756169132Ssimokawa while (status & OHCI_CNTL_DMA_ACTIVE) { 2757113584Ssimokawa#if 0 2758169132Ssimokawa 2759169132Ssimokawa if (off == OHCI_ARQOFF) 2760169132Ssimokawa printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n", 2761169132Ssimokawa db_tr->bus_addr, status, resCount); 2762113584Ssimokawa#endif 2763113584Ssimokawa len = dbch->xferq.psize - resCount; 2764129585Sdfr ld = (uint8_t *)db_tr->buf; 2765113584Ssimokawa if (dbch->pdb_tr == NULL) { 2766113584Ssimokawa len -= dbch->buf_offset; 2767113584Ssimokawa ld += dbch->buf_offset; 2768113584Ssimokawa } 2769113584Ssimokawa if (len > 0) 2770113584Ssimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2771113584Ssimokawa BUS_DMASYNC_POSTREAD); 2772272214Skan while (len > 0) { 2773106789Ssimokawa if (count >= 0 && count-- == 0) 2774106789Ssimokawa goto out; 2775272214Skan if (dbch->pdb_tr != NULL) { 2776113584Ssimokawa /* we have a fragment in previous buffer */ 2777113584Ssimokawa int rlen; 2778103285Sikob 2779113584Ssimokawa offset = dbch->buf_offset; 2780113584Ssimokawa if (offset < 0) 2781113584Ssimokawa offset = - offset; 2782113584Ssimokawa buf = dbch->pdb_tr->buf + offset; 2783113584Ssimokawa rlen = dbch->xferq.psize - offset; 2784113584Ssimokawa if (firewire_debug) 2785113584Ssimokawa printf("rlen=%d, offset=%d\n", 2786113584Ssimokawa rlen, dbch->buf_offset); 2787113584Ssimokawa if (dbch->buf_offset < 0) { 2788113584Ssimokawa /* splitted in header, pull up */ 2789113584Ssimokawa char *p; 2790113584Ssimokawa 2791113584Ssimokawa p = (char *)&pktbuf; 2792113584Ssimokawa bcopy(buf, p, rlen); 2793113584Ssimokawa p += rlen; 2794113584Ssimokawa /* this must be too long but harmless */ 2795113584Ssimokawa rlen = sizeof(pktbuf) - rlen; 2796113584Ssimokawa if (rlen < 0) 2797113584Ssimokawa printf("why rlen < 0\n"); 2798113584Ssimokawa bcopy(db_tr->buf, p, rlen); 2799103285Sikob ld += rlen; 2800103285Sikob len -= rlen; 2801113584Ssimokawa hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf)); 2802169132Ssimokawa if (hlen <= 0) { 2803169132Ssimokawa printf("hlen should be positive."); 2804169132Ssimokawa goto err; 2805113584Ssimokawa } 2806113584Ssimokawa offset = sizeof(pktbuf); 2807113584Ssimokawa vec[0].iov_base = (char *)&pktbuf; 2808113584Ssimokawa vec[0].iov_len = offset; 2809113584Ssimokawa } else { 2810113584Ssimokawa /* splitted in payload */ 2811113584Ssimokawa offset = rlen; 2812113584Ssimokawa vec[0].iov_base = buf; 2813113584Ssimokawa vec[0].iov_len = rlen; 2814103285Sikob } 2815113584Ssimokawa fp=(struct fw_pkt *)vec[0].iov_base; 2816113584Ssimokawa nvec = 1; 2817113584Ssimokawa } else { 2818113584Ssimokawa /* no fragment in previous buffer */ 2819103285Sikob fp=(struct fw_pkt *)ld; 2820113584Ssimokawa hlen = fwohci_arcv_swap(fp, len); 2821113584Ssimokawa if (hlen == 0) 2822169132Ssimokawa goto err; 2823113584Ssimokawa if (hlen < 0) { 2824113584Ssimokawa dbch->pdb_tr = db_tr; 2825113584Ssimokawa dbch->buf_offset = - dbch->buf_offset; 2826113584Ssimokawa /* sanity check */ 2827272214Skan if (resCount != 0) { 2828169132Ssimokawa printf("resCount=%d hlen=%d\n", 2829169132Ssimokawa resCount, hlen); 2830169132Ssimokawa goto err; 2831169132Ssimokawa } 2832113584Ssimokawa goto out; 2833103285Sikob } 2834113584Ssimokawa offset = 0; 2835113584Ssimokawa nvec = 0; 2836113584Ssimokawa } 2837113584Ssimokawa plen = fwohci_get_plen(sc, dbch, fp) - offset; 2838113584Ssimokawa if (plen < 0) { 2839113584Ssimokawa /* minimum header size + trailer 2840113584Ssimokawa = sizeof(fw_pkt) so this shouldn't happens */ 2841120660Ssimokawa printf("plen(%d) is negative! offset=%d\n", 2842120660Ssimokawa plen, offset); 2843169132Ssimokawa goto err; 2844113584Ssimokawa } 2845113584Ssimokawa if (plen > 0) { 2846113584Ssimokawa len -= plen; 2847113584Ssimokawa if (len < 0) { 2848113584Ssimokawa dbch->pdb_tr = db_tr; 2849113584Ssimokawa if (firewire_debug) 2850113584Ssimokawa printf("splitted payload\n"); 2851113584Ssimokawa /* sanity check */ 2852272214Skan if (resCount != 0) { 2853169132Ssimokawa printf("resCount=%d plen=%d" 2854169132Ssimokawa " len=%d\n", 2855169132Ssimokawa resCount, plen, len); 2856169132Ssimokawa goto err; 2857169132Ssimokawa } 2858113584Ssimokawa goto out; 2859103285Sikob } 2860113584Ssimokawa vec[nvec].iov_base = ld; 2861113584Ssimokawa vec[nvec].iov_len = plen; 2862272214Skan nvec++; 2863103285Sikob ld += plen; 2864103285Sikob } 2865129585Sdfr dbch->buf_offset = ld - (uint8_t *)db_tr->buf; 2866113584Ssimokawa if (nvec == 0) 2867113584Ssimokawa printf("nvec == 0\n"); 2868113584Ssimokawa 2869103285Sikob/* DMA result-code will be written at the tail of packet */ 2870169132Ssimokawa stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer))); 2871110577Ssimokawa#if 0 2872120660Ssimokawa printf("plen: %d, stat %x\n", 2873120660Ssimokawa plen ,stat); 2874103285Sikob#endif 2875169132Ssimokawa spd = (stat >> 21) & 0x3; 2876169132Ssimokawa event = (stat >> 16) & 0x1f; 2877169132Ssimokawa switch (event) { 2878113584Ssimokawa case FWOHCIEV_ACKPEND: 2879113584Ssimokawa#if 0 2880113584Ssimokawa printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); 2881113584Ssimokawa#endif 2882113584Ssimokawa /* fall through */ 2883113584Ssimokawa case FWOHCIEV_ACKCOMPL: 2884120660Ssimokawa { 2885120660Ssimokawa struct fw_rcv_buf rb; 2886120660Ssimokawa 2887113584Ssimokawa if ((vec[nvec-1].iov_len -= 2888113584Ssimokawa sizeof(struct fwohci_trailer)) == 0) 2889272214Skan nvec--; 2890120660Ssimokawa rb.fc = &sc->fc; 2891120660Ssimokawa rb.vec = vec; 2892120660Ssimokawa rb.nvec = nvec; 2893120660Ssimokawa rb.spd = spd; 2894120660Ssimokawa fw_rcv(&rb); 2895120660Ssimokawa break; 2896120660Ssimokawa } 2897113584Ssimokawa case FWOHCIEV_BUSRST: 2898170425Ssimokawa if ((sc->fc.status != FWBUSRESET) && 2899170425Ssimokawa (sc->fc.status != FWBUSINIT)) 2900113584Ssimokawa printf("got BUSRST packet!?\n"); 2901113584Ssimokawa break; 2902113584Ssimokawa default: 2903169132Ssimokawa device_printf(sc->fc.dev, 2904169132Ssimokawa "Async DMA Receive error err=%02x %s" 2905169132Ssimokawa " plen=%d offset=%d len=%d status=0x%08x" 2906169132Ssimokawa " tcode=0x%x, stat=0x%08x\n", 2907169132Ssimokawa event, fwohcicode[event], plen, 2908169132Ssimokawa dbch->buf_offset, len, 2909169132Ssimokawa OREAD(sc, OHCI_DMACTL(off)), 2910169132Ssimokawa fp->mode.common.tcode, stat); 2911169132Ssimokawa#if 1 /* XXX */ 2912169132Ssimokawa goto err; 2913103285Sikob#endif 2914113584Ssimokawa break; 2915103285Sikob } 2916272214Skan pcnt++; 2917113584Ssimokawa if (dbch->pdb_tr != NULL) { 2918169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr, 2919169132Ssimokawa off, 1); 2920113584Ssimokawa dbch->pdb_tr = NULL; 2921113584Ssimokawa } 2922113584Ssimokawa 2923113584Ssimokawa } 2924103285Sikobout: 2925103285Sikob if (resCount == 0) { 2926103285Sikob /* done on this buffer */ 2927113584Ssimokawa if (dbch->pdb_tr == NULL) { 2928169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1); 2929113584Ssimokawa dbch->buf_offset = 0; 2930113584Ssimokawa } else 2931113584Ssimokawa if (dbch->pdb_tr != db_tr) 2932113584Ssimokawa printf("pdb_tr != db_tr\n"); 2933103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 2934113584Ssimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2935113584Ssimokawa >> OHCI_STATUS_SHIFT; 2936113584Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2937113584Ssimokawa & OHCI_COUNT_MASK; 2938113584Ssimokawa /* XXX check buffer overrun */ 2939103285Sikob dbch->top = db_tr; 2940103285Sikob } else { 2941103285Sikob dbch->buf_offset = dbch->xferq.psize - resCount; 2942103285Sikob break; 2943103285Sikob } 2944103285Sikob /* XXX make sure DMA is not dead */ 2945103285Sikob } 2946103285Sikob#if 0 2947103285Sikob if (pcnt < 1) 2948103285Sikob printf("fwohci_arcv: no packets\n"); 2949103285Sikob#endif 2950103285Sikob splx(s); 2951169132Ssimokawa return; 2952169132Ssimokawa 2953169132Ssimokawaerr: 2954169132Ssimokawa device_printf(sc->fc.dev, "AR DMA status=%x, ", 2955169132Ssimokawa OREAD(sc, OHCI_DMACTL(off))); 2956169132Ssimokawa dbch->pdb_tr = NULL; 2957169132Ssimokawa /* skip until resCount != 0 */ 2958169132Ssimokawa printf(" skip buffer"); 2959169132Ssimokawa while (resCount == 0) { 2960169132Ssimokawa printf(" #"); 2961169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0); 2962169132Ssimokawa db_tr = STAILQ_NEXT(db_tr, link); 2963169132Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2964169132Ssimokawa & OHCI_COUNT_MASK; 2965188584Ssbruno } 2966169132Ssimokawa printf(" done\n"); 2967169132Ssimokawa dbch->top = db_tr; 2968169132Ssimokawa dbch->buf_offset = dbch->xferq.psize - resCount; 2969169132Ssimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 2970169132Ssimokawa splx(s); 2971103285Sikob} 2972