xref: /freebsd/sys/dev/firewire/fwohci.c (revision 03161bbcf639dca1600a75bb7cc893dbae0e9483)
13c60ba66SKatsushi Kobayashi /*
277ee030bSHidetoshi Shimokawa  * Copyright (c) 2003 Hidetoshi Shimokawa
33c60ba66SKatsushi Kobayashi  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
43c60ba66SKatsushi Kobayashi  * All rights reserved.
53c60ba66SKatsushi Kobayashi  *
63c60ba66SKatsushi Kobayashi  * Redistribution and use in source and binary forms, with or without
73c60ba66SKatsushi Kobayashi  * modification, are permitted provided that the following conditions
83c60ba66SKatsushi Kobayashi  * are met:
93c60ba66SKatsushi Kobayashi  * 1. Redistributions of source code must retain the above copyright
103c60ba66SKatsushi Kobayashi  *    notice, this list of conditions and the following disclaimer.
113c60ba66SKatsushi Kobayashi  * 2. Redistributions in binary form must reproduce the above copyright
123c60ba66SKatsushi Kobayashi  *    notice, this list of conditions and the following disclaimer in the
133c60ba66SKatsushi Kobayashi  *    documentation and/or other materials provided with the distribution.
143c60ba66SKatsushi Kobayashi  * 3. All advertising materials mentioning features or use of this software
153c60ba66SKatsushi Kobayashi  *    must display the acknowledgement as bellow:
163c60ba66SKatsushi Kobayashi  *
178da326fdSHidetoshi Shimokawa  *    This product includes software developed by K. Kobayashi and H. Shimokawa
183c60ba66SKatsushi Kobayashi  *
193c60ba66SKatsushi Kobayashi  * 4. The name of the author may not be used to endorse or promote products
203c60ba66SKatsushi Kobayashi  *    derived from this software without specific prior written permission.
213c60ba66SKatsushi Kobayashi  *
223c60ba66SKatsushi Kobayashi  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
233c60ba66SKatsushi Kobayashi  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
243c60ba66SKatsushi Kobayashi  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
253c60ba66SKatsushi Kobayashi  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
263c60ba66SKatsushi Kobayashi  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
273c60ba66SKatsushi Kobayashi  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
283c60ba66SKatsushi Kobayashi  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293c60ba66SKatsushi Kobayashi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
303c60ba66SKatsushi Kobayashi  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
313c60ba66SKatsushi Kobayashi  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
323c60ba66SKatsushi Kobayashi  * POSSIBILITY OF SUCH DAMAGE.
333c60ba66SKatsushi Kobayashi  *
343c60ba66SKatsushi Kobayashi  * $FreeBSD$
353c60ba66SKatsushi Kobayashi  *
363c60ba66SKatsushi Kobayashi  */
378da326fdSHidetoshi Shimokawa 
383c60ba66SKatsushi Kobayashi #define ATRQ_CH 0
393c60ba66SKatsushi Kobayashi #define ATRS_CH 1
403c60ba66SKatsushi Kobayashi #define ARRQ_CH 2
413c60ba66SKatsushi Kobayashi #define ARRS_CH 3
423c60ba66SKatsushi Kobayashi #define ITX_CH 4
433c60ba66SKatsushi Kobayashi #define IRX_CH 0x24
443c60ba66SKatsushi Kobayashi 
453c60ba66SKatsushi Kobayashi #include <sys/param.h>
463c60ba66SKatsushi Kobayashi #include <sys/systm.h>
473c60ba66SKatsushi Kobayashi #include <sys/mbuf.h>
483c60ba66SKatsushi Kobayashi #include <sys/malloc.h>
493c60ba66SKatsushi Kobayashi #include <sys/sockio.h>
503c60ba66SKatsushi Kobayashi #include <sys/bus.h>
513c60ba66SKatsushi Kobayashi #include <sys/kernel.h>
523c60ba66SKatsushi Kobayashi #include <sys/conf.h>
5377ee030bSHidetoshi Shimokawa #include <sys/endian.h>
543c60ba66SKatsushi Kobayashi 
553c60ba66SKatsushi Kobayashi #include <machine/bus.h>
563c60ba66SKatsushi Kobayashi 
5710d3ed64SHidetoshi Shimokawa #if defined(__DragonFly__) || __FreeBSD_version < 500000
58170e7a20SHidetoshi Shimokawa #include <machine/clock.h>		/* for DELAY() */
59170e7a20SHidetoshi Shimokawa #endif
60170e7a20SHidetoshi Shimokawa 
6110d3ed64SHidetoshi Shimokawa #ifdef __DragonFly__
6210d3ed64SHidetoshi Shimokawa #include "firewire.h"
6310d3ed64SHidetoshi Shimokawa #include "firewirereg.h"
6410d3ed64SHidetoshi Shimokawa #include "fwdma.h"
6510d3ed64SHidetoshi Shimokawa #include "fwohcireg.h"
6610d3ed64SHidetoshi Shimokawa #include "fwohcivar.h"
6710d3ed64SHidetoshi Shimokawa #include "firewire_phy.h"
6810d3ed64SHidetoshi Shimokawa #else
693c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire.h>
703c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirereg.h>
7177ee030bSHidetoshi Shimokawa #include <dev/firewire/fwdma.h>
723c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcireg.h>
733c60ba66SKatsushi Kobayashi #include <dev/firewire/fwohcivar.h>
743c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire_phy.h>
7510d3ed64SHidetoshi Shimokawa #endif
763c60ba66SKatsushi Kobayashi 
773c60ba66SKatsushi Kobayashi #undef OHCI_DEBUG
788da326fdSHidetoshi Shimokawa 
793c60ba66SKatsushi Kobayashi static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL",
803c60ba66SKatsushi Kobayashi 		"STOR","LOAD","NOP ","STOP",};
8177ee030bSHidetoshi Shimokawa 
823c60ba66SKatsushi Kobayashi static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3",
833c60ba66SKatsushi Kobayashi 		"UNDEF","REG","SYS","DEV"};
8477ee030bSHidetoshi Shimokawa static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"};
853c60ba66SKatsushi Kobayashi char fwohcicode[32][0x20]={
863c60ba66SKatsushi Kobayashi 	"No stat","Undef","long","miss Ack err",
873c60ba66SKatsushi Kobayashi 	"underrun","overrun","desc err", "data read err",
883c60ba66SKatsushi Kobayashi 	"data write err","bus reset","timeout","tcode err",
893c60ba66SKatsushi Kobayashi 	"Undef","Undef","unknown event","flushed",
903c60ba66SKatsushi Kobayashi 	"Undef","ack complete","ack pend","Undef",
913c60ba66SKatsushi Kobayashi 	"ack busy_X","ack busy_A","ack busy_B","Undef",
923c60ba66SKatsushi Kobayashi 	"Undef","Undef","Undef","ack tardy",
933c60ba66SKatsushi Kobayashi 	"Undef","ack data_err","ack type_err",""};
9477ee030bSHidetoshi Shimokawa 
950bc666e0SHidetoshi Shimokawa #define MAX_SPEED 3
9648087829SHidetoshi Shimokawa extern char *linkspeed[];
9703161bbcSDoug Rabson uint32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
983c60ba66SKatsushi Kobayashi 
993c60ba66SKatsushi Kobayashi static struct tcode_info tinfo[] = {
1003c60ba66SKatsushi Kobayashi /*		hdr_len block 	flag*/
1013c60ba66SKatsushi Kobayashi /* 0 WREQQ  */ {16,	FWTI_REQ | FWTI_TLABEL},
1023c60ba66SKatsushi Kobayashi /* 1 WREQB  */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
1033c60ba66SKatsushi Kobayashi /* 2 WRES   */ {12,	FWTI_RES},
1043c60ba66SKatsushi Kobayashi /* 3 XXX    */ { 0,	0},
1053c60ba66SKatsushi Kobayashi /* 4 RREQQ  */ {12,	FWTI_REQ | FWTI_TLABEL},
1063c60ba66SKatsushi Kobayashi /* 5 RREQB  */ {16,	FWTI_REQ | FWTI_TLABEL},
1073c60ba66SKatsushi Kobayashi /* 6 RRESQ  */ {16,	FWTI_RES},
1083c60ba66SKatsushi Kobayashi /* 7 RRESB  */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
1093c60ba66SKatsushi Kobayashi /* 8 CYCS   */ { 0,	0},
1103c60ba66SKatsushi Kobayashi /* 9 LREQ   */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
1113c60ba66SKatsushi Kobayashi /* a STREAM */ { 4,	FWTI_REQ | FWTI_BLOCK_STR},
1123c60ba66SKatsushi Kobayashi /* b LRES   */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
1133c60ba66SKatsushi Kobayashi /* c XXX    */ { 0,	0},
1143c60ba66SKatsushi Kobayashi /* d XXX    */ { 0, 	0},
1153c60ba66SKatsushi Kobayashi /* e PHY    */ {12,	FWTI_REQ},
1163c60ba66SKatsushi Kobayashi /* f XXX    */ { 0,	0}
1173c60ba66SKatsushi Kobayashi };
1183c60ba66SKatsushi Kobayashi 
1193c60ba66SKatsushi Kobayashi #define OHCI_WRITE_SIGMASK 0xffff0000
1203c60ba66SKatsushi Kobayashi #define OHCI_READ_SIGMASK 0xffff0000
1213c60ba66SKatsushi Kobayashi 
1223c60ba66SKatsushi Kobayashi #define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x))
1233c60ba66SKatsushi Kobayashi #define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r))
1243c60ba66SKatsushi Kobayashi 
125d09a5d6fSHidetoshi Shimokawa static void fwohci_ibr (struct firewire_comm *);
126d09a5d6fSHidetoshi Shimokawa static void fwohci_db_init (struct fwohci_softc *, struct fwohci_dbch *);
127d09a5d6fSHidetoshi Shimokawa static void fwohci_db_free (struct fwohci_dbch *);
128d09a5d6fSHidetoshi Shimokawa static void fwohci_arcv (struct fwohci_softc *, struct fwohci_dbch *, int);
129d09a5d6fSHidetoshi Shimokawa static void fwohci_txd (struct fwohci_softc *, struct fwohci_dbch *);
130d09a5d6fSHidetoshi Shimokawa static void fwohci_start_atq (struct firewire_comm *);
131d09a5d6fSHidetoshi Shimokawa static void fwohci_start_ats (struct firewire_comm *);
132d09a5d6fSHidetoshi Shimokawa static void fwohci_start (struct fwohci_softc *, struct fwohci_dbch *);
13303161bbcSDoug Rabson static uint32_t fwphy_wrdata ( struct fwohci_softc *, uint32_t, uint32_t);
13403161bbcSDoug Rabson static uint32_t fwphy_rddata ( struct fwohci_softc *, uint32_t);
135d09a5d6fSHidetoshi Shimokawa static int fwohci_rx_enable (struct fwohci_softc *, struct fwohci_dbch *);
136d09a5d6fSHidetoshi Shimokawa static int fwohci_tx_enable (struct fwohci_softc *, struct fwohci_dbch *);
137d09a5d6fSHidetoshi Shimokawa static int fwohci_irx_enable (struct firewire_comm *, int);
138d09a5d6fSHidetoshi Shimokawa static int fwohci_irx_disable (struct firewire_comm *, int);
13977ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
14003161bbcSDoug Rabson static void fwohci_irx_post (struct firewire_comm *, uint32_t *);
14177ee030bSHidetoshi Shimokawa #endif
142d09a5d6fSHidetoshi Shimokawa static int fwohci_itxbuf_enable (struct firewire_comm *, int);
143d09a5d6fSHidetoshi Shimokawa static int fwohci_itx_disable (struct firewire_comm *, int);
144d09a5d6fSHidetoshi Shimokawa static void fwohci_timeout (void *);
145d09a5d6fSHidetoshi Shimokawa static void fwohci_set_intr (struct firewire_comm *, int);
14677ee030bSHidetoshi Shimokawa 
147d09a5d6fSHidetoshi Shimokawa static int fwohci_add_rx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *);
148d09a5d6fSHidetoshi Shimokawa static int fwohci_add_tx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int);
14903161bbcSDoug Rabson static void	dump_db (struct fwohci_softc *, uint32_t);
15003161bbcSDoug Rabson static void 	print_db (struct fwohcidb_tr *, struct fwohcidb *, uint32_t , uint32_t);
15103161bbcSDoug Rabson static void	dump_dma (struct fwohci_softc *, uint32_t);
15203161bbcSDoug Rabson static uint32_t fwohci_cyctimer (struct firewire_comm *);
153d09a5d6fSHidetoshi Shimokawa static void fwohci_rbuf_update (struct fwohci_softc *, int);
154d09a5d6fSHidetoshi Shimokawa static void fwohci_tbuf_update (struct fwohci_softc *, int);
155d09a5d6fSHidetoshi Shimokawa void fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *);
15677ee030bSHidetoshi Shimokawa #if FWOHCI_TASKQUEUE
15777ee030bSHidetoshi Shimokawa static void fwohci_complete(void *, int);
15877ee030bSHidetoshi Shimokawa #endif
1593c60ba66SKatsushi Kobayashi 
1603c60ba66SKatsushi Kobayashi /*
1613c60ba66SKatsushi Kobayashi  * memory allocated for DMA programs
1623c60ba66SKatsushi Kobayashi  */
1633c60ba66SKatsushi Kobayashi #define DMA_PROG_ALLOC		(8 * PAGE_SIZE)
1643c60ba66SKatsushi Kobayashi 
1653c60ba66SKatsushi Kobayashi #define NDB FWMAXQUEUE
1663c60ba66SKatsushi Kobayashi 
1673c60ba66SKatsushi Kobayashi #define	OHCI_VERSION		0x00
16873aa55baSHidetoshi Shimokawa #define	OHCI_ATRETRY		0x08
1693c60ba66SKatsushi Kobayashi #define	OHCI_CROMHDR		0x18
1703c60ba66SKatsushi Kobayashi #define	OHCI_BUS_OPT		0x20
1713c60ba66SKatsushi Kobayashi #define	OHCI_BUSIRMC		(1 << 31)
1723c60ba66SKatsushi Kobayashi #define	OHCI_BUSCMC		(1 << 30)
1733c60ba66SKatsushi Kobayashi #define	OHCI_BUSISC		(1 << 29)
1743c60ba66SKatsushi Kobayashi #define	OHCI_BUSBMC		(1 << 28)
1753c60ba66SKatsushi Kobayashi #define	OHCI_BUSPMC		(1 << 27)
1763c60ba66SKatsushi Kobayashi #define OHCI_BUSFNC		OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\
1773c60ba66SKatsushi Kobayashi 				OHCI_BUSBMC | OHCI_BUSPMC
1783c60ba66SKatsushi Kobayashi 
1793c60ba66SKatsushi Kobayashi #define	OHCI_EUID_HI		0x24
1803c60ba66SKatsushi Kobayashi #define	OHCI_EUID_LO		0x28
1813c60ba66SKatsushi Kobayashi 
1823c60ba66SKatsushi Kobayashi #define	OHCI_CROMPTR		0x34
1833c60ba66SKatsushi Kobayashi #define	OHCI_HCCCTL		0x50
1843c60ba66SKatsushi Kobayashi #define	OHCI_HCCCTLCLR		0x54
1853c60ba66SKatsushi Kobayashi #define	OHCI_AREQHI		0x100
1863c60ba66SKatsushi Kobayashi #define	OHCI_AREQHICLR		0x104
1873c60ba66SKatsushi Kobayashi #define	OHCI_AREQLO		0x108
1883c60ba66SKatsushi Kobayashi #define	OHCI_AREQLOCLR		0x10c
1893c60ba66SKatsushi Kobayashi #define	OHCI_PREQHI		0x110
1903c60ba66SKatsushi Kobayashi #define	OHCI_PREQHICLR		0x114
1913c60ba66SKatsushi Kobayashi #define	OHCI_PREQLO		0x118
1923c60ba66SKatsushi Kobayashi #define	OHCI_PREQLOCLR		0x11c
1933c60ba66SKatsushi Kobayashi #define	OHCI_PREQUPPER		0x120
1943c60ba66SKatsushi Kobayashi 
1953c60ba66SKatsushi Kobayashi #define	OHCI_SID_BUF		0x64
1963c60ba66SKatsushi Kobayashi #define	OHCI_SID_CNT		0x68
19777ee030bSHidetoshi Shimokawa #define OHCI_SID_ERR		(1 << 31)
1983c60ba66SKatsushi Kobayashi #define OHCI_SID_CNT_MASK	0xffc
1993c60ba66SKatsushi Kobayashi 
2003c60ba66SKatsushi Kobayashi #define	OHCI_IT_STAT		0x90
2013c60ba66SKatsushi Kobayashi #define	OHCI_IT_STATCLR		0x94
2023c60ba66SKatsushi Kobayashi #define	OHCI_IT_MASK		0x98
2033c60ba66SKatsushi Kobayashi #define	OHCI_IT_MASKCLR		0x9c
2043c60ba66SKatsushi Kobayashi 
2053c60ba66SKatsushi Kobayashi #define	OHCI_IR_STAT		0xa0
2063c60ba66SKatsushi Kobayashi #define	OHCI_IR_STATCLR		0xa4
2073c60ba66SKatsushi Kobayashi #define	OHCI_IR_MASK		0xa8
2083c60ba66SKatsushi Kobayashi #define	OHCI_IR_MASKCLR		0xac
2093c60ba66SKatsushi Kobayashi 
2103c60ba66SKatsushi Kobayashi #define	OHCI_LNKCTL		0xe0
2113c60ba66SKatsushi Kobayashi #define	OHCI_LNKCTLCLR		0xe4
2123c60ba66SKatsushi Kobayashi 
2133c60ba66SKatsushi Kobayashi #define	OHCI_PHYACCESS		0xec
2143c60ba66SKatsushi Kobayashi #define	OHCI_CYCLETIMER		0xf0
2153c60ba66SKatsushi Kobayashi 
2163c60ba66SKatsushi Kobayashi #define	OHCI_DMACTL(off)	(off)
2173c60ba66SKatsushi Kobayashi #define	OHCI_DMACTLCLR(off)	(off + 4)
2183c60ba66SKatsushi Kobayashi #define	OHCI_DMACMD(off)	(off + 0xc)
2193c60ba66SKatsushi Kobayashi #define	OHCI_DMAMATCH(off)	(off + 0x10)
2203c60ba66SKatsushi Kobayashi 
2213c60ba66SKatsushi Kobayashi #define OHCI_ATQOFF		0x180
2223c60ba66SKatsushi Kobayashi #define OHCI_ATQCTL		OHCI_ATQOFF
2233c60ba66SKatsushi Kobayashi #define OHCI_ATQCTLCLR		(OHCI_ATQOFF + 4)
2243c60ba66SKatsushi Kobayashi #define OHCI_ATQCMD		(OHCI_ATQOFF + 0xc)
2253c60ba66SKatsushi Kobayashi #define OHCI_ATQMATCH		(OHCI_ATQOFF + 0x10)
2263c60ba66SKatsushi Kobayashi 
2273c60ba66SKatsushi Kobayashi #define OHCI_ATSOFF		0x1a0
2283c60ba66SKatsushi Kobayashi #define OHCI_ATSCTL		OHCI_ATSOFF
2293c60ba66SKatsushi Kobayashi #define OHCI_ATSCTLCLR		(OHCI_ATSOFF + 4)
2303c60ba66SKatsushi Kobayashi #define OHCI_ATSCMD		(OHCI_ATSOFF + 0xc)
2313c60ba66SKatsushi Kobayashi #define OHCI_ATSMATCH		(OHCI_ATSOFF + 0x10)
2323c60ba66SKatsushi Kobayashi 
2333c60ba66SKatsushi Kobayashi #define OHCI_ARQOFF		0x1c0
2343c60ba66SKatsushi Kobayashi #define OHCI_ARQCTL		OHCI_ARQOFF
2353c60ba66SKatsushi Kobayashi #define OHCI_ARQCTLCLR		(OHCI_ARQOFF + 4)
2363c60ba66SKatsushi Kobayashi #define OHCI_ARQCMD		(OHCI_ARQOFF + 0xc)
2373c60ba66SKatsushi Kobayashi #define OHCI_ARQMATCH		(OHCI_ARQOFF + 0x10)
2383c60ba66SKatsushi Kobayashi 
2393c60ba66SKatsushi Kobayashi #define OHCI_ARSOFF		0x1e0
2403c60ba66SKatsushi Kobayashi #define OHCI_ARSCTL		OHCI_ARSOFF
2413c60ba66SKatsushi Kobayashi #define OHCI_ARSCTLCLR		(OHCI_ARSOFF + 4)
2423c60ba66SKatsushi Kobayashi #define OHCI_ARSCMD		(OHCI_ARSOFF + 0xc)
2433c60ba66SKatsushi Kobayashi #define OHCI_ARSMATCH		(OHCI_ARSOFF + 0x10)
2443c60ba66SKatsushi Kobayashi 
2453c60ba66SKatsushi Kobayashi #define OHCI_ITOFF(CH)		(0x200 + 0x10 * (CH))
2463c60ba66SKatsushi Kobayashi #define OHCI_ITCTL(CH)		(OHCI_ITOFF(CH))
2473c60ba66SKatsushi Kobayashi #define OHCI_ITCTLCLR(CH)	(OHCI_ITOFF(CH) + 4)
2483c60ba66SKatsushi Kobayashi #define OHCI_ITCMD(CH)		(OHCI_ITOFF(CH) + 0xc)
2493c60ba66SKatsushi Kobayashi 
2503c60ba66SKatsushi Kobayashi #define OHCI_IROFF(CH)		(0x400 + 0x20 * (CH))
2513c60ba66SKatsushi Kobayashi #define OHCI_IRCTL(CH)		(OHCI_IROFF(CH))
2523c60ba66SKatsushi Kobayashi #define OHCI_IRCTLCLR(CH)	(OHCI_IROFF(CH) + 4)
2533c60ba66SKatsushi Kobayashi #define OHCI_IRCMD(CH)		(OHCI_IROFF(CH) + 0xc)
2543c60ba66SKatsushi Kobayashi #define OHCI_IRMATCH(CH)	(OHCI_IROFF(CH) + 0x10)
2553c60ba66SKatsushi Kobayashi 
2563c60ba66SKatsushi Kobayashi d_ioctl_t fwohci_ioctl;
2573c60ba66SKatsushi Kobayashi 
2583c60ba66SKatsushi Kobayashi /*
2593c60ba66SKatsushi Kobayashi  * Communication with PHY device
2603c60ba66SKatsushi Kobayashi  */
26103161bbcSDoug Rabson static uint32_t
26203161bbcSDoug Rabson fwphy_wrdata( struct fwohci_softc *sc, uint32_t addr, uint32_t data)
2633c60ba66SKatsushi Kobayashi {
26403161bbcSDoug Rabson 	uint32_t fun;
2653c60ba66SKatsushi Kobayashi 
2663c60ba66SKatsushi Kobayashi 	addr &= 0xf;
2673c60ba66SKatsushi Kobayashi 	data &= 0xff;
2683c60ba66SKatsushi Kobayashi 
2693c60ba66SKatsushi Kobayashi 	fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA));
2703c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_PHYACCESS, fun);
2713c60ba66SKatsushi Kobayashi 	DELAY(100);
2723c60ba66SKatsushi Kobayashi 
2733c60ba66SKatsushi Kobayashi 	return(fwphy_rddata( sc, addr));
2743c60ba66SKatsushi Kobayashi }
2753c60ba66SKatsushi Kobayashi 
27603161bbcSDoug Rabson static uint32_t
2773c60ba66SKatsushi Kobayashi fwohci_set_bus_manager(struct firewire_comm *fc, u_int node)
2783c60ba66SKatsushi Kobayashi {
2793c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
2803c60ba66SKatsushi Kobayashi 	int i;
28103161bbcSDoug Rabson 	uint32_t bm;
2823c60ba66SKatsushi Kobayashi 
2833c60ba66SKatsushi Kobayashi #define OHCI_CSR_DATA	0x0c
2843c60ba66SKatsushi Kobayashi #define OHCI_CSR_COMP	0x10
2853c60ba66SKatsushi Kobayashi #define OHCI_CSR_CONT	0x14
2863c60ba66SKatsushi Kobayashi #define OHCI_BUS_MANAGER_ID	0
2873c60ba66SKatsushi Kobayashi 
2883c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_CSR_DATA, node);
2893c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_CSR_COMP, 0x3f);
2903c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID);
2913c60ba66SKatsushi Kobayashi  	for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++)
2924ed65ce9SHidetoshi Shimokawa 		DELAY(10);
2933c60ba66SKatsushi Kobayashi 	bm = OREAD(sc, OHCI_CSR_DATA);
29417c3d42cSHidetoshi Shimokawa 	if((bm & 0x3f) == 0x3f)
2953c60ba66SKatsushi Kobayashi 		bm = node;
29617c3d42cSHidetoshi Shimokawa 	if (bootverbose)
29717c3d42cSHidetoshi Shimokawa 		device_printf(sc->fc.dev,
29817c3d42cSHidetoshi Shimokawa 			"fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i);
2993c60ba66SKatsushi Kobayashi 
3003c60ba66SKatsushi Kobayashi 	return(bm);
3013c60ba66SKatsushi Kobayashi }
3023c60ba66SKatsushi Kobayashi 
30303161bbcSDoug Rabson static uint32_t
304c572b810SHidetoshi Shimokawa fwphy_rddata(struct fwohci_softc *sc,  u_int addr)
3053c60ba66SKatsushi Kobayashi {
30603161bbcSDoug Rabson 	uint32_t fun, stat;
307e4b13179SHidetoshi Shimokawa 	u_int i, retry = 0;
3083c60ba66SKatsushi Kobayashi 
3093c60ba66SKatsushi Kobayashi 	addr &= 0xf;
310e4b13179SHidetoshi Shimokawa #define MAX_RETRY 100
311e4b13179SHidetoshi Shimokawa again:
312e4b13179SHidetoshi Shimokawa 	OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL);
3133c60ba66SKatsushi Kobayashi 	fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR);
3143c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_PHYACCESS, fun);
315e4b13179SHidetoshi Shimokawa 	for ( i = 0 ; i < MAX_RETRY ; i ++ ){
3163c60ba66SKatsushi Kobayashi 		fun = OREAD(sc, OHCI_PHYACCESS);
3173c60ba66SKatsushi Kobayashi 		if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0)
3183c60ba66SKatsushi Kobayashi 			break;
3194ed65ce9SHidetoshi Shimokawa 		DELAY(100);
3203c60ba66SKatsushi Kobayashi 	}
321e4b13179SHidetoshi Shimokawa 	if(i >= MAX_RETRY) {
3224ed65ce9SHidetoshi Shimokawa 		if (bootverbose)
3234ed65ce9SHidetoshi Shimokawa 			device_printf(sc->fc.dev, "phy read failed(1).\n");
3241f2361f8SHidetoshi Shimokawa 		if (++retry < MAX_RETRY) {
3254ed65ce9SHidetoshi Shimokawa 			DELAY(100);
3261f2361f8SHidetoshi Shimokawa 			goto again;
3271f2361f8SHidetoshi Shimokawa 		}
328e4b13179SHidetoshi Shimokawa 	}
329e4b13179SHidetoshi Shimokawa 	/* Make sure that SCLK is started */
330e4b13179SHidetoshi Shimokawa 	stat = OREAD(sc, FWOHCI_INTSTAT);
331e4b13179SHidetoshi Shimokawa 	if ((stat & OHCI_INT_REG_FAIL) != 0 ||
332e4b13179SHidetoshi Shimokawa 			((fun >> PHYDEV_REGADDR) & 0xf) != addr) {
3334ed65ce9SHidetoshi Shimokawa 		if (bootverbose)
3344ed65ce9SHidetoshi Shimokawa 			device_printf(sc->fc.dev, "phy read failed(2).\n");
335e4b13179SHidetoshi Shimokawa 		if (++retry < MAX_RETRY) {
3364ed65ce9SHidetoshi Shimokawa 			DELAY(100);
337e4b13179SHidetoshi Shimokawa 			goto again;
338e4b13179SHidetoshi Shimokawa 		}
339e4b13179SHidetoshi Shimokawa 	}
340e4b13179SHidetoshi Shimokawa 	if (bootverbose || retry >= MAX_RETRY)
341e4b13179SHidetoshi Shimokawa 		device_printf(sc->fc.dev,
342f9c8c31dSHidetoshi Shimokawa 		    "fwphy_rddata: 0x%x loop=%d, retry=%d\n", addr, i, retry);
343e4b13179SHidetoshi Shimokawa #undef MAX_RETRY
3443c60ba66SKatsushi Kobayashi 	return((fun >> PHYDEV_RDDATA )& 0xff);
3453c60ba66SKatsushi Kobayashi }
3463c60ba66SKatsushi Kobayashi /* Device specific ioctl. */
3473c60ba66SKatsushi Kobayashi int
3483c60ba66SKatsushi Kobayashi fwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
3493c60ba66SKatsushi Kobayashi {
3503c60ba66SKatsushi Kobayashi 	struct firewire_softc *sc;
3513c60ba66SKatsushi Kobayashi 	struct fwohci_softc *fc;
3523c60ba66SKatsushi Kobayashi 	int unit = DEV2UNIT(dev);
3533c60ba66SKatsushi Kobayashi 	int err = 0;
3543c60ba66SKatsushi Kobayashi 	struct fw_reg_req_t *reg  = (struct fw_reg_req_t *) data;
35503161bbcSDoug Rabson 	uint32_t *dmach = (uint32_t *) data;
3563c60ba66SKatsushi Kobayashi 
3573c60ba66SKatsushi Kobayashi 	sc = devclass_get_softc(firewire_devclass, unit);
3583c60ba66SKatsushi Kobayashi 	if(sc == NULL){
3593c60ba66SKatsushi Kobayashi 		return(EINVAL);
3603c60ba66SKatsushi Kobayashi 	}
3613c60ba66SKatsushi Kobayashi 	fc = (struct fwohci_softc *)sc->fc;
3623c60ba66SKatsushi Kobayashi 
3633c60ba66SKatsushi Kobayashi 	if (!data)
3643c60ba66SKatsushi Kobayashi 		return(EINVAL);
3653c60ba66SKatsushi Kobayashi 
3663c60ba66SKatsushi Kobayashi 	switch (cmd) {
3673c60ba66SKatsushi Kobayashi 	case FWOHCI_WRREG:
3683c60ba66SKatsushi Kobayashi #define OHCI_MAX_REG 0x800
3693c60ba66SKatsushi Kobayashi 		if(reg->addr <= OHCI_MAX_REG){
3703c60ba66SKatsushi Kobayashi 			OWRITE(fc, reg->addr, reg->data);
3713c60ba66SKatsushi Kobayashi 			reg->data = OREAD(fc, reg->addr);
3723c60ba66SKatsushi Kobayashi 		}else{
3733c60ba66SKatsushi Kobayashi 			err = EINVAL;
3743c60ba66SKatsushi Kobayashi 		}
3753c60ba66SKatsushi Kobayashi 		break;
3763c60ba66SKatsushi Kobayashi 	case FWOHCI_RDREG:
3773c60ba66SKatsushi Kobayashi 		if(reg->addr <= OHCI_MAX_REG){
3783c60ba66SKatsushi Kobayashi 			reg->data = OREAD(fc, reg->addr);
3793c60ba66SKatsushi Kobayashi 		}else{
3803c60ba66SKatsushi Kobayashi 			err = EINVAL;
3813c60ba66SKatsushi Kobayashi 		}
3823c60ba66SKatsushi Kobayashi 		break;
3833c60ba66SKatsushi Kobayashi /* Read DMA descriptors for debug  */
3843c60ba66SKatsushi Kobayashi 	case DUMPDMA:
3853c60ba66SKatsushi Kobayashi 		if(*dmach <= OHCI_MAX_DMA_CH ){
3863c60ba66SKatsushi Kobayashi 			dump_dma(fc, *dmach);
3873c60ba66SKatsushi Kobayashi 			dump_db(fc, *dmach);
3883c60ba66SKatsushi Kobayashi 		}else{
3893c60ba66SKatsushi Kobayashi 			err = EINVAL;
3903c60ba66SKatsushi Kobayashi 		}
3913c60ba66SKatsushi Kobayashi 		break;
392f9c8c31dSHidetoshi Shimokawa /* Read/Write Phy registers */
393f9c8c31dSHidetoshi Shimokawa #define OHCI_MAX_PHY_REG 0xf
394f9c8c31dSHidetoshi Shimokawa 	case FWOHCI_RDPHYREG:
395f9c8c31dSHidetoshi Shimokawa 		if (reg->addr <= OHCI_MAX_PHY_REG)
396f9c8c31dSHidetoshi Shimokawa 			reg->data = fwphy_rddata(fc, reg->addr);
397f9c8c31dSHidetoshi Shimokawa 		else
398f9c8c31dSHidetoshi Shimokawa 			err = EINVAL;
399f9c8c31dSHidetoshi Shimokawa 		break;
400f9c8c31dSHidetoshi Shimokawa 	case FWOHCI_WRPHYREG:
401f9c8c31dSHidetoshi Shimokawa 		if (reg->addr <= OHCI_MAX_PHY_REG)
402f9c8c31dSHidetoshi Shimokawa 			reg->data = fwphy_wrdata(fc, reg->addr, reg->data);
403f9c8c31dSHidetoshi Shimokawa 		else
404f9c8c31dSHidetoshi Shimokawa 			err = EINVAL;
405f9c8c31dSHidetoshi Shimokawa 		break;
4063c60ba66SKatsushi Kobayashi 	default:
407f9c8c31dSHidetoshi Shimokawa 		err = EINVAL;
4083c60ba66SKatsushi Kobayashi 		break;
4093c60ba66SKatsushi Kobayashi 	}
4103c60ba66SKatsushi Kobayashi 	return err;
4113c60ba66SKatsushi Kobayashi }
412c572b810SHidetoshi Shimokawa 
413d0fd7bc6SHidetoshi Shimokawa static int
414d0fd7bc6SHidetoshi Shimokawa fwohci_probe_phy(struct fwohci_softc *sc, device_t dev)
4153c60ba66SKatsushi Kobayashi {
41603161bbcSDoug Rabson 	uint32_t reg, reg2;
417d0fd7bc6SHidetoshi Shimokawa 	int e1394a = 1;
418d0fd7bc6SHidetoshi Shimokawa /*
419d0fd7bc6SHidetoshi Shimokawa  * probe PHY parameters
420d0fd7bc6SHidetoshi Shimokawa  * 0. to prove PHY version, whether compliance of 1394a.
421d0fd7bc6SHidetoshi Shimokawa  * 1. to probe maximum speed supported by the PHY and
422d0fd7bc6SHidetoshi Shimokawa  *    number of port supported by core-logic.
423d0fd7bc6SHidetoshi Shimokawa  *    It is not actually available port on your PC .
424d0fd7bc6SHidetoshi Shimokawa  */
425d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
426d0fd7bc6SHidetoshi Shimokawa 	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
427d0fd7bc6SHidetoshi Shimokawa 
428d0fd7bc6SHidetoshi Shimokawa 	if((reg >> 5) != 7 ){
429d0fd7bc6SHidetoshi Shimokawa 		sc->fc.mode &= ~FWPHYASYST;
430d0fd7bc6SHidetoshi Shimokawa 		sc->fc.nport = reg & FW_PHY_NP;
431d0fd7bc6SHidetoshi Shimokawa 		sc->fc.speed = reg & FW_PHY_SPD >> 6;
432d0fd7bc6SHidetoshi Shimokawa 		if (sc->fc.speed > MAX_SPEED) {
433d0fd7bc6SHidetoshi Shimokawa 			device_printf(dev, "invalid speed %d (fixed to %d).\n",
434d0fd7bc6SHidetoshi Shimokawa 				sc->fc.speed, MAX_SPEED);
435d0fd7bc6SHidetoshi Shimokawa 			sc->fc.speed = MAX_SPEED;
436d0fd7bc6SHidetoshi Shimokawa 		}
437d0fd7bc6SHidetoshi Shimokawa 		device_printf(dev,
43894b6f028SHidetoshi Shimokawa 			"Phy 1394 only %s, %d ports.\n",
43994b6f028SHidetoshi Shimokawa 			linkspeed[sc->fc.speed], sc->fc.nport);
440d0fd7bc6SHidetoshi Shimokawa 	}else{
441d0fd7bc6SHidetoshi Shimokawa 		reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG);
442d0fd7bc6SHidetoshi Shimokawa 		sc->fc.mode |= FWPHYASYST;
443d0fd7bc6SHidetoshi Shimokawa 		sc->fc.nport = reg & FW_PHY_NP;
444d0fd7bc6SHidetoshi Shimokawa 		sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5;
445d0fd7bc6SHidetoshi Shimokawa 		if (sc->fc.speed > MAX_SPEED) {
446d0fd7bc6SHidetoshi Shimokawa 			device_printf(dev, "invalid speed %d (fixed to %d).\n",
447d0fd7bc6SHidetoshi Shimokawa 				sc->fc.speed, MAX_SPEED);
448d0fd7bc6SHidetoshi Shimokawa 			sc->fc.speed = MAX_SPEED;
449d0fd7bc6SHidetoshi Shimokawa 		}
450d0fd7bc6SHidetoshi Shimokawa 		device_printf(dev,
45194b6f028SHidetoshi Shimokawa 			"Phy 1394a available %s, %d ports.\n",
45294b6f028SHidetoshi Shimokawa 			linkspeed[sc->fc.speed], sc->fc.nport);
453d0fd7bc6SHidetoshi Shimokawa 
454d0fd7bc6SHidetoshi Shimokawa 		/* check programPhyEnable */
455d0fd7bc6SHidetoshi Shimokawa 		reg2 = fwphy_rddata(sc, 5);
456d0fd7bc6SHidetoshi Shimokawa #if 0
457d0fd7bc6SHidetoshi Shimokawa 		if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) {
458d0fd7bc6SHidetoshi Shimokawa #else	/* XXX force to enable 1394a */
459d0fd7bc6SHidetoshi Shimokawa 		if (e1394a) {
460d0fd7bc6SHidetoshi Shimokawa #endif
461d0fd7bc6SHidetoshi Shimokawa 			if (bootverbose)
462d0fd7bc6SHidetoshi Shimokawa 				device_printf(dev,
463d0fd7bc6SHidetoshi Shimokawa 					"Enable 1394a Enhancements\n");
464d0fd7bc6SHidetoshi Shimokawa 			/* enable EAA EMC */
465d0fd7bc6SHidetoshi Shimokawa 			reg2 |= 0x03;
466d0fd7bc6SHidetoshi Shimokawa 			/* set aPhyEnhanceEnable */
467d0fd7bc6SHidetoshi Shimokawa 			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN);
468d0fd7bc6SHidetoshi Shimokawa 			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY);
469d0fd7bc6SHidetoshi Shimokawa 		} else {
470d0fd7bc6SHidetoshi Shimokawa 			/* for safe */
471d0fd7bc6SHidetoshi Shimokawa 			reg2 &= ~0x83;
472d0fd7bc6SHidetoshi Shimokawa 		}
473d0fd7bc6SHidetoshi Shimokawa 		reg2 = fwphy_wrdata(sc, 5, reg2);
474d0fd7bc6SHidetoshi Shimokawa 	}
475d0fd7bc6SHidetoshi Shimokawa 
476d0fd7bc6SHidetoshi Shimokawa 	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
477d0fd7bc6SHidetoshi Shimokawa 	if((reg >> 5) == 7 ){
478d0fd7bc6SHidetoshi Shimokawa 		reg = fwphy_rddata(sc, 4);
479d0fd7bc6SHidetoshi Shimokawa 		reg |= 1 << 6;
480d0fd7bc6SHidetoshi Shimokawa 		fwphy_wrdata(sc, 4, reg);
481d0fd7bc6SHidetoshi Shimokawa 		reg = fwphy_rddata(sc, 4);
482d0fd7bc6SHidetoshi Shimokawa 	}
483d0fd7bc6SHidetoshi Shimokawa 	return 0;
484d0fd7bc6SHidetoshi Shimokawa }
485d0fd7bc6SHidetoshi Shimokawa 
486d0fd7bc6SHidetoshi Shimokawa 
487d0fd7bc6SHidetoshi Shimokawa void
488d0fd7bc6SHidetoshi Shimokawa fwohci_reset(struct fwohci_softc *sc, device_t dev)
489d0fd7bc6SHidetoshi Shimokawa {
49094b6f028SHidetoshi Shimokawa 	int i, max_rec, speed;
49103161bbcSDoug Rabson 	uint32_t reg, reg2;
4923c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
493d0fd7bc6SHidetoshi Shimokawa 
49495a24954SDoug Rabson 	/* Disable interrupts */
495d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, FWOHCI_INTMASKCLR, ~0);
496d0fd7bc6SHidetoshi Shimokawa 
49795a24954SDoug Rabson 	/* Now stopping all DMA channels */
498d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
499d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
500d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
501d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
502d0fd7bc6SHidetoshi Shimokawa 
503d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_IR_MASKCLR, ~0);
504d0fd7bc6SHidetoshi Shimokawa 	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
505d0fd7bc6SHidetoshi Shimokawa 		OWRITE(sc,  OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
506d0fd7bc6SHidetoshi Shimokawa 		OWRITE(sc,  OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
507d0fd7bc6SHidetoshi Shimokawa 	}
508d0fd7bc6SHidetoshi Shimokawa 
509d0fd7bc6SHidetoshi Shimokawa 	/* FLUSH FIFO and reset Transmitter/Reciever */
510d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
511d0fd7bc6SHidetoshi Shimokawa 	if (bootverbose)
512d0fd7bc6SHidetoshi Shimokawa 		device_printf(dev, "resetting OHCI...");
513d0fd7bc6SHidetoshi Shimokawa 	i = 0;
514d0fd7bc6SHidetoshi Shimokawa 	while(OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) {
515d0fd7bc6SHidetoshi Shimokawa 		if (i++ > 100) break;
516d0fd7bc6SHidetoshi Shimokawa 		DELAY(1000);
517d0fd7bc6SHidetoshi Shimokawa 	}
518d0fd7bc6SHidetoshi Shimokawa 	if (bootverbose)
519d0fd7bc6SHidetoshi Shimokawa 		printf("done (loop=%d)\n", i);
520d0fd7bc6SHidetoshi Shimokawa 
52194b6f028SHidetoshi Shimokawa 	/* Probe phy */
52294b6f028SHidetoshi Shimokawa 	fwohci_probe_phy(sc, dev);
52394b6f028SHidetoshi Shimokawa 
52494b6f028SHidetoshi Shimokawa 	/* Probe link */
525d0fd7bc6SHidetoshi Shimokawa 	reg = OREAD(sc,  OHCI_BUS_OPT);
526d0fd7bc6SHidetoshi Shimokawa 	reg2 = reg | OHCI_BUSFNC;
52794b6f028SHidetoshi Shimokawa 	max_rec = (reg & 0x0000f000) >> 12;
52894b6f028SHidetoshi Shimokawa 	speed = (reg & 0x00000007);
52994b6f028SHidetoshi Shimokawa 	device_printf(dev, "Link %s, max_rec %d bytes.\n",
53094b6f028SHidetoshi Shimokawa 			linkspeed[speed], MAXREC(max_rec));
53194b6f028SHidetoshi Shimokawa 	/* XXX fix max_rec */
53294b6f028SHidetoshi Shimokawa 	sc->fc.maxrec = sc->fc.speed + 8;
53394b6f028SHidetoshi Shimokawa 	if (max_rec != sc->fc.maxrec) {
53494b6f028SHidetoshi Shimokawa 		reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12);
53594b6f028SHidetoshi Shimokawa 		device_printf(dev, "max_rec %d -> %d\n",
53694b6f028SHidetoshi Shimokawa 				MAXREC(max_rec), MAXREC(sc->fc.maxrec));
53794b6f028SHidetoshi Shimokawa 	}
538d0fd7bc6SHidetoshi Shimokawa 	if (bootverbose)
539d0fd7bc6SHidetoshi Shimokawa 		device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2);
540d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc,  OHCI_BUS_OPT, reg2);
541d0fd7bc6SHidetoshi Shimokawa 
54294b6f028SHidetoshi Shimokawa 	/* Initialize registers */
543d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]);
54477ee030bSHidetoshi Shimokawa 	OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr);
545d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND);
546d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
54777ee030bSHidetoshi Shimokawa 	OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
548d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
5499339321dSHidetoshi Shimokawa 
55094b6f028SHidetoshi Shimokawa 	/* Enable link */
55194b6f028SHidetoshi Shimokawa 	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN);
55294b6f028SHidetoshi Shimokawa 
55394b6f028SHidetoshi Shimokawa 	/* Force to start async RX DMA */
5549339321dSHidetoshi Shimokawa 	sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING;
5559339321dSHidetoshi Shimokawa 	sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING;
556d0fd7bc6SHidetoshi Shimokawa 	fwohci_rx_enable(sc, &sc->arrq);
557d0fd7bc6SHidetoshi Shimokawa 	fwohci_rx_enable(sc, &sc->arrs);
558d0fd7bc6SHidetoshi Shimokawa 
55994b6f028SHidetoshi Shimokawa 	/* Initialize async TX */
56094b6f028SHidetoshi Shimokawa 	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
56194b6f028SHidetoshi Shimokawa 	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
562630529adSHidetoshi Shimokawa 
56394b6f028SHidetoshi Shimokawa 	/* AT Retries */
56494b6f028SHidetoshi Shimokawa 	OWRITE(sc, FWOHCI_RETRY,
56594b6f028SHidetoshi Shimokawa 		/* CycleLimit   PhyRespRetries ATRespRetries ATReqRetries */
56694b6f028SHidetoshi Shimokawa 		(0xffff << 16 ) | (0x0f << 8) | (0x0f << 4) | 0x0f) ;
567630529adSHidetoshi Shimokawa 
568630529adSHidetoshi Shimokawa 	sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq);
569630529adSHidetoshi Shimokawa 	sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq);
570630529adSHidetoshi Shimokawa 	sc->atrq.bottom = sc->atrq.top;
571630529adSHidetoshi Shimokawa 	sc->atrs.bottom = sc->atrs.top;
572630529adSHidetoshi Shimokawa 
573d0fd7bc6SHidetoshi Shimokawa 	for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ;
574d0fd7bc6SHidetoshi Shimokawa 				i ++, db_tr = STAILQ_NEXT(db_tr, link)){
575d0fd7bc6SHidetoshi Shimokawa 		db_tr->xfer = NULL;
576d0fd7bc6SHidetoshi Shimokawa 	}
577d0fd7bc6SHidetoshi Shimokawa 	for( i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb ;
578d0fd7bc6SHidetoshi Shimokawa 				i ++, db_tr = STAILQ_NEXT(db_tr, link)){
579d0fd7bc6SHidetoshi Shimokawa 		db_tr->xfer = NULL;
580d0fd7bc6SHidetoshi Shimokawa 	}
581d0fd7bc6SHidetoshi Shimokawa 
58294b6f028SHidetoshi Shimokawa 
58395a24954SDoug Rabson 	/* Enable interrupts */
584d0fd7bc6SHidetoshi Shimokawa 	OWRITE(sc, FWOHCI_INTMASK,
585d0fd7bc6SHidetoshi Shimokawa 			OHCI_INT_ERR  | OHCI_INT_PHY_SID
586d0fd7bc6SHidetoshi Shimokawa 			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
587d0fd7bc6SHidetoshi Shimokawa 			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
588d0fd7bc6SHidetoshi Shimokawa 			| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
589d0fd7bc6SHidetoshi Shimokawa 	fwohci_set_intr(&sc->fc, 1);
590d0fd7bc6SHidetoshi Shimokawa 
591d0fd7bc6SHidetoshi Shimokawa }
592d0fd7bc6SHidetoshi Shimokawa 
593d0fd7bc6SHidetoshi Shimokawa int
594d0fd7bc6SHidetoshi Shimokawa fwohci_init(struct fwohci_softc *sc, device_t dev)
595d0fd7bc6SHidetoshi Shimokawa {
596ff04511eSHidetoshi Shimokawa 	int i, mver;
59703161bbcSDoug Rabson 	uint32_t reg;
59803161bbcSDoug Rabson 	uint8_t ui[8];
5993c60ba66SKatsushi Kobayashi 
60077ee030bSHidetoshi Shimokawa #if FWOHCI_TASKQUEUE
60177ee030bSHidetoshi Shimokawa 	TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
60277ee030bSHidetoshi Shimokawa #endif
60377ee030bSHidetoshi Shimokawa 
604ff04511eSHidetoshi Shimokawa /* OHCI version */
6053c60ba66SKatsushi Kobayashi 	reg = OREAD(sc, OHCI_VERSION);
606ff04511eSHidetoshi Shimokawa 	mver = (reg >> 16) & 0xff;
6073c60ba66SKatsushi Kobayashi 	device_printf(dev, "OHCI version %x.%x (ROM=%d)\n",
608ff04511eSHidetoshi Shimokawa 			mver, reg & 0xff, (reg>>24) & 1);
609ff04511eSHidetoshi Shimokawa 	if (mver < 1 || mver > 9) {
61018349893SHidetoshi Shimokawa 		device_printf(dev, "invalid OHCI version\n");
61118349893SHidetoshi Shimokawa 		return (ENXIO);
61218349893SHidetoshi Shimokawa 	}
61318349893SHidetoshi Shimokawa 
61495a24954SDoug Rabson /* Available Isochronous DMA channel probe */
6157054e848SHidetoshi Shimokawa 	OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
6167054e848SHidetoshi Shimokawa 	OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
6177054e848SHidetoshi Shimokawa 	reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
6187054e848SHidetoshi Shimokawa 	OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
6197054e848SHidetoshi Shimokawa 	OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
6207054e848SHidetoshi Shimokawa 	for (i = 0; i < 0x20; i++)
6217054e848SHidetoshi Shimokawa 		if ((reg & (1 << i)) == 0)
6227054e848SHidetoshi Shimokawa 			break;
6233c60ba66SKatsushi Kobayashi 	sc->fc.nisodma = i;
62495a24954SDoug Rabson 	device_printf(dev, "No. of Isochronous channels is %d.\n", i);
625f40a2915SHidetoshi Shimokawa 	if (i == 0)
626f40a2915SHidetoshi Shimokawa 		return (ENXIO);
6273c60ba66SKatsushi Kobayashi 
6283c60ba66SKatsushi Kobayashi 	sc->fc.arq = &sc->arrq.xferq;
6293c60ba66SKatsushi Kobayashi 	sc->fc.ars = &sc->arrs.xferq;
6303c60ba66SKatsushi Kobayashi 	sc->fc.atq = &sc->atrq.xferq;
6313c60ba66SKatsushi Kobayashi 	sc->fc.ats = &sc->atrs.xferq;
6323c60ba66SKatsushi Kobayashi 
63377ee030bSHidetoshi Shimokawa 	sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
63477ee030bSHidetoshi Shimokawa 	sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
63577ee030bSHidetoshi Shimokawa 	sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
63677ee030bSHidetoshi Shimokawa 	sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
63777ee030bSHidetoshi Shimokawa 
6383c60ba66SKatsushi Kobayashi 	sc->arrq.xferq.start = NULL;
6393c60ba66SKatsushi Kobayashi 	sc->arrs.xferq.start = NULL;
6403c60ba66SKatsushi Kobayashi 	sc->atrq.xferq.start = fwohci_start_atq;
6413c60ba66SKatsushi Kobayashi 	sc->atrs.xferq.start = fwohci_start_ats;
6423c60ba66SKatsushi Kobayashi 
64377ee030bSHidetoshi Shimokawa 	sc->arrq.xferq.buf = NULL;
64477ee030bSHidetoshi Shimokawa 	sc->arrs.xferq.buf = NULL;
64577ee030bSHidetoshi Shimokawa 	sc->atrq.xferq.buf = NULL;
64677ee030bSHidetoshi Shimokawa 	sc->atrs.xferq.buf = NULL;
6473c60ba66SKatsushi Kobayashi 
6486cada79aSHidetoshi Shimokawa 	sc->arrq.xferq.dmach = -1;
6496cada79aSHidetoshi Shimokawa 	sc->arrs.xferq.dmach = -1;
6506cada79aSHidetoshi Shimokawa 	sc->atrq.xferq.dmach = -1;
6516cada79aSHidetoshi Shimokawa 	sc->atrs.xferq.dmach = -1;
6526cada79aSHidetoshi Shimokawa 
6533c60ba66SKatsushi Kobayashi 	sc->arrq.ndesc = 1;
6543c60ba66SKatsushi Kobayashi 	sc->arrs.ndesc = 1;
655645394e6SHidetoshi Shimokawa 	sc->atrq.ndesc = 8;	/* equal to maximum of mbuf chains */
656645394e6SHidetoshi Shimokawa 	sc->atrs.ndesc = 2;
6573c60ba66SKatsushi Kobayashi 
6583c60ba66SKatsushi Kobayashi 	sc->arrq.ndb = NDB;
6593c60ba66SKatsushi Kobayashi 	sc->arrs.ndb = NDB / 2;
6603c60ba66SKatsushi Kobayashi 	sc->atrq.ndb = NDB;
6613c60ba66SKatsushi Kobayashi 	sc->atrs.ndb = NDB / 2;
6623c60ba66SKatsushi Kobayashi 
6633c60ba66SKatsushi Kobayashi 	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
6643c60ba66SKatsushi Kobayashi 		sc->fc.it[i] = &sc->it[i].xferq;
6653c60ba66SKatsushi Kobayashi 		sc->fc.ir[i] = &sc->ir[i].xferq;
6666cada79aSHidetoshi Shimokawa 		sc->it[i].xferq.dmach = i;
6676cada79aSHidetoshi Shimokawa 		sc->ir[i].xferq.dmach = i;
6683c60ba66SKatsushi Kobayashi 		sc->it[i].ndb = 0;
6693c60ba66SKatsushi Kobayashi 		sc->ir[i].ndb = 0;
6703c60ba66SKatsushi Kobayashi 	}
6713c60ba66SKatsushi Kobayashi 
6723c60ba66SKatsushi Kobayashi 	sc->fc.tcode = tinfo;
67377ee030bSHidetoshi Shimokawa 	sc->fc.dev = dev;
6743c60ba66SKatsushi Kobayashi 
67577ee030bSHidetoshi Shimokawa 	sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE,
67677ee030bSHidetoshi Shimokawa 						&sc->crom_dma, BUS_DMA_WAITOK);
67777ee030bSHidetoshi Shimokawa 	if(sc->fc.config_rom == NULL){
67877ee030bSHidetoshi Shimokawa 		device_printf(dev, "config_rom alloc failed.");
6793c60ba66SKatsushi Kobayashi 		return ENOMEM;
6803c60ba66SKatsushi Kobayashi 	}
6813c60ba66SKatsushi Kobayashi 
6820bc666e0SHidetoshi Shimokawa #if 0
6830bc666e0SHidetoshi Shimokawa 	bzero(&sc->fc.config_rom[0], CROMSIZE);
6843c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[1] = 0x31333934;
6853c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[2] = 0xf000a002;
6863c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
6873c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO);
6883c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[5] = 0;
6893c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[0] = (4 << 24) | (5 << 16);
6903c60ba66SKatsushi Kobayashi 
6913c60ba66SKatsushi Kobayashi 	sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4);
69277ee030bSHidetoshi Shimokawa #endif
6933c60ba66SKatsushi Kobayashi 
6943c60ba66SKatsushi Kobayashi 
69595a24954SDoug Rabson /* SID recieve buffer must align 2^11 */
6963c60ba66SKatsushi Kobayashi #define	OHCI_SIDSIZE	(1 << 11)
69777ee030bSHidetoshi Shimokawa 	sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE,
69877ee030bSHidetoshi Shimokawa 						&sc->sid_dma, BUS_DMA_WAITOK);
69977ee030bSHidetoshi Shimokawa 	if (sc->sid_buf == NULL) {
70077ee030bSHidetoshi Shimokawa 		device_printf(dev, "sid_buf alloc failed.");
70116e0f484SHidetoshi Shimokawa 		return ENOMEM;
70216e0f484SHidetoshi Shimokawa 	}
7033c60ba66SKatsushi Kobayashi 
70403161bbcSDoug Rabson 	fwdma_malloc(&sc->fc, sizeof(uint32_t), sizeof(uint32_t),
70577ee030bSHidetoshi Shimokawa 					&sc->dummy_dma, BUS_DMA_WAITOK);
70677ee030bSHidetoshi Shimokawa 
70777ee030bSHidetoshi Shimokawa 	if (sc->dummy_dma.v_addr == NULL) {
70877ee030bSHidetoshi Shimokawa 		device_printf(dev, "dummy_dma alloc failed.");
70977ee030bSHidetoshi Shimokawa 		return ENOMEM;
71077ee030bSHidetoshi Shimokawa 	}
71177ee030bSHidetoshi Shimokawa 
71277ee030bSHidetoshi Shimokawa 	fwohci_db_init(sc, &sc->arrq);
7131f2361f8SHidetoshi Shimokawa 	if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0)
7141f2361f8SHidetoshi Shimokawa 		return ENOMEM;
7151f2361f8SHidetoshi Shimokawa 
71677ee030bSHidetoshi Shimokawa 	fwohci_db_init(sc, &sc->arrs);
7171f2361f8SHidetoshi Shimokawa 	if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0)
7181f2361f8SHidetoshi Shimokawa 		return ENOMEM;
7193c60ba66SKatsushi Kobayashi 
72077ee030bSHidetoshi Shimokawa 	fwohci_db_init(sc, &sc->atrq);
7211f2361f8SHidetoshi Shimokawa 	if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0)
7221f2361f8SHidetoshi Shimokawa 		return ENOMEM;
7231f2361f8SHidetoshi Shimokawa 
72477ee030bSHidetoshi Shimokawa 	fwohci_db_init(sc, &sc->atrs);
7251f2361f8SHidetoshi Shimokawa 	if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0)
7261f2361f8SHidetoshi Shimokawa 		return ENOMEM;
7273c60ba66SKatsushi Kobayashi 
728c547b896SHidetoshi Shimokawa 	sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H);
729c547b896SHidetoshi Shimokawa 	sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L);
730c547b896SHidetoshi Shimokawa 	for( i = 0 ; i < 8 ; i ++)
731c547b896SHidetoshi Shimokawa 		ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i);
7323c60ba66SKatsushi Kobayashi 	device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
733c547b896SHidetoshi Shimokawa 		ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]);
734c547b896SHidetoshi Shimokawa 
7353c60ba66SKatsushi Kobayashi 	sc->fc.ioctl = fwohci_ioctl;
7363c60ba66SKatsushi Kobayashi 	sc->fc.cyctimer = fwohci_cyctimer;
7373c60ba66SKatsushi Kobayashi 	sc->fc.set_bmr = fwohci_set_bus_manager;
7383c60ba66SKatsushi Kobayashi 	sc->fc.ibr = fwohci_ibr;
7393c60ba66SKatsushi Kobayashi 	sc->fc.irx_enable = fwohci_irx_enable;
7403c60ba66SKatsushi Kobayashi 	sc->fc.irx_disable = fwohci_irx_disable;
7413c60ba66SKatsushi Kobayashi 
7423c60ba66SKatsushi Kobayashi 	sc->fc.itx_enable = fwohci_itxbuf_enable;
7433c60ba66SKatsushi Kobayashi 	sc->fc.itx_disable = fwohci_itx_disable;
74477ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
7453c60ba66SKatsushi Kobayashi 	sc->fc.irx_post = fwohci_irx_post;
74677ee030bSHidetoshi Shimokawa #else
74777ee030bSHidetoshi Shimokawa 	sc->fc.irx_post = NULL;
74877ee030bSHidetoshi Shimokawa #endif
7493c60ba66SKatsushi Kobayashi 	sc->fc.itx_post = NULL;
7503c60ba66SKatsushi Kobayashi 	sc->fc.timeout = fwohci_timeout;
7513c60ba66SKatsushi Kobayashi 	sc->fc.poll = fwohci_poll;
7523c60ba66SKatsushi Kobayashi 	sc->fc.set_intr = fwohci_set_intr;
753c572b810SHidetoshi Shimokawa 
75477ee030bSHidetoshi Shimokawa 	sc->intmask = sc->irstat = sc->itstat = 0;
75577ee030bSHidetoshi Shimokawa 
756d0fd7bc6SHidetoshi Shimokawa 	fw_init(&sc->fc);
757d0fd7bc6SHidetoshi Shimokawa 	fwohci_reset(sc, dev);
7583c60ba66SKatsushi Kobayashi 
759d0fd7bc6SHidetoshi Shimokawa 	return 0;
7603c60ba66SKatsushi Kobayashi }
761c572b810SHidetoshi Shimokawa 
762c572b810SHidetoshi Shimokawa void
763c572b810SHidetoshi Shimokawa fwohci_timeout(void *arg)
7643c60ba66SKatsushi Kobayashi {
7653c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc;
7663c60ba66SKatsushi Kobayashi 
7673c60ba66SKatsushi Kobayashi 	sc = (struct fwohci_softc *)arg;
7683c60ba66SKatsushi Kobayashi }
769c572b810SHidetoshi Shimokawa 
77003161bbcSDoug Rabson uint32_t
771c572b810SHidetoshi Shimokawa fwohci_cyctimer(struct firewire_comm *fc)
7723c60ba66SKatsushi Kobayashi {
7733c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
7743c60ba66SKatsushi Kobayashi 	return(OREAD(sc, OHCI_CYCLETIMER));
7753c60ba66SKatsushi Kobayashi }
7763c60ba66SKatsushi Kobayashi 
7771f2361f8SHidetoshi Shimokawa int
7781f2361f8SHidetoshi Shimokawa fwohci_detach(struct fwohci_softc *sc, device_t dev)
7791f2361f8SHidetoshi Shimokawa {
7801f2361f8SHidetoshi Shimokawa 	int i;
7811f2361f8SHidetoshi Shimokawa 
78277ee030bSHidetoshi Shimokawa 	if (sc->sid_buf != NULL)
78377ee030bSHidetoshi Shimokawa 		fwdma_free(&sc->fc, &sc->sid_dma);
78477ee030bSHidetoshi Shimokawa 	if (sc->fc.config_rom != NULL)
78577ee030bSHidetoshi Shimokawa 		fwdma_free(&sc->fc, &sc->crom_dma);
7861f2361f8SHidetoshi Shimokawa 
7871f2361f8SHidetoshi Shimokawa 	fwohci_db_free(&sc->arrq);
7881f2361f8SHidetoshi Shimokawa 	fwohci_db_free(&sc->arrs);
7891f2361f8SHidetoshi Shimokawa 
7901f2361f8SHidetoshi Shimokawa 	fwohci_db_free(&sc->atrq);
7911f2361f8SHidetoshi Shimokawa 	fwohci_db_free(&sc->atrs);
7921f2361f8SHidetoshi Shimokawa 
7931f2361f8SHidetoshi Shimokawa 	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
7941f2361f8SHidetoshi Shimokawa 		fwohci_db_free(&sc->it[i]);
7951f2361f8SHidetoshi Shimokawa 		fwohci_db_free(&sc->ir[i]);
7961f2361f8SHidetoshi Shimokawa 	}
7971f2361f8SHidetoshi Shimokawa 
7981f2361f8SHidetoshi Shimokawa 	return 0;
7991f2361f8SHidetoshi Shimokawa }
8001f2361f8SHidetoshi Shimokawa 
801d6105b60SHidetoshi Shimokawa #define LAST_DB(dbtr, db) do {						\
802d6105b60SHidetoshi Shimokawa 	struct fwohcidb_tr *_dbtr = (dbtr);				\
803d6105b60SHidetoshi Shimokawa 	int _cnt = _dbtr->dbcnt;					\
804d6105b60SHidetoshi Shimokawa 	db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0];			\
805d6105b60SHidetoshi Shimokawa } while (0)
806d6105b60SHidetoshi Shimokawa 
807c572b810SHidetoshi Shimokawa static void
80877ee030bSHidetoshi Shimokawa fwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error)
80977ee030bSHidetoshi Shimokawa {
81077ee030bSHidetoshi Shimokawa 	struct fwohcidb_tr *db_tr;
811c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
81277ee030bSHidetoshi Shimokawa 	bus_dma_segment_t *s;
81377ee030bSHidetoshi Shimokawa 	int i;
81477ee030bSHidetoshi Shimokawa 
81577ee030bSHidetoshi Shimokawa 	db_tr = (struct fwohcidb_tr *)arg;
81677ee030bSHidetoshi Shimokawa 	db = &db_tr->db[db_tr->dbcnt];
81777ee030bSHidetoshi Shimokawa 	if (error) {
81877ee030bSHidetoshi Shimokawa 		if (firewire_debug || error != EFBIG)
81977ee030bSHidetoshi Shimokawa 			printf("fwohci_execute_db: error=%d\n", error);
82077ee030bSHidetoshi Shimokawa 		return;
82177ee030bSHidetoshi Shimokawa 	}
82277ee030bSHidetoshi Shimokawa 	for (i = 0; i < nseg; i++) {
82377ee030bSHidetoshi Shimokawa 		s = &segs[i];
82477ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr);
82577ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len);
82677ee030bSHidetoshi Shimokawa  		FWOHCI_DMA_WRITE(db->db.desc.res, 0);
82777ee030bSHidetoshi Shimokawa 		db++;
82877ee030bSHidetoshi Shimokawa 		db_tr->dbcnt++;
82977ee030bSHidetoshi Shimokawa 	}
83077ee030bSHidetoshi Shimokawa }
83177ee030bSHidetoshi Shimokawa 
83277ee030bSHidetoshi Shimokawa static void
83377ee030bSHidetoshi Shimokawa fwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg,
83477ee030bSHidetoshi Shimokawa 						bus_size_t size, int error)
83577ee030bSHidetoshi Shimokawa {
83677ee030bSHidetoshi Shimokawa 	fwohci_execute_db(arg, segs, nseg, error);
83777ee030bSHidetoshi Shimokawa }
83877ee030bSHidetoshi Shimokawa 
83977ee030bSHidetoshi Shimokawa static void
840c572b810SHidetoshi Shimokawa fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
8413c60ba66SKatsushi Kobayashi {
8423c60ba66SKatsushi Kobayashi 	int i, s;
843c4778b5dSHidetoshi Shimokawa 	int tcode, hdr_len, pl_off;
8443c60ba66SKatsushi Kobayashi 	int fsegment = -1;
84503161bbcSDoug Rabson 	uint32_t off;
8463c60ba66SKatsushi Kobayashi 	struct fw_xfer *xfer;
8473c60ba66SKatsushi Kobayashi 	struct fw_pkt *fp;
848c4778b5dSHidetoshi Shimokawa 	struct fwohci_txpkthdr *ohcifp;
8493c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
850c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
85103161bbcSDoug Rabson 	uint32_t *ld;
8523c60ba66SKatsushi Kobayashi 	struct tcode_info *info;
853d6105b60SHidetoshi Shimokawa 	static int maxdesc=0;
8543c60ba66SKatsushi Kobayashi 
8553c60ba66SKatsushi Kobayashi 	if(&sc->atrq == dbch){
8563c60ba66SKatsushi Kobayashi 		off = OHCI_ATQOFF;
8573c60ba66SKatsushi Kobayashi 	}else if(&sc->atrs == dbch){
8583c60ba66SKatsushi Kobayashi 		off = OHCI_ATSOFF;
8593c60ba66SKatsushi Kobayashi 	}else{
8603c60ba66SKatsushi Kobayashi 		return;
8613c60ba66SKatsushi Kobayashi 	}
8623c60ba66SKatsushi Kobayashi 
8633c60ba66SKatsushi Kobayashi 	if (dbch->flags & FWOHCI_DBCH_FULL)
8643c60ba66SKatsushi Kobayashi 		return;
8653c60ba66SKatsushi Kobayashi 
8663c60ba66SKatsushi Kobayashi 	s = splfw();
8673c60ba66SKatsushi Kobayashi 	db_tr = dbch->top;
8683c60ba66SKatsushi Kobayashi txloop:
8693c60ba66SKatsushi Kobayashi 	xfer = STAILQ_FIRST(&dbch->xferq.q);
8703c60ba66SKatsushi Kobayashi 	if(xfer == NULL){
8713c60ba66SKatsushi Kobayashi 		goto kick;
8723c60ba66SKatsushi Kobayashi 	}
8733c60ba66SKatsushi Kobayashi 	if(dbch->xferq.queued == 0 ){
8743c60ba66SKatsushi Kobayashi 		device_printf(sc->fc.dev, "TX queue empty\n");
8753c60ba66SKatsushi Kobayashi 	}
8763c60ba66SKatsushi Kobayashi 	STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
8773c60ba66SKatsushi Kobayashi 	db_tr->xfer = xfer;
8783c60ba66SKatsushi Kobayashi 	xfer->state = FWXF_START;
8793c60ba66SKatsushi Kobayashi 
880c4778b5dSHidetoshi Shimokawa 	fp = &xfer->send.hdr;
8813c60ba66SKatsushi Kobayashi 	tcode = fp->mode.common.tcode;
8823c60ba66SKatsushi Kobayashi 
883c4778b5dSHidetoshi Shimokawa 	ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
8843c60ba66SKatsushi Kobayashi 	info = &tinfo[tcode];
88577ee030bSHidetoshi Shimokawa 	hdr_len = pl_off = info->hdr_len;
886a1c9e73aSHidetoshi Shimokawa 
887a1c9e73aSHidetoshi Shimokawa 	ld = &ohcifp->mode.ld[0];
888a1c9e73aSHidetoshi Shimokawa 	ld[0] = ld[1] = ld[2] = ld[3] = 0;
889a1c9e73aSHidetoshi Shimokawa 	for( i = 0 ; i < pl_off ; i+= 4)
890a1c9e73aSHidetoshi Shimokawa 		ld[i/4] = fp->mode.ld[i/4];
891a1c9e73aSHidetoshi Shimokawa 
892c4778b5dSHidetoshi Shimokawa 	ohcifp->mode.common.spd = xfer->send.spd & 0x7;
8933c60ba66SKatsushi Kobayashi 	if (tcode == FWTCODE_STREAM ){
8943c60ba66SKatsushi Kobayashi 		hdr_len = 8;
89577ee030bSHidetoshi Shimokawa 		ohcifp->mode.stream.len = fp->mode.stream.len;
8963c60ba66SKatsushi Kobayashi 	} else if (tcode == FWTCODE_PHY) {
8973c60ba66SKatsushi Kobayashi 		hdr_len = 12;
898a1c9e73aSHidetoshi Shimokawa 		ld[1] = fp->mode.ld[1];
899a1c9e73aSHidetoshi Shimokawa 		ld[2] = fp->mode.ld[2];
9003c60ba66SKatsushi Kobayashi 		ohcifp->mode.common.spd = 0;
9013c60ba66SKatsushi Kobayashi 		ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
9023c60ba66SKatsushi Kobayashi 	} else {
90377ee030bSHidetoshi Shimokawa 		ohcifp->mode.asycomm.dst = fp->mode.hdr.dst;
9043c60ba66SKatsushi Kobayashi 		ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS;
9053c60ba66SKatsushi Kobayashi 		ohcifp->mode.asycomm.tlrt |= FWRETRY_X;
9063c60ba66SKatsushi Kobayashi 	}
9073c60ba66SKatsushi Kobayashi 	db = &db_tr->db[0];
90877ee030bSHidetoshi Shimokawa  	FWOHCI_DMA_WRITE(db->db.desc.cmd,
90977ee030bSHidetoshi Shimokawa 			OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
910a1c9e73aSHidetoshi Shimokawa  	FWOHCI_DMA_WRITE(db->db.desc.addr, 0);
91177ee030bSHidetoshi Shimokawa  	FWOHCI_DMA_WRITE(db->db.desc.res, 0);
9123c60ba66SKatsushi Kobayashi /* Specify bound timer of asy. responce */
9133c60ba66SKatsushi Kobayashi 	if(&sc->atrs == dbch){
91477ee030bSHidetoshi Shimokawa  		FWOHCI_DMA_WRITE(db->db.desc.res,
91577ee030bSHidetoshi Shimokawa 			 (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13));
9163c60ba66SKatsushi Kobayashi 	}
91777ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
91877ee030bSHidetoshi Shimokawa 	if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
91977ee030bSHidetoshi Shimokawa 		hdr_len = 12;
92077ee030bSHidetoshi Shimokawa 	for (i = 0; i < hdr_len/4; i ++)
921a1c9e73aSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(ld[i], ld[i]);
92277ee030bSHidetoshi Shimokawa #endif
9233c60ba66SKatsushi Kobayashi 
9242b4601d1SHidetoshi Shimokawa again:
9253c60ba66SKatsushi Kobayashi 	db_tr->dbcnt = 2;
9263c60ba66SKatsushi Kobayashi 	db = &db_tr->db[db_tr->dbcnt];
927c4778b5dSHidetoshi Shimokawa 	if (xfer->send.pay_len > 0) {
92877ee030bSHidetoshi Shimokawa 		int err;
92977ee030bSHidetoshi Shimokawa 		/* handle payload */
9303c60ba66SKatsushi Kobayashi 		if (xfer->mbuf == NULL) {
93177ee030bSHidetoshi Shimokawa 			err = bus_dmamap_load(dbch->dmat, db_tr->dma_map,
932c4778b5dSHidetoshi Shimokawa 				&xfer->send.payload[0], xfer->send.pay_len,
93377ee030bSHidetoshi Shimokawa 				fwohci_execute_db, db_tr,
93477ee030bSHidetoshi Shimokawa 				/*flags*/0);
9353c60ba66SKatsushi Kobayashi 		} else {
9362b4601d1SHidetoshi Shimokawa 			/* XXX we can handle only 6 (=8-2) mbuf chains */
93777ee030bSHidetoshi Shimokawa 			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
93877ee030bSHidetoshi Shimokawa 				xfer->mbuf,
93977ee030bSHidetoshi Shimokawa 				fwohci_execute_db2, db_tr,
94077ee030bSHidetoshi Shimokawa 				/* flags */0);
94177ee030bSHidetoshi Shimokawa 			if (err == EFBIG) {
94277ee030bSHidetoshi Shimokawa 				struct mbuf *m0;
94377ee030bSHidetoshi Shimokawa 
94477ee030bSHidetoshi Shimokawa 				if (firewire_debug)
94577ee030bSHidetoshi Shimokawa 					device_printf(sc->fc.dev, "EFBIG.\n");
94677ee030bSHidetoshi Shimokawa 				m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
94777ee030bSHidetoshi Shimokawa 				if (m0 != NULL) {
9482b4601d1SHidetoshi Shimokawa 					m_copydata(xfer->mbuf, 0,
9492b4601d1SHidetoshi Shimokawa 						xfer->mbuf->m_pkthdr.len,
95077ee030bSHidetoshi Shimokawa 						mtod(m0, caddr_t));
95177ee030bSHidetoshi Shimokawa 					m0->m_len = m0->m_pkthdr.len =
9522b4601d1SHidetoshi Shimokawa 						xfer->mbuf->m_pkthdr.len;
9532b4601d1SHidetoshi Shimokawa 					m_freem(xfer->mbuf);
95477ee030bSHidetoshi Shimokawa 					xfer->mbuf = m0;
9552b4601d1SHidetoshi Shimokawa 					goto again;
9562b4601d1SHidetoshi Shimokawa 				}
9572b4601d1SHidetoshi Shimokawa 				device_printf(sc->fc.dev, "m_getcl failed.\n");
9582b4601d1SHidetoshi Shimokawa 			}
9593c60ba66SKatsushi Kobayashi 		}
96077ee030bSHidetoshi Shimokawa 		if (err)
96177ee030bSHidetoshi Shimokawa 			printf("dmamap_load: err=%d\n", err);
96277ee030bSHidetoshi Shimokawa 		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
96377ee030bSHidetoshi Shimokawa 						BUS_DMASYNC_PREWRITE);
96477ee030bSHidetoshi Shimokawa #if 0 /* OHCI_OUTPUT_MODE == 0 */
96577ee030bSHidetoshi Shimokawa 		for (i = 2; i < db_tr->dbcnt; i++)
96677ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd,
96777ee030bSHidetoshi Shimokawa 						OHCI_OUTPUT_MORE);
96877ee030bSHidetoshi Shimokawa #endif
969d6105b60SHidetoshi Shimokawa 	}
970d6105b60SHidetoshi Shimokawa 	if (maxdesc < db_tr->dbcnt) {
971d6105b60SHidetoshi Shimokawa 		maxdesc = db_tr->dbcnt;
972d6105b60SHidetoshi Shimokawa 		if (bootverbose)
973d6105b60SHidetoshi Shimokawa 			device_printf(sc->fc.dev, "maxdesc: %d\n", maxdesc);
974d6105b60SHidetoshi Shimokawa 	}
9753c60ba66SKatsushi Kobayashi 	/* last db */
9763c60ba66SKatsushi Kobayashi 	LAST_DB(db_tr, db);
97777ee030bSHidetoshi Shimokawa  	FWOHCI_DMA_SET(db->db.desc.cmd,
97877ee030bSHidetoshi Shimokawa 		OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
97977ee030bSHidetoshi Shimokawa  	FWOHCI_DMA_WRITE(db->db.desc.depend,
98077ee030bSHidetoshi Shimokawa 			STAILQ_NEXT(db_tr, link)->bus_addr);
9813c60ba66SKatsushi Kobayashi 
9823c60ba66SKatsushi Kobayashi 	if(fsegment == -1 )
9833c60ba66SKatsushi Kobayashi 		fsegment = db_tr->dbcnt;
9843c60ba66SKatsushi Kobayashi 	if (dbch->pdb_tr != NULL) {
9853c60ba66SKatsushi Kobayashi 		LAST_DB(dbch->pdb_tr, db);
98677ee030bSHidetoshi Shimokawa  		FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
9873c60ba66SKatsushi Kobayashi 	}
9883c60ba66SKatsushi Kobayashi 	dbch->pdb_tr = db_tr;
9893c60ba66SKatsushi Kobayashi 	db_tr = STAILQ_NEXT(db_tr, link);
9903c60ba66SKatsushi Kobayashi 	if(db_tr != dbch->bottom){
9913c60ba66SKatsushi Kobayashi 		goto txloop;
9923c60ba66SKatsushi Kobayashi 	} else {
99317c3d42cSHidetoshi Shimokawa 		device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n");
9943c60ba66SKatsushi Kobayashi 		dbch->flags |= FWOHCI_DBCH_FULL;
9953c60ba66SKatsushi Kobayashi 	}
9963c60ba66SKatsushi Kobayashi kick:
9973c60ba66SKatsushi Kobayashi 	/* kick asy q */
99877ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
99977ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
10003c60ba66SKatsushi Kobayashi 
10013c60ba66SKatsushi Kobayashi 	if(dbch->xferq.flag & FWXFERQ_RUNNING) {
10023c60ba66SKatsushi Kobayashi 		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
10033c60ba66SKatsushi Kobayashi 	} else {
100417c3d42cSHidetoshi Shimokawa 		if (bootverbose)
100517c3d42cSHidetoshi Shimokawa 			device_printf(sc->fc.dev, "start AT DMA status=%x\n",
10063c60ba66SKatsushi Kobayashi 					OREAD(sc, OHCI_DMACTL(off)));
100777ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment);
10083c60ba66SKatsushi Kobayashi 		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
10093c60ba66SKatsushi Kobayashi 		dbch->xferq.flag |= FWXFERQ_RUNNING;
10103c60ba66SKatsushi Kobayashi 	}
1011c572b810SHidetoshi Shimokawa 
10123c60ba66SKatsushi Kobayashi 	dbch->top = db_tr;
10133c60ba66SKatsushi Kobayashi 	splx(s);
10143c60ba66SKatsushi Kobayashi 	return;
10153c60ba66SKatsushi Kobayashi }
1016c572b810SHidetoshi Shimokawa 
1017c572b810SHidetoshi Shimokawa static void
1018c572b810SHidetoshi Shimokawa fwohci_start_atq(struct firewire_comm *fc)
10193c60ba66SKatsushi Kobayashi {
10203c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
10213c60ba66SKatsushi Kobayashi 	fwohci_start( sc, &(sc->atrq));
10223c60ba66SKatsushi Kobayashi 	return;
10233c60ba66SKatsushi Kobayashi }
1024c572b810SHidetoshi Shimokawa 
1025c572b810SHidetoshi Shimokawa static void
1026c572b810SHidetoshi Shimokawa fwohci_start_ats(struct firewire_comm *fc)
10273c60ba66SKatsushi Kobayashi {
10283c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
10293c60ba66SKatsushi Kobayashi 	fwohci_start( sc, &(sc->atrs));
10303c60ba66SKatsushi Kobayashi 	return;
10313c60ba66SKatsushi Kobayashi }
1032c572b810SHidetoshi Shimokawa 
1033c572b810SHidetoshi Shimokawa void
1034c572b810SHidetoshi Shimokawa fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
10353c60ba66SKatsushi Kobayashi {
103677ee030bSHidetoshi Shimokawa 	int s, ch, err = 0;
10373c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *tr;
1038c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
10393c60ba66SKatsushi Kobayashi 	struct fw_xfer *xfer;
104003161bbcSDoug Rabson 	uint32_t off;
104177ee030bSHidetoshi Shimokawa 	u_int stat, status;
10423c60ba66SKatsushi Kobayashi 	int	packets;
10433c60ba66SKatsushi Kobayashi 	struct firewire_comm *fc = (struct firewire_comm *)sc;
104477ee030bSHidetoshi Shimokawa 
10453c60ba66SKatsushi Kobayashi 	if(&sc->atrq == dbch){
10463c60ba66SKatsushi Kobayashi 		off = OHCI_ATQOFF;
104777ee030bSHidetoshi Shimokawa 		ch = ATRQ_CH;
10483c60ba66SKatsushi Kobayashi 	}else if(&sc->atrs == dbch){
10493c60ba66SKatsushi Kobayashi 		off = OHCI_ATSOFF;
105077ee030bSHidetoshi Shimokawa 		ch = ATRS_CH;
10513c60ba66SKatsushi Kobayashi 	}else{
10523c60ba66SKatsushi Kobayashi 		return;
10533c60ba66SKatsushi Kobayashi 	}
10543c60ba66SKatsushi Kobayashi 	s = splfw();
10553c60ba66SKatsushi Kobayashi 	tr = dbch->bottom;
10563c60ba66SKatsushi Kobayashi 	packets = 0;
105777ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
105877ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
10593c60ba66SKatsushi Kobayashi 	while(dbch->xferq.queued > 0){
10603c60ba66SKatsushi Kobayashi 		LAST_DB(tr, db);
106177ee030bSHidetoshi Shimokawa 		status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
106277ee030bSHidetoshi Shimokawa 		if(!(status & OHCI_CNTL_DMA_ACTIVE)){
10633c60ba66SKatsushi Kobayashi 			if (fc->status != FWBUSRESET)
10643c60ba66SKatsushi Kobayashi 				/* maybe out of order?? */
10653c60ba66SKatsushi Kobayashi 				goto out;
10663c60ba66SKatsushi Kobayashi 		}
106777ee030bSHidetoshi Shimokawa 		bus_dmamap_sync(dbch->dmat, tr->dma_map,
106877ee030bSHidetoshi Shimokawa 			BUS_DMASYNC_POSTWRITE);
106977ee030bSHidetoshi Shimokawa 		bus_dmamap_unload(dbch->dmat, tr->dma_map);
1070a1c9e73aSHidetoshi Shimokawa #if 1
1071a1c9e73aSHidetoshi Shimokawa 		if (firewire_debug)
10723c60ba66SKatsushi Kobayashi 			dump_db(sc, ch);
10733c60ba66SKatsushi Kobayashi #endif
107477ee030bSHidetoshi Shimokawa 		if(status & OHCI_CNTL_DMA_DEAD) {
10753c60ba66SKatsushi Kobayashi 			/* Stop DMA */
10763c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
10773c60ba66SKatsushi Kobayashi 			device_printf(sc->fc.dev, "force reset AT FIFO\n");
10783c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN);
10793c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN);
10803c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
10813c60ba66SKatsushi Kobayashi 		}
108277ee030bSHidetoshi Shimokawa 		stat = status & FWOHCIEV_MASK;
10833c60ba66SKatsushi Kobayashi 		switch(stat){
10843c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKPEND:
1085864d7e72SHidetoshi Shimokawa 		case FWOHCIEV_ACKCOMPL:
10863c60ba66SKatsushi Kobayashi 			err = 0;
10873c60ba66SKatsushi Kobayashi 			break;
10883c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKBSA:
10893c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKBSB:
10903c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKBSX:
1091864d7e72SHidetoshi Shimokawa 			device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
10923c60ba66SKatsushi Kobayashi 			err = EBUSY;
10933c60ba66SKatsushi Kobayashi 			break;
10943c60ba66SKatsushi Kobayashi 		case FWOHCIEV_FLUSHED:
10953c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKTARD:
10963c60ba66SKatsushi Kobayashi 			device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
10973c60ba66SKatsushi Kobayashi 			err = EAGAIN;
10983c60ba66SKatsushi Kobayashi 			break;
10993c60ba66SKatsushi Kobayashi 		case FWOHCIEV_MISSACK:
11003c60ba66SKatsushi Kobayashi 		case FWOHCIEV_UNDRRUN:
11013c60ba66SKatsushi Kobayashi 		case FWOHCIEV_OVRRUN:
11023c60ba66SKatsushi Kobayashi 		case FWOHCIEV_DESCERR:
11033c60ba66SKatsushi Kobayashi 		case FWOHCIEV_DTRDERR:
11043c60ba66SKatsushi Kobayashi 		case FWOHCIEV_TIMEOUT:
11053c60ba66SKatsushi Kobayashi 		case FWOHCIEV_TCODERR:
11063c60ba66SKatsushi Kobayashi 		case FWOHCIEV_UNKNOWN:
11073c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKDERR:
11083c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKTERR:
11093c60ba66SKatsushi Kobayashi 		default:
11103c60ba66SKatsushi Kobayashi 			device_printf(sc->fc.dev, "txd err=%2x %s\n",
11113c60ba66SKatsushi Kobayashi 							stat, fwohcicode[stat]);
11123c60ba66SKatsushi Kobayashi 			err = EINVAL;
11133c60ba66SKatsushi Kobayashi 			break;
11143c60ba66SKatsushi Kobayashi 		}
11153c60ba66SKatsushi Kobayashi 		if (tr->xfer != NULL) {
11163c60ba66SKatsushi Kobayashi 			xfer = tr->xfer;
111777ee030bSHidetoshi Shimokawa 			if (xfer->state == FWXF_RCVD) {
11181a753700SHidetoshi Shimokawa #if 0
111977ee030bSHidetoshi Shimokawa 				if (firewire_debug)
112077ee030bSHidetoshi Shimokawa 					printf("already rcvd\n");
11211a753700SHidetoshi Shimokawa #endif
112277ee030bSHidetoshi Shimokawa 				fw_xfer_done(xfer);
112377ee030bSHidetoshi Shimokawa 			} else {
11243c60ba66SKatsushi Kobayashi 				xfer->state = FWXF_SENT;
11253c60ba66SKatsushi Kobayashi 				if (err == EBUSY && fc->status != FWBUSRESET) {
11263c60ba66SKatsushi Kobayashi 					xfer->state = FWXF_BUSY;
11273c60ba66SKatsushi Kobayashi 					xfer->resp = err;
1128864d7e72SHidetoshi Shimokawa 					if (xfer->retry_req != NULL)
11293c60ba66SKatsushi Kobayashi 						xfer->retry_req(xfer);
113013bd8601SHidetoshi Shimokawa 					else {
1131c4778b5dSHidetoshi Shimokawa 						xfer->recv.pay_len = 0;
1132864d7e72SHidetoshi Shimokawa 						fw_xfer_done(xfer);
113313bd8601SHidetoshi Shimokawa 					}
11343c60ba66SKatsushi Kobayashi 				} else if (stat != FWOHCIEV_ACKPEND) {
11353c60ba66SKatsushi Kobayashi 					if (stat != FWOHCIEV_ACKCOMPL)
11363c60ba66SKatsushi Kobayashi 						xfer->state = FWXF_SENTERR;
11373c60ba66SKatsushi Kobayashi 					xfer->resp = err;
1138c4778b5dSHidetoshi Shimokawa 					xfer->recv.pay_len = 0;
11393c60ba66SKatsushi Kobayashi 					fw_xfer_done(xfer);
11403c60ba66SKatsushi Kobayashi 				}
11413c60ba66SKatsushi Kobayashi 			}
1142864d7e72SHidetoshi Shimokawa 			/*
1143864d7e72SHidetoshi Shimokawa 			 * The watchdog timer takes care of split
1144864d7e72SHidetoshi Shimokawa 			 * transcation timeout for ACKPEND case.
1145864d7e72SHidetoshi Shimokawa 			 */
114677ee030bSHidetoshi Shimokawa 		} else {
114777ee030bSHidetoshi Shimokawa 			printf("this shouldn't happen\n");
11483c60ba66SKatsushi Kobayashi 		}
114948249fe0SHidetoshi Shimokawa 		dbch->xferq.queued --;
11503c60ba66SKatsushi Kobayashi 		tr->xfer = NULL;
11513c60ba66SKatsushi Kobayashi 
11523c60ba66SKatsushi Kobayashi 		packets ++;
11533c60ba66SKatsushi Kobayashi 		tr = STAILQ_NEXT(tr, link);
11543c60ba66SKatsushi Kobayashi 		dbch->bottom = tr;
11553b79dd16SHidetoshi Shimokawa 		if (dbch->bottom == dbch->top) {
11563b79dd16SHidetoshi Shimokawa 			/* we reaches the end of context program */
11573b79dd16SHidetoshi Shimokawa 			if (firewire_debug && dbch->xferq.queued > 0)
11583b79dd16SHidetoshi Shimokawa 				printf("queued > 0\n");
11593b79dd16SHidetoshi Shimokawa 			break;
11603b79dd16SHidetoshi Shimokawa 		}
11613c60ba66SKatsushi Kobayashi 	}
11623c60ba66SKatsushi Kobayashi out:
11633c60ba66SKatsushi Kobayashi 	if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
11643c60ba66SKatsushi Kobayashi 		printf("make free slot\n");
11653c60ba66SKatsushi Kobayashi 		dbch->flags &= ~FWOHCI_DBCH_FULL;
11663c60ba66SKatsushi Kobayashi 		fwohci_start(sc, dbch);
11673c60ba66SKatsushi Kobayashi 	}
11683c60ba66SKatsushi Kobayashi 	splx(s);
11693c60ba66SKatsushi Kobayashi }
1170c572b810SHidetoshi Shimokawa 
1171c572b810SHidetoshi Shimokawa static void
1172c572b810SHidetoshi Shimokawa fwohci_db_free(struct fwohci_dbch *dbch)
11733c60ba66SKatsushi Kobayashi {
11743c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
117577ee030bSHidetoshi Shimokawa 	int idb;
11763c60ba66SKatsushi Kobayashi 
11771f2361f8SHidetoshi Shimokawa 	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
11781f2361f8SHidetoshi Shimokawa 		return;
11791f2361f8SHidetoshi Shimokawa 
118077ee030bSHidetoshi Shimokawa 	for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb;
11813c60ba66SKatsushi Kobayashi 			db_tr = STAILQ_NEXT(db_tr, link), idb++){
118277ee030bSHidetoshi Shimokawa 		if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 &&
118377ee030bSHidetoshi Shimokawa 					db_tr->buf != NULL) {
118477ee030bSHidetoshi Shimokawa 			fwdma_free_size(dbch->dmat, db_tr->dma_map,
118577ee030bSHidetoshi Shimokawa 					db_tr->buf, dbch->xferq.psize);
11863c60ba66SKatsushi Kobayashi 			db_tr->buf = NULL;
118777ee030bSHidetoshi Shimokawa 		} else if (db_tr->dma_map != NULL)
118877ee030bSHidetoshi Shimokawa 			bus_dmamap_destroy(dbch->dmat, db_tr->dma_map);
11891f2361f8SHidetoshi Shimokawa 	}
11903c60ba66SKatsushi Kobayashi 	dbch->ndb = 0;
11913c60ba66SKatsushi Kobayashi 	db_tr = STAILQ_FIRST(&dbch->db_trq);
119277ee030bSHidetoshi Shimokawa 	fwdma_free_multiseg(dbch->am);
11935166f1dfSHidetoshi Shimokawa 	free(db_tr, M_FW);
11943c60ba66SKatsushi Kobayashi 	STAILQ_INIT(&dbch->db_trq);
11951f2361f8SHidetoshi Shimokawa 	dbch->flags &= ~FWOHCI_DBCH_INIT;
11963c60ba66SKatsushi Kobayashi }
1197c572b810SHidetoshi Shimokawa 
1198c572b810SHidetoshi Shimokawa static void
119977ee030bSHidetoshi Shimokawa fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
12003c60ba66SKatsushi Kobayashi {
12013c60ba66SKatsushi Kobayashi 	int	idb;
12023c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
12039339321dSHidetoshi Shimokawa 
12049339321dSHidetoshi Shimokawa 	if ((dbch->flags & FWOHCI_DBCH_INIT) != 0)
12059339321dSHidetoshi Shimokawa 		goto out;
12069339321dSHidetoshi Shimokawa 
120777ee030bSHidetoshi Shimokawa 	/* create dma_tag for buffers */
120877ee030bSHidetoshi Shimokawa #define MAX_REQCOUNT	0xffff
120977ee030bSHidetoshi Shimokawa 	if (bus_dma_tag_create(/*parent*/ sc->fc.dmat,
121077ee030bSHidetoshi Shimokawa 			/*alignment*/ 1, /*boundary*/ 0,
121177ee030bSHidetoshi Shimokawa 			/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
121277ee030bSHidetoshi Shimokawa 			/*highaddr*/ BUS_SPACE_MAXADDR,
121377ee030bSHidetoshi Shimokawa 			/*filter*/NULL, /*filterarg*/NULL,
121477ee030bSHidetoshi Shimokawa 			/*maxsize*/ dbch->xferq.psize,
121577ee030bSHidetoshi Shimokawa 			/*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1,
121677ee030bSHidetoshi Shimokawa 			/*maxsegsz*/ MAX_REQCOUNT,
1217f6b1c44dSScott Long 			/*flags*/ 0,
121810d3ed64SHidetoshi Shimokawa #if defined(__FreeBSD__) && __FreeBSD_version >= 501102
1219f6b1c44dSScott Long 			/*lockfunc*/busdma_lock_mutex,
12204f933468SHidetoshi Shimokawa 			/*lockarg*/&Giant,
12214f933468SHidetoshi Shimokawa #endif
12224f933468SHidetoshi Shimokawa 			&dbch->dmat))
122377ee030bSHidetoshi Shimokawa 		return;
122477ee030bSHidetoshi Shimokawa 
12253c60ba66SKatsushi Kobayashi 	/* allocate DB entries and attach one to each DMA channels */
12263c60ba66SKatsushi Kobayashi 	/* DB entry must start at 16 bytes bounary. */
12273c60ba66SKatsushi Kobayashi 	STAILQ_INIT(&dbch->db_trq);
12283c60ba66SKatsushi Kobayashi 	db_tr = (struct fwohcidb_tr *)
12293c60ba66SKatsushi Kobayashi 		malloc(sizeof(struct fwohcidb_tr) * dbch->ndb,
123077ee030bSHidetoshi Shimokawa 		M_FW, M_WAITOK | M_ZERO);
12313c60ba66SKatsushi Kobayashi 	if(db_tr == NULL){
1232e2ad5d6eSHidetoshi Shimokawa 		printf("fwohci_db_init: malloc(1) failed\n");
12333c60ba66SKatsushi Kobayashi 		return;
12343c60ba66SKatsushi Kobayashi 	}
1235e2ad5d6eSHidetoshi Shimokawa 
123677ee030bSHidetoshi Shimokawa #define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc)
123777ee030bSHidetoshi Shimokawa 	dbch->am = fwdma_malloc_multiseg(&sc->fc, DB_SIZE(dbch),
123877ee030bSHidetoshi Shimokawa 		DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK);
123977ee030bSHidetoshi Shimokawa 	if (dbch->am == NULL) {
124077ee030bSHidetoshi Shimokawa 		printf("fwohci_db_init: fwdma_malloc_multiseg failed\n");
12414c790222SHidetoshi Shimokawa 		free(db_tr, M_FW);
1242e2ad5d6eSHidetoshi Shimokawa 		return;
1243e2ad5d6eSHidetoshi Shimokawa 	}
12443c60ba66SKatsushi Kobayashi 	/* Attach DB to DMA ch. */
12453c60ba66SKatsushi Kobayashi 	for(idb = 0 ; idb < dbch->ndb ; idb++){
12463c60ba66SKatsushi Kobayashi 		db_tr->dbcnt = 0;
124777ee030bSHidetoshi Shimokawa 		db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb);
124877ee030bSHidetoshi Shimokawa 		db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb);
124977ee030bSHidetoshi Shimokawa 		/* create dmamap for buffers */
125077ee030bSHidetoshi Shimokawa 		/* XXX do we need 4bytes alignment tag? */
125177ee030bSHidetoshi Shimokawa 		/* XXX don't alloc dma_map for AR */
125277ee030bSHidetoshi Shimokawa 		if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) {
125377ee030bSHidetoshi Shimokawa 			printf("bus_dmamap_create failed\n");
125477ee030bSHidetoshi Shimokawa 			dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
125577ee030bSHidetoshi Shimokawa 			fwohci_db_free(dbch);
125677ee030bSHidetoshi Shimokawa 			return;
125777ee030bSHidetoshi Shimokawa 		}
12583c60ba66SKatsushi Kobayashi 		STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link);
125977ee030bSHidetoshi Shimokawa 		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1260d0fd7bc6SHidetoshi Shimokawa 			if (idb % dbch->xferq.bnpacket == 0)
1261d0fd7bc6SHidetoshi Shimokawa 				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1262d0fd7bc6SHidetoshi Shimokawa 						].start = (caddr_t)db_tr;
1263d0fd7bc6SHidetoshi Shimokawa 			if ((idb + 1) % dbch->xferq.bnpacket == 0)
1264d0fd7bc6SHidetoshi Shimokawa 				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1265d0fd7bc6SHidetoshi Shimokawa 						].end = (caddr_t)db_tr;
12663c60ba66SKatsushi Kobayashi 		}
12673c60ba66SKatsushi Kobayashi 		db_tr++;
12683c60ba66SKatsushi Kobayashi 	}
12693c60ba66SKatsushi Kobayashi 	STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next
12703c60ba66SKatsushi Kobayashi 			= STAILQ_FIRST(&dbch->db_trq);
12719339321dSHidetoshi Shimokawa out:
12729339321dSHidetoshi Shimokawa 	dbch->xferq.queued = 0;
12739339321dSHidetoshi Shimokawa 	dbch->pdb_tr = NULL;
12743c60ba66SKatsushi Kobayashi 	dbch->top = STAILQ_FIRST(&dbch->db_trq);
12753c60ba66SKatsushi Kobayashi 	dbch->bottom = dbch->top;
12761f2361f8SHidetoshi Shimokawa 	dbch->flags = FWOHCI_DBCH_INIT;
12773c60ba66SKatsushi Kobayashi }
1278c572b810SHidetoshi Shimokawa 
1279c572b810SHidetoshi Shimokawa static int
1280c572b810SHidetoshi Shimokawa fwohci_itx_disable(struct firewire_comm *fc, int dmach)
12813c60ba66SKatsushi Kobayashi {
12823c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
128377ee030bSHidetoshi Shimokawa 	int sleepch;
12845a7ba74dSHidetoshi Shimokawa 
128577ee030bSHidetoshi Shimokawa 	OWRITE(sc, OHCI_ITCTLCLR(dmach),
128677ee030bSHidetoshi Shimokawa 			OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
12873c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
12883c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
12895a7ba74dSHidetoshi Shimokawa 	/* XXX we cannot free buffers until the DMA really stops */
129077ee030bSHidetoshi Shimokawa 	tsleep((void *)&sleepch, FWPRI, "fwitxd", hz);
12913c60ba66SKatsushi Kobayashi 	fwohci_db_free(&sc->it[dmach]);
12923c60ba66SKatsushi Kobayashi 	sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
12933c60ba66SKatsushi Kobayashi 	return 0;
12943c60ba66SKatsushi Kobayashi }
1295c572b810SHidetoshi Shimokawa 
1296c572b810SHidetoshi Shimokawa static int
1297c572b810SHidetoshi Shimokawa fwohci_irx_disable(struct firewire_comm *fc, int dmach)
12983c60ba66SKatsushi Kobayashi {
12993c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
130077ee030bSHidetoshi Shimokawa 	int sleepch;
13013c60ba66SKatsushi Kobayashi 
13023c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
13033c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
13043c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
13055a7ba74dSHidetoshi Shimokawa 	/* XXX we cannot free buffers until the DMA really stops */
130677ee030bSHidetoshi Shimokawa 	tsleep((void *)&sleepch, FWPRI, "fwirxd", hz);
13073c60ba66SKatsushi Kobayashi 	fwohci_db_free(&sc->ir[dmach]);
13083c60ba66SKatsushi Kobayashi 	sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
13093c60ba66SKatsushi Kobayashi 	return 0;
13103c60ba66SKatsushi Kobayashi }
1311c572b810SHidetoshi Shimokawa 
131277ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
1313c572b810SHidetoshi Shimokawa static void
131403161bbcSDoug Rabson fwohci_irx_post (struct firewire_comm *fc , uint32_t *qld)
13153c60ba66SKatsushi Kobayashi {
131677ee030bSHidetoshi Shimokawa 	qld[0] = FWOHCI_DMA_READ(qld[0]);
13173c60ba66SKatsushi Kobayashi 	return;
13183c60ba66SKatsushi Kobayashi }
13193c60ba66SKatsushi Kobayashi #endif
13203c60ba66SKatsushi Kobayashi 
1321c572b810SHidetoshi Shimokawa static int
1322c572b810SHidetoshi Shimokawa fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
13233c60ba66SKatsushi Kobayashi {
13243c60ba66SKatsushi Kobayashi 	int err = 0;
132577ee030bSHidetoshi Shimokawa 	int idb, z, i, dmach = 0, ldesc;
132603161bbcSDoug Rabson 	uint32_t off = 0;
13273c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
1328c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
13293c60ba66SKatsushi Kobayashi 
13303c60ba66SKatsushi Kobayashi 	if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){
13313c60ba66SKatsushi Kobayashi 		err = EINVAL;
13323c60ba66SKatsushi Kobayashi 		return err;
13333c60ba66SKatsushi Kobayashi 	}
13343c60ba66SKatsushi Kobayashi 	z = dbch->ndesc;
13353c60ba66SKatsushi Kobayashi 	for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){
13363c60ba66SKatsushi Kobayashi 		if( &sc->it[dmach] == dbch){
13373c60ba66SKatsushi Kobayashi 			off = OHCI_ITOFF(dmach);
13383c60ba66SKatsushi Kobayashi 			break;
13393c60ba66SKatsushi Kobayashi 		}
13403c60ba66SKatsushi Kobayashi 	}
1341a89ec05eSPeter Wemm 	if(off == 0){
13423c60ba66SKatsushi Kobayashi 		err = EINVAL;
13433c60ba66SKatsushi Kobayashi 		return err;
13443c60ba66SKatsushi Kobayashi 	}
13453c60ba66SKatsushi Kobayashi 	if(dbch->xferq.flag & FWXFERQ_RUNNING)
13463c60ba66SKatsushi Kobayashi 		return err;
13473c60ba66SKatsushi Kobayashi 	dbch->xferq.flag |= FWXFERQ_RUNNING;
13483c60ba66SKatsushi Kobayashi 	for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){
13493c60ba66SKatsushi Kobayashi 		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
13503c60ba66SKatsushi Kobayashi 	}
13513c60ba66SKatsushi Kobayashi 	db_tr = dbch->top;
13523c60ba66SKatsushi Kobayashi 	for (idb = 0; idb < dbch->ndb; idb ++) {
135377ee030bSHidetoshi Shimokawa 		fwohci_add_tx_buf(dbch, db_tr, idb);
13543c60ba66SKatsushi Kobayashi 		if(STAILQ_NEXT(db_tr, link) == NULL){
13553c60ba66SKatsushi Kobayashi 			break;
13563c60ba66SKatsushi Kobayashi 		}
135753f1eb86SHidetoshi Shimokawa 		db = db_tr->db;
135877ee030bSHidetoshi Shimokawa 		ldesc = db_tr->dbcnt - 1;
135977ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[0].db.desc.depend,
136077ee030bSHidetoshi Shimokawa 				STAILQ_NEXT(db_tr, link)->bus_addr | z);
136177ee030bSHidetoshi Shimokawa 		db[ldesc].db.desc.depend = db[0].db.desc.depend;
13623c60ba66SKatsushi Kobayashi 		if(dbch->xferq.flag & FWXFERQ_EXTBUF){
13633c60ba66SKatsushi Kobayashi 			if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
136477ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_SET(
136577ee030bSHidetoshi Shimokawa 					db[ldesc].db.desc.cmd,
136677ee030bSHidetoshi Shimokawa 					OHCI_INTERRUPT_ALWAYS);
13674ed65ce9SHidetoshi Shimokawa 				/* OHCI 1.1 and above */
136877ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_SET(
136977ee030bSHidetoshi Shimokawa 					db[0].db.desc.cmd,
137077ee030bSHidetoshi Shimokawa 					OHCI_INTERRUPT_ALWAYS);
13713c60ba66SKatsushi Kobayashi 			}
13723c60ba66SKatsushi Kobayashi 		}
13733c60ba66SKatsushi Kobayashi 		db_tr = STAILQ_NEXT(db_tr, link);
13743c60ba66SKatsushi Kobayashi 	}
137577ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_CLEAR(
137677ee030bSHidetoshi Shimokawa 		dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf);
13773c60ba66SKatsushi Kobayashi 	return err;
13783c60ba66SKatsushi Kobayashi }
1379c572b810SHidetoshi Shimokawa 
1380c572b810SHidetoshi Shimokawa static int
1381c572b810SHidetoshi Shimokawa fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
13823c60ba66SKatsushi Kobayashi {
13833c60ba66SKatsushi Kobayashi 	int err = 0;
138453f1eb86SHidetoshi Shimokawa 	int idb, z, i, dmach = 0, ldesc;
138503161bbcSDoug Rabson 	uint32_t off = 0;
13863c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
1387c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
13883c60ba66SKatsushi Kobayashi 
13893c60ba66SKatsushi Kobayashi 	z = dbch->ndesc;
13903c60ba66SKatsushi Kobayashi 	if(&sc->arrq == dbch){
13913c60ba66SKatsushi Kobayashi 		off = OHCI_ARQOFF;
13923c60ba66SKatsushi Kobayashi 	}else if(&sc->arrs == dbch){
13933c60ba66SKatsushi Kobayashi 		off = OHCI_ARSOFF;
13943c60ba66SKatsushi Kobayashi 	}else{
13953c60ba66SKatsushi Kobayashi 		for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){
13963c60ba66SKatsushi Kobayashi 			if( &sc->ir[dmach] == dbch){
13973c60ba66SKatsushi Kobayashi 				off = OHCI_IROFF(dmach);
13983c60ba66SKatsushi Kobayashi 				break;
13993c60ba66SKatsushi Kobayashi 			}
14003c60ba66SKatsushi Kobayashi 		}
14013c60ba66SKatsushi Kobayashi 	}
1402a89ec05eSPeter Wemm 	if(off == 0){
14033c60ba66SKatsushi Kobayashi 		err = EINVAL;
14043c60ba66SKatsushi Kobayashi 		return err;
14053c60ba66SKatsushi Kobayashi 	}
14063c60ba66SKatsushi Kobayashi 	if(dbch->xferq.flag & FWXFERQ_STREAM){
14073c60ba66SKatsushi Kobayashi 		if(dbch->xferq.flag & FWXFERQ_RUNNING)
14083c60ba66SKatsushi Kobayashi 			return err;
14093c60ba66SKatsushi Kobayashi 	}else{
14103c60ba66SKatsushi Kobayashi 		if(dbch->xferq.flag & FWXFERQ_RUNNING){
14113c60ba66SKatsushi Kobayashi 			err = EBUSY;
14123c60ba66SKatsushi Kobayashi 			return err;
14133c60ba66SKatsushi Kobayashi 		}
14143c60ba66SKatsushi Kobayashi 	}
14153c60ba66SKatsushi Kobayashi 	dbch->xferq.flag |= FWXFERQ_RUNNING;
14169339321dSHidetoshi Shimokawa 	dbch->top = STAILQ_FIRST(&dbch->db_trq);
14173c60ba66SKatsushi Kobayashi 	for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){
14183c60ba66SKatsushi Kobayashi 		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
14193c60ba66SKatsushi Kobayashi 	}
14203c60ba66SKatsushi Kobayashi 	db_tr = dbch->top;
14213c60ba66SKatsushi Kobayashi 	for (idb = 0; idb < dbch->ndb; idb ++) {
142277ee030bSHidetoshi Shimokawa 		fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma);
142377ee030bSHidetoshi Shimokawa 		if (STAILQ_NEXT(db_tr, link) == NULL)
14243c60ba66SKatsushi Kobayashi 			break;
142553f1eb86SHidetoshi Shimokawa 		db = db_tr->db;
142653f1eb86SHidetoshi Shimokawa 		ldesc = db_tr->dbcnt - 1;
142777ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend,
142877ee030bSHidetoshi Shimokawa 			STAILQ_NEXT(db_tr, link)->bus_addr | z);
14293c60ba66SKatsushi Kobayashi 		if(dbch->xferq.flag & FWXFERQ_EXTBUF){
14303c60ba66SKatsushi Kobayashi 			if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
143177ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_SET(
143277ee030bSHidetoshi Shimokawa 					db[ldesc].db.desc.cmd,
143377ee030bSHidetoshi Shimokawa 					OHCI_INTERRUPT_ALWAYS);
143477ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_CLEAR(
143577ee030bSHidetoshi Shimokawa 					db[ldesc].db.desc.depend,
143677ee030bSHidetoshi Shimokawa 					0xf);
14373c60ba66SKatsushi Kobayashi 			}
14383c60ba66SKatsushi Kobayashi 		}
14393c60ba66SKatsushi Kobayashi 		db_tr = STAILQ_NEXT(db_tr, link);
14403c60ba66SKatsushi Kobayashi 	}
144177ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_CLEAR(
144277ee030bSHidetoshi Shimokawa 		dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf);
14433c60ba66SKatsushi Kobayashi 	dbch->buf_offset = 0;
144477ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
144577ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
14463c60ba66SKatsushi Kobayashi 	if(dbch->xferq.flag & FWXFERQ_STREAM){
14473c60ba66SKatsushi Kobayashi 		return err;
14483c60ba66SKatsushi Kobayashi 	}else{
144977ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z);
14503c60ba66SKatsushi Kobayashi 	}
14513c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
14523c60ba66SKatsushi Kobayashi 	return err;
14533c60ba66SKatsushi Kobayashi }
1454c572b810SHidetoshi Shimokawa 
1455c572b810SHidetoshi Shimokawa static int
145677ee030bSHidetoshi Shimokawa fwohci_next_cycle(struct firewire_comm *fc, int cycle_now)
14573c60ba66SKatsushi Kobayashi {
14585a7ba74dSHidetoshi Shimokawa 	int sec, cycle, cycle_match;
14593c60ba66SKatsushi Kobayashi 
146097ae6c1fSHidetoshi Shimokawa 	cycle = cycle_now & 0x1fff;
146197ae6c1fSHidetoshi Shimokawa 	sec = cycle_now >> 13;
146297ae6c1fSHidetoshi Shimokawa #define CYCLE_MOD	0x10
146377ee030bSHidetoshi Shimokawa #if 1
146497ae6c1fSHidetoshi Shimokawa #define CYCLE_DELAY	8	/* min delay to start DMA */
146577ee030bSHidetoshi Shimokawa #else
146677ee030bSHidetoshi Shimokawa #define CYCLE_DELAY	7000	/* min delay to start DMA */
146777ee030bSHidetoshi Shimokawa #endif
146897ae6c1fSHidetoshi Shimokawa 	cycle = cycle + CYCLE_DELAY;
146997ae6c1fSHidetoshi Shimokawa 	if (cycle >= 8000) {
147097ae6c1fSHidetoshi Shimokawa 		sec ++;
147197ae6c1fSHidetoshi Shimokawa 		cycle -= 8000;
147297ae6c1fSHidetoshi Shimokawa 	}
147377ee030bSHidetoshi Shimokawa 	cycle = roundup2(cycle, CYCLE_MOD);
147497ae6c1fSHidetoshi Shimokawa 	if (cycle >= 8000) {
147597ae6c1fSHidetoshi Shimokawa 		sec ++;
147697ae6c1fSHidetoshi Shimokawa 		if (cycle == 8000)
147797ae6c1fSHidetoshi Shimokawa 			cycle = 0;
147897ae6c1fSHidetoshi Shimokawa 		else
147997ae6c1fSHidetoshi Shimokawa 			cycle = CYCLE_MOD;
148097ae6c1fSHidetoshi Shimokawa 	}
148197ae6c1fSHidetoshi Shimokawa 	cycle_match = ((sec << 13) | cycle) & 0x7ffff;
14825a7ba74dSHidetoshi Shimokawa 
14835a7ba74dSHidetoshi Shimokawa 	return(cycle_match);
14845a7ba74dSHidetoshi Shimokawa }
14855a7ba74dSHidetoshi Shimokawa 
14865a7ba74dSHidetoshi Shimokawa static int
14875a7ba74dSHidetoshi Shimokawa fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
14885a7ba74dSHidetoshi Shimokawa {
14895a7ba74dSHidetoshi Shimokawa 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
14905a7ba74dSHidetoshi Shimokawa 	int err = 0;
14915a7ba74dSHidetoshi Shimokawa 	unsigned short tag, ich;
14925a7ba74dSHidetoshi Shimokawa 	struct fwohci_dbch *dbch;
14935a7ba74dSHidetoshi Shimokawa 	int cycle_match, cycle_now, s, ldesc;
149403161bbcSDoug Rabson 	uint32_t stat;
14955a7ba74dSHidetoshi Shimokawa 	struct fw_bulkxfer *first, *chunk, *prev;
14965a7ba74dSHidetoshi Shimokawa 	struct fw_xferq *it;
14975a7ba74dSHidetoshi Shimokawa 
14985a7ba74dSHidetoshi Shimokawa 	dbch = &sc->it[dmach];
14995a7ba74dSHidetoshi Shimokawa 	it = &dbch->xferq;
15005a7ba74dSHidetoshi Shimokawa 
15015a7ba74dSHidetoshi Shimokawa 	tag = (it->flag >> 6) & 3;
15025a7ba74dSHidetoshi Shimokawa 	ich = it->flag & 0x3f;
15035a7ba74dSHidetoshi Shimokawa 	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
15045a7ba74dSHidetoshi Shimokawa 		dbch->ndb = it->bnpacket * it->bnchunk;
15055a7ba74dSHidetoshi Shimokawa 		dbch->ndesc = 3;
150677ee030bSHidetoshi Shimokawa 		fwohci_db_init(sc, dbch);
15075a7ba74dSHidetoshi Shimokawa 		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
15085a7ba74dSHidetoshi Shimokawa 			return ENOMEM;
15095a7ba74dSHidetoshi Shimokawa 		err = fwohci_tx_enable(sc, dbch);
15105a7ba74dSHidetoshi Shimokawa 	}
15115a7ba74dSHidetoshi Shimokawa 	if(err)
15125a7ba74dSHidetoshi Shimokawa 		return err;
15135a7ba74dSHidetoshi Shimokawa 
151453f1eb86SHidetoshi Shimokawa 	ldesc = dbch->ndesc - 1;
15155a7ba74dSHidetoshi Shimokawa 	s = splfw();
15165a7ba74dSHidetoshi Shimokawa 	prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
15175a7ba74dSHidetoshi Shimokawa 	while  ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
1518c4778b5dSHidetoshi Shimokawa 		struct fwohcidb *db;
15195a7ba74dSHidetoshi Shimokawa 
152077ee030bSHidetoshi Shimokawa 		fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
152177ee030bSHidetoshi Shimokawa 					BUS_DMASYNC_PREWRITE);
15225a7ba74dSHidetoshi Shimokawa 		fwohci_txbufdb(sc, dmach, chunk);
15235a7ba74dSHidetoshi Shimokawa 		if (prev != NULL) {
15245a7ba74dSHidetoshi Shimokawa 			db = ((struct fwohcidb_tr *)(prev->end))->db;
152577ee030bSHidetoshi Shimokawa #if 0 /* XXX necessary? */
152677ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
152777ee030bSHidetoshi Shimokawa 						OHCI_BRANCH_ALWAYS);
152877ee030bSHidetoshi Shimokawa #endif
152953f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npacket changes */
15305a7ba74dSHidetoshi Shimokawa 			db[ldesc].db.desc.depend = db[0].db.desc.depend =
153177ee030bSHidetoshi Shimokawa 				((struct fwohcidb_tr *)
153277ee030bSHidetoshi Shimokawa 				(chunk->start))->bus_addr | dbch->ndesc;
153353f1eb86SHidetoshi Shimokawa #else
153477ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
153577ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
153653f1eb86SHidetoshi Shimokawa #endif
15375a7ba74dSHidetoshi Shimokawa 		}
15385a7ba74dSHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&it->stvalid, link);
15395a7ba74dSHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
15405a7ba74dSHidetoshi Shimokawa 		prev = chunk;
15415a7ba74dSHidetoshi Shimokawa 	}
154277ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
154377ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
15445a7ba74dSHidetoshi Shimokawa 	splx(s);
15455a7ba74dSHidetoshi Shimokawa 	stat = OREAD(sc, OHCI_ITCTL(dmach));
154677ee030bSHidetoshi Shimokawa 	if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S))
154777ee030bSHidetoshi Shimokawa 		printf("stat 0x%x\n", stat);
154877ee030bSHidetoshi Shimokawa 
15495a7ba74dSHidetoshi Shimokawa 	if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S))
15505a7ba74dSHidetoshi Shimokawa 		return 0;
15515a7ba74dSHidetoshi Shimokawa 
155277ee030bSHidetoshi Shimokawa #if 0
15535a7ba74dSHidetoshi Shimokawa 	OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
155477ee030bSHidetoshi Shimokawa #endif
15555a7ba74dSHidetoshi Shimokawa 	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
15565a7ba74dSHidetoshi Shimokawa 	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
15575a7ba74dSHidetoshi Shimokawa 	OWRITE(sc, OHCI_IT_MASK, 1 << dmach);
155877ee030bSHidetoshi Shimokawa 	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT);
15595a7ba74dSHidetoshi Shimokawa 
15605a7ba74dSHidetoshi Shimokawa 	first = STAILQ_FIRST(&it->stdma);
156177ee030bSHidetoshi Shimokawa 	OWRITE(sc, OHCI_ITCMD(dmach),
156277ee030bSHidetoshi Shimokawa 		((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
156377ee030bSHidetoshi Shimokawa 	if (firewire_debug) {
15645a7ba74dSHidetoshi Shimokawa 		printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
156577ee030bSHidetoshi Shimokawa #if 1
156677ee030bSHidetoshi Shimokawa 		dump_dma(sc, ITX_CH + dmach);
156777ee030bSHidetoshi Shimokawa #endif
156877ee030bSHidetoshi Shimokawa 	}
15695a7ba74dSHidetoshi Shimokawa 	if ((stat & OHCI_CNTL_DMA_RUN) == 0) {
15705a7ba74dSHidetoshi Shimokawa #if 1
15715a7ba74dSHidetoshi Shimokawa 		/* Don't start until all chunks are buffered */
15725a7ba74dSHidetoshi Shimokawa 		if (STAILQ_FIRST(&it->stfree) != NULL)
15735a7ba74dSHidetoshi Shimokawa 			goto out;
15745a7ba74dSHidetoshi Shimokawa #endif
157577ee030bSHidetoshi Shimokawa #if 1
157697ae6c1fSHidetoshi Shimokawa 		/* Clear cycle match counter bits */
157797ae6c1fSHidetoshi Shimokawa 		OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000);
15785a7ba74dSHidetoshi Shimokawa 
15795a7ba74dSHidetoshi Shimokawa 		/* 2bit second + 13bit cycle */
15805a7ba74dSHidetoshi Shimokawa 		cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff;
158177ee030bSHidetoshi Shimokawa 		cycle_match = fwohci_next_cycle(fc, cycle_now);
15825a7ba74dSHidetoshi Shimokawa 
158397ae6c1fSHidetoshi Shimokawa 		OWRITE(sc, OHCI_ITCTL(dmach),
158497ae6c1fSHidetoshi Shimokawa 				OHCI_CNTL_CYCMATCH_S | (cycle_match << 16)
158597ae6c1fSHidetoshi Shimokawa 				| OHCI_CNTL_DMA_RUN);
158677ee030bSHidetoshi Shimokawa #else
158777ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
158877ee030bSHidetoshi Shimokawa #endif
158977ee030bSHidetoshi Shimokawa 		if (firewire_debug) {
15907643dc18SHidetoshi Shimokawa 			printf("cycle_match: 0x%04x->0x%04x\n",
15917643dc18SHidetoshi Shimokawa 						cycle_now, cycle_match);
159277ee030bSHidetoshi Shimokawa 			dump_dma(sc, ITX_CH + dmach);
159377ee030bSHidetoshi Shimokawa 			dump_db(sc, ITX_CH + dmach);
159477ee030bSHidetoshi Shimokawa 		}
15957643dc18SHidetoshi Shimokawa 	} else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) {
15965a7ba74dSHidetoshi Shimokawa 		device_printf(sc->fc.dev,
15975a7ba74dSHidetoshi Shimokawa 			"IT DMA underrun (0x%08x)\n", stat);
159877ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE);
15993c60ba66SKatsushi Kobayashi 	}
16005a7ba74dSHidetoshi Shimokawa out:
16013c60ba66SKatsushi Kobayashi 	return err;
16023c60ba66SKatsushi Kobayashi }
1603c572b810SHidetoshi Shimokawa 
1604c572b810SHidetoshi Shimokawa static int
160577ee030bSHidetoshi Shimokawa fwohci_irx_enable(struct firewire_comm *fc, int dmach)
16063c60ba66SKatsushi Kobayashi {
16073c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
16085a7ba74dSHidetoshi Shimokawa 	int err = 0, s, ldesc;
16093c60ba66SKatsushi Kobayashi 	unsigned short tag, ich;
161003161bbcSDoug Rabson 	uint32_t stat;
16115a7ba74dSHidetoshi Shimokawa 	struct fwohci_dbch *dbch;
161277ee030bSHidetoshi Shimokawa 	struct fwohcidb_tr *db_tr;
16135a7ba74dSHidetoshi Shimokawa 	struct fw_bulkxfer *first, *prev, *chunk;
16145a7ba74dSHidetoshi Shimokawa 	struct fw_xferq *ir;
1615435dd29bSHidetoshi Shimokawa 
16165a7ba74dSHidetoshi Shimokawa 	dbch = &sc->ir[dmach];
16175a7ba74dSHidetoshi Shimokawa 	ir = &dbch->xferq;
16185a7ba74dSHidetoshi Shimokawa 
16195a7ba74dSHidetoshi Shimokawa 	if ((ir->flag & FWXFERQ_RUNNING) == 0) {
16205a7ba74dSHidetoshi Shimokawa 		tag = (ir->flag >> 6) & 3;
16215a7ba74dSHidetoshi Shimokawa 		ich = ir->flag & 0x3f;
16223c60ba66SKatsushi Kobayashi 		OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich);
16233c60ba66SKatsushi Kobayashi 
16245a7ba74dSHidetoshi Shimokawa 		ir->queued = 0;
16255a7ba74dSHidetoshi Shimokawa 		dbch->ndb = ir->bnpacket * ir->bnchunk;
16265a7ba74dSHidetoshi Shimokawa 		dbch->ndesc = 2;
162777ee030bSHidetoshi Shimokawa 		fwohci_db_init(sc, dbch);
16285a7ba74dSHidetoshi Shimokawa 		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
16290aaa9a23SHidetoshi Shimokawa 			return ENOMEM;
16305a7ba74dSHidetoshi Shimokawa 		err = fwohci_rx_enable(sc, dbch);
16313c60ba66SKatsushi Kobayashi 	}
16323c60ba66SKatsushi Kobayashi 	if(err)
16333c60ba66SKatsushi Kobayashi 		return err;
16343c60ba66SKatsushi Kobayashi 
16355a7ba74dSHidetoshi Shimokawa 	first = STAILQ_FIRST(&ir->stfree);
16365a7ba74dSHidetoshi Shimokawa 	if (first == NULL) {
16375a7ba74dSHidetoshi Shimokawa 		device_printf(fc->dev, "IR DMA no free chunk\n");
16385a7ba74dSHidetoshi Shimokawa 		return 0;
16395a7ba74dSHidetoshi Shimokawa 	}
16405a7ba74dSHidetoshi Shimokawa 
16419ca8add3SHidetoshi Shimokawa 	ldesc = dbch->ndesc - 1;
16429ca8add3SHidetoshi Shimokawa 	s = splfw();
16435a7ba74dSHidetoshi Shimokawa 	prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
16445a7ba74dSHidetoshi Shimokawa 	while  ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
1645c4778b5dSHidetoshi Shimokawa 		struct fwohcidb *db;
16465a7ba74dSHidetoshi Shimokawa 
16472b4601d1SHidetoshi Shimokawa #if 1 /* XXX for if_fwe */
164877ee030bSHidetoshi Shimokawa 		if (chunk->mbuf != NULL) {
164977ee030bSHidetoshi Shimokawa 			db_tr = (struct fwohcidb_tr *)(chunk->start);
165077ee030bSHidetoshi Shimokawa 			db_tr->dbcnt = 1;
165177ee030bSHidetoshi Shimokawa 			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
165277ee030bSHidetoshi Shimokawa 					chunk->mbuf, fwohci_execute_db2, db_tr,
165377ee030bSHidetoshi Shimokawa 					/* flags */0);
165477ee030bSHidetoshi Shimokawa  			FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd,
165577ee030bSHidetoshi Shimokawa 				OHCI_UPDATE | OHCI_INPUT_LAST |
165677ee030bSHidetoshi Shimokawa 				OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
165777ee030bSHidetoshi Shimokawa 		}
16582b4601d1SHidetoshi Shimokawa #endif
16595a7ba74dSHidetoshi Shimokawa 		db = ((struct fwohcidb_tr *)(chunk->end))->db;
166077ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0);
166177ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
16625a7ba74dSHidetoshi Shimokawa 		if (prev != NULL) {
16635a7ba74dSHidetoshi Shimokawa 			db = ((struct fwohcidb_tr *)(prev->end))->db;
166477ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
16655a7ba74dSHidetoshi Shimokawa 		}
16665a7ba74dSHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&ir->stfree, link);
16675a7ba74dSHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
16685a7ba74dSHidetoshi Shimokawa 		prev = chunk;
16695a7ba74dSHidetoshi Shimokawa 	}
167077ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
167177ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
16725a7ba74dSHidetoshi Shimokawa 	splx(s);
16735a7ba74dSHidetoshi Shimokawa 	stat = OREAD(sc, OHCI_IRCTL(dmach));
16745a7ba74dSHidetoshi Shimokawa 	if (stat & OHCI_CNTL_DMA_ACTIVE)
16755a7ba74dSHidetoshi Shimokawa 		return 0;
16765a7ba74dSHidetoshi Shimokawa 	if (stat & OHCI_CNTL_DMA_RUN) {
16773c60ba66SKatsushi Kobayashi 		OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
16785a7ba74dSHidetoshi Shimokawa 		device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat);
16795a7ba74dSHidetoshi Shimokawa 	}
16805a7ba74dSHidetoshi Shimokawa 
168177ee030bSHidetoshi Shimokawa 	if (firewire_debug)
168277ee030bSHidetoshi Shimokawa 		printf("start IR DMA 0x%x\n", stat);
16833c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
16843c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
16853c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IR_MASK, 1 << dmach);
16863c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000);
16873c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR);
16883c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IRCMD(dmach),
168977ee030bSHidetoshi Shimokawa 		((struct fwohcidb_tr *)(first->start))->bus_addr
16905a7ba74dSHidetoshi Shimokawa 							| dbch->ndesc);
16913c60ba66SKatsushi Kobayashi 	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
16923c60ba66SKatsushi Kobayashi 	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
169377ee030bSHidetoshi Shimokawa #if 0
169477ee030bSHidetoshi Shimokawa 	dump_db(sc, IRX_CH + dmach);
169577ee030bSHidetoshi Shimokawa #endif
16963c60ba66SKatsushi Kobayashi 	return err;
16973c60ba66SKatsushi Kobayashi }
1698c572b810SHidetoshi Shimokawa 
1699c572b810SHidetoshi Shimokawa int
170064cf5240SHidetoshi Shimokawa fwohci_stop(struct fwohci_softc *sc, device_t dev)
17013c60ba66SKatsushi Kobayashi {
17023c60ba66SKatsushi Kobayashi 	u_int i;
17033c60ba66SKatsushi Kobayashi 
17043c60ba66SKatsushi Kobayashi /* Now stopping all DMA channel */
17053c60ba66SKatsushi Kobayashi 	OWRITE(sc,  OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
17063c60ba66SKatsushi Kobayashi 	OWRITE(sc,  OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
17073c60ba66SKatsushi Kobayashi 	OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
17083c60ba66SKatsushi Kobayashi 	OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
17093c60ba66SKatsushi Kobayashi 
17103c60ba66SKatsushi Kobayashi 	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
17113c60ba66SKatsushi Kobayashi 		OWRITE(sc,  OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
17123c60ba66SKatsushi Kobayashi 		OWRITE(sc,  OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
17133c60ba66SKatsushi Kobayashi 	}
17143c60ba66SKatsushi Kobayashi 
17153c60ba66SKatsushi Kobayashi /* FLUSH FIFO and reset Transmitter/Reciever */
17163c60ba66SKatsushi Kobayashi 	OWRITE(sc,  OHCI_HCCCTL, OHCI_HCC_RESET);
17173c60ba66SKatsushi Kobayashi 
17183c60ba66SKatsushi Kobayashi /* Stop interrupt */
17193c60ba66SKatsushi Kobayashi 	OWRITE(sc, FWOHCI_INTMASKCLR,
17203c60ba66SKatsushi Kobayashi 			OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID
17213c60ba66SKatsushi Kobayashi 			| OHCI_INT_PHY_INT
17223c60ba66SKatsushi Kobayashi 			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
17233c60ba66SKatsushi Kobayashi 			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
17243c60ba66SKatsushi Kobayashi 			| OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS
17253c60ba66SKatsushi Kobayashi 			| OHCI_INT_PHY_BUS_R);
1726630529adSHidetoshi Shimokawa 
172718349893SHidetoshi Shimokawa 	if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0)
1728630529adSHidetoshi Shimokawa 		fw_drain_txq(&sc->fc);
1729630529adSHidetoshi Shimokawa 
17309339321dSHidetoshi Shimokawa /* XXX Link down?  Bus reset? */
17319339321dSHidetoshi Shimokawa 	return 0;
17329339321dSHidetoshi Shimokawa }
17339339321dSHidetoshi Shimokawa 
17349339321dSHidetoshi Shimokawa int
17359339321dSHidetoshi Shimokawa fwohci_resume(struct fwohci_softc *sc, device_t dev)
17369339321dSHidetoshi Shimokawa {
17379339321dSHidetoshi Shimokawa 	int i;
1738630529adSHidetoshi Shimokawa 	struct fw_xferq *ir;
1739630529adSHidetoshi Shimokawa 	struct fw_bulkxfer *chunk;
17409339321dSHidetoshi Shimokawa 
17419339321dSHidetoshi Shimokawa 	fwohci_reset(sc, dev);
174295a24954SDoug Rabson 	/* XXX resume isochronous receive automatically. (how about TX?) */
17439339321dSHidetoshi Shimokawa 	for(i = 0; i < sc->fc.nisodma; i ++) {
1744630529adSHidetoshi Shimokawa 		ir = &sc->ir[i].xferq;
1745630529adSHidetoshi Shimokawa 		if((ir->flag & FWXFERQ_RUNNING) != 0) {
17469339321dSHidetoshi Shimokawa 			device_printf(sc->fc.dev,
17479339321dSHidetoshi Shimokawa 				"resume iso receive ch: %d\n", i);
1748630529adSHidetoshi Shimokawa 			ir->flag &= ~FWXFERQ_RUNNING;
1749630529adSHidetoshi Shimokawa 			/* requeue stdma to stfree */
1750630529adSHidetoshi Shimokawa 			while((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
1751630529adSHidetoshi Shimokawa 				STAILQ_REMOVE_HEAD(&ir->stdma, link);
1752630529adSHidetoshi Shimokawa 				STAILQ_INSERT_TAIL(&ir->stfree, chunk, link);
1753630529adSHidetoshi Shimokawa 			}
17549339321dSHidetoshi Shimokawa 			sc->fc.irx_enable(&sc->fc, i);
17559339321dSHidetoshi Shimokawa 		}
17569339321dSHidetoshi Shimokawa 	}
17579339321dSHidetoshi Shimokawa 
17589339321dSHidetoshi Shimokawa 	bus_generic_resume(dev);
17599339321dSHidetoshi Shimokawa 	sc->fc.ibr(&sc->fc);
17603c60ba66SKatsushi Kobayashi 	return 0;
17613c60ba66SKatsushi Kobayashi }
17623c60ba66SKatsushi Kobayashi 
17633c60ba66SKatsushi Kobayashi #define ACK_ALL
17643c60ba66SKatsushi Kobayashi static void
176503161bbcSDoug Rabson fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
17663c60ba66SKatsushi Kobayashi {
176703161bbcSDoug Rabson 	uint32_t irstat, itstat;
17683c60ba66SKatsushi Kobayashi 	u_int i;
17693c60ba66SKatsushi Kobayashi 	struct firewire_comm *fc = (struct firewire_comm *)sc;
17703c60ba66SKatsushi Kobayashi 
17713c60ba66SKatsushi Kobayashi #ifdef OHCI_DEBUG
17723c60ba66SKatsushi Kobayashi 	if(stat & OREAD(sc, FWOHCI_INTMASK))
17733c60ba66SKatsushi 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",
17743c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_EN ? "DMA_EN ":"",
17753c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_PHY_REG ? "PHY_REG ":"",
17763c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"",
17773c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_ERR ? "INT_ERR ":"",
17783c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"",
17793c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"",
17803c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"",
17813c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_CYC_START ? "CYC_START ":"",
17823c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_PHY_INT ? "PHY_INT ":"",
17833c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"",
17843c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_PHY_SID ? "SID ":"",
17853c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"",
17863c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"",
17873c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_IR ? "DMA_IR ":"",
17883c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_IT  ? "DMA_IT " :"",
17893c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_PRRS  ? "DMA_PRRS " :"",
17903c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_PRRQ  ? "DMA_PRRQ " :"",
17913c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_ARRS  ? "DMA_ARRS " :"",
17923c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_ARRQ  ? "DMA_ARRQ " :"",
17933c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_ATRS  ? "DMA_ATRS " :"",
17943c60ba66SKatsushi Kobayashi 			stat & OHCI_INT_DMA_ATRQ  ? "DMA_ATRQ " :"",
17953c60ba66SKatsushi Kobayashi 			stat, OREAD(sc, FWOHCI_INTMASK)
17963c60ba66SKatsushi Kobayashi 		);
17973c60ba66SKatsushi Kobayashi #endif
17983c60ba66SKatsushi Kobayashi /* Bus reset */
17993c60ba66SKatsushi Kobayashi 	if(stat & OHCI_INT_PHY_BUS_R ){
18001adf6842SHidetoshi Shimokawa 		if (fc->status == FWBUSRESET)
18011adf6842SHidetoshi Shimokawa 			goto busresetout;
18021adf6842SHidetoshi Shimokawa 		/* Disable bus reset interrupt until sid recv. */
18031adf6842SHidetoshi Shimokawa 		OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_PHY_BUS_R);
18041adf6842SHidetoshi Shimokawa 
18053c60ba66SKatsushi Kobayashi 		device_printf(fc->dev, "BUS reset\n");
18063c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_CYC_LOST);
18073c60ba66SKatsushi Kobayashi 		OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC);
18083c60ba66SKatsushi Kobayashi 
18093c60ba66SKatsushi Kobayashi 		OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
18103c60ba66SKatsushi Kobayashi 		sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING;
18113c60ba66SKatsushi Kobayashi 		OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
18123c60ba66SKatsushi Kobayashi 		sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
18133c60ba66SKatsushi Kobayashi 
18143c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18153c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
18163c60ba66SKatsushi Kobayashi #endif
1817627d85fbSHidetoshi Shimokawa 		fw_busreset(fc);
18180bc666e0SHidetoshi Shimokawa 		OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
18190bc666e0SHidetoshi Shimokawa 		OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
18203c60ba66SKatsushi Kobayashi 	}
18211adf6842SHidetoshi Shimokawa busresetout:
18223c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_IR )){
18233c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18243c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR);
18253c60ba66SKatsushi Kobayashi #endif
182610d3ed64SHidetoshi Shimokawa #if defined(__DragonFly__) || __FreeBSD_version < 500000
182777ee030bSHidetoshi Shimokawa 		irstat = sc->irstat;
182877ee030bSHidetoshi Shimokawa 		sc->irstat = 0;
182910d3ed64SHidetoshi Shimokawa #else
183010d3ed64SHidetoshi Shimokawa 		irstat = atomic_readandclear_int(&sc->irstat);
183177ee030bSHidetoshi Shimokawa #endif
18323c60ba66SKatsushi Kobayashi 		for(i = 0; i < fc->nisodma ; i++){
1833b9b35d19SHidetoshi Shimokawa 			struct fwohci_dbch *dbch;
1834b9b35d19SHidetoshi Shimokawa 
18353c60ba66SKatsushi Kobayashi 			if((irstat & (1 << i)) != 0){
1836b9b35d19SHidetoshi Shimokawa 				dbch = &sc->ir[i];
1837b9b35d19SHidetoshi Shimokawa 				if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) {
1838b9b35d19SHidetoshi Shimokawa 					device_printf(sc->fc.dev,
1839b9b35d19SHidetoshi Shimokawa 						"dma(%d) not active\n", i);
1840b9b35d19SHidetoshi Shimokawa 					continue;
1841b9b35d19SHidetoshi Shimokawa 				}
18423c60ba66SKatsushi Kobayashi 				fwohci_rbuf_update(sc, i);
18433c60ba66SKatsushi Kobayashi 			}
18443c60ba66SKatsushi Kobayashi 		}
18453c60ba66SKatsushi Kobayashi 	}
18463c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_IT )){
18473c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18483c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT);
18493c60ba66SKatsushi Kobayashi #endif
185010d3ed64SHidetoshi Shimokawa #if defined(__DragonFly__) || __FreeBSD_version < 500000
185177ee030bSHidetoshi Shimokawa 		itstat = sc->itstat;
185277ee030bSHidetoshi Shimokawa 		sc->itstat = 0;
185310d3ed64SHidetoshi Shimokawa #else
185410d3ed64SHidetoshi Shimokawa 		itstat = atomic_readandclear_int(&sc->itstat);
185577ee030bSHidetoshi Shimokawa #endif
18563c60ba66SKatsushi Kobayashi 		for(i = 0; i < fc->nisodma ; i++){
18573c60ba66SKatsushi Kobayashi 			if((itstat & (1 << i)) != 0){
18583c60ba66SKatsushi Kobayashi 				fwohci_tbuf_update(sc, i);
18593c60ba66SKatsushi Kobayashi 			}
18603c60ba66SKatsushi Kobayashi 		}
18613c60ba66SKatsushi Kobayashi 	}
18623c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_PRRS )){
18633c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18643c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS);
18653c60ba66SKatsushi Kobayashi #endif
18663c60ba66SKatsushi Kobayashi #if 0
18673c60ba66SKatsushi Kobayashi 		dump_dma(sc, ARRS_CH);
18683c60ba66SKatsushi Kobayashi 		dump_db(sc, ARRS_CH);
18693c60ba66SKatsushi Kobayashi #endif
1870783058faSHidetoshi Shimokawa 		fwohci_arcv(sc, &sc->arrs, count);
18713c60ba66SKatsushi Kobayashi 	}
18723c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_PRRQ )){
18733c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18743c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ);
18753c60ba66SKatsushi Kobayashi #endif
18763c60ba66SKatsushi Kobayashi #if 0
18773c60ba66SKatsushi Kobayashi 		dump_dma(sc, ARRQ_CH);
18783c60ba66SKatsushi Kobayashi 		dump_db(sc, ARRQ_CH);
18793c60ba66SKatsushi Kobayashi #endif
1880783058faSHidetoshi Shimokawa 		fwohci_arcv(sc, &sc->arrq, count);
18813c60ba66SKatsushi Kobayashi 	}
18823c60ba66SKatsushi Kobayashi 	if(stat & OHCI_INT_PHY_SID){
188303161bbcSDoug Rabson 		uint32_t *buf, node_id;
18843c60ba66SKatsushi Kobayashi 		int plen;
18853c60ba66SKatsushi Kobayashi 
18863c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
18873c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID);
18883c60ba66SKatsushi Kobayashi #endif
18891adf6842SHidetoshi Shimokawa 		/* Enable bus reset interrupt */
18901adf6842SHidetoshi Shimokawa 		OWRITE(sc, FWOHCI_INTMASK,  OHCI_INT_PHY_BUS_R);
1891dcae7539SHidetoshi Shimokawa 		/* Allow async. request to us */
1892dcae7539SHidetoshi Shimokawa 		OWRITE(sc, OHCI_AREQHI, 1 << 31);
1893dcae7539SHidetoshi Shimokawa 		/* XXX insecure ?? */
1894dcae7539SHidetoshi Shimokawa 		OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
1895dcae7539SHidetoshi Shimokawa 		OWRITE(sc, OHCI_PREQLO, 0xffffffff);
1896dcae7539SHidetoshi Shimokawa 		OWRITE(sc, OHCI_PREQUPPER, 0x10000);
189773aa55baSHidetoshi Shimokawa 		/* Set ATRetries register */
189873aa55baSHidetoshi Shimokawa 		OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
18993c60ba66SKatsushi Kobayashi /*
19003c60ba66SKatsushi Kobayashi ** Checking whether the node is root or not. If root, turn on
19013c60ba66SKatsushi Kobayashi ** cycle master.
19023c60ba66SKatsushi Kobayashi */
190377ee030bSHidetoshi Shimokawa 		node_id = OREAD(sc, FWOHCI_NODEID);
190477ee030bSHidetoshi Shimokawa 		plen = OREAD(sc, OHCI_SID_CNT);
190577ee030bSHidetoshi Shimokawa 
190677ee030bSHidetoshi Shimokawa 		device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
190777ee030bSHidetoshi Shimokawa 			node_id, (plen >> 16) & 0xff);
190877ee030bSHidetoshi Shimokawa 		if (!(node_id & OHCI_NODE_VALID)) {
19093c60ba66SKatsushi Kobayashi 			printf("Bus reset failure\n");
19103c60ba66SKatsushi Kobayashi 			goto sidout;
19113c60ba66SKatsushi Kobayashi 		}
191277ee030bSHidetoshi Shimokawa 		if (node_id & OHCI_NODE_ROOT) {
19133c60ba66SKatsushi Kobayashi 			printf("CYCLEMASTER mode\n");
19143c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_LNKCTL,
19153c60ba66SKatsushi Kobayashi 				OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
19163c60ba66SKatsushi Kobayashi 		} else {
19173c60ba66SKatsushi Kobayashi 			printf("non CYCLEMASTER mode\n");
19183c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
19193c60ba66SKatsushi Kobayashi 			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
19203c60ba66SKatsushi Kobayashi 		}
192177ee030bSHidetoshi Shimokawa 		fc->nodeid = node_id & 0x3f;
19223c60ba66SKatsushi Kobayashi 
192377ee030bSHidetoshi Shimokawa 		if (plen & OHCI_SID_ERR) {
192477ee030bSHidetoshi Shimokawa 			device_printf(fc->dev, "SID Error\n");
192577ee030bSHidetoshi Shimokawa 			goto sidout;
192677ee030bSHidetoshi Shimokawa 		}
192777ee030bSHidetoshi Shimokawa 		plen &= OHCI_SID_CNT_MASK;
192816e0f484SHidetoshi Shimokawa 		if (plen < 4 || plen > OHCI_SIDSIZE) {
192916e0f484SHidetoshi Shimokawa 			device_printf(fc->dev, "invalid SID len = %d\n", plen);
193016e0f484SHidetoshi Shimokawa 			goto sidout;
193116e0f484SHidetoshi Shimokawa 		}
19323c60ba66SKatsushi Kobayashi 		plen -= 4; /* chop control info */
193303161bbcSDoug Rabson 		buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
193477ee030bSHidetoshi Shimokawa 		if (buf == NULL) {
193577ee030bSHidetoshi Shimokawa 			device_printf(fc->dev, "malloc failed\n");
193677ee030bSHidetoshi Shimokawa 			goto sidout;
193777ee030bSHidetoshi Shimokawa 		}
193877ee030bSHidetoshi Shimokawa 		for (i = 0; i < plen / 4; i ++)
193977ee030bSHidetoshi Shimokawa 			buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
194010d3ed64SHidetoshi Shimokawa #if 1 /* XXX needed?? */
194148249fe0SHidetoshi Shimokawa 		/* pending all pre-bus_reset packets */
194248249fe0SHidetoshi Shimokawa 		fwohci_txd(sc, &sc->atrq);
194348249fe0SHidetoshi Shimokawa 		fwohci_txd(sc, &sc->atrs);
194448249fe0SHidetoshi Shimokawa 		fwohci_arcv(sc, &sc->arrs, -1);
194548249fe0SHidetoshi Shimokawa 		fwohci_arcv(sc, &sc->arrq, -1);
1946627d85fbSHidetoshi Shimokawa 		fw_drain_txq(fc);
194748249fe0SHidetoshi Shimokawa #endif
194877ee030bSHidetoshi Shimokawa 		fw_sidrcv(fc, buf, plen);
194977ee030bSHidetoshi Shimokawa 		free(buf, M_FW);
19503c60ba66SKatsushi Kobayashi 	}
19513c60ba66SKatsushi Kobayashi sidout:
19523c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_ATRQ )){
19533c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
19543c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ);
19553c60ba66SKatsushi Kobayashi #endif
19563c60ba66SKatsushi Kobayashi 		fwohci_txd(sc, &(sc->atrq));
19573c60ba66SKatsushi Kobayashi 	}
19583c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_DMA_ATRS )){
19593c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
19603c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS);
19613c60ba66SKatsushi Kobayashi #endif
19623c60ba66SKatsushi Kobayashi 		fwohci_txd(sc, &(sc->atrs));
19633c60ba66SKatsushi Kobayashi 	}
19643c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_PW_ERR )){
19653c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
19663c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR);
19673c60ba66SKatsushi Kobayashi #endif
19683c60ba66SKatsushi Kobayashi 		device_printf(fc->dev, "posted write error\n");
19693c60ba66SKatsushi Kobayashi 	}
19703c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_ERR )){
19713c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
19723c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR);
19733c60ba66SKatsushi Kobayashi #endif
19743c60ba66SKatsushi Kobayashi 		device_printf(fc->dev, "unrecoverable error\n");
19753c60ba66SKatsushi Kobayashi 	}
19763c60ba66SKatsushi Kobayashi 	if((stat & OHCI_INT_PHY_INT)) {
19773c60ba66SKatsushi Kobayashi #ifndef ACK_ALL
19783c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT);
19793c60ba66SKatsushi Kobayashi #endif
19803c60ba66SKatsushi Kobayashi 		device_printf(fc->dev, "phy int\n");
19813c60ba66SKatsushi Kobayashi 	}
19823c60ba66SKatsushi Kobayashi 
19833c60ba66SKatsushi Kobayashi 	return;
19843c60ba66SKatsushi Kobayashi }
19853c60ba66SKatsushi Kobayashi 
198677ee030bSHidetoshi Shimokawa #if FWOHCI_TASKQUEUE
198777ee030bSHidetoshi Shimokawa static void
198877ee030bSHidetoshi Shimokawa fwohci_complete(void *arg, int pending)
198977ee030bSHidetoshi Shimokawa {
199077ee030bSHidetoshi Shimokawa 	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
199103161bbcSDoug Rabson 	uint32_t stat;
199277ee030bSHidetoshi Shimokawa 
199377ee030bSHidetoshi Shimokawa again:
199477ee030bSHidetoshi Shimokawa 	stat = atomic_readandclear_int(&sc->intstat);
199577ee030bSHidetoshi Shimokawa 	if (stat)
199677ee030bSHidetoshi Shimokawa 		fwohci_intr_body(sc, stat, -1);
199777ee030bSHidetoshi Shimokawa 	else
199877ee030bSHidetoshi Shimokawa 		return;
199977ee030bSHidetoshi Shimokawa 	goto again;
200077ee030bSHidetoshi Shimokawa }
200177ee030bSHidetoshi Shimokawa #endif
200277ee030bSHidetoshi Shimokawa 
200303161bbcSDoug Rabson static uint32_t
200477ee030bSHidetoshi Shimokawa fwochi_check_stat(struct fwohci_softc *sc)
200577ee030bSHidetoshi Shimokawa {
200603161bbcSDoug Rabson 	uint32_t stat, irstat, itstat;
200777ee030bSHidetoshi Shimokawa 
200877ee030bSHidetoshi Shimokawa 	stat = OREAD(sc, FWOHCI_INTSTAT);
200977ee030bSHidetoshi Shimokawa 	if (stat == 0xffffffff) {
201077ee030bSHidetoshi Shimokawa 		device_printf(sc->fc.dev,
201177ee030bSHidetoshi Shimokawa 			"device physically ejected?\n");
201277ee030bSHidetoshi Shimokawa 		return(stat);
201377ee030bSHidetoshi Shimokawa 	}
201477ee030bSHidetoshi Shimokawa #ifdef ACK_ALL
201577ee030bSHidetoshi Shimokawa 	if (stat)
201677ee030bSHidetoshi Shimokawa 		OWRITE(sc, FWOHCI_INTSTATCLR, stat);
201777ee030bSHidetoshi Shimokawa #endif
201877ee030bSHidetoshi Shimokawa 	if (stat & OHCI_INT_DMA_IR) {
201977ee030bSHidetoshi Shimokawa 		irstat = OREAD(sc, OHCI_IR_STAT);
202077ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_IR_STATCLR, irstat);
202177ee030bSHidetoshi Shimokawa 		atomic_set_int(&sc->irstat, irstat);
202277ee030bSHidetoshi Shimokawa 	}
202377ee030bSHidetoshi Shimokawa 	if (stat & OHCI_INT_DMA_IT) {
202477ee030bSHidetoshi Shimokawa 		itstat = OREAD(sc, OHCI_IT_STAT);
202577ee030bSHidetoshi Shimokawa 		OWRITE(sc, OHCI_IT_STATCLR, itstat);
202677ee030bSHidetoshi Shimokawa 		atomic_set_int(&sc->itstat, itstat);
202777ee030bSHidetoshi Shimokawa 	}
202877ee030bSHidetoshi Shimokawa 	return(stat);
202977ee030bSHidetoshi Shimokawa }
203077ee030bSHidetoshi Shimokawa 
20313c60ba66SKatsushi Kobayashi void
20323c60ba66SKatsushi Kobayashi fwohci_intr(void *arg)
20333c60ba66SKatsushi Kobayashi {
20343c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
203503161bbcSDoug Rabson 	uint32_t stat;
203677ee030bSHidetoshi Shimokawa #if !FWOHCI_TASKQUEUE
203703161bbcSDoug Rabson 	uint32_t bus_reset = 0;
203877ee030bSHidetoshi Shimokawa #endif
20393c60ba66SKatsushi Kobayashi 
20403c60ba66SKatsushi Kobayashi 	if (!(sc->intmask & OHCI_INT_EN)) {
20413c60ba66SKatsushi Kobayashi 		/* polling mode */
20423c60ba66SKatsushi Kobayashi 		return;
20433c60ba66SKatsushi Kobayashi 	}
20443c60ba66SKatsushi Kobayashi 
204577ee030bSHidetoshi Shimokawa #if !FWOHCI_TASKQUEUE
204677ee030bSHidetoshi Shimokawa again:
20473c60ba66SKatsushi Kobayashi #endif
204877ee030bSHidetoshi Shimokawa 	stat = fwochi_check_stat(sc);
204977ee030bSHidetoshi Shimokawa 	if (stat == 0 || stat == 0xffffffff)
205077ee030bSHidetoshi Shimokawa 		return;
205177ee030bSHidetoshi Shimokawa #if FWOHCI_TASKQUEUE
205277ee030bSHidetoshi Shimokawa 	atomic_set_int(&sc->intstat, stat);
205377ee030bSHidetoshi Shimokawa 	/* XXX mask bus reset intr. during bus reset phase */
205477ee030bSHidetoshi Shimokawa 	if (stat)
205577ee030bSHidetoshi Shimokawa 		taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete);
205677ee030bSHidetoshi Shimokawa #else
20571adf6842SHidetoshi Shimokawa 	/* We cannot clear bus reset event during bus reset phase */
20581adf6842SHidetoshi Shimokawa 	if ((stat & ~bus_reset) == 0)
20591adf6842SHidetoshi Shimokawa 		return;
20601adf6842SHidetoshi Shimokawa 	bus_reset = stat & OHCI_INT_PHY_BUS_R;
2061783058faSHidetoshi Shimokawa 	fwohci_intr_body(sc, stat, -1);
206277ee030bSHidetoshi Shimokawa 	goto again;
206377ee030bSHidetoshi Shimokawa #endif
20643c60ba66SKatsushi Kobayashi }
20653c60ba66SKatsushi Kobayashi 
2066740b10aaSHidetoshi Shimokawa void
20673c60ba66SKatsushi Kobayashi fwohci_poll(struct firewire_comm *fc, int quick, int count)
20683c60ba66SKatsushi Kobayashi {
20693c60ba66SKatsushi Kobayashi 	int s;
207003161bbcSDoug Rabson 	uint32_t stat;
20713c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc;
20723c60ba66SKatsushi Kobayashi 
20733c60ba66SKatsushi Kobayashi 
20743c60ba66SKatsushi Kobayashi 	sc = (struct fwohci_softc *)fc;
20753c60ba66SKatsushi Kobayashi 	stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT |
20763c60ba66SKatsushi Kobayashi 		OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ |
20773c60ba66SKatsushi Kobayashi 		OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS;
20783c60ba66SKatsushi Kobayashi #if 0
20793c60ba66SKatsushi Kobayashi 	if (!quick) {
20803c60ba66SKatsushi Kobayashi #else
20813c60ba66SKatsushi Kobayashi 	if (1) {
20823c60ba66SKatsushi Kobayashi #endif
208377ee030bSHidetoshi Shimokawa 		stat = fwochi_check_stat(sc);
208477ee030bSHidetoshi Shimokawa 		if (stat == 0 || stat == 0xffffffff)
20853c60ba66SKatsushi Kobayashi 			return;
20863c60ba66SKatsushi Kobayashi 	}
20873c60ba66SKatsushi Kobayashi 	s = splfw();
2088783058faSHidetoshi Shimokawa 	fwohci_intr_body(sc, stat, count);
20893c60ba66SKatsushi Kobayashi 	splx(s);
20903c60ba66SKatsushi Kobayashi }
20913c60ba66SKatsushi Kobayashi 
20923c60ba66SKatsushi Kobayashi static void
20933c60ba66SKatsushi Kobayashi fwohci_set_intr(struct firewire_comm *fc, int enable)
20943c60ba66SKatsushi Kobayashi {
20953c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc;
20963c60ba66SKatsushi Kobayashi 
20973c60ba66SKatsushi Kobayashi 	sc = (struct fwohci_softc *)fc;
209817c3d42cSHidetoshi Shimokawa 	if (bootverbose)
20999339321dSHidetoshi Shimokawa 		device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable);
21003c60ba66SKatsushi Kobayashi 	if (enable) {
21013c60ba66SKatsushi Kobayashi 		sc->intmask |= OHCI_INT_EN;
21023c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN);
21033c60ba66SKatsushi Kobayashi 	} else {
21043c60ba66SKatsushi Kobayashi 		sc->intmask &= ~OHCI_INT_EN;
21053c60ba66SKatsushi Kobayashi 		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN);
21063c60ba66SKatsushi Kobayashi 	}
21073c60ba66SKatsushi Kobayashi }
21083c60ba66SKatsushi Kobayashi 
2109c572b810SHidetoshi Shimokawa static void
2110c572b810SHidetoshi Shimokawa fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
21113c60ba66SKatsushi Kobayashi {
21123c60ba66SKatsushi Kobayashi 	struct firewire_comm *fc = &sc->fc;
2113c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
21145a7ba74dSHidetoshi Shimokawa 	struct fw_bulkxfer *chunk;
21155a7ba74dSHidetoshi Shimokawa 	struct fw_xferq *it;
211603161bbcSDoug Rabson 	uint32_t stat, count;
211777ee030bSHidetoshi Shimokawa 	int s, w=0, ldesc;
21183c60ba66SKatsushi Kobayashi 
21195a7ba74dSHidetoshi Shimokawa 	it = fc->it[dmach];
212077ee030bSHidetoshi Shimokawa 	ldesc = sc->it[dmach].ndesc - 1;
21215a7ba74dSHidetoshi Shimokawa 	s = splfw(); /* unnecessary ? */
212277ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
2123a1c9e73aSHidetoshi Shimokawa 	if (firewire_debug)
2124a1c9e73aSHidetoshi Shimokawa 		dump_db(sc, ITX_CH + dmach);
21255a7ba74dSHidetoshi Shimokawa 	while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
21265a7ba74dSHidetoshi Shimokawa 		db = ((struct fwohcidb_tr *)(chunk->end))->db;
212777ee030bSHidetoshi Shimokawa 		stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
212877ee030bSHidetoshi Shimokawa 				>> OHCI_STATUS_SHIFT;
21295a7ba74dSHidetoshi Shimokawa 		db = ((struct fwohcidb_tr *)(chunk->start))->db;
2130a1c9e73aSHidetoshi Shimokawa 		/* timestamp */
213177ee030bSHidetoshi Shimokawa 		count = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
213277ee030bSHidetoshi Shimokawa 				& OHCI_COUNT_MASK;
21335a7ba74dSHidetoshi Shimokawa 		if (stat == 0)
21345a7ba74dSHidetoshi Shimokawa 			break;
21355a7ba74dSHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&it->stdma, link);
21365a7ba74dSHidetoshi Shimokawa 		switch (stat & FWOHCIEV_MASK){
21373c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKCOMPL:
21385a7ba74dSHidetoshi Shimokawa #if 0
21395a7ba74dSHidetoshi Shimokawa 			device_printf(fc->dev, "0x%08x\n", count);
21400aaa9a23SHidetoshi Shimokawa #endif
21413c60ba66SKatsushi Kobayashi 			break;
21423c60ba66SKatsushi Kobayashi 		default:
21435a7ba74dSHidetoshi Shimokawa 			device_printf(fc->dev,
214477ee030bSHidetoshi Shimokawa 				"Isochronous transmit err %02x(%s)\n",
214577ee030bSHidetoshi Shimokawa 					stat, fwohcicode[stat & 0x1f]);
21463c60ba66SKatsushi Kobayashi 		}
21475a7ba74dSHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
21485a7ba74dSHidetoshi Shimokawa 		w++;
21495a7ba74dSHidetoshi Shimokawa 	}
21505a7ba74dSHidetoshi Shimokawa 	splx(s);
21515a7ba74dSHidetoshi Shimokawa 	if (w)
21525a7ba74dSHidetoshi Shimokawa 		wakeup(it);
21533c60ba66SKatsushi Kobayashi }
2154c572b810SHidetoshi Shimokawa 
2155c572b810SHidetoshi Shimokawa static void
2156c572b810SHidetoshi Shimokawa fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
21573c60ba66SKatsushi Kobayashi {
21580aaa9a23SHidetoshi Shimokawa 	struct firewire_comm *fc = &sc->fc;
2159c4778b5dSHidetoshi Shimokawa 	struct fwohcidb_tr *db_tr;
21605a7ba74dSHidetoshi Shimokawa 	struct fw_bulkxfer *chunk;
21615a7ba74dSHidetoshi Shimokawa 	struct fw_xferq *ir;
216203161bbcSDoug Rabson 	uint32_t stat;
216377ee030bSHidetoshi Shimokawa 	int s, w=0, ldesc;
21640aaa9a23SHidetoshi Shimokawa 
21655a7ba74dSHidetoshi Shimokawa 	ir = fc->ir[dmach];
216677ee030bSHidetoshi Shimokawa 	ldesc = sc->ir[dmach].ndesc - 1;
216777ee030bSHidetoshi Shimokawa #if 0
216877ee030bSHidetoshi Shimokawa 	dump_db(sc, dmach);
216977ee030bSHidetoshi Shimokawa #endif
21705a7ba74dSHidetoshi Shimokawa 	s = splfw();
217177ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
21725a7ba74dSHidetoshi Shimokawa 	while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
217377ee030bSHidetoshi Shimokawa 		db_tr = (struct fwohcidb_tr *)chunk->end;
217477ee030bSHidetoshi Shimokawa 		stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res)
217577ee030bSHidetoshi Shimokawa 				>> OHCI_STATUS_SHIFT;
21765a7ba74dSHidetoshi Shimokawa 		if (stat == 0)
21775a7ba74dSHidetoshi Shimokawa 			break;
217877ee030bSHidetoshi Shimokawa 
217977ee030bSHidetoshi Shimokawa 		if (chunk->mbuf != NULL) {
218077ee030bSHidetoshi Shimokawa 			bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map,
218177ee030bSHidetoshi Shimokawa 						BUS_DMASYNC_POSTREAD);
218277ee030bSHidetoshi Shimokawa 			bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map);
218377ee030bSHidetoshi Shimokawa 		} else if (ir->buf != NULL) {
218477ee030bSHidetoshi Shimokawa 			fwdma_sync_multiseg(ir->buf, chunk->poffset,
218577ee030bSHidetoshi Shimokawa 				ir->bnpacket, BUS_DMASYNC_POSTREAD);
218677ee030bSHidetoshi Shimokawa 		} else {
218777ee030bSHidetoshi Shimokawa 			/* XXX */
218877ee030bSHidetoshi Shimokawa 			printf("fwohci_rbuf_update: this shouldn't happend\n");
218977ee030bSHidetoshi Shimokawa 		}
219077ee030bSHidetoshi Shimokawa 
21915a7ba74dSHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&ir->stdma, link);
21925a7ba74dSHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link);
21935a7ba74dSHidetoshi Shimokawa 		switch (stat & FWOHCIEV_MASK) {
21943c60ba66SKatsushi Kobayashi 		case FWOHCIEV_ACKCOMPL:
21952b4601d1SHidetoshi Shimokawa 			chunk->resp = 0;
21963c60ba66SKatsushi Kobayashi 			break;
21973c60ba66SKatsushi Kobayashi 		default:
21982b4601d1SHidetoshi Shimokawa 			chunk->resp = EINVAL;
21995a7ba74dSHidetoshi Shimokawa 			device_printf(fc->dev,
220077ee030bSHidetoshi Shimokawa 				"Isochronous receive err %02x(%s)\n",
220177ee030bSHidetoshi Shimokawa 					stat, fwohcicode[stat & 0x1f]);
22023c60ba66SKatsushi Kobayashi 		}
22035a7ba74dSHidetoshi Shimokawa 		w++;
22045a7ba74dSHidetoshi Shimokawa 	}
22055a7ba74dSHidetoshi Shimokawa 	splx(s);
22062b4601d1SHidetoshi Shimokawa 	if (w) {
22072b4601d1SHidetoshi Shimokawa 		if (ir->flag & FWXFERQ_HANDLER)
22082b4601d1SHidetoshi Shimokawa 			ir->hand(ir);
22092b4601d1SHidetoshi Shimokawa 		else
22105a7ba74dSHidetoshi Shimokawa 			wakeup(ir);
22113c60ba66SKatsushi Kobayashi 	}
22122b4601d1SHidetoshi Shimokawa }
2213c572b810SHidetoshi Shimokawa 
2214c572b810SHidetoshi Shimokawa void
221503161bbcSDoug Rabson dump_dma(struct fwohci_softc *sc, uint32_t ch)
2216c572b810SHidetoshi Shimokawa {
221703161bbcSDoug Rabson 	uint32_t off, cntl, stat, cmd, match;
22183c60ba66SKatsushi Kobayashi 
22193c60ba66SKatsushi Kobayashi 	if(ch == 0){
22203c60ba66SKatsushi Kobayashi 		off = OHCI_ATQOFF;
22213c60ba66SKatsushi Kobayashi 	}else if(ch == 1){
22223c60ba66SKatsushi Kobayashi 		off = OHCI_ATSOFF;
22233c60ba66SKatsushi Kobayashi 	}else if(ch == 2){
22243c60ba66SKatsushi Kobayashi 		off = OHCI_ARQOFF;
22253c60ba66SKatsushi Kobayashi 	}else if(ch == 3){
22263c60ba66SKatsushi Kobayashi 		off = OHCI_ARSOFF;
22273c60ba66SKatsushi Kobayashi 	}else if(ch < IRX_CH){
22283c60ba66SKatsushi Kobayashi 		off = OHCI_ITCTL(ch - ITX_CH);
22293c60ba66SKatsushi Kobayashi 	}else{
22303c60ba66SKatsushi Kobayashi 		off = OHCI_IRCTL(ch - IRX_CH);
22313c60ba66SKatsushi Kobayashi 	}
22323c60ba66SKatsushi Kobayashi 	cntl = stat = OREAD(sc, off);
22333c60ba66SKatsushi Kobayashi 	cmd = OREAD(sc, off + 0xc);
22343c60ba66SKatsushi Kobayashi 	match = OREAD(sc, off + 0x10);
22353c60ba66SKatsushi Kobayashi 
223677ee030bSHidetoshi Shimokawa 	device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n",
22373c60ba66SKatsushi Kobayashi 		ch,
22383c60ba66SKatsushi Kobayashi 		cntl,
22393c60ba66SKatsushi Kobayashi 		cmd,
22403c60ba66SKatsushi Kobayashi 		match);
22413c60ba66SKatsushi Kobayashi 	stat &= 0xffff ;
224277ee030bSHidetoshi Shimokawa 	if (stat) {
22433c60ba66SKatsushi Kobayashi 		device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n",
22443c60ba66SKatsushi Kobayashi 			ch,
22453c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
22463c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
22473c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
22483c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
22493c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
22503c60ba66SKatsushi Kobayashi 			stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
22513c60ba66SKatsushi Kobayashi 			fwohcicode[stat & 0x1f],
22523c60ba66SKatsushi Kobayashi 			stat & 0x1f
22533c60ba66SKatsushi Kobayashi 		);
22543c60ba66SKatsushi Kobayashi 	}else{
22553c60ba66SKatsushi Kobayashi 		device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch);
22563c60ba66SKatsushi Kobayashi 	}
22573c60ba66SKatsushi Kobayashi }
2258c572b810SHidetoshi Shimokawa 
2259c572b810SHidetoshi Shimokawa void
226003161bbcSDoug Rabson dump_db(struct fwohci_softc *sc, uint32_t ch)
2261c572b810SHidetoshi Shimokawa {
22623c60ba66SKatsushi Kobayashi 	struct fwohci_dbch *dbch;
226377ee030bSHidetoshi Shimokawa 	struct fwohcidb_tr *cp = NULL, *pp, *np = NULL;
2264c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *curr = NULL, *prev, *next = NULL;
22653c60ba66SKatsushi Kobayashi 	int idb, jdb;
226603161bbcSDoug Rabson 	uint32_t cmd, off;
22673c60ba66SKatsushi Kobayashi 	if(ch == 0){
22683c60ba66SKatsushi Kobayashi 		off = OHCI_ATQOFF;
22693c60ba66SKatsushi Kobayashi 		dbch = &sc->atrq;
22703c60ba66SKatsushi Kobayashi 	}else if(ch == 1){
22713c60ba66SKatsushi Kobayashi 		off = OHCI_ATSOFF;
22723c60ba66SKatsushi Kobayashi 		dbch = &sc->atrs;
22733c60ba66SKatsushi Kobayashi 	}else if(ch == 2){
22743c60ba66SKatsushi Kobayashi 		off = OHCI_ARQOFF;
22753c60ba66SKatsushi Kobayashi 		dbch = &sc->arrq;
22763c60ba66SKatsushi Kobayashi 	}else if(ch == 3){
22773c60ba66SKatsushi Kobayashi 		off = OHCI_ARSOFF;
22783c60ba66SKatsushi Kobayashi 		dbch = &sc->arrs;
22793c60ba66SKatsushi Kobayashi 	}else if(ch < IRX_CH){
22803c60ba66SKatsushi Kobayashi 		off = OHCI_ITCTL(ch - ITX_CH);
22813c60ba66SKatsushi Kobayashi 		dbch = &sc->it[ch - ITX_CH];
22823c60ba66SKatsushi Kobayashi 	}else {
22833c60ba66SKatsushi Kobayashi 		off = OHCI_IRCTL(ch - IRX_CH);
22843c60ba66SKatsushi Kobayashi 		dbch = &sc->ir[ch - IRX_CH];
22853c60ba66SKatsushi Kobayashi 	}
22863c60ba66SKatsushi Kobayashi 	cmd = OREAD(sc, off + 0xc);
22873c60ba66SKatsushi Kobayashi 
22883c60ba66SKatsushi Kobayashi 	if( dbch->ndb == 0 ){
22893c60ba66SKatsushi Kobayashi 		device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch);
22903c60ba66SKatsushi Kobayashi 		return;
22913c60ba66SKatsushi Kobayashi 	}
22923c60ba66SKatsushi Kobayashi 	pp = dbch->top;
22933c60ba66SKatsushi Kobayashi 	prev = pp->db;
22943c60ba66SKatsushi Kobayashi 	for(idb = 0 ; idb < dbch->ndb ; idb ++ ){
22953c60ba66SKatsushi Kobayashi 		if(pp == NULL){
22963c60ba66SKatsushi Kobayashi 			curr = NULL;
22973c60ba66SKatsushi Kobayashi 			goto outdb;
22983c60ba66SKatsushi Kobayashi 		}
22993c60ba66SKatsushi Kobayashi 		cp = STAILQ_NEXT(pp, link);
23003c60ba66SKatsushi Kobayashi 		if(cp == NULL){
23013c60ba66SKatsushi Kobayashi 			curr = NULL;
23023c60ba66SKatsushi Kobayashi 			goto outdb;
23033c60ba66SKatsushi Kobayashi 		}
23043c60ba66SKatsushi Kobayashi 		np = STAILQ_NEXT(cp, link);
23053c60ba66SKatsushi Kobayashi 		for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){
230677ee030bSHidetoshi Shimokawa 			if ((cmd  & 0xfffffff0) == cp->bus_addr) {
23073c60ba66SKatsushi Kobayashi 				curr = cp->db;
23083c60ba66SKatsushi Kobayashi 				if(np != NULL){
23093c60ba66SKatsushi Kobayashi 					next = np->db;
23103c60ba66SKatsushi Kobayashi 				}else{
23113c60ba66SKatsushi Kobayashi 					next = NULL;
23123c60ba66SKatsushi Kobayashi 				}
23133c60ba66SKatsushi Kobayashi 				goto outdb;
23143c60ba66SKatsushi Kobayashi 			}
23153c60ba66SKatsushi Kobayashi 		}
23163c60ba66SKatsushi Kobayashi 		pp = STAILQ_NEXT(pp, link);
23173c60ba66SKatsushi Kobayashi 		prev = pp->db;
23183c60ba66SKatsushi Kobayashi 	}
23193c60ba66SKatsushi Kobayashi outdb:
23203c60ba66SKatsushi Kobayashi 	if( curr != NULL){
232177ee030bSHidetoshi Shimokawa #if 0
23223c60ba66SKatsushi Kobayashi 		printf("Prev DB %d\n", ch);
232377ee030bSHidetoshi Shimokawa 		print_db(pp, prev, ch, dbch->ndesc);
232477ee030bSHidetoshi Shimokawa #endif
23253c60ba66SKatsushi Kobayashi 		printf("Current DB %d\n", ch);
232677ee030bSHidetoshi Shimokawa 		print_db(cp, curr, ch, dbch->ndesc);
232777ee030bSHidetoshi Shimokawa #if 0
23283c60ba66SKatsushi Kobayashi 		printf("Next DB %d\n", ch);
232977ee030bSHidetoshi Shimokawa 		print_db(np, next, ch, dbch->ndesc);
233077ee030bSHidetoshi Shimokawa #endif
23313c60ba66SKatsushi Kobayashi 	}else{
23323c60ba66SKatsushi Kobayashi 		printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd);
23333c60ba66SKatsushi Kobayashi 	}
23343c60ba66SKatsushi Kobayashi 	return;
23353c60ba66SKatsushi Kobayashi }
2336c572b810SHidetoshi Shimokawa 
2337c572b810SHidetoshi Shimokawa void
2338c4778b5dSHidetoshi Shimokawa print_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db,
233903161bbcSDoug Rabson 		uint32_t ch, uint32_t max)
2340c572b810SHidetoshi Shimokawa {
23413c60ba66SKatsushi Kobayashi 	fwohcireg_t stat;
23423c60ba66SKatsushi Kobayashi 	int i, key;
234303161bbcSDoug Rabson 	uint32_t cmd, res;
23443c60ba66SKatsushi Kobayashi 
23453c60ba66SKatsushi Kobayashi 	if(db == NULL){
23463c60ba66SKatsushi Kobayashi 		printf("No Descriptor is found\n");
23473c60ba66SKatsushi Kobayashi 		return;
23483c60ba66SKatsushi Kobayashi 	}
23493c60ba66SKatsushi Kobayashi 
23503c60ba66SKatsushi Kobayashi 	printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n",
23513c60ba66SKatsushi Kobayashi 		ch,
23523c60ba66SKatsushi Kobayashi 		"Current",
23533c60ba66SKatsushi Kobayashi 		"OP  ",
23543c60ba66SKatsushi Kobayashi 		"KEY",
23553c60ba66SKatsushi Kobayashi 		"INT",
23563c60ba66SKatsushi Kobayashi 		"BR ",
23573c60ba66SKatsushi Kobayashi 		"len",
23583c60ba66SKatsushi Kobayashi 		"Addr",
23593c60ba66SKatsushi Kobayashi 		"Depend",
23603c60ba66SKatsushi Kobayashi 		"Stat",
23613c60ba66SKatsushi Kobayashi 		"Cnt");
23623c60ba66SKatsushi Kobayashi 	for( i = 0 ; i <= max ; i ++){
236377ee030bSHidetoshi Shimokawa 		cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd);
236477ee030bSHidetoshi Shimokawa 		res = FWOHCI_DMA_READ(db[i].db.desc.res);
236577ee030bSHidetoshi Shimokawa 		key = cmd & OHCI_KEY_MASK;
236677ee030bSHidetoshi Shimokawa 		stat = res >> OHCI_STATUS_SHIFT;
236710d3ed64SHidetoshi Shimokawa #if defined(__DragonFly__) || __FreeBSD_version < 500000
2368a4239576SHidetoshi Shimokawa 		printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x",
236970b400a8SHidetoshi Shimokawa 				db_tr->bus_addr,
237010d3ed64SHidetoshi Shimokawa #else
237110d3ed64SHidetoshi Shimokawa 		printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x",
237210d3ed64SHidetoshi Shimokawa 				(uintmax_t)db_tr->bus_addr,
2373a4239576SHidetoshi Shimokawa #endif
237477ee030bSHidetoshi Shimokawa 				dbcode[(cmd >> 28) & 0xf],
237577ee030bSHidetoshi Shimokawa 				dbkey[(cmd >> 24) & 0x7],
237677ee030bSHidetoshi Shimokawa 				dbcond[(cmd >> 20) & 0x3],
237777ee030bSHidetoshi Shimokawa 				dbcond[(cmd >> 18) & 0x3],
237877ee030bSHidetoshi Shimokawa 				cmd & OHCI_COUNT_MASK,
237977ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i].db.desc.addr),
238077ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i].db.desc.depend),
238177ee030bSHidetoshi Shimokawa 				stat,
238277ee030bSHidetoshi Shimokawa 				res & OHCI_COUNT_MASK);
23833c60ba66SKatsushi Kobayashi 		if(stat & 0xff00){
23843c60ba66SKatsushi Kobayashi 			printf(" %s%s%s%s%s%s %s(%x)\n",
23853c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
23863c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
23873c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
23883c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
23893c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
23903c60ba66SKatsushi Kobayashi 				stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
23913c60ba66SKatsushi Kobayashi 				fwohcicode[stat & 0x1f],
23923c60ba66SKatsushi Kobayashi 				stat & 0x1f
23933c60ba66SKatsushi Kobayashi 			);
23943c60ba66SKatsushi Kobayashi 		}else{
23953c60ba66SKatsushi Kobayashi 			printf(" Nostat\n");
23963c60ba66SKatsushi Kobayashi 		}
23973c60ba66SKatsushi Kobayashi 		if(key == OHCI_KEY_ST2 ){
23983c60ba66SKatsushi Kobayashi 			printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
239977ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i+1].db.immed[0]),
240077ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i+1].db.immed[1]),
240177ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i+1].db.immed[2]),
240277ee030bSHidetoshi Shimokawa 				FWOHCI_DMA_READ(db[i+1].db.immed[3]));
24033c60ba66SKatsushi Kobayashi 		}
24043c60ba66SKatsushi Kobayashi 		if(key == OHCI_KEY_DEVICE){
24053c60ba66SKatsushi Kobayashi 			return;
24063c60ba66SKatsushi Kobayashi 		}
240777ee030bSHidetoshi Shimokawa 		if((cmd & OHCI_BRANCH_MASK)
24083c60ba66SKatsushi Kobayashi 				== OHCI_BRANCH_ALWAYS){
24093c60ba66SKatsushi Kobayashi 			return;
24103c60ba66SKatsushi Kobayashi 		}
241177ee030bSHidetoshi Shimokawa 		if((cmd & OHCI_CMD_MASK)
24123c60ba66SKatsushi Kobayashi 				== OHCI_OUTPUT_LAST){
24133c60ba66SKatsushi Kobayashi 			return;
24143c60ba66SKatsushi Kobayashi 		}
241577ee030bSHidetoshi Shimokawa 		if((cmd & OHCI_CMD_MASK)
24163c60ba66SKatsushi Kobayashi 				== OHCI_INPUT_LAST){
24173c60ba66SKatsushi Kobayashi 			return;
24183c60ba66SKatsushi Kobayashi 		}
24193c60ba66SKatsushi Kobayashi 		if(key == OHCI_KEY_ST2 ){
24203c60ba66SKatsushi Kobayashi 			i++;
24213c60ba66SKatsushi Kobayashi 		}
24223c60ba66SKatsushi Kobayashi 	}
24233c60ba66SKatsushi Kobayashi 	return;
24243c60ba66SKatsushi Kobayashi }
2425c572b810SHidetoshi Shimokawa 
2426c572b810SHidetoshi Shimokawa void
2427c572b810SHidetoshi Shimokawa fwohci_ibr(struct firewire_comm *fc)
24283c60ba66SKatsushi Kobayashi {
24293c60ba66SKatsushi Kobayashi 	struct fwohci_softc *sc;
243003161bbcSDoug Rabson 	uint32_t fun;
24313c60ba66SKatsushi Kobayashi 
2432864d7e72SHidetoshi Shimokawa 	device_printf(fc->dev, "Initiate bus reset\n");
24333c60ba66SKatsushi Kobayashi 	sc = (struct fwohci_softc *)fc;
2434ac9f6692SHidetoshi Shimokawa 
2435ac9f6692SHidetoshi Shimokawa 	/*
2436ac9f6692SHidetoshi Shimokawa 	 * Set root hold-off bit so that non cyclemaster capable node
2437ac9f6692SHidetoshi Shimokawa 	 * shouldn't became the root node.
2438ac9f6692SHidetoshi Shimokawa 	 */
24393c60ba66SKatsushi Kobayashi #if 1
24403c60ba66SKatsushi Kobayashi 	fun = fwphy_rddata(sc, FW_PHY_IBR_REG);
24414ed65ce9SHidetoshi Shimokawa 	fun |= FW_PHY_IBR | FW_PHY_RHB;
24423c60ba66SKatsushi Kobayashi 	fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun);
24434ed65ce9SHidetoshi Shimokawa #else	/* Short bus reset */
24443c60ba66SKatsushi Kobayashi 	fun = fwphy_rddata(sc, FW_PHY_ISBR_REG);
24454ed65ce9SHidetoshi Shimokawa 	fun |= FW_PHY_ISBR | FW_PHY_RHB;
24463c60ba66SKatsushi Kobayashi 	fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun);
24473c60ba66SKatsushi Kobayashi #endif
24483c60ba66SKatsushi Kobayashi }
2449c572b810SHidetoshi Shimokawa 
2450c572b810SHidetoshi Shimokawa void
2451c572b810SHidetoshi Shimokawa fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
24523c60ba66SKatsushi Kobayashi {
24533c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr, *fdb_tr;
24543c60ba66SKatsushi Kobayashi 	struct fwohci_dbch *dbch;
2455c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db;
24563c60ba66SKatsushi Kobayashi 	struct fw_pkt *fp;
2457c4778b5dSHidetoshi Shimokawa 	struct fwohci_txpkthdr *ohcifp;
24583c60ba66SKatsushi Kobayashi 	unsigned short chtag;
24593c60ba66SKatsushi Kobayashi 	int idb;
24603c60ba66SKatsushi Kobayashi 
24613c60ba66SKatsushi Kobayashi 	dbch = &sc->it[dmach];
24623c60ba66SKatsushi Kobayashi 	chtag = sc->it[dmach].xferq.flag & 0xff;
24633c60ba66SKatsushi Kobayashi 
24643c60ba66SKatsushi Kobayashi 	db_tr = (struct fwohcidb_tr *)(bulkxfer->start);
24653c60ba66SKatsushi Kobayashi 	fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end);
24663c60ba66SKatsushi Kobayashi /*
246777ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr);
24683c60ba66SKatsushi Kobayashi */
246977ee030bSHidetoshi Shimokawa 	for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) {
247053f1eb86SHidetoshi Shimokawa 		db = db_tr->db;
24713c60ba66SKatsushi Kobayashi 		fp = (struct fw_pkt *)db_tr->buf;
2472c4778b5dSHidetoshi Shimokawa 		ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed;
247377ee030bSHidetoshi Shimokawa 		ohcifp->mode.ld[0] = fp->mode.ld[0];
2474a1c9e73aSHidetoshi Shimokawa 		ohcifp->mode.common.spd = 0 & 0x7;
247577ee030bSHidetoshi Shimokawa 		ohcifp->mode.stream.len = fp->mode.stream.len;
24763c60ba66SKatsushi Kobayashi 		ohcifp->mode.stream.chtag = chtag;
24773c60ba66SKatsushi Kobayashi 		ohcifp->mode.stream.tcode = 0xa;
247877ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
247977ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]);
248077ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]);
248177ee030bSHidetoshi Shimokawa #endif
24823c60ba66SKatsushi Kobayashi 
248377ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK);
248477ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len);
248577ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
248653f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npackets changes */
248777ee030bSHidetoshi Shimokawa 		db[2].db.desc.cmd = OHCI_OUTPUT_LAST
24883c60ba66SKatsushi Kobayashi 			| OHCI_UPDATE
248953f1eb86SHidetoshi Shimokawa 			| OHCI_BRANCH_ALWAYS;
249053f1eb86SHidetoshi Shimokawa 		db[0].db.desc.depend =
249153f1eb86SHidetoshi Shimokawa 			= db[dbch->ndesc - 1].db.desc.depend
249277ee030bSHidetoshi Shimokawa 			= STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc;
249353f1eb86SHidetoshi Shimokawa #else
249477ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
249577ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc);
249653f1eb86SHidetoshi Shimokawa #endif
24973c60ba66SKatsushi Kobayashi 		bulkxfer->end = (caddr_t)db_tr;
24983c60ba66SKatsushi Kobayashi 		db_tr = STAILQ_NEXT(db_tr, link);
24993c60ba66SKatsushi Kobayashi 	}
250053f1eb86SHidetoshi Shimokawa 	db = ((struct fwohcidb_tr *)bulkxfer->end)->db;
250177ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf);
250277ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf);
250353f1eb86SHidetoshi Shimokawa #if 0 /* if bulkxfer->npackets changes */
250453f1eb86SHidetoshi Shimokawa 	db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
25054ed65ce9SHidetoshi Shimokawa 	/* OHCI 1.1 and above */
250653f1eb86SHidetoshi Shimokawa 	db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
250753f1eb86SHidetoshi Shimokawa #endif
250853f1eb86SHidetoshi Shimokawa /*
25093c60ba66SKatsushi Kobayashi 	db_tr = (struct fwohcidb_tr *)bulkxfer->start;
25103c60ba66SKatsushi Kobayashi 	fdb_tr = (struct fwohcidb_tr *)bulkxfer->end;
251177ee030bSHidetoshi Shimokawa device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr);
25123c60ba66SKatsushi Kobayashi */
25133c60ba66SKatsushi Kobayashi 	return;
25143c60ba66SKatsushi Kobayashi }
2515c572b810SHidetoshi Shimokawa 
2516c572b810SHidetoshi Shimokawa static int
251777ee030bSHidetoshi Shimokawa fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
251877ee030bSHidetoshi Shimokawa 								int poffset)
25193c60ba66SKatsushi Kobayashi {
2520c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db = db_tr->db;
252177ee030bSHidetoshi Shimokawa 	struct fw_xferq *it;
25223c60ba66SKatsushi Kobayashi 	int err = 0;
252377ee030bSHidetoshi Shimokawa 
252477ee030bSHidetoshi Shimokawa 	it = &dbch->xferq;
252577ee030bSHidetoshi Shimokawa 	if(it->buf == 0){
25263c60ba66SKatsushi Kobayashi 		err = EINVAL;
25273c60ba66SKatsushi Kobayashi 		return err;
25283c60ba66SKatsushi Kobayashi 	}
252977ee030bSHidetoshi Shimokawa 	db_tr->buf = fwdma_v_addr(it->buf, poffset);
25303c60ba66SKatsushi Kobayashi 	db_tr->dbcnt = 3;
25313c60ba66SKatsushi Kobayashi 
253277ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
253377ee030bSHidetoshi Shimokawa 		OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
2534a1c9e73aSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0);
2535c4778b5dSHidetoshi Shimokawa 	bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed));
253677ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[2].db.desc.addr,
253703161bbcSDoug Rabson 	fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t));
253877ee030bSHidetoshi Shimokawa 
253977ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[2].db.desc.cmd,
254077ee030bSHidetoshi Shimokawa 		OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS);
254153f1eb86SHidetoshi Shimokawa #if 1
254277ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[0].db.desc.res, 0);
254377ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
254453f1eb86SHidetoshi Shimokawa #endif
254577ee030bSHidetoshi Shimokawa 	return 0;
25463c60ba66SKatsushi Kobayashi }
2547c572b810SHidetoshi Shimokawa 
2548c572b810SHidetoshi Shimokawa int
254977ee030bSHidetoshi Shimokawa fwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
255077ee030bSHidetoshi Shimokawa 		int poffset, struct fwdma_alloc *dummy_dma)
25513c60ba66SKatsushi Kobayashi {
2552c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db = db_tr->db;
255377ee030bSHidetoshi Shimokawa 	struct fw_xferq *ir;
255477ee030bSHidetoshi Shimokawa 	int i, ldesc;
255577ee030bSHidetoshi Shimokawa 	bus_addr_t dbuf[2];
25563c60ba66SKatsushi Kobayashi 	int dsiz[2];
25573c60ba66SKatsushi Kobayashi 
255877ee030bSHidetoshi Shimokawa 	ir = &dbch->xferq;
255977ee030bSHidetoshi Shimokawa 	if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) {
256077ee030bSHidetoshi Shimokawa 		db_tr->buf = fwdma_malloc_size(dbch->dmat, &db_tr->dma_map,
256177ee030bSHidetoshi Shimokawa 			ir->psize, &dbuf[0], BUS_DMA_NOWAIT);
256277ee030bSHidetoshi Shimokawa 		if (db_tr->buf == NULL)
256377ee030bSHidetoshi Shimokawa 			return(ENOMEM);
25643c60ba66SKatsushi Kobayashi 		db_tr->dbcnt = 1;
256577ee030bSHidetoshi Shimokawa 		dsiz[0] = ir->psize;
256677ee030bSHidetoshi Shimokawa 		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
256777ee030bSHidetoshi Shimokawa 			BUS_DMASYNC_PREREAD);
25683c60ba66SKatsushi Kobayashi 	} else {
256977ee030bSHidetoshi Shimokawa 		db_tr->dbcnt = 0;
257077ee030bSHidetoshi Shimokawa 		if (dummy_dma != NULL) {
257103161bbcSDoug Rabson 			dsiz[db_tr->dbcnt] = sizeof(uint32_t);
257277ee030bSHidetoshi Shimokawa 			dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr;
257377ee030bSHidetoshi Shimokawa 		}
257477ee030bSHidetoshi Shimokawa 		dsiz[db_tr->dbcnt] = ir->psize;
257577ee030bSHidetoshi Shimokawa 		if (ir->buf != NULL) {
257677ee030bSHidetoshi Shimokawa 			db_tr->buf = fwdma_v_addr(ir->buf, poffset);
257777ee030bSHidetoshi Shimokawa 			dbuf[db_tr->dbcnt] = fwdma_bus_addr( ir->buf, poffset);
257877ee030bSHidetoshi Shimokawa 		}
257977ee030bSHidetoshi Shimokawa 		db_tr->dbcnt++;
25803c60ba66SKatsushi Kobayashi 	}
25813c60ba66SKatsushi Kobayashi 	for(i = 0 ; i < db_tr->dbcnt ; i++){
258277ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]);
258377ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]);
258477ee030bSHidetoshi Shimokawa 		if (ir->flag & FWXFERQ_STREAM) {
258577ee030bSHidetoshi Shimokawa 			FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE);
25863c60ba66SKatsushi Kobayashi 		}
258777ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]);
25883c60ba66SKatsushi Kobayashi 	}
258977ee030bSHidetoshi Shimokawa 	ldesc = db_tr->dbcnt - 1;
259077ee030bSHidetoshi Shimokawa 	if (ir->flag & FWXFERQ_STREAM) {
259177ee030bSHidetoshi Shimokawa 		FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST);
25923c60ba66SKatsushi Kobayashi 	}
259377ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS);
259477ee030bSHidetoshi Shimokawa 	return 0;
25953c60ba66SKatsushi Kobayashi }
2596c572b810SHidetoshi Shimokawa 
259777ee030bSHidetoshi Shimokawa 
259877ee030bSHidetoshi Shimokawa static int
259977ee030bSHidetoshi Shimokawa fwohci_arcv_swap(struct fw_pkt *fp, int len)
26003c60ba66SKatsushi Kobayashi {
260177ee030bSHidetoshi Shimokawa 	struct fw_pkt *fp0;
260203161bbcSDoug Rabson 	uint32_t ld0;
2603c4778b5dSHidetoshi Shimokawa 	int slen, hlen;
260477ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
260577ee030bSHidetoshi Shimokawa 	int i;
260677ee030bSHidetoshi Shimokawa #endif
26073c60ba66SKatsushi Kobayashi 
260877ee030bSHidetoshi Shimokawa 	ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]);
260977ee030bSHidetoshi Shimokawa #if 0
261077ee030bSHidetoshi Shimokawa 	printf("ld0: x%08x\n", ld0);
261177ee030bSHidetoshi Shimokawa #endif
261277ee030bSHidetoshi Shimokawa 	fp0 = (struct fw_pkt *)&ld0;
2613c4778b5dSHidetoshi Shimokawa 	/* determine length to swap */
261477ee030bSHidetoshi Shimokawa 	switch (fp0->mode.common.tcode) {
261577ee030bSHidetoshi Shimokawa 	case FWTCODE_RREQQ:
261677ee030bSHidetoshi Shimokawa 	case FWTCODE_WRES:
261777ee030bSHidetoshi Shimokawa 	case FWTCODE_WREQQ:
261877ee030bSHidetoshi Shimokawa 	case FWTCODE_RRESQ:
261977ee030bSHidetoshi Shimokawa 	case FWOHCITCODE_PHY:
262077ee030bSHidetoshi Shimokawa 		slen = 12;
26213c60ba66SKatsushi Kobayashi 		break;
262277ee030bSHidetoshi Shimokawa 	case FWTCODE_RREQB:
262377ee030bSHidetoshi Shimokawa 	case FWTCODE_WREQB:
262477ee030bSHidetoshi Shimokawa 	case FWTCODE_LREQ:
262577ee030bSHidetoshi Shimokawa 	case FWTCODE_RRESB:
262677ee030bSHidetoshi Shimokawa 	case FWTCODE_LRES:
262777ee030bSHidetoshi Shimokawa 		slen = 16;
26283c60ba66SKatsushi Kobayashi 		break;
26293c60ba66SKatsushi Kobayashi 	default:
263077ee030bSHidetoshi Shimokawa 		printf("Unknown tcode %d\n", fp0->mode.common.tcode);
263177ee030bSHidetoshi Shimokawa 		return(0);
26323c60ba66SKatsushi Kobayashi 	}
2633c4778b5dSHidetoshi Shimokawa 	hlen = tinfo[fp0->mode.common.tcode].hdr_len;
2634c4778b5dSHidetoshi Shimokawa 	if (hlen > len) {
263577ee030bSHidetoshi Shimokawa 		if (firewire_debug)
263677ee030bSHidetoshi Shimokawa 			printf("splitted header\n");
2637c4778b5dSHidetoshi Shimokawa 		return(-hlen);
26383c60ba66SKatsushi Kobayashi 	}
263977ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
264077ee030bSHidetoshi Shimokawa 	for(i = 0; i < slen/4; i ++)
264177ee030bSHidetoshi Shimokawa 		fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
264277ee030bSHidetoshi Shimokawa #endif
2643c4778b5dSHidetoshi Shimokawa 	return(hlen);
26443c60ba66SKatsushi Kobayashi }
26453c60ba66SKatsushi Kobayashi 
26463c60ba66SKatsushi Kobayashi static int
264777ee030bSHidetoshi Shimokawa fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp)
26483c60ba66SKatsushi Kobayashi {
2649c4778b5dSHidetoshi Shimokawa 	struct tcode_info *info;
265077ee030bSHidetoshi Shimokawa 	int r;
26513c60ba66SKatsushi Kobayashi 
2652c4778b5dSHidetoshi Shimokawa 	info = &tinfo[fp->mode.common.tcode];
265303161bbcSDoug Rabson 	r = info->hdr_len + sizeof(uint32_t);
2654c4778b5dSHidetoshi Shimokawa 	if ((info->flag & FWTI_BLOCK_ASY) != 0)
265503161bbcSDoug Rabson 		r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t));
2656c4778b5dSHidetoshi Shimokawa 
265703161bbcSDoug Rabson 	if (r == sizeof(uint32_t))
2658c4778b5dSHidetoshi Shimokawa 		/* XXX */
2659627d85fbSHidetoshi Shimokawa 		device_printf(sc->fc.dev, "Unknown tcode %d\n",
2660627d85fbSHidetoshi Shimokawa 						fp->mode.common.tcode);
2661c4778b5dSHidetoshi Shimokawa 
2662627d85fbSHidetoshi Shimokawa 	if (r > dbch->xferq.psize) {
2663627d85fbSHidetoshi Shimokawa 		device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
2664627d85fbSHidetoshi Shimokawa 		/* panic ? */
2665627d85fbSHidetoshi Shimokawa 	}
2666c4778b5dSHidetoshi Shimokawa 
2667627d85fbSHidetoshi Shimokawa 	return r;
26683c60ba66SKatsushi Kobayashi }
26693c60ba66SKatsushi Kobayashi 
2670c572b810SHidetoshi Shimokawa static void
267177ee030bSHidetoshi Shimokawa fwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
267277ee030bSHidetoshi Shimokawa {
2673c4778b5dSHidetoshi Shimokawa 	struct fwohcidb *db = &db_tr->db[0];
267477ee030bSHidetoshi Shimokawa 
267577ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
267677ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
267777ee030bSHidetoshi Shimokawa 	FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
267877ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
267977ee030bSHidetoshi Shimokawa 	dbch->bottom = db_tr;
268077ee030bSHidetoshi Shimokawa }
268177ee030bSHidetoshi Shimokawa 
268277ee030bSHidetoshi Shimokawa static void
2683c572b810SHidetoshi Shimokawa fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
26843c60ba66SKatsushi Kobayashi {
26853c60ba66SKatsushi Kobayashi 	struct fwohcidb_tr *db_tr;
268677ee030bSHidetoshi Shimokawa 	struct iovec vec[2];
268777ee030bSHidetoshi Shimokawa 	struct fw_pkt pktbuf;
268877ee030bSHidetoshi Shimokawa 	int nvec;
26893c60ba66SKatsushi Kobayashi 	struct fw_pkt *fp;
269003161bbcSDoug Rabson 	uint8_t *ld;
269103161bbcSDoug Rabson 	uint32_t stat, off, status;
26923c60ba66SKatsushi Kobayashi 	u_int spd;
269377ee030bSHidetoshi Shimokawa 	int len, plen, hlen, pcnt, offset;
26943c60ba66SKatsushi Kobayashi 	int s;
26953c60ba66SKatsushi Kobayashi 	caddr_t buf;
26963c60ba66SKatsushi Kobayashi 	int resCount;
26973c60ba66SKatsushi Kobayashi 
26983c60ba66SKatsushi Kobayashi 	if(&sc->arrq == dbch){
26993c60ba66SKatsushi Kobayashi 		off = OHCI_ARQOFF;
27003c60ba66SKatsushi Kobayashi 	}else if(&sc->arrs == dbch){
27013c60ba66SKatsushi Kobayashi 		off = OHCI_ARSOFF;
27023c60ba66SKatsushi Kobayashi 	}else{
27033c60ba66SKatsushi Kobayashi 		return;
27043c60ba66SKatsushi Kobayashi 	}
27053c60ba66SKatsushi Kobayashi 
27063c60ba66SKatsushi Kobayashi 	s = splfw();
27073c60ba66SKatsushi Kobayashi 	db_tr = dbch->top;
27083c60ba66SKatsushi Kobayashi 	pcnt = 0;
27093c60ba66SKatsushi Kobayashi 	/* XXX we cannot handle a packet which lies in more than two buf */
271077ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
271177ee030bSHidetoshi Shimokawa 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
271277ee030bSHidetoshi Shimokawa 	status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
271377ee030bSHidetoshi Shimokawa 	resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
271477ee030bSHidetoshi Shimokawa #if 0
271577ee030bSHidetoshi Shimokawa 	printf("status 0x%04x, resCount 0x%04x\n", status, resCount);
271677ee030bSHidetoshi Shimokawa #endif
271777ee030bSHidetoshi Shimokawa 	while (status & OHCI_CNTL_DMA_ACTIVE) {
271877ee030bSHidetoshi Shimokawa 		len = dbch->xferq.psize - resCount;
271903161bbcSDoug Rabson 		ld = (uint8_t *)db_tr->buf;
272077ee030bSHidetoshi Shimokawa 		if (dbch->pdb_tr == NULL) {
272177ee030bSHidetoshi Shimokawa 			len -= dbch->buf_offset;
272277ee030bSHidetoshi Shimokawa 			ld += dbch->buf_offset;
272377ee030bSHidetoshi Shimokawa 		}
272477ee030bSHidetoshi Shimokawa 		if (len > 0)
272577ee030bSHidetoshi Shimokawa 			bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
272677ee030bSHidetoshi Shimokawa 					BUS_DMASYNC_POSTREAD);
27273c60ba66SKatsushi Kobayashi 		while (len > 0 ) {
2728783058faSHidetoshi Shimokawa 			if (count >= 0 && count-- == 0)
2729783058faSHidetoshi Shimokawa 				goto out;
273077ee030bSHidetoshi Shimokawa 			if(dbch->pdb_tr != NULL){
273177ee030bSHidetoshi Shimokawa 				/* we have a fragment in previous buffer */
273277ee030bSHidetoshi Shimokawa 				int rlen;
27333c60ba66SKatsushi Kobayashi 
273477ee030bSHidetoshi Shimokawa 				offset = dbch->buf_offset;
273577ee030bSHidetoshi Shimokawa 				if (offset < 0)
273677ee030bSHidetoshi Shimokawa 					offset = - offset;
273777ee030bSHidetoshi Shimokawa 				buf = dbch->pdb_tr->buf + offset;
273877ee030bSHidetoshi Shimokawa 				rlen = dbch->xferq.psize - offset;
273977ee030bSHidetoshi Shimokawa 				if (firewire_debug)
274077ee030bSHidetoshi Shimokawa 					printf("rlen=%d, offset=%d\n",
274177ee030bSHidetoshi Shimokawa 						rlen, dbch->buf_offset);
274277ee030bSHidetoshi Shimokawa 				if (dbch->buf_offset < 0) {
274377ee030bSHidetoshi Shimokawa 					/* splitted in header, pull up */
274477ee030bSHidetoshi Shimokawa 					char *p;
274577ee030bSHidetoshi Shimokawa 
274677ee030bSHidetoshi Shimokawa 					p = (char *)&pktbuf;
274777ee030bSHidetoshi Shimokawa 					bcopy(buf, p, rlen);
274877ee030bSHidetoshi Shimokawa 					p += rlen;
274977ee030bSHidetoshi Shimokawa 					/* this must be too long but harmless */
275077ee030bSHidetoshi Shimokawa 					rlen = sizeof(pktbuf) - rlen;
275177ee030bSHidetoshi Shimokawa 					if (rlen < 0)
275277ee030bSHidetoshi Shimokawa 						printf("why rlen < 0\n");
275377ee030bSHidetoshi Shimokawa 					bcopy(db_tr->buf, p, rlen);
27543c60ba66SKatsushi Kobayashi 					ld += rlen;
27553c60ba66SKatsushi Kobayashi 					len -= rlen;
275677ee030bSHidetoshi Shimokawa 					hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
275777ee030bSHidetoshi Shimokawa 					if (hlen < 0) {
275877ee030bSHidetoshi Shimokawa 						printf("hlen < 0 shouldn't happen");
27593c60ba66SKatsushi Kobayashi 					}
276077ee030bSHidetoshi Shimokawa 					offset = sizeof(pktbuf);
276177ee030bSHidetoshi Shimokawa 					vec[0].iov_base = (char *)&pktbuf;
276277ee030bSHidetoshi Shimokawa 					vec[0].iov_len = offset;
27633c60ba66SKatsushi Kobayashi 				} else {
276477ee030bSHidetoshi Shimokawa 					/* splitted in payload */
276577ee030bSHidetoshi Shimokawa 					offset = rlen;
276677ee030bSHidetoshi Shimokawa 					vec[0].iov_base = buf;
276777ee030bSHidetoshi Shimokawa 					vec[0].iov_len = rlen;
276877ee030bSHidetoshi Shimokawa 				}
276977ee030bSHidetoshi Shimokawa 				fp=(struct fw_pkt *)vec[0].iov_base;
277077ee030bSHidetoshi Shimokawa 				nvec = 1;
277177ee030bSHidetoshi Shimokawa 			} else {
277277ee030bSHidetoshi Shimokawa 				/* no fragment in previous buffer */
27733c60ba66SKatsushi Kobayashi 				fp=(struct fw_pkt *)ld;
277477ee030bSHidetoshi Shimokawa 				hlen = fwohci_arcv_swap(fp, len);
277577ee030bSHidetoshi Shimokawa 				if (hlen == 0)
277677ee030bSHidetoshi Shimokawa 					/* XXX need reset */
277777ee030bSHidetoshi Shimokawa 					goto out;
277877ee030bSHidetoshi Shimokawa 				if (hlen < 0) {
277977ee030bSHidetoshi Shimokawa 					dbch->pdb_tr = db_tr;
278077ee030bSHidetoshi Shimokawa 					dbch->buf_offset = - dbch->buf_offset;
278177ee030bSHidetoshi Shimokawa 					/* sanity check */
278277ee030bSHidetoshi Shimokawa 					if (resCount != 0)
27835b50d9adSHidetoshi Shimokawa 						printf("resCount = %d !?\n",
27845b50d9adSHidetoshi Shimokawa 						    resCount);
27855b50d9adSHidetoshi Shimokawa 					/* XXX clear pdb_tr */
27863c60ba66SKatsushi Kobayashi 					goto out;
27873c60ba66SKatsushi Kobayashi 				}
278877ee030bSHidetoshi Shimokawa 				offset = 0;
278977ee030bSHidetoshi Shimokawa 				nvec = 0;
27903c60ba66SKatsushi Kobayashi 			}
279177ee030bSHidetoshi Shimokawa 			plen = fwohci_get_plen(sc, dbch, fp) - offset;
27923c60ba66SKatsushi Kobayashi 			if (plen < 0) {
279377ee030bSHidetoshi Shimokawa 				/* minimum header size + trailer
279477ee030bSHidetoshi Shimokawa 				= sizeof(fw_pkt) so this shouldn't happens */
2795c4778b5dSHidetoshi Shimokawa 				printf("plen(%d) is negative! offset=%d\n",
2796c4778b5dSHidetoshi Shimokawa 				    plen, offset);
27975b50d9adSHidetoshi Shimokawa 				/* XXX clear pdb_tr */
279877ee030bSHidetoshi Shimokawa 				goto out;
27993c60ba66SKatsushi Kobayashi 			}
280077ee030bSHidetoshi Shimokawa 			if (plen > 0) {
280177ee030bSHidetoshi Shimokawa 				len -= plen;
280277ee030bSHidetoshi Shimokawa 				if (len < 0) {
280377ee030bSHidetoshi Shimokawa 					dbch->pdb_tr = db_tr;
280477ee030bSHidetoshi Shimokawa 					if (firewire_debug)
280577ee030bSHidetoshi Shimokawa 						printf("splitted payload\n");
280677ee030bSHidetoshi Shimokawa 					/* sanity check */
280777ee030bSHidetoshi Shimokawa 					if (resCount != 0)
28085b50d9adSHidetoshi Shimokawa 						printf("resCount = %d !?\n",
28095b50d9adSHidetoshi Shimokawa 						    resCount);
28105b50d9adSHidetoshi Shimokawa 					/* XXX clear pdb_tr */
281177ee030bSHidetoshi Shimokawa 					goto out;
28123c60ba66SKatsushi Kobayashi 				}
281377ee030bSHidetoshi Shimokawa 				vec[nvec].iov_base = ld;
281477ee030bSHidetoshi Shimokawa 				vec[nvec].iov_len = plen;
281577ee030bSHidetoshi Shimokawa 				nvec ++;
28163c60ba66SKatsushi Kobayashi 				ld += plen;
28173c60ba66SKatsushi Kobayashi 			}
281803161bbcSDoug Rabson 			dbch->buf_offset = ld - (uint8_t *)db_tr->buf;
281977ee030bSHidetoshi Shimokawa 			if (nvec == 0)
282077ee030bSHidetoshi Shimokawa 				printf("nvec == 0\n");
282177ee030bSHidetoshi Shimokawa 
28223c60ba66SKatsushi Kobayashi /* DMA result-code will be written at the tail of packet */
282377ee030bSHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
282477ee030bSHidetoshi Shimokawa 			stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16;
282577ee030bSHidetoshi Shimokawa #else
28263c60ba66SKatsushi Kobayashi 			stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
282777ee030bSHidetoshi Shimokawa #endif
282877ee030bSHidetoshi Shimokawa #if 0
2829c4778b5dSHidetoshi Shimokawa 			printf("plen: %d, stat %x\n",
2830c4778b5dSHidetoshi Shimokawa 			    plen ,stat);
283177ee030bSHidetoshi Shimokawa #endif
28323c60ba66SKatsushi Kobayashi 			spd = (stat >> 5) & 0x3;
28333c60ba66SKatsushi Kobayashi 			stat &= 0x1f;
28343c60ba66SKatsushi Kobayashi 			switch(stat){
28353c60ba66SKatsushi Kobayashi 			case FWOHCIEV_ACKPEND:
2836864d7e72SHidetoshi Shimokawa #if 0
283773aa55baSHidetoshi Shimokawa 				printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
28383c60ba66SKatsushi Kobayashi #endif
28393c60ba66SKatsushi Kobayashi 				/* fall through */
28403c60ba66SKatsushi Kobayashi 			case FWOHCIEV_ACKCOMPL:
2841c4778b5dSHidetoshi Shimokawa 			{
2842c4778b5dSHidetoshi Shimokawa 				struct fw_rcv_buf rb;
2843c4778b5dSHidetoshi Shimokawa 
284477ee030bSHidetoshi Shimokawa 				if ((vec[nvec-1].iov_len -=
284577ee030bSHidetoshi Shimokawa 					sizeof(struct fwohci_trailer)) == 0)
284677ee030bSHidetoshi Shimokawa 					nvec--;
2847c4778b5dSHidetoshi Shimokawa 				rb.fc = &sc->fc;
2848c4778b5dSHidetoshi Shimokawa 				rb.vec = vec;
2849c4778b5dSHidetoshi Shimokawa 				rb.nvec = nvec;
2850c4778b5dSHidetoshi Shimokawa 				rb.spd = spd;
2851c4778b5dSHidetoshi Shimokawa 				fw_rcv(&rb);
28523c60ba66SKatsushi Kobayashi 				break;
2853c4778b5dSHidetoshi Shimokawa 			}
28543c60ba66SKatsushi Kobayashi 			case FWOHCIEV_BUSRST:
28553c60ba66SKatsushi Kobayashi 				if (sc->fc.status != FWBUSRESET)
28563c60ba66SKatsushi Kobayashi 					printf("got BUSRST packet!?\n");
28573c60ba66SKatsushi Kobayashi 				break;
28583c60ba66SKatsushi Kobayashi 			default:
28593c60ba66SKatsushi Kobayashi 				device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]);
28603c60ba66SKatsushi Kobayashi #if 0 /* XXX */
28613c60ba66SKatsushi Kobayashi 				goto out;
28623c60ba66SKatsushi Kobayashi #endif
28633c60ba66SKatsushi Kobayashi 				break;
28643c60ba66SKatsushi Kobayashi 			}
28653c60ba66SKatsushi Kobayashi 			pcnt ++;
286677ee030bSHidetoshi Shimokawa 			if (dbch->pdb_tr != NULL) {
286777ee030bSHidetoshi Shimokawa 				fwohci_arcv_free_buf(dbch, dbch->pdb_tr);
286877ee030bSHidetoshi Shimokawa 				dbch->pdb_tr = NULL;
286977ee030bSHidetoshi Shimokawa 			}
287077ee030bSHidetoshi Shimokawa 
287177ee030bSHidetoshi Shimokawa 		}
28723c60ba66SKatsushi Kobayashi out:
28733c60ba66SKatsushi Kobayashi 		if (resCount == 0) {
28743c60ba66SKatsushi Kobayashi 			/* done on this buffer */
287577ee030bSHidetoshi Shimokawa 			if (dbch->pdb_tr == NULL) {
287677ee030bSHidetoshi Shimokawa 				fwohci_arcv_free_buf(dbch, db_tr);
28773c60ba66SKatsushi Kobayashi 				dbch->buf_offset = 0;
287877ee030bSHidetoshi Shimokawa 			} else
287977ee030bSHidetoshi Shimokawa 				if (dbch->pdb_tr != db_tr)
288077ee030bSHidetoshi Shimokawa 					printf("pdb_tr != db_tr\n");
288177ee030bSHidetoshi Shimokawa 			db_tr = STAILQ_NEXT(db_tr, link);
288277ee030bSHidetoshi Shimokawa 			status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
288377ee030bSHidetoshi Shimokawa 						>> OHCI_STATUS_SHIFT;
288477ee030bSHidetoshi Shimokawa 			resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
288577ee030bSHidetoshi Shimokawa 						& OHCI_COUNT_MASK;
288677ee030bSHidetoshi Shimokawa 			/* XXX check buffer overrun */
288777ee030bSHidetoshi Shimokawa 			dbch->top = db_tr;
28883c60ba66SKatsushi Kobayashi 		} else {
28893c60ba66SKatsushi Kobayashi 			dbch->buf_offset = dbch->xferq.psize - resCount;
28903c60ba66SKatsushi Kobayashi 			break;
28913c60ba66SKatsushi Kobayashi 		}
28923c60ba66SKatsushi Kobayashi 		/* XXX make sure DMA is not dead */
28933c60ba66SKatsushi Kobayashi 	}
28943c60ba66SKatsushi Kobayashi #if 0
28953c60ba66SKatsushi Kobayashi 	if (pcnt < 1)
28963c60ba66SKatsushi Kobayashi 		printf("fwohci_arcv: no packets\n");
28973c60ba66SKatsushi Kobayashi #endif
28983c60ba66SKatsushi Kobayashi 	splx(s);
28993c60ba66SKatsushi Kobayashi }
2900