1139749Simp/*-
2113584Ssimokawa * Copyright (c) 2003 Hidetoshi Shimokawa
3103285Sikob * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4103285Sikob * All rights reserved.
5103285Sikob *
6103285Sikob * Redistribution and use in source and binary forms, with or without
7103285Sikob * modification, are permitted provided that the following conditions
8103285Sikob * are met:
9103285Sikob * 1. Redistributions of source code must retain the above copyright
10103285Sikob *    notice, this list of conditions and the following disclaimer.
11103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
12103285Sikob *    notice, this list of conditions and the following disclaimer in the
13103285Sikob *    documentation and/or other materials provided with the distribution.
14103285Sikob * 3. All advertising materials mentioning features or use of this software
15103285Sikob *    must display the acknowledgement as bellow:
16103285Sikob *
17106802Ssimokawa *    This product includes software developed by K. Kobayashi and H. Shimokawa
18103285Sikob *
19103285Sikob * 4. The name of the author may not be used to endorse or promote products
20103285Sikob *    derived from this software without specific prior written permission.
21103285Sikob *
22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23103285Sikob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24103285Sikob * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25103285Sikob * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26103285Sikob * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27103285Sikob * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28103285Sikob * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30103285Sikob * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31103285Sikob * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32103285Sikob * POSSIBILITY OF SUCH DAMAGE.
33272214Skan *
34103285Sikob * $FreeBSD: stable/11/sys/dev/firewire/fwohci.c 310073 2016-12-14 16:30:47Z avg $
35103285Sikob *
36103285Sikob */
37106802Ssimokawa
38103285Sikob#include <sys/param.h>
39103285Sikob#include <sys/systm.h>
40103285Sikob#include <sys/mbuf.h>
41103285Sikob#include <sys/malloc.h>
42103285Sikob#include <sys/sockio.h>
43169123Ssimokawa#include <sys/sysctl.h>
44103285Sikob#include <sys/bus.h>
45103285Sikob#include <sys/kernel.h>
46103285Sikob#include <sys/conf.h>
47113584Ssimokawa#include <sys/endian.h>
48170374Ssimokawa#include <sys/kdb.h>
49103285Sikob
50103285Sikob#include <machine/bus.h>
51277511Swill#include <machine/md_var.h>
52103285Sikob
53103285Sikob#include <dev/firewire/firewire.h>
54103285Sikob#include <dev/firewire/firewirereg.h>
55113584Ssimokawa#include <dev/firewire/fwdma.h>
56103285Sikob#include <dev/firewire/fwohcireg.h>
57103285Sikob#include <dev/firewire/fwohcivar.h>
58103285Sikob#include <dev/firewire/firewire_phy.h>
59103285Sikob
60103285Sikob#undef OHCI_DEBUG
61106802Ssimokawa
62267992Shselaskystatic int nocyclemaster;
63170400Ssimokawaint firewire_phydma_enable = 1;
64169123SsimokawaSYSCTL_DECL(_hw_firewire);
65267992ShselaskySYSCTL_INT(_hw_firewire, OID_AUTO, nocyclemaster, CTLFLAG_RWTUN,
66267992Shselasky	&nocyclemaster, 0, "Do not send cycle start packets");
67267992ShselaskySYSCTL_INT(_hw_firewire, OID_AUTO, phydma_enable, CTLFLAG_RWTUN,
68267992Shselasky	&firewire_phydma_enable, 0, "Allow physical request DMA from firewire");
69169123Ssimokawa
70272214Skanstatic char dbcode[16][0x10] = {"OUTM", "OUTL", "INPM", "INPL",
71272214Skan				"STOR", "LOAD", "NOP ", "STOP",};
72113584Ssimokawa
73272214Skanstatic char dbkey[8][0x10] = {"ST0", "ST1", "ST2", "ST3",
74272214Skan			      "UNDEF", "REG", "SYS", "DEV"};
75272214Skanstatic char dbcond[4][0x10] = {"NEV", "C=1", "C=0", "ALL"};
76272214Skanchar fwohcicode[32][0x20]= {
77272214Skan	"No stat", "Undef", "long", "miss Ack err",
78272214Skan	"FIFO underrun", "FIFO overrun", "desc err", "data read err",
79272214Skan	"data write err", "bus reset", "timeout", "tcode err",
80272214Skan	"Undef", "Undef", "unknown event", "flushed",
81272214Skan	"Undef" ,"ack complete", "ack pend", "Undef",
82272214Skan	"ack busy_X", "ack busy_A", "ack busy_B", "Undef",
83272214Skan	"Undef", "Undef", "Undef", "ack tardy",
84272214Skan	"Undef", "ack data_err", "ack type_err", ""};
85113584Ssimokawa
86116376Ssimokawa#define MAX_SPEED 3
87124378Ssimokawaextern char *linkspeed[];
88272214Skanuint32_t tagbit[4] = {1 << 28, 1 << 29, 1 << 30, 1 << 31};
89103285Sikob
90103285Sikobstatic struct tcode_info tinfo[] = {
91170374Ssimokawa/*		hdr_len block 	flag	valid_response */
92170374Ssimokawa/* 0 WREQQ  */ {16,	FWTI_REQ | FWTI_TLABEL,	FWTCODE_WRES},
93170374Ssimokawa/* 1 WREQB  */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES},
94170374Ssimokawa/* 2 WRES   */ {12,	FWTI_RES, 0xff},
95170374Ssimokawa/* 3 XXX    */ { 0,	0, 0xff},
96170374Ssimokawa/* 4 RREQQ  */ {12,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ},
97170374Ssimokawa/* 5 RREQB  */ {16,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB},
98170374Ssimokawa/* 6 RRESQ  */ {16,	FWTI_RES, 0xff},
99170374Ssimokawa/* 7 RRESB  */ {16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff},
100170374Ssimokawa/* 8 CYCS   */ { 0,	0, 0xff},
101170374Ssimokawa/* 9 LREQ   */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES},
102170374Ssimokawa/* a STREAM */ { 4,	FWTI_REQ | FWTI_BLOCK_STR, 0xff},
103170374Ssimokawa/* b LRES   */ {16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff},
104170374Ssimokawa/* c XXX    */ { 0,	0, 0xff},
105170374Ssimokawa/* d XXX    */ { 0, 	0, 0xff},
106170374Ssimokawa/* e PHY    */ {12,	FWTI_REQ, 0xff},
107170374Ssimokawa/* f XXX    */ { 0,	0, 0xff}
108103285Sikob};
109103285Sikob
110272214Skan#define ATRQ_CH 0
111272214Skan#define ATRS_CH 1
112272214Skan#define ARRQ_CH 2
113272214Skan#define ARRS_CH 3
114272214Skan#define ITX_CH 4
115272214Skan#define IRX_CH 0x24
116272214Skan
117103285Sikob#define OHCI_WRITE_SIGMASK 0xffff0000
118103285Sikob#define OHCI_READ_SIGMASK 0xffff0000
119103285Sikob
120103285Sikob#define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x))
121103285Sikob#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r))
122103285Sikob
123124169Ssimokawastatic void fwohci_ibr (struct firewire_comm *);
124124169Ssimokawastatic void fwohci_db_init (struct fwohci_softc *, struct fwohci_dbch *);
125124169Ssimokawastatic void fwohci_db_free (struct fwohci_dbch *);
126124169Ssimokawastatic void fwohci_arcv (struct fwohci_softc *, struct fwohci_dbch *, int);
127124169Ssimokawastatic void fwohci_txd (struct fwohci_softc *, struct fwohci_dbch *);
128124169Ssimokawastatic void fwohci_start_atq (struct firewire_comm *);
129124169Ssimokawastatic void fwohci_start_ats (struct firewire_comm *);
130124169Ssimokawastatic void fwohci_start (struct fwohci_softc *, struct fwohci_dbch *);
131272214Skanstatic uint32_t fwphy_wrdata (struct fwohci_softc *, uint32_t, uint32_t);
132272214Skanstatic uint32_t fwphy_rddata (struct fwohci_softc *, uint32_t);
133124169Ssimokawastatic int fwohci_rx_enable (struct fwohci_softc *, struct fwohci_dbch *);
134124169Ssimokawastatic int fwohci_tx_enable (struct fwohci_softc *, struct fwohci_dbch *);
135124169Ssimokawastatic int fwohci_irx_enable (struct firewire_comm *, int);
136124169Ssimokawastatic int fwohci_irx_disable (struct firewire_comm *, int);
137113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
138129585Sdfrstatic void fwohci_irx_post (struct firewire_comm *, uint32_t *);
139113584Ssimokawa#endif
140124169Ssimokawastatic int fwohci_itxbuf_enable (struct firewire_comm *, int);
141124169Ssimokawastatic int fwohci_itx_disable (struct firewire_comm *, int);
142124169Ssimokawastatic void fwohci_timeout (void *);
143124169Ssimokawastatic void fwohci_set_intr (struct firewire_comm *, int);
144113584Ssimokawa
145124169Ssimokawastatic int fwohci_add_rx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *);
146124169Ssimokawastatic int fwohci_add_tx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int);
147272214Skanstatic void dump_db (struct fwohci_softc *, uint32_t);
148272214Skanstatic void print_db (struct fwohcidb_tr *, struct fwohcidb *, uint32_t , uint32_t);
149272214Skanstatic void dump_dma (struct fwohci_softc *, uint32_t);
150129585Sdfrstatic uint32_t fwohci_cyctimer (struct firewire_comm *);
151124169Ssimokawastatic void fwohci_rbuf_update (struct fwohci_softc *, int);
152124169Ssimokawastatic void fwohci_tbuf_update (struct fwohci_softc *, int);
153124169Ssimokawavoid fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *);
154170374Ssimokawastatic void fwohci_task_busreset(void *, int);
155170374Ssimokawastatic void fwohci_task_sid(void *, int);
156170374Ssimokawastatic void fwohci_task_dma(void *, int);
157103285Sikob
158103285Sikob/*
159103285Sikob * memory allocated for DMA programs
160103285Sikob */
161103285Sikob#define DMA_PROG_ALLOC		(8 * PAGE_SIZE)
162103285Sikob
163103285Sikob#define NDB FWMAXQUEUE
164103285Sikob
165103285Sikob#define	OHCI_VERSION		0x00
166112523Ssimokawa#define	OHCI_ATRETRY		0x08
167103285Sikob#define	OHCI_CROMHDR		0x18
168103285Sikob#define	OHCI_BUS_OPT		0x20
169258780Seadler#define	OHCI_BUSIRMC		(1U << 31)
170103285Sikob#define	OHCI_BUSCMC		(1 << 30)
171103285Sikob#define	OHCI_BUSISC		(1 << 29)
172103285Sikob#define	OHCI_BUSBMC		(1 << 28)
173103285Sikob#define	OHCI_BUSPMC		(1 << 27)
174103285Sikob#define OHCI_BUSFNC		OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\
175103285Sikob				OHCI_BUSBMC | OHCI_BUSPMC
176103285Sikob
177103285Sikob#define	OHCI_EUID_HI		0x24
178103285Sikob#define	OHCI_EUID_LO		0x28
179103285Sikob
180103285Sikob#define	OHCI_CROMPTR		0x34
181103285Sikob#define	OHCI_HCCCTL		0x50
182103285Sikob#define	OHCI_HCCCTLCLR		0x54
183103285Sikob#define	OHCI_AREQHI		0x100
184103285Sikob#define	OHCI_AREQHICLR		0x104
185103285Sikob#define	OHCI_AREQLO		0x108
186103285Sikob#define	OHCI_AREQLOCLR		0x10c
187103285Sikob#define	OHCI_PREQHI		0x110
188103285Sikob#define	OHCI_PREQHICLR		0x114
189103285Sikob#define	OHCI_PREQLO		0x118
190103285Sikob#define	OHCI_PREQLOCLR		0x11c
191103285Sikob#define	OHCI_PREQUPPER		0x120
192277511Swill#define OHCI_PREQUPPER_MAX	0xffff0000
193103285Sikob
194103285Sikob#define	OHCI_SID_BUF		0x64
195103285Sikob#define	OHCI_SID_CNT		0x68
196258780Seadler#define OHCI_SID_ERR		(1U << 31)
197103285Sikob#define OHCI_SID_CNT_MASK	0xffc
198103285Sikob
199103285Sikob#define	OHCI_IT_STAT		0x90
200103285Sikob#define	OHCI_IT_STATCLR		0x94
201103285Sikob#define	OHCI_IT_MASK		0x98
202103285Sikob#define	OHCI_IT_MASKCLR		0x9c
203103285Sikob
204103285Sikob#define	OHCI_IR_STAT		0xa0
205103285Sikob#define	OHCI_IR_STATCLR		0xa4
206103285Sikob#define	OHCI_IR_MASK		0xa8
207103285Sikob#define	OHCI_IR_MASKCLR		0xac
208103285Sikob
209103285Sikob#define	OHCI_LNKCTL		0xe0
210103285Sikob#define	OHCI_LNKCTLCLR		0xe4
211103285Sikob
212103285Sikob#define	OHCI_PHYACCESS		0xec
213103285Sikob#define	OHCI_CYCLETIMER		0xf0
214103285Sikob
215103285Sikob#define	OHCI_DMACTL(off)	(off)
216103285Sikob#define	OHCI_DMACTLCLR(off)	(off + 4)
217103285Sikob#define	OHCI_DMACMD(off)	(off + 0xc)
218103285Sikob#define	OHCI_DMAMATCH(off)	(off + 0x10)
219103285Sikob
220103285Sikob#define OHCI_ATQOFF		0x180
221103285Sikob#define OHCI_ATQCTL		OHCI_ATQOFF
222103285Sikob#define OHCI_ATQCTLCLR		(OHCI_ATQOFF + 4)
223103285Sikob#define OHCI_ATQCMD		(OHCI_ATQOFF + 0xc)
224103285Sikob#define OHCI_ATQMATCH		(OHCI_ATQOFF + 0x10)
225103285Sikob
226103285Sikob#define OHCI_ATSOFF		0x1a0
227103285Sikob#define OHCI_ATSCTL		OHCI_ATSOFF
228103285Sikob#define OHCI_ATSCTLCLR		(OHCI_ATSOFF + 4)
229103285Sikob#define OHCI_ATSCMD		(OHCI_ATSOFF + 0xc)
230103285Sikob#define OHCI_ATSMATCH		(OHCI_ATSOFF + 0x10)
231103285Sikob
232103285Sikob#define OHCI_ARQOFF		0x1c0
233103285Sikob#define OHCI_ARQCTL		OHCI_ARQOFF
234103285Sikob#define OHCI_ARQCTLCLR		(OHCI_ARQOFF + 4)
235103285Sikob#define OHCI_ARQCMD		(OHCI_ARQOFF + 0xc)
236103285Sikob#define OHCI_ARQMATCH		(OHCI_ARQOFF + 0x10)
237103285Sikob
238103285Sikob#define OHCI_ARSOFF		0x1e0
239103285Sikob#define OHCI_ARSCTL		OHCI_ARSOFF
240103285Sikob#define OHCI_ARSCTLCLR		(OHCI_ARSOFF + 4)
241103285Sikob#define OHCI_ARSCMD		(OHCI_ARSOFF + 0xc)
242103285Sikob#define OHCI_ARSMATCH		(OHCI_ARSOFF + 0x10)
243103285Sikob
244103285Sikob#define OHCI_ITOFF(CH)		(0x200 + 0x10 * (CH))
245103285Sikob#define OHCI_ITCTL(CH)		(OHCI_ITOFF(CH))
246103285Sikob#define OHCI_ITCTLCLR(CH)	(OHCI_ITOFF(CH) + 4)
247103285Sikob#define OHCI_ITCMD(CH)		(OHCI_ITOFF(CH) + 0xc)
248103285Sikob
249103285Sikob#define OHCI_IROFF(CH)		(0x400 + 0x20 * (CH))
250103285Sikob#define OHCI_IRCTL(CH)		(OHCI_IROFF(CH))
251103285Sikob#define OHCI_IRCTLCLR(CH)	(OHCI_IROFF(CH) + 4)
252103285Sikob#define OHCI_IRCMD(CH)		(OHCI_IROFF(CH) + 0xc)
253103285Sikob#define OHCI_IRMATCH(CH)	(OHCI_IROFF(CH) + 0x10)
254103285Sikob
255103285Sikobd_ioctl_t fwohci_ioctl;
256103285Sikob
257103285Sikob/*
258103285Sikob * Communication with PHY device
259103285Sikob */
260170374Ssimokawa/* XXX need lock for phy access */
261129585Sdfrstatic uint32_t
262272214Skanfwphy_wrdata(struct fwohci_softc *sc, uint32_t addr, uint32_t data)
263103285Sikob{
264129585Sdfr	uint32_t fun;
265103285Sikob
266103285Sikob	addr &= 0xf;
267103285Sikob	data &= 0xff;
268103285Sikob
269272214Skan	fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) |
270272214Skan	      (data << PHYDEV_WRDATA));
271103285Sikob	OWRITE(sc, OHCI_PHYACCESS, fun);
272103285Sikob	DELAY(100);
273103285Sikob
274272214Skan	return (fwphy_rddata(sc, addr));
275103285Sikob}
276103285Sikob
277129585Sdfrstatic uint32_t
278103285Sikobfwohci_set_bus_manager(struct firewire_comm *fc, u_int node)
279103285Sikob{
280103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
281103285Sikob	int i;
282129585Sdfr	uint32_t bm;
283103285Sikob
284103285Sikob#define OHCI_CSR_DATA	0x0c
285103285Sikob#define OHCI_CSR_COMP	0x10
286103285Sikob#define OHCI_CSR_CONT	0x14
287103285Sikob#define OHCI_BUS_MANAGER_ID	0
288103285Sikob
289103285Sikob	OWRITE(sc, OHCI_CSR_DATA, node);
290103285Sikob	OWRITE(sc, OHCI_CSR_COMP, 0x3f);
291103285Sikob	OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID);
292103285Sikob 	for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++)
293109280Ssimokawa		DELAY(10);
294103285Sikob	bm = OREAD(sc, OHCI_CSR_DATA);
295272214Skan	if ((bm & 0x3f) == 0x3f)
296103285Sikob		bm = node;
297132432Ssimokawa	if (firewire_debug)
298188509Ssbruno		device_printf(sc->fc.dev, "%s: %d->%d (loop=%d)\n",
299188509Ssbruno				__func__, bm, node, i);
300272214Skan	return (bm);
301103285Sikob}
302103285Sikob
303129585Sdfrstatic uint32_t
304272214Skanfwphy_rddata(struct fwohci_softc *sc, u_int addr)
305103285Sikob{
306129585Sdfr	uint32_t fun, stat;
307108500Ssimokawa	u_int i, retry = 0;
308103285Sikob
309103285Sikob	addr &= 0xf;
310108500Ssimokawa#define MAX_RETRY 100
311108500Ssimokawaagain:
312108500Ssimokawa	OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL);
313103285Sikob	fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR);
314103285Sikob	OWRITE(sc, OHCI_PHYACCESS, fun);
315272214Skan	for (i = 0; i < MAX_RETRY; i++) {
316103285Sikob		fun = OREAD(sc, OHCI_PHYACCESS);
317103285Sikob		if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0)
318103285Sikob			break;
319109280Ssimokawa		DELAY(100);
320103285Sikob	}
321272214Skan	if (i >= MAX_RETRY) {
322132432Ssimokawa		if (firewire_debug)
323188509Ssbruno			device_printf(sc->fc.dev, "%s: failed(1).\n", __func__);
324108527Ssimokawa		if (++retry < MAX_RETRY) {
325109280Ssimokawa			DELAY(100);
326108527Ssimokawa			goto again;
327108527Ssimokawa		}
328108500Ssimokawa	}
329108500Ssimokawa	/* Make sure that SCLK is started */
330108500Ssimokawa	stat = OREAD(sc, FWOHCI_INTSTAT);
331108500Ssimokawa	if ((stat & OHCI_INT_REG_FAIL) != 0 ||
332108500Ssimokawa			((fun >> PHYDEV_REGADDR) & 0xf) != addr) {
333132432Ssimokawa		if (firewire_debug)
334188509Ssbruno			device_printf(sc->fc.dev, "%s: failed(2).\n", __func__);
335108500Ssimokawa		if (++retry < MAX_RETRY) {
336109280Ssimokawa			DELAY(100);
337108500Ssimokawa			goto again;
338108500Ssimokawa		}
339108500Ssimokawa	}
340188509Ssbruno	if (firewire_debug > 1 || retry >= MAX_RETRY)
341272214Skan		device_printf(sc->fc.dev,
342188509Ssbruno		    "%s:: 0x%x loop=%d, retry=%d\n",
343188509Ssbruno			__func__, addr, i, retry);
344108500Ssimokawa#undef MAX_RETRY
345272214Skan	return ((fun >> PHYDEV_RDDATA) & 0xff);
346103285Sikob}
347272214Skan
348103285Sikob/* Device specific ioctl. */
349103285Sikobint
350130585Sphkfwohci_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
351103285Sikob{
352103285Sikob	struct firewire_softc *sc;
353103285Sikob	struct fwohci_softc *fc;
354103285Sikob	int unit = DEV2UNIT(dev);
355103285Sikob	int err = 0;
356272214Skan	struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data;
357129585Sdfr	uint32_t *dmach = (uint32_t *) data;
358103285Sikob
359103285Sikob	sc = devclass_get_softc(firewire_devclass, unit);
360272214Skan	if (sc == NULL)
361272214Skan		return (EINVAL);
362272214Skan
363103285Sikob	fc = (struct fwohci_softc *)sc->fc;
364103285Sikob
365103285Sikob	if (!data)
366272214Skan		return (EINVAL);
367103285Sikob
368103285Sikob	switch (cmd) {
369103285Sikob	case FWOHCI_WRREG:
370103285Sikob#define OHCI_MAX_REG 0x800
371272214Skan		if (reg->addr <= OHCI_MAX_REG) {
372103285Sikob			OWRITE(fc, reg->addr, reg->data);
373103285Sikob			reg->data = OREAD(fc, reg->addr);
374272214Skan		} else {
375103285Sikob			err = EINVAL;
376103285Sikob		}
377103285Sikob		break;
378103285Sikob	case FWOHCI_RDREG:
379272214Skan		if (reg->addr <= OHCI_MAX_REG) {
380103285Sikob			reg->data = OREAD(fc, reg->addr);
381272214Skan		} else {
382103285Sikob			err = EINVAL;
383103285Sikob		}
384103285Sikob		break;
385103285Sikob/* Read DMA descriptors for debug  */
386103285Sikob	case DUMPDMA:
387272214Skan		if (*dmach <= OHCI_MAX_DMA_CH) {
388103285Sikob			dump_dma(fc, *dmach);
389103285Sikob			dump_db(fc, *dmach);
390272214Skan		} else {
391103285Sikob			err = EINVAL;
392103285Sikob		}
393103285Sikob		break;
394119118Ssimokawa/* Read/Write Phy registers */
395119118Ssimokawa#define OHCI_MAX_PHY_REG 0xf
396119118Ssimokawa	case FWOHCI_RDPHYREG:
397119118Ssimokawa		if (reg->addr <= OHCI_MAX_PHY_REG)
398119118Ssimokawa			reg->data = fwphy_rddata(fc, reg->addr);
399119118Ssimokawa		else
400119118Ssimokawa			err = EINVAL;
401119118Ssimokawa		break;
402119118Ssimokawa	case FWOHCI_WRPHYREG:
403119118Ssimokawa		if (reg->addr <= OHCI_MAX_PHY_REG)
404119118Ssimokawa			reg->data = fwphy_wrdata(fc, reg->addr, reg->data);
405119118Ssimokawa		else
406119118Ssimokawa			err = EINVAL;
407119118Ssimokawa		break;
408103285Sikob	default:
409119118Ssimokawa		err = EINVAL;
410103285Sikob		break;
411103285Sikob	}
412103285Sikob	return err;
413103285Sikob}
414106790Ssimokawa
415108530Ssimokawastatic int
416108530Ssimokawafwohci_probe_phy(struct fwohci_softc *sc, device_t dev)
417103285Sikob{
418129585Sdfr	uint32_t reg, reg2;
419108530Ssimokawa	int e1394a = 1;
420272214Skan
421272214Skan	/*
422272214Skan	 * probe PHY parameters
423272214Skan	 * 0. to prove PHY version, whether compliance of 1394a.
424272214Skan	 * 1. to probe maximum speed supported by the PHY and
425272214Skan	 *    number of port supported by core-logic.
426272214Skan	 *    It is not actually available port on your PC .
427272214Skan	 */
428108530Ssimokawa	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
429167685Ssimokawa	DELAY(500);
430167685Ssimokawa
431108530Ssimokawa	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
432108530Ssimokawa
433272214Skan	if ((reg >> 5) != 7) {
434108530Ssimokawa		sc->fc.mode &= ~FWPHYASYST;
435108530Ssimokawa		sc->fc.nport = reg & FW_PHY_NP;
436108530Ssimokawa		sc->fc.speed = reg & FW_PHY_SPD >> 6;
437108530Ssimokawa		if (sc->fc.speed > MAX_SPEED) {
438108530Ssimokawa			device_printf(dev, "invalid speed %d (fixed to %d).\n",
439108530Ssimokawa				sc->fc.speed, MAX_SPEED);
440108530Ssimokawa			sc->fc.speed = MAX_SPEED;
441108530Ssimokawa		}
442108530Ssimokawa		device_printf(dev,
443108701Ssimokawa			"Phy 1394 only %s, %d ports.\n",
444108701Ssimokawa			linkspeed[sc->fc.speed], sc->fc.nport);
445272214Skan	} else {
446108530Ssimokawa		reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG);
447108530Ssimokawa		sc->fc.mode |= FWPHYASYST;
448108530Ssimokawa		sc->fc.nport = reg & FW_PHY_NP;
449108530Ssimokawa		sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5;
450108530Ssimokawa		if (sc->fc.speed > MAX_SPEED) {
451108530Ssimokawa			device_printf(dev, "invalid speed %d (fixed to %d).\n",
452108530Ssimokawa				sc->fc.speed, MAX_SPEED);
453108530Ssimokawa			sc->fc.speed = MAX_SPEED;
454108530Ssimokawa		}
455108530Ssimokawa		device_printf(dev,
456108701Ssimokawa			"Phy 1394a available %s, %d ports.\n",
457108701Ssimokawa			linkspeed[sc->fc.speed], sc->fc.nport);
458108530Ssimokawa
459108530Ssimokawa		/* check programPhyEnable */
460108530Ssimokawa		reg2 = fwphy_rddata(sc, 5);
461108530Ssimokawa#if 0
462108530Ssimokawa		if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) {
463108530Ssimokawa#else	/* XXX force to enable 1394a */
464108530Ssimokawa		if (e1394a) {
465108530Ssimokawa#endif
466132432Ssimokawa			if (firewire_debug)
467108530Ssimokawa				device_printf(dev,
468108530Ssimokawa					"Enable 1394a Enhancements\n");
469108530Ssimokawa			/* enable EAA EMC */
470108530Ssimokawa			reg2 |= 0x03;
471108530Ssimokawa			/* set aPhyEnhanceEnable */
472108530Ssimokawa			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN);
473108530Ssimokawa			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY);
474108530Ssimokawa		} else {
475108530Ssimokawa			/* for safe */
476108530Ssimokawa			reg2 &= ~0x83;
477108530Ssimokawa		}
478108530Ssimokawa		reg2 = fwphy_wrdata(sc, 5, reg2);
479108530Ssimokawa	}
480108530Ssimokawa
481108530Ssimokawa	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
482272214Skan	if ((reg >> 5) == 7) {
483108530Ssimokawa		reg = fwphy_rddata(sc, 4);
484108530Ssimokawa		reg |= 1 << 6;
485108530Ssimokawa		fwphy_wrdata(sc, 4, reg);
486108530Ssimokawa		reg = fwphy_rddata(sc, 4);
487108530Ssimokawa	}
488108530Ssimokawa	return 0;
489108530Ssimokawa}
490108530Ssimokawa
491108530Ssimokawa
492108530Ssimokawavoid
493108530Ssimokawafwohci_reset(struct fwohci_softc *sc, device_t dev)
494108530Ssimokawa{
495108701Ssimokawa	int i, max_rec, speed;
496129585Sdfr	uint32_t reg, reg2;
497103285Sikob	struct fwohcidb_tr *db_tr;
498103285Sikob
499272214Skan	/* Disable interrupts */
500108530Ssimokawa	OWRITE(sc, FWOHCI_INTMASKCLR, ~0);
501108530Ssimokawa
502129541Sdfr	/* Now stopping all DMA channels */
503272214Skan	OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
504272214Skan	OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
505272214Skan	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
506272214Skan	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
507108530Ssimokawa
508272214Skan	OWRITE(sc, OHCI_IR_MASKCLR, ~0);
509272214Skan	for (i = 0; i < sc->fc.nisodma; i++) {
510272214Skan		OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
511272214Skan		OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
512108530Ssimokawa	}
513108530Ssimokawa
514298955Spfg	/* FLUSH FIFO and reset Transmitter/Receiver */
515108530Ssimokawa	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
516132432Ssimokawa	if (firewire_debug)
517108530Ssimokawa		device_printf(dev, "resetting OHCI...");
518108530Ssimokawa	i = 0;
519272214Skan	while (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) {
520108530Ssimokawa		if (i++ > 100) break;
521108530Ssimokawa		DELAY(1000);
522108530Ssimokawa	}
523132432Ssimokawa	if (firewire_debug)
524108530Ssimokawa		printf("done (loop=%d)\n", i);
525108530Ssimokawa
526108701Ssimokawa	/* Probe phy */
527108701Ssimokawa	fwohci_probe_phy(sc, dev);
528108701Ssimokawa
529108701Ssimokawa	/* Probe link */
530272214Skan	reg = OREAD(sc, OHCI_BUS_OPT);
531108530Ssimokawa	reg2 = reg | OHCI_BUSFNC;
532108701Ssimokawa	max_rec = (reg & 0x0000f000) >> 12;
533108701Ssimokawa	speed = (reg & 0x00000007);
534108701Ssimokawa	device_printf(dev, "Link %s, max_rec %d bytes.\n",
535108701Ssimokawa			linkspeed[speed], MAXREC(max_rec));
536108701Ssimokawa	/* XXX fix max_rec */
537108701Ssimokawa	sc->fc.maxrec = sc->fc.speed + 8;
538108701Ssimokawa	if (max_rec != sc->fc.maxrec) {
539108701Ssimokawa		reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12);
540108701Ssimokawa		device_printf(dev, "max_rec %d -> %d\n",
541108701Ssimokawa				MAXREC(max_rec), MAXREC(sc->fc.maxrec));
542108701Ssimokawa	}
543132432Ssimokawa	if (firewire_debug)
544108530Ssimokawa		device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2);
545272214Skan	OWRITE(sc, OHCI_BUS_OPT, reg2);
546108530Ssimokawa
547108701Ssimokawa	/* Initialize registers */
548108530Ssimokawa	OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]);
549113584Ssimokawa	OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr);
550108530Ssimokawa	OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND);
551108530Ssimokawa	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
552113584Ssimokawa	OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
553108530Ssimokawa	OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
554108530Ssimokawa
555108701Ssimokawa	/* Enable link */
556108530Ssimokawa	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN);
557108642Ssimokawa
558108701Ssimokawa	/* Force to start async RX DMA */
559108642Ssimokawa	sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING;
560108642Ssimokawa	sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING;
561108530Ssimokawa	fwohci_rx_enable(sc, &sc->arrq);
562108530Ssimokawa	fwohci_rx_enable(sc, &sc->arrs);
563108530Ssimokawa
564108701Ssimokawa	/* Initialize async TX */
565108701Ssimokawa	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
566108701Ssimokawa	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
567116978Ssimokawa
568108701Ssimokawa	/* AT Retries */
569108701Ssimokawa	OWRITE(sc, FWOHCI_RETRY,
570108701Ssimokawa		/* CycleLimit   PhyRespRetries ATRespRetries ATReqRetries */
571272214Skan		(0xffff << 16) | (0x0f << 8) | (0x0f << 4) | 0x0f);
572116978Ssimokawa
573116978Ssimokawa	sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq);
574116978Ssimokawa	sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq);
575116978Ssimokawa	sc->atrq.bottom = sc->atrq.top;
576116978Ssimokawa	sc->atrs.bottom = sc->atrs.top;
577116978Ssimokawa
578272214Skan	for (i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb;
579272214Skan	    i++, db_tr = STAILQ_NEXT(db_tr, link)) {
580108530Ssimokawa		db_tr->xfer = NULL;
581108530Ssimokawa	}
582272214Skan	for (i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb;
583272214Skan	    i++, db_tr = STAILQ_NEXT(db_tr, link)) {
584108530Ssimokawa		db_tr->xfer = NULL;
585108530Ssimokawa	}
586108530Ssimokawa
587129541Sdfr	/* Enable interrupts */
588170374Ssimokawa	sc->intmask =  (OHCI_INT_ERR  | OHCI_INT_PHY_SID
589272214Skan			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
590108530Ssimokawa			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
591108530Ssimokawa			| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
592170374Ssimokawa	sc->intmask |=  OHCI_INT_DMA_IR | OHCI_INT_DMA_IT;
593170374Ssimokawa	sc->intmask |=	OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT;
594170374Ssimokawa	OWRITE(sc, FWOHCI_INTMASK, sc->intmask);
595108530Ssimokawa	fwohci_set_intr(&sc->fc, 1);
596108530Ssimokawa}
597108530Ssimokawa
598108530Ssimokawaint
599108530Ssimokawafwohci_init(struct fwohci_softc *sc, device_t dev)
600108530Ssimokawa{
601121781Ssimokawa	int i, mver;
602129585Sdfr	uint32_t reg;
603129585Sdfr	uint8_t ui[8];
604108530Ssimokawa
605121781Ssimokawa/* OHCI version */
606103285Sikob	reg = OREAD(sc, OHCI_VERSION);
607121781Ssimokawa	mver = (reg >> 16) & 0xff;
608103285Sikob	device_printf(dev, "OHCI version %x.%x (ROM=%d)\n",
609272214Skan			mver, reg & 0xff, (reg >> 24) & 1);
610121781Ssimokawa	if (mver < 1 || mver > 9) {
611118416Ssimokawa		device_printf(dev, "invalid OHCI version\n");
612118416Ssimokawa		return (ENXIO);
613118416Ssimokawa	}
614118416Ssimokawa
615129541Sdfr/* Available Isochronous DMA channel probe */
616110045Ssimokawa	OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
617110045Ssimokawa	OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
618110045Ssimokawa	reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
619110045Ssimokawa	OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
620110045Ssimokawa	OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
621110045Ssimokawa	for (i = 0; i < 0x20; i++)
622110045Ssimokawa		if ((reg & (1 << i)) == 0)
623110045Ssimokawa			break;
624103285Sikob	sc->fc.nisodma = i;
625129541Sdfr	device_printf(dev, "No. of Isochronous channels is %d.\n", i);
626118820Ssimokawa	if (i == 0)
627118820Ssimokawa		return (ENXIO);
628103285Sikob
629103285Sikob	sc->fc.arq = &sc->arrq.xferq;
630103285Sikob	sc->fc.ars = &sc->arrs.xferq;
631103285Sikob	sc->fc.atq = &sc->atrq.xferq;
632103285Sikob	sc->fc.ats = &sc->atrs.xferq;
633103285Sikob
634113584Ssimokawa	sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
635113584Ssimokawa	sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
636113584Ssimokawa	sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
637113584Ssimokawa	sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
638113584Ssimokawa
639103285Sikob	sc->arrq.xferq.start = NULL;
640103285Sikob	sc->arrs.xferq.start = NULL;
641103285Sikob	sc->atrq.xferq.start = fwohci_start_atq;
642103285Sikob	sc->atrs.xferq.start = fwohci_start_ats;
643103285Sikob
644113584Ssimokawa	sc->arrq.xferq.buf = NULL;
645113584Ssimokawa	sc->arrs.xferq.buf = NULL;
646113584Ssimokawa	sc->atrq.xferq.buf = NULL;
647113584Ssimokawa	sc->atrs.xferq.buf = NULL;
648103285Sikob
649118293Ssimokawa	sc->arrq.xferq.dmach = -1;
650118293Ssimokawa	sc->arrs.xferq.dmach = -1;
651118293Ssimokawa	sc->atrq.xferq.dmach = -1;
652118293Ssimokawa	sc->atrs.xferq.dmach = -1;
653118293Ssimokawa
654103285Sikob	sc->arrq.ndesc = 1;
655103285Sikob	sc->arrs.ndesc = 1;
656110593Ssimokawa	sc->atrq.ndesc = 8;	/* equal to maximum of mbuf chains */
657110593Ssimokawa	sc->atrs.ndesc = 2;
658103285Sikob
659103285Sikob	sc->arrq.ndb = NDB;
660103285Sikob	sc->arrs.ndb = NDB / 2;
661103285Sikob	sc->atrq.ndb = NDB;
662103285Sikob	sc->atrs.ndb = NDB / 2;
663103285Sikob
664272214Skan	for (i = 0; i < sc->fc.nisodma; i++) {
665103285Sikob		sc->fc.it[i] = &sc->it[i].xferq;
666103285Sikob		sc->fc.ir[i] = &sc->ir[i].xferq;
667118293Ssimokawa		sc->it[i].xferq.dmach = i;
668118293Ssimokawa		sc->ir[i].xferq.dmach = i;
669103285Sikob		sc->it[i].ndb = 0;
670103285Sikob		sc->ir[i].ndb = 0;
671103285Sikob	}
672103285Sikob
673103285Sikob	sc->fc.tcode = tinfo;
674113584Ssimokawa	sc->fc.dev = dev;
675103285Sikob
676113584Ssimokawa	sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE,
677219543Smarius	    &sc->crom_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
678272214Skan	if (sc->fc.config_rom == NULL) {
679113584Ssimokawa		device_printf(dev, "config_rom alloc failed.");
680103285Sikob		return ENOMEM;
681103285Sikob	}
682103285Sikob
683116376Ssimokawa#if 0
684116376Ssimokawa	bzero(&sc->fc.config_rom[0], CROMSIZE);
685103285Sikob	sc->fc.config_rom[1] = 0x31333934;
686103285Sikob	sc->fc.config_rom[2] = 0xf000a002;
687103285Sikob	sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
688103285Sikob	sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO);
689103285Sikob	sc->fc.config_rom[5] = 0;
690103285Sikob	sc->fc.config_rom[0] = (4 << 24) | (5 << 16);
691103285Sikob
692103285Sikob	sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4);
693113584Ssimokawa#endif
694103285Sikob
695298955Spfg/* SID receive buffer must align 2^11 */
696103285Sikob#define	OHCI_SIDSIZE	(1 << 11)
697113584Ssimokawa	sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE,
698219543Smarius	    &sc->sid_dma, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
699113584Ssimokawa	if (sc->sid_buf == NULL) {
700113584Ssimokawa		device_printf(dev, "sid_buf alloc failed.");
701108527Ssimokawa		return ENOMEM;
702108527Ssimokawa	}
703113584Ssimokawa
704129585Sdfr	fwdma_malloc(&sc->fc, sizeof(uint32_t), sizeof(uint32_t),
705272214Skan	    &sc->dummy_dma, BUS_DMA_WAITOK);
706113584Ssimokawa
707113584Ssimokawa	if (sc->dummy_dma.v_addr == NULL) {
708113584Ssimokawa		device_printf(dev, "dummy_dma alloc failed.");
709109736Ssimokawa		return ENOMEM;
710109736Ssimokawa	}
711113584Ssimokawa
712113584Ssimokawa	fwohci_db_init(sc, &sc->arrq);
713108527Ssimokawa	if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0)
714108527Ssimokawa		return ENOMEM;
715108527Ssimokawa
716113584Ssimokawa	fwohci_db_init(sc, &sc->arrs);
717108527Ssimokawa	if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0)
718108527Ssimokawa		return ENOMEM;
719103285Sikob
720113584Ssimokawa	fwohci_db_init(sc, &sc->atrq);
721108527Ssimokawa	if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0)
722108527Ssimokawa		return ENOMEM;
723108527Ssimokawa
724113584Ssimokawa	fwohci_db_init(sc, &sc->atrs);
725108527Ssimokawa	if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0)
726108527Ssimokawa		return ENOMEM;
727103285Sikob
728109814Ssimokawa	sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H);
729109814Ssimokawa	sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L);
730272214Skan	for (i = 0; i < 8; i++)
731109814Ssimokawa		ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i);
732103285Sikob	device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
733109814Ssimokawa		ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]);
734109814Ssimokawa
735103285Sikob	sc->fc.ioctl = fwohci_ioctl;
736103285Sikob	sc->fc.cyctimer = fwohci_cyctimer;
737103285Sikob	sc->fc.set_bmr = fwohci_set_bus_manager;
738103285Sikob	sc->fc.ibr = fwohci_ibr;
739103285Sikob	sc->fc.irx_enable = fwohci_irx_enable;
740103285Sikob	sc->fc.irx_disable = fwohci_irx_disable;
741103285Sikob
742103285Sikob	sc->fc.itx_enable = fwohci_itxbuf_enable;
743103285Sikob	sc->fc.itx_disable = fwohci_itx_disable;
744113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
745103285Sikob	sc->fc.irx_post = fwohci_irx_post;
746113584Ssimokawa#else
747113584Ssimokawa	sc->fc.irx_post = NULL;
748113584Ssimokawa#endif
749103285Sikob	sc->fc.itx_post = NULL;
750103285Sikob	sc->fc.timeout = fwohci_timeout;
751103285Sikob	sc->fc.poll = fwohci_poll;
752103285Sikob	sc->fc.set_intr = fwohci_set_intr;
753106790Ssimokawa
754113584Ssimokawa	sc->intmask = sc->irstat = sc->itstat = 0;
755113584Ssimokawa
756170374Ssimokawa	/* Init task queue */
757170374Ssimokawa	sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK,
758170374Ssimokawa		taskqueue_thread_enqueue, &sc->fc.taskqueue);
759170374Ssimokawa	taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq",
760272214Skan		device_get_unit(dev));
761170374Ssimokawa	TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc);
762170374Ssimokawa	TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc);
763170374Ssimokawa	TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc);
764170374Ssimokawa
765108530Ssimokawa	fw_init(&sc->fc);
766108530Ssimokawa	fwohci_reset(sc, dev);
767103285Sikob
768108530Ssimokawa	return 0;
769103285Sikob}
770106790Ssimokawa
771106790Ssimokawavoid
772106790Ssimokawafwohci_timeout(void *arg)
773103285Sikob{
774103285Sikob	struct fwohci_softc *sc;
775103285Sikob
776103285Sikob	sc = (struct fwohci_softc *)arg;
777103285Sikob}
778106790Ssimokawa
779129585Sdfruint32_t
780106790Ssimokawafwohci_cyctimer(struct firewire_comm *fc)
781103285Sikob{
782103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
783272214Skan	return (OREAD(sc, OHCI_CYCLETIMER));
784103285Sikob}
785103285Sikob
786108527Ssimokawaint
787108527Ssimokawafwohci_detach(struct fwohci_softc *sc, device_t dev)
788108527Ssimokawa{
789108527Ssimokawa	int i;
790108527Ssimokawa
791113584Ssimokawa	if (sc->sid_buf != NULL)
792113584Ssimokawa		fwdma_free(&sc->fc, &sc->sid_dma);
793113584Ssimokawa	if (sc->fc.config_rom != NULL)
794113584Ssimokawa		fwdma_free(&sc->fc, &sc->crom_dma);
795108527Ssimokawa
796108527Ssimokawa	fwohci_db_free(&sc->arrq);
797108527Ssimokawa	fwohci_db_free(&sc->arrs);
798108527Ssimokawa
799108527Ssimokawa	fwohci_db_free(&sc->atrq);
800108527Ssimokawa	fwohci_db_free(&sc->atrs);
801108527Ssimokawa
802272214Skan	for (i = 0; i < sc->fc.nisodma; i++) {
803108527Ssimokawa		fwohci_db_free(&sc->it[i]);
804108527Ssimokawa		fwohci_db_free(&sc->ir[i]);
805108527Ssimokawa	}
806170374Ssimokawa	if (sc->fc.taskqueue != NULL) {
807170374Ssimokawa		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset);
808170374Ssimokawa		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid);
809170374Ssimokawa		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma);
810170374Ssimokawa		taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout);
811170374Ssimokawa		taskqueue_free(sc->fc.taskqueue);
812170374Ssimokawa		sc->fc.taskqueue = NULL;
813170374Ssimokawa	}
814108527Ssimokawa
815108527Ssimokawa	return 0;
816108527Ssimokawa}
817108527Ssimokawa
818108655Ssimokawa#define LAST_DB(dbtr, db) do {						\
819108655Ssimokawa	struct fwohcidb_tr *_dbtr = (dbtr);				\
820108655Ssimokawa	int _cnt = _dbtr->dbcnt;					\
821108655Ssimokawa	db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0];			\
822108655Ssimokawa} while (0)
823272214Skan
824106790Ssimokawastatic void
825113584Ssimokawafwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error)
826113584Ssimokawa{
827113584Ssimokawa	struct fwohcidb_tr *db_tr;
828120660Ssimokawa	struct fwohcidb *db;
829113584Ssimokawa	bus_dma_segment_t *s;
830113584Ssimokawa	int i;
831113584Ssimokawa
832113584Ssimokawa	db_tr = (struct fwohcidb_tr *)arg;
833113584Ssimokawa	db = &db_tr->db[db_tr->dbcnt];
834113584Ssimokawa	if (error) {
835113584Ssimokawa		if (firewire_debug || error != EFBIG)
836113584Ssimokawa			printf("fwohci_execute_db: error=%d\n", error);
837113584Ssimokawa		return;
838113584Ssimokawa	}
839113584Ssimokawa	for (i = 0; i < nseg; i++) {
840113584Ssimokawa		s = &segs[i];
841113584Ssimokawa		FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr);
842113584Ssimokawa		FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len);
843113584Ssimokawa 		FWOHCI_DMA_WRITE(db->db.desc.res, 0);
844113584Ssimokawa		db++;
845113584Ssimokawa		db_tr->dbcnt++;
846113584Ssimokawa	}
847113584Ssimokawa}
848113584Ssimokawa
849113584Ssimokawastatic void
850113584Ssimokawafwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg,
851272214Skan    bus_size_t size, int error)
852113584Ssimokawa{
853113584Ssimokawa	fwohci_execute_db(arg, segs, nseg, error);
854113584Ssimokawa}
855113584Ssimokawa
856113584Ssimokawastatic void
857106790Ssimokawafwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
858103285Sikob{
859277511Swill	int i;
860120660Ssimokawa	int tcode, hdr_len, pl_off;
861103285Sikob	int fsegment = -1;
862129585Sdfr	uint32_t off;
863103285Sikob	struct fw_xfer *xfer;
864103285Sikob	struct fw_pkt *fp;
865120660Ssimokawa	struct fwohci_txpkthdr *ohcifp;
866103285Sikob	struct fwohcidb_tr *db_tr;
867120660Ssimokawa	struct fwohcidb *db;
868129585Sdfr	uint32_t *ld;
869103285Sikob	struct tcode_info *info;
870108655Ssimokawa	static int maxdesc=0;
871103285Sikob
872170374Ssimokawa	FW_GLOCK_ASSERT(&sc->fc);
873170374Ssimokawa
874272214Skan	if (&sc->atrq == dbch) {
875103285Sikob		off = OHCI_ATQOFF;
876272214Skan	} else if (&sc->atrs == dbch) {
877103285Sikob		off = OHCI_ATSOFF;
878272214Skan	} else {
879103285Sikob		return;
880103285Sikob	}
881103285Sikob
882103285Sikob	if (dbch->flags & FWOHCI_DBCH_FULL)
883103285Sikob		return;
884103285Sikob
885103285Sikob	db_tr = dbch->top;
886103285Sikobtxloop:
887103285Sikob	xfer = STAILQ_FIRST(&dbch->xferq.q);
888272214Skan	if (xfer == NULL) {
889103285Sikob		goto kick;
890103285Sikob	}
891170374Ssimokawa#if 0
892272214Skan	if (dbch->xferq.queued == 0) {
893103285Sikob		device_printf(sc->fc.dev, "TX queue empty\n");
894103285Sikob	}
895170374Ssimokawa#endif
896103285Sikob	STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
897103285Sikob	db_tr->xfer = xfer;
898170374Ssimokawa	xfer->flag = FWXF_START;
899103285Sikob
900120660Ssimokawa	fp = &xfer->send.hdr;
901103285Sikob	tcode = fp->mode.common.tcode;
902103285Sikob
903120660Ssimokawa	ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
904103285Sikob	info = &tinfo[tcode];
905113584Ssimokawa	hdr_len = pl_off = info->hdr_len;
906119155Ssimokawa
907119155Ssimokawa	ld = &ohcifp->mode.ld[0];
908119155Ssimokawa	ld[0] = ld[1] = ld[2] = ld[3] = 0;
909272214Skan	for (i = 0; i < pl_off; i+= 4)
910119155Ssimokawa		ld[i/4] = fp->mode.ld[i/4];
911119155Ssimokawa
912120660Ssimokawa	ohcifp->mode.common.spd = xfer->send.spd & 0x7;
913272214Skan	if (tcode == FWTCODE_STREAM) {
914103285Sikob		hdr_len = 8;
915113584Ssimokawa		ohcifp->mode.stream.len = fp->mode.stream.len;
916103285Sikob	} else if (tcode == FWTCODE_PHY) {
917103285Sikob		hdr_len = 12;
918119155Ssimokawa		ld[1] = fp->mode.ld[1];
919119155Ssimokawa		ld[2] = fp->mode.ld[2];
920103285Sikob		ohcifp->mode.common.spd = 0;
921103285Sikob		ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
922103285Sikob	} else {
923113584Ssimokawa		ohcifp->mode.asycomm.dst = fp->mode.hdr.dst;
924103285Sikob		ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS;
925103285Sikob		ohcifp->mode.asycomm.tlrt |= FWRETRY_X;
926103285Sikob	}
927103285Sikob	db = &db_tr->db[0];
928113584Ssimokawa 	FWOHCI_DMA_WRITE(db->db.desc.cmd,
929113584Ssimokawa			OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
930119155Ssimokawa 	FWOHCI_DMA_WRITE(db->db.desc.addr, 0);
931113584Ssimokawa 	FWOHCI_DMA_WRITE(db->db.desc.res, 0);
932298955Spfg/* Specify bound timer of asy. response */
933272214Skan	if (&sc->atrs == dbch) {
934113584Ssimokawa 		FWOHCI_DMA_WRITE(db->db.desc.res,
935113584Ssimokawa			 (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13));
936103285Sikob	}
937113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
938113584Ssimokawa	if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
939113584Ssimokawa		hdr_len = 12;
940272214Skan	for (i = 0; i < hdr_len/4; i++)
941119155Ssimokawa		FWOHCI_DMA_WRITE(ld[i], ld[i]);
942113584Ssimokawa#endif
943103285Sikob
944111942Ssimokawaagain:
945103285Sikob	db_tr->dbcnt = 2;
946103285Sikob	db = &db_tr->db[db_tr->dbcnt];
947120660Ssimokawa	if (xfer->send.pay_len > 0) {
948113584Ssimokawa		int err;
949113584Ssimokawa		/* handle payload */
950103285Sikob		if (xfer->mbuf == NULL) {
951113584Ssimokawa			err = bus_dmamap_load(dbch->dmat, db_tr->dma_map,
952120660Ssimokawa				&xfer->send.payload[0], xfer->send.pay_len,
953113584Ssimokawa				fwohci_execute_db, db_tr,
954113584Ssimokawa				/*flags*/0);
955103285Sikob		} else {
956111942Ssimokawa			/* XXX we can handle only 6 (=8-2) mbuf chains */
957113584Ssimokawa			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
958113584Ssimokawa				xfer->mbuf,
959113584Ssimokawa				fwohci_execute_db2, db_tr,
960113584Ssimokawa				/* flags */0);
961113584Ssimokawa			if (err == EFBIG) {
962113584Ssimokawa				struct mbuf *m0;
963113584Ssimokawa
964113584Ssimokawa				if (firewire_debug)
965113584Ssimokawa					device_printf(sc->fc.dev, "EFBIG.\n");
966243857Sglebius				m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
967113584Ssimokawa				if (m0 != NULL) {
968111942Ssimokawa					m_copydata(xfer->mbuf, 0,
969111942Ssimokawa						xfer->mbuf->m_pkthdr.len,
970113584Ssimokawa						mtod(m0, caddr_t));
971272214Skan					m0->m_len = m0->m_pkthdr.len =
972111942Ssimokawa						xfer->mbuf->m_pkthdr.len;
973111942Ssimokawa					m_freem(xfer->mbuf);
974113584Ssimokawa					xfer->mbuf = m0;
975111942Ssimokawa					goto again;
976111942Ssimokawa				}
977111942Ssimokawa				device_printf(sc->fc.dev, "m_getcl failed.\n");
978111942Ssimokawa			}
979103285Sikob		}
980113584Ssimokawa		if (err)
981113584Ssimokawa			printf("dmamap_load: err=%d\n", err);
982113584Ssimokawa		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
983113584Ssimokawa						BUS_DMASYNC_PREWRITE);
984113584Ssimokawa#if 0 /* OHCI_OUTPUT_MODE == 0 */
985113584Ssimokawa		for (i = 2; i < db_tr->dbcnt; i++)
986113584Ssimokawa			FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd,
987113584Ssimokawa						OHCI_OUTPUT_MORE);
988113584Ssimokawa#endif
989103285Sikob	}
990108655Ssimokawa	if (maxdesc < db_tr->dbcnt) {
991108655Ssimokawa		maxdesc = db_tr->dbcnt;
992132432Ssimokawa		if (firewire_debug)
993187993Ssbruno			device_printf(sc->fc.dev, "%s: maxdesc %d\n", __func__, maxdesc);
994108655Ssimokawa	}
995103285Sikob	/* last db */
996103285Sikob	LAST_DB(db_tr, db);
997113584Ssimokawa 	FWOHCI_DMA_SET(db->db.desc.cmd,
998113584Ssimokawa		OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
999113584Ssimokawa 	FWOHCI_DMA_WRITE(db->db.desc.depend,
1000113584Ssimokawa			STAILQ_NEXT(db_tr, link)->bus_addr);
1001103285Sikob
1002272214Skan	if (fsegment == -1)
1003103285Sikob		fsegment = db_tr->dbcnt;
1004103285Sikob	if (dbch->pdb_tr != NULL) {
1005103285Sikob		LAST_DB(dbch->pdb_tr, db);
1006113584Ssimokawa 		FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
1007103285Sikob	}
1008272214Skan	dbch->xferq.queued++;
1009103285Sikob	dbch->pdb_tr = db_tr;
1010103285Sikob	db_tr = STAILQ_NEXT(db_tr, link);
1011272214Skan	if (db_tr != dbch->bottom) {
1012103285Sikob		goto txloop;
1013103285Sikob	} else {
1014107653Ssimokawa		device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n");
1015103285Sikob		dbch->flags |= FWOHCI_DBCH_FULL;
1016103285Sikob	}
1017103285Sikobkick:
1018103285Sikob	/* kick asy q */
1019113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1020113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1021103285Sikob
1022272214Skan	if (dbch->xferq.flag & FWXFERQ_RUNNING) {
1023103285Sikob		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
1024103285Sikob	} else {
1025132432Ssimokawa		if (firewire_debug)
1026107653Ssimokawa			device_printf(sc->fc.dev, "start AT DMA status=%x\n",
1027103285Sikob					OREAD(sc, OHCI_DMACTL(off)));
1028113584Ssimokawa		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment);
1029103285Sikob		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
1030103285Sikob		dbch->xferq.flag |= FWXFERQ_RUNNING;
1031103285Sikob	}
1032106790Ssimokawa
1033103285Sikob	dbch->top = db_tr;
1034103285Sikob	return;
1035103285Sikob}
1036106790Ssimokawa
1037106790Ssimokawastatic void
1038106790Ssimokawafwohci_start_atq(struct firewire_comm *fc)
1039103285Sikob{
1040103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1041170374Ssimokawa	FW_GLOCK(&sc->fc);
1042272214Skan	fwohci_start(sc, &(sc->atrq));
1043170374Ssimokawa	FW_GUNLOCK(&sc->fc);
1044103285Sikob	return;
1045103285Sikob}
1046106790Ssimokawa
1047106790Ssimokawastatic void
1048106790Ssimokawafwohci_start_ats(struct firewire_comm *fc)
1049103285Sikob{
1050103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1051170374Ssimokawa	FW_GLOCK(&sc->fc);
1052272214Skan	fwohci_start(sc, &(sc->atrs));
1053170374Ssimokawa	FW_GUNLOCK(&sc->fc);
1054103285Sikob	return;
1055103285Sikob}
1056106790Ssimokawa
1057106790Ssimokawavoid
1058106790Ssimokawafwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1059103285Sikob{
1060113584Ssimokawa	int s, ch, err = 0;
1061103285Sikob	struct fwohcidb_tr *tr;
1062120660Ssimokawa	struct fwohcidb *db;
1063103285Sikob	struct fw_xfer *xfer;
1064129585Sdfr	uint32_t off;
1065113584Ssimokawa	u_int stat, status;
1066103285Sikob	int	packets;
1067103285Sikob	struct firewire_comm *fc = (struct firewire_comm *)sc;
1068113584Ssimokawa
1069272214Skan	if (&sc->atrq == dbch) {
1070103285Sikob		off = OHCI_ATQOFF;
1071113584Ssimokawa		ch = ATRQ_CH;
1072272214Skan	} else if (&sc->atrs == dbch) {
1073103285Sikob		off = OHCI_ATSOFF;
1074113584Ssimokawa		ch = ATRS_CH;
1075272214Skan	} else {
1076103285Sikob		return;
1077103285Sikob	}
1078103285Sikob	s = splfw();
1079103285Sikob	tr = dbch->bottom;
1080103285Sikob	packets = 0;
1081113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
1082113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
1083272214Skan	while (dbch->xferq.queued > 0) {
1084103285Sikob		LAST_DB(tr, db);
1085113584Ssimokawa		status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
1086272214Skan		if (!(status & OHCI_CNTL_DMA_ACTIVE)) {
1087272214Skan			if (fc->status != FWBUSINIT)
1088103285Sikob				/* maybe out of order?? */
1089103285Sikob				goto out;
1090103285Sikob		}
1091113584Ssimokawa		bus_dmamap_sync(dbch->dmat, tr->dma_map,
1092113584Ssimokawa			BUS_DMASYNC_POSTWRITE);
1093113584Ssimokawa		bus_dmamap_unload(dbch->dmat, tr->dma_map);
1094119155Ssimokawa#if 1
1095167629Ssimokawa		if (firewire_debug > 1)
1096119155Ssimokawa			dump_db(sc, ch);
1097103285Sikob#endif
1098272214Skan		if (status & OHCI_CNTL_DMA_DEAD) {
1099113584Ssimokawa			/* Stop DMA */
1100103285Sikob			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
1101103285Sikob			device_printf(sc->fc.dev, "force reset AT FIFO\n");
1102103285Sikob			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN);
1103103285Sikob			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN);
1104103285Sikob			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
1105103285Sikob		}
1106113584Ssimokawa		stat = status & FWOHCIEV_MASK;
1107272214Skan		switch (stat) {
1108110577Ssimokawa		case FWOHCIEV_ACKPEND:
1109103285Sikob		case FWOHCIEV_ACKCOMPL:
1110103285Sikob			err = 0;
1111103285Sikob			break;
1112103285Sikob		case FWOHCIEV_ACKBSA:
1113103285Sikob		case FWOHCIEV_ACKBSB:
1114110577Ssimokawa		case FWOHCIEV_ACKBSX:
1115103285Sikob			err = EBUSY;
1116103285Sikob			break;
1117103285Sikob		case FWOHCIEV_FLUSHED:
1118103285Sikob		case FWOHCIEV_ACKTARD:
1119103285Sikob			err = EAGAIN;
1120103285Sikob			break;
1121103285Sikob		case FWOHCIEV_MISSACK:
1122103285Sikob		case FWOHCIEV_UNDRRUN:
1123103285Sikob		case FWOHCIEV_OVRRUN:
1124103285Sikob		case FWOHCIEV_DESCERR:
1125103285Sikob		case FWOHCIEV_DTRDERR:
1126103285Sikob		case FWOHCIEV_TIMEOUT:
1127103285Sikob		case FWOHCIEV_TCODERR:
1128103285Sikob		case FWOHCIEV_UNKNOWN:
1129103285Sikob		case FWOHCIEV_ACKDERR:
1130103285Sikob		case FWOHCIEV_ACKTERR:
1131103285Sikob		default:
1132103285Sikob			err = EINVAL;
1133103285Sikob			break;
1134103285Sikob		}
1135110577Ssimokawa		if (tr->xfer != NULL) {
1136103285Sikob			xfer = tr->xfer;
1137170374Ssimokawa			if (xfer->flag & FWXF_RCVD) {
1138119289Ssimokawa#if 0
1139113584Ssimokawa				if (firewire_debug)
1140113584Ssimokawa					printf("already rcvd\n");
1141119289Ssimokawa#endif
1142113584Ssimokawa				fw_xfer_done(xfer);
1143113584Ssimokawa			} else {
1144170427Ssimokawa				microtime(&xfer->tv);
1145170374Ssimokawa				xfer->flag = FWXF_SENT;
1146170425Ssimokawa				if (err == EBUSY) {
1147170374Ssimokawa					xfer->flag = FWXF_BUSY;
1148114218Ssimokawa					xfer->resp = err;
1149167630Ssimokawa					xfer->recv.pay_len = 0;
1150167630Ssimokawa					fw_xfer_done(xfer);
1151114218Ssimokawa				} else if (stat != FWOHCIEV_ACKPEND) {
1152114218Ssimokawa					if (stat != FWOHCIEV_ACKCOMPL)
1153170374Ssimokawa						xfer->flag = FWXF_SENTERR;
1154114218Ssimokawa					xfer->resp = err;
1155120660Ssimokawa					xfer->recv.pay_len = 0;
1156113584Ssimokawa					fw_xfer_done(xfer);
1157114218Ssimokawa				}
1158103285Sikob			}
1159110577Ssimokawa			/*
1160110577Ssimokawa			 * The watchdog timer takes care of split
1161272214Skan			 * transaction timeout for ACKPEND case.
1162110577Ssimokawa			 */
1163113584Ssimokawa		} else {
1164113584Ssimokawa			printf("this shouldn't happen\n");
1165103285Sikob		}
1166170374Ssimokawa		FW_GLOCK(fc);
1167272214Skan		dbch->xferq.queued--;
1168170374Ssimokawa		FW_GUNLOCK(fc);
1169103285Sikob		tr->xfer = NULL;
1170103285Sikob
1171272214Skan		packets++;
1172103285Sikob		tr = STAILQ_NEXT(tr, link);
1173103285Sikob		dbch->bottom = tr;
1174111956Ssimokawa		if (dbch->bottom == dbch->top) {
1175111956Ssimokawa			/* we reaches the end of context program */
1176111956Ssimokawa			if (firewire_debug && dbch->xferq.queued > 0)
1177111956Ssimokawa				printf("queued > 0\n");
1178111956Ssimokawa			break;
1179111956Ssimokawa		}
1180103285Sikob	}
1181103285Sikobout:
1182103285Sikob	if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
1183103285Sikob		printf("make free slot\n");
1184103285Sikob		dbch->flags &= ~FWOHCI_DBCH_FULL;
1185170374Ssimokawa		FW_GLOCK(fc);
1186103285Sikob		fwohci_start(sc, dbch);
1187170374Ssimokawa		FW_GUNLOCK(fc);
1188103285Sikob	}
1189103285Sikob	splx(s);
1190103285Sikob}
1191106790Ssimokawa
1192106790Ssimokawastatic void
1193106790Ssimokawafwohci_db_free(struct fwohci_dbch *dbch)
1194103285Sikob{
1195103285Sikob	struct fwohcidb_tr *db_tr;
1196113584Ssimokawa	int idb;
1197103285Sikob
1198108527Ssimokawa	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1199108527Ssimokawa		return;
1200108527Ssimokawa
1201272214Skan	for (db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb;
1202272214Skan	    db_tr = STAILQ_NEXT(db_tr, link), idb++) {
1203113584Ssimokawa		if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 &&
1204272214Skan		    db_tr->buf != NULL) {
1205113584Ssimokawa			fwdma_free_size(dbch->dmat, db_tr->dma_map,
1206113584Ssimokawa					db_tr->buf, dbch->xferq.psize);
1207113584Ssimokawa			db_tr->buf = NULL;
1208113584Ssimokawa		} else if (db_tr->dma_map != NULL)
1209113584Ssimokawa			bus_dmamap_destroy(dbch->dmat, db_tr->dma_map);
1210103285Sikob	}
1211103285Sikob	dbch->ndb = 0;
1212103285Sikob	db_tr = STAILQ_FIRST(&dbch->db_trq);
1213113584Ssimokawa	fwdma_free_multiseg(dbch->am);
1214110195Ssimokawa	free(db_tr, M_FW);
1215103285Sikob	STAILQ_INIT(&dbch->db_trq);
1216108527Ssimokawa	dbch->flags &= ~FWOHCI_DBCH_INIT;
1217103285Sikob}
1218106790Ssimokawa
1219106790Ssimokawastatic void
1220113584Ssimokawafwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1221103285Sikob{
1222103285Sikob	int	idb;
1223103285Sikob	struct fwohcidb_tr *db_tr;
1224108642Ssimokawa
1225108642Ssimokawa	if ((dbch->flags & FWOHCI_DBCH_INIT) != 0)
1226108642Ssimokawa		goto out;
1227108642Ssimokawa
1228113584Ssimokawa	/* create dma_tag for buffers */
1229113584Ssimokawa#define MAX_REQCOUNT	0xffff
1230113584Ssimokawa	if (bus_dma_tag_create(/*parent*/ sc->fc.dmat,
1231113584Ssimokawa			/*alignment*/ 1, /*boundary*/ 0,
1232113584Ssimokawa			/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
1233113584Ssimokawa			/*highaddr*/ BUS_SPACE_MAXADDR,
1234113584Ssimokawa			/*filter*/NULL, /*filterarg*/NULL,
1235113584Ssimokawa			/*maxsize*/ dbch->xferq.psize,
1236113584Ssimokawa			/*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1,
1237113584Ssimokawa			/*maxsegsz*/ MAX_REQCOUNT,
1238117126Sscottl			/*flags*/ 0,
1239117126Sscottl			/*lockfunc*/busdma_lock_mutex,
1240170374Ssimokawa			/*lockarg*/FW_GMTX(&sc->fc),
1241117228Ssimokawa			&dbch->dmat))
1242113584Ssimokawa		return;
1243113584Ssimokawa
1244103285Sikob	/* allocate DB entries and attach one to each DMA channels */
1245103285Sikob	/* DB entry must start at 16 bytes bounary. */
1246103285Sikob	STAILQ_INIT(&dbch->db_trq);
1247103285Sikob	db_tr = (struct fwohcidb_tr *)
1248103285Sikob		malloc(sizeof(struct fwohcidb_tr) * dbch->ndb,
1249113584Ssimokawa		M_FW, M_WAITOK | M_ZERO);
1250109379Ssimokawa
1251113584Ssimokawa#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc)
1252272215Skan	dbch->am = fwdma_malloc_multiseg(&sc->fc, sizeof(struct fwohcidb),
1253113584Ssimokawa		DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK);
1254113584Ssimokawa	if (dbch->am == NULL) {
1255113584Ssimokawa		printf("fwohci_db_init: fwdma_malloc_multiseg failed\n");
1256124836Ssimokawa		free(db_tr, M_FW);
1257103285Sikob		return;
1258103285Sikob	}
1259103285Sikob	/* Attach DB to DMA ch. */
1260272214Skan	for (idb = 0; idb < dbch->ndb; idb++) {
1261103285Sikob		db_tr->dbcnt = 0;
1262113584Ssimokawa		db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb);
1263113584Ssimokawa		db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb);
1264113584Ssimokawa		/* create dmamap for buffers */
1265113584Ssimokawa		/* XXX do we need 4bytes alignment tag? */
1266113584Ssimokawa		/* XXX don't alloc dma_map for AR */
1267113584Ssimokawa		if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) {
1268113584Ssimokawa			printf("bus_dmamap_create failed\n");
1269113584Ssimokawa			dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
1270113584Ssimokawa			fwohci_db_free(dbch);
1271113584Ssimokawa			return;
1272113584Ssimokawa		}
1273103285Sikob		STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link);
1274113584Ssimokawa		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1275108530Ssimokawa			if (idb % dbch->xferq.bnpacket == 0)
1276108530Ssimokawa				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1277108530Ssimokawa						].start = (caddr_t)db_tr;
1278108530Ssimokawa			if ((idb + 1) % dbch->xferq.bnpacket == 0)
1279108530Ssimokawa				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1280108530Ssimokawa						].end = (caddr_t)db_tr;
1281103285Sikob		}
1282103285Sikob		db_tr++;
1283103285Sikob	}
1284103285Sikob	STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next
1285103285Sikob			= STAILQ_FIRST(&dbch->db_trq);
1286108642Ssimokawaout:
1287108642Ssimokawa	dbch->xferq.queued = 0;
1288108642Ssimokawa	dbch->pdb_tr = NULL;
1289103285Sikob	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1290103285Sikob	dbch->bottom = dbch->top;
1291108527Ssimokawa	dbch->flags = FWOHCI_DBCH_INIT;
1292103285Sikob}
1293106790Ssimokawa
1294106790Ssimokawastatic int
1295106790Ssimokawafwohci_itx_disable(struct firewire_comm *fc, int dmach)
1296103285Sikob{
1297103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1298109890Ssimokawa
1299272214Skan	OWRITE(sc, OHCI_ITCTLCLR(dmach),
1300113584Ssimokawa			OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
1301103285Sikob	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
1302103285Sikob	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
1303109890Ssimokawa	/* XXX we cannot free buffers until the DMA really stops */
1304167086Sjhb	pause("fwitxd", hz);
1305103285Sikob	fwohci_db_free(&sc->it[dmach]);
1306103285Sikob	sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
1307103285Sikob	return 0;
1308103285Sikob}
1309106790Ssimokawa
1310106790Ssimokawastatic int
1311106790Ssimokawafwohci_irx_disable(struct firewire_comm *fc, int dmach)
1312103285Sikob{
1313103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1314103285Sikob
1315103285Sikob	OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1316103285Sikob	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
1317103285Sikob	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
1318109890Ssimokawa	/* XXX we cannot free buffers until the DMA really stops */
1319167086Sjhb	pause("fwirxd", hz);
1320103285Sikob	fwohci_db_free(&sc->ir[dmach]);
1321103285Sikob	sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
1322103285Sikob	return 0;
1323103285Sikob}
1324106790Ssimokawa
1325113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
1326106790Ssimokawastatic void
1327129585Sdfrfwohci_irx_post (struct firewire_comm *fc , uint32_t *qld)
1328103285Sikob{
1329113584Ssimokawa	qld[0] = FWOHCI_DMA_READ(qld[0]);
1330103285Sikob	return;
1331103285Sikob}
1332103285Sikob#endif
1333103285Sikob
1334106790Ssimokawastatic int
1335106790Ssimokawafwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1336103285Sikob{
1337103285Sikob	int err = 0;
1338113584Ssimokawa	int idb, z, i, dmach = 0, ldesc;
1339129585Sdfr	uint32_t off = 0;
1340103285Sikob	struct fwohcidb_tr *db_tr;
1341120660Ssimokawa	struct fwohcidb *db;
1342103285Sikob
1343272214Skan	if (!(dbch->xferq.flag & FWXFERQ_EXTBUF)) {
1344103285Sikob		err = EINVAL;
1345103285Sikob		return err;
1346103285Sikob	}
1347103285Sikob	z = dbch->ndesc;
1348272214Skan	for (dmach = 0; dmach < sc->fc.nisodma; dmach++) {
1349272214Skan		if (&sc->it[dmach] == dbch) {
1350103285Sikob			off = OHCI_ITOFF(dmach);
1351103285Sikob			break;
1352103285Sikob		}
1353103285Sikob	}
1354272214Skan	if (off == 0) {
1355103285Sikob		err = EINVAL;
1356103285Sikob		return err;
1357103285Sikob	}
1358272214Skan	if (dbch->xferq.flag & FWXFERQ_RUNNING)
1359103285Sikob		return err;
1360103285Sikob	dbch->xferq.flag |= FWXFERQ_RUNNING;
1361272214Skan	for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) {
1362103285Sikob		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1363103285Sikob	}
1364103285Sikob	db_tr = dbch->top;
1365272214Skan	for (idb = 0; idb < dbch->ndb; idb++) {
1366113584Ssimokawa		fwohci_add_tx_buf(dbch, db_tr, idb);
1367272214Skan		if (STAILQ_NEXT(db_tr, link) == NULL) {
1368103285Sikob			break;
1369103285Sikob		}
1370109892Ssimokawa		db = db_tr->db;
1371113584Ssimokawa		ldesc = db_tr->dbcnt - 1;
1372113584Ssimokawa		FWOHCI_DMA_WRITE(db[0].db.desc.depend,
1373113584Ssimokawa				STAILQ_NEXT(db_tr, link)->bus_addr | z);
1374113584Ssimokawa		db[ldesc].db.desc.depend = db[0].db.desc.depend;
1375272214Skan		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1376272214Skan			if (((idb + 1) % dbch->xferq.bnpacket) == 0) {
1377113584Ssimokawa				FWOHCI_DMA_SET(
1378113584Ssimokawa					db[ldesc].db.desc.cmd,
1379113584Ssimokawa					OHCI_INTERRUPT_ALWAYS);
1380109280Ssimokawa				/* OHCI 1.1 and above */
1381113584Ssimokawa				FWOHCI_DMA_SET(
1382113584Ssimokawa					db[0].db.desc.cmd,
1383113584Ssimokawa					OHCI_INTERRUPT_ALWAYS);
1384103285Sikob			}
1385103285Sikob		}
1386103285Sikob		db_tr = STAILQ_NEXT(db_tr, link);
1387103285Sikob	}
1388113584Ssimokawa	FWOHCI_DMA_CLEAR(
1389113584Ssimokawa		dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf);
1390103285Sikob	return err;
1391103285Sikob}
1392106790Ssimokawa
1393106790Ssimokawastatic int
1394106790Ssimokawafwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1395103285Sikob{
1396103285Sikob	int err = 0;
1397109892Ssimokawa	int idb, z, i, dmach = 0, ldesc;
1398129585Sdfr	uint32_t off = 0;
1399103285Sikob	struct fwohcidb_tr *db_tr;
1400120660Ssimokawa	struct fwohcidb *db;
1401103285Sikob
1402103285Sikob	z = dbch->ndesc;
1403272214Skan	if (&sc->arrq == dbch) {
1404103285Sikob		off = OHCI_ARQOFF;
1405272214Skan	} else if (&sc->arrs == dbch) {
1406103285Sikob		off = OHCI_ARSOFF;
1407272214Skan	} else {
1408272214Skan		for (dmach = 0; dmach < sc->fc.nisodma; dmach++) {
1409272214Skan			if (&sc->ir[dmach] == dbch) {
1410103285Sikob				off = OHCI_IROFF(dmach);
1411103285Sikob				break;
1412103285Sikob			}
1413103285Sikob		}
1414103285Sikob	}
1415272214Skan	if (off == 0) {
1416103285Sikob		err = EINVAL;
1417103285Sikob		return err;
1418103285Sikob	}
1419272214Skan	if (dbch->xferq.flag & FWXFERQ_STREAM) {
1420272214Skan		if (dbch->xferq.flag & FWXFERQ_RUNNING)
1421103285Sikob			return err;
1422272214Skan	} else {
1423272214Skan		if (dbch->xferq.flag & FWXFERQ_RUNNING) {
1424103285Sikob			err = EBUSY;
1425103285Sikob			return err;
1426103285Sikob		}
1427103285Sikob	}
1428103285Sikob	dbch->xferq.flag |= FWXFERQ_RUNNING;
1429108642Ssimokawa	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1430272214Skan	for (i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++) {
1431103285Sikob		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1432103285Sikob	}
1433103285Sikob	db_tr = dbch->top;
1434272214Skan	for (idb = 0; idb < dbch->ndb; idb++) {
1435113584Ssimokawa		fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma);
1436113584Ssimokawa		if (STAILQ_NEXT(db_tr, link) == NULL)
1437103285Sikob			break;
1438109892Ssimokawa		db = db_tr->db;
1439109892Ssimokawa		ldesc = db_tr->dbcnt - 1;
1440113584Ssimokawa		FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend,
1441113584Ssimokawa			STAILQ_NEXT(db_tr, link)->bus_addr | z);
1442272214Skan		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1443272214Skan			if (((idb + 1) % dbch->xferq.bnpacket) == 0) {
1444113584Ssimokawa				FWOHCI_DMA_SET(
1445113584Ssimokawa					db[ldesc].db.desc.cmd,
1446113584Ssimokawa					OHCI_INTERRUPT_ALWAYS);
1447113584Ssimokawa				FWOHCI_DMA_CLEAR(
1448113584Ssimokawa					db[ldesc].db.desc.depend,
1449113584Ssimokawa					0xf);
1450103285Sikob			}
1451103285Sikob		}
1452103285Sikob		db_tr = STAILQ_NEXT(db_tr, link);
1453103285Sikob	}
1454113584Ssimokawa	FWOHCI_DMA_CLEAR(
1455113584Ssimokawa		dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf);
1456103285Sikob	dbch->buf_offset = 0;
1457113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1458113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1459272214Skan	if (dbch->xferq.flag & FWXFERQ_STREAM) {
1460103285Sikob		return err;
1461272214Skan	} else {
1462113584Ssimokawa		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z);
1463103285Sikob	}
1464103285Sikob	OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
1465103285Sikob	return err;
1466103285Sikob}
1467106790Ssimokawa
1468106790Ssimokawastatic int
1469113584Ssimokawafwohci_next_cycle(struct firewire_comm *fc, int cycle_now)
1470109890Ssimokawa{
1471109890Ssimokawa	int sec, cycle, cycle_match;
1472109890Ssimokawa
1473109890Ssimokawa	cycle = cycle_now & 0x1fff;
1474109890Ssimokawa	sec = cycle_now >> 13;
1475109890Ssimokawa#define CYCLE_MOD	0x10
1476113584Ssimokawa#if 1
1477109890Ssimokawa#define CYCLE_DELAY	8	/* min delay to start DMA */
1478113584Ssimokawa#else
1479113584Ssimokawa#define CYCLE_DELAY	7000	/* min delay to start DMA */
1480113584Ssimokawa#endif
1481109890Ssimokawa	cycle = cycle + CYCLE_DELAY;
1482109890Ssimokawa	if (cycle >= 8000) {
1483272214Skan		sec++;
1484109890Ssimokawa		cycle -= 8000;
1485109890Ssimokawa	}
1486113584Ssimokawa	cycle = roundup2(cycle, CYCLE_MOD);
1487109890Ssimokawa	if (cycle >= 8000) {
1488272214Skan		sec++;
1489109890Ssimokawa		if (cycle == 8000)
1490109890Ssimokawa			cycle = 0;
1491109890Ssimokawa		else
1492109890Ssimokawa			cycle = CYCLE_MOD;
1493109890Ssimokawa	}
1494109890Ssimokawa	cycle_match = ((sec << 13) | cycle) & 0x7ffff;
1495109890Ssimokawa
1496272214Skan	return (cycle_match);
1497109890Ssimokawa}
1498109890Ssimokawa
1499109890Ssimokawastatic int
1500106790Ssimokawafwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
1501103285Sikob{
1502103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1503103285Sikob	int err = 0;
1504103285Sikob	unsigned short tag, ich;
1505103285Sikob	struct fwohci_dbch *dbch;
1506109890Ssimokawa	int cycle_match, cycle_now, s, ldesc;
1507129585Sdfr	uint32_t stat;
1508109890Ssimokawa	struct fw_bulkxfer *first, *chunk, *prev;
1509109890Ssimokawa	struct fw_xferq *it;
1510103285Sikob
1511103285Sikob	dbch = &sc->it[dmach];
1512109890Ssimokawa	it = &dbch->xferq;
1513109890Ssimokawa
1514109890Ssimokawa	tag = (it->flag >> 6) & 3;
1515109890Ssimokawa	ich = it->flag & 0x3f;
1516109179Ssimokawa	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
1517109890Ssimokawa		dbch->ndb = it->bnpacket * it->bnchunk;
1518103285Sikob		dbch->ndesc = 3;
1519113584Ssimokawa		fwohci_db_init(sc, dbch);
1520109179Ssimokawa		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1521109179Ssimokawa			return ENOMEM;
1522170374Ssimokawa
1523103285Sikob		err = fwohci_tx_enable(sc, dbch);
1524103285Sikob	}
1525272214Skan	if (err)
1526103285Sikob		return err;
1527109890Ssimokawa
1528109892Ssimokawa	ldesc = dbch->ndesc - 1;
1529109890Ssimokawa	s = splfw();
1530170374Ssimokawa	FW_GLOCK(fc);
1531109890Ssimokawa	prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
1532109890Ssimokawa	while  ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
1533120660Ssimokawa		struct fwohcidb *db;
1534109890Ssimokawa
1535113584Ssimokawa		fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
1536113584Ssimokawa					BUS_DMASYNC_PREWRITE);
1537109890Ssimokawa		fwohci_txbufdb(sc, dmach, chunk);
1538109890Ssimokawa		if (prev != NULL) {
1539109890Ssimokawa			db = ((struct fwohcidb_tr *)(prev->end))->db;
1540113584Ssimokawa#if 0 /* XXX necessary? */
1541113584Ssimokawa			FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
1542113584Ssimokawa						OHCI_BRANCH_ALWAYS);
1543113584Ssimokawa#endif
1544109892Ssimokawa#if 0 /* if bulkxfer->npacket changes */
1545272214Skan			db[ldesc].db.desc.depend = db[0].db.desc.depend =
1546113584Ssimokawa				((struct fwohcidb_tr *)
1547113584Ssimokawa				(chunk->start))->bus_addr | dbch->ndesc;
1548109892Ssimokawa#else
1549113584Ssimokawa			FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
1550113584Ssimokawa			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
1551109892Ssimokawa#endif
1552103285Sikob		}
1553109890Ssimokawa		STAILQ_REMOVE_HEAD(&it->stvalid, link);
1554109890Ssimokawa		STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
1555109890Ssimokawa		prev = chunk;
1556109403Ssimokawa	}
1557170374Ssimokawa	FW_GUNLOCK(fc);
1558113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1559113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1560109890Ssimokawa	splx(s);
1561109890Ssimokawa	stat = OREAD(sc, OHCI_ITCTL(dmach));
1562113584Ssimokawa	if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S))
1563113584Ssimokawa		printf("stat 0x%x\n", stat);
1564113584Ssimokawa
1565109890Ssimokawa	if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S))
1566109890Ssimokawa		return 0;
1567109890Ssimokawa
1568113584Ssimokawa#if 0
1569109890Ssimokawa	OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1570113584Ssimokawa#endif
1571109403Ssimokawa	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
1572109403Ssimokawa	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
1573109403Ssimokawa	OWRITE(sc, OHCI_IT_MASK, 1 << dmach);
1574113584Ssimokawa	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT);
1575109890Ssimokawa
1576109890Ssimokawa	first = STAILQ_FIRST(&it->stdma);
1577113584Ssimokawa	OWRITE(sc, OHCI_ITCMD(dmach),
1578113584Ssimokawa		((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
1579167629Ssimokawa	if (firewire_debug > 1) {
1580109890Ssimokawa		printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
1581113584Ssimokawa#if 1
1582113584Ssimokawa		dump_dma(sc, ITX_CH + dmach);
1583113584Ssimokawa#endif
1584113584Ssimokawa	}
1585109403Ssimokawa	if ((stat & OHCI_CNTL_DMA_RUN) == 0) {
1586109890Ssimokawa#if 1
1587109890Ssimokawa		/* Don't start until all chunks are buffered */
1588109890Ssimokawa		if (STAILQ_FIRST(&it->stfree) != NULL)
1589109890Ssimokawa			goto out;
1590109890Ssimokawa#endif
1591113584Ssimokawa#if 1
1592109890Ssimokawa		/* Clear cycle match counter bits */
1593109890Ssimokawa		OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000);
1594109890Ssimokawa
1595109356Ssimokawa		/* 2bit second + 13bit cycle */
1596109356Ssimokawa		cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff;
1597113584Ssimokawa		cycle_match = fwohci_next_cycle(fc, cycle_now);
1598109890Ssimokawa
1599109356Ssimokawa		OWRITE(sc, OHCI_ITCTL(dmach),
1600109356Ssimokawa				OHCI_CNTL_CYCMATCH_S | (cycle_match << 16)
1601109356Ssimokawa				| OHCI_CNTL_DMA_RUN);
1602113584Ssimokawa#else
1603113584Ssimokawa		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
1604113584Ssimokawa#endif
1605167629Ssimokawa		if (firewire_debug > 1) {
1606109403Ssimokawa			printf("cycle_match: 0x%04x->0x%04x\n",
1607109403Ssimokawa						cycle_now, cycle_match);
1608113584Ssimokawa			dump_dma(sc, ITX_CH + dmach);
1609113584Ssimokawa			dump_db(sc, ITX_CH + dmach);
1610113584Ssimokawa		}
1611109403Ssimokawa	} else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) {
1612109890Ssimokawa		device_printf(sc->fc.dev,
1613109890Ssimokawa			"IT DMA underrun (0x%08x)\n", stat);
1614113584Ssimokawa		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE);
1615103285Sikob	}
1616109890Ssimokawaout:
1617103285Sikob	return err;
1618103285Sikob}
1619106790Ssimokawa
1620106790Ssimokawastatic int
1621113584Ssimokawafwohci_irx_enable(struct firewire_comm *fc, int dmach)
1622103285Sikob{
1623103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1624109890Ssimokawa	int err = 0, s, ldesc;
1625103285Sikob	unsigned short tag, ich;
1626129585Sdfr	uint32_t stat;
1627109890Ssimokawa	struct fwohci_dbch *dbch;
1628113584Ssimokawa	struct fwohcidb_tr *db_tr;
1629109890Ssimokawa	struct fw_bulkxfer *first, *prev, *chunk;
1630109890Ssimokawa	struct fw_xferq *ir;
1631103285Sikob
1632109890Ssimokawa	dbch = &sc->ir[dmach];
1633109890Ssimokawa	ir = &dbch->xferq;
1634109890Ssimokawa
1635109890Ssimokawa	if ((ir->flag & FWXFERQ_RUNNING) == 0) {
1636109890Ssimokawa		tag = (ir->flag >> 6) & 3;
1637109890Ssimokawa		ich = ir->flag & 0x3f;
1638108995Ssimokawa		OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich);
1639108995Ssimokawa
1640109890Ssimokawa		ir->queued = 0;
1641109890Ssimokawa		dbch->ndb = ir->bnpacket * ir->bnchunk;
1642109890Ssimokawa		dbch->ndesc = 2;
1643113584Ssimokawa		fwohci_db_init(sc, dbch);
1644109890Ssimokawa		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1645109179Ssimokawa			return ENOMEM;
1646109890Ssimokawa		err = fwohci_rx_enable(sc, dbch);
1647103285Sikob	}
1648272214Skan	if (err)
1649103285Sikob		return err;
1650103285Sikob
1651109890Ssimokawa	first = STAILQ_FIRST(&ir->stfree);
1652109890Ssimokawa	if (first == NULL) {
1653109890Ssimokawa		device_printf(fc->dev, "IR DMA no free chunk\n");
1654109890Ssimokawa		return 0;
1655109890Ssimokawa	}
1656109890Ssimokawa
1657111892Ssimokawa	ldesc = dbch->ndesc - 1;
1658111892Ssimokawa	s = splfw();
1659170374Ssimokawa	if ((ir->flag & FWXFERQ_HANDLER) == 0)
1660170374Ssimokawa		FW_GLOCK(fc);
1661109890Ssimokawa	prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
1662109890Ssimokawa	while  ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
1663120660Ssimokawa		struct fwohcidb *db;
1664109890Ssimokawa
1665111942Ssimokawa#if 1 /* XXX for if_fwe */
1666113584Ssimokawa		if (chunk->mbuf != NULL) {
1667113584Ssimokawa			db_tr = (struct fwohcidb_tr *)(chunk->start);
1668113584Ssimokawa			db_tr->dbcnt = 1;
1669113584Ssimokawa			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
1670113584Ssimokawa					chunk->mbuf, fwohci_execute_db2, db_tr,
1671113584Ssimokawa					/* flags */0);
1672113584Ssimokawa 			FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd,
1673113584Ssimokawa				OHCI_UPDATE | OHCI_INPUT_LAST |
1674113584Ssimokawa				OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
1675113584Ssimokawa		}
1676111942Ssimokawa#endif
1677109890Ssimokawa		db = ((struct fwohcidb_tr *)(chunk->end))->db;
1678113584Ssimokawa		FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0);
1679113584Ssimokawa		FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
1680109890Ssimokawa		if (prev != NULL) {
1681109890Ssimokawa			db = ((struct fwohcidb_tr *)(prev->end))->db;
1682113584Ssimokawa			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
1683103285Sikob		}
1684109890Ssimokawa		STAILQ_REMOVE_HEAD(&ir->stfree, link);
1685109890Ssimokawa		STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
1686109890Ssimokawa		prev = chunk;
1687103285Sikob	}
1688170374Ssimokawa	if ((ir->flag & FWXFERQ_HANDLER) == 0)
1689170374Ssimokawa		FW_GUNLOCK(fc);
1690113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1691113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1692109890Ssimokawa	splx(s);
1693109890Ssimokawa	stat = OREAD(sc, OHCI_IRCTL(dmach));
1694109890Ssimokawa	if (stat & OHCI_CNTL_DMA_ACTIVE)
1695109890Ssimokawa		return 0;
1696109890Ssimokawa	if (stat & OHCI_CNTL_DMA_RUN) {
1697109890Ssimokawa		OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1698109890Ssimokawa		device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat);
1699109890Ssimokawa	}
1700109890Ssimokawa
1701113584Ssimokawa	if (firewire_debug)
1702113584Ssimokawa		printf("start IR DMA 0x%x\n", stat);
1703109890Ssimokawa	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
1704109890Ssimokawa	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
1705109890Ssimokawa	OWRITE(sc, OHCI_IR_MASK, 1 << dmach);
1706109890Ssimokawa	OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000);
1707109890Ssimokawa	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR);
1708109890Ssimokawa	OWRITE(sc, OHCI_IRCMD(dmach),
1709113584Ssimokawa		((struct fwohcidb_tr *)(first->start))->bus_addr
1710109890Ssimokawa							| dbch->ndesc);
1711109890Ssimokawa	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
1712109890Ssimokawa	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
1713113584Ssimokawa#if 0
1714113584Ssimokawa	dump_db(sc, IRX_CH + dmach);
1715113584Ssimokawa#endif
1716103285Sikob	return err;
1717103285Sikob}
1718106790Ssimokawa
1719106790Ssimokawaint
1720110145Ssimokawafwohci_stop(struct fwohci_softc *sc, device_t dev)
1721103285Sikob{
1722103285Sikob	u_int i;
1723103285Sikob
1724178911Ssimokawa	fwohci_set_intr(&sc->fc, 0);
1725178911Ssimokawa
1726103285Sikob/* Now stopping all DMA channel */
1727272214Skan	OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
1728272214Skan	OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
1729272214Skan	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
1730272214Skan	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
1731103285Sikob
1732272214Skan	for (i = 0; i < sc->fc.nisodma; i++) {
1733272214Skan		OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
1734272214Skan		OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
1735103285Sikob	}
1736103285Sikob
1737272214Skan#if 0 /* Let dcons(4) be accessed */
1738103285Sikob/* Stop interrupt */
1739103285Sikob	OWRITE(sc, FWOHCI_INTMASKCLR,
1740103285Sikob			OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID
1741103285Sikob			| OHCI_INT_PHY_INT
1742272214Skan			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
1743103285Sikob			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
1744272214Skan			| OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS
1745103285Sikob			| OHCI_INT_PHY_BUS_R);
1746116978Ssimokawa
1747298955Spfg/* FLUSH FIFO and reset Transmitter/Receiver */
1748272214Skan	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
1749170374Ssimokawa#endif
1750116978Ssimokawa
1751108642Ssimokawa/* XXX Link down?  Bus reset? */
1752103285Sikob	return 0;
1753103285Sikob}
1754103285Sikob
1755108642Ssimokawaint
1756108642Ssimokawafwohci_resume(struct fwohci_softc *sc, device_t dev)
1757108642Ssimokawa{
1758108642Ssimokawa	int i;
1759116978Ssimokawa	struct fw_xferq *ir;
1760116978Ssimokawa	struct fw_bulkxfer *chunk;
1761108642Ssimokawa
1762108642Ssimokawa	fwohci_reset(sc, dev);
1763129541Sdfr	/* XXX resume isochronous receive automatically. (how about TX?) */
1764272214Skan	for (i = 0; i < sc->fc.nisodma; i++) {
1765116978Ssimokawa		ir = &sc->ir[i].xferq;
1766272214Skan		if ((ir->flag & FWXFERQ_RUNNING) != 0) {
1767108642Ssimokawa			device_printf(sc->fc.dev,
1768108642Ssimokawa				"resume iso receive ch: %d\n", i);
1769116978Ssimokawa			ir->flag &= ~FWXFERQ_RUNNING;
1770116978Ssimokawa			/* requeue stdma to stfree */
1771272214Skan			while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
1772116978Ssimokawa				STAILQ_REMOVE_HEAD(&ir->stdma, link);
1773116978Ssimokawa				STAILQ_INSERT_TAIL(&ir->stfree, chunk, link);
1774116978Ssimokawa			}
1775108642Ssimokawa			sc->fc.irx_enable(&sc->fc, i);
1776108642Ssimokawa		}
1777108642Ssimokawa	}
1778108642Ssimokawa
1779108642Ssimokawa	bus_generic_resume(dev);
1780108642Ssimokawa	sc->fc.ibr(&sc->fc);
1781108642Ssimokawa	return 0;
1782108642Ssimokawa}
1783108642Ssimokawa
1784170374Ssimokawa#ifdef OHCI_DEBUG
1785103285Sikobstatic void
1786170374Ssimokawafwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat)
1787103285Sikob{
1788272214Skan	if (stat & OREAD(sc, FWOHCI_INTMASK))
1789103285Sikob		device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n",
1790103285Sikob			stat & OHCI_INT_EN ? "DMA_EN ":"",
1791103285Sikob			stat & OHCI_INT_PHY_REG ? "PHY_REG ":"",
1792103285Sikob			stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"",
1793103285Sikob			stat & OHCI_INT_ERR ? "INT_ERR ":"",
1794103285Sikob			stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"",
1795103285Sikob			stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"",
1796103285Sikob			stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"",
1797103285Sikob			stat & OHCI_INT_CYC_START ? "CYC_START ":"",
1798103285Sikob			stat & OHCI_INT_PHY_INT ? "PHY_INT ":"",
1799103285Sikob			stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"",
1800103285Sikob			stat & OHCI_INT_PHY_SID ? "SID ":"",
1801103285Sikob			stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"",
1802103285Sikob			stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"",
1803103285Sikob			stat & OHCI_INT_DMA_IR ? "DMA_IR ":"",
1804103285Sikob			stat & OHCI_INT_DMA_IT  ? "DMA_IT " :"",
1805103285Sikob			stat & OHCI_INT_DMA_PRRS  ? "DMA_PRRS " :"",
1806103285Sikob			stat & OHCI_INT_DMA_PRRQ  ? "DMA_PRRQ " :"",
1807103285Sikob			stat & OHCI_INT_DMA_ARRS  ? "DMA_ARRS " :"",
1808103285Sikob			stat & OHCI_INT_DMA_ARRQ  ? "DMA_ARRQ " :"",
1809103285Sikob			stat & OHCI_INT_DMA_ATRS  ? "DMA_ATRS " :"",
1810103285Sikob			stat & OHCI_INT_DMA_ATRQ  ? "DMA_ATRQ " :"",
1811272214Skan			stat, OREAD(sc, FWOHCI_INTMASK)
1812103285Sikob		);
1813170374Ssimokawa}
1814103285Sikob#endif
1815272214Skan
1816170374Ssimokawastatic void
1817170374Ssimokawafwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count)
1818170374Ssimokawa{
1819170374Ssimokawa	struct firewire_comm *fc = (struct firewire_comm *)sc;
1820277511Swill	uintmax_t prequpper;
1821170374Ssimokawa	uint32_t node_id, plen;
1822170374Ssimokawa
1823187993Ssbruno	FW_GLOCK_ASSERT(fc);
1824170374Ssimokawa	if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) {
1825170374Ssimokawa		fc->status = FWBUSRESET;
1826111074Ssimokawa		/* Disable bus reset interrupt until sid recv. */
1827272214Skan		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R);
1828272214Skan
1829188509Ssbruno		device_printf(fc->dev, "%s: BUS reset\n", __func__);
1830272214Skan		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST);
1831103285Sikob		OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC);
1832103285Sikob
1833272214Skan		OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
1834103285Sikob		sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING;
1835272214Skan		OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
1836103285Sikob		sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
1837103285Sikob
1838170374Ssimokawa		if (!kdb_active)
1839170374Ssimokawa			taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset);
1840170374Ssimokawa	}
1841170374Ssimokawa	if (stat & OHCI_INT_PHY_SID) {
1842170374Ssimokawa		/* Enable bus reset interrupt */
1843103285Sikob		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
1844170374Ssimokawa		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R);
1845170374Ssimokawa
1846170374Ssimokawa		/* Allow async. request to us */
1847170374Ssimokawa		OWRITE(sc, OHCI_AREQHI, 1 << 31);
1848170400Ssimokawa		if (firewire_phydma_enable) {
1849170400Ssimokawa			/* allow from all nodes */
1850170400Ssimokawa			OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
1851170400Ssimokawa			OWRITE(sc, OHCI_PREQLO, 0xffffffff);
1852277511Swill			prequpper = ((uintmax_t)Maxmem << PAGE_SHIFT) >> 16;
1853277511Swill			if (prequpper > OHCI_PREQUPPER_MAX) {
1854277511Swill				device_printf(fc->dev,
1855277511Swill				    "Physical memory size of 0x%jx exceeds "
1856277511Swill				    "fire wire address space.  Limiting dma "
1857277511Swill				    "to memory below 0x%jx\n",
1858277511Swill				    (uintmax_t)Maxmem << PAGE_SHIFT,
1859277511Swill				    (uintmax_t)OHCI_PREQUPPER_MAX << 16);
1860277511Swill				prequpper = OHCI_PREQUPPER_MAX;
1861277511Swill			}
1862277511Swill			OWRITE(sc, OHCI_PREQUPPER, prequpper & 0xffffffff);
1863310073Savg			if (OREAD(sc, OHCI_PREQUPPER) !=
1864310073Savg			    (prequpper & 0xffffffff)) {
1865310073Savg				device_printf(fc->dev,
1866310073Savg				   "PhysicalUpperBound register is not "
1867310073Savg				   "implemented.  Physical memory access "
1868310073Savg				   "is limited to the first 4GB\n");
1869310073Savg				device_printf(fc->dev,
1870310073Savg				   "PhysicalUpperBound = 0x%08x\n",
1871310073Savg				    OREAD(sc, OHCI_PREQUPPER));
1872310073Savg			}
1873170400Ssimokawa		}
1874170374Ssimokawa		/* Set ATRetries register */
1875272214Skan		OWRITE(sc, OHCI_ATRETRY, 1<<(13 + 16) | 0xfff);
1876170374Ssimokawa
1877170374Ssimokawa		/*
1878272214Skan		 * Checking whether the node is root or not. If root, turn on
1879170374Ssimokawa		 * cycle master.
1880170374Ssimokawa		 */
1881170374Ssimokawa		node_id = OREAD(sc, FWOHCI_NODEID);
1882170374Ssimokawa		plen = OREAD(sc, OHCI_SID_CNT);
1883170374Ssimokawa
1884170374Ssimokawa		fc->nodeid = node_id & 0x3f;
1885188509Ssbruno		device_printf(fc->dev, "%s: node_id=0x%08x, SelfID Count=%d, ",
1886188509Ssbruno				__func__, fc->nodeid, (plen >> 16) & 0xff);
1887170374Ssimokawa		if (!(node_id & OHCI_NODE_VALID)) {
1888188509Ssbruno			device_printf(fc->dev, "%s: Bus reset failure\n",
1889188509Ssbruno				__func__);
1890170374Ssimokawa			goto sidout;
1891170374Ssimokawa		}
1892170374Ssimokawa
1893170374Ssimokawa		/* cycle timer */
1894170374Ssimokawa		sc->cycle_lost = 0;
1895272214Skan		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST);
1896170374Ssimokawa		if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) {
1897170374Ssimokawa			printf("CYCLEMASTER mode\n");
1898170374Ssimokawa			OWRITE(sc, OHCI_LNKCTL,
1899170374Ssimokawa				OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
1900170374Ssimokawa		} else {
1901170374Ssimokawa			printf("non CYCLEMASTER mode\n");
1902170374Ssimokawa			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
1903170374Ssimokawa			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
1904170374Ssimokawa		}
1905170374Ssimokawa
1906170374Ssimokawa		fc->status = FWBUSINIT;
1907170374Ssimokawa
1908170374Ssimokawa		if (!kdb_active)
1909170374Ssimokawa			taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid);
1910103285Sikob	}
1911170374Ssimokawasidout:
1912170374Ssimokawa	if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active))
1913170374Ssimokawa		taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma);
1914170374Ssimokawa}
1915170374Ssimokawa
1916170374Ssimokawastatic void
1917170374Ssimokawafwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count)
1918170374Ssimokawa{
1919170374Ssimokawa	uint32_t irstat, itstat;
1920170374Ssimokawa	u_int i;
1921170374Ssimokawa	struct firewire_comm *fc = (struct firewire_comm *)sc;
1922170374Ssimokawa
1923170374Ssimokawa	if (stat & OHCI_INT_DMA_IR) {
1924127468Ssimokawa		irstat = atomic_readandclear_int(&sc->irstat);
1925272214Skan		for (i = 0; i < fc->nisodma; i++) {
1926109644Ssimokawa			struct fwohci_dbch *dbch;
1927109644Ssimokawa
1928272214Skan			if ((irstat & (1 << i)) != 0) {
1929109644Ssimokawa				dbch = &sc->ir[i];
1930109644Ssimokawa				if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) {
1931109644Ssimokawa					device_printf(sc->fc.dev,
1932109644Ssimokawa						"dma(%d) not active\n", i);
1933109644Ssimokawa					continue;
1934109644Ssimokawa				}
1935113584Ssimokawa				fwohci_rbuf_update(sc, i);
1936103285Sikob			}
1937103285Sikob		}
1938103285Sikob	}
1939170374Ssimokawa	if (stat & OHCI_INT_DMA_IT) {
1940127468Ssimokawa		itstat = atomic_readandclear_int(&sc->itstat);
1941272214Skan		for (i = 0; i < fc->nisodma; i++) {
1942272214Skan			if ((itstat & (1 << i)) != 0) {
1943103285Sikob				fwohci_tbuf_update(sc, i);
1944103285Sikob			}
1945103285Sikob		}
1946103285Sikob	}
1947170374Ssimokawa	if (stat & OHCI_INT_DMA_PRRS) {
1948103285Sikob#if 0
1949103285Sikob		dump_dma(sc, ARRS_CH);
1950103285Sikob		dump_db(sc, ARRS_CH);
1951103285Sikob#endif
1952106789Ssimokawa		fwohci_arcv(sc, &sc->arrs, count);
1953103285Sikob	}
1954170374Ssimokawa	if (stat & OHCI_INT_DMA_PRRQ) {
1955103285Sikob#if 0
1956103285Sikob		dump_dma(sc, ARRQ_CH);
1957103285Sikob		dump_db(sc, ARRQ_CH);
1958103285Sikob#endif
1959106789Ssimokawa		fwohci_arcv(sc, &sc->arrq, count);
1960103285Sikob	}
1961167628Ssimokawa	if (stat & OHCI_INT_CYC_LOST) {
1962167628Ssimokawa		if (sc->cycle_lost >= 0)
1963272214Skan			sc->cycle_lost++;
1964167628Ssimokawa		if (sc->cycle_lost > 10) {
1965167628Ssimokawa			sc->cycle_lost = -1;
1966167628Ssimokawa#if 0
1967167628Ssimokawa			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER);
1968167628Ssimokawa#endif
1969272214Skan			OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST);
1970214021Sbrucec			device_printf(fc->dev, "too many cycles lost, "
1971214021Sbrucec			 "no cycle master present?\n");
1972167628Ssimokawa		}
1973167628Ssimokawa	}
1974170374Ssimokawa	if (stat & OHCI_INT_DMA_ATRQ) {
1975103285Sikob		fwohci_txd(sc, &(sc->atrq));
1976103285Sikob	}
1977170374Ssimokawa	if (stat & OHCI_INT_DMA_ATRS) {
1978103285Sikob		fwohci_txd(sc, &(sc->atrs));
1979103285Sikob	}
1980170374Ssimokawa	if (stat & OHCI_INT_PW_ERR) {
1981103285Sikob		device_printf(fc->dev, "posted write error\n");
1982103285Sikob	}
1983170374Ssimokawa	if (stat & OHCI_INT_ERR) {
1984103285Sikob		device_printf(fc->dev, "unrecoverable error\n");
1985103285Sikob	}
1986170374Ssimokawa	if (stat & OHCI_INT_PHY_INT) {
1987103285Sikob		device_printf(fc->dev, "phy int\n");
1988103285Sikob	}
1989103285Sikob}
1990103285Sikob
1991113584Ssimokawastatic void
1992170374Ssimokawafwohci_task_busreset(void *arg, int pending)
1993113584Ssimokawa{
1994113584Ssimokawa	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
1995170374Ssimokawa
1996187993Ssbruno	FW_GLOCK(&sc->fc);
1997170374Ssimokawa	fw_busreset(&sc->fc, FWBUSRESET);
1998170374Ssimokawa	OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
1999170374Ssimokawa	OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
2000187993Ssbruno	FW_GUNLOCK(&sc->fc);
2001170374Ssimokawa}
2002170374Ssimokawa
2003170374Ssimokawastatic void
2004170374Ssimokawafwohci_task_sid(void *arg, int pending)
2005170374Ssimokawa{
2006170374Ssimokawa	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
2007170374Ssimokawa	struct firewire_comm *fc = &sc->fc;
2008170374Ssimokawa	uint32_t *buf;
2009170374Ssimokawa	int i, plen;
2010170374Ssimokawa
2011170374Ssimokawa
2012187993Ssbruno	/*
2013187993Ssbruno	 * We really should have locking
2014187993Ssbruno	 * here.  Not sure why it's not
2015187993Ssbruno	 */
2016170374Ssimokawa	plen = OREAD(sc, OHCI_SID_CNT);
2017170374Ssimokawa
2018170374Ssimokawa	if (plen & OHCI_SID_ERR) {
2019170374Ssimokawa		device_printf(fc->dev, "SID Error\n");
2020170374Ssimokawa		return;
2021170374Ssimokawa	}
2022170374Ssimokawa	plen &= OHCI_SID_CNT_MASK;
2023170374Ssimokawa	if (plen < 4 || plen > OHCI_SIDSIZE) {
2024170374Ssimokawa		device_printf(fc->dev, "invalid SID len = %d\n", plen);
2025170374Ssimokawa		return;
2026170374Ssimokawa	}
2027170374Ssimokawa	plen -= 4; /* chop control info */
2028170374Ssimokawa	buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
2029170374Ssimokawa	if (buf == NULL) {
2030170374Ssimokawa		device_printf(fc->dev, "malloc failed\n");
2031170374Ssimokawa		return;
2032170374Ssimokawa	}
2033272214Skan	for (i = 0; i < plen / 4; i++)
2034272214Skan		buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i + 1]);
2035187993Ssbruno
2036170374Ssimokawa	/* pending all pre-bus_reset packets */
2037170374Ssimokawa	fwohci_txd(sc, &sc->atrq);
2038170374Ssimokawa	fwohci_txd(sc, &sc->atrs);
2039170374Ssimokawa	fwohci_arcv(sc, &sc->arrs, -1);
2040170374Ssimokawa	fwohci_arcv(sc, &sc->arrq, -1);
2041170374Ssimokawa	fw_drain_txq(fc);
2042170374Ssimokawa	fw_sidrcv(fc, buf, plen);
2043170374Ssimokawa	free(buf, M_FW);
2044170374Ssimokawa}
2045170374Ssimokawa
2046170374Ssimokawastatic void
2047170374Ssimokawafwohci_task_dma(void *arg, int pending)
2048170374Ssimokawa{
2049170374Ssimokawa	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
2050129585Sdfr	uint32_t stat;
2051113584Ssimokawa
2052113584Ssimokawaagain:
2053113584Ssimokawa	stat = atomic_readandclear_int(&sc->intstat);
2054113584Ssimokawa	if (stat)
2055170374Ssimokawa		fwohci_intr_dma(sc, stat, -1);
2056113584Ssimokawa	else
2057113584Ssimokawa		return;
2058113584Ssimokawa	goto again;
2059113584Ssimokawa}
2060113584Ssimokawa
2061170374Ssimokawastatic int
2062170374Ssimokawafwohci_check_stat(struct fwohci_softc *sc)
2063113584Ssimokawa{
2064129585Sdfr	uint32_t stat, irstat, itstat;
2065113584Ssimokawa
2066187993Ssbruno	FW_GLOCK_ASSERT(&sc->fc);
2067113584Ssimokawa	stat = OREAD(sc, FWOHCI_INTSTAT);
2068113584Ssimokawa	if (stat == 0xffffffff) {
2069223353Simp		if (!bus_child_present(sc->fc.dev))
2070223353Simp			return (FILTER_HANDLED);
2071223353Simp		device_printf(sc->fc.dev, "device physically ejected?\n");
2072170374Ssimokawa		return (FILTER_STRAY);
2073113584Ssimokawa	}
2074113584Ssimokawa	if (stat)
2075170374Ssimokawa		OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R);
2076170374Ssimokawa
2077170374Ssimokawa	stat &= sc->intmask;
2078170374Ssimokawa	if (stat == 0)
2079170374Ssimokawa		return (FILTER_STRAY);
2080170374Ssimokawa
2081170374Ssimokawa	atomic_set_int(&sc->intstat, stat);
2082113584Ssimokawa	if (stat & OHCI_INT_DMA_IR) {
2083113584Ssimokawa		irstat = OREAD(sc, OHCI_IR_STAT);
2084113584Ssimokawa		OWRITE(sc, OHCI_IR_STATCLR, irstat);
2085113584Ssimokawa		atomic_set_int(&sc->irstat, irstat);
2086113584Ssimokawa	}
2087113584Ssimokawa	if (stat & OHCI_INT_DMA_IT) {
2088113584Ssimokawa		itstat = OREAD(sc, OHCI_IT_STAT);
2089113584Ssimokawa		OWRITE(sc, OHCI_IT_STATCLR, itstat);
2090113584Ssimokawa		atomic_set_int(&sc->itstat, itstat);
2091113584Ssimokawa	}
2092170374Ssimokawa
2093170374Ssimokawa	fwohci_intr_core(sc, stat, -1);
2094170374Ssimokawa	return (FILTER_HANDLED);
2095113584Ssimokawa}
2096113584Ssimokawa
2097187993Ssbrunovoid
2098187993Ssbrunofwohci_intr(void *arg)
2099103285Sikob{
2100103285Sikob	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
2101103285Sikob
2102187993Ssbruno	FW_GLOCK(&sc->fc);
2103187993Ssbruno	fwohci_check_stat(sc);
2104187993Ssbruno	FW_GUNLOCK(&sc->fc);
2105170374Ssimokawa}
2106103285Sikob
2107170374Ssimokawavoid
2108103285Sikobfwohci_poll(struct firewire_comm *fc, int quick, int count)
2109103285Sikob{
2110170374Ssimokawa	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
2111187993Ssbruno
2112187993Ssbruno	FW_GLOCK(fc);
2113170374Ssimokawa	fwohci_check_stat(sc);
2114187993Ssbruno	FW_GUNLOCK(fc);
2115103285Sikob}
2116103285Sikob
2117103285Sikobstatic void
2118103285Sikobfwohci_set_intr(struct firewire_comm *fc, int enable)
2119103285Sikob{
2120103285Sikob	struct fwohci_softc *sc;
2121103285Sikob
2122103285Sikob	sc = (struct fwohci_softc *)fc;
2123132432Ssimokawa	if (firewire_debug)
2124108642Ssimokawa		device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable);
2125103285Sikob	if (enable) {
2126103285Sikob		sc->intmask |= OHCI_INT_EN;
2127103285Sikob		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN);
2128103285Sikob	} else {
2129103285Sikob		sc->intmask &= ~OHCI_INT_EN;
2130103285Sikob		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN);
2131103285Sikob	}
2132103285Sikob}
2133103285Sikob
2134106790Ssimokawastatic void
2135106790Ssimokawafwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
2136103285Sikob{
2137103285Sikob	struct firewire_comm *fc = &sc->fc;
2138120660Ssimokawa	struct fwohcidb *db;
2139109890Ssimokawa	struct fw_bulkxfer *chunk;
2140109890Ssimokawa	struct fw_xferq *it;
2141129585Sdfr	uint32_t stat, count;
2142113584Ssimokawa	int s, w=0, ldesc;
2143103285Sikob
2144109890Ssimokawa	it = fc->it[dmach];
2145113584Ssimokawa	ldesc = sc->it[dmach].ndesc - 1;
2146109890Ssimokawa	s = splfw(); /* unnecessary ? */
2147170374Ssimokawa	FW_GLOCK(fc);
2148113584Ssimokawa	fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
2149119155Ssimokawa	if (firewire_debug)
2150119155Ssimokawa		dump_db(sc, ITX_CH + dmach);
2151109890Ssimokawa	while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
2152109890Ssimokawa		db = ((struct fwohcidb_tr *)(chunk->end))->db;
2153272214Skan		stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
2154113584Ssimokawa				>> OHCI_STATUS_SHIFT;
2155109890Ssimokawa		db = ((struct fwohcidb_tr *)(chunk->start))->db;
2156119155Ssimokawa		/* timestamp */
2157113584Ssimokawa		count = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
2158113584Ssimokawa				& OHCI_COUNT_MASK;
2159109890Ssimokawa		if (stat == 0)
2160109890Ssimokawa			break;
2161109890Ssimokawa		STAILQ_REMOVE_HEAD(&it->stdma, link);
2162272214Skan		switch (stat & FWOHCIEV_MASK) {
2163109890Ssimokawa		case FWOHCIEV_ACKCOMPL:
2164109890Ssimokawa#if 0
2165109890Ssimokawa			device_printf(fc->dev, "0x%08x\n", count);
2166109179Ssimokawa#endif
2167109890Ssimokawa			break;
2168109890Ssimokawa		default:
2169109423Ssimokawa			device_printf(fc->dev,
2170113584Ssimokawa				"Isochronous transmit err %02x(%s)\n",
2171113584Ssimokawa					stat, fwohcicode[stat & 0x1f]);
2172109890Ssimokawa		}
2173109890Ssimokawa		STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
2174109890Ssimokawa		w++;
2175109403Ssimokawa	}
2176170374Ssimokawa	FW_GUNLOCK(fc);
2177109890Ssimokawa	splx(s);
2178109890Ssimokawa	if (w)
2179109890Ssimokawa		wakeup(it);
2180103285Sikob}
2181106790Ssimokawa
2182106790Ssimokawastatic void
2183106790Ssimokawafwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
2184103285Sikob{
2185109179Ssimokawa	struct firewire_comm *fc = &sc->fc;
2186120660Ssimokawa	struct fwohcidb_tr *db_tr;
2187109890Ssimokawa	struct fw_bulkxfer *chunk;
2188109890Ssimokawa	struct fw_xferq *ir;
2189129585Sdfr	uint32_t stat;
2190277511Swill	int w = 0, ldesc;
2191109179Ssimokawa
2192109890Ssimokawa	ir = fc->ir[dmach];
2193113584Ssimokawa	ldesc = sc->ir[dmach].ndesc - 1;
2194170374Ssimokawa
2195113584Ssimokawa#if 0
2196113584Ssimokawa	dump_db(sc, dmach);
2197113584Ssimokawa#endif
2198170374Ssimokawa	if ((ir->flag & FWXFERQ_HANDLER) == 0)
2199170374Ssimokawa		FW_GLOCK(fc);
2200113584Ssimokawa	fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
2201109890Ssimokawa	while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
2202113584Ssimokawa		db_tr = (struct fwohcidb_tr *)chunk->end;
2203113584Ssimokawa		stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res)
2204113584Ssimokawa				>> OHCI_STATUS_SHIFT;
2205109890Ssimokawa		if (stat == 0)
2206109890Ssimokawa			break;
2207113584Ssimokawa
2208113584Ssimokawa		if (chunk->mbuf != NULL) {
2209113584Ssimokawa			bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map,
2210113584Ssimokawa						BUS_DMASYNC_POSTREAD);
2211113584Ssimokawa			bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map);
2212113584Ssimokawa		} else if (ir->buf != NULL) {
2213113584Ssimokawa			fwdma_sync_multiseg(ir->buf, chunk->poffset,
2214113584Ssimokawa				ir->bnpacket, BUS_DMASYNC_POSTREAD);
2215113584Ssimokawa		} else {
2216113584Ssimokawa			/* XXX */
2217298955Spfg			printf("fwohci_rbuf_update: this shouldn't happened\n");
2218113584Ssimokawa		}
2219113584Ssimokawa
2220109890Ssimokawa		STAILQ_REMOVE_HEAD(&ir->stdma, link);
2221109890Ssimokawa		STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link);
2222109890Ssimokawa		switch (stat & FWOHCIEV_MASK) {
2223109890Ssimokawa		case FWOHCIEV_ACKCOMPL:
2224111942Ssimokawa			chunk->resp = 0;
2225109890Ssimokawa			break;
2226109890Ssimokawa		default:
2227111942Ssimokawa			chunk->resp = EINVAL;
2228109890Ssimokawa			device_printf(fc->dev,
2229113584Ssimokawa				"Isochronous receive err %02x(%s)\n",
2230113584Ssimokawa					stat, fwohcicode[stat & 0x1f]);
2231109890Ssimokawa		}
2232109890Ssimokawa		w++;
2233103285Sikob	}
2234170374Ssimokawa	if ((ir->flag & FWXFERQ_HANDLER) == 0)
2235170374Ssimokawa		FW_GUNLOCK(fc);
2236170374Ssimokawa	if (w == 0)
2237170374Ssimokawa		return;
2238170374Ssimokawa
2239272214Skan	if (ir->flag & FWXFERQ_HANDLER)
2240170374Ssimokawa		ir->hand(ir);
2241170374Ssimokawa	else
2242170374Ssimokawa		wakeup(ir);
2243103285Sikob}
2244106790Ssimokawa
2245106790Ssimokawavoid
2246129585Sdfrdump_dma(struct fwohci_softc *sc, uint32_t ch)
2247106790Ssimokawa{
2248129585Sdfr	uint32_t off, cntl, stat, cmd, match;
2249103285Sikob
2250272214Skan	if (ch == 0) {
2251103285Sikob		off = OHCI_ATQOFF;
2252272214Skan	} else if (ch == 1) {
2253103285Sikob		off = OHCI_ATSOFF;
2254272214Skan	} else if (ch == 2) {
2255103285Sikob		off = OHCI_ARQOFF;
2256272214Skan	} else if (ch == 3) {
2257103285Sikob		off = OHCI_ARSOFF;
2258272214Skan	} else if (ch < IRX_CH) {
2259103285Sikob		off = OHCI_ITCTL(ch - ITX_CH);
2260272214Skan	} else {
2261103285Sikob		off = OHCI_IRCTL(ch - IRX_CH);
2262103285Sikob	}
2263103285Sikob	cntl = stat = OREAD(sc, off);
2264103285Sikob	cmd = OREAD(sc, off + 0xc);
2265103285Sikob	match = OREAD(sc, off + 0x10);
2266103285Sikob
2267113584Ssimokawa	device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n",
2268103285Sikob		ch,
2269272214Skan		cntl,
2270272214Skan		cmd,
2271103285Sikob		match);
2272272214Skan	stat &= 0xffff;
2273113584Ssimokawa	if (stat) {
2274103285Sikob		device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n",
2275103285Sikob			ch,
2276103285Sikob			stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2277103285Sikob			stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2278103285Sikob			stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2279103285Sikob			stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2280103285Sikob			stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2281103285Sikob			stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2282103285Sikob			fwohcicode[stat & 0x1f],
2283103285Sikob			stat & 0x1f
2284103285Sikob		);
2285272214Skan	} else {
2286103285Sikob		device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch);
2287103285Sikob	}
2288103285Sikob}
2289106790Ssimokawa
2290106790Ssimokawavoid
2291129585Sdfrdump_db(struct fwohci_softc *sc, uint32_t ch)
2292106790Ssimokawa{
2293103285Sikob	struct fwohci_dbch *dbch;
2294113584Ssimokawa	struct fwohcidb_tr *cp = NULL, *pp, *np = NULL;
2295120660Ssimokawa	struct fwohcidb *curr = NULL, *prev, *next = NULL;
2296103285Sikob	int idb, jdb;
2297129585Sdfr	uint32_t cmd, off;
2298272214Skan
2299272214Skan	if (ch == 0) {
2300103285Sikob		off = OHCI_ATQOFF;
2301103285Sikob		dbch = &sc->atrq;
2302272214Skan	} else if (ch == 1) {
2303103285Sikob		off = OHCI_ATSOFF;
2304103285Sikob		dbch = &sc->atrs;
2305272214Skan	} else if (ch == 2) {
2306103285Sikob		off = OHCI_ARQOFF;
2307103285Sikob		dbch = &sc->arrq;
2308272214Skan	} else if (ch == 3) {
2309103285Sikob		off = OHCI_ARSOFF;
2310103285Sikob		dbch = &sc->arrs;
2311272214Skan	} else if (ch < IRX_CH) {
2312103285Sikob		off = OHCI_ITCTL(ch - ITX_CH);
2313103285Sikob		dbch = &sc->it[ch - ITX_CH];
2314272214Skan	} else {
2315103285Sikob		off = OHCI_IRCTL(ch - IRX_CH);
2316103285Sikob		dbch = &sc->ir[ch - IRX_CH];
2317103285Sikob	}
2318103285Sikob	cmd = OREAD(sc, off + 0xc);
2319103285Sikob
2320272214Skan	if (dbch->ndb == 0) {
2321103285Sikob		device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch);
2322103285Sikob		return;
2323103285Sikob	}
2324103285Sikob	pp = dbch->top;
2325103285Sikob	prev = pp->db;
2326272214Skan	for (idb = 0; idb < dbch->ndb; idb++) {
2327103285Sikob		cp = STAILQ_NEXT(pp, link);
2328272214Skan		if (cp == NULL) {
2329103285Sikob			curr = NULL;
2330103285Sikob			goto outdb;
2331103285Sikob		}
2332103285Sikob		np = STAILQ_NEXT(cp, link);
2333272214Skan		for (jdb = 0; jdb < dbch->ndesc; jdb++) {
2334113584Ssimokawa			if ((cmd  & 0xfffffff0) == cp->bus_addr) {
2335103285Sikob				curr = cp->db;
2336272214Skan				if (np != NULL) {
2337103285Sikob					next = np->db;
2338272214Skan				} else {
2339103285Sikob					next = NULL;
2340103285Sikob				}
2341103285Sikob				goto outdb;
2342103285Sikob			}
2343103285Sikob		}
2344103285Sikob		pp = STAILQ_NEXT(pp, link);
2345272214Skan		if (pp == NULL) {
2346144263Ssam			curr = NULL;
2347144263Ssam			goto outdb;
2348144263Ssam		}
2349103285Sikob		prev = pp->db;
2350103285Sikob	}
2351103285Sikoboutdb:
2352272214Skan	if (curr != NULL) {
2353113584Ssimokawa#if 0
2354103285Sikob		printf("Prev DB %d\n", ch);
2355113584Ssimokawa		print_db(pp, prev, ch, dbch->ndesc);
2356113584Ssimokawa#endif
2357103285Sikob		printf("Current DB %d\n", ch);
2358113584Ssimokawa		print_db(cp, curr, ch, dbch->ndesc);
2359113584Ssimokawa#if 0
2360103285Sikob		printf("Next DB %d\n", ch);
2361113584Ssimokawa		print_db(np, next, ch, dbch->ndesc);
2362113584Ssimokawa#endif
2363272214Skan	} else {
2364103285Sikob		printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd);
2365103285Sikob	}
2366103285Sikob	return;
2367103285Sikob}
2368106790Ssimokawa
2369106790Ssimokawavoid
2370120660Ssimokawaprint_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db,
2371129585Sdfr		uint32_t ch, uint32_t max)
2372106790Ssimokawa{
2373103285Sikob	fwohcireg_t stat;
2374103285Sikob	int i, key;
2375129585Sdfr	uint32_t cmd, res;
2376103285Sikob
2377272214Skan	if (db == NULL) {
2378103285Sikob		printf("No Descriptor is found\n");
2379103285Sikob		return;
2380103285Sikob	}
2381103285Sikob
2382103285Sikob	printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n",
2383103285Sikob		ch,
2384103285Sikob		"Current",
2385103285Sikob		"OP  ",
2386103285Sikob		"KEY",
2387103285Sikob		"INT",
2388103285Sikob		"BR ",
2389103285Sikob		"len",
2390103285Sikob		"Addr",
2391103285Sikob		"Depend",
2392103285Sikob		"Stat",
2393103285Sikob		"Cnt");
2394272214Skan	for (i = 0; i <= max; i++) {
2395113584Ssimokawa		cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd);
2396113584Ssimokawa		res = FWOHCI_DMA_READ(db[i].db.desc.res);
2397113584Ssimokawa		key = cmd & OHCI_KEY_MASK;
2398113584Ssimokawa		stat = res >> OHCI_STATUS_SHIFT;
2399113972Ssimokawa		printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x",
2400114142Ssimokawa				(uintmax_t)db_tr->bus_addr,
2401113584Ssimokawa				dbcode[(cmd >> 28) & 0xf],
2402113584Ssimokawa				dbkey[(cmd >> 24) & 0x7],
2403113584Ssimokawa				dbcond[(cmd >> 20) & 0x3],
2404113584Ssimokawa				dbcond[(cmd >> 18) & 0x3],
2405113584Ssimokawa				cmd & OHCI_COUNT_MASK,
2406113584Ssimokawa				FWOHCI_DMA_READ(db[i].db.desc.addr),
2407113584Ssimokawa				FWOHCI_DMA_READ(db[i].db.desc.depend),
2408113584Ssimokawa				stat,
2409113584Ssimokawa				res & OHCI_COUNT_MASK);
2410272214Skan		if (stat & 0xff00) {
2411103285Sikob			printf(" %s%s%s%s%s%s %s(%x)\n",
2412103285Sikob				stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2413103285Sikob				stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2414103285Sikob				stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2415103285Sikob				stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2416103285Sikob				stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2417103285Sikob				stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2418103285Sikob				fwohcicode[stat & 0x1f],
2419103285Sikob				stat & 0x1f
2420103285Sikob			);
2421272214Skan		} else {
2422103285Sikob			printf(" Nostat\n");
2423103285Sikob		}
2424272214Skan		if (key == OHCI_KEY_ST2) {
2425272214Skan			printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
2426272214Skan				FWOHCI_DMA_READ(db[i + 1].db.immed[0]),
2427272214Skan				FWOHCI_DMA_READ(db[i + 1].db.immed[1]),
2428272214Skan				FWOHCI_DMA_READ(db[i + 1].db.immed[2]),
2429272214Skan				FWOHCI_DMA_READ(db[i + 1].db.immed[3]));
2430103285Sikob		}
2431272214Skan		if (key == OHCI_KEY_DEVICE) {
2432103285Sikob			return;
2433103285Sikob		}
2434272214Skan		if ((cmd & OHCI_BRANCH_MASK)
2435272214Skan				== OHCI_BRANCH_ALWAYS) {
2436103285Sikob			return;
2437103285Sikob		}
2438272214Skan		if ((cmd & OHCI_CMD_MASK)
2439272214Skan				== OHCI_OUTPUT_LAST) {
2440103285Sikob			return;
2441103285Sikob		}
2442272214Skan		if ((cmd & OHCI_CMD_MASK)
2443272214Skan				== OHCI_INPUT_LAST) {
2444103285Sikob			return;
2445103285Sikob		}
2446272214Skan		if (key == OHCI_KEY_ST2) {
2447103285Sikob			i++;
2448103285Sikob		}
2449103285Sikob	}
2450103285Sikob	return;
2451103285Sikob}
2452106790Ssimokawa
2453106790Ssimokawavoid
2454106790Ssimokawafwohci_ibr(struct firewire_comm *fc)
2455103285Sikob{
2456103285Sikob	struct fwohci_softc *sc;
2457129585Sdfr	uint32_t fun;
2458103285Sikob
2459110577Ssimokawa	device_printf(fc->dev, "Initiate bus reset\n");
2460103285Sikob	sc = (struct fwohci_softc *)fc;
2461108276Ssimokawa
2462187993Ssbruno	FW_GLOCK(fc);
2463108276Ssimokawa	/*
2464129611Sdfr	 * Make sure our cached values from the config rom are
2465129611Sdfr	 * initialised.
2466129611Sdfr	 */
2467129611Sdfr	OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
2468129611Sdfr	OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
2469129611Sdfr
2470129611Sdfr	/*
2471108276Ssimokawa	 * Set root hold-off bit so that non cyclemaster capable node
2472108276Ssimokawa	 * shouldn't became the root node.
2473108276Ssimokawa	 */
2474103285Sikob#if 1
2475103285Sikob	fun = fwphy_rddata(sc, FW_PHY_IBR_REG);
2476109280Ssimokawa	fun |= FW_PHY_IBR | FW_PHY_RHB;
2477103285Sikob	fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun);
2478109280Ssimokawa#else	/* Short bus reset */
2479103285Sikob	fun = fwphy_rddata(sc, FW_PHY_ISBR_REG);
2480109280Ssimokawa	fun |= FW_PHY_ISBR | FW_PHY_RHB;
2481103285Sikob	fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun);
2482103285Sikob#endif
2483187993Ssbruno	FW_GUNLOCK(fc);
2484103285Sikob}
2485106790Ssimokawa
2486106790Ssimokawavoid
2487106790Ssimokawafwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
2488103285Sikob{
2489103285Sikob	struct fwohcidb_tr *db_tr, *fdb_tr;
2490103285Sikob	struct fwohci_dbch *dbch;
2491120660Ssimokawa	struct fwohcidb *db;
2492103285Sikob	struct fw_pkt *fp;
2493120660Ssimokawa	struct fwohci_txpkthdr *ohcifp;
2494103285Sikob	unsigned short chtag;
2495103285Sikob	int idb;
2496103285Sikob
2497170374Ssimokawa	FW_GLOCK_ASSERT(&sc->fc);
2498170374Ssimokawa
2499103285Sikob	dbch = &sc->it[dmach];
2500103285Sikob	chtag = sc->it[dmach].xferq.flag & 0xff;
2501103285Sikob
2502103285Sikob	db_tr = (struct fwohcidb_tr *)(bulkxfer->start);
2503103285Sikob	fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end);
2504103285Sikob/*
2505113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr);
2506103285Sikob*/
2507272214Skan	for (idb = 0; idb < dbch->xferq.bnpacket; idb++) {
2508109892Ssimokawa		db = db_tr->db;
2509103285Sikob		fp = (struct fw_pkt *)db_tr->buf;
2510120660Ssimokawa		ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed;
2511113584Ssimokawa		ohcifp->mode.ld[0] = fp->mode.ld[0];
2512119155Ssimokawa		ohcifp->mode.common.spd = 0 & 0x7;
2513113584Ssimokawa		ohcifp->mode.stream.len = fp->mode.stream.len;
2514103285Sikob		ohcifp->mode.stream.chtag = chtag;
2515103285Sikob		ohcifp->mode.stream.tcode = 0xa;
2516113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
2517272214Skan		FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]);
2518272214Skan		FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]);
2519113584Ssimokawa#endif
2520103285Sikob
2521113584Ssimokawa		FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK);
2522113584Ssimokawa		FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len);
2523113584Ssimokawa		FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2524109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */
2525113584Ssimokawa		db[2].db.desc.cmd = OHCI_OUTPUT_LAST
2526103285Sikob			| OHCI_UPDATE
2527109892Ssimokawa			| OHCI_BRANCH_ALWAYS;
2528109892Ssimokawa		db[0].db.desc.depend =
2529109892Ssimokawa			= db[dbch->ndesc - 1].db.desc.depend
2530113584Ssimokawa			= STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc;
2531109892Ssimokawa#else
2532113584Ssimokawa		FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
2533113584Ssimokawa		FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc);
2534109892Ssimokawa#endif
2535103285Sikob		bulkxfer->end = (caddr_t)db_tr;
2536103285Sikob		db_tr = STAILQ_NEXT(db_tr, link);
2537103285Sikob	}
2538109892Ssimokawa	db = ((struct fwohcidb_tr *)bulkxfer->end)->db;
2539113584Ssimokawa	FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf);
2540113584Ssimokawa	FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf);
2541109892Ssimokawa#if 0 /* if bulkxfer->npackets changes */
2542109892Ssimokawa	db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2543109280Ssimokawa	/* OHCI 1.1 and above */
2544109892Ssimokawa	db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2545109892Ssimokawa#endif
2546109892Ssimokawa/*
2547103285Sikob	db_tr = (struct fwohcidb_tr *)bulkxfer->start;
2548103285Sikob	fdb_tr = (struct fwohcidb_tr *)bulkxfer->end;
2549113584Ssimokawadevice_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr);
2550103285Sikob*/
2551103285Sikob	return;
2552103285Sikob}
2553106790Ssimokawa
2554106790Ssimokawastatic int
2555113584Ssimokawafwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2556113584Ssimokawa								int poffset)
2557103285Sikob{
2558120660Ssimokawa	struct fwohcidb *db = db_tr->db;
2559113584Ssimokawa	struct fw_xferq *it;
2560103285Sikob	int err = 0;
2561113584Ssimokawa
2562113584Ssimokawa	it = &dbch->xferq;
2563272214Skan	if (it->buf == 0) {
2564103285Sikob		err = EINVAL;
2565103285Sikob		return err;
2566103285Sikob	}
2567113584Ssimokawa	db_tr->buf = fwdma_v_addr(it->buf, poffset);
2568103285Sikob	db_tr->dbcnt = 3;
2569103285Sikob
2570113584Ssimokawa	FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
2571113584Ssimokawa		OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
2572119155Ssimokawa	FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0);
2573120660Ssimokawa	bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed));
2574113584Ssimokawa	FWOHCI_DMA_WRITE(db[2].db.desc.addr,
2575129585Sdfr	fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t));
2576113584Ssimokawa
2577113584Ssimokawa	FWOHCI_DMA_WRITE(db[2].db.desc.cmd,
2578113584Ssimokawa		OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS);
2579109892Ssimokawa#if 1
2580113584Ssimokawa	FWOHCI_DMA_WRITE(db[0].db.desc.res, 0);
2581113584Ssimokawa	FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2582109892Ssimokawa#endif
2583113584Ssimokawa	return 0;
2584103285Sikob}
2585106790Ssimokawa
2586106790Ssimokawaint
2587113584Ssimokawafwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2588113584Ssimokawa		int poffset, struct fwdma_alloc *dummy_dma)
2589103285Sikob{
2590120660Ssimokawa	struct fwohcidb *db = db_tr->db;
2591113584Ssimokawa	struct fw_xferq *ir;
2592113584Ssimokawa	int i, ldesc;
2593113584Ssimokawa	bus_addr_t dbuf[2];
2594103285Sikob	int dsiz[2];
2595103285Sikob
2596113584Ssimokawa	ir = &dbch->xferq;
2597113584Ssimokawa	if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) {
2598178911Ssimokawa		if (db_tr->buf == NULL) {
2599178911Ssimokawa			db_tr->buf = fwdma_malloc_size(dbch->dmat,
2600178911Ssimokawa			    &db_tr->dma_map, ir->psize, &dbuf[0],
2601178911Ssimokawa			    BUS_DMA_NOWAIT);
2602178911Ssimokawa			if (db_tr->buf == NULL)
2603272214Skan				return (ENOMEM);
2604178911Ssimokawa		}
2605103285Sikob		db_tr->dbcnt = 1;
2606113584Ssimokawa		dsiz[0] = ir->psize;
2607113584Ssimokawa		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
2608113584Ssimokawa			BUS_DMASYNC_PREREAD);
2609113584Ssimokawa	} else {
2610113584Ssimokawa		db_tr->dbcnt = 0;
2611113584Ssimokawa		if (dummy_dma != NULL) {
2612129585Sdfr			dsiz[db_tr->dbcnt] = sizeof(uint32_t);
2613113584Ssimokawa			dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr;
2614113584Ssimokawa		}
2615113584Ssimokawa		dsiz[db_tr->dbcnt] = ir->psize;
2616113584Ssimokawa		if (ir->buf != NULL) {
2617113584Ssimokawa			db_tr->buf = fwdma_v_addr(ir->buf, poffset);
2618272214Skan			dbuf[db_tr->dbcnt] = fwdma_bus_addr(ir->buf, poffset);
2619113584Ssimokawa		}
2620113584Ssimokawa		db_tr->dbcnt++;
2621103285Sikob	}
2622272214Skan	for (i = 0; i < db_tr->dbcnt; i++) {
2623113584Ssimokawa		FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]);
2624113584Ssimokawa		FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]);
2625113584Ssimokawa		if (ir->flag & FWXFERQ_STREAM) {
2626113584Ssimokawa			FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE);
2627103285Sikob		}
2628113584Ssimokawa		FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]);
2629103285Sikob	}
2630113584Ssimokawa	ldesc = db_tr->dbcnt - 1;
2631113584Ssimokawa	if (ir->flag & FWXFERQ_STREAM) {
2632113584Ssimokawa		FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST);
2633103285Sikob	}
2634113584Ssimokawa	FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS);
2635113584Ssimokawa	return 0;
2636103285Sikob}
2637106790Ssimokawa
2638113584Ssimokawa
2639113584Ssimokawastatic int
2640113584Ssimokawafwohci_arcv_swap(struct fw_pkt *fp, int len)
2641103285Sikob{
2642113584Ssimokawa	struct fw_pkt *fp0;
2643129585Sdfr	uint32_t ld0;
2644120660Ssimokawa	int slen, hlen;
2645113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
2646113584Ssimokawa	int i;
2647113584Ssimokawa#endif
2648103285Sikob
2649113584Ssimokawa	ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]);
2650113584Ssimokawa#if 0
2651113584Ssimokawa	printf("ld0: x%08x\n", ld0);
2652113584Ssimokawa#endif
2653113584Ssimokawa	fp0 = (struct fw_pkt *)&ld0;
2654120660Ssimokawa	/* determine length to swap */
2655113584Ssimokawa	switch (fp0->mode.common.tcode) {
2656113584Ssimokawa	case FWTCODE_RREQQ:
2657113584Ssimokawa	case FWTCODE_WRES:
2658113584Ssimokawa	case FWTCODE_WREQQ:
2659113584Ssimokawa	case FWTCODE_RRESQ:
2660113584Ssimokawa	case FWOHCITCODE_PHY:
2661113584Ssimokawa		slen = 12;
2662113584Ssimokawa		break;
2663113584Ssimokawa	case FWTCODE_RREQB:
2664113584Ssimokawa	case FWTCODE_WREQB:
2665113584Ssimokawa	case FWTCODE_LREQ:
2666113584Ssimokawa	case FWTCODE_RRESB:
2667113584Ssimokawa	case FWTCODE_LRES:
2668113584Ssimokawa		slen = 16;
2669113584Ssimokawa		break;
2670113584Ssimokawa	default:
2671113584Ssimokawa		printf("Unknown tcode %d\n", fp0->mode.common.tcode);
2672272214Skan		return (0);
2673103285Sikob	}
2674120660Ssimokawa	hlen = tinfo[fp0->mode.common.tcode].hdr_len;
2675120660Ssimokawa	if (hlen > len) {
2676113584Ssimokawa		if (firewire_debug)
2677113584Ssimokawa			printf("splitted header\n");
2678272214Skan		return (-hlen);
2679103285Sikob	}
2680113584Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
2681272214Skan	for (i = 0; i < slen/4; i++)
2682113584Ssimokawa		fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
2683113584Ssimokawa#endif
2684272214Skan	return (hlen);
2685103285Sikob}
2686103285Sikob
2687103285Sikobstatic int
2688113584Ssimokawafwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp)
2689103285Sikob{
2690120660Ssimokawa	struct tcode_info *info;
2691113584Ssimokawa	int r;
2692103285Sikob
2693120660Ssimokawa	info = &tinfo[fp->mode.common.tcode];
2694129585Sdfr	r = info->hdr_len + sizeof(uint32_t);
2695120660Ssimokawa	if ((info->flag & FWTI_BLOCK_ASY) != 0)
2696129585Sdfr		r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t));
2697120660Ssimokawa
2698169132Ssimokawa	if (r == sizeof(uint32_t)) {
2699120660Ssimokawa		/* XXX */
2700110798Ssimokawa		device_printf(sc->fc.dev, "Unknown tcode %d\n",
2701110798Ssimokawa						fp->mode.common.tcode);
2702169132Ssimokawa		return (-1);
2703169132Ssimokawa	}
2704120660Ssimokawa
2705110798Ssimokawa	if (r > dbch->xferq.psize) {
2706110798Ssimokawa		device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
2707169132Ssimokawa		return (-1);
2708110798Ssimokawa		/* panic ? */
2709110798Ssimokawa	}
2710120660Ssimokawa
2711110798Ssimokawa	return r;
2712103285Sikob}
2713103285Sikob
2714106790Ssimokawastatic void
2715169132Ssimokawafwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch,
2716169132Ssimokawa    struct fwohcidb_tr *db_tr, uint32_t off, int wake)
2717113584Ssimokawa{
2718120660Ssimokawa	struct fwohcidb *db = &db_tr->db[0];
2719113584Ssimokawa
2720113584Ssimokawa	FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
2721113584Ssimokawa	FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
2722113584Ssimokawa	FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
2723113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
2724113584Ssimokawa	dbch->bottom = db_tr;
2725169132Ssimokawa
2726169132Ssimokawa	if (wake)
2727169132Ssimokawa		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
2728113584Ssimokawa}
2729113584Ssimokawa
2730113584Ssimokawastatic void
2731106790Ssimokawafwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
2732103285Sikob{
2733103285Sikob	struct fwohcidb_tr *db_tr;
2734113584Ssimokawa	struct iovec vec[2];
2735113584Ssimokawa	struct fw_pkt pktbuf;
2736113584Ssimokawa	int nvec;
2737103285Sikob	struct fw_pkt *fp;
2738129585Sdfr	uint8_t *ld;
2739169132Ssimokawa	uint32_t stat, off, status, event;
2740103285Sikob	u_int spd;
2741113584Ssimokawa	int len, plen, hlen, pcnt, offset;
2742103285Sikob	int s;
2743103285Sikob	caddr_t buf;
2744103285Sikob	int resCount;
2745103285Sikob
2746272214Skan	if (&sc->arrq == dbch) {
2747103285Sikob		off = OHCI_ARQOFF;
2748272214Skan	} else if (&sc->arrs == dbch) {
2749103285Sikob		off = OHCI_ARSOFF;
2750272214Skan	} else {
2751103285Sikob		return;
2752103285Sikob	}
2753103285Sikob
2754103285Sikob	s = splfw();
2755103285Sikob	db_tr = dbch->top;
2756103285Sikob	pcnt = 0;
2757103285Sikob	/* XXX we cannot handle a packet which lies in more than two buf */
2758113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
2759113584Ssimokawa	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
2760113584Ssimokawa	status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
2761113584Ssimokawa	resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
2762169132Ssimokawa	while (status & OHCI_CNTL_DMA_ACTIVE) {
2763113584Ssimokawa#if 0
2764169132Ssimokawa
2765169132Ssimokawa		if (off == OHCI_ARQOFF)
2766169132Ssimokawa			printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n",
2767169132Ssimokawa			    db_tr->bus_addr, status, resCount);
2768113584Ssimokawa#endif
2769113584Ssimokawa		len = dbch->xferq.psize - resCount;
2770129585Sdfr		ld = (uint8_t *)db_tr->buf;
2771113584Ssimokawa		if (dbch->pdb_tr == NULL) {
2772113584Ssimokawa			len -= dbch->buf_offset;
2773113584Ssimokawa			ld += dbch->buf_offset;
2774113584Ssimokawa		}
2775113584Ssimokawa		if (len > 0)
2776113584Ssimokawa			bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
2777113584Ssimokawa					BUS_DMASYNC_POSTREAD);
2778272214Skan		while (len > 0) {
2779106789Ssimokawa			if (count >= 0 && count-- == 0)
2780106789Ssimokawa				goto out;
2781272214Skan			if (dbch->pdb_tr != NULL) {
2782113584Ssimokawa				/* we have a fragment in previous buffer */
2783113584Ssimokawa				int rlen;
2784103285Sikob
2785113584Ssimokawa				offset = dbch->buf_offset;
2786113584Ssimokawa				if (offset < 0)
2787113584Ssimokawa					offset = - offset;
2788113584Ssimokawa				buf = dbch->pdb_tr->buf + offset;
2789113584Ssimokawa				rlen = dbch->xferq.psize - offset;
2790113584Ssimokawa				if (firewire_debug)
2791113584Ssimokawa					printf("rlen=%d, offset=%d\n",
2792113584Ssimokawa						rlen, dbch->buf_offset);
2793113584Ssimokawa				if (dbch->buf_offset < 0) {
2794113584Ssimokawa					/* splitted in header, pull up */
2795113584Ssimokawa					char *p;
2796113584Ssimokawa
2797113584Ssimokawa					p = (char *)&pktbuf;
2798113584Ssimokawa					bcopy(buf, p, rlen);
2799113584Ssimokawa					p += rlen;
2800113584Ssimokawa					/* this must be too long but harmless */
2801113584Ssimokawa					rlen = sizeof(pktbuf) - rlen;
2802113584Ssimokawa					if (rlen < 0)
2803113584Ssimokawa						printf("why rlen < 0\n");
2804113584Ssimokawa					bcopy(db_tr->buf, p, rlen);
2805103285Sikob					ld += rlen;
2806103285Sikob					len -= rlen;
2807113584Ssimokawa					hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
2808169132Ssimokawa					if (hlen <= 0) {
2809169132Ssimokawa						printf("hlen should be positive.");
2810169132Ssimokawa						goto err;
2811113584Ssimokawa					}
2812113584Ssimokawa					offset = sizeof(pktbuf);
2813113584Ssimokawa					vec[0].iov_base = (char *)&pktbuf;
2814113584Ssimokawa					vec[0].iov_len = offset;
2815113584Ssimokawa				} else {
2816113584Ssimokawa					/* splitted in payload */
2817113584Ssimokawa					offset = rlen;
2818113584Ssimokawa					vec[0].iov_base = buf;
2819113584Ssimokawa					vec[0].iov_len = rlen;
2820103285Sikob				}
2821113584Ssimokawa				fp=(struct fw_pkt *)vec[0].iov_base;
2822113584Ssimokawa				nvec = 1;
2823113584Ssimokawa			} else {
2824113584Ssimokawa				/* no fragment in previous buffer */
2825103285Sikob				fp=(struct fw_pkt *)ld;
2826113584Ssimokawa				hlen = fwohci_arcv_swap(fp, len);
2827113584Ssimokawa				if (hlen == 0)
2828169132Ssimokawa					goto err;
2829113584Ssimokawa				if (hlen < 0) {
2830113584Ssimokawa					dbch->pdb_tr = db_tr;
2831113584Ssimokawa					dbch->buf_offset = - dbch->buf_offset;
2832113584Ssimokawa					/* sanity check */
2833272214Skan					if (resCount != 0) {
2834169132Ssimokawa						printf("resCount=%d hlen=%d\n",
2835169132Ssimokawa						    resCount, hlen);
2836169132Ssimokawa						    goto err;
2837169132Ssimokawa					}
2838113584Ssimokawa					goto out;
2839103285Sikob				}
2840113584Ssimokawa				offset = 0;
2841113584Ssimokawa				nvec = 0;
2842113584Ssimokawa			}
2843113584Ssimokawa			plen = fwohci_get_plen(sc, dbch, fp) - offset;
2844113584Ssimokawa			if (plen < 0) {
2845113584Ssimokawa				/* minimum header size + trailer
2846113584Ssimokawa				= sizeof(fw_pkt) so this shouldn't happens */
2847120660Ssimokawa				printf("plen(%d) is negative! offset=%d\n",
2848120660Ssimokawa				    plen, offset);
2849169132Ssimokawa				goto err;
2850113584Ssimokawa			}
2851113584Ssimokawa			if (plen > 0) {
2852113584Ssimokawa				len -= plen;
2853113584Ssimokawa				if (len < 0) {
2854113584Ssimokawa					dbch->pdb_tr = db_tr;
2855113584Ssimokawa					if (firewire_debug)
2856113584Ssimokawa						printf("splitted payload\n");
2857113584Ssimokawa					/* sanity check */
2858272214Skan					if (resCount != 0) {
2859169132Ssimokawa						printf("resCount=%d plen=%d"
2860169132Ssimokawa						    " len=%d\n",
2861169132Ssimokawa						    resCount, plen, len);
2862169132Ssimokawa						goto err;
2863169132Ssimokawa					}
2864113584Ssimokawa					goto out;
2865103285Sikob				}
2866113584Ssimokawa				vec[nvec].iov_base = ld;
2867113584Ssimokawa				vec[nvec].iov_len = plen;
2868272214Skan				nvec++;
2869103285Sikob				ld += plen;
2870103285Sikob			}
2871129585Sdfr			dbch->buf_offset = ld - (uint8_t *)db_tr->buf;
2872113584Ssimokawa			if (nvec == 0)
2873113584Ssimokawa				printf("nvec == 0\n");
2874113584Ssimokawa
2875103285Sikob/* DMA result-code will be written at the tail of packet */
2876169132Ssimokawa			stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer)));
2877110577Ssimokawa#if 0
2878120660Ssimokawa			printf("plen: %d, stat %x\n",
2879120660Ssimokawa			    plen ,stat);
2880103285Sikob#endif
2881169132Ssimokawa			spd = (stat >> 21) & 0x3;
2882169132Ssimokawa			event = (stat >> 16) & 0x1f;
2883169132Ssimokawa			switch (event) {
2884113584Ssimokawa			case FWOHCIEV_ACKPEND:
2885113584Ssimokawa#if 0
2886113584Ssimokawa				printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
2887113584Ssimokawa#endif
2888113584Ssimokawa				/* fall through */
2889113584Ssimokawa			case FWOHCIEV_ACKCOMPL:
2890120660Ssimokawa			{
2891120660Ssimokawa				struct fw_rcv_buf rb;
2892120660Ssimokawa
2893113584Ssimokawa				if ((vec[nvec-1].iov_len -=
2894113584Ssimokawa					sizeof(struct fwohci_trailer)) == 0)
2895272214Skan					nvec--;
2896120660Ssimokawa				rb.fc = &sc->fc;
2897120660Ssimokawa				rb.vec = vec;
2898120660Ssimokawa				rb.nvec = nvec;
2899120660Ssimokawa				rb.spd = spd;
2900120660Ssimokawa				fw_rcv(&rb);
2901120660Ssimokawa				break;
2902120660Ssimokawa			}
2903113584Ssimokawa			case FWOHCIEV_BUSRST:
2904170425Ssimokawa				if ((sc->fc.status != FWBUSRESET) &&
2905170425Ssimokawa				    (sc->fc.status != FWBUSINIT))
2906113584Ssimokawa					printf("got BUSRST packet!?\n");
2907113584Ssimokawa				break;
2908113584Ssimokawa			default:
2909169132Ssimokawa				device_printf(sc->fc.dev,
2910169132Ssimokawa				    "Async DMA Receive error err=%02x %s"
2911169132Ssimokawa				    " plen=%d offset=%d len=%d status=0x%08x"
2912169132Ssimokawa				    " tcode=0x%x, stat=0x%08x\n",
2913169132Ssimokawa				    event, fwohcicode[event], plen,
2914169132Ssimokawa				    dbch->buf_offset, len,
2915169132Ssimokawa				    OREAD(sc, OHCI_DMACTL(off)),
2916169132Ssimokawa				    fp->mode.common.tcode, stat);
2917169132Ssimokawa#if 1 /* XXX */
2918169132Ssimokawa				goto err;
2919103285Sikob#endif
2920113584Ssimokawa				break;
2921103285Sikob			}
2922272214Skan			pcnt++;
2923113584Ssimokawa			if (dbch->pdb_tr != NULL) {
2924169132Ssimokawa				fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr,
2925169132Ssimokawa				    off, 1);
2926113584Ssimokawa				dbch->pdb_tr = NULL;
2927113584Ssimokawa			}
2928113584Ssimokawa
2929113584Ssimokawa		}
2930103285Sikobout:
2931103285Sikob		if (resCount == 0) {
2932103285Sikob			/* done on this buffer */
2933113584Ssimokawa			if (dbch->pdb_tr == NULL) {
2934169132Ssimokawa				fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1);
2935113584Ssimokawa				dbch->buf_offset = 0;
2936113584Ssimokawa			} else
2937113584Ssimokawa				if (dbch->pdb_tr != db_tr)
2938113584Ssimokawa					printf("pdb_tr != db_tr\n");
2939103285Sikob			db_tr = STAILQ_NEXT(db_tr, link);
2940113584Ssimokawa			status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2941113584Ssimokawa						>> OHCI_STATUS_SHIFT;
2942113584Ssimokawa			resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2943113584Ssimokawa						& OHCI_COUNT_MASK;
2944113584Ssimokawa			/* XXX check buffer overrun */
2945103285Sikob			dbch->top = db_tr;
2946103285Sikob		} else {
2947103285Sikob			dbch->buf_offset = dbch->xferq.psize - resCount;
2948103285Sikob			break;
2949103285Sikob		}
2950103285Sikob		/* XXX make sure DMA is not dead */
2951103285Sikob	}
2952103285Sikob#if 0
2953103285Sikob	if (pcnt < 1)
2954103285Sikob		printf("fwohci_arcv: no packets\n");
2955103285Sikob#endif
2956103285Sikob	splx(s);
2957169132Ssimokawa	return;
2958169132Ssimokawa
2959169132Ssimokawaerr:
2960169132Ssimokawa	device_printf(sc->fc.dev, "AR DMA status=%x, ",
2961169132Ssimokawa					OREAD(sc, OHCI_DMACTL(off)));
2962169132Ssimokawa	dbch->pdb_tr = NULL;
2963169132Ssimokawa	/* skip until resCount != 0 */
2964169132Ssimokawa	printf(" skip buffer");
2965169132Ssimokawa	while (resCount == 0) {
2966169132Ssimokawa		printf(" #");
2967169132Ssimokawa		fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0);
2968169132Ssimokawa		db_tr = STAILQ_NEXT(db_tr, link);
2969169132Ssimokawa		resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2970169132Ssimokawa						& OHCI_COUNT_MASK;
2971188584Ssbruno	}
2972169132Ssimokawa	printf(" done\n");
2973169132Ssimokawa	dbch->top = db_tr;
2974169132Ssimokawa	dbch->buf_offset = dbch->xferq.psize - resCount;
2975169132Ssimokawa	OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
2976169132Ssimokawa	splx(s);
2977103285Sikob}
2978