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: stable/11/sys/dev/firewire/fwohci.c 310073 2016-12-14 16:30:47Z avg $ 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 514298955Spfg /* FLUSH FIFO and reset Transmitter/Receiver */ 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 695298955Spfg/* SID receive 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); 932298955Spfg/* Specify bound timer of asy. response */ 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); 1250109379Ssimokawa 1251113584Ssimokawa#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc) 1252272215Skan dbch->am = fwdma_malloc_multiseg(&sc->fc, sizeof(struct fwohcidb), 1253113584Ssimokawa DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK); 1254113584Ssimokawa if (dbch->am == NULL) { 1255113584Ssimokawa printf("fwohci_db_init: fwdma_malloc_multiseg failed\n"); 1256124836Ssimokawa free(db_tr, M_FW); 1257103285Sikob return; 1258103285Sikob } 1259103285Sikob /* Attach DB to DMA ch. */ 1260272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1261103285Sikob db_tr->dbcnt = 0; 1262113584Ssimokawa db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb); 1263113584Ssimokawa db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb); 1264113584Ssimokawa /* create dmamap for buffers */ 1265113584Ssimokawa /* XXX do we need 4bytes alignment tag? */ 1266113584Ssimokawa /* XXX don't alloc dma_map for AR */ 1267113584Ssimokawa if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) { 1268113584Ssimokawa printf("bus_dmamap_create failed\n"); 1269113584Ssimokawa dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */ 1270113584Ssimokawa fwohci_db_free(dbch); 1271113584Ssimokawa return; 1272113584Ssimokawa } 1273103285Sikob STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); 1274113584Ssimokawa if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1275108530Ssimokawa if (idb % dbch->xferq.bnpacket == 0) 1276108530Ssimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1277108530Ssimokawa ].start = (caddr_t)db_tr; 1278108530Ssimokawa if ((idb + 1) % dbch->xferq.bnpacket == 0) 1279108530Ssimokawa dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1280108530Ssimokawa ].end = (caddr_t)db_tr; 1281103285Sikob } 1282103285Sikob db_tr++; 1283103285Sikob } 1284103285Sikob STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next 1285103285Sikob = STAILQ_FIRST(&dbch->db_trq); 1286108642Ssimokawaout: 1287108642Ssimokawa dbch->xferq.queued = 0; 1288108642Ssimokawa dbch->pdb_tr = NULL; 1289103285Sikob dbch->top = STAILQ_FIRST(&dbch->db_trq); 1290103285Sikob dbch->bottom = dbch->top; 1291108527Ssimokawa dbch->flags = FWOHCI_DBCH_INIT; 1292103285Sikob} 1293106790Ssimokawa 1294106790Ssimokawastatic int 1295106790Ssimokawafwohci_itx_disable(struct firewire_comm *fc, int dmach) 1296103285Sikob{ 1297103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1298109890Ssimokawa 1299272214Skan OWRITE(sc, OHCI_ITCTLCLR(dmach), 1300113584Ssimokawa OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S); 1301103285Sikob OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1302103285Sikob OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1303109890Ssimokawa /* XXX we cannot free buffers until the DMA really stops */ 1304167086Sjhb pause("fwitxd", hz); 1305103285Sikob fwohci_db_free(&sc->it[dmach]); 1306103285Sikob sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1307103285Sikob return 0; 1308103285Sikob} 1309106790Ssimokawa 1310106790Ssimokawastatic int 1311106790Ssimokawafwohci_irx_disable(struct firewire_comm *fc, int dmach) 1312103285Sikob{ 1313103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1314103285Sikob 1315103285Sikob OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1316103285Sikob OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1317103285Sikob OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1318109890Ssimokawa /* XXX we cannot free buffers until the DMA really stops */ 1319167086Sjhb pause("fwirxd", hz); 1320103285Sikob fwohci_db_free(&sc->ir[dmach]); 1321103285Sikob sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1322103285Sikob return 0; 1323103285Sikob} 1324106790Ssimokawa 1325113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 1326106790Ssimokawastatic void 1327129585Sdfrfwohci_irx_post (struct firewire_comm *fc , uint32_t *qld) 1328103285Sikob{ 1329113584Ssimokawa qld[0] = FWOHCI_DMA_READ(qld[0]); 1330103285Sikob return; 1331103285Sikob} 1332103285Sikob#endif 1333103285Sikob 1334106790Ssimokawastatic int 1335106790Ssimokawafwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1336103285Sikob{ 1337103285Sikob int err = 0; 1338113584Ssimokawa int idb, z, i, dmach = 0, ldesc; 1339129585Sdfr uint32_t off = 0; 1340103285Sikob struct fwohcidb_tr *db_tr; 1341120660Ssimokawa struct fwohcidb *db; 1342103285Sikob 1343272214Skan if (!(dbch->xferq.flag & FWXFERQ_EXTBUF)) { 1344103285Sikob err = EINVAL; 1345103285Sikob return err; 1346103285Sikob } 1347103285Sikob z = dbch->ndesc; 1348272214Skan for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 1349272214Skan if (&sc->it[dmach] == dbch) { 1350103285Sikob off = OHCI_ITOFF(dmach); 1351103285Sikob break; 1352103285Sikob } 1353103285Sikob } 1354272214Skan if (off == 0) { 1355103285Sikob err = EINVAL; 1356103285Sikob return err; 1357103285Sikob } 1358272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) 1359103285Sikob return err; 1360103285Sikob dbch->xferq.flag |= FWXFERQ_RUNNING; 1361272214Skan for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 1362103285Sikob dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1363103285Sikob } 1364103285Sikob db_tr = dbch->top; 1365272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1366113584Ssimokawa fwohci_add_tx_buf(dbch, db_tr, idb); 1367272214Skan if (STAILQ_NEXT(db_tr, link) == NULL) { 1368103285Sikob break; 1369103285Sikob } 1370109892Ssimokawa db = db_tr->db; 1371113584Ssimokawa ldesc = db_tr->dbcnt - 1; 1372113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.depend, 1373113584Ssimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 1374113584Ssimokawa db[ldesc].db.desc.depend = db[0].db.desc.depend; 1375272214Skan if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1376272214Skan if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 1377113584Ssimokawa FWOHCI_DMA_SET( 1378113584Ssimokawa db[ldesc].db.desc.cmd, 1379113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1380109280Ssimokawa /* OHCI 1.1 and above */ 1381113584Ssimokawa FWOHCI_DMA_SET( 1382113584Ssimokawa db[0].db.desc.cmd, 1383113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1384103285Sikob } 1385103285Sikob } 1386103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 1387103285Sikob } 1388113584Ssimokawa FWOHCI_DMA_CLEAR( 1389113584Ssimokawa dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf); 1390103285Sikob return err; 1391103285Sikob} 1392106790Ssimokawa 1393106790Ssimokawastatic int 1394106790Ssimokawafwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1395103285Sikob{ 1396103285Sikob int err = 0; 1397109892Ssimokawa int idb, z, i, dmach = 0, ldesc; 1398129585Sdfr uint32_t off = 0; 1399103285Sikob struct fwohcidb_tr *db_tr; 1400120660Ssimokawa struct fwohcidb *db; 1401103285Sikob 1402103285Sikob z = dbch->ndesc; 1403272214Skan if (&sc->arrq == dbch) { 1404103285Sikob off = OHCI_ARQOFF; 1405272214Skan } else if (&sc->arrs == dbch) { 1406103285Sikob off = OHCI_ARSOFF; 1407272214Skan } else { 1408272214Skan for (dmach = 0; dmach < sc->fc.nisodma; dmach++) { 1409272214Skan if (&sc->ir[dmach] == dbch) { 1410103285Sikob off = OHCI_IROFF(dmach); 1411103285Sikob break; 1412103285Sikob } 1413103285Sikob } 1414103285Sikob } 1415272214Skan if (off == 0) { 1416103285Sikob err = EINVAL; 1417103285Sikob return err; 1418103285Sikob } 1419272214Skan if (dbch->xferq.flag & FWXFERQ_STREAM) { 1420272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) 1421103285Sikob return err; 1422272214Skan } else { 1423272214Skan if (dbch->xferq.flag & FWXFERQ_RUNNING) { 1424103285Sikob err = EBUSY; 1425103285Sikob return err; 1426103285Sikob } 1427103285Sikob } 1428103285Sikob dbch->xferq.flag |= FWXFERQ_RUNNING; 1429108642Ssimokawa dbch->top = STAILQ_FIRST(&dbch->db_trq); 1430272214Skan for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) { 1431103285Sikob dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1432103285Sikob } 1433103285Sikob db_tr = dbch->top; 1434272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 1435113584Ssimokawa fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma); 1436113584Ssimokawa if (STAILQ_NEXT(db_tr, link) == NULL) 1437103285Sikob break; 1438109892Ssimokawa db = db_tr->db; 1439109892Ssimokawa ldesc = db_tr->dbcnt - 1; 1440113584Ssimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend, 1441113584Ssimokawa STAILQ_NEXT(db_tr, link)->bus_addr | z); 1442272214Skan if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1443272214Skan if (((idb + 1) % dbch->xferq.bnpacket) == 0) { 1444113584Ssimokawa FWOHCI_DMA_SET( 1445113584Ssimokawa db[ldesc].db.desc.cmd, 1446113584Ssimokawa OHCI_INTERRUPT_ALWAYS); 1447113584Ssimokawa FWOHCI_DMA_CLEAR( 1448113584Ssimokawa db[ldesc].db.desc.depend, 1449113584Ssimokawa 0xf); 1450103285Sikob } 1451103285Sikob } 1452103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 1453103285Sikob } 1454113584Ssimokawa FWOHCI_DMA_CLEAR( 1455113584Ssimokawa dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf); 1456103285Sikob dbch->buf_offset = 0; 1457113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1458113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1459272214Skan if (dbch->xferq.flag & FWXFERQ_STREAM) { 1460103285Sikob return err; 1461272214Skan } else { 1462113584Ssimokawa OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z); 1463103285Sikob } 1464103285Sikob OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 1465103285Sikob return err; 1466103285Sikob} 1467106790Ssimokawa 1468106790Ssimokawastatic int 1469113584Ssimokawafwohci_next_cycle(struct firewire_comm *fc, int cycle_now) 1470109890Ssimokawa{ 1471109890Ssimokawa int sec, cycle, cycle_match; 1472109890Ssimokawa 1473109890Ssimokawa cycle = cycle_now & 0x1fff; 1474109890Ssimokawa sec = cycle_now >> 13; 1475109890Ssimokawa#define CYCLE_MOD 0x10 1476113584Ssimokawa#if 1 1477109890Ssimokawa#define CYCLE_DELAY 8 /* min delay to start DMA */ 1478113584Ssimokawa#else 1479113584Ssimokawa#define CYCLE_DELAY 7000 /* min delay to start DMA */ 1480113584Ssimokawa#endif 1481109890Ssimokawa cycle = cycle + CYCLE_DELAY; 1482109890Ssimokawa if (cycle >= 8000) { 1483272214Skan sec++; 1484109890Ssimokawa cycle -= 8000; 1485109890Ssimokawa } 1486113584Ssimokawa cycle = roundup2(cycle, CYCLE_MOD); 1487109890Ssimokawa if (cycle >= 8000) { 1488272214Skan sec++; 1489109890Ssimokawa if (cycle == 8000) 1490109890Ssimokawa cycle = 0; 1491109890Ssimokawa else 1492109890Ssimokawa cycle = CYCLE_MOD; 1493109890Ssimokawa } 1494109890Ssimokawa cycle_match = ((sec << 13) | cycle) & 0x7ffff; 1495109890Ssimokawa 1496272214Skan return (cycle_match); 1497109890Ssimokawa} 1498109890Ssimokawa 1499109890Ssimokawastatic int 1500106790Ssimokawafwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) 1501103285Sikob{ 1502103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1503103285Sikob int err = 0; 1504103285Sikob unsigned short tag, ich; 1505103285Sikob struct fwohci_dbch *dbch; 1506109890Ssimokawa int cycle_match, cycle_now, s, ldesc; 1507129585Sdfr uint32_t stat; 1508109890Ssimokawa struct fw_bulkxfer *first, *chunk, *prev; 1509109890Ssimokawa struct fw_xferq *it; 1510103285Sikob 1511103285Sikob dbch = &sc->it[dmach]; 1512109890Ssimokawa it = &dbch->xferq; 1513109890Ssimokawa 1514109890Ssimokawa tag = (it->flag >> 6) & 3; 1515109890Ssimokawa ich = it->flag & 0x3f; 1516109179Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { 1517109890Ssimokawa dbch->ndb = it->bnpacket * it->bnchunk; 1518103285Sikob dbch->ndesc = 3; 1519113584Ssimokawa fwohci_db_init(sc, dbch); 1520109179Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1521109179Ssimokawa return ENOMEM; 1522170374Ssimokawa 1523103285Sikob err = fwohci_tx_enable(sc, dbch); 1524103285Sikob } 1525272214Skan if (err) 1526103285Sikob return err; 1527109890Ssimokawa 1528109892Ssimokawa ldesc = dbch->ndesc - 1; 1529109890Ssimokawa s = splfw(); 1530170374Ssimokawa FW_GLOCK(fc); 1531109890Ssimokawa prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); 1532109890Ssimokawa while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { 1533120660Ssimokawa struct fwohcidb *db; 1534109890Ssimokawa 1535113584Ssimokawa fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket, 1536113584Ssimokawa BUS_DMASYNC_PREWRITE); 1537109890Ssimokawa fwohci_txbufdb(sc, dmach, chunk); 1538109890Ssimokawa if (prev != NULL) { 1539109890Ssimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 1540113584Ssimokawa#if 0 /* XXX necessary? */ 1541113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, 1542113584Ssimokawa OHCI_BRANCH_ALWAYS); 1543113584Ssimokawa#endif 1544109892Ssimokawa#if 0 /* if bulkxfer->npacket changes */ 1545272214Skan db[ldesc].db.desc.depend = db[0].db.desc.depend = 1546113584Ssimokawa ((struct fwohcidb_tr *) 1547113584Ssimokawa (chunk->start))->bus_addr | dbch->ndesc; 1548109892Ssimokawa#else 1549113584Ssimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 1550113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1551109892Ssimokawa#endif 1552103285Sikob } 1553109890Ssimokawa STAILQ_REMOVE_HEAD(&it->stvalid, link); 1554109890Ssimokawa STAILQ_INSERT_TAIL(&it->stdma, chunk, link); 1555109890Ssimokawa prev = chunk; 1556109403Ssimokawa } 1557170374Ssimokawa FW_GUNLOCK(fc); 1558113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1559113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1560109890Ssimokawa splx(s); 1561109890Ssimokawa stat = OREAD(sc, OHCI_ITCTL(dmach)); 1562113584Ssimokawa if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S)) 1563113584Ssimokawa printf("stat 0x%x\n", stat); 1564113584Ssimokawa 1565109890Ssimokawa if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) 1566109890Ssimokawa return 0; 1567109890Ssimokawa 1568113584Ssimokawa#if 0 1569109890Ssimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1570113584Ssimokawa#endif 1571109403Ssimokawa OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1572109403Ssimokawa OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1573109403Ssimokawa OWRITE(sc, OHCI_IT_MASK, 1 << dmach); 1574113584Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); 1575109890Ssimokawa 1576109890Ssimokawa first = STAILQ_FIRST(&it->stdma); 1577113584Ssimokawa OWRITE(sc, OHCI_ITCMD(dmach), 1578113584Ssimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); 1579167629Ssimokawa if (firewire_debug > 1) { 1580109890Ssimokawa printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); 1581113584Ssimokawa#if 1 1582113584Ssimokawa dump_dma(sc, ITX_CH + dmach); 1583113584Ssimokawa#endif 1584113584Ssimokawa } 1585109403Ssimokawa if ((stat & OHCI_CNTL_DMA_RUN) == 0) { 1586109890Ssimokawa#if 1 1587109890Ssimokawa /* Don't start until all chunks are buffered */ 1588109890Ssimokawa if (STAILQ_FIRST(&it->stfree) != NULL) 1589109890Ssimokawa goto out; 1590109890Ssimokawa#endif 1591113584Ssimokawa#if 1 1592109890Ssimokawa /* Clear cycle match counter bits */ 1593109890Ssimokawa OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); 1594109890Ssimokawa 1595109356Ssimokawa /* 2bit second + 13bit cycle */ 1596109356Ssimokawa cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; 1597113584Ssimokawa cycle_match = fwohci_next_cycle(fc, cycle_now); 1598109890Ssimokawa 1599109356Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), 1600109356Ssimokawa OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) 1601109356Ssimokawa | OHCI_CNTL_DMA_RUN); 1602113584Ssimokawa#else 1603113584Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); 1604113584Ssimokawa#endif 1605167629Ssimokawa if (firewire_debug > 1) { 1606109403Ssimokawa printf("cycle_match: 0x%04x->0x%04x\n", 1607109403Ssimokawa cycle_now, cycle_match); 1608113584Ssimokawa dump_dma(sc, ITX_CH + dmach); 1609113584Ssimokawa dump_db(sc, ITX_CH + dmach); 1610113584Ssimokawa } 1611109403Ssimokawa } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { 1612109890Ssimokawa device_printf(sc->fc.dev, 1613109890Ssimokawa "IT DMA underrun (0x%08x)\n", stat); 1614113584Ssimokawa OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE); 1615103285Sikob } 1616109890Ssimokawaout: 1617103285Sikob return err; 1618103285Sikob} 1619106790Ssimokawa 1620106790Ssimokawastatic int 1621113584Ssimokawafwohci_irx_enable(struct firewire_comm *fc, int dmach) 1622103285Sikob{ 1623103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1624109890Ssimokawa int err = 0, s, ldesc; 1625103285Sikob unsigned short tag, ich; 1626129585Sdfr uint32_t stat; 1627109890Ssimokawa struct fwohci_dbch *dbch; 1628113584Ssimokawa struct fwohcidb_tr *db_tr; 1629109890Ssimokawa struct fw_bulkxfer *first, *prev, *chunk; 1630109890Ssimokawa struct fw_xferq *ir; 1631103285Sikob 1632109890Ssimokawa dbch = &sc->ir[dmach]; 1633109890Ssimokawa ir = &dbch->xferq; 1634109890Ssimokawa 1635109890Ssimokawa if ((ir->flag & FWXFERQ_RUNNING) == 0) { 1636109890Ssimokawa tag = (ir->flag >> 6) & 3; 1637109890Ssimokawa ich = ir->flag & 0x3f; 1638108995Ssimokawa OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 1639108995Ssimokawa 1640109890Ssimokawa ir->queued = 0; 1641109890Ssimokawa dbch->ndb = ir->bnpacket * ir->bnchunk; 1642109890Ssimokawa dbch->ndesc = 2; 1643113584Ssimokawa fwohci_db_init(sc, dbch); 1644109890Ssimokawa if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1645109179Ssimokawa return ENOMEM; 1646109890Ssimokawa err = fwohci_rx_enable(sc, dbch); 1647103285Sikob } 1648272214Skan if (err) 1649103285Sikob return err; 1650103285Sikob 1651109890Ssimokawa first = STAILQ_FIRST(&ir->stfree); 1652109890Ssimokawa if (first == NULL) { 1653109890Ssimokawa device_printf(fc->dev, "IR DMA no free chunk\n"); 1654109890Ssimokawa return 0; 1655109890Ssimokawa } 1656109890Ssimokawa 1657111892Ssimokawa ldesc = dbch->ndesc - 1; 1658111892Ssimokawa s = splfw(); 1659170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 1660170374Ssimokawa FW_GLOCK(fc); 1661109890Ssimokawa prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); 1662109890Ssimokawa while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { 1663120660Ssimokawa struct fwohcidb *db; 1664109890Ssimokawa 1665111942Ssimokawa#if 1 /* XXX for if_fwe */ 1666113584Ssimokawa if (chunk->mbuf != NULL) { 1667113584Ssimokawa db_tr = (struct fwohcidb_tr *)(chunk->start); 1668113584Ssimokawa db_tr->dbcnt = 1; 1669113584Ssimokawa err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 1670113584Ssimokawa chunk->mbuf, fwohci_execute_db2, db_tr, 1671113584Ssimokawa /* flags */0); 1672113584Ssimokawa FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd, 1673113584Ssimokawa OHCI_UPDATE | OHCI_INPUT_LAST | 1674113584Ssimokawa OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 1675113584Ssimokawa } 1676111942Ssimokawa#endif 1677109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 1678113584Ssimokawa FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0); 1679113584Ssimokawa FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf); 1680109890Ssimokawa if (prev != NULL) { 1681109890Ssimokawa db = ((struct fwohcidb_tr *)(prev->end))->db; 1682113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1683103285Sikob } 1684109890Ssimokawa STAILQ_REMOVE_HEAD(&ir->stfree, link); 1685109890Ssimokawa STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); 1686109890Ssimokawa prev = chunk; 1687103285Sikob } 1688170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 1689170374Ssimokawa FW_GUNLOCK(fc); 1690113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1691113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1692109890Ssimokawa splx(s); 1693109890Ssimokawa stat = OREAD(sc, OHCI_IRCTL(dmach)); 1694109890Ssimokawa if (stat & OHCI_CNTL_DMA_ACTIVE) 1695109890Ssimokawa return 0; 1696109890Ssimokawa if (stat & OHCI_CNTL_DMA_RUN) { 1697109890Ssimokawa OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1698109890Ssimokawa device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); 1699109890Ssimokawa } 1700109890Ssimokawa 1701113584Ssimokawa if (firewire_debug) 1702113584Ssimokawa printf("start IR DMA 0x%x\n", stat); 1703109890Ssimokawa OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1704109890Ssimokawa OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1705109890Ssimokawa OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 1706109890Ssimokawa OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); 1707109890Ssimokawa OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 1708109890Ssimokawa OWRITE(sc, OHCI_IRCMD(dmach), 1709113584Ssimokawa ((struct fwohcidb_tr *)(first->start))->bus_addr 1710109890Ssimokawa | dbch->ndesc); 1711109890Ssimokawa OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 1712109890Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 1713113584Ssimokawa#if 0 1714113584Ssimokawa dump_db(sc, IRX_CH + dmach); 1715113584Ssimokawa#endif 1716103285Sikob return err; 1717103285Sikob} 1718106790Ssimokawa 1719106790Ssimokawaint 1720110145Ssimokawafwohci_stop(struct fwohci_softc *sc, device_t dev) 1721103285Sikob{ 1722103285Sikob u_int i; 1723103285Sikob 1724178911Ssimokawa fwohci_set_intr(&sc->fc, 0); 1725178911Ssimokawa 1726103285Sikob/* Now stopping all DMA channel */ 1727272214Skan OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 1728272214Skan OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 1729272214Skan OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1730272214Skan OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1731103285Sikob 1732272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 1733272214Skan OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 1734272214Skan OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 1735103285Sikob } 1736103285Sikob 1737272214Skan#if 0 /* Let dcons(4) be accessed */ 1738103285Sikob/* Stop interrupt */ 1739103285Sikob OWRITE(sc, FWOHCI_INTMASKCLR, 1740103285Sikob OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID 1741103285Sikob | OHCI_INT_PHY_INT 1742272214Skan | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 1743103285Sikob | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 1744272214Skan | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 1745103285Sikob | OHCI_INT_PHY_BUS_R); 1746116978Ssimokawa 1747298955Spfg/* FLUSH FIFO and reset Transmitter/Receiver */ 1748272214Skan OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 1749170374Ssimokawa#endif 1750116978Ssimokawa 1751108642Ssimokawa/* XXX Link down? Bus reset? */ 1752103285Sikob return 0; 1753103285Sikob} 1754103285Sikob 1755108642Ssimokawaint 1756108642Ssimokawafwohci_resume(struct fwohci_softc *sc, device_t dev) 1757108642Ssimokawa{ 1758108642Ssimokawa int i; 1759116978Ssimokawa struct fw_xferq *ir; 1760116978Ssimokawa struct fw_bulkxfer *chunk; 1761108642Ssimokawa 1762108642Ssimokawa fwohci_reset(sc, dev); 1763129541Sdfr /* XXX resume isochronous receive automatically. (how about TX?) */ 1764272214Skan for (i = 0; i < sc->fc.nisodma; i++) { 1765116978Ssimokawa ir = &sc->ir[i].xferq; 1766272214Skan if ((ir->flag & FWXFERQ_RUNNING) != 0) { 1767108642Ssimokawa device_printf(sc->fc.dev, 1768108642Ssimokawa "resume iso receive ch: %d\n", i); 1769116978Ssimokawa ir->flag &= ~FWXFERQ_RUNNING; 1770116978Ssimokawa /* requeue stdma to stfree */ 1771272214Skan while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 1772116978Ssimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 1773116978Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, chunk, link); 1774116978Ssimokawa } 1775108642Ssimokawa sc->fc.irx_enable(&sc->fc, i); 1776108642Ssimokawa } 1777108642Ssimokawa } 1778108642Ssimokawa 1779108642Ssimokawa bus_generic_resume(dev); 1780108642Ssimokawa sc->fc.ibr(&sc->fc); 1781108642Ssimokawa return 0; 1782108642Ssimokawa} 1783108642Ssimokawa 1784170374Ssimokawa#ifdef OHCI_DEBUG 1785103285Sikobstatic void 1786170374Ssimokawafwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat) 1787103285Sikob{ 1788272214Skan if (stat & OREAD(sc, FWOHCI_INTMASK)) 1789103285Sikob 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", 1790103285Sikob stat & OHCI_INT_EN ? "DMA_EN ":"", 1791103285Sikob stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", 1792103285Sikob stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", 1793103285Sikob stat & OHCI_INT_ERR ? "INT_ERR ":"", 1794103285Sikob stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", 1795103285Sikob stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", 1796103285Sikob stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", 1797103285Sikob stat & OHCI_INT_CYC_START ? "CYC_START ":"", 1798103285Sikob stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", 1799103285Sikob stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", 1800103285Sikob stat & OHCI_INT_PHY_SID ? "SID ":"", 1801103285Sikob stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", 1802103285Sikob stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", 1803103285Sikob stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", 1804103285Sikob stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", 1805103285Sikob stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", 1806103285Sikob stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", 1807103285Sikob stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", 1808103285Sikob stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", 1809103285Sikob stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", 1810103285Sikob stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", 1811272214Skan stat, OREAD(sc, FWOHCI_INTMASK) 1812103285Sikob ); 1813170374Ssimokawa} 1814103285Sikob#endif 1815272214Skan 1816170374Ssimokawastatic void 1817170374Ssimokawafwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) 1818170374Ssimokawa{ 1819170374Ssimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 1820277511Swill uintmax_t prequpper; 1821170374Ssimokawa uint32_t node_id, plen; 1822170374Ssimokawa 1823187993Ssbruno FW_GLOCK_ASSERT(fc); 1824170374Ssimokawa if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) { 1825170374Ssimokawa fc->status = FWBUSRESET; 1826111074Ssimokawa /* Disable bus reset interrupt until sid recv. */ 1827272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); 1828272214Skan 1829188509Ssbruno device_printf(fc->dev, "%s: BUS reset\n", __func__); 1830272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 1831103285Sikob OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); 1832103285Sikob 1833272214Skan OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1834103285Sikob sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; 1835272214Skan OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1836103285Sikob sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; 1837103285Sikob 1838170374Ssimokawa if (!kdb_active) 1839170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset); 1840170374Ssimokawa } 1841170374Ssimokawa if (stat & OHCI_INT_PHY_SID) { 1842170374Ssimokawa /* Enable bus reset interrupt */ 1843103285Sikob OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); 1844170374Ssimokawa OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); 1845170374Ssimokawa 1846170374Ssimokawa /* Allow async. request to us */ 1847170374Ssimokawa OWRITE(sc, OHCI_AREQHI, 1 << 31); 1848170400Ssimokawa if (firewire_phydma_enable) { 1849170400Ssimokawa /* allow from all nodes */ 1850170400Ssimokawa OWRITE(sc, OHCI_PREQHI, 0x7fffffff); 1851170400Ssimokawa OWRITE(sc, OHCI_PREQLO, 0xffffffff); 1852277511Swill prequpper = ((uintmax_t)Maxmem << PAGE_SHIFT) >> 16; 1853277511Swill if (prequpper > OHCI_PREQUPPER_MAX) { 1854277511Swill device_printf(fc->dev, 1855277511Swill "Physical memory size of 0x%jx exceeds " 1856277511Swill "fire wire address space. Limiting dma " 1857277511Swill "to memory below 0x%jx\n", 1858277511Swill (uintmax_t)Maxmem << PAGE_SHIFT, 1859277511Swill (uintmax_t)OHCI_PREQUPPER_MAX << 16); 1860277511Swill prequpper = OHCI_PREQUPPER_MAX; 1861277511Swill } 1862277511Swill OWRITE(sc, OHCI_PREQUPPER, prequpper & 0xffffffff); 1863310073Savg if (OREAD(sc, OHCI_PREQUPPER) != 1864310073Savg (prequpper & 0xffffffff)) { 1865310073Savg device_printf(fc->dev, 1866310073Savg "PhysicalUpperBound register is not " 1867310073Savg "implemented. Physical memory access " 1868310073Savg "is limited to the first 4GB\n"); 1869310073Savg device_printf(fc->dev, 1870310073Savg "PhysicalUpperBound = 0x%08x\n", 1871310073Savg OREAD(sc, OHCI_PREQUPPER)); 1872310073Savg } 1873170400Ssimokawa } 1874170374Ssimokawa /* Set ATRetries register */ 1875272214Skan OWRITE(sc, OHCI_ATRETRY, 1<<(13 + 16) | 0xfff); 1876170374Ssimokawa 1877170374Ssimokawa /* 1878272214Skan * Checking whether the node is root or not. If root, turn on 1879170374Ssimokawa * cycle master. 1880170374Ssimokawa */ 1881170374Ssimokawa node_id = OREAD(sc, FWOHCI_NODEID); 1882170374Ssimokawa plen = OREAD(sc, OHCI_SID_CNT); 1883170374Ssimokawa 1884170374Ssimokawa fc->nodeid = node_id & 0x3f; 1885188509Ssbruno device_printf(fc->dev, "%s: node_id=0x%08x, SelfID Count=%d, ", 1886188509Ssbruno __func__, fc->nodeid, (plen >> 16) & 0xff); 1887170374Ssimokawa if (!(node_id & OHCI_NODE_VALID)) { 1888188509Ssbruno device_printf(fc->dev, "%s: Bus reset failure\n", 1889188509Ssbruno __func__); 1890170374Ssimokawa goto sidout; 1891170374Ssimokawa } 1892170374Ssimokawa 1893170374Ssimokawa /* cycle timer */ 1894170374Ssimokawa sc->cycle_lost = 0; 1895272214Skan OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST); 1896170374Ssimokawa if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) { 1897170374Ssimokawa printf("CYCLEMASTER mode\n"); 1898170374Ssimokawa OWRITE(sc, OHCI_LNKCTL, 1899170374Ssimokawa OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); 1900170374Ssimokawa } else { 1901170374Ssimokawa printf("non CYCLEMASTER mode\n"); 1902170374Ssimokawa OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); 1903170374Ssimokawa OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); 1904170374Ssimokawa } 1905170374Ssimokawa 1906170374Ssimokawa fc->status = FWBUSINIT; 1907170374Ssimokawa 1908170374Ssimokawa if (!kdb_active) 1909170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid); 1910103285Sikob } 1911170374Ssimokawasidout: 1912170374Ssimokawa if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active)) 1913170374Ssimokawa taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma); 1914170374Ssimokawa} 1915170374Ssimokawa 1916170374Ssimokawastatic void 1917170374Ssimokawafwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count) 1918170374Ssimokawa{ 1919170374Ssimokawa uint32_t irstat, itstat; 1920170374Ssimokawa u_int i; 1921170374Ssimokawa struct firewire_comm *fc = (struct firewire_comm *)sc; 1922170374Ssimokawa 1923170374Ssimokawa if (stat & OHCI_INT_DMA_IR) { 1924127468Ssimokawa irstat = atomic_readandclear_int(&sc->irstat); 1925272214Skan for (i = 0; i < fc->nisodma; i++) { 1926109644Ssimokawa struct fwohci_dbch *dbch; 1927109644Ssimokawa 1928272214Skan if ((irstat & (1 << i)) != 0) { 1929109644Ssimokawa dbch = &sc->ir[i]; 1930109644Ssimokawa if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) { 1931109644Ssimokawa device_printf(sc->fc.dev, 1932109644Ssimokawa "dma(%d) not active\n", i); 1933109644Ssimokawa continue; 1934109644Ssimokawa } 1935113584Ssimokawa fwohci_rbuf_update(sc, i); 1936103285Sikob } 1937103285Sikob } 1938103285Sikob } 1939170374Ssimokawa if (stat & OHCI_INT_DMA_IT) { 1940127468Ssimokawa itstat = atomic_readandclear_int(&sc->itstat); 1941272214Skan for (i = 0; i < fc->nisodma; i++) { 1942272214Skan if ((itstat & (1 << i)) != 0) { 1943103285Sikob fwohci_tbuf_update(sc, i); 1944103285Sikob } 1945103285Sikob } 1946103285Sikob } 1947170374Ssimokawa if (stat & OHCI_INT_DMA_PRRS) { 1948103285Sikob#if 0 1949103285Sikob dump_dma(sc, ARRS_CH); 1950103285Sikob dump_db(sc, ARRS_CH); 1951103285Sikob#endif 1952106789Ssimokawa fwohci_arcv(sc, &sc->arrs, count); 1953103285Sikob } 1954170374Ssimokawa if (stat & OHCI_INT_DMA_PRRQ) { 1955103285Sikob#if 0 1956103285Sikob dump_dma(sc, ARRQ_CH); 1957103285Sikob dump_db(sc, ARRQ_CH); 1958103285Sikob#endif 1959106789Ssimokawa fwohci_arcv(sc, &sc->arrq, count); 1960103285Sikob } 1961167628Ssimokawa if (stat & OHCI_INT_CYC_LOST) { 1962167628Ssimokawa if (sc->cycle_lost >= 0) 1963272214Skan sc->cycle_lost++; 1964167628Ssimokawa if (sc->cycle_lost > 10) { 1965167628Ssimokawa sc->cycle_lost = -1; 1966167628Ssimokawa#if 0 1967167628Ssimokawa OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); 1968167628Ssimokawa#endif 1969272214Skan OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 1970214021Sbrucec device_printf(fc->dev, "too many cycles lost, " 1971214021Sbrucec "no cycle master present?\n"); 1972167628Ssimokawa } 1973167628Ssimokawa } 1974170374Ssimokawa if (stat & OHCI_INT_DMA_ATRQ) { 1975103285Sikob fwohci_txd(sc, &(sc->atrq)); 1976103285Sikob } 1977170374Ssimokawa if (stat & OHCI_INT_DMA_ATRS) { 1978103285Sikob fwohci_txd(sc, &(sc->atrs)); 1979103285Sikob } 1980170374Ssimokawa if (stat & OHCI_INT_PW_ERR) { 1981103285Sikob device_printf(fc->dev, "posted write error\n"); 1982103285Sikob } 1983170374Ssimokawa if (stat & OHCI_INT_ERR) { 1984103285Sikob device_printf(fc->dev, "unrecoverable error\n"); 1985103285Sikob } 1986170374Ssimokawa if (stat & OHCI_INT_PHY_INT) { 1987103285Sikob device_printf(fc->dev, "phy int\n"); 1988103285Sikob } 1989103285Sikob} 1990103285Sikob 1991113584Ssimokawastatic void 1992170374Ssimokawafwohci_task_busreset(void *arg, int pending) 1993113584Ssimokawa{ 1994113584Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 1995170374Ssimokawa 1996187993Ssbruno FW_GLOCK(&sc->fc); 1997170374Ssimokawa fw_busreset(&sc->fc, FWBUSRESET); 1998170374Ssimokawa OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 1999170374Ssimokawa OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 2000187993Ssbruno FW_GUNLOCK(&sc->fc); 2001170374Ssimokawa} 2002170374Ssimokawa 2003170374Ssimokawastatic void 2004170374Ssimokawafwohci_task_sid(void *arg, int pending) 2005170374Ssimokawa{ 2006170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2007170374Ssimokawa struct firewire_comm *fc = &sc->fc; 2008170374Ssimokawa uint32_t *buf; 2009170374Ssimokawa int i, plen; 2010170374Ssimokawa 2011170374Ssimokawa 2012187993Ssbruno /* 2013187993Ssbruno * We really should have locking 2014187993Ssbruno * here. Not sure why it's not 2015187993Ssbruno */ 2016170374Ssimokawa plen = OREAD(sc, OHCI_SID_CNT); 2017170374Ssimokawa 2018170374Ssimokawa if (plen & OHCI_SID_ERR) { 2019170374Ssimokawa device_printf(fc->dev, "SID Error\n"); 2020170374Ssimokawa return; 2021170374Ssimokawa } 2022170374Ssimokawa plen &= OHCI_SID_CNT_MASK; 2023170374Ssimokawa if (plen < 4 || plen > OHCI_SIDSIZE) { 2024170374Ssimokawa device_printf(fc->dev, "invalid SID len = %d\n", plen); 2025170374Ssimokawa return; 2026170374Ssimokawa } 2027170374Ssimokawa plen -= 4; /* chop control info */ 2028170374Ssimokawa buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); 2029170374Ssimokawa if (buf == NULL) { 2030170374Ssimokawa device_printf(fc->dev, "malloc failed\n"); 2031170374Ssimokawa return; 2032170374Ssimokawa } 2033272214Skan for (i = 0; i < plen / 4; i++) 2034272214Skan buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i + 1]); 2035187993Ssbruno 2036170374Ssimokawa /* pending all pre-bus_reset packets */ 2037170374Ssimokawa fwohci_txd(sc, &sc->atrq); 2038170374Ssimokawa fwohci_txd(sc, &sc->atrs); 2039170374Ssimokawa fwohci_arcv(sc, &sc->arrs, -1); 2040170374Ssimokawa fwohci_arcv(sc, &sc->arrq, -1); 2041170374Ssimokawa fw_drain_txq(fc); 2042170374Ssimokawa fw_sidrcv(fc, buf, plen); 2043170374Ssimokawa free(buf, M_FW); 2044170374Ssimokawa} 2045170374Ssimokawa 2046170374Ssimokawastatic void 2047170374Ssimokawafwohci_task_dma(void *arg, int pending) 2048170374Ssimokawa{ 2049170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2050129585Sdfr uint32_t stat; 2051113584Ssimokawa 2052113584Ssimokawaagain: 2053113584Ssimokawa stat = atomic_readandclear_int(&sc->intstat); 2054113584Ssimokawa if (stat) 2055170374Ssimokawa fwohci_intr_dma(sc, stat, -1); 2056113584Ssimokawa else 2057113584Ssimokawa return; 2058113584Ssimokawa goto again; 2059113584Ssimokawa} 2060113584Ssimokawa 2061170374Ssimokawastatic int 2062170374Ssimokawafwohci_check_stat(struct fwohci_softc *sc) 2063113584Ssimokawa{ 2064129585Sdfr uint32_t stat, irstat, itstat; 2065113584Ssimokawa 2066187993Ssbruno FW_GLOCK_ASSERT(&sc->fc); 2067113584Ssimokawa stat = OREAD(sc, FWOHCI_INTSTAT); 2068113584Ssimokawa if (stat == 0xffffffff) { 2069223353Simp if (!bus_child_present(sc->fc.dev)) 2070223353Simp return (FILTER_HANDLED); 2071223353Simp device_printf(sc->fc.dev, "device physically ejected?\n"); 2072170374Ssimokawa return (FILTER_STRAY); 2073113584Ssimokawa } 2074113584Ssimokawa if (stat) 2075170374Ssimokawa OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R); 2076170374Ssimokawa 2077170374Ssimokawa stat &= sc->intmask; 2078170374Ssimokawa if (stat == 0) 2079170374Ssimokawa return (FILTER_STRAY); 2080170374Ssimokawa 2081170374Ssimokawa atomic_set_int(&sc->intstat, stat); 2082113584Ssimokawa if (stat & OHCI_INT_DMA_IR) { 2083113584Ssimokawa irstat = OREAD(sc, OHCI_IR_STAT); 2084113584Ssimokawa OWRITE(sc, OHCI_IR_STATCLR, irstat); 2085113584Ssimokawa atomic_set_int(&sc->irstat, irstat); 2086113584Ssimokawa } 2087113584Ssimokawa if (stat & OHCI_INT_DMA_IT) { 2088113584Ssimokawa itstat = OREAD(sc, OHCI_IT_STAT); 2089113584Ssimokawa OWRITE(sc, OHCI_IT_STATCLR, itstat); 2090113584Ssimokawa atomic_set_int(&sc->itstat, itstat); 2091113584Ssimokawa } 2092170374Ssimokawa 2093170374Ssimokawa fwohci_intr_core(sc, stat, -1); 2094170374Ssimokawa return (FILTER_HANDLED); 2095113584Ssimokawa} 2096113584Ssimokawa 2097187993Ssbrunovoid 2098187993Ssbrunofwohci_intr(void *arg) 2099103285Sikob{ 2100103285Sikob struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2101103285Sikob 2102187993Ssbruno FW_GLOCK(&sc->fc); 2103187993Ssbruno fwohci_check_stat(sc); 2104187993Ssbruno FW_GUNLOCK(&sc->fc); 2105170374Ssimokawa} 2106103285Sikob 2107170374Ssimokawavoid 2108103285Sikobfwohci_poll(struct firewire_comm *fc, int quick, int count) 2109103285Sikob{ 2110170374Ssimokawa struct fwohci_softc *sc = (struct fwohci_softc *)fc; 2111187993Ssbruno 2112187993Ssbruno FW_GLOCK(fc); 2113170374Ssimokawa fwohci_check_stat(sc); 2114187993Ssbruno FW_GUNLOCK(fc); 2115103285Sikob} 2116103285Sikob 2117103285Sikobstatic void 2118103285Sikobfwohci_set_intr(struct firewire_comm *fc, int enable) 2119103285Sikob{ 2120103285Sikob struct fwohci_softc *sc; 2121103285Sikob 2122103285Sikob sc = (struct fwohci_softc *)fc; 2123132432Ssimokawa if (firewire_debug) 2124108642Ssimokawa device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable); 2125103285Sikob if (enable) { 2126103285Sikob sc->intmask |= OHCI_INT_EN; 2127103285Sikob OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); 2128103285Sikob } else { 2129103285Sikob sc->intmask &= ~OHCI_INT_EN; 2130103285Sikob OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); 2131103285Sikob } 2132103285Sikob} 2133103285Sikob 2134106790Ssimokawastatic void 2135106790Ssimokawafwohci_tbuf_update(struct fwohci_softc *sc, int dmach) 2136103285Sikob{ 2137103285Sikob struct firewire_comm *fc = &sc->fc; 2138120660Ssimokawa struct fwohcidb *db; 2139109890Ssimokawa struct fw_bulkxfer *chunk; 2140109890Ssimokawa struct fw_xferq *it; 2141129585Sdfr uint32_t stat, count; 2142113584Ssimokawa int s, w=0, ldesc; 2143103285Sikob 2144109890Ssimokawa it = fc->it[dmach]; 2145113584Ssimokawa ldesc = sc->it[dmach].ndesc - 1; 2146109890Ssimokawa s = splfw(); /* unnecessary ? */ 2147170374Ssimokawa FW_GLOCK(fc); 2148113584Ssimokawa fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); 2149119155Ssimokawa if (firewire_debug) 2150119155Ssimokawa dump_db(sc, ITX_CH + dmach); 2151109890Ssimokawa while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { 2152109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->end))->db; 2153272214Skan stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2154113584Ssimokawa >> OHCI_STATUS_SHIFT; 2155109890Ssimokawa db = ((struct fwohcidb_tr *)(chunk->start))->db; 2156119155Ssimokawa /* timestamp */ 2157113584Ssimokawa count = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2158113584Ssimokawa & OHCI_COUNT_MASK; 2159109890Ssimokawa if (stat == 0) 2160109890Ssimokawa break; 2161109890Ssimokawa STAILQ_REMOVE_HEAD(&it->stdma, link); 2162272214Skan switch (stat & FWOHCIEV_MASK) { 2163109890Ssimokawa case FWOHCIEV_ACKCOMPL: 2164109890Ssimokawa#if 0 2165109890Ssimokawa device_printf(fc->dev, "0x%08x\n", count); 2166109179Ssimokawa#endif 2167109890Ssimokawa break; 2168109890Ssimokawa default: 2169109423Ssimokawa device_printf(fc->dev, 2170113584Ssimokawa "Isochronous transmit err %02x(%s)\n", 2171113584Ssimokawa stat, fwohcicode[stat & 0x1f]); 2172109890Ssimokawa } 2173109890Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, chunk, link); 2174109890Ssimokawa w++; 2175109403Ssimokawa } 2176170374Ssimokawa FW_GUNLOCK(fc); 2177109890Ssimokawa splx(s); 2178109890Ssimokawa if (w) 2179109890Ssimokawa wakeup(it); 2180103285Sikob} 2181106790Ssimokawa 2182106790Ssimokawastatic void 2183106790Ssimokawafwohci_rbuf_update(struct fwohci_softc *sc, int dmach) 2184103285Sikob{ 2185109179Ssimokawa struct firewire_comm *fc = &sc->fc; 2186120660Ssimokawa struct fwohcidb_tr *db_tr; 2187109890Ssimokawa struct fw_bulkxfer *chunk; 2188109890Ssimokawa struct fw_xferq *ir; 2189129585Sdfr uint32_t stat; 2190277511Swill int w = 0, ldesc; 2191109179Ssimokawa 2192109890Ssimokawa ir = fc->ir[dmach]; 2193113584Ssimokawa ldesc = sc->ir[dmach].ndesc - 1; 2194170374Ssimokawa 2195113584Ssimokawa#if 0 2196113584Ssimokawa dump_db(sc, dmach); 2197113584Ssimokawa#endif 2198170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 2199170374Ssimokawa FW_GLOCK(fc); 2200113584Ssimokawa fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); 2201109890Ssimokawa while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 2202113584Ssimokawa db_tr = (struct fwohcidb_tr *)chunk->end; 2203113584Ssimokawa stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) 2204113584Ssimokawa >> OHCI_STATUS_SHIFT; 2205109890Ssimokawa if (stat == 0) 2206109890Ssimokawa break; 2207113584Ssimokawa 2208113584Ssimokawa if (chunk->mbuf != NULL) { 2209113584Ssimokawa bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map, 2210113584Ssimokawa BUS_DMASYNC_POSTREAD); 2211113584Ssimokawa bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map); 2212113584Ssimokawa } else if (ir->buf != NULL) { 2213113584Ssimokawa fwdma_sync_multiseg(ir->buf, chunk->poffset, 2214113584Ssimokawa ir->bnpacket, BUS_DMASYNC_POSTREAD); 2215113584Ssimokawa } else { 2216113584Ssimokawa /* XXX */ 2217298955Spfg printf("fwohci_rbuf_update: this shouldn't happened\n"); 2218113584Ssimokawa } 2219113584Ssimokawa 2220109890Ssimokawa STAILQ_REMOVE_HEAD(&ir->stdma, link); 2221109890Ssimokawa STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); 2222109890Ssimokawa switch (stat & FWOHCIEV_MASK) { 2223109890Ssimokawa case FWOHCIEV_ACKCOMPL: 2224111942Ssimokawa chunk->resp = 0; 2225109890Ssimokawa break; 2226109890Ssimokawa default: 2227111942Ssimokawa chunk->resp = EINVAL; 2228109890Ssimokawa device_printf(fc->dev, 2229113584Ssimokawa "Isochronous receive err %02x(%s)\n", 2230113584Ssimokawa stat, fwohcicode[stat & 0x1f]); 2231109890Ssimokawa } 2232109890Ssimokawa w++; 2233103285Sikob } 2234170374Ssimokawa if ((ir->flag & FWXFERQ_HANDLER) == 0) 2235170374Ssimokawa FW_GUNLOCK(fc); 2236170374Ssimokawa if (w == 0) 2237170374Ssimokawa return; 2238170374Ssimokawa 2239272214Skan if (ir->flag & FWXFERQ_HANDLER) 2240170374Ssimokawa ir->hand(ir); 2241170374Ssimokawa else 2242170374Ssimokawa wakeup(ir); 2243103285Sikob} 2244106790Ssimokawa 2245106790Ssimokawavoid 2246129585Sdfrdump_dma(struct fwohci_softc *sc, uint32_t ch) 2247106790Ssimokawa{ 2248129585Sdfr uint32_t off, cntl, stat, cmd, match; 2249103285Sikob 2250272214Skan if (ch == 0) { 2251103285Sikob off = OHCI_ATQOFF; 2252272214Skan } else if (ch == 1) { 2253103285Sikob off = OHCI_ATSOFF; 2254272214Skan } else if (ch == 2) { 2255103285Sikob off = OHCI_ARQOFF; 2256272214Skan } else if (ch == 3) { 2257103285Sikob off = OHCI_ARSOFF; 2258272214Skan } else if (ch < IRX_CH) { 2259103285Sikob off = OHCI_ITCTL(ch - ITX_CH); 2260272214Skan } else { 2261103285Sikob off = OHCI_IRCTL(ch - IRX_CH); 2262103285Sikob } 2263103285Sikob cntl = stat = OREAD(sc, off); 2264103285Sikob cmd = OREAD(sc, off + 0xc); 2265103285Sikob match = OREAD(sc, off + 0x10); 2266103285Sikob 2267113584Ssimokawa device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n", 2268103285Sikob ch, 2269272214Skan cntl, 2270272214Skan cmd, 2271103285Sikob match); 2272272214Skan stat &= 0xffff; 2273113584Ssimokawa if (stat) { 2274103285Sikob device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", 2275103285Sikob ch, 2276103285Sikob stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2277103285Sikob stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2278103285Sikob stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2279103285Sikob stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2280103285Sikob stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2281103285Sikob stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2282103285Sikob fwohcicode[stat & 0x1f], 2283103285Sikob stat & 0x1f 2284103285Sikob ); 2285272214Skan } else { 2286103285Sikob device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); 2287103285Sikob } 2288103285Sikob} 2289106790Ssimokawa 2290106790Ssimokawavoid 2291129585Sdfrdump_db(struct fwohci_softc *sc, uint32_t ch) 2292106790Ssimokawa{ 2293103285Sikob struct fwohci_dbch *dbch; 2294113584Ssimokawa struct fwohcidb_tr *cp = NULL, *pp, *np = NULL; 2295120660Ssimokawa struct fwohcidb *curr = NULL, *prev, *next = NULL; 2296103285Sikob int idb, jdb; 2297129585Sdfr uint32_t cmd, off; 2298272214Skan 2299272214Skan if (ch == 0) { 2300103285Sikob off = OHCI_ATQOFF; 2301103285Sikob dbch = &sc->atrq; 2302272214Skan } else if (ch == 1) { 2303103285Sikob off = OHCI_ATSOFF; 2304103285Sikob dbch = &sc->atrs; 2305272214Skan } else if (ch == 2) { 2306103285Sikob off = OHCI_ARQOFF; 2307103285Sikob dbch = &sc->arrq; 2308272214Skan } else if (ch == 3) { 2309103285Sikob off = OHCI_ARSOFF; 2310103285Sikob dbch = &sc->arrs; 2311272214Skan } else if (ch < IRX_CH) { 2312103285Sikob off = OHCI_ITCTL(ch - ITX_CH); 2313103285Sikob dbch = &sc->it[ch - ITX_CH]; 2314272214Skan } else { 2315103285Sikob off = OHCI_IRCTL(ch - IRX_CH); 2316103285Sikob dbch = &sc->ir[ch - IRX_CH]; 2317103285Sikob } 2318103285Sikob cmd = OREAD(sc, off + 0xc); 2319103285Sikob 2320272214Skan if (dbch->ndb == 0) { 2321103285Sikob device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); 2322103285Sikob return; 2323103285Sikob } 2324103285Sikob pp = dbch->top; 2325103285Sikob prev = pp->db; 2326272214Skan for (idb = 0; idb < dbch->ndb; idb++) { 2327103285Sikob cp = STAILQ_NEXT(pp, link); 2328272214Skan if (cp == NULL) { 2329103285Sikob curr = NULL; 2330103285Sikob goto outdb; 2331103285Sikob } 2332103285Sikob np = STAILQ_NEXT(cp, link); 2333272214Skan for (jdb = 0; jdb < dbch->ndesc; jdb++) { 2334113584Ssimokawa if ((cmd & 0xfffffff0) == cp->bus_addr) { 2335103285Sikob curr = cp->db; 2336272214Skan if (np != NULL) { 2337103285Sikob next = np->db; 2338272214Skan } else { 2339103285Sikob next = NULL; 2340103285Sikob } 2341103285Sikob goto outdb; 2342103285Sikob } 2343103285Sikob } 2344103285Sikob pp = STAILQ_NEXT(pp, link); 2345272214Skan if (pp == NULL) { 2346144263Ssam curr = NULL; 2347144263Ssam goto outdb; 2348144263Ssam } 2349103285Sikob prev = pp->db; 2350103285Sikob } 2351103285Sikoboutdb: 2352272214Skan if (curr != NULL) { 2353113584Ssimokawa#if 0 2354103285Sikob printf("Prev DB %d\n", ch); 2355113584Ssimokawa print_db(pp, prev, ch, dbch->ndesc); 2356113584Ssimokawa#endif 2357103285Sikob printf("Current DB %d\n", ch); 2358113584Ssimokawa print_db(cp, curr, ch, dbch->ndesc); 2359113584Ssimokawa#if 0 2360103285Sikob printf("Next DB %d\n", ch); 2361113584Ssimokawa print_db(np, next, ch, dbch->ndesc); 2362113584Ssimokawa#endif 2363272214Skan } else { 2364103285Sikob printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); 2365103285Sikob } 2366103285Sikob return; 2367103285Sikob} 2368106790Ssimokawa 2369106790Ssimokawavoid 2370120660Ssimokawaprint_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db, 2371129585Sdfr uint32_t ch, uint32_t max) 2372106790Ssimokawa{ 2373103285Sikob fwohcireg_t stat; 2374103285Sikob int i, key; 2375129585Sdfr uint32_t cmd, res; 2376103285Sikob 2377272214Skan if (db == NULL) { 2378103285Sikob printf("No Descriptor is found\n"); 2379103285Sikob return; 2380103285Sikob } 2381103285Sikob 2382103285Sikob printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", 2383103285Sikob ch, 2384103285Sikob "Current", 2385103285Sikob "OP ", 2386103285Sikob "KEY", 2387103285Sikob "INT", 2388103285Sikob "BR ", 2389103285Sikob "len", 2390103285Sikob "Addr", 2391103285Sikob "Depend", 2392103285Sikob "Stat", 2393103285Sikob "Cnt"); 2394272214Skan for (i = 0; i <= max; i++) { 2395113584Ssimokawa cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd); 2396113584Ssimokawa res = FWOHCI_DMA_READ(db[i].db.desc.res); 2397113584Ssimokawa key = cmd & OHCI_KEY_MASK; 2398113584Ssimokawa stat = res >> OHCI_STATUS_SHIFT; 2399113972Ssimokawa printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x", 2400114142Ssimokawa (uintmax_t)db_tr->bus_addr, 2401113584Ssimokawa dbcode[(cmd >> 28) & 0xf], 2402113584Ssimokawa dbkey[(cmd >> 24) & 0x7], 2403113584Ssimokawa dbcond[(cmd >> 20) & 0x3], 2404113584Ssimokawa dbcond[(cmd >> 18) & 0x3], 2405113584Ssimokawa cmd & OHCI_COUNT_MASK, 2406113584Ssimokawa FWOHCI_DMA_READ(db[i].db.desc.addr), 2407113584Ssimokawa FWOHCI_DMA_READ(db[i].db.desc.depend), 2408113584Ssimokawa stat, 2409113584Ssimokawa res & OHCI_COUNT_MASK); 2410272214Skan if (stat & 0xff00) { 2411103285Sikob printf(" %s%s%s%s%s%s %s(%x)\n", 2412103285Sikob stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2413103285Sikob stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2414103285Sikob stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2415103285Sikob stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2416103285Sikob stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2417103285Sikob stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2418103285Sikob fwohcicode[stat & 0x1f], 2419103285Sikob stat & 0x1f 2420103285Sikob ); 2421272214Skan } else { 2422103285Sikob printf(" Nostat\n"); 2423103285Sikob } 2424272214Skan if (key == OHCI_KEY_ST2) { 2425272214Skan printf("0x%08x 0x%08x 0x%08x 0x%08x\n", 2426272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[0]), 2427272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[1]), 2428272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[2]), 2429272214Skan FWOHCI_DMA_READ(db[i + 1].db.immed[3])); 2430103285Sikob } 2431272214Skan if (key == OHCI_KEY_DEVICE) { 2432103285Sikob return; 2433103285Sikob } 2434272214Skan if ((cmd & OHCI_BRANCH_MASK) 2435272214Skan == OHCI_BRANCH_ALWAYS) { 2436103285Sikob return; 2437103285Sikob } 2438272214Skan if ((cmd & OHCI_CMD_MASK) 2439272214Skan == OHCI_OUTPUT_LAST) { 2440103285Sikob return; 2441103285Sikob } 2442272214Skan if ((cmd & OHCI_CMD_MASK) 2443272214Skan == OHCI_INPUT_LAST) { 2444103285Sikob return; 2445103285Sikob } 2446272214Skan if (key == OHCI_KEY_ST2) { 2447103285Sikob i++; 2448103285Sikob } 2449103285Sikob } 2450103285Sikob return; 2451103285Sikob} 2452106790Ssimokawa 2453106790Ssimokawavoid 2454106790Ssimokawafwohci_ibr(struct firewire_comm *fc) 2455103285Sikob{ 2456103285Sikob struct fwohci_softc *sc; 2457129585Sdfr uint32_t fun; 2458103285Sikob 2459110577Ssimokawa device_printf(fc->dev, "Initiate bus reset\n"); 2460103285Sikob sc = (struct fwohci_softc *)fc; 2461108276Ssimokawa 2462187993Ssbruno FW_GLOCK(fc); 2463108276Ssimokawa /* 2464129611Sdfr * Make sure our cached values from the config rom are 2465129611Sdfr * initialised. 2466129611Sdfr */ 2467129611Sdfr OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 2468129611Sdfr OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 2469129611Sdfr 2470129611Sdfr /* 2471108276Ssimokawa * Set root hold-off bit so that non cyclemaster capable node 2472108276Ssimokawa * shouldn't became the root node. 2473108276Ssimokawa */ 2474103285Sikob#if 1 2475103285Sikob fun = fwphy_rddata(sc, FW_PHY_IBR_REG); 2476109280Ssimokawa fun |= FW_PHY_IBR | FW_PHY_RHB; 2477103285Sikob fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); 2478109280Ssimokawa#else /* Short bus reset */ 2479103285Sikob fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); 2480109280Ssimokawa fun |= FW_PHY_ISBR | FW_PHY_RHB; 2481103285Sikob fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); 2482103285Sikob#endif 2483187993Ssbruno FW_GUNLOCK(fc); 2484103285Sikob} 2485106790Ssimokawa 2486106790Ssimokawavoid 2487106790Ssimokawafwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 2488103285Sikob{ 2489103285Sikob struct fwohcidb_tr *db_tr, *fdb_tr; 2490103285Sikob struct fwohci_dbch *dbch; 2491120660Ssimokawa struct fwohcidb *db; 2492103285Sikob struct fw_pkt *fp; 2493120660Ssimokawa struct fwohci_txpkthdr *ohcifp; 2494103285Sikob unsigned short chtag; 2495103285Sikob int idb; 2496103285Sikob 2497170374Ssimokawa FW_GLOCK_ASSERT(&sc->fc); 2498170374Ssimokawa 2499103285Sikob dbch = &sc->it[dmach]; 2500103285Sikob chtag = sc->it[dmach].xferq.flag & 0xff; 2501103285Sikob 2502103285Sikob db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 2503103285Sikob fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 2504103285Sikob/* 2505113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr); 2506103285Sikob*/ 2507272214Skan for (idb = 0; idb < dbch->xferq.bnpacket; idb++) { 2508109892Ssimokawa db = db_tr->db; 2509103285Sikob fp = (struct fw_pkt *)db_tr->buf; 2510120660Ssimokawa ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed; 2511113584Ssimokawa ohcifp->mode.ld[0] = fp->mode.ld[0]; 2512119155Ssimokawa ohcifp->mode.common.spd = 0 & 0x7; 2513113584Ssimokawa ohcifp->mode.stream.len = fp->mode.stream.len; 2514103285Sikob ohcifp->mode.stream.chtag = chtag; 2515103285Sikob ohcifp->mode.stream.tcode = 0xa; 2516113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2517272214Skan FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]); 2518272214Skan FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]); 2519113584Ssimokawa#endif 2520103285Sikob 2521113584Ssimokawa FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK); 2522113584Ssimokawa FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len); 2523113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2524109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */ 2525113584Ssimokawa db[2].db.desc.cmd = OHCI_OUTPUT_LAST 2526103285Sikob | OHCI_UPDATE 2527109892Ssimokawa | OHCI_BRANCH_ALWAYS; 2528109892Ssimokawa db[0].db.desc.depend = 2529109892Ssimokawa = db[dbch->ndesc - 1].db.desc.depend 2530113584Ssimokawa = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc; 2531109892Ssimokawa#else 2532113584Ssimokawa FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 2533113584Ssimokawa FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc); 2534109892Ssimokawa#endif 2535103285Sikob bulkxfer->end = (caddr_t)db_tr; 2536103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 2537103285Sikob } 2538109892Ssimokawa db = ((struct fwohcidb_tr *)bulkxfer->end)->db; 2539113584Ssimokawa FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf); 2540113584Ssimokawa FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf); 2541109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */ 2542109892Ssimokawa db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2543109280Ssimokawa /* OHCI 1.1 and above */ 2544109892Ssimokawa db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2545109892Ssimokawa#endif 2546109892Ssimokawa/* 2547103285Sikob db_tr = (struct fwohcidb_tr *)bulkxfer->start; 2548103285Sikob fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; 2549113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr); 2550103285Sikob*/ 2551103285Sikob return; 2552103285Sikob} 2553106790Ssimokawa 2554106790Ssimokawastatic int 2555113584Ssimokawafwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2556113584Ssimokawa int poffset) 2557103285Sikob{ 2558120660Ssimokawa struct fwohcidb *db = db_tr->db; 2559113584Ssimokawa struct fw_xferq *it; 2560103285Sikob int err = 0; 2561113584Ssimokawa 2562113584Ssimokawa it = &dbch->xferq; 2563272214Skan if (it->buf == 0) { 2564103285Sikob err = EINVAL; 2565103285Sikob return err; 2566103285Sikob } 2567113584Ssimokawa db_tr->buf = fwdma_v_addr(it->buf, poffset); 2568103285Sikob db_tr->dbcnt = 3; 2569103285Sikob 2570113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.cmd, 2571113584Ssimokawa OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8); 2572119155Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0); 2573120660Ssimokawa bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed)); 2574113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.addr, 2575129585Sdfr fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t)); 2576113584Ssimokawa 2577113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.cmd, 2578113584Ssimokawa OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS); 2579109892Ssimokawa#if 1 2580113584Ssimokawa FWOHCI_DMA_WRITE(db[0].db.desc.res, 0); 2581113584Ssimokawa FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2582109892Ssimokawa#endif 2583113584Ssimokawa return 0; 2584103285Sikob} 2585106790Ssimokawa 2586106790Ssimokawaint 2587113584Ssimokawafwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2588113584Ssimokawa int poffset, struct fwdma_alloc *dummy_dma) 2589103285Sikob{ 2590120660Ssimokawa struct fwohcidb *db = db_tr->db; 2591113584Ssimokawa struct fw_xferq *ir; 2592113584Ssimokawa int i, ldesc; 2593113584Ssimokawa bus_addr_t dbuf[2]; 2594103285Sikob int dsiz[2]; 2595103285Sikob 2596113584Ssimokawa ir = &dbch->xferq; 2597113584Ssimokawa if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) { 2598178911Ssimokawa if (db_tr->buf == NULL) { 2599178911Ssimokawa db_tr->buf = fwdma_malloc_size(dbch->dmat, 2600178911Ssimokawa &db_tr->dma_map, ir->psize, &dbuf[0], 2601178911Ssimokawa BUS_DMA_NOWAIT); 2602178911Ssimokawa if (db_tr->buf == NULL) 2603272214Skan return (ENOMEM); 2604178911Ssimokawa } 2605103285Sikob db_tr->dbcnt = 1; 2606113584Ssimokawa dsiz[0] = ir->psize; 2607113584Ssimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2608113584Ssimokawa BUS_DMASYNC_PREREAD); 2609113584Ssimokawa } else { 2610113584Ssimokawa db_tr->dbcnt = 0; 2611113584Ssimokawa if (dummy_dma != NULL) { 2612129585Sdfr dsiz[db_tr->dbcnt] = sizeof(uint32_t); 2613113584Ssimokawa dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr; 2614113584Ssimokawa } 2615113584Ssimokawa dsiz[db_tr->dbcnt] = ir->psize; 2616113584Ssimokawa if (ir->buf != NULL) { 2617113584Ssimokawa db_tr->buf = fwdma_v_addr(ir->buf, poffset); 2618272214Skan dbuf[db_tr->dbcnt] = fwdma_bus_addr(ir->buf, poffset); 2619113584Ssimokawa } 2620113584Ssimokawa db_tr->dbcnt++; 2621103285Sikob } 2622272214Skan for (i = 0; i < db_tr->dbcnt; i++) { 2623113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]); 2624113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]); 2625113584Ssimokawa if (ir->flag & FWXFERQ_STREAM) { 2626113584Ssimokawa FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE); 2627103285Sikob } 2628113584Ssimokawa FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]); 2629103285Sikob } 2630113584Ssimokawa ldesc = db_tr->dbcnt - 1; 2631113584Ssimokawa if (ir->flag & FWXFERQ_STREAM) { 2632113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST); 2633103285Sikob } 2634113584Ssimokawa FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS); 2635113584Ssimokawa return 0; 2636103285Sikob} 2637106790Ssimokawa 2638113584Ssimokawa 2639113584Ssimokawastatic int 2640113584Ssimokawafwohci_arcv_swap(struct fw_pkt *fp, int len) 2641103285Sikob{ 2642113584Ssimokawa struct fw_pkt *fp0; 2643129585Sdfr uint32_t ld0; 2644120660Ssimokawa int slen, hlen; 2645113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2646113584Ssimokawa int i; 2647113584Ssimokawa#endif 2648103285Sikob 2649113584Ssimokawa ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]); 2650113584Ssimokawa#if 0 2651113584Ssimokawa printf("ld0: x%08x\n", ld0); 2652113584Ssimokawa#endif 2653113584Ssimokawa fp0 = (struct fw_pkt *)&ld0; 2654120660Ssimokawa /* determine length to swap */ 2655113584Ssimokawa switch (fp0->mode.common.tcode) { 2656113584Ssimokawa case FWTCODE_RREQQ: 2657113584Ssimokawa case FWTCODE_WRES: 2658113584Ssimokawa case FWTCODE_WREQQ: 2659113584Ssimokawa case FWTCODE_RRESQ: 2660113584Ssimokawa case FWOHCITCODE_PHY: 2661113584Ssimokawa slen = 12; 2662113584Ssimokawa break; 2663113584Ssimokawa case FWTCODE_RREQB: 2664113584Ssimokawa case FWTCODE_WREQB: 2665113584Ssimokawa case FWTCODE_LREQ: 2666113584Ssimokawa case FWTCODE_RRESB: 2667113584Ssimokawa case FWTCODE_LRES: 2668113584Ssimokawa slen = 16; 2669113584Ssimokawa break; 2670113584Ssimokawa default: 2671113584Ssimokawa printf("Unknown tcode %d\n", fp0->mode.common.tcode); 2672272214Skan return (0); 2673103285Sikob } 2674120660Ssimokawa hlen = tinfo[fp0->mode.common.tcode].hdr_len; 2675120660Ssimokawa if (hlen > len) { 2676113584Ssimokawa if (firewire_debug) 2677113584Ssimokawa printf("splitted header\n"); 2678272214Skan return (-hlen); 2679103285Sikob } 2680113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 2681272214Skan for (i = 0; i < slen/4; i++) 2682113584Ssimokawa fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]); 2683113584Ssimokawa#endif 2684272214Skan return (hlen); 2685103285Sikob} 2686103285Sikob 2687103285Sikobstatic int 2688113584Ssimokawafwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp) 2689103285Sikob{ 2690120660Ssimokawa struct tcode_info *info; 2691113584Ssimokawa int r; 2692103285Sikob 2693120660Ssimokawa info = &tinfo[fp->mode.common.tcode]; 2694129585Sdfr r = info->hdr_len + sizeof(uint32_t); 2695120660Ssimokawa if ((info->flag & FWTI_BLOCK_ASY) != 0) 2696129585Sdfr r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t)); 2697120660Ssimokawa 2698169132Ssimokawa if (r == sizeof(uint32_t)) { 2699120660Ssimokawa /* XXX */ 2700110798Ssimokawa device_printf(sc->fc.dev, "Unknown tcode %d\n", 2701110798Ssimokawa fp->mode.common.tcode); 2702169132Ssimokawa return (-1); 2703169132Ssimokawa } 2704120660Ssimokawa 2705110798Ssimokawa if (r > dbch->xferq.psize) { 2706110798Ssimokawa device_printf(sc->fc.dev, "Invalid packet length %d\n", r); 2707169132Ssimokawa return (-1); 2708110798Ssimokawa /* panic ? */ 2709110798Ssimokawa } 2710120660Ssimokawa 2711110798Ssimokawa return r; 2712103285Sikob} 2713103285Sikob 2714106790Ssimokawastatic void 2715169132Ssimokawafwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch, 2716169132Ssimokawa struct fwohcidb_tr *db_tr, uint32_t off, int wake) 2717113584Ssimokawa{ 2718120660Ssimokawa struct fwohcidb *db = &db_tr->db[0]; 2719113584Ssimokawa 2720113584Ssimokawa FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf); 2721113584Ssimokawa FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize); 2722113584Ssimokawa FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1); 2723113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 2724113584Ssimokawa dbch->bottom = db_tr; 2725169132Ssimokawa 2726169132Ssimokawa if (wake) 2727169132Ssimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 2728113584Ssimokawa} 2729113584Ssimokawa 2730113584Ssimokawastatic void 2731106790Ssimokawafwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 2732103285Sikob{ 2733103285Sikob struct fwohcidb_tr *db_tr; 2734113584Ssimokawa struct iovec vec[2]; 2735113584Ssimokawa struct fw_pkt pktbuf; 2736113584Ssimokawa int nvec; 2737103285Sikob struct fw_pkt *fp; 2738129585Sdfr uint8_t *ld; 2739169132Ssimokawa uint32_t stat, off, status, event; 2740103285Sikob u_int spd; 2741113584Ssimokawa int len, plen, hlen, pcnt, offset; 2742103285Sikob int s; 2743103285Sikob caddr_t buf; 2744103285Sikob int resCount; 2745103285Sikob 2746272214Skan if (&sc->arrq == dbch) { 2747103285Sikob off = OHCI_ARQOFF; 2748272214Skan } else if (&sc->arrs == dbch) { 2749103285Sikob off = OHCI_ARSOFF; 2750272214Skan } else { 2751103285Sikob return; 2752103285Sikob } 2753103285Sikob 2754103285Sikob s = splfw(); 2755103285Sikob db_tr = dbch->top; 2756103285Sikob pcnt = 0; 2757103285Sikob /* XXX we cannot handle a packet which lies in more than two buf */ 2758113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 2759113584Ssimokawa fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 2760113584Ssimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT; 2761113584Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK; 2762169132Ssimokawa while (status & OHCI_CNTL_DMA_ACTIVE) { 2763113584Ssimokawa#if 0 2764169132Ssimokawa 2765169132Ssimokawa if (off == OHCI_ARQOFF) 2766169132Ssimokawa printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n", 2767169132Ssimokawa db_tr->bus_addr, status, resCount); 2768113584Ssimokawa#endif 2769113584Ssimokawa len = dbch->xferq.psize - resCount; 2770129585Sdfr ld = (uint8_t *)db_tr->buf; 2771113584Ssimokawa if (dbch->pdb_tr == NULL) { 2772113584Ssimokawa len -= dbch->buf_offset; 2773113584Ssimokawa ld += dbch->buf_offset; 2774113584Ssimokawa } 2775113584Ssimokawa if (len > 0) 2776113584Ssimokawa bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2777113584Ssimokawa BUS_DMASYNC_POSTREAD); 2778272214Skan while (len > 0) { 2779106789Ssimokawa if (count >= 0 && count-- == 0) 2780106789Ssimokawa goto out; 2781272214Skan if (dbch->pdb_tr != NULL) { 2782113584Ssimokawa /* we have a fragment in previous buffer */ 2783113584Ssimokawa int rlen; 2784103285Sikob 2785113584Ssimokawa offset = dbch->buf_offset; 2786113584Ssimokawa if (offset < 0) 2787113584Ssimokawa offset = - offset; 2788113584Ssimokawa buf = dbch->pdb_tr->buf + offset; 2789113584Ssimokawa rlen = dbch->xferq.psize - offset; 2790113584Ssimokawa if (firewire_debug) 2791113584Ssimokawa printf("rlen=%d, offset=%d\n", 2792113584Ssimokawa rlen, dbch->buf_offset); 2793113584Ssimokawa if (dbch->buf_offset < 0) { 2794113584Ssimokawa /* splitted in header, pull up */ 2795113584Ssimokawa char *p; 2796113584Ssimokawa 2797113584Ssimokawa p = (char *)&pktbuf; 2798113584Ssimokawa bcopy(buf, p, rlen); 2799113584Ssimokawa p += rlen; 2800113584Ssimokawa /* this must be too long but harmless */ 2801113584Ssimokawa rlen = sizeof(pktbuf) - rlen; 2802113584Ssimokawa if (rlen < 0) 2803113584Ssimokawa printf("why rlen < 0\n"); 2804113584Ssimokawa bcopy(db_tr->buf, p, rlen); 2805103285Sikob ld += rlen; 2806103285Sikob len -= rlen; 2807113584Ssimokawa hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf)); 2808169132Ssimokawa if (hlen <= 0) { 2809169132Ssimokawa printf("hlen should be positive."); 2810169132Ssimokawa goto err; 2811113584Ssimokawa } 2812113584Ssimokawa offset = sizeof(pktbuf); 2813113584Ssimokawa vec[0].iov_base = (char *)&pktbuf; 2814113584Ssimokawa vec[0].iov_len = offset; 2815113584Ssimokawa } else { 2816113584Ssimokawa /* splitted in payload */ 2817113584Ssimokawa offset = rlen; 2818113584Ssimokawa vec[0].iov_base = buf; 2819113584Ssimokawa vec[0].iov_len = rlen; 2820103285Sikob } 2821113584Ssimokawa fp=(struct fw_pkt *)vec[0].iov_base; 2822113584Ssimokawa nvec = 1; 2823113584Ssimokawa } else { 2824113584Ssimokawa /* no fragment in previous buffer */ 2825103285Sikob fp=(struct fw_pkt *)ld; 2826113584Ssimokawa hlen = fwohci_arcv_swap(fp, len); 2827113584Ssimokawa if (hlen == 0) 2828169132Ssimokawa goto err; 2829113584Ssimokawa if (hlen < 0) { 2830113584Ssimokawa dbch->pdb_tr = db_tr; 2831113584Ssimokawa dbch->buf_offset = - dbch->buf_offset; 2832113584Ssimokawa /* sanity check */ 2833272214Skan if (resCount != 0) { 2834169132Ssimokawa printf("resCount=%d hlen=%d\n", 2835169132Ssimokawa resCount, hlen); 2836169132Ssimokawa goto err; 2837169132Ssimokawa } 2838113584Ssimokawa goto out; 2839103285Sikob } 2840113584Ssimokawa offset = 0; 2841113584Ssimokawa nvec = 0; 2842113584Ssimokawa } 2843113584Ssimokawa plen = fwohci_get_plen(sc, dbch, fp) - offset; 2844113584Ssimokawa if (plen < 0) { 2845113584Ssimokawa /* minimum header size + trailer 2846113584Ssimokawa = sizeof(fw_pkt) so this shouldn't happens */ 2847120660Ssimokawa printf("plen(%d) is negative! offset=%d\n", 2848120660Ssimokawa plen, offset); 2849169132Ssimokawa goto err; 2850113584Ssimokawa } 2851113584Ssimokawa if (plen > 0) { 2852113584Ssimokawa len -= plen; 2853113584Ssimokawa if (len < 0) { 2854113584Ssimokawa dbch->pdb_tr = db_tr; 2855113584Ssimokawa if (firewire_debug) 2856113584Ssimokawa printf("splitted payload\n"); 2857113584Ssimokawa /* sanity check */ 2858272214Skan if (resCount != 0) { 2859169132Ssimokawa printf("resCount=%d plen=%d" 2860169132Ssimokawa " len=%d\n", 2861169132Ssimokawa resCount, plen, len); 2862169132Ssimokawa goto err; 2863169132Ssimokawa } 2864113584Ssimokawa goto out; 2865103285Sikob } 2866113584Ssimokawa vec[nvec].iov_base = ld; 2867113584Ssimokawa vec[nvec].iov_len = plen; 2868272214Skan nvec++; 2869103285Sikob ld += plen; 2870103285Sikob } 2871129585Sdfr dbch->buf_offset = ld - (uint8_t *)db_tr->buf; 2872113584Ssimokawa if (nvec == 0) 2873113584Ssimokawa printf("nvec == 0\n"); 2874113584Ssimokawa 2875103285Sikob/* DMA result-code will be written at the tail of packet */ 2876169132Ssimokawa stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer))); 2877110577Ssimokawa#if 0 2878120660Ssimokawa printf("plen: %d, stat %x\n", 2879120660Ssimokawa plen ,stat); 2880103285Sikob#endif 2881169132Ssimokawa spd = (stat >> 21) & 0x3; 2882169132Ssimokawa event = (stat >> 16) & 0x1f; 2883169132Ssimokawa switch (event) { 2884113584Ssimokawa case FWOHCIEV_ACKPEND: 2885113584Ssimokawa#if 0 2886113584Ssimokawa printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); 2887113584Ssimokawa#endif 2888113584Ssimokawa /* fall through */ 2889113584Ssimokawa case FWOHCIEV_ACKCOMPL: 2890120660Ssimokawa { 2891120660Ssimokawa struct fw_rcv_buf rb; 2892120660Ssimokawa 2893113584Ssimokawa if ((vec[nvec-1].iov_len -= 2894113584Ssimokawa sizeof(struct fwohci_trailer)) == 0) 2895272214Skan nvec--; 2896120660Ssimokawa rb.fc = &sc->fc; 2897120660Ssimokawa rb.vec = vec; 2898120660Ssimokawa rb.nvec = nvec; 2899120660Ssimokawa rb.spd = spd; 2900120660Ssimokawa fw_rcv(&rb); 2901120660Ssimokawa break; 2902120660Ssimokawa } 2903113584Ssimokawa case FWOHCIEV_BUSRST: 2904170425Ssimokawa if ((sc->fc.status != FWBUSRESET) && 2905170425Ssimokawa (sc->fc.status != FWBUSINIT)) 2906113584Ssimokawa printf("got BUSRST packet!?\n"); 2907113584Ssimokawa break; 2908113584Ssimokawa default: 2909169132Ssimokawa device_printf(sc->fc.dev, 2910169132Ssimokawa "Async DMA Receive error err=%02x %s" 2911169132Ssimokawa " plen=%d offset=%d len=%d status=0x%08x" 2912169132Ssimokawa " tcode=0x%x, stat=0x%08x\n", 2913169132Ssimokawa event, fwohcicode[event], plen, 2914169132Ssimokawa dbch->buf_offset, len, 2915169132Ssimokawa OREAD(sc, OHCI_DMACTL(off)), 2916169132Ssimokawa fp->mode.common.tcode, stat); 2917169132Ssimokawa#if 1 /* XXX */ 2918169132Ssimokawa goto err; 2919103285Sikob#endif 2920113584Ssimokawa break; 2921103285Sikob } 2922272214Skan pcnt++; 2923113584Ssimokawa if (dbch->pdb_tr != NULL) { 2924169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr, 2925169132Ssimokawa off, 1); 2926113584Ssimokawa dbch->pdb_tr = NULL; 2927113584Ssimokawa } 2928113584Ssimokawa 2929113584Ssimokawa } 2930103285Sikobout: 2931103285Sikob if (resCount == 0) { 2932103285Sikob /* done on this buffer */ 2933113584Ssimokawa if (dbch->pdb_tr == NULL) { 2934169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1); 2935113584Ssimokawa dbch->buf_offset = 0; 2936113584Ssimokawa } else 2937113584Ssimokawa if (dbch->pdb_tr != db_tr) 2938113584Ssimokawa printf("pdb_tr != db_tr\n"); 2939103285Sikob db_tr = STAILQ_NEXT(db_tr, link); 2940113584Ssimokawa status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2941113584Ssimokawa >> OHCI_STATUS_SHIFT; 2942113584Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2943113584Ssimokawa & OHCI_COUNT_MASK; 2944113584Ssimokawa /* XXX check buffer overrun */ 2945103285Sikob dbch->top = db_tr; 2946103285Sikob } else { 2947103285Sikob dbch->buf_offset = dbch->xferq.psize - resCount; 2948103285Sikob break; 2949103285Sikob } 2950103285Sikob /* XXX make sure DMA is not dead */ 2951103285Sikob } 2952103285Sikob#if 0 2953103285Sikob if (pcnt < 1) 2954103285Sikob printf("fwohci_arcv: no packets\n"); 2955103285Sikob#endif 2956103285Sikob splx(s); 2957169132Ssimokawa return; 2958169132Ssimokawa 2959169132Ssimokawaerr: 2960169132Ssimokawa device_printf(sc->fc.dev, "AR DMA status=%x, ", 2961169132Ssimokawa OREAD(sc, OHCI_DMACTL(off))); 2962169132Ssimokawa dbch->pdb_tr = NULL; 2963169132Ssimokawa /* skip until resCount != 0 */ 2964169132Ssimokawa printf(" skip buffer"); 2965169132Ssimokawa while (resCount == 0) { 2966169132Ssimokawa printf(" #"); 2967169132Ssimokawa fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0); 2968169132Ssimokawa db_tr = STAILQ_NEXT(db_tr, link); 2969169132Ssimokawa resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2970169132Ssimokawa & OHCI_COUNT_MASK; 2971188584Ssbruno } 2972169132Ssimokawa printf(" done\n"); 2973169132Ssimokawa dbch->top = db_tr; 2974169132Ssimokawa dbch->buf_offset = dbch->xferq.psize - resCount; 2975169132Ssimokawa OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 2976169132Ssimokawa splx(s); 2977103285Sikob} 2978