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