fwohci.c revision 118293
1193326Sed/* 2193326Sed * Copyright (c) 2003 Hidetoshi Shimokawa 3193326Sed * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4193326Sed * All rights reserved. 5193326Sed * 6193326Sed * Redistribution and use in source and binary forms, with or without 7193326Sed * modification, are permitted provided that the following conditions 8193326Sed * are met: 9193326Sed * 1. Redistributions of source code must retain the above copyright 10221345Sdim * notice, this list of conditions and the following disclaimer. 11193326Sed * 2. Redistributions in binary form must reproduce the above copyright 12193326Sed * notice, this list of conditions and the following disclaimer in the 13193326Sed * documentation and/or other materials provided with the distribution. 14193326Sed * 3. All advertising materials mentioning features or use of this software 15193326Sed * must display the acknowledgement as bellow: 16193326Sed * 17193326Sed * This product includes software developed by K. Kobayashi and H. Shimokawa 18249423Sdim * 19249423Sdim * 4. The name of the author may not be used to endorse or promote products 20193326Sed * derived from this software without specific prior written permission. 21193326Sed * 22193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23193326Sed * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24193326Sed * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25193326Sed * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26249423Sdim * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27221345Sdim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28193326Sed * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30249423Sdim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31249423Sdim * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32249423Sdim * POSSIBILITY OF SUCH DAMAGE. 33249423Sdim * 34221345Sdim * $FreeBSD: head/sys/dev/firewire/fwohci.c 118293 2003-08-01 04:51:21Z simokawa $ 35193326Sed * 36226633Sdim */ 37193326Sed 38193326Sed#define ATRQ_CH 0 39193326Sed#define ATRS_CH 1 40193326Sed#define ARRQ_CH 2 41193326Sed#define ARRS_CH 3 42193326Sed#define ITX_CH 4 43193326Sed#define IRX_CH 0x24 44221345Sdim 45221345Sdim#include <sys/param.h> 46221345Sdim#include <sys/systm.h> 47221345Sdim#include <sys/mbuf.h> 48221345Sdim#include <sys/malloc.h> 49224145Sdim#include <sys/sockio.h> 50221345Sdim#include <sys/bus.h> 51223017Sdim#include <sys/kernel.h> 52221345Sdim#include <sys/conf.h> 53221345Sdim#include <sys/endian.h> 54221345Sdim 55221345Sdim#include <machine/bus.h> 56221345Sdim 57221345Sdim#if __FreeBSD_version < 500000 58221345Sdim#include <machine/clock.h> /* for DELAY() */ 59221345Sdim#endif 60221345Sdim 61221345Sdim#include <dev/firewire/firewire.h> 62224145Sdim#include <dev/firewire/firewirereg.h> 63221345Sdim#include <dev/firewire/fwdma.h> 64221345Sdim#include <dev/firewire/fwohcireg.h> 65221345Sdim#include <dev/firewire/fwohcivar.h> 66221345Sdim#include <dev/firewire/firewire_phy.h> 67221345Sdim 68221345Sdim#undef OHCI_DEBUG 69224145Sdim 70221345Sdimstatic char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL", 71221345Sdim "STOR","LOAD","NOP ","STOP",}; 72221345Sdim 73221345Sdimstatic char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", 74221345Sdim "UNDEF","REG","SYS","DEV"}; 75221345Sdimstatic char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; 76221345Sdimchar fwohcicode[32][0x20]={ 77223017Sdim "No stat","Undef","long","miss Ack err", 78221345Sdim "underrun","overrun","desc err", "data read err", 79221345Sdim "data write err","bus reset","timeout","tcode err", 80221345Sdim "Undef","Undef","unknown event","flushed", 81226633Sdim "Undef","ack complete","ack pend","Undef", 82221345Sdim "ack busy_X","ack busy_A","ack busy_B","Undef", 83221345Sdim "Undef","Undef","Undef","ack tardy", 84221345Sdim "Undef","ack data_err","ack type_err",""}; 85223017Sdim 86221345Sdim#define MAX_SPEED 3 87221345Sdimextern char linkspeed[][0x10]; 88221345Sdimu_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31}; 89221345Sdim 90221345Sdimstatic struct tcode_info tinfo[] = { 91221345Sdim/* hdr_len block flag*/ 92223017Sdim/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL}, 93223017Sdim/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, 94223017Sdim/* 2 WRES */ {12, FWTI_RES}, 95223017Sdim/* 3 XXX */ { 0, 0}, 96221345Sdim/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL}, 97221345Sdim/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL}, 98221345Sdim/* 6 RRESQ */ {16, FWTI_RES}, 99221345Sdim/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY}, 100239462Sdim/* 8 CYCS */ { 0, 0}, 101239462Sdim/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, 102221345Sdim/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR}, 103221345Sdim/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY}, 104221345Sdim/* c XXX */ { 0, 0}, 105193326Sed/* d XXX */ { 0, 0}, 106221345Sdim/* e PHY */ {12, FWTI_REQ}, 107221345Sdim/* f XXX */ { 0, 0} 108226633Sdim}; 109221345Sdim 110221345Sdim#define OHCI_WRITE_SIGMASK 0xffff0000 111226633Sdim#define OHCI_READ_SIGMASK 0xffff0000 112221345Sdim 113221345Sdim#define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x)) 114221345Sdim#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r)) 115224145Sdim 116221345Sdimstatic void fwohci_ibr __P((struct firewire_comm *)); 117221345Sdimstatic void fwohci_db_init __P((struct fwohci_softc *, struct fwohci_dbch *)); 118226633Sdimstatic void fwohci_db_free __P((struct fwohci_dbch *)); 119221345Sdimstatic void fwohci_arcv __P((struct fwohci_softc *, struct fwohci_dbch *, int)); 120221345Sdimstatic void fwohci_txd __P((struct fwohci_softc *, struct fwohci_dbch *)); 121224145Sdimstatic void fwohci_start_atq __P((struct firewire_comm *)); 122221345Sdimstatic void fwohci_start_ats __P((struct firewire_comm *)); 123221345Sdimstatic void fwohci_start __P((struct fwohci_softc *, struct fwohci_dbch *)); 124221345Sdimstatic u_int32_t fwphy_wrdata __P(( struct fwohci_softc *, u_int32_t, u_int32_t)); 125221345Sdimstatic u_int32_t fwphy_rddata __P(( struct fwohci_softc *, u_int32_t)); 126221345Sdimstatic int fwohci_rx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); 127224145Sdimstatic int fwohci_tx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); 128221345Sdimstatic int fwohci_irx_enable __P((struct firewire_comm *, int)); 129221345Sdimstatic int fwohci_irx_disable __P((struct firewire_comm *, int)); 130221345Sdim#if BYTE_ORDER == BIG_ENDIAN 131221345Sdimstatic void fwohci_irx_post __P((struct firewire_comm *, u_int32_t *)); 132224145Sdim#endif 133221345Sdimstatic int fwohci_itxbuf_enable __P((struct firewire_comm *, int)); 134221345Sdimstatic int fwohci_itx_disable __P((struct firewire_comm *, int)); 135226633Sdimstatic void fwohci_timeout __P((void *)); 136221345Sdimstatic void fwohci_set_intr __P((struct firewire_comm *, int)); 137221345Sdim 138204643Srdivackystatic int fwohci_add_rx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *)); 139221345Sdimstatic int fwohci_add_tx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int)); 140224145Sdimstatic void dump_db __P((struct fwohci_softc *, u_int32_t)); 141221345Sdimstatic void print_db __P((struct fwohcidb_tr *, volatile struct fwohcidb *, u_int32_t , u_int32_t)); 142221345Sdimstatic void dump_dma __P((struct fwohci_softc *, u_int32_t)); 143221345Sdimstatic u_int32_t fwohci_cyctimer __P((struct firewire_comm *)); 144224145Sdimstatic void fwohci_rbuf_update __P((struct fwohci_softc *, int)); 145221345Sdimstatic void fwohci_tbuf_update __P((struct fwohci_softc *, int)); 146221345Sdimvoid fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *)); 147221345Sdim#if FWOHCI_TASKQUEUE 148224145Sdimstatic void fwohci_complete(void *, int); 149221345Sdim#endif 150226633Sdim 151226633Sdim/* 152226633Sdim * memory allocated for DMA programs 153221345Sdim */ 154226633Sdim#define DMA_PROG_ALLOC (8 * PAGE_SIZE) 155221345Sdim 156221345Sdim/* #define NDB 1024 */ 157226633Sdim#define NDB FWMAXQUEUE 158221345Sdim#define NDVDB (DVBUF * NDB) 159226633Sdim 160226633Sdim#define OHCI_VERSION 0x00 161226633Sdim#define OHCI_ATRETRY 0x08 162226633Sdim#define OHCI_CROMHDR 0x18 163226633Sdim#define OHCI_BUS_OPT 0x20 164221345Sdim#define OHCI_BUSIRMC (1 << 31) 165221345Sdim#define OHCI_BUSCMC (1 << 30) 166221345Sdim#define OHCI_BUSISC (1 << 29) 167221345Sdim#define OHCI_BUSBMC (1 << 28) 168221345Sdim#define OHCI_BUSPMC (1 << 27) 169221345Sdim#define OHCI_BUSFNC OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\ 170221345Sdim OHCI_BUSBMC | OHCI_BUSPMC 171221345Sdim 172221345Sdim#define OHCI_EUID_HI 0x24 173221345Sdim#define OHCI_EUID_LO 0x28 174226633Sdim 175221345Sdim#define OHCI_CROMPTR 0x34 176221345Sdim#define OHCI_HCCCTL 0x50 177221345Sdim#define OHCI_HCCCTLCLR 0x54 178221345Sdim#define OHCI_AREQHI 0x100 179221345Sdim#define OHCI_AREQHICLR 0x104 180221345Sdim#define OHCI_AREQLO 0x108 181221345Sdim#define OHCI_AREQLOCLR 0x10c 182221345Sdim#define OHCI_PREQHI 0x110 183221345Sdim#define OHCI_PREQHICLR 0x114 184221345Sdim#define OHCI_PREQLO 0x118 185234353Sdim#define OHCI_PREQLOCLR 0x11c 186221345Sdim#define OHCI_PREQUPPER 0x120 187221345Sdim 188221345Sdim#define OHCI_SID_BUF 0x64 189226633Sdim#define OHCI_SID_CNT 0x68 190221345Sdim#define OHCI_SID_ERR (1 << 31) 191221345Sdim#define OHCI_SID_CNT_MASK 0xffc 192221345Sdim 193221345Sdim#define OHCI_IT_STAT 0x90 194226633Sdim#define OHCI_IT_STATCLR 0x94 195249423Sdim#define OHCI_IT_MASK 0x98 196226633Sdim#define OHCI_IT_MASKCLR 0x9c 197221345Sdim 198221345Sdim#define OHCI_IR_STAT 0xa0 199221345Sdim#define OHCI_IR_STATCLR 0xa4 200221345Sdim#define OHCI_IR_MASK 0xa8 201221345Sdim#define OHCI_IR_MASKCLR 0xac 202221345Sdim 203221345Sdim#define OHCI_LNKCTL 0xe0 204221345Sdim#define OHCI_LNKCTLCLR 0xe4 205221345Sdim 206226633Sdim#define OHCI_PHYACCESS 0xec 207249423Sdim#define OHCI_CYCLETIMER 0xf0 208226633Sdim 209221345Sdim#define OHCI_DMACTL(off) (off) 210221345Sdim#define OHCI_DMACTLCLR(off) (off + 4) 211221345Sdim#define OHCI_DMACMD(off) (off + 0xc) 212221345Sdim#define OHCI_DMAMATCH(off) (off + 0x10) 213221345Sdim 214221345Sdim#define OHCI_ATQOFF 0x180 215221345Sdim#define OHCI_ATQCTL OHCI_ATQOFF 216221345Sdim#define OHCI_ATQCTLCLR (OHCI_ATQOFF + 4) 217226633Sdim#define OHCI_ATQCMD (OHCI_ATQOFF + 0xc) 218249423Sdim#define OHCI_ATQMATCH (OHCI_ATQOFF + 0x10) 219226633Sdim 220221345Sdim#define OHCI_ATSOFF 0x1a0 221221345Sdim#define OHCI_ATSCTL OHCI_ATSOFF 222221345Sdim#define OHCI_ATSCTLCLR (OHCI_ATSOFF + 4) 223221345Sdim#define OHCI_ATSCMD (OHCI_ATSOFF + 0xc) 224221345Sdim#define OHCI_ATSMATCH (OHCI_ATSOFF + 0x10) 225243830Sdim 226243830Sdim#define OHCI_ARQOFF 0x1c0 227243830Sdim#define OHCI_ARQCTL OHCI_ARQOFF 228249423Sdim#define OHCI_ARQCTLCLR (OHCI_ARQOFF + 4) 229243830Sdim#define OHCI_ARQCMD (OHCI_ARQOFF + 0xc) 230243830Sdim#define OHCI_ARQMATCH (OHCI_ARQOFF + 0x10) 231243830Sdim 232243830Sdim#define OHCI_ARSOFF 0x1e0 233243830Sdim#define OHCI_ARSCTL OHCI_ARSOFF 234243830Sdim#define OHCI_ARSCTLCLR (OHCI_ARSOFF + 4) 235243830Sdim#define OHCI_ARSCMD (OHCI_ARSOFF + 0xc) 236243830Sdim#define OHCI_ARSMATCH (OHCI_ARSOFF + 0x10) 237243830Sdim 238243830Sdim#define OHCI_ITOFF(CH) (0x200 + 0x10 * (CH)) 239249423Sdim#define OHCI_ITCTL(CH) (OHCI_ITOFF(CH)) 240243830Sdim#define OHCI_ITCTLCLR(CH) (OHCI_ITOFF(CH) + 4) 241243830Sdim#define OHCI_ITCMD(CH) (OHCI_ITOFF(CH) + 0xc) 242243830Sdim 243243830Sdim#define OHCI_IROFF(CH) (0x400 + 0x20 * (CH)) 244243830Sdim#define OHCI_IRCTL(CH) (OHCI_IROFF(CH)) 245249423Sdim#define OHCI_IRCTLCLR(CH) (OHCI_IROFF(CH) + 4) 246249423Sdim#define OHCI_IRCMD(CH) (OHCI_IROFF(CH) + 0xc) 247249423Sdim#define OHCI_IRMATCH(CH) (OHCI_IROFF(CH) + 0x10) 248249423Sdim 249249423Sdimd_ioctl_t fwohci_ioctl; 250249423Sdim 251249423Sdim/* 252249423Sdim * Communication with PHY device 253249423Sdim */ 254249423Sdimstatic u_int32_t 255249423Sdimfwphy_wrdata( struct fwohci_softc *sc, u_int32_t addr, u_int32_t data) 256249423Sdim{ 257249423Sdim u_int32_t fun; 258249423Sdim 259249423Sdim addr &= 0xf; 260249423Sdim data &= 0xff; 261249423Sdim 262249423Sdim fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA)); 263249423Sdim OWRITE(sc, OHCI_PHYACCESS, fun); 264249423Sdim DELAY(100); 265249423Sdim 266249423Sdim return(fwphy_rddata( sc, addr)); 267249423Sdim} 268249423Sdim 269249423Sdimstatic u_int32_t 270249423Sdimfwohci_set_bus_manager(struct firewire_comm *fc, u_int node) 271249423Sdim{ 272249423Sdim struct fwohci_softc *sc = (struct fwohci_softc *)fc; 273221345Sdim int i; 274221345Sdim u_int32_t bm; 275221345Sdim 276249423Sdim#define OHCI_CSR_DATA 0x0c 277221345Sdim#define OHCI_CSR_COMP 0x10 278221345Sdim#define OHCI_CSR_CONT 0x14 279221345Sdim#define OHCI_BUS_MANAGER_ID 0 280221345Sdim 281221345Sdim OWRITE(sc, OHCI_CSR_DATA, node); 282221345Sdim OWRITE(sc, OHCI_CSR_COMP, 0x3f); 283221345Sdim OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID); 284221345Sdim for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++) 285221345Sdim DELAY(10); 286221345Sdim bm = OREAD(sc, OHCI_CSR_DATA); 287221345Sdim if((bm & 0x3f) == 0x3f) 288221345Sdim bm = node; 289221345Sdim if (bootverbose) 290221345Sdim device_printf(sc->fc.dev, 291193326Sed "fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i); 292221345Sdim 293221345Sdim return(bm); 294221345Sdim} 295221345Sdim 296193326Sedstatic u_int32_t 297221345Sdimfwphy_rddata(struct fwohci_softc *sc, u_int addr) 298193326Sed{ 299221345Sdim u_int32_t fun, stat; 300193326Sed u_int i, retry = 0; 301221345Sdim 302221345Sdim addr &= 0xf; 303193326Sed#define MAX_RETRY 100 304221345Sdimagain: 305221345Sdim OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL); 306221345Sdim fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR); 307203955Srdivacky OWRITE(sc, OHCI_PHYACCESS, fun); 308221345Sdim for ( i = 0 ; i < MAX_RETRY ; i ++ ){ 309193326Sed fun = OREAD(sc, OHCI_PHYACCESS); 310221345Sdim if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0) 311221345Sdim break; 312221345Sdim DELAY(100); 313221345Sdim } 314221345Sdim if(i >= MAX_RETRY) { 315221345Sdim if (bootverbose) 316221345Sdim device_printf(sc->fc.dev, "phy read failed(1).\n"); 317221345Sdim if (++retry < MAX_RETRY) { 318221345Sdim DELAY(100); 319226633Sdim goto again; 320221345Sdim } 321221345Sdim } 322221345Sdim /* Make sure that SCLK is started */ 323221345Sdim stat = OREAD(sc, FWOHCI_INTSTAT); 324221345Sdim if ((stat & OHCI_INT_REG_FAIL) != 0 || 325221345Sdim ((fun >> PHYDEV_REGADDR) & 0xf) != addr) { 326221345Sdim if (bootverbose) 327203955Srdivacky device_printf(sc->fc.dev, "phy read failed(2).\n"); 328221345Sdim if (++retry < MAX_RETRY) { 329221345Sdim DELAY(100); 330221345Sdim goto again; 331221345Sdim } 332221345Sdim } 333221345Sdim if (bootverbose || retry >= MAX_RETRY) 334234353Sdim device_printf(sc->fc.dev, 335234353Sdim "fwphy_rddata: loop=%d, retry=%d\n", i, retry); 336234353Sdim#undef MAX_RETRY 337234353Sdim return((fun >> PHYDEV_RDDATA )& 0xff); 338221345Sdim} 339221345Sdim/* Device specific ioctl. */ 340221345Sdimint 341239462Sdimfwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 342239462Sdim{ 343221345Sdim struct firewire_softc *sc; 344221345Sdim struct fwohci_softc *fc; 345221345Sdim int unit = DEV2UNIT(dev); 346221345Sdim int err = 0; 347221345Sdim struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data; 348221345Sdim u_int32_t *dmach = (u_int32_t *) data; 349221345Sdim 350239462Sdim sc = devclass_get_softc(firewire_devclass, unit); 351221345Sdim if(sc == NULL){ 352239462Sdim return(EINVAL); 353221345Sdim } 354221345Sdim fc = (struct fwohci_softc *)sc->fc; 355193326Sed 356221345Sdim if (!data) 357221345Sdim return(EINVAL); 358221345Sdim 359221345Sdim switch (cmd) { 360221345Sdim case FWOHCI_WRREG: 361221345Sdim#define OHCI_MAX_REG 0x800 362221345Sdim if(reg->addr <= OHCI_MAX_REG){ 363221345Sdim OWRITE(fc, reg->addr, reg->data); 364221345Sdim reg->data = OREAD(fc, reg->addr); 365221345Sdim }else{ 366221345Sdim err = EINVAL; 367221345Sdim } 368221345Sdim break; 369221345Sdim case FWOHCI_RDREG: 370221345Sdim if(reg->addr <= OHCI_MAX_REG){ 371221345Sdim reg->data = OREAD(fc, reg->addr); 372221345Sdim }else{ 373223017Sdim err = EINVAL; 374221345Sdim } 375221345Sdim break; 376221345Sdim/* Read DMA descriptors for debug */ 377221345Sdim case DUMPDMA: 378221345Sdim if(*dmach <= OHCI_MAX_DMA_CH ){ 379221345Sdim dump_dma(fc, *dmach); 380221345Sdim dump_db(fc, *dmach); 381221345Sdim }else{ 382221345Sdim err = EINVAL; 383221345Sdim } 384221345Sdim break; 385221345Sdim default: 386234353Sdim break; 387234353Sdim } 388234353Sdim return err; 389221345Sdim} 390221345Sdim 391221345Sdimstatic int 392221345Sdimfwohci_probe_phy(struct fwohci_softc *sc, device_t dev) 393221345Sdim{ 394226633Sdim u_int32_t reg, reg2; 395226633Sdim int e1394a = 1; 396234353Sdim/* 397234353Sdim * probe PHY parameters 398193326Sed * 0. to prove PHY version, whether compliance of 1394a. 399239462Sdim * 1. to probe maximum speed supported by the PHY and 400221345Sdim * number of port supported by core-logic. 401221345Sdim * It is not actually available port on your PC . 402193326Sed */ 403221345Sdim OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS); 404221345Sdim reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 405198092Srdivacky 406226633Sdim if((reg >> 5) != 7 ){ 407226633Sdim sc->fc.mode &= ~FWPHYASYST; 408221345Sdim sc->fc.nport = reg & FW_PHY_NP; 409221345Sdim sc->fc.speed = reg & FW_PHY_SPD >> 6; 410234353Sdim if (sc->fc.speed > MAX_SPEED) { 411221345Sdim device_printf(dev, "invalid speed %d (fixed to %d).\n", 412221345Sdim sc->fc.speed, MAX_SPEED); 413221345Sdim sc->fc.speed = MAX_SPEED; 414221345Sdim } 415249423Sdim device_printf(dev, 416221345Sdim "Phy 1394 only %s, %d ports.\n", 417193326Sed linkspeed[sc->fc.speed], sc->fc.nport); 418193326Sed }else{ 419193326Sed reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG); 420193326Sed sc->fc.mode |= FWPHYASYST; 421193326Sed sc->fc.nport = reg & FW_PHY_NP; 422193326Sed sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5; 423193326Sed if (sc->fc.speed > MAX_SPEED) { 424193326Sed device_printf(dev, "invalid speed %d (fixed to %d).\n", 425193326Sed sc->fc.speed, MAX_SPEED); 426198092Srdivacky sc->fc.speed = MAX_SPEED; 427198092Srdivacky } 428207619Srdivacky device_printf(dev, 429226633Sdim "Phy 1394a available %s, %d ports.\n", 430226633Sdim linkspeed[sc->fc.speed], sc->fc.nport); 431207619Srdivacky 432221345Sdim /* check programPhyEnable */ 433221345Sdim reg2 = fwphy_rddata(sc, 5); 434193326Sed#if 0 435234353Sdim if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) { 436234353Sdim#else /* XXX force to enable 1394a */ 437221345Sdim if (e1394a) { 438221345Sdim#endif 439249423Sdim if (bootverbose) 440221345Sdim device_printf(dev, 441221345Sdim "Enable 1394a Enhancements\n"); 442193326Sed /* enable EAA EMC */ 443193326Sed reg2 |= 0x03; 444221345Sdim /* set aPhyEnhanceEnable */ 445221345Sdim OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN); 446239462Sdim OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY); 447194613Sed } else { 448224145Sdim /* for safe */ 449249423Sdim reg2 &= ~0x83; 450239462Sdim } 451221345Sdim reg2 = fwphy_wrdata(sc, 5, reg2); 452221345Sdim } 453221345Sdim 454221345Sdim reg = fwphy_rddata(sc, FW_PHY_SPD_REG); 455221345Sdim if((reg >> 5) == 7 ){ 456221345Sdim reg = fwphy_rddata(sc, 4); 457263508Sdim reg |= 1 << 6; 458263508Sdim fwphy_wrdata(sc, 4, reg); 459226633Sdim reg = fwphy_rddata(sc, 4); 460226633Sdim } 461226633Sdim return 0; 462221345Sdim} 463221345Sdim 464263508Sdim 465263508Sdimvoid 466226633Sdimfwohci_reset(struct fwohci_softc *sc, device_t dev) 467226633Sdim{ 468226633Sdim int i, max_rec, speed; 469226633Sdim u_int32_t reg, reg2; 470226633Sdim struct fwohcidb_tr *db_tr; 471226633Sdim 472226633Sdim /* Disable interrupt */ 473226633Sdim OWRITE(sc, FWOHCI_INTMASKCLR, ~0); 474226633Sdim 475226633Sdim /* Now stopping all DMA channel */ 476226633Sdim OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 477234353Sdim OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 478193326Sed OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 479221345Sdim OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 480221345Sdim 481221345Sdim OWRITE(sc, OHCI_IR_MASKCLR, ~0); 482202879Srdivacky for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 483221345Sdim OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 484221345Sdim OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 485221345Sdim } 486208600Srdivacky 487193326Sed /* FLUSH FIFO and reset Transmitter/Reciever */ 488193326Sed OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 489193326Sed if (bootverbose) 490193326Sed device_printf(dev, "resetting OHCI..."); 491207619Srdivacky i = 0; 492193326Sed while(OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) { 493221345Sdim if (i++ > 100) break; 494221345Sdim DELAY(1000); 495208600Srdivacky } 496193326Sed if (bootverbose) 497193326Sed printf("done (loop=%d)\n", i); 498193326Sed 499193326Sed /* Probe phy */ 500193326Sed fwohci_probe_phy(sc, dev); 501193326Sed 502198092Srdivacky /* Probe link */ 503198092Srdivacky reg = OREAD(sc, OHCI_BUS_OPT); 504249423Sdim reg2 = reg | OHCI_BUSFNC; 505193326Sed max_rec = (reg & 0x0000f000) >> 12; 506249423Sdim speed = (reg & 0x00000007); 507210299Sed device_printf(dev, "Link %s, max_rec %d bytes.\n", 508249423Sdim linkspeed[speed], MAXREC(max_rec)); 509193326Sed /* XXX fix max_rec */ 510212904Sdim sc->fc.maxrec = sc->fc.speed + 8; 511198092Srdivacky if (max_rec != sc->fc.maxrec) { 512198092Srdivacky reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12); 513193326Sed device_printf(dev, "max_rec %d -> %d\n", 514193326Sed MAXREC(max_rec), MAXREC(sc->fc.maxrec)); 515193326Sed } 516234353Sdim if (bootverbose) 517249423Sdim device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2); 518193326Sed OWRITE(sc, OHCI_BUS_OPT, reg2); 519193326Sed 520193326Sed /* Initialize registers */ 521223017Sdim OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]); 522223017Sdim OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr); 523234353Sdim OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND); 524234353Sdim OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR); 525223017Sdim OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr); 526223017Sdim OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID); 527249423Sdim fw_busreset(&sc->fc); 528249423Sdim 529198092Srdivacky /* Enable link */ 530198092Srdivacky OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN); 531221345Sdim 532210299Sed /* Force to start async RX DMA */ 533221345Sdim sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING; 534210299Sed sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING; 535221345Sdim fwohci_rx_enable(sc, &sc->arrq); 536249423Sdim fwohci_rx_enable(sc, &sc->arrs); 537249423Sdim 538221345Sdim /* Initialize async TX */ 539193326Sed OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 540221345Sdim OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD); 541193326Sed 542221345Sdim /* AT Retries */ 543212904Sdim OWRITE(sc, FWOHCI_RETRY, 544212904Sdim /* CycleLimit PhyRespRetries ATRespRetries ATReqRetries */ 545221345Sdim (0xffff << 16 ) | (0x0f << 8) | (0x0f << 4) | 0x0f) ; 546198092Srdivacky 547198092Srdivacky sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq); 548221345Sdim sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq); 549193326Sed sc->atrq.bottom = sc->atrq.top; 550221345Sdim sc->atrs.bottom = sc->atrs.top; 551198092Srdivacky 552198092Srdivacky for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ; 553210299Sed i ++, db_tr = STAILQ_NEXT(db_tr, link)){ 554221345Sdim db_tr->xfer = NULL; 555193326Sed } 556193326Sed for( i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb ; 557193326Sed i ++, db_tr = STAILQ_NEXT(db_tr, link)){ 558193326Sed db_tr->xfer = NULL; 559221345Sdim } 560193326Sed 561193326Sed 562249423Sdim /* Enable interrupt */ 563221345Sdim OWRITE(sc, FWOHCI_INTMASK, 564218893Sdim OHCI_INT_ERR | OHCI_INT_PHY_SID 565212904Sdim | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 566212904Sdim | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 567243830Sdim | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); 568243830Sdim fwohci_set_intr(&sc->fc, 1); 569243830Sdim 570243830Sdim} 571249423Sdim 572249423Sdimint 573249423Sdimfwohci_init(struct fwohci_softc *sc, device_t dev) 574249423Sdim{ 575249423Sdim int i; 576249423Sdim u_int32_t reg; 577223017Sdim u_int8_t ui[8]; 578223017Sdim 579223017Sdim#if FWOHCI_TASKQUEUE 580193326Sed TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc); 581221345Sdim#endif 582221345Sdim 583221345Sdim reg = OREAD(sc, OHCI_VERSION); 584221345Sdim device_printf(dev, "OHCI version %x.%x (ROM=%d)\n", 585221345Sdim (reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1); 586221345Sdim 587221345Sdim/* Available Isochrounous DMA channel probe */ 588221345Sdim OWRITE(sc, OHCI_IT_MASK, 0xffffffff); 589221345Sdim OWRITE(sc, OHCI_IR_MASK, 0xffffffff); 590221345Sdim reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK); 591221345Sdim OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff); 592221345Sdim OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff); 593221345Sdim for (i = 0; i < 0x20; i++) 594221345Sdim if ((reg & (1 << i)) == 0) 595221345Sdim break; 596221345Sdim sc->fc.nisodma = i; 597221345Sdim device_printf(dev, "No. of Isochronous channel is %d.\n", i); 598221345Sdim 599221345Sdim sc->fc.arq = &sc->arrq.xferq; 600221345Sdim sc->fc.ars = &sc->arrs.xferq; 601263508Sdim sc->fc.atq = &sc->atrq.xferq; 602263508Sdim sc->fc.ats = &sc->atrs.xferq; 603221345Sdim 604228379Sdim sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 605234353Sdim sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 606234353Sdim sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 607249423Sdim sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); 608228379Sdim 609228379Sdim sc->arrq.xferq.start = NULL; 610221345Sdim sc->arrs.xferq.start = NULL; 611221345Sdim sc->atrq.xferq.start = fwohci_start_atq; 612221345Sdim sc->atrs.xferq.start = fwohci_start_ats; 613263508Sdim 614263508Sdim sc->arrq.xferq.buf = NULL; 615221345Sdim sc->arrs.xferq.buf = NULL; 616221345Sdim sc->atrq.xferq.buf = NULL; 617221345Sdim sc->atrs.xferq.buf = NULL; 618249423Sdim 619221345Sdim sc->arrq.xferq.dmach = -1; 620221345Sdim sc->arrs.xferq.dmach = -1; 621221345Sdim sc->atrq.xferq.dmach = -1; 622221345Sdim sc->atrs.xferq.dmach = -1; 623221345Sdim 624221345Sdim sc->arrq.ndesc = 1; 625221345Sdim sc->arrs.ndesc = 1; 626221345Sdim sc->atrq.ndesc = 8; /* equal to maximum of mbuf chains */ 627221345Sdim sc->atrs.ndesc = 2; 628221345Sdim 629221345Sdim sc->arrq.ndb = NDB; 630221345Sdim sc->arrs.ndb = NDB / 2; 631221345Sdim sc->atrq.ndb = NDB; 632221345Sdim sc->atrs.ndb = NDB / 2; 633221345Sdim 634221345Sdim for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 635221345Sdim sc->fc.it[i] = &sc->it[i].xferq; 636221345Sdim sc->fc.ir[i] = &sc->ir[i].xferq; 637221345Sdim sc->it[i].xferq.dmach = i; 638221345Sdim sc->ir[i].xferq.dmach = i; 639249423Sdim sc->it[i].ndb = 0; 640249423Sdim sc->ir[i].ndb = 0; 641249423Sdim } 642249423Sdim 643249423Sdim sc->fc.tcode = tinfo; 644249423Sdim sc->fc.dev = dev; 645249423Sdim 646249423Sdim sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE, 647249423Sdim &sc->crom_dma, BUS_DMA_WAITOK); 648249423Sdim if(sc->fc.config_rom == NULL){ 649249423Sdim device_printf(dev, "config_rom alloc failed."); 650249423Sdim return ENOMEM; 651249423Sdim } 652249423Sdim 653221345Sdim#if 0 654221345Sdim bzero(&sc->fc.config_rom[0], CROMSIZE); 655221345Sdim sc->fc.config_rom[1] = 0x31333934; 656243830Sdim sc->fc.config_rom[2] = 0xf000a002; 657243830Sdim sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI); 658221345Sdim sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO); 659221345Sdim sc->fc.config_rom[5] = 0; 660221345Sdim sc->fc.config_rom[0] = (4 << 24) | (5 << 16); 661221345Sdim 662263508Sdim sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4); 663263508Sdim#endif 664221345Sdim 665221345Sdim 666221345Sdim/* SID recieve buffer must allign 2^11 */ 667221345Sdim#define OHCI_SIDSIZE (1 << 11) 668221345Sdim sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE, 669221345Sdim &sc->sid_dma, BUS_DMA_WAITOK); 670221345Sdim if (sc->sid_buf == NULL) { 671221345Sdim device_printf(dev, "sid_buf alloc failed."); 672221345Sdim return ENOMEM; 673221345Sdim } 674221345Sdim 675221345Sdim fwdma_malloc(&sc->fc, sizeof(u_int32_t), sizeof(u_int32_t), 676221345Sdim &sc->dummy_dma, BUS_DMA_WAITOK); 677221345Sdim 678221345Sdim if (sc->dummy_dma.v_addr == NULL) { 679221345Sdim device_printf(dev, "dummy_dma alloc failed."); 680221345Sdim return ENOMEM; 681221345Sdim } 682228379Sdim 683234353Sdim fwohci_db_init(sc, &sc->arrq); 684234353Sdim if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0) 685234353Sdim return ENOMEM; 686249423Sdim 687228379Sdim fwohci_db_init(sc, &sc->arrs); 688221345Sdim if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0) 689221345Sdim return ENOMEM; 690221345Sdim 691228379Sdim fwohci_db_init(sc, &sc->atrq); 692228379Sdim if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0) 693221345Sdim return ENOMEM; 694221345Sdim 695221345Sdim fwohci_db_init(sc, &sc->atrs); 696221345Sdim if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0) 697221345Sdim return ENOMEM; 698221345Sdim 699221345Sdim sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H); 700221345Sdim sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L); 701263508Sdim for( i = 0 ; i < 8 ; i ++) 702263508Sdim ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i); 703221345Sdim device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 704221345Sdim ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]); 705221345Sdim 706249423Sdim sc->fc.ioctl = fwohci_ioctl; 707249423Sdim sc->fc.cyctimer = fwohci_cyctimer; 708221345Sdim sc->fc.set_bmr = fwohci_set_bus_manager; 709221345Sdim sc->fc.ibr = fwohci_ibr; 710221345Sdim sc->fc.irx_enable = fwohci_irx_enable; 711221345Sdim sc->fc.irx_disable = fwohci_irx_disable; 712221345Sdim 713221345Sdim sc->fc.itx_enable = fwohci_itxbuf_enable; 714249423Sdim sc->fc.itx_disable = fwohci_itx_disable; 715249423Sdim#if BYTE_ORDER == BIG_ENDIAN 716224145Sdim sc->fc.irx_post = fwohci_irx_post; 717221345Sdim#else 718221345Sdim sc->fc.irx_post = NULL; 719221345Sdim#endif 720221345Sdim sc->fc.itx_post = NULL; 721221345Sdim sc->fc.timeout = fwohci_timeout; 722221345Sdim sc->fc.poll = fwohci_poll; 723221345Sdim sc->fc.set_intr = fwohci_set_intr; 724221345Sdim 725221345Sdim sc->intmask = sc->irstat = sc->itstat = 0; 726234353Sdim 727224145Sdim fw_init(&sc->fc); 728221345Sdim fwohci_reset(sc, dev); 729221345Sdim 730221345Sdim return 0; 731226633Sdim} 732221345Sdim 733249423Sdimvoid 734249423Sdimfwohci_timeout(void *arg) 735249423Sdim{ 736249423Sdim struct fwohci_softc *sc; 737249423Sdim 738249423Sdim sc = (struct fwohci_softc *)arg; 739249423Sdim} 740249423Sdim 741249423Sdimu_int32_t 742249423Sdimfwohci_cyctimer(struct firewire_comm *fc) 743249423Sdim{ 744221345Sdim struct fwohci_softc *sc = (struct fwohci_softc *)fc; 745249423Sdim return(OREAD(sc, OHCI_CYCLETIMER)); 746249423Sdim} 747249423Sdim 748249423Sdimint 749249423Sdimfwohci_detach(struct fwohci_softc *sc, device_t dev) 750249423Sdim{ 751249423Sdim int i; 752249423Sdim 753249423Sdim if (sc->sid_buf != NULL) 754249423Sdim fwdma_free(&sc->fc, &sc->sid_dma); 755249423Sdim if (sc->fc.config_rom != NULL) 756249423Sdim fwdma_free(&sc->fc, &sc->crom_dma); 757249423Sdim 758249423Sdim fwohci_db_free(&sc->arrq); 759249423Sdim fwohci_db_free(&sc->arrs); 760249423Sdim 761249423Sdim fwohci_db_free(&sc->atrq); 762221345Sdim fwohci_db_free(&sc->atrs); 763249423Sdim 764249423Sdim for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 765249423Sdim fwohci_db_free(&sc->it[i]); 766249423Sdim fwohci_db_free(&sc->ir[i]); 767249423Sdim } 768249423Sdim 769249423Sdim return 0; 770249423Sdim} 771249423Sdim 772249423Sdim#define LAST_DB(dbtr, db) do { \ 773249423Sdim struct fwohcidb_tr *_dbtr = (dbtr); \ 774249423Sdim int _cnt = _dbtr->dbcnt; \ 775249423Sdim db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0]; \ 776249423Sdim} while (0) 777249423Sdim 778249423Sdimstatic void 779249423Sdimfwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error) 780249423Sdim{ 781249423Sdim struct fwohcidb_tr *db_tr; 782249423Sdim volatile struct fwohcidb *db; 783249423Sdim bus_dma_segment_t *s; 784249423Sdim int i; 785249423Sdim 786249423Sdim db_tr = (struct fwohcidb_tr *)arg; 787249423Sdim db = &db_tr->db[db_tr->dbcnt]; 788249423Sdim if (error) { 789249423Sdim if (firewire_debug || error != EFBIG) 790249423Sdim printf("fwohci_execute_db: error=%d\n", error); 791249423Sdim return; 792249423Sdim } 793249423Sdim for (i = 0; i < nseg; i++) { 794249423Sdim s = &segs[i]; 795249423Sdim FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr); 796249423Sdim FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len); 797221345Sdim FWOHCI_DMA_WRITE(db->db.desc.res, 0); 798221345Sdim db++; 799263508Sdim db_tr->dbcnt++; 800243830Sdim } 801243830Sdim} 802243830Sdim 803243830Sdimstatic void 804243830Sdimfwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg, 805263508Sdim bus_size_t size, int error) 806263508Sdim{ 807263508Sdim fwohci_execute_db(arg, segs, nseg, error); 808243830Sdim} 809243830Sdim 810243830Sdimstatic void 811263508Sdimfwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 812243830Sdim{ 813243830Sdim int i, s; 814243830Sdim int tcode, hdr_len, pl_off, pl_len; 815243830Sdim int fsegment = -1; 816263508Sdim u_int32_t off; 817263508Sdim struct fw_xfer *xfer; 818243830Sdim struct fw_pkt *fp; 819243830Sdim volatile struct fwohci_txpkthdr *ohcifp; 820243830Sdim struct fwohcidb_tr *db_tr; 821243830Sdim volatile struct fwohcidb *db; 822263508Sdim struct tcode_info *info; 823263508Sdim static int maxdesc=0; 824263508Sdim 825263508Sdim if(&sc->atrq == dbch){ 826263508Sdim off = OHCI_ATQOFF; 827263508Sdim }else if(&sc->atrs == dbch){ 828263508Sdim off = OHCI_ATSOFF; 829243830Sdim }else{ 830243830Sdim return; 831243830Sdim } 832243830Sdim 833243830Sdim if (dbch->flags & FWOHCI_DBCH_FULL) 834243830Sdim return; 835263508Sdim 836263508Sdim s = splfw(); 837243830Sdim db_tr = dbch->top; 838243830Sdimtxloop: 839243830Sdim xfer = STAILQ_FIRST(&dbch->xferq.q); 840263508Sdim if(xfer == NULL){ 841263508Sdim goto kick; 842263508Sdim } 843263508Sdim if(dbch->xferq.queued == 0 ){ 844263508Sdim device_printf(sc->fc.dev, "TX queue empty\n"); 845243830Sdim } 846243830Sdim STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); 847249423Sdim db_tr->xfer = xfer; 848239462Sdim xfer->state = FWXF_START; 849239462Sdim 850249423Sdim fp = (struct fw_pkt *)xfer->send.buf; 851239462Sdim tcode = fp->mode.common.tcode; 852239462Sdim 853239462Sdim ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed; 854239462Sdim info = &tinfo[tcode]; 855239462Sdim hdr_len = pl_off = info->hdr_len; 856239462Sdim for( i = 0 ; i < pl_off ; i+= 4){ 857239462Sdim ohcifp->mode.ld[i/4] = fp->mode.ld[i/4]; 858239462Sdim } 859239462Sdim ohcifp->mode.common.spd = xfer->spd; 860239462Sdim if (tcode == FWTCODE_STREAM ){ 861239462Sdim hdr_len = 8; 862239462Sdim ohcifp->mode.stream.len = fp->mode.stream.len; 863239462Sdim } else if (tcode == FWTCODE_PHY) { 864239462Sdim hdr_len = 12; 865239462Sdim ohcifp->mode.ld[1] = fp->mode.ld[1]; 866239462Sdim ohcifp->mode.ld[2] = fp->mode.ld[2]; 867243830Sdim ohcifp->mode.common.spd = 0; 868243830Sdim ohcifp->mode.common.tcode = FWOHCITCODE_PHY; 869243830Sdim } else { 870263508Sdim ohcifp->mode.asycomm.dst = fp->mode.hdr.dst; 871263508Sdim ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; 872243830Sdim ohcifp->mode.asycomm.tlrt |= FWRETRY_X; 873243830Sdim } 874243830Sdim db = &db_tr->db[0]; 875263508Sdim FWOHCI_DMA_WRITE(db->db.desc.cmd, 876263508Sdim OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len); 877243830Sdim FWOHCI_DMA_WRITE(db->db.desc.res, 0); 878239462Sdim/* Specify bound timer of asy. responce */ 879193326Sed if(&sc->atrs == dbch){ 880193326Sed FWOHCI_DMA_WRITE(db->db.desc.res, 881193326Sed (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13)); 882194613Sed } 883194613Sed#if BYTE_ORDER == BIG_ENDIAN 884194613Sed if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ) 885198092Srdivacky hdr_len = 12; 886194613Sed for (i = 0; i < hdr_len/4; i ++) 887194613Sed FWOHCI_DMA_WRITE(ohcifp->mode.ld[i], ohcifp->mode.ld[i]); 888198092Srdivacky#endif 889198092Srdivacky 890194613Sedagain: 891194613Sed db_tr->dbcnt = 2; 892194613Sed db = &db_tr->db[db_tr->dbcnt]; 893198092Srdivacky pl_len = xfer->send.len - pl_off; 894198092Srdivacky if (pl_len > 0) { 895194613Sed int err; 896198092Srdivacky /* handle payload */ 897198092Srdivacky if (xfer->mbuf == NULL) { 898194613Sed caddr_t pl_addr; 899193326Sed 900226633Sdim pl_addr = xfer->send.buf + pl_off; 901226633Sdim err = bus_dmamap_load(dbch->dmat, db_tr->dma_map, 902221345Sdim pl_addr, pl_len, 903221345Sdim fwohci_execute_db, db_tr, 904202379Srdivacky /*flags*/0); 905202379Srdivacky } else { 906226633Sdim /* XXX we can handle only 6 (=8-2) mbuf chains */ 907221345Sdim err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 908193326Sed xfer->mbuf, 909193326Sed fwohci_execute_db2, db_tr, 910221345Sdim /* flags */0); 911221345Sdim if (err == EFBIG) { 912234353Sdim struct mbuf *m0; 913234353Sdim 914234353Sdim if (firewire_debug) 915207619Srdivacky device_printf(sc->fc.dev, "EFBIG.\n"); 916207619Srdivacky m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 917207619Srdivacky if (m0 != NULL) { 918221345Sdim m_copydata(xfer->mbuf, 0, 919193326Sed xfer->mbuf->m_pkthdr.len, 920221345Sdim mtod(m0, caddr_t)); 921193326Sed m0->m_len = m0->m_pkthdr.len = 922221345Sdim xfer->mbuf->m_pkthdr.len; 923218893Sdim m_freem(xfer->mbuf); 924221345Sdim xfer->mbuf = m0; 925218893Sdim goto again; 926221345Sdim } 927218893Sdim device_printf(sc->fc.dev, "m_getcl failed.\n"); 928198092Srdivacky } 929198092Srdivacky } 930198092Srdivacky if (err) 931198092Srdivacky printf("dmamap_load: err=%d\n", err); 932198092Srdivacky bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 933193326Sed BUS_DMASYNC_PREWRITE); 934193326Sed#if 0 /* OHCI_OUTPUT_MODE == 0 */ 935198092Srdivacky for (i = 2; i < db_tr->dbcnt; i++) 936193326Sed FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd, 937202879Srdivacky OHCI_OUTPUT_MORE); 938202879Srdivacky#endif 939202879Srdivacky } 940202879Srdivacky if (maxdesc < db_tr->dbcnt) { 941202879Srdivacky maxdesc = db_tr->dbcnt; 942202879Srdivacky if (bootverbose) 943193326Sed device_printf(sc->fc.dev, "maxdesc: %d\n", maxdesc); 944193326Sed } 945193326Sed /* last db */ 946198092Srdivacky LAST_DB(db_tr, db); 947226633Sdim FWOHCI_DMA_SET(db->db.desc.cmd, 948226633Sdim OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 949226633Sdim FWOHCI_DMA_WRITE(db->db.desc.depend, 950226633Sdim STAILQ_NEXT(db_tr, link)->bus_addr); 951226633Sdim 952226633Sdim if(fsegment == -1 ) 953193326Sed fsegment = db_tr->dbcnt; 954221345Sdim if (dbch->pdb_tr != NULL) { 955221345Sdim LAST_DB(dbch->pdb_tr, db); 956221345Sdim FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt); 957221345Sdim } 958221345Sdim dbch->pdb_tr = db_tr; 959221345Sdim db_tr = STAILQ_NEXT(db_tr, link); 960202879Srdivacky if(db_tr != dbch->bottom){ 961202879Srdivacky goto txloop; 962203955Srdivacky } else { 963198092Srdivacky device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n"); 964224145Sdim dbch->flags |= FWOHCI_DBCH_FULL; 965221345Sdim } 966221345Sdimkick: 967224145Sdim /* kick asy q */ 968221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 969221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 970221345Sdim 971221345Sdim if(dbch->xferq.flag & FWXFERQ_RUNNING) { 972221345Sdim OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); 973221345Sdim } else { 974221345Sdim if (bootverbose) 975221345Sdim device_printf(sc->fc.dev, "start AT DMA status=%x\n", 976221345Sdim OREAD(sc, OHCI_DMACTL(off))); 977221345Sdim OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment); 978221345Sdim OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 979221345Sdim dbch->xferq.flag |= FWXFERQ_RUNNING; 980221345Sdim } 981221345Sdim 982221345Sdim dbch->top = db_tr; 983221345Sdim splx(s); 984221345Sdim return; 985221345Sdim} 986221345Sdim 987221345Sdimstatic void 988221345Sdimfwohci_start_atq(struct firewire_comm *fc) 989221345Sdim{ 990221345Sdim struct fwohci_softc *sc = (struct fwohci_softc *)fc; 991221345Sdim fwohci_start( sc, &(sc->atrq)); 992221345Sdim return; 993221345Sdim} 994193326Sed 995224145Sdimstatic void 996221345Sdimfwohci_start_ats(struct firewire_comm *fc) 997221345Sdim{ 998203955Srdivacky struct fwohci_softc *sc = (struct fwohci_softc *)fc; 999234353Sdim fwohci_start( sc, &(sc->atrs)); 1000226633Sdim return; 1001224145Sdim} 1002224145Sdim 1003221345Sdimvoid 1004226633Sdimfwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1005223017Sdim{ 1006223017Sdim int s, ch, err = 0; 1007223017Sdim struct fwohcidb_tr *tr; 1008203955Srdivacky volatile struct fwohcidb *db; 1009203955Srdivacky struct fw_xfer *xfer; 1010203955Srdivacky u_int32_t off; 1011203955Srdivacky u_int stat, status; 1012203955Srdivacky int packets; 1013203955Srdivacky struct firewire_comm *fc = (struct firewire_comm *)sc; 1014203955Srdivacky 1015203955Srdivacky if(&sc->atrq == dbch){ 1016221345Sdim off = OHCI_ATQOFF; 1017221345Sdim ch = ATRQ_CH; 1018203955Srdivacky }else if(&sc->atrs == dbch){ 1019221345Sdim off = OHCI_ATSOFF; 1020221345Sdim ch = ATRS_CH; 1021203955Srdivacky }else{ 1022221345Sdim return; 1023221345Sdim } 1024203955Srdivacky s = splfw(); 1025221345Sdim tr = dbch->bottom; 1026203955Srdivacky packets = 0; 1027221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 1028203955Srdivacky fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 1029221345Sdim while(dbch->xferq.queued > 0){ 1030221345Sdim LAST_DB(tr, db); 1031203955Srdivacky status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT; 1032193326Sed if(!(status & OHCI_CNTL_DMA_ACTIVE)){ 1033198092Srdivacky if (fc->status != FWBUSRESET) 1034249423Sdim /* maybe out of order?? */ 1035224145Sdim goto out; 1036224145Sdim } 1037224145Sdim bus_dmamap_sync(dbch->dmat, tr->dma_map, 1038202379Srdivacky BUS_DMASYNC_POSTWRITE); 1039202379Srdivacky bus_dmamap_unload(dbch->dmat, tr->dma_map); 1040202379Srdivacky#if 0 1041202379Srdivacky dump_db(sc, ch); 1042224145Sdim#endif 1043224145Sdim if(status & OHCI_CNTL_DMA_DEAD) { 1044224145Sdim /* Stop DMA */ 1045224145Sdim OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 1046224145Sdim device_printf(sc->fc.dev, "force reset AT FIFO\n"); 1047249423Sdim OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN); 1048193326Sed OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN); 1049193326Sed OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); 1050226633Sdim } 1051193326Sed stat = status & FWOHCIEV_MASK; 1052249423Sdim switch(stat){ 1053193326Sed case FWOHCIEV_ACKPEND: 1054193326Sed case FWOHCIEV_ACKCOMPL: 1055224145Sdim err = 0; 1056224145Sdim break; 1057249423Sdim case FWOHCIEV_ACKBSA: 1058224145Sdim case FWOHCIEV_ACKBSB: 1059249423Sdim case FWOHCIEV_ACKBSX: 1060224145Sdim device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); 1061249423Sdim err = EBUSY; 1062249423Sdim break; 1063224145Sdim case FWOHCIEV_FLUSHED: 1064224145Sdim case FWOHCIEV_ACKTARD: 1065249423Sdim device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); 1066221345Sdim err = EAGAIN; 1067221345Sdim break; 1068263508Sdim case FWOHCIEV_MISSACK: 1069221345Sdim case FWOHCIEV_UNDRRUN: 1070221345Sdim case FWOHCIEV_OVRRUN: 1071221345Sdim case FWOHCIEV_DESCERR: 1072226633Sdim case FWOHCIEV_DTRDERR: 1073221345Sdim case FWOHCIEV_TIMEOUT: 1074221345Sdim case FWOHCIEV_TCODERR: 1075221345Sdim case FWOHCIEV_UNKNOWN: 1076221345Sdim case FWOHCIEV_ACKDERR: 1077221345Sdim case FWOHCIEV_ACKTERR: 1078221345Sdim default: 1079221345Sdim device_printf(sc->fc.dev, "txd err=%2x %s\n", 1080221345Sdim stat, fwohcicode[stat]); 1081221345Sdim err = EINVAL; 1082221345Sdim break; 1083221345Sdim } 1084221345Sdim if (tr->xfer != NULL) { 1085221345Sdim xfer = tr->xfer; 1086221345Sdim if (xfer->state == FWXF_RCVD) { 1087221345Sdim if (firewire_debug) 1088249423Sdim printf("already rcvd\n"); 1089249423Sdim fw_xfer_done(xfer); 1090221345Sdim } else { 1091221345Sdim xfer->state = FWXF_SENT; 1092221345Sdim if (err == EBUSY && fc->status != FWBUSRESET) { 1093221345Sdim xfer->state = FWXF_BUSY; 1094221345Sdim xfer->resp = err; 1095249423Sdim if (xfer->retry_req != NULL) 1096210299Sed xfer->retry_req(xfer); 1097249423Sdim else { 1098193326Sed xfer->recv.len = 0; 1099193326Sed fw_xfer_done(xfer); 1100249423Sdim } 1101249423Sdim } else if (stat != FWOHCIEV_ACKPEND) { 1102193326Sed if (stat != FWOHCIEV_ACKCOMPL) 1103193326Sed xfer->state = FWXF_SENTERR; 1104249423Sdim xfer->resp = err; 1105221345Sdim xfer->recv.len = 0; 1106193326Sed fw_xfer_done(xfer); 1107221345Sdim } 1108243830Sdim } 1109243830Sdim /* 1110243830Sdim * The watchdog timer takes care of split 1111243830Sdim * transcation timeout for ACKPEND case. 1112243830Sdim */ 1113243830Sdim } else { 1114243830Sdim printf("this shouldn't happen\n"); 1115243830Sdim } 1116243830Sdim dbch->xferq.queued --; 1117243830Sdim tr->xfer = NULL; 1118243830Sdim 1119221345Sdim packets ++; 1120243830Sdim tr = STAILQ_NEXT(tr, link); 1121243830Sdim dbch->bottom = tr; 1122243830Sdim if (dbch->bottom == dbch->top) { 1123243830Sdim /* we reaches the end of context program */ 1124243830Sdim if (firewire_debug && dbch->xferq.queued > 0) 1125243830Sdim printf("queued > 0\n"); 1126243830Sdim break; 1127243830Sdim } 1128243830Sdim } 1129243830Sdimout: 1130243830Sdim if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { 1131243830Sdim printf("make free slot\n"); 1132221345Sdim dbch->flags &= ~FWOHCI_DBCH_FULL; 1133221345Sdim fwohci_start(sc, dbch); 1134193326Sed } 1135221345Sdim splx(s); 1136221345Sdim} 1137221345Sdim 1138221345Sdimstatic void 1139221345Sdimfwohci_db_free(struct fwohci_dbch *dbch) 1140221345Sdim{ 1141221345Sdim struct fwohcidb_tr *db_tr; 1142221345Sdim int idb; 1143221345Sdim 1144221345Sdim if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1145221345Sdim return; 1146221345Sdim 1147221345Sdim for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb; 1148193326Sed db_tr = STAILQ_NEXT(db_tr, link), idb++){ 1149221345Sdim if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 && 1150221345Sdim db_tr->buf != NULL) { 1151221345Sdim fwdma_free_size(dbch->dmat, db_tr->dma_map, 1152221345Sdim db_tr->buf, dbch->xferq.psize); 1153221345Sdim db_tr->buf = NULL; 1154221345Sdim } else if (db_tr->dma_map != NULL) 1155193326Sed bus_dmamap_destroy(dbch->dmat, db_tr->dma_map); 1156221345Sdim } 1157212904Sdim dbch->ndb = 0; 1158221345Sdim db_tr = STAILQ_FIRST(&dbch->db_trq); 1159221345Sdim fwdma_free_multiseg(dbch->am); 1160234353Sdim free(db_tr, M_FW); 1161234353Sdim STAILQ_INIT(&dbch->db_trq); 1162221345Sdim dbch->flags &= ~FWOHCI_DBCH_INIT; 1163221345Sdim} 1164221345Sdim 1165221345Sdimstatic void 1166221345Sdimfwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1167221345Sdim{ 1168221345Sdim int idb; 1169221345Sdim struct fwohcidb_tr *db_tr; 1170221345Sdim 1171221345Sdim if ((dbch->flags & FWOHCI_DBCH_INIT) != 0) 1172221345Sdim goto out; 1173198092Srdivacky 1174221345Sdim /* create dma_tag for buffers */ 1175226633Sdim#define MAX_REQCOUNT 0xffff 1176221345Sdim if (bus_dma_tag_create(/*parent*/ sc->fc.dmat, 1177198092Srdivacky /*alignment*/ 1, /*boundary*/ 0, 1178221345Sdim /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 1179221345Sdim /*highaddr*/ BUS_SPACE_MAXADDR, 1180198092Srdivacky /*filter*/NULL, /*filterarg*/NULL, 1181221345Sdim /*maxsize*/ dbch->xferq.psize, 1182221345Sdim /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1, 1183221345Sdim /*maxsegsz*/ MAX_REQCOUNT, 1184221345Sdim /*flags*/ 0, 1185224145Sdim#if __FreeBSD_version >= 501102 1186221345Sdim /*lockfunc*/busdma_lock_mutex, 1187221345Sdim /*lockarg*/&Giant, 1188221345Sdim#endif 1189193326Sed &dbch->dmat)) 1190193326Sed return; 1191193326Sed 1192202879Srdivacky /* allocate DB entries and attach one to each DMA channels */ 1193203955Srdivacky /* DB entry must start at 16 bytes bounary. */ 1194212904Sdim STAILQ_INIT(&dbch->db_trq); 1195202879Srdivacky db_tr = (struct fwohcidb_tr *) 1196203955Srdivacky malloc(sizeof(struct fwohcidb_tr) * dbch->ndb, 1197203955Srdivacky M_FW, M_WAITOK | M_ZERO); 1198203955Srdivacky if(db_tr == NULL){ 1199203955Srdivacky printf("fwohci_db_init: malloc(1) failed\n"); 1200203955Srdivacky return; 1201234353Sdim } 1202234353Sdim 1203234353Sdim#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc) 1204234353Sdim dbch->am = fwdma_malloc_multiseg(&sc->fc, DB_SIZE(dbch), 1205234353Sdim DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK); 1206234353Sdim if (dbch->am == NULL) { 1207234353Sdim printf("fwohci_db_init: fwdma_malloc_multiseg failed\n"); 1208234353Sdim return; 1209234353Sdim } 1210234353Sdim /* Attach DB to DMA ch. */ 1211234353Sdim for(idb = 0 ; idb < dbch->ndb ; idb++){ 1212234353Sdim db_tr->dbcnt = 0; 1213234353Sdim db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb); 1214234353Sdim db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb); 1215234353Sdim /* create dmamap for buffers */ 1216193326Sed /* XXX do we need 4bytes alignment tag? */ 1217234353Sdim /* XXX don't alloc dma_map for AR */ 1218193326Sed if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) { 1219193326Sed printf("bus_dmamap_create failed\n"); 1220193326Sed dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */ 1221234353Sdim fwohci_db_free(dbch); 1222193326Sed return; 1223203955Srdivacky } 1224203955Srdivacky STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); 1225203955Srdivacky if (dbch->xferq.flag & FWXFERQ_EXTBUF) { 1226193326Sed if (idb % dbch->xferq.bnpacket == 0) 1227193326Sed dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1228193326Sed ].start = (caddr_t)db_tr; 1229193326Sed if ((idb + 1) % dbch->xferq.bnpacket == 0) 1230193326Sed dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket 1231193326Sed ].end = (caddr_t)db_tr; 1232221345Sdim } 1233221345Sdim db_tr++; 1234208600Srdivacky } 1235193326Sed STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next 1236193326Sed = STAILQ_FIRST(&dbch->db_trq); 1237193326Sedout: 1238193326Sed dbch->xferq.queued = 0; 1239193326Sed dbch->pdb_tr = NULL; 1240193326Sed dbch->top = STAILQ_FIRST(&dbch->db_trq); 1241198092Srdivacky dbch->bottom = dbch->top; 1242198092Srdivacky dbch->flags = FWOHCI_DBCH_INIT; 1243223017Sdim} 1244234353Sdim 1245203955Srdivackystatic int 1246223017Sdimfwohci_itx_disable(struct firewire_comm *fc, int dmach) 1247223017Sdim{ 1248203955Srdivacky struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1249203955Srdivacky int sleepch; 1250203955Srdivacky 1251203955Srdivacky OWRITE(sc, OHCI_ITCTLCLR(dmach), 1252203955Srdivacky OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S); 1253193326Sed OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1254249423Sdim OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1255207619Srdivacky /* XXX we cannot free buffers until the DMA really stops */ 1256207619Srdivacky tsleep((void *)&sleepch, FWPRI, "fwitxd", hz); 1257193326Sed fwohci_db_free(&sc->it[dmach]); 1258193326Sed sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1259221345Sdim return 0; 1260221345Sdim} 1261224145Sdim 1262193326Sedstatic int 1263234353Sdimfwohci_irx_disable(struct firewire_comm *fc, int dmach) 1264193326Sed{ 1265193326Sed struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1266193326Sed int sleepch; 1267193326Sed 1268193326Sed OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1269193326Sed OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1270226633Sdim OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1271193326Sed /* XXX we cannot free buffers until the DMA really stops */ 1272193326Sed tsleep((void *)&sleepch, FWPRI, "fwirxd", hz); 1273226633Sdim fwohci_db_free(&sc->ir[dmach]); 1274193326Sed sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; 1275207619Srdivacky return 0; 1276193326Sed} 1277193326Sed 1278193326Sed#if BYTE_ORDER == BIG_ENDIAN 1279193326Sedstatic void 1280198092Srdivackyfwohci_irx_post (struct firewire_comm *fc , u_int32_t *qld) 1281198092Srdivacky{ 1282193326Sed qld[0] = FWOHCI_DMA_READ(qld[0]); 1283193326Sed return; 1284193326Sed} 1285193326Sed#endif 1286193326Sed 1287193326Sedstatic int 1288193326Sedfwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1289193326Sed{ 1290193326Sed int err = 0; 1291193326Sed int idb, z, i, dmach = 0, ldesc; 1292193326Sed u_int32_t off = NULL; 1293193326Sed struct fwohcidb_tr *db_tr; 1294193326Sed volatile struct fwohcidb *db; 1295193326Sed 1296193326Sed if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ 1297193326Sed err = EINVAL; 1298193326Sed return err; 1299193326Sed } 1300207619Srdivacky z = dbch->ndesc; 1301198092Srdivacky for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 1302224145Sdim if( &sc->it[dmach] == dbch){ 1303193326Sed off = OHCI_ITOFF(dmach); 1304207619Srdivacky break; 1305193326Sed } 1306207619Srdivacky } 1307193326Sed if(off == NULL){ 1308224145Sdim err = EINVAL; 1309198092Srdivacky return err; 1310207619Srdivacky } 1311193326Sed if(dbch->xferq.flag & FWXFERQ_RUNNING) 1312207619Srdivacky return err; 1313207619Srdivacky dbch->xferq.flag |= FWXFERQ_RUNNING; 1314193326Sed for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ 1315221345Sdim dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1316221345Sdim } 1317193326Sed db_tr = dbch->top; 1318263508Sdim for (idb = 0; idb < dbch->ndb; idb ++) { 1319234353Sdim fwohci_add_tx_buf(dbch, db_tr, idb); 1320207619Srdivacky if(STAILQ_NEXT(db_tr, link) == NULL){ 1321207619Srdivacky break; 1322207619Srdivacky } 1323207619Srdivacky db = db_tr->db; 1324207619Srdivacky ldesc = db_tr->dbcnt - 1; 1325207619Srdivacky FWOHCI_DMA_WRITE(db[0].db.desc.depend, 1326221345Sdim STAILQ_NEXT(db_tr, link)->bus_addr | z); 1327193326Sed db[ldesc].db.desc.depend = db[0].db.desc.depend; 1328207619Srdivacky if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 1329234353Sdim if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ 1330207619Srdivacky FWOHCI_DMA_SET( 1331207619Srdivacky db[ldesc].db.desc.cmd, 1332193326Sed OHCI_INTERRUPT_ALWAYS); 1333193326Sed /* OHCI 1.1 and above */ 1334198092Srdivacky FWOHCI_DMA_SET( 1335221345Sdim db[0].db.desc.cmd, 1336221345Sdim OHCI_INTERRUPT_ALWAYS); 1337208600Srdivacky } 1338193326Sed } 1339193326Sed db_tr = STAILQ_NEXT(db_tr, link); 1340193326Sed } 1341193326Sed FWOHCI_DMA_CLEAR( 1342207619Srdivacky dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf); 1343193326Sed return err; 1344223017Sdim} 1345223017Sdim 1346207619Srdivackystatic int 1347234353Sdimfwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1348203955Srdivacky{ 1349223017Sdim int err = 0; 1350223017Sdim int idb, z, i, dmach = 0, ldesc; 1351203955Srdivacky u_int32_t off = NULL; 1352203955Srdivacky struct fwohcidb_tr *db_tr; 1353203955Srdivacky volatile struct fwohcidb *db; 1354203955Srdivacky 1355203955Srdivacky z = dbch->ndesc; 1356207619Srdivacky if(&sc->arrq == dbch){ 1357207619Srdivacky off = OHCI_ARQOFF; 1358207619Srdivacky }else if(&sc->arrs == dbch){ 1359207619Srdivacky off = OHCI_ARSOFF; 1360207619Srdivacky }else{ 1361207619Srdivacky for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 1362207619Srdivacky if( &sc->ir[dmach] == dbch){ 1363207619Srdivacky off = OHCI_IROFF(dmach); 1364207619Srdivacky break; 1365207619Srdivacky } 1366221345Sdim } 1367221345Sdim } 1368221345Sdim if(off == NULL){ 1369221345Sdim err = EINVAL; 1370207619Srdivacky return err; 1371207619Srdivacky } 1372207619Srdivacky if(dbch->xferq.flag & FWXFERQ_STREAM){ 1373208600Srdivacky if(dbch->xferq.flag & FWXFERQ_RUNNING) 1374207619Srdivacky return err; 1375207619Srdivacky }else{ 1376207619Srdivacky if(dbch->xferq.flag & FWXFERQ_RUNNING){ 1377207619Srdivacky err = EBUSY; 1378208600Srdivacky return err; 1379207619Srdivacky } 1380207619Srdivacky } 1381207619Srdivacky dbch->xferq.flag |= FWXFERQ_RUNNING; 1382208600Srdivacky dbch->top = STAILQ_FIRST(&dbch->db_trq); 1383207619Srdivacky for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ 1384207619Srdivacky dbch->bottom = STAILQ_NEXT(dbch->bottom, link); 1385207619Srdivacky } 1386198092Srdivacky db_tr = dbch->top; 1387193326Sed for (idb = 0; idb < dbch->ndb; idb ++) { 1388193326Sed fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma); 1389249423Sdim if (STAILQ_NEXT(db_tr, link) == NULL) 1390193326Sed break; 1391249423Sdim db = db_tr->db; 1392221345Sdim ldesc = db_tr->dbcnt - 1; 1393221345Sdim FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend, 1394221345Sdim STAILQ_NEXT(db_tr, link)->bus_addr | z); 1395221345Sdim if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 1396221345Sdim if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ 1397221345Sdim FWOHCI_DMA_SET( 1398221345Sdim db[ldesc].db.desc.cmd, 1399221345Sdim OHCI_INTERRUPT_ALWAYS); 1400221345Sdim FWOHCI_DMA_CLEAR( 1401221345Sdim db[ldesc].db.desc.depend, 1402193326Sed 0xf); 1403221345Sdim } 1404221345Sdim } 1405224145Sdim db_tr = STAILQ_NEXT(db_tr, link); 1406193326Sed } 1407234353Sdim FWOHCI_DMA_CLEAR( 1408193326Sed dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf); 1409234353Sdim dbch->buf_offset = 0; 1410234353Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1411207619Srdivacky fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1412234353Sdim if(dbch->xferq.flag & FWXFERQ_STREAM){ 1413234353Sdim return err; 1414234353Sdim }else{ 1415234353Sdim OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z); 1416234353Sdim } 1417263508Sdim OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); 1418234353Sdim return err; 1419234353Sdim} 1420234353Sdim 1421234353Sdimstatic int 1422234353Sdimfwohci_next_cycle(struct firewire_comm *fc, int cycle_now) 1423234353Sdim{ 1424234353Sdim int sec, cycle, cycle_match; 1425234353Sdim 1426234353Sdim cycle = cycle_now & 0x1fff; 1427234353Sdim sec = cycle_now >> 13; 1428234353Sdim#define CYCLE_MOD 0x10 1429234353Sdim#if 1 1430234353Sdim#define CYCLE_DELAY 8 /* min delay to start DMA */ 1431234353Sdim#else 1432234353Sdim#define CYCLE_DELAY 7000 /* min delay to start DMA */ 1433234353Sdim#endif 1434234353Sdim cycle = cycle + CYCLE_DELAY; 1435234353Sdim if (cycle >= 8000) { 1436234353Sdim sec ++; 1437234353Sdim cycle -= 8000; 1438234353Sdim } 1439234353Sdim cycle = roundup2(cycle, CYCLE_MOD); 1440207619Srdivacky if (cycle >= 8000) { 1441263508Sdim sec ++; 1442207619Srdivacky if (cycle == 8000) 1443193326Sed cycle = 0; 1444208600Srdivacky else 1445207619Srdivacky cycle = CYCLE_MOD; 1446208600Srdivacky } 1447208600Srdivacky cycle_match = ((sec << 13) | cycle) & 0x7ffff; 1448208600Srdivacky 1449207619Srdivacky return(cycle_match); 1450207619Srdivacky} 1451221345Sdim 1452207619Srdivackystatic int 1453207619Srdivackyfwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) 1454207619Srdivacky{ 1455207619Srdivacky struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1456207619Srdivacky int err = 0; 1457221345Sdim unsigned short tag, ich; 1458226633Sdim struct fwohci_dbch *dbch; 1459207619Srdivacky int cycle_match, cycle_now, s, ldesc; 1460207619Srdivacky u_int32_t stat; 1461207619Srdivacky struct fw_bulkxfer *first, *chunk, *prev; 1462207619Srdivacky struct fw_xferq *it; 1463207619Srdivacky 1464207619Srdivacky dbch = &sc->it[dmach]; 1465207619Srdivacky it = &dbch->xferq; 1466207619Srdivacky 1467207619Srdivacky tag = (it->flag >> 6) & 3; 1468221345Sdim ich = it->flag & 0x3f; 1469207619Srdivacky if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { 1470207619Srdivacky dbch->ndb = it->bnpacket * it->bnchunk; 1471207619Srdivacky dbch->ndesc = 3; 1472221345Sdim fwohci_db_init(sc, dbch); 1473207619Srdivacky if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1474207619Srdivacky return ENOMEM; 1475207619Srdivacky err = fwohci_tx_enable(sc, dbch); 1476207619Srdivacky } 1477207619Srdivacky if(err) 1478207619Srdivacky return err; 1479207619Srdivacky 1480193326Sed ldesc = dbch->ndesc - 1; 1481193326Sed s = splfw(); 1482198092Srdivacky prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); 1483193326Sed while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { 1484234353Sdim volatile struct fwohcidb *db; 1485234353Sdim 1486234353Sdim fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket, 1487234353Sdim BUS_DMASYNC_PREWRITE); 1488234353Sdim fwohci_txbufdb(sc, dmach, chunk); 1489234353Sdim if (prev != NULL) { 1490198092Srdivacky db = ((struct fwohcidb_tr *)(prev->end))->db; 1491198092Srdivacky#if 0 /* XXX necessary? */ 1492198092Srdivacky FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, 1493224145Sdim OHCI_BRANCH_ALWAYS); 1494193326Sed#endif 1495193326Sed#if 0 /* if bulkxfer->npacket changes */ 1496221345Sdim db[ldesc].db.desc.depend = db[0].db.desc.depend = 1497193326Sed ((struct fwohcidb_tr *) 1498193326Sed (chunk->start))->bus_addr | dbch->ndesc; 1499193326Sed#else 1500193326Sed FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 1501193326Sed FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1502221345Sdim#endif 1503193326Sed } 1504221345Sdim STAILQ_REMOVE_HEAD(&it->stvalid, link); 1505221345Sdim STAILQ_INSERT_TAIL(&it->stdma, chunk, link); 1506221345Sdim prev = chunk; 1507221345Sdim } 1508221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1509221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1510221345Sdim splx(s); 1511221345Sdim stat = OREAD(sc, OHCI_ITCTL(dmach)); 1512221345Sdim if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S)) 1513221345Sdim printf("stat 0x%x\n", stat); 1514193326Sed 1515193326Sed if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) 1516193326Sed return 0; 1517193326Sed 1518193326Sed#if 0 1519193326Sed OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1520193326Sed#endif 1521193326Sed OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); 1522193326Sed OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); 1523226633Sdim OWRITE(sc, OHCI_IT_MASK, 1 << dmach); 1524224145Sdim OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); 1525224145Sdim 1526198092Srdivacky first = STAILQ_FIRST(&it->stdma); 1527198092Srdivacky OWRITE(sc, OHCI_ITCMD(dmach), 1528193326Sed ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); 1529193326Sed if (firewire_debug) { 1530193326Sed printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); 1531193326Sed#if 1 1532193326Sed dump_dma(sc, ITX_CH + dmach); 1533193326Sed#endif 1534226633Sdim } 1535193326Sed if ((stat & OHCI_CNTL_DMA_RUN) == 0) { 1536198092Srdivacky#if 1 1537193326Sed /* Don't start until all chunks are buffered */ 1538193326Sed if (STAILQ_FIRST(&it->stfree) != NULL) 1539193326Sed goto out; 1540193326Sed#endif 1541193326Sed#if 1 1542234353Sdim /* Clear cycle match counter bits */ 1543234353Sdim OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); 1544234353Sdim 1545234353Sdim /* 2bit second + 13bit cycle */ 1546199482Srdivacky cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; 1547199482Srdivacky cycle_match = fwohci_next_cycle(fc, cycle_now); 1548198092Srdivacky 1549224145Sdim OWRITE(sc, OHCI_ITCTL(dmach), 1550193326Sed OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) 1551193326Sed | OHCI_CNTL_DMA_RUN); 1552193326Sed#else 1553193326Sed OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); 1554193326Sed#endif 1555193326Sed if (firewire_debug) { 1556193326Sed printf("cycle_match: 0x%04x->0x%04x\n", 1557193326Sed cycle_now, cycle_match); 1558198092Srdivacky dump_dma(sc, ITX_CH + dmach); 1559198092Srdivacky dump_db(sc, ITX_CH + dmach); 1560193326Sed } 1561193326Sed } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { 1562193326Sed device_printf(sc->fc.dev, 1563193326Sed "IT DMA underrun (0x%08x)\n", stat); 1564193326Sed OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE); 1565193326Sed } 1566193326Sedout: 1567193326Sed return err; 1568198092Srdivacky} 1569193326Sed 1570193326Sedstatic int 1571193326Sedfwohci_irx_enable(struct firewire_comm *fc, int dmach) 1572193326Sed{ 1573224145Sdim struct fwohci_softc *sc = (struct fwohci_softc *)fc; 1574193326Sed int err = 0, s, ldesc; 1575193326Sed unsigned short tag, ich; 1576193326Sed u_int32_t stat; 1577193326Sed struct fwohci_dbch *dbch; 1578193326Sed struct fwohcidb_tr *db_tr; 1579193326Sed struct fw_bulkxfer *first, *prev, *chunk; 1580193326Sed struct fw_xferq *ir; 1581193326Sed 1582193326Sed dbch = &sc->ir[dmach]; 1583193326Sed ir = &dbch->xferq; 1584193326Sed 1585193326Sed if ((ir->flag & FWXFERQ_RUNNING) == 0) { 1586193326Sed tag = (ir->flag >> 6) & 3; 1587193326Sed ich = ir->flag & 0x3f; 1588193326Sed OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); 1589193326Sed 1590193326Sed ir->queued = 0; 1591198092Srdivacky dbch->ndb = ir->bnpacket * ir->bnchunk; 1592198092Srdivacky dbch->ndesc = 2; 1593207619Srdivacky fwohci_db_init(sc, dbch); 1594226633Sdim if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1595226633Sdim return ENOMEM; 1596207619Srdivacky err = fwohci_rx_enable(sc, dbch); 1597193326Sed } 1598193326Sed if(err) 1599193326Sed return err; 1600198092Srdivacky 1601198092Srdivacky first = STAILQ_FIRST(&ir->stfree); 1602198092Srdivacky if (first == NULL) { 1603198092Srdivacky device_printf(fc->dev, "IR DMA no free chunk\n"); 1604224145Sdim return 0; 1605234353Sdim } 1606193326Sed 1607193326Sed ldesc = dbch->ndesc - 1; 1608193326Sed s = splfw(); 1609193326Sed prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); 1610193326Sed while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { 1611193326Sed volatile struct fwohcidb *db; 1612193326Sed 1613198092Srdivacky#if 1 /* XXX for if_fwe */ 1614193326Sed if (chunk->mbuf != NULL) { 1615193326Sed db_tr = (struct fwohcidb_tr *)(chunk->start); 1616193326Sed db_tr->dbcnt = 1; 1617193326Sed err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, 1618193326Sed chunk->mbuf, fwohci_execute_db2, db_tr, 1619198092Srdivacky /* flags */0); 1620198092Srdivacky FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd, 1621198092Srdivacky OHCI_UPDATE | OHCI_INPUT_LAST | 1622198092Srdivacky OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); 1623228379Sdim } 1624228379Sdim#endif 1625193326Sed db = ((struct fwohcidb_tr *)(chunk->end))->db; 1626193326Sed FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0); 1627193326Sed FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf); 1628193326Sed if (prev != NULL) { 1629193326Sed db = ((struct fwohcidb_tr *)(prev->end))->db; 1630193326Sed FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); 1631193326Sed } 1632193326Sed STAILQ_REMOVE_HEAD(&ir->stfree, link); 1633193326Sed STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); 1634219077Sdim prev = chunk; 1635243830Sdim } 1636221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 1637221345Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); 1638221345Sdim splx(s); 1639221345Sdim stat = OREAD(sc, OHCI_IRCTL(dmach)); 1640219077Sdim if (stat & OHCI_CNTL_DMA_ACTIVE) 1641219077Sdim return 0; 1642193326Sed if (stat & OHCI_CNTL_DMA_RUN) { 1643193326Sed OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); 1644198092Srdivacky device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); 1645198092Srdivacky } 1646198092Srdivacky 1647193326Sed if (firewire_debug) 1648198092Srdivacky printf("start IR DMA 0x%x\n", stat); 1649226633Sdim OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); 1650198092Srdivacky OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); 1651198092Srdivacky OWRITE(sc, OHCI_IR_MASK, 1 << dmach); 1652226633Sdim OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); 1653226633Sdim OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); 1654193326Sed OWRITE(sc, OHCI_IRCMD(dmach), 1655202379Srdivacky ((struct fwohcidb_tr *)(first->start))->bus_addr 1656234353Sdim | dbch->ndesc); 1657234353Sdim OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); 1658234353Sdim OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); 1659234353Sdim#if 0 1660234353Sdim dump_db(sc, IRX_CH + dmach); 1661234353Sdim#endif 1662234353Sdim return err; 1663234353Sdim} 1664234353Sdim 1665234353Sdimint 1666234353Sdimfwohci_stop(struct fwohci_softc *sc, device_t dev) 1667234353Sdim{ 1668234353Sdim u_int i; 1669234353Sdim 1670193326Sed/* Now stopping all DMA channel */ 1671193326Sed OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); 1672234353Sdim OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); 1673234353Sdim OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1674234353Sdim OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1675198092Srdivacky 1676224145Sdim for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ 1677193326Sed OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); 1678193326Sed OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); 1679193326Sed } 1680193326Sed 1681193326Sed/* FLUSH FIFO and reset Transmitter/Reciever */ 1682193326Sed OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); 1683193326Sed 1684198092Srdivacky/* Stop interrupt */ 1685198092Srdivacky OWRITE(sc, FWOHCI_INTMASKCLR, 1686193326Sed OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID 1687193326Sed | OHCI_INT_PHY_INT 1688193326Sed | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 1689193326Sed | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS 1690198092Srdivacky | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 1691198092Srdivacky | OHCI_INT_PHY_BUS_R); 1692224145Sdim 1693193326Sed fw_drain_txq(&sc->fc); 1694193326Sed 1695193326Sed/* XXX Link down? Bus reset? */ 1696193326Sed return 0; 1697193326Sed} 1698193326Sed 1699198092Srdivackyint 1700193326Sedfwohci_resume(struct fwohci_softc *sc, device_t dev) 1701234353Sdim{ 1702193326Sed int i; 1703193326Sed struct fw_xferq *ir; 1704224145Sdim struct fw_bulkxfer *chunk; 1705193326Sed 1706218893Sdim fwohci_reset(sc, dev); 1707193326Sed /* XXX resume isochronus receive automatically. (how about TX?) */ 1708193326Sed for(i = 0; i < sc->fc.nisodma; i ++) { 1709198092Srdivacky ir = &sc->ir[i].xferq; 1710193326Sed if((ir->flag & FWXFERQ_RUNNING) != 0) { 1711193326Sed device_printf(sc->fc.dev, 1712199990Srdivacky "resume iso receive ch: %d\n", i); 1713199990Srdivacky ir->flag &= ~FWXFERQ_RUNNING; 1714199990Srdivacky /* requeue stdma to stfree */ 1715199990Srdivacky while((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 1716193326Sed STAILQ_REMOVE_HEAD(&ir->stdma, link); 1717199990Srdivacky STAILQ_INSERT_TAIL(&ir->stfree, chunk, link); 1718199990Srdivacky } 1719199990Srdivacky sc->fc.irx_enable(&sc->fc, i); 1720198092Srdivacky } 1721198092Srdivacky } 1722193326Sed 1723193326Sed bus_generic_resume(dev); 1724193326Sed sc->fc.ibr(&sc->fc); 1725193326Sed return 0; 1726193326Sed} 1727193326Sed 1728193326Sed#define ACK_ALL 1729193326Sedstatic void 1730193326Sedfwohci_intr_body(struct fwohci_softc *sc, u_int32_t stat, int count) 1731193326Sed{ 1732193326Sed u_int32_t irstat, itstat; 1733249423Sdim u_int i; 1734193326Sed struct firewire_comm *fc = (struct firewire_comm *)sc; 1735193326Sed 1736226633Sdim#ifdef OHCI_DEBUG 1737193326Sed if(stat & OREAD(sc, FWOHCI_INTMASK)) 1738249423Sdim 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", 1739193326Sed stat & OHCI_INT_EN ? "DMA_EN ":"", 1740193326Sed stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", 1741193326Sed stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", 1742193326Sed stat & OHCI_INT_ERR ? "INT_ERR ":"", 1743226633Sdim stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", 1744226633Sdim stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", 1745193326Sed stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", 1746193326Sed stat & OHCI_INT_CYC_START ? "CYC_START ":"", 1747198092Srdivacky stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", 1748193326Sed stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", 1749193326Sed stat & OHCI_INT_PHY_SID ? "SID ":"", 1750193326Sed stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", 1751224145Sdim stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", 1752193326Sed stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", 1753193326Sed stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", 1754198092Srdivacky stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", 1755198092Srdivacky stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", 1756198092Srdivacky stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", 1757198092Srdivacky stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", 1758193326Sed stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", 1759198092Srdivacky stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", 1760193326Sed stat, OREAD(sc, FWOHCI_INTMASK) 1761193326Sed ); 1762193326Sed#endif 1763226633Sdim/* Bus reset */ 1764193326Sed if(stat & OHCI_INT_PHY_BUS_R ){ 1765193326Sed if (fc->status == FWBUSRESET) 1766198092Srdivacky goto busresetout; 1767198092Srdivacky /* Disable bus reset interrupt until sid recv. */ 1768198092Srdivacky OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); 1769198092Srdivacky 1770193326Sed device_printf(fc->dev, "BUS reset\n"); 1771193326Sed OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); 1772193326Sed OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); 1773193326Sed 1774193326Sed OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); 1775193326Sed sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; 1776234353Sdim OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); 1777234353Sdim sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; 1778234353Sdim 1779234353Sdim#ifndef ACK_ALL 1780234353Sdim OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); 1781226633Sdim#endif 1782193326Sed fw_busreset(fc); 1783193326Sed OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); 1784193326Sed OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); 1785226633Sdim } 1786226633Sdimbusresetout: 1787226633Sdim if((stat & OHCI_INT_DMA_IR )){ 1788226633Sdim#ifndef ACK_ALL 1789195341Sed OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR); 1790195341Sed#endif 1791193326Sed#if __FreeBSD_version >= 500000 1792193326Sed irstat = atomic_readandclear_int(&sc->irstat); 1793198092Srdivacky#else 1794243830Sdim irstat = sc->irstat; 1795243830Sdim sc->irstat = 0; 1796243830Sdim#endif 1797243830Sdim for(i = 0; i < fc->nisodma ; i++){ 1798198092Srdivacky struct fwohci_dbch *dbch; 1799198092Srdivacky 1800198092Srdivacky if((irstat & (1 << i)) != 0){ 1801198092Srdivacky dbch = &sc->ir[i]; 1802193326Sed if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) { 1803193326Sed device_printf(sc->fc.dev, 1804226633Sdim "dma(%d) not active\n", i); 1805226633Sdim continue; 1806226633Sdim } 1807226633Sdim fwohci_rbuf_update(sc, i); 1808198092Srdivacky } 1809195341Sed } 1810195341Sed } 1811193326Sed if((stat & OHCI_INT_DMA_IT )){ 1812193326Sed#ifndef ACK_ALL 1813198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT); 1814243830Sdim#endif 1815243830Sdim#if __FreeBSD_version >= 500000 1816243830Sdim itstat = atomic_readandclear_int(&sc->itstat); 1817243830Sdim#else 1818198092Srdivacky itstat = sc->itstat; 1819198092Srdivacky sc->itstat = 0; 1820198092Srdivacky#endif 1821198092Srdivacky for(i = 0; i < fc->nisodma ; i++){ 1822193326Sed if((itstat & (1 << i)) != 0){ 1823193326Sed fwohci_tbuf_update(sc, i); 1824193326Sed } 1825193326Sed } 1826193326Sed } 1827193326Sed if((stat & OHCI_INT_DMA_PRRS )){ 1828193326Sed#ifndef ACK_ALL 1829198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS); 1830198092Srdivacky#endif 1831198092Srdivacky#if 0 1832198092Srdivacky dump_dma(sc, ARRS_CH); 1833198092Srdivacky dump_db(sc, ARRS_CH); 1834198092Srdivacky#endif 1835198092Srdivacky fwohci_arcv(sc, &sc->arrs, count); 1836198092Srdivacky } 1837198092Srdivacky if((stat & OHCI_INT_DMA_PRRQ )){ 1838198092Srdivacky#ifndef ACK_ALL 1839198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ); 1840198092Srdivacky#endif 1841224145Sdim#if 0 1842249423Sdim dump_dma(sc, ARRQ_CH); 1843249423Sdim dump_db(sc, ARRQ_CH); 1844198092Srdivacky#endif 1845198092Srdivacky fwohci_arcv(sc, &sc->arrq, count); 1846198092Srdivacky } 1847198092Srdivacky if(stat & OHCI_INT_PHY_SID){ 1848198092Srdivacky u_int32_t *buf, node_id; 1849198092Srdivacky int plen; 1850198092Srdivacky 1851198092Srdivacky#ifndef ACK_ALL 1852198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID); 1853239462Sdim#endif 1854198092Srdivacky /* Enable bus reset interrupt */ 1855249423Sdim OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); 1856249423Sdim /* Allow async. request to us */ 1857243830Sdim OWRITE(sc, OHCI_AREQHI, 1 << 31); 1858198092Srdivacky /* XXX insecure ?? */ 1859198092Srdivacky OWRITE(sc, OHCI_PREQHI, 0x7fffffff); 1860198092Srdivacky OWRITE(sc, OHCI_PREQLO, 0xffffffff); 1861198092Srdivacky OWRITE(sc, OHCI_PREQUPPER, 0x10000); 1862198092Srdivacky /* Set ATRetries register */ 1863198092Srdivacky OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff); 1864198092Srdivacky/* 1865198092Srdivacky** Checking whether the node is root or not. If root, turn on 1866198092Srdivacky** cycle master. 1867198092Srdivacky*/ 1868198092Srdivacky node_id = OREAD(sc, FWOHCI_NODEID); 1869198092Srdivacky plen = OREAD(sc, OHCI_SID_CNT); 1870198092Srdivacky 1871198092Srdivacky device_printf(fc->dev, "node_id=0x%08x, gen=%d, ", 1872198092Srdivacky node_id, (plen >> 16) & 0xff); 1873198092Srdivacky if (!(node_id & OHCI_NODE_VALID)) { 1874198092Srdivacky printf("Bus reset failure\n"); 1875198092Srdivacky goto sidout; 1876198092Srdivacky } 1877198092Srdivacky if (node_id & OHCI_NODE_ROOT) { 1878198092Srdivacky printf("CYCLEMASTER mode\n"); 1879198092Srdivacky OWRITE(sc, OHCI_LNKCTL, 1880198092Srdivacky OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); 1881198092Srdivacky } else { 1882198092Srdivacky printf("non CYCLEMASTER mode\n"); 1883198092Srdivacky OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); 1884198092Srdivacky OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); 1885198092Srdivacky } 1886198092Srdivacky fc->nodeid = node_id & 0x3f; 1887198092Srdivacky 1888198092Srdivacky if (plen & OHCI_SID_ERR) { 1889198092Srdivacky device_printf(fc->dev, "SID Error\n"); 1890198092Srdivacky goto sidout; 1891198092Srdivacky } 1892224145Sdim plen &= OHCI_SID_CNT_MASK; 1893198092Srdivacky if (plen < 4 || plen > OHCI_SIDSIZE) { 1894198092Srdivacky device_printf(fc->dev, "invalid SID len = %d\n", plen); 1895198092Srdivacky goto sidout; 1896198092Srdivacky } 1897198092Srdivacky plen -= 4; /* chop control info */ 1898198092Srdivacky buf = (u_int32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); 1899198092Srdivacky if (buf == NULL) { 1900198092Srdivacky device_printf(fc->dev, "malloc failed\n"); 1901198092Srdivacky goto sidout; 1902198092Srdivacky } 1903198092Srdivacky for (i = 0; i < plen / 4; i ++) 1904198092Srdivacky buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]); 1905224145Sdim#if 1 1906198092Srdivacky /* pending all pre-bus_reset packets */ 1907198092Srdivacky fwohci_txd(sc, &sc->atrq); 1908198092Srdivacky fwohci_txd(sc, &sc->atrs); 1909198092Srdivacky fwohci_arcv(sc, &sc->arrs, -1); 1910198092Srdivacky fwohci_arcv(sc, &sc->arrq, -1); 1911193326Sed fw_drain_txq(fc); 1912193326Sed#endif 1913224145Sdim fw_sidrcv(fc, buf, plen); 1914193326Sed free(buf, M_FW); 1915193326Sed } 1916193326Sedsidout: 1917193326Sed if((stat & OHCI_INT_DMA_ATRQ )){ 1918198092Srdivacky#ifndef ACK_ALL 1919198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ); 1920198092Srdivacky#endif 1921198092Srdivacky fwohci_txd(sc, &(sc->atrq)); 1922193326Sed } 1923198092Srdivacky if((stat & OHCI_INT_DMA_ATRS )){ 1924193326Sed#ifndef ACK_ALL 1925193326Sed OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS); 1926193326Sed#endif 1927226633Sdim fwohci_txd(sc, &(sc->atrs)); 1928193326Sed } 1929193326Sed if((stat & OHCI_INT_PW_ERR )){ 1930193326Sed#ifndef ACK_ALL 1931193326Sed OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR); 1932198092Srdivacky#endif 1933198092Srdivacky device_printf(fc->dev, "posted write error\n"); 1934198092Srdivacky } 1935198092Srdivacky if((stat & OHCI_INT_ERR )){ 1936198092Srdivacky#ifndef ACK_ALL 1937193326Sed OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR); 1938193326Sed#endif 1939193326Sed device_printf(fc->dev, "unrecoverable error\n"); 1940249423Sdim } 1941198092Srdivacky if((stat & OHCI_INT_PHY_INT)) { 1942226633Sdim#ifndef ACK_ALL 1943226633Sdim OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT); 1944193326Sed#endif 1945198092Srdivacky device_printf(fc->dev, "phy int\n"); 1946198092Srdivacky } 1947198092Srdivacky 1948198092Srdivacky return; 1949198092Srdivacky} 1950198092Srdivacky 1951198092Srdivacky#if FWOHCI_TASKQUEUE 1952198092Srdivackystatic void 1953198092Srdivackyfwohci_complete(void *arg, int pending) 1954198092Srdivacky{ 1955198092Srdivacky struct fwohci_softc *sc = (struct fwohci_softc *)arg; 1956198092Srdivacky u_int32_t stat; 1957198092Srdivacky 1958198092Srdivackyagain: 1959224145Sdim stat = atomic_readandclear_int(&sc->intstat); 1960198092Srdivacky if (stat) 1961218893Sdim fwohci_intr_body(sc, stat, -1); 1962198092Srdivacky else 1963198092Srdivacky return; 1964198092Srdivacky goto again; 1965198092Srdivacky} 1966198092Srdivacky#endif 1967198092Srdivacky 1968198092Srdivackystatic u_int32_t 1969198092Srdivackyfwochi_check_stat(struct fwohci_softc *sc) 1970198092Srdivacky{ 1971198092Srdivacky u_int32_t stat, irstat, itstat; 1972198092Srdivacky 1973198092Srdivacky stat = OREAD(sc, FWOHCI_INTSTAT); 1974198092Srdivacky if (stat == 0xffffffff) { 1975198092Srdivacky device_printf(sc->fc.dev, 1976198092Srdivacky "device physically ejected?\n"); 1977198092Srdivacky return(stat); 1978198092Srdivacky } 1979198092Srdivacky#ifdef ACK_ALL 1980198092Srdivacky if (stat) 1981198092Srdivacky OWRITE(sc, FWOHCI_INTSTATCLR, stat); 1982224145Sdim#endif 1983198092Srdivacky if (stat & OHCI_INT_DMA_IR) { 1984198092Srdivacky irstat = OREAD(sc, OHCI_IR_STAT); 1985198092Srdivacky OWRITE(sc, OHCI_IR_STATCLR, irstat); 1986226633Sdim atomic_set_int(&sc->irstat, irstat); 1987226633Sdim } 1988226633Sdim if (stat & OHCI_INT_DMA_IT) { 1989226633Sdim itstat = OREAD(sc, OHCI_IT_STAT); 1990226633Sdim OWRITE(sc, OHCI_IT_STATCLR, itstat); 1991226633Sdim atomic_set_int(&sc->itstat, itstat); 1992226633Sdim } 1993226633Sdim return(stat); 1994226633Sdim} 1995226633Sdim 1996226633Sdimvoid 1997234353Sdimfwohci_intr(void *arg) 1998226633Sdim{ 1999228379Sdim struct fwohci_softc *sc = (struct fwohci_softc *)arg; 2000228379Sdim u_int32_t stat; 2001228379Sdim#if !FWOHCI_TASKQUEUE 2002226633Sdim u_int32_t bus_reset = 0; 2003226633Sdim#endif 2004226633Sdim 2005226633Sdim if (!(sc->intmask & OHCI_INT_EN)) { 2006228379Sdim /* polling mode */ 2007226633Sdim return; 2008249423Sdim } 2009226633Sdim 2010226633Sdim#if !FWOHCI_TASKQUEUE 2011226633Sdimagain: 2012226633Sdim#endif 2013226633Sdim stat = fwochi_check_stat(sc); 2014226633Sdim if (stat == 0 || stat == 0xffffffff) 2015226633Sdim return; 2016226633Sdim#if FWOHCI_TASKQUEUE 2017226633Sdim atomic_set_int(&sc->intstat, stat); 2018226633Sdim /* XXX mask bus reset intr. during bus reset phase */ 2019226633Sdim if (stat) 2020226633Sdim taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete); 2021226633Sdim#else 2022226633Sdim /* We cannot clear bus reset event during bus reset phase */ 2023226633Sdim if ((stat & ~bus_reset) == 0) 2024226633Sdim return; 2025226633Sdim bus_reset = stat & OHCI_INT_PHY_BUS_R; 2026226633Sdim fwohci_intr_body(sc, stat, -1); 2027226633Sdim goto again; 2028226633Sdim#endif 2029193326Sed} 2030193326Sed 2031193326Sedvoid 2032193326Sedfwohci_poll(struct firewire_comm *fc, int quick, int count) 2033226633Sdim{ 2034226633Sdim int s; 2035193326Sed u_int32_t stat; 2036195341Sed struct fwohci_softc *sc; 2037193326Sed 2038193326Sed 2039193326Sed sc = (struct fwohci_softc *)fc; 2040193326Sed stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT | 2041198092Srdivacky OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ | 2042193326Sed OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS; 2043193326Sed#if 0 2044193326Sed if (!quick) { 2045226633Sdim#else 2046226633Sdim if (1) { 2047198092Srdivacky#endif 2048195341Sed stat = fwochi_check_stat(sc); 2049193326Sed if (stat == 0 || stat == 0xffffffff) 2050193326Sed return; 2051193326Sed } 2052193326Sed s = splfw(); 2053198092Srdivacky fwohci_intr_body(sc, stat, count); 2054193326Sed splx(s); 2055193326Sed} 2056193326Sed 2057226633Sdimstatic void 2058205219Srdivackyfwohci_set_intr(struct firewire_comm *fc, int enable) 2059205219Srdivacky{ 2060193326Sed struct fwohci_softc *sc; 2061193326Sed 2062193326Sed sc = (struct fwohci_softc *)fc; 2063193326Sed if (bootverbose) 2064193326Sed device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable); 2065193326Sed if (enable) { 2066193326Sed sc->intmask |= OHCI_INT_EN; 2067198092Srdivacky OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); 2068193326Sed } else { 2069193326Sed sc->intmask &= ~OHCI_INT_EN; 2070193326Sed OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); 2071193326Sed } 2072193326Sed} 2073193326Sed 2074193326Sedstatic void 2075193326Sedfwohci_tbuf_update(struct fwohci_softc *sc, int dmach) 2076193326Sed{ 2077193326Sed struct firewire_comm *fc = &sc->fc; 2078193326Sed volatile struct fwohcidb *db; 2079224145Sdim struct fw_bulkxfer *chunk; 2080198092Srdivacky struct fw_xferq *it; 2081193326Sed u_int32_t stat, count; 2082193326Sed int s, w=0, ldesc; 2083198092Srdivacky 2084226633Sdim it = fc->it[dmach]; 2085226633Sdim ldesc = sc->it[dmach].ndesc - 1; 2086198092Srdivacky s = splfw(); /* unnecessary ? */ 2087249423Sdim fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); 2088249423Sdim while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { 2089224145Sdim db = ((struct fwohcidb_tr *)(chunk->end))->db; 2090249423Sdim stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2091249423Sdim >> OHCI_STATUS_SHIFT; 2092198092Srdivacky db = ((struct fwohcidb_tr *)(chunk->start))->db; 2093198092Srdivacky count = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 2094198092Srdivacky & OHCI_COUNT_MASK; 2095198092Srdivacky if (stat == 0) 2096198092Srdivacky break; 2097198092Srdivacky STAILQ_REMOVE_HEAD(&it->stdma, link); 2098198092Srdivacky switch (stat & FWOHCIEV_MASK){ 2099198092Srdivacky case FWOHCIEV_ACKCOMPL: 2100239462Sdim#if 0 2101204643Srdivacky device_printf(fc->dev, "0x%08x\n", count); 2102204643Srdivacky#endif 2103204643Srdivacky break; 2104249423Sdim default: 2105249423Sdim device_printf(fc->dev, 2106198092Srdivacky "Isochronous transmit err %02x(%s)\n", 2107243830Sdim stat, fwohcicode[stat & 0x1f]); 2108249423Sdim } 2109198092Srdivacky STAILQ_INSERT_TAIL(&it->stfree, chunk, link); 2110198092Srdivacky w++; 2111198092Srdivacky } 2112198092Srdivacky splx(s); 2113204643Srdivacky if (w) 2114204643Srdivacky wakeup(it); 2115204643Srdivacky} 2116204643Srdivacky 2117198092Srdivackystatic void 2118198092Srdivackyfwohci_rbuf_update(struct fwohci_softc *sc, int dmach) 2119198092Srdivacky{ 2120198092Srdivacky struct firewire_comm *fc = &sc->fc; 2121198092Srdivacky volatile struct fwohcidb_tr *db_tr; 2122198092Srdivacky struct fw_bulkxfer *chunk; 2123198092Srdivacky struct fw_xferq *ir; 2124198092Srdivacky u_int32_t stat; 2125198092Srdivacky int s, w=0, ldesc; 2126198092Srdivacky 2127204643Srdivacky ir = fc->ir[dmach]; 2128204643Srdivacky ldesc = sc->ir[dmach].ndesc - 1; 2129204643Srdivacky#if 0 2130204643Srdivacky dump_db(sc, dmach); 2131198092Srdivacky#endif 2132198092Srdivacky s = splfw(); 2133198092Srdivacky fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); 2134198092Srdivacky while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { 2135198092Srdivacky db_tr = (struct fwohcidb_tr *)chunk->end; 2136198092Srdivacky stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) 2137198092Srdivacky >> OHCI_STATUS_SHIFT; 2138198092Srdivacky if (stat == 0) 2139198092Srdivacky break; 2140198092Srdivacky 2141198092Srdivacky if (chunk->mbuf != NULL) { 2142198092Srdivacky bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map, 2143198092Srdivacky BUS_DMASYNC_POSTREAD); 2144198092Srdivacky bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map); 2145198092Srdivacky } else if (ir->buf != NULL) { 2146198092Srdivacky fwdma_sync_multiseg(ir->buf, chunk->poffset, 2147224145Sdim ir->bnpacket, BUS_DMASYNC_POSTREAD); 2148198092Srdivacky } else { 2149198092Srdivacky /* XXX */ 2150198092Srdivacky printf("fwohci_rbuf_update: this shouldn't happend\n"); 2151198092Srdivacky } 2152198092Srdivacky 2153234353Sdim STAILQ_REMOVE_HEAD(&ir->stdma, link); 2154234353Sdim STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); 2155234353Sdim switch (stat & FWOHCIEV_MASK) { 2156234353Sdim case FWOHCIEV_ACKCOMPL: 2157234353Sdim chunk->resp = 0; 2158234353Sdim break; 2159234353Sdim default: 2160234353Sdim chunk->resp = EINVAL; 2161234353Sdim device_printf(fc->dev, 2162193326Sed "Isochronous receive err %02x(%s)\n", 2163193326Sed stat, fwohcicode[stat & 0x1f]); 2164193326Sed } 2165193326Sed w++; 2166198092Srdivacky } 2167193326Sed splx(s); 2168193326Sed if (w) { 2169194613Sed if (ir->flag & FWXFERQ_HANDLER) 2170193326Sed ir->hand(ir); 2171194613Sed else 2172194613Sed wakeup(ir); 2173193326Sed } 2174193326Sed} 2175193326Sed 2176193326Sedvoid 2177193326Seddump_dma(struct fwohci_softc *sc, u_int32_t ch) 2178194613Sed{ 2179194613Sed u_int32_t off, cntl, stat, cmd, match; 2180195341Sed 2181198092Srdivacky if(ch == 0){ 2182195341Sed off = OHCI_ATQOFF; 2183195341Sed }else if(ch == 1){ 2184195341Sed off = OHCI_ATSOFF; 2185198092Srdivacky }else if(ch == 2){ 2186198092Srdivacky off = OHCI_ARQOFF; 2187198092Srdivacky }else if(ch == 3){ 2188195341Sed off = OHCI_ARSOFF; 2189198092Srdivacky }else if(ch < IRX_CH){ 2190193326Sed off = OHCI_ITCTL(ch - ITX_CH); 2191218893Sdim }else{ 2192218893Sdim off = OHCI_IRCTL(ch - IRX_CH); 2193193326Sed } 2194193326Sed cntl = stat = OREAD(sc, off); 2195226633Sdim cmd = OREAD(sc, off + 0xc); 2196226633Sdim match = OREAD(sc, off + 0x10); 2197226633Sdim 2198198092Srdivacky device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n", 2199198092Srdivacky ch, 2200226633Sdim cntl, 2201226633Sdim cmd, 2202198092Srdivacky match); 2203198092Srdivacky stat &= 0xffff ; 2204218893Sdim if (stat) { 2205193326Sed device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", 2206193326Sed ch, 2207243830Sdim stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2208193326Sed stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2209193326Sed stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2210207619Srdivacky stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2211226633Sdim stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2212226633Sdim stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2213193326Sed fwohcicode[stat & 0x1f], 2214207619Srdivacky stat & 0x1f 2215193326Sed ); 2216193326Sed }else{ 2217207619Srdivacky device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); 2218198092Srdivacky } 2219193326Sed} 2220207619Srdivacky 2221199482Srdivackyvoid 2222243830Sdimdump_db(struct fwohci_softc *sc, u_int32_t ch) 2223198092Srdivacky{ 2224193326Sed struct fwohci_dbch *dbch; 2225224145Sdim struct fwohcidb_tr *cp = NULL, *pp, *np = NULL; 2226224145Sdim volatile struct fwohcidb *curr = NULL, *prev, *next = NULL; 2227224145Sdim int idb, jdb; 2228224145Sdim u_int32_t cmd, off; 2229224145Sdim if(ch == 0){ 2230224145Sdim off = OHCI_ATQOFF; 2231224145Sdim dbch = &sc->atrq; 2232224145Sdim }else if(ch == 1){ 2233224145Sdim off = OHCI_ATSOFF; 2234224145Sdim dbch = &sc->atrs; 2235224145Sdim }else if(ch == 2){ 2236224145Sdim off = OHCI_ARQOFF; 2237224145Sdim dbch = &sc->arrq; 2238198092Srdivacky }else if(ch == 3){ 2239224145Sdim off = OHCI_ARSOFF; 2240198092Srdivacky dbch = &sc->arrs; 2241224145Sdim }else if(ch < IRX_CH){ 2242224145Sdim off = OHCI_ITCTL(ch - ITX_CH); 2243224145Sdim dbch = &sc->it[ch - ITX_CH]; 2244226633Sdim }else { 2245226633Sdim off = OHCI_IRCTL(ch - IRX_CH); 2246226633Sdim dbch = &sc->ir[ch - IRX_CH]; 2247226633Sdim } 2248226633Sdim cmd = OREAD(sc, off + 0xc); 2249226633Sdim 2250226633Sdim if( dbch->ndb == 0 ){ 2251226633Sdim device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); 2252226633Sdim return; 2253226633Sdim } 2254226633Sdim pp = dbch->top; 2255226633Sdim prev = pp->db; 2256226633Sdim for(idb = 0 ; idb < dbch->ndb ; idb ++ ){ 2257226633Sdim if(pp == NULL){ 2258193326Sed curr = NULL; 2259226633Sdim goto outdb; 2260226633Sdim } 2261221345Sdim cp = STAILQ_NEXT(pp, link); 2262221345Sdim if(cp == NULL){ 2263193326Sed curr = NULL; 2264221345Sdim goto outdb; 2265193326Sed } 2266226633Sdim np = STAILQ_NEXT(cp, link); 2267226633Sdim for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){ 2268198092Srdivacky if ((cmd & 0xfffffff0) == cp->bus_addr) { 2269195341Sed curr = cp->db; 2270193326Sed if(np != NULL){ 2271193326Sed next = np->db; 2272193326Sed }else{ 2273193326Sed next = NULL; 2274198092Srdivacky } 2275193326Sed goto outdb; 2276193326Sed } 2277198092Srdivacky } 2278198092Srdivacky pp = STAILQ_NEXT(pp, link); 2279198092Srdivacky prev = pp->db; 2280198092Srdivacky } 2281193326Sedoutdb: 2282226633Sdim if( curr != NULL){ 2283226633Sdim#if 0 2284193326Sed printf("Prev DB %d\n", ch); 2285195341Sed print_db(pp, prev, ch, dbch->ndesc); 2286193326Sed#endif 2287193326Sed printf("Current DB %d\n", ch); 2288193326Sed print_db(cp, curr, ch, dbch->ndesc); 2289193326Sed#if 0 2290198092Srdivacky printf("Next DB %d\n", ch); 2291193326Sed print_db(np, next, ch, dbch->ndesc); 2292193326Sed#endif 2293226633Sdim }else{ 2294234353Sdim printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); 2295234353Sdim } 2296234353Sdim return; 2297193326Sed} 2298193326Sed 2299193326Sedvoid 2300193326Sedprint_db(struct fwohcidb_tr *db_tr, volatile struct fwohcidb *db, 2301193326Sed u_int32_t ch, u_int32_t max) 2302193326Sed{ 2303193326Sed fwohcireg_t stat; 2304193326Sed int i, key; 2305193326Sed u_int32_t cmd, res; 2306193326Sed 2307193326Sed if(db == NULL){ 2308193326Sed printf("No Descriptor is found\n"); 2309226633Sdim return; 2310193326Sed } 2311193326Sed 2312193326Sed printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", 2313193326Sed ch, 2314193326Sed "Current", 2315193326Sed "OP ", 2316193326Sed "KEY", 2317198092Srdivacky "INT", 2318198092Srdivacky "BR ", 2319198092Srdivacky "len", 2320198092Srdivacky "Addr", 2321198092Srdivacky "Depend", 2322218893Sdim "Stat", 2323198092Srdivacky "Cnt"); 2324198092Srdivacky for( i = 0 ; i <= max ; i ++){ 2325198092Srdivacky cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd); 2326198092Srdivacky res = FWOHCI_DMA_READ(db[i].db.desc.res); 2327226633Sdim key = cmd & OHCI_KEY_MASK; 2328198092Srdivacky stat = res >> OHCI_STATUS_SHIFT; 2329198092Srdivacky#if __FreeBSD_version >= 500000 2330198092Srdivacky printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x", 2331198092Srdivacky (uintmax_t)db_tr->bus_addr, 2332226633Sdim#else 2333226633Sdim printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x", 2334226633Sdim db_tr->bus_addr, 2335198092Srdivacky#endif 2336218893Sdim dbcode[(cmd >> 28) & 0xf], 2337226633Sdim dbkey[(cmd >> 24) & 0x7], 2338198092Srdivacky dbcond[(cmd >> 20) & 0x3], 2339198092Srdivacky dbcond[(cmd >> 18) & 0x3], 2340226633Sdim cmd & OHCI_COUNT_MASK, 2341218893Sdim FWOHCI_DMA_READ(db[i].db.desc.addr), 2342198092Srdivacky FWOHCI_DMA_READ(db[i].db.desc.depend), 2343198092Srdivacky stat, 2344234353Sdim res & OHCI_COUNT_MASK); 2345234353Sdim if(stat & 0xff00){ 2346234353Sdim printf(" %s%s%s%s%s%s %s(%x)\n", 2347234353Sdim stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", 2348234353Sdim stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", 2349198092Srdivacky stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", 2350234353Sdim stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", 2351234353Sdim stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", 2352234353Sdim stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", 2353234353Sdim fwohcicode[stat & 0x1f], 2354198092Srdivacky stat & 0x1f 2355226633Sdim ); 2356198092Srdivacky }else{ 2357228379Sdim printf(" Nostat\n"); 2358193326Sed } 2359193326Sed if(key == OHCI_KEY_ST2 ){ 2360199482Srdivacky printf("0x%08x 0x%08x 0x%08x 0x%08x\n", 2361226633Sdim FWOHCI_DMA_READ(db[i+1].db.immed[0]), 2362228379Sdim FWOHCI_DMA_READ(db[i+1].db.immed[1]), 2363193326Sed FWOHCI_DMA_READ(db[i+1].db.immed[2]), 2364193326Sed FWOHCI_DMA_READ(db[i+1].db.immed[3])); 2365193326Sed } 2366198092Srdivacky if(key == OHCI_KEY_DEVICE){ 2367193326Sed return; 2368193326Sed } 2369198092Srdivacky if((cmd & OHCI_BRANCH_MASK) 2370226633Sdim == OHCI_BRANCH_ALWAYS){ 2371193326Sed return; 2372193326Sed } 2373193326Sed if((cmd & OHCI_CMD_MASK) 2374218893Sdim == OHCI_OUTPUT_LAST){ 2375193326Sed return; 2376218893Sdim } 2377193326Sed if((cmd & OHCI_CMD_MASK) 2378193326Sed == OHCI_INPUT_LAST){ 2379193326Sed return; 2380218893Sdim } 2381193326Sed if(key == OHCI_KEY_ST2 ){ 2382218893Sdim i++; 2383193326Sed } 2384193326Sed } 2385193326Sed return; 2386193326Sed} 2387193326Sed 2388193326Sedvoid 2389193326Sedfwohci_ibr(struct firewire_comm *fc) 2390193326Sed{ 2391195099Sed struct fwohci_softc *sc; 2392198092Srdivacky u_int32_t fun; 2393193326Sed 2394193326Sed device_printf(fc->dev, "Initiate bus reset\n"); 2395221345Sdim sc = (struct fwohci_softc *)fc; 2396193326Sed 2397193326Sed /* 2398198092Srdivacky * Set root hold-off bit so that non cyclemaster capable node 2399198092Srdivacky * shouldn't became the root node. 2400198092Srdivacky */ 2401226633Sdim#if 1 2402193326Sed fun = fwphy_rddata(sc, FW_PHY_IBR_REG); 2403224145Sdim fun |= FW_PHY_IBR | FW_PHY_RHB; 2404193326Sed fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); 2405224145Sdim#else /* Short bus reset */ 2406193326Sed fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); 2407193326Sed fun |= FW_PHY_ISBR | FW_PHY_RHB; 2408193326Sed fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); 2409193326Sed#endif 2410193326Sed} 2411193326Sed 2412193326Sedvoid 2413193326Sedfwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 2414193326Sed{ 2415193326Sed struct fwohcidb_tr *db_tr, *fdb_tr; 2416198092Srdivacky struct fwohci_dbch *dbch; 2417234353Sdim volatile struct fwohcidb *db; 2418221345Sdim struct fw_pkt *fp; 2419199990Srdivacky volatile struct fwohci_txpkthdr *ohcifp; 2420221345Sdim unsigned short chtag; 2421198092Srdivacky int idb; 2422198092Srdivacky 2423193326Sed dbch = &sc->it[dmach]; 2424193326Sed chtag = sc->it[dmach].xferq.flag & 0xff; 2425198092Srdivacky 2426224145Sdim db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 2427198092Srdivacky fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 2428198092Srdivacky/* 2429193326Seddevice_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr); 2430193326Sed*/ 2431193326Sed for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) { 2432193326Sed db = db_tr->db; 2433193326Sed fp = (struct fw_pkt *)db_tr->buf; 2434193326Sed ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed; 2435193326Sed ohcifp->mode.ld[0] = fp->mode.ld[0]; 2436193326Sed ohcifp->mode.stream.len = fp->mode.stream.len; 2437193326Sed ohcifp->mode.stream.chtag = chtag; 2438193326Sed ohcifp->mode.stream.tcode = 0xa; 2439193326Sed ohcifp->mode.stream.spd = 0; 2440193326Sed#if BYTE_ORDER == BIG_ENDIAN 2441224145Sdim FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]); 2442198092Srdivacky FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]); 2443198092Srdivacky#endif 2444193326Sed 2445193326Sed FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK); 2446193326Sed FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len); 2447193326Sed FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2448193326Sed#if 0 /* if bulkxfer->npackets changes */ 2449221345Sdim db[2].db.desc.cmd = OHCI_OUTPUT_LAST 2450221345Sdim | OHCI_UPDATE 2451221345Sdim | OHCI_BRANCH_ALWAYS; 2452221345Sdim db[0].db.desc.depend = 2453221345Sdim = db[dbch->ndesc - 1].db.desc.depend 2454221345Sdim = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc; 2455221345Sdim#else 2456226633Sdim FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); 2457226633Sdim FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc); 2458221345Sdim#endif 2459221345Sdim bulkxfer->end = (caddr_t)db_tr; 2460221345Sdim db_tr = STAILQ_NEXT(db_tr, link); 2461221345Sdim } 2462221345Sdim db = ((struct fwohcidb_tr *)bulkxfer->end)->db; 2463221345Sdim FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf); 2464221345Sdim FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf); 2465221345Sdim#if 0 /* if bulkxfer->npackets changes */ 2466221345Sdim db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2467221345Sdim /* OHCI 1.1 and above */ 2468221345Sdim db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2469221345Sdim#endif 2470221345Sdim/* 2471221345Sdim db_tr = (struct fwohcidb_tr *)bulkxfer->start; 2472193326Sed fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; 2473221345Sdimdevice_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr); 2474221345Sdim*/ 2475221345Sdim return; 2476221345Sdim} 2477221345Sdim 2478193326Sedstatic int 2479193326Sedfwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2480193326Sed int poffset) 2481193326Sed{ 2482221345Sdim volatile struct fwohcidb *db = db_tr->db; 2483193326Sed struct fw_xferq *it; 2484221345Sdim int err = 0; 2485221345Sdim 2486193326Sed it = &dbch->xferq; 2487198092Srdivacky if(it->buf == 0){ 2488193326Sed err = EINVAL; 2489193326Sed return err; 2490193326Sed } 2491221345Sdim db_tr->buf = fwdma_v_addr(it->buf, poffset); 2492221345Sdim db_tr->dbcnt = 3; 2493193326Sed 2494226633Sdim FWOHCI_DMA_WRITE(db[0].db.desc.cmd, 2495221345Sdim OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8); 2496221345Sdim FWOHCI_DMA_WRITE(db[2].db.desc.addr, 2497226633Sdim fwdma_bus_addr(it->buf, poffset) + sizeof(u_int32_t)); 2498193326Sed 2499193326Sed FWOHCI_DMA_WRITE(db[2].db.desc.cmd, 2500221345Sdim OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS); 2501221345Sdim#if 1 2502221345Sdim FWOHCI_DMA_WRITE(db[0].db.desc.res, 0); 2503193326Sed FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); 2504221345Sdim#endif 2505193326Sed return 0; 2506198092Srdivacky} 2507193326Sed 2508193326Sedint 2509198092Srdivackyfwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, 2510193326Sed int poffset, struct fwdma_alloc *dummy_dma) 2511193326Sed{ 2512193326Sed volatile struct fwohcidb *db = db_tr->db; 2513193326Sed struct fw_xferq *ir; 2514193326Sed int i, ldesc; 2515193326Sed bus_addr_t dbuf[2]; 2516193326Sed int dsiz[2]; 2517193326Sed 2518198092Srdivacky ir = &dbch->xferq; 2519193326Sed if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) { 2520193326Sed db_tr->buf = fwdma_malloc_size(dbch->dmat, &db_tr->dma_map, 2521193326Sed ir->psize, &dbuf[0], BUS_DMA_NOWAIT); 2522193326Sed if (db_tr->buf == NULL) 2523224145Sdim return(ENOMEM); 2524223017Sdim db_tr->dbcnt = 1; 2525224145Sdim dsiz[0] = ir->psize; 2526193326Sed bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2527221345Sdim BUS_DMASYNC_PREREAD); 2528221345Sdim } else { 2529193326Sed db_tr->dbcnt = 0; 2530243830Sdim if (dummy_dma != NULL) { 2531221345Sdim dsiz[db_tr->dbcnt] = sizeof(u_int32_t); 2532221345Sdim dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr; 2533221345Sdim } 2534221345Sdim dsiz[db_tr->dbcnt] = ir->psize; 2535221345Sdim if (ir->buf != NULL) { 2536221345Sdim db_tr->buf = fwdma_v_addr(ir->buf, poffset); 2537221345Sdim dbuf[db_tr->dbcnt] = fwdma_bus_addr( ir->buf, poffset); 2538221345Sdim } 2539221345Sdim db_tr->dbcnt++; 2540221345Sdim } 2541221345Sdim for(i = 0 ; i < db_tr->dbcnt ; i++){ 2542223017Sdim FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]); 2543221345Sdim FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]); 2544224145Sdim if (ir->flag & FWXFERQ_STREAM) { 2545234353Sdim FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE); 2546224145Sdim } 2547223017Sdim FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]); 2548223017Sdim } 2549224145Sdim ldesc = db_tr->dbcnt - 1; 2550234353Sdim if (ir->flag & FWXFERQ_STREAM) { 2551224145Sdim FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST); 2552224145Sdim } 2553224145Sdim FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS); 2554224145Sdim return 0; 2555224145Sdim} 2556224145Sdim 2557224145Sdim 2558224145Sdimstatic int 2559223017Sdimfwohci_arcv_swap(struct fw_pkt *fp, int len) 2560193326Sed{ 2561193326Sed struct fw_pkt *fp0; 2562193326Sed u_int32_t ld0; 2563193326Sed int slen; 2564193326Sed#if BYTE_ORDER == BIG_ENDIAN 2565198092Srdivacky int i; 2566193326Sed#endif 2567193326Sed 2568198092Srdivacky ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]); 2569198092Srdivacky#if 0 2570198092Srdivacky printf("ld0: x%08x\n", ld0); 2571193326Sed#endif 2572193326Sed fp0 = (struct fw_pkt *)&ld0; 2573223017Sdim switch (fp0->mode.common.tcode) { 2574226633Sdim case FWTCODE_RREQQ: 2575226633Sdim case FWTCODE_WRES: 2576223017Sdim case FWTCODE_WREQQ: 2577193326Sed case FWTCODE_RRESQ: 2578234353Sdim case FWOHCITCODE_PHY: 2579234353Sdim slen = 12; 2580234353Sdim break; 2581234353Sdim case FWTCODE_RREQB: 2582234353Sdim case FWTCODE_WREQB: 2583234353Sdim case FWTCODE_LREQ: 2584234353Sdim case FWTCODE_RRESB: 2585234353Sdim case FWTCODE_LRES: 2586234353Sdim slen = 16; 2587234353Sdim break; 2588234353Sdim default: 2589234353Sdim printf("Unknown tcode %d\n", fp0->mode.common.tcode); 2590234353Sdim return(0); 2591234353Sdim } 2592234353Sdim if (slen > len) { 2593234353Sdim if (firewire_debug) 2594234353Sdim printf("splitted header\n"); 2595234353Sdim return(-slen); 2596234353Sdim } 2597234353Sdim#if BYTE_ORDER == BIG_ENDIAN 2598234353Sdim for(i = 0; i < slen/4; i ++) 2599234353Sdim fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]); 2600234353Sdim#endif 2601234353Sdim return(slen); 2602234353Sdim} 2603234353Sdim 2604234353Sdim#define PLEN(x) roundup2(x, sizeof(u_int32_t)) 2605234353Sdimstatic int 2606234353Sdimfwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp) 2607234353Sdim{ 2608234353Sdim int r; 2609234353Sdim 2610234353Sdim switch(fp->mode.common.tcode){ 2611234353Sdim case FWTCODE_RREQQ: 2612234353Sdim r = sizeof(fp->mode.rreqq) + sizeof(u_int32_t); 2613234353Sdim break; 2614234353Sdim case FWTCODE_WRES: 2615234353Sdim r = sizeof(fp->mode.wres) + sizeof(u_int32_t); 2616234353Sdim break; 2617234353Sdim case FWTCODE_WREQQ: 2618193326Sed r = sizeof(fp->mode.wreqq) + sizeof(u_int32_t); 2619193326Sed break; 2620193326Sed case FWTCODE_RREQB: 2621193326Sed r = sizeof(fp->mode.rreqb) + sizeof(u_int32_t); 2622193326Sed break; 2623193326Sed case FWTCODE_RRESQ: 2624198092Srdivacky r = sizeof(fp->mode.rresq) + sizeof(u_int32_t); 2625198092Srdivacky break; 2626193326Sed case FWTCODE_WREQB: 2627226633Sdim r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.wreqb.len) 2628226633Sdim + sizeof(u_int32_t); 2629221345Sdim break; 2630193326Sed case FWTCODE_LREQ: 2631193326Sed r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lreq.len) 2632193326Sed + sizeof(u_int32_t); 2633226633Sdim break; 2634234353Sdim case FWTCODE_RRESB: 2635193326Sed r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.rresb.len) 2636193326Sed + sizeof(u_int32_t); 2637193326Sed break; 2638198092Srdivacky case FWTCODE_LRES: 2639198092Srdivacky r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lres.len) 2640198092Srdivacky + sizeof(u_int32_t); 2641198092Srdivacky break; 2642198092Srdivacky case FWOHCITCODE_PHY: 2643193326Sed r = 16; 2644193326Sed break; 2645193326Sed default: 2646223017Sdim device_printf(sc->fc.dev, "Unknown tcode %d\n", 2647221345Sdim fp->mode.common.tcode); 2648193326Sed r = 0; 2649193326Sed } 2650223017Sdim if (r > dbch->xferq.psize) { 2651221345Sdim device_printf(sc->fc.dev, "Invalid packet length %d\n", r); 2652193326Sed /* panic ? */ 2653193326Sed } 2654234353Sdim return r; 2655234353Sdim} 2656234353Sdim 2657234353Sdimstatic void 2658234353Sdimfwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr) 2659223017Sdim{ 2660221345Sdim volatile struct fwohcidb *db = &db_tr->db[0]; 2661207619Srdivacky 2662223017Sdim FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf); 2663221345Sdim FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize); 2664218893Sdim FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1); 2665249423Sdim fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); 2666234353Sdim dbch->bottom = db_tr; 2667234353Sdim} 2668249423Sdim 2669249423Sdimstatic void 2670249423Sdimfwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 2671207619Srdivacky{ 2672198092Srdivacky struct fwohcidb_tr *db_tr; 2673221345Sdim struct iovec vec[2]; 2674193326Sed struct fw_pkt pktbuf; 2675193326Sed int nvec; 2676221345Sdim struct fw_pkt *fp; 2677210299Sed u_int8_t *ld; 2678221345Sdim u_int32_t stat, off, status; 2679210299Sed u_int spd; 2680193326Sed int len, plen, hlen, pcnt, offset; 2681193326Sed int s; 2682221345Sdim caddr_t buf; 2683210299Sed int resCount; 2684210299Sed 2685210299Sed if(&sc->arrq == dbch){ 2686210299Sed off = OHCI_ARQOFF; 2687243830Sdim }else if(&sc->arrs == dbch){ 2688210299Sed off = OHCI_ARSOFF; 2689210299Sed }else{ 2690210299Sed return; 2691210299Sed } 2692221345Sdim 2693221345Sdim s = splfw(); 2694221345Sdim db_tr = dbch->top; 2695221345Sdim pcnt = 0; 2696221345Sdim /* XXX we cannot handle a packet which lies in more than two buf */ 2697193326Sed fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); 2698193326Sed fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); 2699221345Sdim status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT; 2700249423Sdim resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK; 2701249423Sdim#if 0 2702193326Sed printf("status 0x%04x, resCount 0x%04x\n", status, resCount); 2703193326Sed#endif 2704193326Sed while (status & OHCI_CNTL_DMA_ACTIVE) { 2705226633Sdim len = dbch->xferq.psize - resCount; 2706193326Sed ld = (u_int8_t *)db_tr->buf; 2707193326Sed if (dbch->pdb_tr == NULL) { 2708198092Srdivacky len -= dbch->buf_offset; 2709193326Sed ld += dbch->buf_offset; 2710193326Sed } 2711193326Sed if (len > 0) 2712226633Sdim bus_dmamap_sync(dbch->dmat, db_tr->dma_map, 2713243830Sdim BUS_DMASYNC_POSTREAD); 2714249423Sdim while (len > 0 ) { 2715243830Sdim if (count >= 0 && count-- == 0) 2716239462Sdim goto out; 2717249423Sdim if(dbch->pdb_tr != NULL){ 2718249423Sdim /* we have a fragment in previous buffer */ 2719193326Sed int rlen; 2720193326Sed 2721221345Sdim offset = dbch->buf_offset; 2722198092Srdivacky if (offset < 0) 2723249423Sdim offset = - offset; 2724223017Sdim buf = dbch->pdb_tr->buf + offset; 2725203955Srdivacky rlen = dbch->xferq.psize - offset; 2726193326Sed if (firewire_debug) 2727193326Sed printf("rlen=%d, offset=%d\n", 2728221345Sdim rlen, dbch->buf_offset); 2729198092Srdivacky if (dbch->buf_offset < 0) { 2730249423Sdim /* splitted in header, pull up */ 2731203955Srdivacky char *p; 2732203955Srdivacky 2733203955Srdivacky p = (char *)&pktbuf; 2734193326Sed bcopy(buf, p, rlen); 2735193326Sed p += rlen; 2736221345Sdim /* this must be too long but harmless */ 2737212904Sdim rlen = sizeof(pktbuf) - rlen; 2738212904Sdim if (rlen < 0) 2739249423Sdim printf("why rlen < 0\n"); 2740203955Srdivacky bcopy(db_tr->buf, p, rlen); 2741203955Srdivacky ld += rlen; 2742212904Sdim len -= rlen; 2743212904Sdim hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf)); 2744212904Sdim if (hlen < 0) { 2745212904Sdim printf("hlen < 0 shouldn't happen"); 2746226633Sdim } 2747193326Sed offset = sizeof(pktbuf); 2748193326Sed vec[0].iov_base = (char *)&pktbuf; 2749221345Sdim vec[0].iov_len = offset; 2750198092Srdivacky } else { 2751198092Srdivacky /* splitted in payload */ 2752249423Sdim offset = rlen; 2753203955Srdivacky vec[0].iov_base = buf; 2754223017Sdim vec[0].iov_len = rlen; 2755203955Srdivacky } 2756193326Sed fp=(struct fw_pkt *)vec[0].iov_base; 2757193326Sed nvec = 1; 2758221345Sdim } else { 2759198092Srdivacky /* no fragment in previous buffer */ 2760249423Sdim fp=(struct fw_pkt *)ld; 2761203955Srdivacky hlen = fwohci_arcv_swap(fp, len); 2762203955Srdivacky if (hlen == 0) 2763203955Srdivacky /* XXX need reset */ 2764193326Sed goto out; 2765193326Sed if (hlen < 0) { 2766221345Sdim dbch->pdb_tr = db_tr; 2767198092Srdivacky dbch->buf_offset = - dbch->buf_offset; 2768198092Srdivacky /* sanity check */ 2769210299Sed if (resCount != 0) 2770249423Sdim printf("resCount != 0 !?\n"); 2771223017Sdim goto out; 2772223017Sdim } 2773203955Srdivacky offset = 0; 2774210299Sed nvec = 0; 2775198092Srdivacky } 2776198092Srdivacky plen = fwohci_get_plen(sc, dbch, fp) - offset; 2777193326Sed if (plen < 0) { 2778193326Sed /* minimum header size + trailer 2779193326Sed = sizeof(fw_pkt) so this shouldn't happens */ 2780193326Sed printf("plen is negative! offset=%d\n", offset); 2781193326Sed goto out; 2782193326Sed } 2783193326Sed if (plen > 0) { 2784193326Sed len -= plen; 2785198092Srdivacky if (len < 0) { 2786198092Srdivacky dbch->pdb_tr = db_tr; 2787218893Sdim if (firewire_debug) 2788218893Sdim printf("splitted payload\n"); 2789218893Sdim /* sanity check */ 2790218893Sdim if (resCount != 0) 2791218893Sdim printf("resCount != 0 !?\n"); 2792218893Sdim goto out; 2793218893Sdim } 2794218893Sdim vec[nvec].iov_base = ld; 2795218893Sdim vec[nvec].iov_len = plen; 2796218893Sdim nvec ++; 2797218893Sdim ld += plen; 2798207619Srdivacky } 2799207619Srdivacky dbch->buf_offset = ld - (u_int8_t *)db_tr->buf; 2800207619Srdivacky if (nvec == 0) 2801226633Sdim printf("nvec == 0\n"); 2802226633Sdim 2803198092Srdivacky/* DMA result-code will be written at the tail of packet */ 2804198092Srdivacky#if BYTE_ORDER == BIG_ENDIAN 2805198092Srdivacky stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16; 2806198092Srdivacky#else 2807234353Sdim stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat; 2808198092Srdivacky#endif 2809226633Sdim#if 0 2810198092Srdivacky printf("plen: %d, stat %x\n", plen ,stat); 2811198092Srdivacky#endif 2812198092Srdivacky spd = (stat >> 5) & 0x3; 2813198092Srdivacky stat &= 0x1f; 2814198092Srdivacky switch(stat){ 2815198092Srdivacky case FWOHCIEV_ACKPEND: 2816198092Srdivacky#if 0 2817198092Srdivacky printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); 2818198092Srdivacky#endif 2819193326Sed /* fall through */ 2820198092Srdivacky case FWOHCIEV_ACKCOMPL: 2821193326Sed if ((vec[nvec-1].iov_len -= 2822193326Sed sizeof(struct fwohci_trailer)) == 0) 2823221345Sdim nvec--; 2824193326Sed fw_rcv(&sc->fc, vec, nvec, 0, spd); 2825193326Sed break; 2826193326Sed case FWOHCIEV_BUSRST: 2827193326Sed if (sc->fc.status != FWBUSRESET) 2828208600Srdivacky printf("got BUSRST packet!?\n"); 2829208600Srdivacky break; 2830193326Sed default: 2831193326Sed device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]); 2832193326Sed#if 0 /* XXX */ 2833198092Srdivacky goto out; 2834193326Sed#endif 2835193326Sed break; 2836193326Sed } 2837226633Sdim pcnt ++; 2838226633Sdim if (dbch->pdb_tr != NULL) { 2839226633Sdim fwohci_arcv_free_buf(dbch, dbch->pdb_tr); 2840193326Sed dbch->pdb_tr = NULL; 2841193326Sed } 2842198092Srdivacky 2843193326Sed } 2844193326Sedout: 2845193326Sed if (resCount == 0) { 2846198092Srdivacky /* done on this buffer */ 2847193326Sed if (dbch->pdb_tr == NULL) { 2848193326Sed fwohci_arcv_free_buf(dbch, db_tr); 2849193326Sed dbch->buf_offset = 0; 2850221345Sdim } else 2851193326Sed if (dbch->pdb_tr != db_tr) 2852193326Sed printf("pdb_tr != db_tr\n"); 2853239462Sdim db_tr = STAILQ_NEXT(db_tr, link); 2854193326Sed status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2855224145Sdim >> OHCI_STATUS_SHIFT; 2856224145Sdim resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) 2857224145Sdim & OHCI_COUNT_MASK; 2858224145Sdim /* XXX check buffer overrun */ 2859224145Sdim dbch->top = db_tr; 2860224145Sdim } else { 2861224145Sdim dbch->buf_offset = dbch->xferq.psize - resCount; 2862224145Sdim break; 2863224145Sdim } 2864224145Sdim /* XXX make sure DMA is not dead */ 2865226633Sdim } 2866226633Sdim#if 0 2867234353Sdim if (pcnt < 1) 2868234353Sdim printf("fwohci_arcv: no packets\n"); 2869234353Sdim#endif 2870234353Sdim splx(s); 2871193326Sed} 2872193326Sed