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