1/*	$NetBSD: fwohci.c,v 1.152 2023/08/10 20:49:20 mrg Exp $	*/
2
3/*-
4 * Copyright (c) 2003 Hidetoshi Shimokawa
5 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the acknowledgement as bellow:
18 *
19 *    This product includes software developed by K. Kobayashi and H. Shimokawa
20 *
21 * 4. The name of the author may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * $FreeBSD: src/sys/dev/firewire/fwohci.c,v 1.98 2009/02/13 17:44:07 sbruno Exp $
37 *
38 */
39#include <sys/cdefs.h>
40__KERNEL_RCSID(0, "$NetBSD: fwohci.c,v 1.152 2023/08/10 20:49:20 mrg Exp $");
41
42#include <sys/param.h>
43#include <sys/atomic.h>
44#include <sys/bus.h>
45#include <sys/device.h>
46#include <sys/errno.h>
47#include <sys/conf.h>
48#include <sys/kernel.h>
49#include <sys/malloc.h>
50#include <sys/mbuf.h>
51#include <sys/proc.h>
52#include <sys/reboot.h>
53#include <sys/select.h>
54#include <sys/sysctl.h>
55#include <sys/systm.h>
56
57#include <dev/ieee1394/firewire.h>
58#include <dev/ieee1394/firewirereg.h>
59#include <dev/ieee1394/fwdma.h>
60#include <dev/ieee1394/fwohcireg.h>
61#include <dev/ieee1394/fwohcivar.h>
62#include <dev/ieee1394/firewire_phy.h>
63
64#include "ioconf.h"
65
66#undef OHCI_DEBUG
67
68static int nocyclemaster = 0;
69int firewire_phydma_enable = 1;
70/*
71 * Setup sysctl(3) MIB, hw.fwohci.*
72 *
73 * TBD condition CTLFLAG_PERMANENT on being a module or not
74 */
75SYSCTL_SETUP(sysctl_fwohci, "sysctl fwohci(4) subtree setup")
76{
77	int rc, fwohci_node_num;
78	const struct sysctlnode *node;
79
80	if ((rc = sysctl_createv(clog, 0, NULL, &node,
81	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "fwohci",
82	    SYSCTL_DESCR("fwohci controls"),
83	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
84		goto err;
85	}
86	fwohci_node_num = node->sysctl_num;
87
88	/* fwohci no cyclemaster flag */
89	if ((rc = sysctl_createv(clog, 0, NULL, &node,
90	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
91	    "nocyclemaster", SYSCTL_DESCR("Do not send cycle start packets"),
92	    NULL, 0, &nocyclemaster,
93	    0, CTL_HW, fwohci_node_num, CTL_CREATE, CTL_EOL)) != 0) {
94		goto err;
95	}
96
97	/* fwohci physical request DMA enable */
98	if ((rc = sysctl_createv(clog, 0, NULL, &node,
99	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "phydma_enable",
100	    SYSCTL_DESCR("Allow physical request DMA from firewire"),
101	    NULL, 0, &firewire_phydma_enable,
102	    0, CTL_HW, fwohci_node_num, CTL_CREATE, CTL_EOL)) != 0) {
103		goto err;
104	}
105	return;
106
107err:
108	aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
109}
110
111static const char * const dbcode[16] = {
112    "OUTM", "OUTL", "INPM", "INPL", "STOR", "LOAD", "NOP ", "STOP",
113    "", "", "", "", "", "", "", ""
114};
115
116static const char * const dbkey[8] = {
117    "ST0", "ST1", "ST2", "ST3", "UNDEF", "REG", "SYS", "DEV"
118};
119
120static const char * const dbcond[4] = { "NEV", "C=1", "C=0", "ALL" };
121static const char * const fwohcicode[32] = {
122	"No stat",	"Undef",	"long",		"miss Ack err",
123	"FIFO underrun","FIFO overrun",	"desc err",	"data read err",
124	"data write err","bus reset",	"timeout",	"tcode err",
125	"Undef",	"Undef",	"unknown event","flushed",
126	"Undef",	"ack complete",	"ack pend",	"Undef",
127	"ack busy_X",	"ack busy_A",	"ack busy_B",	"Undef",
128	"Undef",	"Undef",	"Undef",	"ack tardy",
129	"Undef",	"ack data_err",	"ack type_err",	""
130};
131
132#define MAX_SPEED 3
133extern const char *fw_linkspeed[];
134static uint32_t const tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31 };
135
136static const struct tcode_info tinfo[] = {
137/*		hdr_len block 	flag	valid_response */
138/* 0 WREQQ  */ { 16,	FWTI_REQ | FWTI_TLABEL, FWTCODE_WRES },
139/* 1 WREQB  */ { 16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES },
140/* 2 WRES   */ { 12,	FWTI_RES, 0xff },
141/* 3 XXX    */ {  0,	0, 0xff },
142/* 4 RREQQ  */ { 12,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ },
143/* 5 RREQB  */ { 16,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB },
144/* 6 RRESQ  */ { 16,	FWTI_RES, 0xff },
145/* 7 RRESB  */ { 16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff },
146/* 8 CYCS   */ {  0,	0, 0xff },
147/* 9 LREQ   */ { 16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES },
148/* a STREAM */ {  4,	FWTI_REQ | FWTI_BLOCK_STR, 0xff },
149/* b LRES   */ { 16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff },
150/* c XXX    */ {  0,	0, 0xff },
151/* d XXX    */ {  0,	0, 0xff },
152/* e PHY    */ { 12,	FWTI_REQ, 0xff },
153/* f XXX    */ {  0,	0, 0xff }
154};
155
156#define OHCI_WRITE_SIGMASK 0xffff0000
157#define OHCI_READ_SIGMASK 0xffff0000
158
159
160int fwohci_print(void *, const char *);
161
162static int fwohci_ioctl(dev_t, u_long, void *, int, struct lwp *);
163
164static uint32_t fwohci_cyctimer(struct firewire_comm *);
165static uint32_t fwohci_set_bus_manager(struct firewire_comm *, u_int);
166static void fwohci_ibr(struct firewire_comm *);
167static int fwohci_irx_enable(struct firewire_comm *, int);
168static int fwohci_irx_disable(struct firewire_comm *, int);
169static int fwohci_itxbuf_enable(struct firewire_comm *, int);
170static int fwohci_itx_disable(struct firewire_comm *, int);
171static void fwohci_timeout(struct firewire_comm *fc);
172#if BYTE_ORDER == BIG_ENDIAN
173static void fwohci_irx_post(struct firewire_comm *, uint32_t *);
174#endif
175static void fwohci_set_intr(struct firewire_comm *, int);
176
177static uint32_t fwphy_rddata(struct fwohci_softc *, uint32_t);
178static uint32_t fwphy_wrdata(struct fwohci_softc *, uint32_t, uint32_t);
179static int fwohci_probe_phy(struct fwohci_softc *);
180static void fwohci_reset(struct fwohci_softc *);
181static void fwohci_execute_db(struct fwohcidb_tr *, bus_dmamap_t);
182static void fwohci_start(struct fwohci_softc *, struct fwohci_dbch *);
183static void fwohci_start_atq(struct firewire_comm *);
184static void fwohci_start_ats(struct firewire_comm *);
185static void fwohci_txd(struct fwohci_softc *, struct fwohci_dbch *);
186static void fwohci_db_free(struct fwohci_softc *, struct fwohci_dbch *);
187static void fwohci_db_init(struct fwohci_softc *, struct fwohci_dbch *);
188static int fwohci_rx_enable(struct fwohci_softc *, struct fwohci_dbch *);
189static int fwohci_tx_enable(struct fwohci_softc *, struct fwohci_dbch *);
190static int fwohci_next_cycle(struct fwohci_softc *, int);
191#ifdef OHCI_DEBUG
192static void fwohci_dump_intr(struct fwohci_softc *, uint32_t);
193#endif
194static void fwohci_intr_core(struct fwohci_softc *, uint32_t);
195static void fwohci_intr_dma(struct fwohci_softc *, uint32_t);
196static void fwohci_task_sid(struct fwohci_softc *);
197static void fwohci_task_dma(struct fwohci_softc *);
198static void fwohci_tbuf_update(struct fwohci_softc *, int);
199static void fwohci_rbuf_update(struct fwohci_softc *, int);
200static void dump_dma(struct fwohci_softc *, uint32_t);
201static void dump_db(struct fwohci_softc *, uint32_t);
202static void print_db(struct fwohcidb_tr *, struct fwohcidb *, uint32_t,
203		     uint32_t);
204static void fwohci_txbufdb(struct fwohci_softc *, int, struct fw_bulkxfer *);
205static int fwohci_add_tx_buf(struct fwohci_dbch *, struct fwohcidb_tr *, int);
206static int fwohci_add_rx_buf(struct fwohci_dbch *, struct fwohcidb_tr *, int,
207			     struct fwdma_alloc *);
208static int fwohci_arcv_swap(struct fw_pkt *, int);
209static int fwohci_get_plen(struct fwohci_softc *, struct fwohci_dbch *,
210			   struct fw_pkt *);
211static void fwohci_arcv_free_buf(struct fwohci_softc *, struct fwohci_dbch *,
212				 struct fwohcidb_tr *, int);
213static void fwohci_arcv(struct fwohci_softc *, struct fwohci_dbch *);
214
215
216/*
217 * memory allocated for DMA programs
218 */
219#define DMA_PROG_ALLOC		(8 * PAGE_SIZE)
220
221#define NDB FWMAXQUEUE
222
223#define	OHCI_VERSION		0x000
224#define	OHCI_ATRETRY		0x008
225#define	OHCI_CROMHDR		0x018
226#define	OHCI_BUS_OPT		0x020
227#define	OHCI_BUSIRMC		(1U << 31)
228#define	OHCI_BUSCMC		(1 << 30)
229#define	OHCI_BUSISC		(1 << 29)
230#define	OHCI_BUSBMC		(1 << 28)
231#define	OHCI_BUSPMC		(1 << 27)
232#define OHCI_BUSFNC \
233	(OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC | OHCI_BUSBMC | OHCI_BUSPMC)
234
235#define	OHCI_EUID_HI		0x024
236#define	OHCI_EUID_LO		0x028
237
238#define	OHCI_CROMPTR		0x034
239#define	OHCI_HCCCTL		0x050
240#define	OHCI_HCCCTLCLR		0x054
241#define	OHCI_AREQHI		0x100
242#define	OHCI_AREQHICLR		0x104
243#define	OHCI_AREQLO		0x108
244#define	OHCI_AREQLOCLR		0x10c
245#define	OHCI_PREQHI		0x110
246#define	OHCI_PREQHICLR		0x114
247#define	OHCI_PREQLO		0x118
248#define	OHCI_PREQLOCLR		0x11c
249#define	OHCI_PREQUPPER		0x120
250
251#define	OHCI_SID_BUF		0x064
252#define	OHCI_SID_CNT		0x068
253#define OHCI_SID_ERR		(1U << 31)
254#define OHCI_SID_CNT_MASK	0xffc
255
256#define	OHCI_IT_STAT		0x090
257#define	OHCI_IT_STATCLR		0x094
258#define	OHCI_IT_MASK		0x098
259#define	OHCI_IT_MASKCLR		0x09c
260
261#define	OHCI_IR_STAT		0x0a0
262#define	OHCI_IR_STATCLR		0x0a4
263#define	OHCI_IR_MASK		0x0a8
264#define	OHCI_IR_MASKCLR		0x0ac
265
266#define	OHCI_LNKCTL		0x0e0
267#define	OHCI_LNKCTLCLR		0x0e4
268
269#define	OHCI_PHYACCESS		0x0ec
270#define	OHCI_CYCLETIMER		0x0f0
271
272#define	OHCI_DMACTL(off)	(off)
273#define	OHCI_DMACTLCLR(off)	(off + 0x04)
274#define	OHCI_DMACMD(off)	(off + 0x0c)
275#define	OHCI_DMAMATCH(off)	(off + 0x10)
276
277#define OHCI_ATQOFF		0x180
278#define OHCI_ATQCTL		OHCI_ATQOFF
279#define OHCI_ATQCTLCLR		(OHCI_ATQOFF + 0x04)
280#define OHCI_ATQCMD		(OHCI_ATQOFF + 0x0c)
281#define OHCI_ATQMATCH		(OHCI_ATQOFF + 0x10)
282
283#define OHCI_ATSOFF		0x1a0
284#define OHCI_ATSCTL		OHCI_ATSOFF
285#define OHCI_ATSCTLCLR		(OHCI_ATSOFF + 0x04)
286#define OHCI_ATSCMD		(OHCI_ATSOFF + 0x0c)
287#define OHCI_ATSMATCH		(OHCI_ATSOFF + 0x10)
288
289#define OHCI_ARQOFF		0x1c0
290#define OHCI_ARQCTL		OHCI_ARQOFF
291#define OHCI_ARQCTLCLR		(OHCI_ARQOFF + 0x04)
292#define OHCI_ARQCMD		(OHCI_ARQOFF + 0x0c)
293#define OHCI_ARQMATCH		(OHCI_ARQOFF + 0x10)
294
295#define OHCI_ARSOFF		0x1e0
296#define OHCI_ARSCTL		OHCI_ARSOFF
297#define OHCI_ARSCTLCLR		(OHCI_ARSOFF + 0x04)
298#define OHCI_ARSCMD		(OHCI_ARSOFF + 0x0c)
299#define OHCI_ARSMATCH		(OHCI_ARSOFF + 0x10)
300
301#define OHCI_ITOFF(CH)		(0x200 + 0x10 * (CH))
302#define OHCI_ITCTL(CH)		(OHCI_ITOFF(CH))
303#define OHCI_ITCTLCLR(CH)	(OHCI_ITOFF(CH) + 0x04)
304#define OHCI_ITCMD(CH)		(OHCI_ITOFF(CH) + 0x0c)
305
306#define OHCI_IROFF(CH)		(0x400 + 0x20 * (CH))
307#define OHCI_IRCTL(CH)		(OHCI_IROFF(CH))
308#define OHCI_IRCTLCLR(CH)	(OHCI_IROFF(CH) + 0x04)
309#define OHCI_IRCMD(CH)		(OHCI_IROFF(CH) + 0x0c)
310#define OHCI_IRMATCH(CH)	(OHCI_IROFF(CH) + 0x10)
311
312#define ATRQ_CH	 0
313#define ATRS_CH	 1
314#define ARRQ_CH	 2
315#define ARRS_CH	 3
316#define ITX_CH	 4
317#define IRX_CH	36
318
319
320/*
321 * Call fwohci_init before fwohci_attach to initialize the kernel's
322 * data structures well enough that fwohci_detach won't crash, even if
323 * fwohci_attach fails.
324 */
325
326void
327fwohci_init(struct fwohci_softc *sc)
328{
329	sc->fc.arq = &sc->arrq.xferq;
330	sc->fc.ars = &sc->arrs.xferq;
331	sc->fc.atq = &sc->atrq.xferq;
332	sc->fc.ats = &sc->atrs.xferq;
333
334	sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
335	sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
336	sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
337	sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
338
339	sc->arrq.xferq.start = NULL;
340	sc->arrs.xferq.start = NULL;
341	sc->atrq.xferq.start = fwohci_start_atq;
342	sc->atrs.xferq.start = fwohci_start_ats;
343
344	sc->arrq.xferq.buf = NULL;
345	sc->arrs.xferq.buf = NULL;
346	sc->atrq.xferq.buf = NULL;
347	sc->atrs.xferq.buf = NULL;
348
349	sc->arrq.xferq.dmach = -1;
350	sc->arrs.xferq.dmach = -1;
351	sc->atrq.xferq.dmach = -1;
352	sc->atrs.xferq.dmach = -1;
353
354	sc->arrq.ndesc = 1;
355	sc->arrs.ndesc = 1;
356	sc->atrq.ndesc = 8;	/* equal to maximum of mbuf chains */
357	sc->atrs.ndesc = 2;
358
359	sc->arrq.ndb = NDB;
360	sc->arrs.ndb = NDB / 2;
361	sc->atrq.ndb = NDB;
362	sc->atrs.ndb = NDB / 2;
363
364	sc->arrq.off = OHCI_ARQOFF;
365	sc->arrs.off = OHCI_ARSOFF;
366	sc->atrq.off = OHCI_ATQOFF;
367	sc->atrs.off = OHCI_ATSOFF;
368
369	sc->fc.tcode = tinfo;
370
371	sc->fc.cyctimer = fwohci_cyctimer;
372	sc->fc.ibr = fwohci_ibr;
373	sc->fc.set_bmr = fwohci_set_bus_manager;
374	sc->fc.ioctl = fwohci_ioctl;
375	sc->fc.irx_enable = fwohci_irx_enable;
376	sc->fc.irx_disable = fwohci_irx_disable;
377
378	sc->fc.itx_enable = fwohci_itxbuf_enable;
379	sc->fc.itx_disable = fwohci_itx_disable;
380	sc->fc.timeout = fwohci_timeout;
381	sc->fc.set_intr = fwohci_set_intr;
382#if BYTE_ORDER == BIG_ENDIAN
383	sc->fc.irx_post = fwohci_irx_post;
384#else
385	sc->fc.irx_post = NULL;
386#endif
387	sc->fc.itx_post = NULL;
388
389	sc->intmask = sc->irstat = sc->itstat = 0;
390
391	fw_init(&sc->fc);
392}
393
394/*
395 * Call fwohci_attach after fwohci_init to initialize the hardware and
396 * attach children.
397 */
398
399int
400fwohci_attach(struct fwohci_softc *sc)
401{
402	uint32_t reg;
403	uint8_t ui[8];
404	int i, mver;
405
406/* OHCI version */
407	reg = OREAD(sc, OHCI_VERSION);
408	mver = (reg >> 16) & 0xff;
409	aprint_normal_dev(sc->fc.dev, "OHCI version %x.%x (ROM=%d)\n",
410	    mver, reg & 0xff, (reg >> 24) & 1);
411	if (mver < 1 || mver > 9) {
412		aprint_error_dev(sc->fc.dev, "invalid OHCI version\n");
413		return ENXIO;
414	}
415
416/* Available Isochronous DMA channel probe */
417	OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
418	OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
419	reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
420	OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
421	OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
422	for (i = 0; i < 0x20; i++)
423		if ((reg & (1 << i)) == 0)
424			break;
425	sc->fc.nisodma = i;
426	aprint_normal_dev(sc->fc.dev, "No. of Isochronous channels is %d.\n",
427	    i);
428	if (i == 0)
429		return ENXIO;
430
431	for (i = 0; i < sc->fc.nisodma; i++) {
432		sc->fc.it[i] = &sc->it[i].xferq;
433		sc->fc.ir[i] = &sc->ir[i].xferq;
434		sc->it[i].xferq.dmach = i;
435		sc->ir[i].xferq.dmach = i;
436		sc->it[i].ndb = 0;
437		sc->ir[i].ndb = 0;
438		sc->it[i].off = OHCI_ITOFF(i);
439		sc->ir[i].off = OHCI_IROFF(i);
440	}
441
442	fw_init_isodma(&sc->fc);
443
444	sc->fc.config_rom = fwdma_alloc_setup(sc->fc.dev, sc->fc.dmat,
445	    CROMSIZE, &sc->crom_dma, CROMSIZE, BUS_DMA_NOWAIT);
446	if (sc->fc.config_rom == NULL) {
447		aprint_error_dev(sc->fc.dev, "config_rom alloc failed.\n");
448		return ENOMEM;
449	}
450
451#if 0
452	memset(sc->fc.config_rom, 0, CROMSIZE);
453	sc->fc.config_rom[1] = 0x31333934;
454	sc->fc.config_rom[2] = 0xf000a002;
455	sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
456	sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO);
457	sc->fc.config_rom[5] = 0;
458	sc->fc.config_rom[0] = (4 << 24) | (5 << 16);
459
460	sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4);
461#endif
462
463/* SID receive buffer must align 2^11 */
464#define	OHCI_SIDSIZE	(1 << 11)
465	sc->sid_buf = fwdma_alloc_setup(sc->fc.dev, sc->fc.dmat, OHCI_SIDSIZE,
466	    &sc->sid_dma, OHCI_SIDSIZE, BUS_DMA_NOWAIT);
467	if (sc->sid_buf == NULL) {
468		aprint_error_dev(sc->fc.dev, "sid_buf alloc failed.");
469		return ENOMEM;
470	}
471
472	fwdma_alloc_setup(sc->fc.dev, sc->fc.dmat, sizeof(uint32_t),
473	    &sc->dummy_dma, sizeof(uint32_t), BUS_DMA_NOWAIT);
474	if (sc->dummy_dma.v_addr == NULL) {
475		aprint_error_dev(sc->fc.dev, "dummy_dma alloc failed.");
476		return ENOMEM;
477	}
478
479	fwohci_db_init(sc, &sc->arrq);
480	if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0)
481		return ENOMEM;
482
483	fwohci_db_init(sc, &sc->arrs);
484	if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0)
485		return ENOMEM;
486
487	fwohci_db_init(sc, &sc->atrq);
488	if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0)
489		return ENOMEM;
490
491	fwohci_db_init(sc, &sc->atrs);
492	if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0)
493		return ENOMEM;
494
495	sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H);
496	sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L);
497	for (i = 0; i < 8; i++)
498		ui[i] = FW_EUI64_BYTE(&sc->fc.eui, i);
499	aprint_normal_dev(sc->fc.dev,
500	    "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
501	    ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]);
502
503	fwohci_reset(sc);
504
505	sc->fc.bdev =
506	    config_found(sc->fc.dev, __UNCONST("ieee1394if"), fwohci_print,
507	    CFARGS_NONE);
508
509	return 0;
510}
511
512int
513fwohci_detach(struct fwohci_softc *sc, int flags)
514{
515	int i, rv;
516
517	if (sc->fc.bdev != NULL) {
518		rv = config_detach(sc->fc.bdev, flags);
519		if (rv)
520			return rv;
521	}
522	if (sc->sid_buf != NULL)
523		fwdma_free(sc->sid_dma.dma_tag, sc->sid_dma.dma_map,
524		    sc->sid_dma.v_addr);
525	if (sc->fc.config_rom != NULL)
526		fwdma_free(sc->crom_dma.dma_tag, sc->crom_dma.dma_map,
527		    sc->crom_dma.v_addr);
528
529	fwohci_db_free(sc, &sc->arrq);
530	fwohci_db_free(sc, &sc->arrs);
531	fwohci_db_free(sc, &sc->atrq);
532	fwohci_db_free(sc, &sc->atrs);
533	for (i = 0; i < sc->fc.nisodma; i++) {
534		fwohci_db_free(sc, &sc->it[i]);
535		fwohci_db_free(sc, &sc->ir[i]);
536	}
537
538	fw_destroy_isodma(&sc->fc);
539	fw_destroy(&sc->fc);
540
541	return 0;
542}
543
544int
545fwohci_intr(void *arg)
546{
547	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
548	uint32_t stat, irstat, itstat;
549
550	if (!device_is_active(sc->fc.dev))
551		return 0;
552
553	if (!(sc->intmask & OHCI_INT_EN))
554		/* polling mode? */
555		return 0;
556
557	stat = OREAD(sc, FWOHCI_INTSTAT);
558	if (stat == 0xffffffff) {
559		aprint_error_dev(sc->fc.dev, "device physically ejected?\n");
560		return 0;
561	}
562	if (stat)
563		OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R);
564
565	stat &= sc->intmask;
566	if (stat == 0)
567		return 0;
568
569	atomic_swap_32(&sc->intstat, stat);
570	if (stat & OHCI_INT_DMA_IR) {
571		irstat = OREAD(sc, OHCI_IR_STAT);
572		OWRITE(sc, OHCI_IR_STATCLR, irstat);
573		atomic_swap_32(&sc->irstat, irstat);
574	}
575	if (stat & OHCI_INT_DMA_IT) {
576		itstat = OREAD(sc, OHCI_IT_STAT);
577		OWRITE(sc, OHCI_IT_STATCLR, itstat);
578		atomic_swap_32(&sc->itstat, itstat);
579	}
580
581	fwohci_intr_core(sc, stat);
582	return 1;
583}
584
585int
586fwohci_resume(struct fwohci_softc *sc)
587{
588	struct fw_xferq *ir;
589	struct fw_bulkxfer *chunk;
590	int i;
591	extern int firewire_resume(struct firewire_comm *);
592
593	fwohci_reset(sc);
594	/* XXX resume isochronous receive automatically. (how about TX?) */
595	for (i = 0; i < sc->fc.nisodma; i++) {
596		ir = &sc->ir[i].xferq;
597		if ((ir->flag & FWXFERQ_RUNNING) != 0) {
598			aprint_normal_dev(sc->fc.dev,
599			    "resume iso receive ch: %d\n", i);
600			ir->flag &= ~FWXFERQ_RUNNING;
601			/* requeue stdma to stfree */
602			while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
603				STAILQ_REMOVE_HEAD(&ir->stdma, link);
604				STAILQ_INSERT_TAIL(&ir->stfree, chunk, link);
605			}
606			sc->fc.irx_enable(&sc->fc, i);
607		}
608	}
609
610	firewire_resume(&sc->fc);
611	sc->fc.ibr(&sc->fc);
612	return 0;
613}
614
615int
616fwohci_stop(struct fwohci_softc *sc)
617{
618	u_int i;
619
620	fwohci_set_intr(&sc->fc, 0);
621
622/* Now stopping all DMA channel */
623	OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
624	OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
625	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
626	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
627
628	for (i = 0; i < sc->fc.nisodma; i++) {
629		OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
630		OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
631	}
632
633#if 0 /* Let dcons(4) be accessed */
634/* Stop interrupt */
635	OWRITE(sc, FWOHCI_INTMASKCLR,
636	    OHCI_INT_EN |
637	    OHCI_INT_ERR |
638	    OHCI_INT_PHY_SID |
639	    OHCI_INT_PHY_INT |
640	    OHCI_INT_DMA_ATRQ |
641	    OHCI_INT_DMA_ATRS |
642	    OHCI_INT_DMA_PRRQ |
643	    OHCI_INT_DMA_PRRS |
644	    OHCI_INT_DMA_ARRQ |
645	    OHCI_INT_DMA_ARRS |
646	    OHCI_INT_PHY_BUS_R);
647
648/* FLUSH FIFO and reset Transmitter/Receiver */
649	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
650#endif
651
652/* XXX Link down?  Bus reset? */
653	return 0;
654}
655
656
657static int
658fwohci_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td)
659{
660	struct fwohci_softc *sc;
661	struct fw_reg_req_t *reg = (struct fw_reg_req_t *)data;
662	uint32_t *dmach = (uint32_t *)data;
663	int err = 0;
664
665	sc = device_lookup_private(&fwohci_cd, DEV2UNIT(dev));
666	if (sc == NULL)
667		return ENXIO;
668
669	if (!data)
670		return EINVAL;
671
672	switch (cmd) {
673	case FWOHCI_WRREG:
674#define OHCI_MAX_REG 0x800
675		if (reg->addr <= OHCI_MAX_REG) {
676			OWRITE(sc, reg->addr, reg->data);
677			reg->data = OREAD(sc, reg->addr);
678		} else
679			err = EINVAL;
680		break;
681
682	case FWOHCI_RDREG:
683		if (reg->addr <= OHCI_MAX_REG)
684			reg->data = OREAD(sc, reg->addr);
685		else
686			err = EINVAL;
687		break;
688
689/* Read DMA descriptors for debug  */
690	case DUMPDMA:
691		if (*dmach <= OHCI_MAX_DMA_CH) {
692			dump_dma(sc, *dmach);
693			dump_db(sc, *dmach);
694		} else
695			err = EINVAL;
696		break;
697
698/* Read/Write Phy registers */
699#define OHCI_MAX_PHY_REG 0xf
700	case FWOHCI_RDPHYREG:
701		if (reg->addr <= OHCI_MAX_PHY_REG)
702			reg->data = fwphy_rddata(sc, reg->addr);
703		else
704			err = EINVAL;
705		break;
706
707	case FWOHCI_WRPHYREG:
708		if (reg->addr <= OHCI_MAX_PHY_REG)
709			reg->data = fwphy_wrdata(sc, reg->addr, reg->data);
710		else
711			err = EINVAL;
712		break;
713
714	default:
715		err = EINVAL;
716		break;
717	}
718	return err;
719}
720
721int
722fwohci_print(void *aux, const char *pnp)
723{
724	struct fw_attach_args *fwa = (struct fw_attach_args *)aux;
725
726	if (pnp)
727		aprint_normal("%s at %s", fwa->name, pnp);
728
729	return UNCONF;
730}
731
732
733static uint32_t
734fwohci_cyctimer(struct firewire_comm *fc)
735{
736	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
737
738	return OREAD(sc, OHCI_CYCLETIMER);
739}
740
741static uint32_t
742fwohci_set_bus_manager(struct firewire_comm *fc, u_int node)
743{
744	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
745	uint32_t bm;
746	int i;
747
748#define OHCI_CSR_DATA	0x0c
749#define OHCI_CSR_COMP	0x10
750#define OHCI_CSR_CONT	0x14
751#define OHCI_BUS_MANAGER_ID	0
752
753	OWRITE(sc, OHCI_CSR_DATA, node);
754	OWRITE(sc, OHCI_CSR_COMP, 0x3f);
755	OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID);
756 	for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1U <<31)) && (i < 1000); i++)
757		DELAY(10);
758	bm = OREAD(sc, OHCI_CSR_DATA);
759	if ((bm & 0x3f) == 0x3f)
760		bm = node;
761	if (firewire_debug)
762		printf("fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i);
763
764	return bm;
765}
766
767static void
768fwohci_ibr(struct firewire_comm *fc)
769{
770	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
771	uint32_t fun;
772
773	aprint_normal_dev(fc->dev, "Initiate bus reset\n");
774
775	/*
776	 * Make sure our cached values from the config rom are
777	 * initialised.
778	 */
779	OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
780	OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
781
782	/*
783	 * Set root hold-off bit so that non cyclemaster capable node
784	 * shouldn't became the root node.
785	 */
786#if 1
787	fun = fwphy_rddata(sc, FW_PHY_IBR_REG);
788	fun |= FW_PHY_IBR | FW_PHY_RHB;
789	fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun);
790#else	/* Short bus reset */
791	fun = fwphy_rddata(sc, FW_PHY_ISBR_REG);
792	fun |= FW_PHY_ISBR | FW_PHY_RHB;
793	fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun);
794#endif
795}
796
797static int
798fwohci_irx_enable(struct firewire_comm *fc, int dmach)
799{
800	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
801	struct fwohci_dbch *dbch;
802	struct fwohcidb_tr *db_tr;
803	struct fw_bulkxfer *first, *prev, *chunk, *txfer;
804	struct fw_xferq *ir;
805	uint32_t stat;
806	unsigned short tag, ich;
807	int err = 0, ldesc;
808
809	dbch = &sc->ir[dmach];
810	ir = &dbch->xferq;
811
812	if ((ir->flag & FWXFERQ_RUNNING) == 0) {
813		tag = (ir->flag >> 6) & 3;
814		ich = ir->flag & 0x3f;
815		OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich);
816
817		ir->queued = 0;
818		dbch->ndb = ir->bnpacket * ir->bnchunk;
819		dbch->ndesc = 2;
820		fwohci_db_init(sc, dbch);
821		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
822			return ENOMEM;
823		err = fwohci_rx_enable(sc, dbch);
824		if (err)
825			return err;
826	}
827
828	first = STAILQ_FIRST(&ir->stfree);
829	if (first == NULL) {
830		aprint_error_dev(fc->dev, "IR DMA no free chunk\n");
831		return 0;
832	}
833
834	ldesc = dbch->ndesc - 1;
835	prev = NULL;
836	STAILQ_FOREACH(txfer, &ir->stdma, link)
837		prev = txfer;
838	while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
839		struct fwohcidb *db;
840
841		if (chunk->mbuf != NULL) {
842			db_tr = (struct fwohcidb_tr *)(chunk->start);
843			db_tr->dbcnt = 1;
844			err = bus_dmamap_load_mbuf(fc->dmat, db_tr->dma_map,
845			    chunk->mbuf, BUS_DMA_NOWAIT);
846			if (err == 0)
847				fwohci_execute_db(db_tr, db_tr->dma_map);
848			else
849				aprint_error_dev(fc->dev,
850				    "mbuf load failed: %d\n", err);
851 			FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd,
852			    OHCI_UPDATE |
853			    OHCI_INPUT_LAST |
854			    OHCI_INTERRUPT_ALWAYS |
855			    OHCI_BRANCH_ALWAYS);
856		}
857		db = ((struct fwohcidb_tr *)(chunk->end))->db;
858		FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0);
859		FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
860		if (prev != NULL) {
861			db = ((struct fwohcidb_tr *)(prev->end))->db;
862			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
863		}
864		STAILQ_REMOVE_HEAD(&ir->stfree, link);
865		STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
866		prev = chunk;
867	}
868	fwdma_sync_multiseg_all(dbch->am,
869	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
870	stat = OREAD(sc, OHCI_IRCTL(dmach));
871	if (stat & OHCI_CNTL_DMA_ACTIVE)
872		return 0;
873	if (stat & OHCI_CNTL_DMA_RUN) {
874		OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
875		aprint_error_dev(fc->dev, "IR DMA overrun (0x%08x)\n", stat);
876	}
877
878	if (firewire_debug)
879		printf("start IR DMA 0x%x\n", stat);
880	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
881	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
882	OWRITE(sc, OHCI_IR_MASK, 1 << dmach);
883	OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000);
884	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR);
885	OWRITE(sc, OHCI_IRCMD(dmach),
886	    ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
887	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
888	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
889#if 0
890	dump_db(sc, IRX_CH + dmach);
891#endif
892	return err;
893}
894
895static int
896fwohci_irx_disable(struct firewire_comm *fc, int dmach)
897{
898	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
899
900	OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
901	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
902	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
903	/* XXX we cannot free buffers until the DMA really stops */
904	kpause("fwirxd", true, hz, NULL);
905	fwohci_db_free(sc, &sc->ir[dmach]);
906	sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
907	return 0;
908}
909
910
911static int
912fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
913{
914	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
915	struct fwohci_dbch *dbch;
916	struct fw_bulkxfer *first, *chunk, *prev, *txfer;
917	struct fw_xferq *it;
918	uint32_t stat;
919	int cycle_match, cycle_now, ldesc, err = 0;
920
921	dbch = &sc->it[dmach];
922	it = &dbch->xferq;
923
924	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
925		dbch->ndb = it->bnpacket * it->bnchunk;
926		dbch->ndesc = 3;
927		fwohci_db_init(sc, dbch);
928		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
929			return ENOMEM;
930
931		err = fwohci_tx_enable(sc, dbch);
932		if (err)
933			return err;
934	}
935
936	ldesc = dbch->ndesc - 1;
937	prev = NULL;
938	STAILQ_FOREACH(txfer, &it->stdma, link)
939		prev = txfer;
940	while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
941		struct fwohcidb *db;
942
943		fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
944		    BUS_DMASYNC_PREWRITE);
945		fwohci_txbufdb(sc, dmach, chunk);
946		if (prev != NULL) {
947			db = ((struct fwohcidb_tr *)(prev->end))->db;
948#if 0 /* XXX necessary? */
949			FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
950			    OHCI_BRANCH_ALWAYS);
951#endif
952#if 0 /* if bulkxfer->npacket changes */
953			db[ldesc].db.desc.depend = db[0].db.desc.depend =
954			    ((struct fwohcidb_tr *)(chunk->start))->bus_addr |
955								dbch->ndesc;
956#else
957			FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
958			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
959#endif
960		}
961		STAILQ_REMOVE_HEAD(&it->stvalid, link);
962		STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
963		prev = chunk;
964	}
965	fwdma_sync_multiseg_all(dbch->am,
966	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
967	stat = OREAD(sc, OHCI_ITCTL(dmach));
968	if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S))
969		printf("stat 0x%x\n", stat);
970
971	if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S))
972		return 0;
973
974#if 0
975	OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
976#endif
977	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
978	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
979	OWRITE(sc, OHCI_IT_MASK, 1 << dmach);
980	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT);
981
982	first = STAILQ_FIRST(&it->stdma);
983	OWRITE(sc, OHCI_ITCMD(dmach),
984	    ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
985	if (firewire_debug > 1) {
986		printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
987#if 1
988		dump_dma(sc, ITX_CH + dmach);
989#endif
990	}
991	if ((stat & OHCI_CNTL_DMA_RUN) == 0) {
992#if 1
993		/* Don't start until all chunks are buffered */
994		if (STAILQ_FIRST(&it->stfree) != NULL)
995			goto out;
996#endif
997#if 1
998		/* Clear cycle match counter bits */
999		OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000);
1000
1001		/* 2bit second + 13bit cycle */
1002		cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff;
1003		cycle_match = fwohci_next_cycle(sc, cycle_now);
1004
1005		OWRITE(sc, OHCI_ITCTL(dmach),
1006		    OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) |
1007							OHCI_CNTL_DMA_RUN);
1008#else
1009		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
1010#endif
1011		if (firewire_debug > 1) {
1012			printf("cycle_match: 0x%04x->0x%04x\n",
1013			    cycle_now, cycle_match);
1014			dump_dma(sc, ITX_CH + dmach);
1015			dump_db(sc, ITX_CH + dmach);
1016		}
1017	} else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) {
1018		aprint_error_dev(fc->dev, "IT DMA underrun (0x%08x)\n", stat);
1019		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE);
1020	}
1021out:
1022	return err;
1023}
1024
1025static int
1026fwohci_itx_disable(struct firewire_comm *fc, int dmach)
1027{
1028	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1029
1030	OWRITE(sc, OHCI_ITCTLCLR(dmach),
1031	    OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
1032	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
1033	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
1034	/* XXX we cannot free buffers until the DMA really stops */
1035	kpause("fwitxd", true, hz, NULL);
1036	fwohci_db_free(sc, &sc->it[dmach]);
1037	sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
1038	return 0;
1039}
1040
1041static void
1042fwohci_timeout(struct firewire_comm *fc)
1043{
1044#if 0
1045	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1046#endif
1047	/* nothing? */
1048}
1049
1050#if BYTE_ORDER == BIG_ENDIAN
1051static void
1052fwohci_irx_post (struct firewire_comm *fc, uint32_t *qld)
1053{
1054
1055	qld[0] = FWOHCI_DMA_READ(qld[0]);
1056	return;
1057}
1058#endif
1059
1060static void
1061fwohci_set_intr(struct firewire_comm *fc, int enable)
1062{
1063	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1064
1065	if (firewire_debug)
1066		printf("fwohci_set_intr: %d\n", enable);
1067	if (enable) {
1068		sc->intmask |= OHCI_INT_EN;
1069		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN);
1070	} else {
1071		sc->intmask &= ~OHCI_INT_EN;
1072		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN);
1073	}
1074}
1075
1076/*
1077 * Communication with PHY device
1078 */
1079/* XXX need lock for phy access */
1080static uint32_t
1081fwphy_rddata(struct fwohci_softc *sc, u_int addr)
1082{
1083	uint32_t fun, stat;
1084	u_int i, retry = 0;
1085
1086	addr &= 0xf;
1087#define MAX_RETRY 100
1088again:
1089	OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL);
1090	fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR);
1091	OWRITE(sc, OHCI_PHYACCESS, fun);
1092	for (i = 0; i < MAX_RETRY; i++) {
1093		fun = OREAD(sc, OHCI_PHYACCESS);
1094		if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0)
1095			break;
1096		DELAY(100);
1097	}
1098	if (i >= MAX_RETRY) {
1099		if (firewire_debug)
1100			printf("phy read failed(1).\n");
1101		if (++retry < MAX_RETRY) {
1102			DELAY(100);
1103			goto again;
1104		}
1105	}
1106	/* Make sure that SCLK is started */
1107	stat = OREAD(sc, FWOHCI_INTSTAT);
1108	if ((stat & OHCI_INT_REG_FAIL) != 0 ||
1109	    ((fun >> PHYDEV_REGADDR) & 0xf) != addr) {
1110		if (firewire_debug)
1111			printf("phy read failed(2).\n");
1112		if (++retry < MAX_RETRY) {
1113			DELAY(100);
1114			goto again;
1115		}
1116	}
1117	if (firewire_debug || retry >= MAX_RETRY)
1118		aprint_error_dev(sc->fc.dev,
1119		    "fwphy_rddata: 0x%x loop=%d, retry=%d\n",
1120		    addr, i, retry);
1121#undef MAX_RETRY
1122	return (fun >> PHYDEV_RDDATA) & 0xff;
1123}
1124
1125static uint32_t
1126fwphy_wrdata(struct fwohci_softc *sc, uint32_t addr, uint32_t data)
1127{
1128	uint32_t fun;
1129
1130	addr &= 0xf;
1131	data &= 0xff;
1132
1133	fun =
1134	    (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA));
1135	OWRITE(sc, OHCI_PHYACCESS, fun);
1136	DELAY(100);
1137
1138	return fwphy_rddata(sc, addr);
1139}
1140
1141static int
1142fwohci_probe_phy(struct fwohci_softc *sc)
1143{
1144	uint32_t reg, reg2;
1145	int e1394a = 1;
1146
1147/*
1148 * probe PHY parameters
1149 * 0. to prove PHY version, whether compliance of 1394a.
1150 * 1. to probe maximum speed supported by the PHY and
1151 *    number of port supported by core-logic.
1152 *    It is not actually available port on your PC .
1153 */
1154	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
1155	DELAY(500);
1156
1157	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
1158
1159	if ((reg >> 5) != 7) {
1160		sc->fc.mode &= ~FWPHYASYST;
1161		sc->fc.nport = reg & FW_PHY_NP;
1162		sc->fc.speed = reg & FW_PHY_SPD >> 6;
1163		if (sc->fc.speed > MAX_SPEED) {
1164			aprint_error_dev(sc->fc.dev,
1165			    "invalid speed %d (fixed to %d).\n",
1166			    sc->fc.speed, MAX_SPEED);
1167			sc->fc.speed = MAX_SPEED;
1168		}
1169		aprint_normal_dev(sc->fc.dev, "Phy 1394 only %s, %d ports.\n",
1170		    fw_linkspeed[sc->fc.speed], sc->fc.nport);
1171	} else {
1172		reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG);
1173		sc->fc.mode |= FWPHYASYST;
1174		sc->fc.nport = reg & FW_PHY_NP;
1175		sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5;
1176		if (sc->fc.speed > MAX_SPEED) {
1177			aprint_error_dev(sc->fc.dev,
1178			    "invalid speed %d (fixed to %d).\n",
1179			    sc->fc.speed, MAX_SPEED);
1180			sc->fc.speed = MAX_SPEED;
1181		}
1182		aprint_normal_dev(sc->fc.dev,
1183		    "Phy 1394a available %s, %d ports.\n",
1184		    fw_linkspeed[sc->fc.speed], sc->fc.nport);
1185
1186		/* check programPhyEnable */
1187		reg2 = fwphy_rddata(sc, 5);
1188#if 0
1189		if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) {
1190#else	/* XXX force to enable 1394a */
1191		if (e1394a) {
1192#endif
1193			if (firewire_debug)
1194				printf("Enable 1394a Enhancements\n");
1195			/* enable EAA EMC */
1196			reg2 |= 0x03;
1197			/* set aPhyEnhanceEnable */
1198			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN);
1199			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY);
1200		}
1201#if 0
1202		else {
1203			/* for safe */
1204			reg2 &= ~0x83;
1205		}
1206#endif
1207		reg2 = fwphy_wrdata(sc, 5, reg2);
1208	}
1209
1210	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
1211	if ((reg >> 5) == 7) {
1212		reg = fwphy_rddata(sc, 4);
1213		reg |= 1 << 6;
1214		fwphy_wrdata(sc, 4, reg);
1215		reg = fwphy_rddata(sc, 4);
1216	}
1217	return 0;
1218}
1219
1220static void
1221fwohci_reset(struct fwohci_softc *sc)
1222{
1223	struct fwohcidb_tr *db_tr;
1224	uint32_t reg, reg2;
1225	int i, max_rec, speed;
1226
1227	/* Disable interrupts */
1228	OWRITE(sc, FWOHCI_INTMASKCLR, ~0);
1229
1230	/* Now stopping all DMA channels */
1231	OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
1232	OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
1233	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
1234	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
1235
1236	OWRITE(sc, OHCI_IR_MASKCLR, ~0);
1237	for (i = 0; i < sc->fc.nisodma; i++) {
1238		OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
1239		OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
1240	}
1241
1242	/* FLUSH FIFO and reset Transmitter/Receiver */
1243	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
1244	if (firewire_debug)
1245		printf("resetting OHCI...");
1246	i = 0;
1247	while (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) {
1248		if (i++ > 100)
1249			break;
1250		DELAY(1000);
1251	}
1252	if (firewire_debug)
1253		printf("done (loop=%d)\n", i);
1254
1255	/* Probe phy */
1256	fwohci_probe_phy(sc);
1257
1258	/* Probe link */
1259	reg = OREAD(sc, OHCI_BUS_OPT);
1260	reg2 = reg | OHCI_BUSFNC;
1261	max_rec = (reg & 0x0000f000) >> 12;
1262	speed = (reg & 0x00000007);
1263	aprint_normal_dev(sc->fc.dev, "Link %s, max_rec %d bytes.\n",
1264	    fw_linkspeed[speed], MAXREC(max_rec));
1265	/* XXX fix max_rec */
1266	sc->fc.maxrec = sc->fc.speed + 8;
1267	if (max_rec != sc->fc.maxrec) {
1268		reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12);
1269		aprint_normal_dev(sc->fc.dev, "max_rec %d -> %d\n",
1270		    MAXREC(max_rec), MAXREC(sc->fc.maxrec));
1271	}
1272	if (firewire_debug)
1273		printf("BUS_OPT 0x%x -> 0x%x\n", reg, reg2);
1274	OWRITE(sc, OHCI_BUS_OPT, reg2);
1275
1276	/* Initialize registers */
1277	OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]);
1278	OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr);
1279	OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND);
1280	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
1281	OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
1282	OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
1283
1284	/* Enable link */
1285	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN);
1286
1287	/* Force to start async RX DMA */
1288	sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING;
1289	sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING;
1290	fwohci_rx_enable(sc, &sc->arrq);
1291	fwohci_rx_enable(sc, &sc->arrs);
1292
1293	/* Initialize async TX */
1294	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
1295	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
1296
1297	/* AT Retries */
1298	OWRITE(sc, FWOHCI_RETRY,
1299	    /* CycleLimit   PhyRespRetries ATRespRetries ATReqRetries */
1300	    (0xffffU << 16) | (0x0f << 8) | (0x0f << 4) | 0x0f);
1301
1302	sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq);
1303	sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq);
1304	sc->atrq.bottom = sc->atrq.top;
1305	sc->atrs.bottom = sc->atrs.top;
1306
1307	for (i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb;
1308	    i++, db_tr = STAILQ_NEXT(db_tr, link))
1309		db_tr->xfer = NULL;
1310	for (i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb;
1311	    i++, db_tr = STAILQ_NEXT(db_tr, link))
1312		db_tr->xfer = NULL;
1313
1314
1315	/* Enable interrupts */
1316	sc->intmask =  (OHCI_INT_ERR | OHCI_INT_PHY_SID
1317			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
1318			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
1319			| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
1320	sc->intmask |= OHCI_INT_DMA_IR | OHCI_INT_DMA_IT;
1321	sc->intmask |= OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT;
1322	OWRITE(sc, FWOHCI_INTMASK, sc->intmask);
1323	fwohci_set_intr(&sc->fc, 1);
1324}
1325
1326#define LAST_DB(dbtr) \
1327	&dbtr->db[(dbtr->dbcnt > 2) ? (dbtr->dbcnt - 1) : 0];
1328
1329static void
1330fwohci_execute_db(struct fwohcidb_tr *db_tr, bus_dmamap_t dmamap)
1331{
1332	struct fwohcidb *db;
1333	bus_dma_segment_t *s;
1334	int i;
1335
1336	db = &db_tr->db[db_tr->dbcnt];
1337	for (i = 0; i < dmamap->dm_nsegs; i++) {
1338		s = &dmamap->dm_segs[i];
1339		FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr);
1340		FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len);
1341 		FWOHCI_DMA_WRITE(db->db.desc.res, 0);
1342		db++;
1343		db_tr->dbcnt++;
1344	}
1345}
1346
1347static void
1348fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1349{
1350	struct fw_xfer *xfer;
1351	struct fw_pkt *fp;
1352	struct fwohci_txpkthdr *ohcifp;
1353	struct fwohcidb_tr *db_tr, *kick;
1354	struct fwohcidb *db;
1355	uint32_t *ld;
1356	int tcode, hdr_len, pl_off, fsegment = -1, i;
1357	const struct tcode_info *info;
1358	static int maxdesc = 0;
1359
1360	KASSERT(mutex_owned(&dbch->xferq.q_mtx));
1361
1362#if DIAGNOSTIC
1363	if (dbch->off != OHCI_ATQOFF &&
1364	    dbch->off != OHCI_ATSOFF)
1365		panic("not async tx");
1366#endif
1367
1368	if (dbch->flags & FWOHCI_DBCH_FULL)
1369		return;
1370
1371	db_tr = dbch->top;
1372	kick = db_tr;
1373	if (dbch->pdb_tr != NULL) {
1374		kick = dbch->pdb_tr;
1375		fwdma_sync_multiseg(dbch->am, kick->idx, kick->idx,
1376		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1377	}
1378txloop:
1379	xfer = STAILQ_FIRST(&dbch->xferq.q);
1380	if (xfer == NULL)
1381		goto kick;
1382#if 0
1383	if (dbch->xferq.queued == 0)
1384		aprint_error_dev(sc->fc.dev, "TX queue empty\n");
1385#endif
1386	STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
1387	db_tr->xfer = xfer;
1388	xfer->flag = FWXF_START;
1389
1390	fp = &xfer->send.hdr;
1391	tcode = fp->mode.common.tcode;
1392
1393	ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
1394	info = &tinfo[tcode];
1395	hdr_len = pl_off = info->hdr_len;
1396
1397	ld = ohcifp->mode.ld;
1398	ld[0] = ld[1] = ld[2] = ld[3] = 0;
1399	for (i = 0; i < pl_off / 4; i++)
1400		ld[i] = fp->mode.ld[i];
1401
1402	ohcifp->mode.common.spd = xfer->send.spd & 0x7;
1403	if (tcode == FWTCODE_STREAM) {
1404		hdr_len = 8;
1405		ohcifp->mode.stream.len = fp->mode.stream.len;
1406	} else if (tcode == FWTCODE_PHY) {
1407		hdr_len = 12;
1408		ld[1] = fp->mode.ld[1];
1409		ld[2] = fp->mode.ld[2];
1410		ohcifp->mode.common.spd = 0;
1411		ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
1412	} else {
1413		ohcifp->mode.asycomm.dst = fp->mode.hdr.dst;
1414		ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS;
1415		ohcifp->mode.asycomm.tlrt |= FWRETRY_X;
1416	}
1417	db = db_tr->db;
1418 	FWOHCI_DMA_WRITE(db->db.desc.cmd,
1419	    OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
1420 	FWOHCI_DMA_WRITE(db->db.desc.addr, 0);
1421 	FWOHCI_DMA_WRITE(db->db.desc.res, 0);
1422/* Specify bound timer of asy. response */
1423	if (dbch->off != OHCI_ATSOFF)
1424 		FWOHCI_DMA_WRITE(db->db.desc.res,
1425		     (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13));
1426#if BYTE_ORDER == BIG_ENDIAN
1427	if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
1428		hdr_len = 12;
1429	for (i = 0; i < hdr_len / 4; i++)
1430		FWOHCI_DMA_WRITE(ld[i], ld[i]);
1431#endif
1432
1433again:
1434	db_tr->dbcnt = 2;
1435	db = &db_tr->db[db_tr->dbcnt];
1436	if (xfer->send.pay_len > 0) {
1437		int err;
1438		/* handle payload */
1439		if (xfer->mbuf == NULL)
1440			err = bus_dmamap_load(sc->fc.dmat, db_tr->dma_map,
1441			    xfer->send.payload, xfer->send.pay_len, NULL,
1442			    BUS_DMA_WAITOK);
1443		else {
1444			/* XXX we can handle only 6 (=8-2) mbuf chains */
1445			err = bus_dmamap_load_mbuf(sc->fc.dmat, db_tr->dma_map,
1446			    xfer->mbuf, BUS_DMA_WAITOK);
1447			if (err == EFBIG) {
1448				struct mbuf *m0;
1449
1450				if (firewire_debug)
1451					printf("EFBIG.\n");
1452				m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1453				if (m0 != NULL) {
1454					m_copydata(xfer->mbuf, 0,
1455					    xfer->mbuf->m_pkthdr.len,
1456					    mtod(m0, void *));
1457					m0->m_len = m0->m_pkthdr.len =
1458					    xfer->mbuf->m_pkthdr.len;
1459					m_freem(xfer->mbuf);
1460					xfer->mbuf = m0;
1461					goto again;
1462				}
1463				aprint_error_dev(sc->fc.dev,
1464				    "m_getcl failed.\n");
1465			}
1466		}
1467		if (!err)
1468			fwohci_execute_db(db_tr, db_tr->dma_map);
1469		else
1470			aprint_error_dev(sc->fc.dev,
1471			    "dmamap_load: err=%d\n", err);
1472		bus_dmamap_sync(sc->fc.dmat, db_tr->dma_map,
1473		    0, db_tr->dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
1474#if 0 /* OHCI_OUTPUT_MODE == 0 */
1475		for (i = 2; i < db_tr->dbcnt; i++)
1476			FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd,
1477			    OHCI_OUTPUT_MORE);
1478#endif
1479	}
1480	if (maxdesc < db_tr->dbcnt) {
1481		maxdesc = db_tr->dbcnt;
1482		if (firewire_debug)
1483			printf("maxdesc: %d\n", maxdesc);
1484	}
1485	/* last db */
1486	db = LAST_DB(db_tr);
1487 	FWOHCI_DMA_SET(db->db.desc.cmd,
1488	    OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
1489 	FWOHCI_DMA_WRITE(db->db.desc.depend,
1490	    STAILQ_NEXT(db_tr, link)->bus_addr);
1491
1492	if (fsegment == -1)
1493		fsegment = db_tr->dbcnt;
1494	if (dbch->pdb_tr != NULL) {
1495		db = LAST_DB(dbch->pdb_tr);
1496 		FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
1497	}
1498	dbch->xferq.queued++;
1499	dbch->pdb_tr = db_tr;
1500	db_tr = STAILQ_NEXT(db_tr, link);
1501	if (db_tr != dbch->bottom)
1502		goto txloop;
1503	else {
1504		aprint_error_dev(sc->fc.dev, "fwohci_start: lack of db_trq\n");
1505		dbch->flags |= FWOHCI_DBCH_FULL;
1506	}
1507kick:
1508	/* kick asy q */
1509	fwdma_sync_multiseg(dbch->am, kick->idx, dbch->pdb_tr->idx,
1510	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1511
1512	if (dbch->xferq.flag & FWXFERQ_RUNNING)
1513		OWRITE(sc, OHCI_DMACTL(dbch->off), OHCI_CNTL_DMA_WAKE);
1514	else {
1515		if (firewire_debug)
1516			printf("start AT DMA status=%x\n",
1517			    OREAD(sc, OHCI_DMACTL(dbch->off)));
1518		OWRITE(sc, OHCI_DMACMD(dbch->off),
1519		    dbch->top->bus_addr | fsegment);
1520		OWRITE(sc, OHCI_DMACTL(dbch->off), OHCI_CNTL_DMA_RUN);
1521		dbch->xferq.flag |= FWXFERQ_RUNNING;
1522	}
1523
1524	dbch->top = db_tr;
1525	return;
1526}
1527
1528static void
1529fwohci_start_atq(struct firewire_comm *fc)
1530{
1531	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1532	struct fwohci_dbch *dbch = &sc->atrq;
1533
1534	mutex_enter(&dbch->xferq.q_mtx);
1535	fwohci_start(sc, dbch);
1536	mutex_exit(&dbch->xferq.q_mtx);
1537	return;
1538}
1539
1540static void
1541fwohci_start_ats(struct firewire_comm *fc)
1542{
1543	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1544	struct fwohci_dbch *dbch = &sc->atrs;
1545
1546	mutex_enter(&dbch->xferq.q_mtx);
1547	fwohci_start(sc, dbch);
1548	mutex_exit(&dbch->xferq.q_mtx);
1549	return;
1550}
1551
1552static void
1553fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1554{
1555	struct firewire_comm *fc = &sc->fc;
1556	struct fwohcidb_tr *tr;
1557	struct fwohcidb *db;
1558	struct fw_xfer *xfer;
1559	u_int stat, status;
1560	int packets = 0, ch, err = 0;
1561
1562#if DIAGNOSTIC
1563	if (dbch->off != OHCI_ATQOFF &&
1564	    dbch->off != OHCI_ATSOFF)
1565		panic("not async tx");
1566#endif
1567	if (dbch->off == OHCI_ATQOFF)
1568		ch = ATRQ_CH;
1569	else	/* OHCI_ATSOFF */
1570		ch = ATRS_CH;
1571
1572	mutex_enter(&dbch->xferq.q_mtx);
1573	tr = dbch->bottom;
1574	while (dbch->xferq.queued > 0) {
1575		fwdma_sync_multiseg(dbch->am, tr->idx, tr->idx,
1576		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1577		db = LAST_DB(tr);
1578		status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
1579		if (!(status & OHCI_CNTL_DMA_ACTIVE))
1580			if (fc->status != FWBUSINIT)
1581				goto out;
1582		if (tr->xfer->send.pay_len > 0) {
1583			bus_dmamap_sync(fc->dmat, tr->dma_map,
1584			    0, tr->dma_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1585			bus_dmamap_unload(fc->dmat, tr->dma_map);
1586		}
1587#if 1
1588		if (firewire_debug > 1)
1589			dump_db(sc, ch);
1590#endif
1591		if (status & OHCI_CNTL_DMA_DEAD) {
1592			/* Stop DMA */
1593			OWRITE(sc, OHCI_DMACTLCLR(dbch->off),
1594			    OHCI_CNTL_DMA_RUN);
1595			aprint_error_dev(fc->dev, "force reset AT FIFO\n");
1596			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN);
1597			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN);
1598			OWRITE(sc, OHCI_DMACTLCLR(dbch->off),
1599			    OHCI_CNTL_DMA_RUN);
1600		}
1601		stat = status & FWOHCIEV_MASK;
1602		switch(stat) {
1603		case FWOHCIEV_ACKPEND:
1604
1605			/* FALLTHROUGH */
1606
1607		case FWOHCIEV_ACKCOMPL:
1608			err = 0;
1609			break;
1610
1611		case FWOHCIEV_ACKBSA:
1612		case FWOHCIEV_ACKBSB:
1613		case FWOHCIEV_ACKBSX:
1614			aprint_error_dev(fc->dev, "txd err=%2x %s\n", stat,
1615			    fwohcicode[stat]);
1616			err = EBUSY;
1617			break;
1618
1619		case FWOHCIEV_FLUSHED:
1620		case FWOHCIEV_ACKTARD:
1621			aprint_error_dev(fc->dev, "txd err=%2x %s\n", stat,
1622			    fwohcicode[stat]);
1623			err = EAGAIN;
1624			break;
1625
1626		case FWOHCIEV_MISSACK:
1627		case FWOHCIEV_UNDRRUN:
1628		case FWOHCIEV_OVRRUN:
1629		case FWOHCIEV_DESCERR:
1630		case FWOHCIEV_DTRDERR:
1631		case FWOHCIEV_TIMEOUT:
1632		case FWOHCIEV_TCODERR:
1633		case FWOHCIEV_UNKNOWN:
1634		case FWOHCIEV_ACKDERR:
1635		case FWOHCIEV_ACKTERR:
1636		default:
1637			aprint_error_dev(fc->dev, "txd err=%2x %s\n", stat,
1638			    fwohcicode[stat]);
1639			err = EINVAL;
1640			break;
1641		}
1642		dbch->xferq.queued--;
1643		dbch->bottom = STAILQ_NEXT(tr, link);
1644		if (tr->xfer != NULL) {
1645			xfer = tr->xfer;
1646			tr->xfer = NULL;
1647			mutex_exit(&dbch->xferq.q_mtx);
1648			if (xfer->flag & FWXF_RCVD) {
1649#if 0
1650				if (firewire_debug)
1651					printf("already rcvd\n");
1652#endif
1653				fw_xfer_done(xfer);
1654			} else {
1655				microtime(&xfer->tv);
1656				xfer->flag = FWXF_SENT;
1657				if (err == EBUSY) {
1658					xfer->flag = FWXF_BUSY;
1659					xfer->resp = err;
1660					xfer->recv.pay_len = 0;
1661					fw_xfer_done(xfer);
1662				} else if (stat != FWOHCIEV_ACKPEND) {
1663					if (stat != FWOHCIEV_ACKCOMPL)
1664						xfer->flag = FWXF_SENTERR;
1665					xfer->resp = err;
1666					xfer->recv.pay_len = 0;
1667					fw_xfer_done(xfer);
1668				}
1669			}
1670			mutex_enter(&dbch->xferq.q_mtx);
1671			/*
1672			 * The watchdog timer takes care of split
1673			 * transaction timeout for ACKPEND case.
1674			 */
1675		} else
1676			aprint_error_dev(fc->dev, "this shouldn't happen\n");
1677		packets++;
1678		if (dbch->bottom == dbch->top) {
1679			/* we reaches the end of context program */
1680			if (firewire_debug && dbch->xferq.queued > 0)
1681				printf("queued > 0\n");
1682			break;
1683		}
1684		tr = dbch->bottom;
1685	}
1686out:
1687	if (dbch->xferq.queued > 0 || packets > 0)
1688		fwdma_sync_multiseg(dbch->am, tr->idx, tr->idx,
1689		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1690	if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
1691		aprint_normal_dev(fc->dev, "make free slot\n");
1692		dbch->flags &= ~FWOHCI_DBCH_FULL;
1693		fwohci_start(sc, dbch);
1694	}
1695	mutex_exit(&dbch->xferq.q_mtx);
1696}
1697
1698static void
1699fwohci_db_free(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1700{
1701	struct fwohcidb_tr *db_tr, *last;
1702
1703	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1704		return;
1705
1706	for (last = db_tr = STAILQ_FIRST(&dbch->db_trq); db_tr != last;
1707	    db_tr = STAILQ_NEXT(db_tr, link)) {
1708		bus_dmamap_destroy(sc->fc.dmat, db_tr->dma_map);
1709		if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 &&
1710		    db_tr->buf != NULL) {
1711			fwdma_free(sc->fc.dmat, db_tr->dma_map, db_tr->buf);
1712			db_tr->buf = NULL;
1713		}
1714	}
1715	dbch->ndb = 0;
1716	db_tr = STAILQ_FIRST(&dbch->db_trq);
1717	fwdma_free_multiseg(dbch->am);
1718	free(db_tr, M_FW);
1719	STAILQ_INIT(&dbch->db_trq);
1720	dbch->flags &= ~FWOHCI_DBCH_INIT;
1721	seldestroy(&dbch->xferq.rsel);
1722}
1723
1724static void
1725fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1726{
1727	struct firewire_comm *fc = &sc->fc;
1728	struct fwohcidb_tr *db_tr, *lastq, *tmpq;
1729	int idb;
1730	const int db_tr_sz = sizeof(struct fwohcidb_tr) * dbch->ndb;
1731
1732	if ((dbch->flags & FWOHCI_DBCH_INIT) != 0)
1733		goto out;
1734
1735	/* allocate DB entries and attach one to each DMA channels */
1736	/* DB entry must start at 16 bytes boundary. */
1737	STAILQ_INIT(&dbch->db_trq);
1738	db_tr = (struct fwohcidb_tr *)malloc(db_tr_sz, M_FW, M_WAITOK | M_ZERO);
1739	if (db_tr == NULL) {
1740		aprint_error_dev(fc->dev, "malloc(1) failed\n");
1741		return;
1742	}
1743
1744#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc)
1745	dbch->am = fwdma_malloc_multiseg(fc, DB_SIZE(dbch), DB_SIZE(dbch),
1746#if 0
1747	    dbch->ndb, BUS_DMA_WAITOK);
1748#else	/* Ooops, debugging now... */
1749	    dbch->ndb, BUS_DMA_WAITOK |
1750		((dbch->off == OHCI_ARQOFF || dbch->off == OHCI_ARSOFF) ?
1751							BUS_DMA_COHERENT : 0));
1752#endif
1753	if (dbch->am == NULL) {
1754		aprint_error_dev(fc->dev, "fwdma_malloc_multiseg failed\n");
1755		free(db_tr, M_FW);
1756		return;
1757	}
1758	/* Attach DB to DMA ch. */
1759	for (idb = 0; idb < dbch->ndb; idb++) {
1760		db_tr->idx = idb;
1761		db_tr->dbcnt = 0;
1762		db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb);
1763		db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb);
1764		/* create dmamap for buffers */
1765#define MAX_REQCOUNT	0xffff
1766		if (bus_dmamap_create(fc->dmat, dbch->xferq.psize,
1767		    dbch->ndesc > 3 ? dbch->ndesc - 2 : 1, MAX_REQCOUNT, 0,
1768		    0, &db_tr->dma_map) != 0) {
1769			aprint_error_dev(fc->dev, "bus_dmamap_create failed\n");
1770			dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
1771			fwohci_db_free(sc, dbch);
1772			return;
1773		}
1774		if (dbch->off == OHCI_ARQOFF ||
1775		    dbch->off == OHCI_ARSOFF) {
1776			db_tr->buf = fwdma_malloc(fc->dev, fc->dmat,
1777			    &db_tr->dma_map, dbch->xferq.psize, 1,
1778			    BUS_DMA_NOWAIT);
1779			if (db_tr->buf == NULL) {
1780				aprint_error_dev(fc->dev,
1781				    "fwdma_malloc failed\n");
1782				dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
1783				fwohci_db_free(sc, dbch);
1784				return;
1785			}
1786		}
1787		STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link);
1788		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1789			struct fw_bulkxfer *bulkxfer =
1790			    &dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket];
1791
1792			if (idb % dbch->xferq.bnpacket == 0)
1793				bulkxfer->start = (void *)db_tr;
1794			if ((idb + 1) % dbch->xferq.bnpacket == 0)
1795				bulkxfer->end = (void *)db_tr;
1796		}
1797		db_tr++;
1798	}
1799	lastq = NULL;
1800	STAILQ_FOREACH(tmpq, &dbch->db_trq, link)
1801		lastq = tmpq;
1802	lastq->link.stqe_next = STAILQ_FIRST(&dbch->db_trq);
1803out:
1804	dbch->xferq.queued = 0;
1805	dbch->pdb_tr = NULL;
1806	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1807	dbch->bottom = dbch->top;
1808	dbch->flags = FWOHCI_DBCH_INIT;
1809	selinit(&dbch->xferq.rsel);
1810}
1811
1812static int
1813fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1814{
1815	int err = 0;
1816	int idb, z, i, dmach = 0, ldesc;
1817	struct fwohcidb_tr *db_tr;
1818	struct fwohcidb *db;
1819
1820	if (!(dbch->xferq.flag & FWXFERQ_EXTBUF)) {
1821		err = EINVAL;
1822		return err;
1823	}
1824	z = dbch->ndesc;
1825	for (dmach = 0; dmach < sc->fc.nisodma; dmach++)
1826		if (dbch->off == sc->it[dmach].off)
1827			break;
1828	if (dmach == sc->fc.nisodma) {
1829		err = EINVAL;
1830		return err;
1831	}
1832	if (dbch->xferq.flag & FWXFERQ_RUNNING)
1833		return err;
1834	dbch->xferq.flag |= FWXFERQ_RUNNING;
1835	for (i = 0, dbch->bottom = dbch->top; i < dbch->ndb - 1; i++)
1836		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1837	db_tr = dbch->top;
1838	for (idb = 0; idb < dbch->ndb; idb++) {
1839		fwohci_add_tx_buf(dbch, db_tr, idb);
1840		if (STAILQ_NEXT(db_tr, link) == NULL)
1841			break;
1842		db = db_tr->db;
1843		ldesc = db_tr->dbcnt - 1;
1844		FWOHCI_DMA_WRITE(db[0].db.desc.depend,
1845		    STAILQ_NEXT(db_tr, link)->bus_addr | z);
1846		db[ldesc].db.desc.depend = db[0].db.desc.depend;
1847		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1848			if (((idb + 1) % dbch->xferq.bnpacket) == 0) {
1849				FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
1850				    OHCI_INTERRUPT_ALWAYS);
1851				/* OHCI 1.1 and above */
1852				FWOHCI_DMA_SET(db[0].db.desc.cmd,
1853				    OHCI_INTERRUPT_ALWAYS);
1854			}
1855		}
1856		db_tr = STAILQ_NEXT(db_tr, link);
1857	}
1858	FWOHCI_DMA_CLEAR(
1859	    dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf);
1860	return err;
1861}
1862
1863static int
1864fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1865{
1866	struct fwohcidb_tr *db_tr;
1867	struct fwohcidb *db;
1868	int idb, z, i, ldesc, err = 0;
1869
1870	z = dbch->ndesc;
1871	if (dbch->xferq.flag & FWXFERQ_STREAM) {
1872		if (dbch->xferq.flag & FWXFERQ_RUNNING)
1873			return err;
1874	} else
1875		if (dbch->xferq.flag & FWXFERQ_RUNNING) {
1876			err = EBUSY;
1877			return err;
1878		}
1879	dbch->xferq.flag |= FWXFERQ_RUNNING;
1880	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1881	for (i = 0, dbch->bottom = dbch->top; i < dbch->ndb - 1; i++)
1882		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1883	db_tr = dbch->top;
1884	if (db_tr->dbcnt != 0)
1885		goto run;
1886	for (idb = 0; idb < dbch->ndb; idb++) {
1887		if (dbch->off == OHCI_ARQOFF ||
1888		    dbch->off == OHCI_ARSOFF)
1889			bus_dmamap_sync(sc->fc.dmat, db_tr->dma_map,
1890			    0, db_tr->dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
1891		fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma);
1892		if (STAILQ_NEXT(db_tr, link) == NULL)
1893			break;
1894		db = db_tr->db;
1895		ldesc = db_tr->dbcnt - 1;
1896		FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend,
1897		    STAILQ_NEXT(db_tr, link)->bus_addr | z);
1898		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1899			if (((idb + 1) % dbch->xferq.bnpacket) == 0) {
1900				FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
1901				    OHCI_INTERRUPT_ALWAYS);
1902				FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
1903			}
1904		}
1905		db_tr = STAILQ_NEXT(db_tr, link);
1906	}
1907	FWOHCI_DMA_CLEAR(dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend,
1908	    0xf);
1909	dbch->buf_offset = 0;
1910run:
1911	fwdma_sync_multiseg_all(dbch->am,
1912	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1913	if (!(dbch->xferq.flag & FWXFERQ_STREAM)) {
1914		OWRITE(sc, OHCI_DMACMD(dbch->off), dbch->top->bus_addr | z);
1915		OWRITE(sc, OHCI_DMACTL(dbch->off), OHCI_CNTL_DMA_RUN);
1916	}
1917	return err;
1918}
1919
1920static int
1921fwohci_next_cycle(struct fwohci_softc *sc, int cycle_now)
1922{
1923	int sec, cycle, cycle_match;
1924
1925	cycle = cycle_now & 0x1fff;
1926	sec = cycle_now >> 13;
1927#define CYCLE_MOD	0x10
1928#if 1
1929#define CYCLE_DELAY	8	/* min delay to start DMA */
1930#else
1931#define CYCLE_DELAY	7000	/* min delay to start DMA */
1932#endif
1933	cycle = cycle + CYCLE_DELAY;
1934	if (cycle >= 8000) {
1935		sec++;
1936		cycle -= 8000;
1937	}
1938	cycle = roundup2(cycle, CYCLE_MOD);
1939	if (cycle >= 8000) {
1940		sec++;
1941		if (cycle == 8000)
1942			cycle = 0;
1943		else
1944			cycle = CYCLE_MOD;
1945	}
1946	cycle_match = ((sec << 13) | cycle) & 0x7ffff;
1947
1948	return cycle_match;
1949}
1950
1951#ifdef OHCI_DEBUG
1952static void
1953fwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat)
1954{
1955
1956	if (stat & OREAD(sc, FWOHCI_INTMASK))
1957		print("%s: INTERRUPT"
1958		    " < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>"
1959		    " 0x%08x, 0x%08x\n",
1960		    device_xname(fc->dev),
1961		    stat & OHCI_INT_EN ? "DMA_EN ":"",
1962		    stat & OHCI_INT_PHY_REG ? "PHY_REG ":"",
1963		    stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"",
1964		    stat & OHCI_INT_ERR ? "INT_ERR ":"",
1965		    stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"",
1966		    stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"",
1967		    stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"",
1968		    stat & OHCI_INT_CYC_START ? "CYC_START ":"",
1969		    stat & OHCI_INT_PHY_INT ? "PHY_INT ":"",
1970		    stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"",
1971		    stat & OHCI_INT_PHY_SID ? "SID ":"",
1972		    stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"",
1973		    stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"",
1974		    stat & OHCI_INT_DMA_IR ? "DMA_IR ":"",
1975		    stat & OHCI_INT_DMA_IT ? "DMA_IT " :"",
1976		    stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"",
1977		    stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"",
1978		    stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"",
1979		    stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"",
1980		    stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"",
1981		    stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"",
1982		    stat, OREAD(sc, FWOHCI_INTMASK)
1983		);
1984}
1985#endif
1986
1987static void
1988fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat)
1989{
1990	struct firewire_comm *fc = &sc->fc;
1991	uint32_t node_id, plen;
1992
1993	if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) {
1994		fc->status = FWBUSRESET;
1995		/* Disable bus reset interrupt until sid recv. */
1996		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R);
1997
1998		aprint_normal_dev(fc->dev, "BUS reset\n");
1999		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST);
2000		OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC);
2001
2002		OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
2003		sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING;
2004		OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
2005		sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
2006
2007		fw_busreset(&sc->fc, FWBUSRESET);
2008		OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
2009		OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
2010	}
2011	if (stat & OHCI_INT_PHY_SID) {
2012		/* Enable bus reset interrupt */
2013		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
2014		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R);
2015
2016		/* Allow async. request to us */
2017		OWRITE(sc, OHCI_AREQHI, 1U << 31);
2018		if (firewire_phydma_enable) {
2019			/* allow from all nodes */
2020			OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
2021			OWRITE(sc, OHCI_PREQLO, 0xffffffff);
2022			/* 0 to 4GB region */
2023			OWRITE(sc, OHCI_PREQUPPER, 0x10000);
2024		}
2025		/* Set ATRetries register */
2026		OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
2027
2028		/*
2029		 * Checking whether the node is root or not. If root, turn on
2030		 * cycle master.
2031		 */
2032		node_id = OREAD(sc, FWOHCI_NODEID);
2033		plen = OREAD(sc, OHCI_SID_CNT);
2034
2035		fc->nodeid = node_id & 0x3f;
2036		aprint_normal_dev(fc->dev, "node_id=0x%08x, gen=%d, ",
2037		    node_id, (plen >> 16) & 0xff);
2038		if (!(node_id & OHCI_NODE_VALID)) {
2039			aprint_error_dev(fc->dev, "Bus reset failure\n");
2040			goto sidout;
2041		}
2042
2043		/* cycle timer */
2044		sc->cycle_lost = 0;
2045		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_CYC_LOST);
2046		if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) {
2047			aprint_normal("CYCLEMASTER mode\n");
2048			OWRITE(sc, OHCI_LNKCTL,
2049			    OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
2050		} else {
2051			aprint_normal("non CYCLEMASTER mode\n");
2052			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
2053			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
2054		}
2055
2056		fc->status = FWBUSINIT;
2057
2058		fwohci_task_sid(sc);
2059	}
2060sidout:
2061	if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)))
2062		fwohci_task_dma(sc);
2063}
2064
2065static void
2066fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat)
2067{
2068	struct firewire_comm *fc = &sc->fc;
2069	uint32_t irstat, itstat;
2070	u_int i;
2071
2072	if (stat & OHCI_INT_DMA_IR) {
2073		irstat = atomic_swap_32(&sc->irstat, 0);
2074		for (i = 0; i < fc->nisodma; i++)
2075			if ((irstat & (1 << i)) != 0) {
2076				struct fwohci_dbch *dbch = &sc->ir[i];
2077
2078				if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) {
2079					aprint_error_dev(fc->dev,
2080					    "dma(%d) not active\n", i);
2081					continue;
2082				}
2083				fwohci_rbuf_update(sc, i);
2084			}
2085	}
2086	if (stat & OHCI_INT_DMA_IT) {
2087		itstat = atomic_swap_32(&sc->itstat, 0);
2088		for (i = 0; i < fc->nisodma; i++)
2089			if ((itstat & (1 << i)) != 0)
2090				fwohci_tbuf_update(sc, i);
2091	}
2092	if (stat & OHCI_INT_DMA_PRRS) {
2093#if 0
2094		dump_dma(sc, ARRS_CH);
2095		dump_db(sc, ARRS_CH);
2096#endif
2097		fwohci_arcv(sc, &sc->arrs);
2098	}
2099	if (stat & OHCI_INT_DMA_PRRQ) {
2100#if 0
2101		dump_dma(sc, ARRQ_CH);
2102		dump_db(sc, ARRQ_CH);
2103#endif
2104		fwohci_arcv(sc, &sc->arrq);
2105	}
2106	if (stat & OHCI_INT_CYC_LOST) {
2107		if (sc->cycle_lost >= 0)
2108			sc->cycle_lost++;
2109		if (sc->cycle_lost > 10) {
2110			sc->cycle_lost = -1;
2111#if 0
2112			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER);
2113#endif
2114			OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST);
2115			aprint_error_dev(fc->dev, "too many cycle lost, "
2116			    "no cycle master present?\n");
2117		}
2118	}
2119	if (stat & OHCI_INT_DMA_ATRQ)
2120		fwohci_txd(sc, &(sc->atrq));
2121	if (stat & OHCI_INT_DMA_ATRS)
2122		fwohci_txd(sc, &(sc->atrs));
2123	if (stat & OHCI_INT_PW_ERR)
2124		aprint_error_dev(fc->dev, "posted write error\n");
2125	if (stat & OHCI_INT_ERR)
2126		aprint_error_dev(fc->dev, "unrecoverable error\n");
2127	if (stat & OHCI_INT_PHY_INT)
2128		aprint_normal_dev(fc->dev, "phy int\n");
2129
2130	return;
2131}
2132
2133static void
2134fwohci_task_sid(struct fwohci_softc *sc)
2135{
2136	struct firewire_comm *fc = &sc->fc;
2137	uint32_t *buf;
2138	int i, plen;
2139
2140	plen = OREAD(sc, OHCI_SID_CNT);
2141
2142	if (plen & OHCI_SID_ERR) {
2143		aprint_error_dev(fc->dev, "SID Error\n");
2144		return;
2145	}
2146	plen &= OHCI_SID_CNT_MASK;
2147	if (plen < 4 || plen > OHCI_SIDSIZE) {
2148		aprint_error_dev(fc->dev, "invalid SID len = %d\n", plen);
2149		return;
2150	}
2151	plen -= 4; /* chop control info */
2152	buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
2153	if (buf == NULL) {
2154		aprint_error_dev(fc->dev, "malloc failed\n");
2155		return;
2156	}
2157	for (i = 0; i < plen / 4; i++)
2158		buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i + 1]);
2159#if 1 /* XXX needed?? */
2160	/* pending all pre-bus_reset packets */
2161	fwohci_txd(sc, &sc->atrq);
2162	fwohci_txd(sc, &sc->atrs);
2163	fwohci_arcv(sc, &sc->arrs);
2164	fwohci_arcv(sc, &sc->arrq);
2165	fw_drain_txq(fc);
2166#endif
2167	fw_sidrcv(fc, buf, plen);
2168	free(buf, M_FW);
2169}
2170
2171static void
2172fwohci_task_dma(struct fwohci_softc *sc)
2173{
2174	uint32_t stat;
2175
2176again:
2177	stat = atomic_swap_32(&sc->intstat, 0);
2178	if (stat)
2179		fwohci_intr_dma(sc, stat);
2180	else
2181		return;
2182	goto again;
2183}
2184
2185static void
2186fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
2187{
2188	struct firewire_comm *fc = &sc->fc;
2189	struct fwohcidb *db;
2190	struct fw_bulkxfer *chunk;
2191	struct fw_xferq *it;
2192	uint32_t stat;
2193#if 0
2194	uint32_t count;
2195#endif
2196	int w = 0, ldesc;
2197
2198	it = fc->it[dmach];
2199	ldesc = sc->it[dmach].ndesc - 1;
2200	mutex_enter(&fc->fc_mtx);
2201	fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
2202	if (firewire_debug)
2203		dump_db(sc, ITX_CH + dmach);
2204	while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
2205		db = ((struct fwohcidb_tr *)(chunk->end))->db;
2206		stat =
2207		    FWOHCI_DMA_READ(db[ldesc].db.desc.res) >> OHCI_STATUS_SHIFT;
2208		db = ((struct fwohcidb_tr *)(chunk->start))->db;
2209		/* timestamp */
2210#if 0
2211		count =
2212		    FWOHCI_DMA_READ(db[ldesc].db.desc.res) & OHCI_COUNT_MASK;
2213#else
2214		(void)FWOHCI_DMA_READ(db[ldesc].db.desc.res);
2215#endif
2216		if (stat == 0)
2217			break;
2218		STAILQ_REMOVE_HEAD(&it->stdma, link);
2219		switch (stat & FWOHCIEV_MASK) {
2220		case FWOHCIEV_ACKCOMPL:
2221#if 0
2222			printf("0x%08x\n", count);
2223#endif
2224			break;
2225		default:
2226			aprint_error_dev(fc->dev,
2227			    "Isochronous transmit err %02x(%s)\n",
2228			    stat, fwohcicode[stat & 0x1f]);
2229		}
2230		STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
2231		w++;
2232	}
2233	if (w)
2234		cv_broadcast(&it->cv);
2235	mutex_exit(&fc->fc_mtx);
2236}
2237
2238static void
2239fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
2240{
2241	struct firewire_comm *fc = &sc->fc;
2242	struct fwohcidb_tr *db_tr;
2243	struct fw_bulkxfer *chunk;
2244	struct fw_xferq *ir;
2245	uint32_t stat;
2246	int w = 0, ldesc;
2247
2248	ir = fc->ir[dmach];
2249	ldesc = sc->ir[dmach].ndesc - 1;
2250
2251#if 0
2252	dump_db(sc, dmach);
2253#endif
2254	if ((ir->flag & FWXFERQ_HANDLER) == 0)
2255		mutex_enter(&fc->fc_mtx);
2256	fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
2257	while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
2258		db_tr = (struct fwohcidb_tr *)chunk->end;
2259		stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) >>
2260		    OHCI_STATUS_SHIFT;
2261		if (stat == 0)
2262			break;
2263
2264		if (chunk->mbuf != NULL) {
2265			bus_dmamap_sync(fc->dmat, db_tr->dma_map, 0,
2266			    db_tr->dma_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
2267			bus_dmamap_unload(fc->dmat, db_tr->dma_map);
2268		} else if (ir->buf != NULL)
2269			fwdma_sync_multiseg(ir->buf, chunk->poffset,
2270			    ir->bnpacket, BUS_DMASYNC_POSTREAD);
2271		else
2272			/* XXX */
2273			aprint_error_dev(fc->dev,
2274			    "fwohci_rbuf_update: this shouldn't happen\n");
2275
2276		STAILQ_REMOVE_HEAD(&ir->stdma, link);
2277		STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link);
2278		switch (stat & FWOHCIEV_MASK) {
2279		case FWOHCIEV_ACKCOMPL:
2280			chunk->resp = 0;
2281			break;
2282		default:
2283			chunk->resp = EINVAL;
2284			aprint_error_dev(fc->dev,
2285			    "Isochronous receive err %02x(%s)\n",
2286			    stat, fwohcicode[stat & 0x1f]);
2287		}
2288		w++;
2289	}
2290	if ((ir->flag & FWXFERQ_HANDLER) == 0) {
2291		if (w)
2292			cv_broadcast(&ir->cv);
2293		mutex_exit(&fc->fc_mtx);
2294	}
2295	if (w == 0)
2296		return;
2297	if (ir->flag & FWXFERQ_HANDLER)
2298		ir->hand(ir);
2299}
2300
2301static void
2302dump_dma(struct fwohci_softc *sc, uint32_t ch)
2303{
2304	struct fwohci_dbch *dbch;
2305	uint32_t cntl, stat, cmd, match;
2306
2307	if (ch == ATRQ_CH)
2308		dbch = &sc->atrq;
2309	else if (ch == ATRS_CH)
2310		dbch = &sc->atrs;
2311	else if (ch == ARRQ_CH)
2312		dbch = &sc->arrq;
2313	else if (ch == ARRS_CH)
2314		dbch = &sc->arrs;
2315	else if (ch < IRX_CH)
2316		dbch = &sc->it[ch - ITX_CH];
2317	else
2318		dbch = &sc->ir[ch - IRX_CH];
2319	cntl = stat = OREAD(sc, dbch->off);
2320	cmd = OREAD(sc, dbch->off + 0xc);
2321	match = OREAD(sc, dbch->off + 0x10);
2322
2323	aprint_normal_dev(sc->fc.dev,
2324	    "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n",
2325	    ch,
2326	    cntl,
2327	    cmd,
2328	    match);
2329	stat &= 0xffff;
2330	if (stat)
2331		aprint_normal_dev(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n",
2332		    ch,
2333		    stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2334		    stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2335		    stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2336		    stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2337		    stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2338		    stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2339		    fwohcicode[stat & 0x1f],
2340		    stat & 0x1f
2341		);
2342	else
2343		aprint_normal_dev(sc->fc.dev, "dma %d ch: Nostat\n", ch);
2344}
2345
2346static void
2347dump_db(struct fwohci_softc *sc, uint32_t ch)
2348{
2349	struct fwohci_dbch *dbch;
2350	struct fwohcidb_tr *cp = NULL, *pp;
2351	struct fwohcidb *curr = NULL;
2352#if 0
2353	struct fwohcidb_tr *np = NULL;
2354	struct fwohcidb *prev, *next = NULL;
2355#endif
2356	int idb, jdb;
2357	uint32_t cmd;
2358
2359	if (ch == ATRQ_CH)
2360		dbch = &sc->atrq;
2361	else if (ch == ATRS_CH)
2362		dbch = &sc->atrs;
2363	else if (ch == ARRQ_CH)
2364		dbch = &sc->arrq;
2365	else if (ch == ARRS_CH)
2366		dbch = &sc->arrs;
2367	else if (ch < IRX_CH)
2368		dbch = &sc->it[ch - ITX_CH];
2369	else
2370		dbch = &sc->ir[ch - IRX_CH];
2371	cmd = OREAD(sc, dbch->off + 0xc);
2372
2373	if (dbch->ndb == 0) {
2374		aprint_error_dev(sc->fc.dev, "No DB is attached ch=%d\n", ch);
2375		return;
2376	}
2377	pp = dbch->top;
2378#if 0
2379	prev = pp->db;
2380#endif
2381	for (idb = 0; idb < dbch->ndb; idb++) {
2382		cp = STAILQ_NEXT(pp, link);
2383		if (cp == NULL) {
2384			curr = NULL;
2385			goto outdb;
2386		}
2387#if 0
2388		np = STAILQ_NEXT(cp, link);
2389#endif
2390		for (jdb = 0; jdb < dbch->ndesc; jdb++)
2391			if ((cmd & 0xfffffff0) == cp->bus_addr) {
2392				curr = cp->db;
2393#if 0
2394				if (np != NULL)
2395					next = np->db;
2396				else
2397					next = NULL;
2398#endif
2399				goto outdb;
2400			}
2401		pp = STAILQ_NEXT(pp, link);
2402		if (pp == NULL) {
2403			curr = NULL;
2404			goto outdb;
2405		}
2406#if 0
2407		prev = pp->db;
2408#endif
2409	}
2410outdb:
2411	if (curr != NULL) {
2412#if 0
2413		aprint_normal("Prev DB %d\n", ch);
2414		print_db(pp, prev, ch, dbch->ndesc);
2415#endif
2416		aprint_normal("Current DB %d\n", ch);
2417		print_db(cp, curr, ch, dbch->ndesc);
2418#if 0
2419		aprint_normal("Next DB %d\n", ch);
2420		print_db(np, next, ch, dbch->ndesc);
2421#endif
2422	} else
2423		aprint_error("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd);
2424	return;
2425}
2426
2427static void
2428print_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db, uint32_t ch,
2429	 uint32_t hogemax)
2430{
2431	fwohcireg_t stat;
2432	int i, key;
2433	uint32_t cmd, res;
2434
2435	if (db == NULL) {
2436		aprint_error("No Descriptor is found\n");
2437		return;
2438	}
2439
2440	aprint_normal("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n",
2441	    ch,
2442	    "Current",
2443	    "OP  ",
2444	    "KEY",
2445	    "INT",
2446	    "BR ",
2447	    "len",
2448	    "Addr",
2449	    "Depend",
2450	    "Stat",
2451	    "Cnt");
2452	for (i = 0; i <= hogemax; i++) {
2453		cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd);
2454		res = FWOHCI_DMA_READ(db[i].db.desc.res);
2455		key = cmd & OHCI_KEY_MASK;
2456		stat = res >> OHCI_STATUS_SHIFT;
2457		aprint_normal("%08jx %s %s %s %s %5d %08x %08x %04x:%04x",
2458		    (uintmax_t)db_tr->bus_addr,
2459		    dbcode[(cmd >> 28) & 0xf],
2460		    dbkey[(cmd >> 24) & 0x7],
2461		    dbcond[(cmd >> 20) & 0x3],
2462		    dbcond[(cmd >> 18) & 0x3],
2463		    cmd & OHCI_COUNT_MASK,
2464		    FWOHCI_DMA_READ(db[i].db.desc.addr),
2465		    FWOHCI_DMA_READ(db[i].db.desc.depend),
2466		    stat,
2467		    res & OHCI_COUNT_MASK);
2468		if (stat & 0xff00)
2469			aprint_normal(" %s%s%s%s%s%s %s(%x)\n",
2470			    stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2471			    stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2472			    stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2473			    stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2474			    stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2475			    stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2476			    fwohcicode[stat & 0x1f],
2477			    stat & 0x1f
2478			);
2479		else
2480			aprint_normal(" Nostat\n");
2481		if (key == OHCI_KEY_ST2)
2482			aprint_normal("0x%08x 0x%08x 0x%08x 0x%08x\n",
2483			    FWOHCI_DMA_READ(db[i+1].db.immed[0]),
2484			    FWOHCI_DMA_READ(db[i+1].db.immed[1]),
2485			    FWOHCI_DMA_READ(db[i+1].db.immed[2]),
2486			    FWOHCI_DMA_READ(db[i+1].db.immed[3]));
2487		if (key == OHCI_KEY_DEVICE)
2488			return;
2489		if ((cmd & OHCI_BRANCH_MASK) == OHCI_BRANCH_ALWAYS)
2490			return;
2491		if ((cmd & OHCI_CMD_MASK) == OHCI_OUTPUT_LAST)
2492			return;
2493		if ((cmd & OHCI_CMD_MASK) == OHCI_INPUT_LAST)
2494			return;
2495		if (key == OHCI_KEY_ST2)
2496			i++;
2497	}
2498	return;
2499}
2500
2501static void
2502fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
2503{
2504	struct fwohcidb_tr *db_tr /*, *fdb_tr */;
2505	struct fwohci_dbch *dbch;
2506	struct fwohcidb *db;
2507	struct fw_pkt *fp;
2508	struct fwohci_txpkthdr *ohcifp;
2509	unsigned short chtag;
2510	int idb;
2511
2512	KASSERT(mutex_owned(&sc->fc.fc_mtx));
2513
2514	dbch = &sc->it[dmach];
2515	chtag = sc->it[dmach].xferq.flag & 0xff;
2516
2517	db_tr = (struct fwohcidb_tr *)(bulkxfer->start);
2518/*
2519	fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end);
2520aprint_normal(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr);
2521*/
2522	for (idb = 0; idb < dbch->xferq.bnpacket; idb++) {
2523		db = db_tr->db;
2524		fp = (struct fw_pkt *)db_tr->buf;
2525		ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed;
2526		ohcifp->mode.ld[0] = fp->mode.ld[0];
2527		ohcifp->mode.common.spd = 0 & 0x7;
2528		ohcifp->mode.stream.len = fp->mode.stream.len;
2529		ohcifp->mode.stream.chtag = chtag;
2530		ohcifp->mode.stream.tcode = 0xa;
2531#if BYTE_ORDER == BIG_ENDIAN
2532		FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]);
2533		FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]);
2534#endif
2535
2536		FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK);
2537		FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len);
2538		FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2539#if 0 /* if bulkxfer->npackets changes */
2540		db[2].db.desc.cmd =
2541		    OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS;
2542		db[0].db.desc.depend = db[dbch->ndesc - 1].db.desc.depend =
2543		    STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc;
2544#else
2545		FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
2546		FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc);
2547#endif
2548		bulkxfer->end = (void *)db_tr;
2549		db_tr = STAILQ_NEXT(db_tr, link);
2550	}
2551	db = ((struct fwohcidb_tr *)bulkxfer->end)->db;
2552	FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf);
2553	FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf);
2554#if 0 /* if bulkxfer->npackets changes */
2555	db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2556	/* OHCI 1.1 and above */
2557	db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2558#endif
2559/*
2560	db_tr = (struct fwohcidb_tr *)bulkxfer->start;
2561	fdb_tr = (struct fwohcidb_tr *)bulkxfer->end;
2562aprint_normal(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr);
2563*/
2564	return;
2565}
2566
2567static int
2568fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2569		  int poffset)
2570{
2571	struct fwohcidb *db = db_tr->db;
2572	struct fw_xferq *it;
2573	int err = 0;
2574
2575	it = &dbch->xferq;
2576	if (it->buf == 0) {
2577		err = EINVAL;
2578		return err;
2579	}
2580	db_tr->buf = fwdma_v_addr(it->buf, poffset);
2581	db_tr->dbcnt = 3;
2582
2583	FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
2584	    OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
2585	FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0);
2586	memset((void *)db[1].db.immed, 0, sizeof(db[1].db.immed));
2587	FWOHCI_DMA_WRITE(db[2].db.desc.addr,
2588	    fwdma_bus_addr(it->buf, poffset) + sizeof(uint32_t));
2589
2590	FWOHCI_DMA_WRITE(db[2].db.desc.cmd,
2591	    OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS);
2592#if 1
2593	FWOHCI_DMA_WRITE(db[0].db.desc.res, 0);
2594	FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2595#endif
2596	return 0;
2597}
2598
2599int
2600fwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2601		  int poffset, struct fwdma_alloc *dummy_dma)
2602{
2603	struct fwohcidb *db = db_tr->db;
2604	struct fw_xferq *rq;
2605	int i, ldesc;
2606	bus_addr_t dbuf[2];
2607	int dsiz[2];
2608
2609	rq = &dbch->xferq;
2610	if (rq->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) {
2611		/* async */
2612		db_tr->dbcnt = 1;
2613		dsiz[0] = rq->psize;
2614		dbuf[0] = db_tr->dma_map->dm_segs[0].ds_addr;
2615	} else {
2616		/* isoc */
2617		db_tr->dbcnt = 0;
2618		dsiz[db_tr->dbcnt] = sizeof(uint32_t);
2619		dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr;
2620		dsiz[db_tr->dbcnt] = rq->psize;
2621		if (rq->buf != NULL) {
2622			db_tr->buf = fwdma_v_addr(rq->buf, poffset);
2623			dbuf[db_tr->dbcnt] = fwdma_bus_addr(rq->buf, poffset);
2624		}
2625		db_tr->dbcnt++;
2626	}
2627	for (i = 0; i < db_tr->dbcnt; i++) {
2628		FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]);
2629		FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]);
2630		if (rq->flag & FWXFERQ_STREAM)
2631			FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE);
2632		FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]);
2633	}
2634	ldesc = db_tr->dbcnt - 1;
2635	if (rq->flag & FWXFERQ_STREAM)
2636		FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST);
2637	FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS);
2638	return 0;
2639}
2640
2641
2642static int
2643fwohci_arcv_swap(struct fw_pkt *fp, int len)
2644{
2645	struct fw_pkt *fp0;
2646	union {
2647		uint32_t ld0;
2648		struct fw_pkt pkt;
2649	} pktu;
2650	int hlen;
2651#if BYTE_ORDER == BIG_ENDIAN
2652	int slen, i;
2653#endif
2654
2655	pktu.ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]);
2656#if 0
2657	printf("ld0: x%08x\n", pktu.ld0);
2658#endif
2659	fp0 = (struct fw_pkt *)&pktu;
2660	/* determine length to swap */
2661	switch (fp0->mode.common.tcode) {
2662	case FWTCODE_WRES:
2663	case FWTCODE_RREQQ:
2664	case FWTCODE_WREQQ:
2665	case FWTCODE_RRESQ:
2666	case FWOHCITCODE_PHY:
2667#if BYTE_ORDER == BIG_ENDIAN
2668		slen = 12;
2669#endif
2670		break;
2671
2672	case FWTCODE_RREQB:
2673	case FWTCODE_WREQB:
2674	case FWTCODE_LREQ:
2675	case FWTCODE_RRESB:
2676	case FWTCODE_LRES:
2677#if BYTE_ORDER == BIG_ENDIAN
2678		slen = 16;
2679#endif
2680		break;
2681
2682	default:
2683		aprint_error("Unknown tcode %d\n", fp0->mode.common.tcode);
2684		return 0;
2685	}
2686	hlen = tinfo[fp0->mode.common.tcode].hdr_len;
2687	if (hlen > len) {
2688		if (firewire_debug)
2689			printf("split header\n");
2690		return len - hlen;
2691	}
2692#if BYTE_ORDER == BIG_ENDIAN
2693	for (i = 0; i < slen / 4; i++)
2694		fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
2695#endif
2696	return hlen;
2697}
2698
2699static int
2700fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch,
2701		struct fw_pkt *fp)
2702{
2703	const struct tcode_info *info;
2704	int r;
2705
2706	info = &tinfo[fp->mode.common.tcode];
2707	r = info->hdr_len + sizeof(uint32_t);
2708	if (info->flag & FWTI_BLOCK_ASY)
2709		r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t));
2710
2711	if (r == sizeof(uint32_t)) {
2712		/* XXX */
2713		aprint_error_dev(sc->fc.dev, "Unknown tcode %d\n",
2714		    fp->mode.common.tcode);
2715		return -1;
2716	}
2717
2718	if (r > dbch->xferq.psize) {
2719		aprint_error_dev(sc->fc.dev, "Invalid packet length %d\n", r);
2720		return -1;
2721		/* panic ? */
2722	}
2723
2724	return r;
2725}
2726
2727static void
2728fwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch,
2729		     struct fwohcidb_tr *db_tr, int wake)
2730{
2731	struct fwohcidb *db = db_tr->db;
2732	struct fwohcidb_tr *bdb_tr = dbch->bottom;
2733
2734	FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
2735	FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
2736
2737	fwdma_sync_multiseg(dbch->am, bdb_tr->idx, bdb_tr->idx,
2738	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2739	FWOHCI_DMA_SET(bdb_tr->db[0].db.desc.depend, dbch->ndesc);
2740
2741	fwdma_sync_multiseg(dbch->am, bdb_tr->idx, db_tr->idx,
2742	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2743	dbch->bottom = db_tr;
2744
2745	if (wake)
2746		OWRITE(sc, OHCI_DMACTL(dbch->off), OHCI_CNTL_DMA_WAKE);
2747}
2748
2749static void
2750fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
2751{
2752	struct fwohcidb_tr *db_tr;
2753	struct fw_pkt pktbuf, *fp;
2754	struct iovec vec[2];
2755	bus_addr_t m;
2756	bus_size_t n;
2757	u_int spd;
2758	uint32_t stat, status, event;
2759	uint8_t *ld;
2760	int nvec, resCount, len, plen, hlen, offset;
2761	const int psize = dbch->xferq.psize;
2762
2763#if DIAGNOSTIC
2764	if (dbch->off != OHCI_ARQOFF &&
2765	    dbch->off != OHCI_ARSOFF)
2766		panic("not async rx");
2767#endif
2768
2769	mutex_enter(&dbch->xferq.q_mtx);
2770	db_tr = dbch->top;
2771	/* XXX we cannot handle a packet which lies in more than two buf */
2772	fwdma_sync_multiseg(dbch->am, db_tr->idx, db_tr->idx,
2773	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2774	status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
2775	resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
2776	while (status & OHCI_CNTL_DMA_ACTIVE) {
2777#if 0
2778		if (dbch->off == OHCI_ARQOFF)
2779			aprint_normal_dev(sc->fc.dev,
2780			    "buf 0x%08x, status 0x%04x, resCount 0x%04x\n",
2781			    db_tr->bus_addr, status, resCount);
2782#endif
2783		n = 0;
2784		len = psize - resCount;
2785		ld = (uint8_t *)db_tr->buf;
2786		if (dbch->pdb_tr == NULL) {
2787			len -= dbch->buf_offset;
2788			ld += dbch->buf_offset;
2789			m = dbch->buf_offset;
2790		} else
2791			m = 0;
2792		if (len > 0)
2793			bus_dmamap_sync(sc->fc.dmat, db_tr->dma_map,
2794			    m, len, BUS_DMASYNC_POSTREAD);
2795		while (len > 0) {
2796			if (dbch->pdb_tr != NULL) {
2797				/* we have a fragment in previous buffer */
2798				int rlen = 0;
2799				void *buf;
2800
2801				if (dbch->buf_offset < 0) {
2802					/* split in header, pull up */
2803					char *p;
2804
2805					rlen -= dbch->buf_offset;
2806					buf = (char *)dbch->pdb_tr->buf +
2807					    psize - rlen;
2808
2809					KASSERT(rlen <= sizeof(pktbuf));
2810
2811					p = (char *)&pktbuf;
2812					memcpy(p, buf, rlen);
2813					p += rlen;
2814					/* this must be too long but harmless */
2815					rlen = sizeof(pktbuf) - rlen;
2816					memcpy(p, db_tr->buf, rlen);
2817					ld += rlen;
2818					len -= rlen;
2819					hlen = fwohci_arcv_swap(&pktbuf,
2820					    sizeof(pktbuf));
2821					if (hlen <= 0) {
2822						aprint_error_dev(sc->fc.dev,
2823						    "hlen should be positive.");
2824						goto err;
2825					}
2826					offset = sizeof(pktbuf);
2827					vec[0].iov_base = (char *)&pktbuf;
2828					vec[0].iov_len = offset;
2829				} else {
2830					/* split in payload */
2831					buf = (char *)dbch->pdb_tr->buf +
2832					    dbch->buf_offset;
2833					rlen = psize - dbch->buf_offset;
2834					if (firewire_debug)
2835						printf("rlen=%d, offset=%d\n",
2836						    rlen, dbch->buf_offset);
2837					offset = rlen;
2838					vec[0].iov_base = buf;
2839					vec[0].iov_len = rlen;
2840				}
2841				fp = (struct fw_pkt *)vec[0].iov_base;
2842				nvec = 1;
2843			} else {
2844				/* no fragment in previous buffer */
2845				fp = (struct fw_pkt *)ld;
2846				hlen = fwohci_arcv_swap(fp, len);
2847				if (hlen == 0)
2848					goto err;
2849				if (hlen < 0) {
2850					dbch->pdb_tr = db_tr;
2851					dbch->buf_offset -= psize;
2852					/* sanity check */
2853					if (resCount != 0)  {
2854						aprint_error_dev(sc->fc.dev,
2855						    "resCount=%d hlen=%d\n",
2856						    resCount, hlen);
2857						goto err;
2858					}
2859					goto out;
2860				}
2861				offset = 0;
2862				nvec = 0;
2863			}
2864			plen = fwohci_get_plen(sc, dbch, fp) - offset;
2865			if (plen < 0) {
2866				/*
2867				 * minimum header size + trailer =
2868				 *     sizeof(fw_pkt) so this shouldn't happens
2869				 */
2870				aprint_error_dev(sc->fc.dev,
2871				    "plen(%d) is negative! offset=%d\n",
2872				    plen, offset);
2873				goto err;
2874			}
2875			if (plen > 0) {
2876				len -= plen;
2877				if (len < 0) {
2878					dbch->pdb_tr = db_tr;
2879					if (firewire_debug)
2880						printf("split payload\n");
2881					/* sanity check */
2882					if (resCount != 0) {
2883						aprint_error_dev(sc->fc.dev,
2884						    "resCount=%d plen=%d"
2885						    " len=%d\n",
2886						    resCount, plen, len);
2887						goto err;
2888					}
2889					goto out;
2890				}
2891				vec[nvec].iov_base = ld;
2892				vec[nvec].iov_len = plen;
2893				nvec++;
2894				ld += plen;
2895			}
2896			if (nvec == 0)
2897				aprint_error_dev(sc->fc.dev, "nvec == 0\n");
2898
2899/* DMA result-code will be written at the tail of packet */
2900			stat = FWOHCI_DMA_READ(*(uint32_t *)(ld -
2901						sizeof(struct fwohci_trailer)));
2902#if 0
2903			aprint_normal("plen: %d, stat %x\n", plen, stat);
2904#endif
2905			spd = (stat >> 21) & 0x3;
2906			event = (stat >> 16) & 0x1f;
2907			switch (event) {
2908			case FWOHCIEV_ACKPEND:
2909#if 0
2910				aprint_normal(sc->fc.dev,
2911				    "ack pending tcode=0x%x..\n",
2912				    fp->mode.common.tcode);
2913#endif
2914				/* fall through */
2915			case FWOHCIEV_ACKCOMPL:
2916			{
2917				struct fw_rcv_buf rb;
2918
2919				vec[nvec - 1].iov_len -=
2920				    sizeof(struct fwohci_trailer);
2921				if (vec[nvec - 1].iov_len == 0)
2922					nvec--;
2923				rb.fc = &sc->fc;
2924				rb.vec = vec;
2925				rb.nvec = nvec;
2926				rb.spd = spd;
2927				fw_rcv(&rb);
2928				break;
2929			}
2930			case FWOHCIEV_BUSRST:
2931				if ((sc->fc.status != FWBUSRESET) &&
2932				    (sc->fc.status != FWBUSINIT))
2933					aprint_error_dev(sc->fc.dev,
2934					    "got BUSRST packet!?\n");
2935				break;
2936			default:
2937				aprint_error_dev(sc->fc.dev,
2938				    "Async DMA Receive error err=%02x %s"
2939				    " plen=%d offset=%d len=%d status=0x%08x"
2940				    " tcode=0x%x, stat=0x%08x\n",
2941				    event, fwohcicode[event], plen,
2942				    (int)(ld - (uint8_t *)db_tr->buf - plen),
2943				    len, OREAD(sc, OHCI_DMACTL(dbch->off)),
2944				    fp->mode.common.tcode, stat);
2945#if 1 /* XXX */
2946				goto err;
2947#endif
2948				break;
2949			}
2950			if (dbch->pdb_tr != NULL) {
2951				if (dbch->buf_offset < 0)
2952					bus_dmamap_sync(sc->fc.dmat,
2953					    dbch->pdb_tr->dma_map,
2954					    psize + dbch->buf_offset,
2955					    0 - dbch->buf_offset,
2956					    BUS_DMASYNC_PREREAD);
2957				else
2958					bus_dmamap_sync(sc->fc.dmat,
2959					    dbch->pdb_tr->dma_map,
2960					    dbch->buf_offset,
2961					    psize - dbch->buf_offset,
2962					    BUS_DMASYNC_PREREAD);
2963				fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr, 1);
2964				dbch->pdb_tr = NULL;
2965			}
2966			dbch->buf_offset = ld - (uint8_t *)db_tr->buf;
2967			n += (plen + offset);
2968		}
2969out:
2970		if (n > 0)
2971			bus_dmamap_sync(sc->fc.dmat, db_tr->dma_map, m, n,
2972			    BUS_DMASYNC_PREREAD);
2973
2974		if (resCount != 0) {
2975			dbch->buf_offset = psize - resCount;
2976			break;
2977		}
2978
2979		/* done on this buffer */
2980
2981		if (dbch->pdb_tr == NULL) {
2982			fwohci_arcv_free_buf(sc, dbch, db_tr, 1);
2983			dbch->buf_offset = 0;
2984		} else
2985			if (dbch->pdb_tr != db_tr)
2986				aprint_error_dev(sc->fc.dev,
2987				    "pdb_tr != db_tr\n");
2988		dbch->top = STAILQ_NEXT(db_tr, link);
2989
2990		db_tr = dbch->top;
2991		fwdma_sync_multiseg(dbch->am, db_tr->idx, db_tr->idx,
2992		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2993		status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >>
2994		    OHCI_STATUS_SHIFT;
2995		resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2996		    & OHCI_COUNT_MASK;
2997
2998		/* XXX check buffer overrun */
2999
3000		/* XXX make sure DMA is not dead */
3001	}
3002	fwdma_sync_multiseg(dbch->am, db_tr->idx, db_tr->idx,
3003	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3004	mutex_exit(&dbch->xferq.q_mtx);
3005	return;
3006
3007err:
3008	aprint_error_dev(sc->fc.dev, "AR DMA status=%x, ",
3009	    OREAD(sc, OHCI_DMACTL(dbch->off)));
3010	if (dbch->pdb_tr != NULL) {
3011		if (dbch->buf_offset < 0)
3012			bus_dmamap_sync(sc->fc.dmat, dbch->pdb_tr->dma_map,
3013			    psize + dbch->buf_offset, 0 - dbch->buf_offset,
3014			    BUS_DMASYNC_PREREAD);
3015		else
3016			bus_dmamap_sync(sc->fc.dmat, dbch->pdb_tr->dma_map,
3017			    dbch->buf_offset, psize - dbch->buf_offset,
3018			    BUS_DMASYNC_PREREAD);
3019		fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr, 1);
3020		dbch->pdb_tr = NULL;
3021	}
3022	/* skip until resCount != 0 */
3023	aprint_error(" skip buffer");
3024	while (resCount == 0) {
3025		aprint_error(" #");
3026		fwohci_arcv_free_buf(sc, dbch, db_tr, 0);
3027		db_tr = STAILQ_NEXT(db_tr, link);
3028		resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
3029		    & OHCI_COUNT_MASK;
3030	}
3031	aprint_error(" done\n");
3032	dbch->top = db_tr;
3033	dbch->buf_offset = psize - resCount;
3034	OWRITE(sc, OHCI_DMACTL(dbch->off), OHCI_CNTL_DMA_WAKE);
3035	fwdma_sync_multiseg(dbch->am, db_tr->idx, db_tr->idx,
3036	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3037	bus_dmamap_sync(sc->fc.dmat, db_tr->dma_map,
3038	    0, db_tr->dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
3039	mutex_exit(&dbch->xferq.q_mtx);
3040}
3041