fwohci.c revision 118293
1193326Sed/*
2193326Sed * Copyright (c) 2003 Hidetoshi Shimokawa
3193326Sed * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4193326Sed * All rights reserved.
5193326Sed *
6193326Sed * Redistribution and use in source and binary forms, with or without
7193326Sed * modification, are permitted provided that the following conditions
8193326Sed * are met:
9193326Sed * 1. Redistributions of source code must retain the above copyright
10221345Sdim *    notice, this list of conditions and the following disclaimer.
11193326Sed * 2. Redistributions in binary form must reproduce the above copyright
12193326Sed *    notice, this list of conditions and the following disclaimer in the
13193326Sed *    documentation and/or other materials provided with the distribution.
14193326Sed * 3. All advertising materials mentioning features or use of this software
15193326Sed *    must display the acknowledgement as bellow:
16193326Sed *
17193326Sed *    This product includes software developed by K. Kobayashi and H. Shimokawa
18249423Sdim *
19249423Sdim * 4. The name of the author may not be used to endorse or promote products
20193326Sed *    derived from this software without specific prior written permission.
21193326Sed *
22193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23193326Sed * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24193326Sed * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25193326Sed * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26249423Sdim * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27221345Sdim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28193326Sed * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30249423Sdim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31249423Sdim * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32249423Sdim * POSSIBILITY OF SUCH DAMAGE.
33249423Sdim *
34221345Sdim * $FreeBSD: head/sys/dev/firewire/fwohci.c 118293 2003-08-01 04:51:21Z simokawa $
35193326Sed *
36226633Sdim */
37193326Sed
38193326Sed#define ATRQ_CH 0
39193326Sed#define ATRS_CH 1
40193326Sed#define ARRQ_CH 2
41193326Sed#define ARRS_CH 3
42193326Sed#define ITX_CH 4
43193326Sed#define IRX_CH 0x24
44221345Sdim
45221345Sdim#include <sys/param.h>
46221345Sdim#include <sys/systm.h>
47221345Sdim#include <sys/mbuf.h>
48221345Sdim#include <sys/malloc.h>
49224145Sdim#include <sys/sockio.h>
50221345Sdim#include <sys/bus.h>
51223017Sdim#include <sys/kernel.h>
52221345Sdim#include <sys/conf.h>
53221345Sdim#include <sys/endian.h>
54221345Sdim
55221345Sdim#include <machine/bus.h>
56221345Sdim
57221345Sdim#if __FreeBSD_version < 500000
58221345Sdim#include <machine/clock.h>		/* for DELAY() */
59221345Sdim#endif
60221345Sdim
61221345Sdim#include <dev/firewire/firewire.h>
62224145Sdim#include <dev/firewire/firewirereg.h>
63221345Sdim#include <dev/firewire/fwdma.h>
64221345Sdim#include <dev/firewire/fwohcireg.h>
65221345Sdim#include <dev/firewire/fwohcivar.h>
66221345Sdim#include <dev/firewire/firewire_phy.h>
67221345Sdim
68221345Sdim#undef OHCI_DEBUG
69224145Sdim
70221345Sdimstatic char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL",
71221345Sdim		"STOR","LOAD","NOP ","STOP",};
72221345Sdim
73221345Sdimstatic char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3",
74221345Sdim		"UNDEF","REG","SYS","DEV"};
75221345Sdimstatic char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"};
76221345Sdimchar fwohcicode[32][0x20]={
77223017Sdim	"No stat","Undef","long","miss Ack err",
78221345Sdim	"underrun","overrun","desc err", "data read err",
79221345Sdim	"data write err","bus reset","timeout","tcode err",
80221345Sdim	"Undef","Undef","unknown event","flushed",
81226633Sdim	"Undef","ack complete","ack pend","Undef",
82221345Sdim	"ack busy_X","ack busy_A","ack busy_B","Undef",
83221345Sdim	"Undef","Undef","Undef","ack tardy",
84221345Sdim	"Undef","ack data_err","ack type_err",""};
85223017Sdim
86221345Sdim#define MAX_SPEED 3
87221345Sdimextern char linkspeed[][0x10];
88221345Sdimu_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
89221345Sdim
90221345Sdimstatic struct tcode_info tinfo[] = {
91221345Sdim/*		hdr_len block 	flag*/
92223017Sdim/* 0 WREQQ  */ {16,	FWTI_REQ | FWTI_TLABEL},
93223017Sdim/* 1 WREQB  */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
94223017Sdim/* 2 WRES   */ {12,	FWTI_RES},
95223017Sdim/* 3 XXX    */ { 0,	0},
96221345Sdim/* 4 RREQQ  */ {12,	FWTI_REQ | FWTI_TLABEL},
97221345Sdim/* 5 RREQB  */ {16,	FWTI_REQ | FWTI_TLABEL},
98221345Sdim/* 6 RRESQ  */ {16,	FWTI_RES},
99221345Sdim/* 7 RRESB  */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
100239462Sdim/* 8 CYCS   */ { 0,	0},
101239462Sdim/* 9 LREQ   */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
102221345Sdim/* a STREAM */ { 4,	FWTI_REQ | FWTI_BLOCK_STR},
103221345Sdim/* b LRES   */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
104221345Sdim/* c XXX    */ { 0,	0},
105193326Sed/* d XXX    */ { 0, 	0},
106221345Sdim/* e PHY    */ {12,	FWTI_REQ},
107221345Sdim/* f XXX    */ { 0,	0}
108226633Sdim};
109221345Sdim
110221345Sdim#define OHCI_WRITE_SIGMASK 0xffff0000
111226633Sdim#define OHCI_READ_SIGMASK 0xffff0000
112221345Sdim
113221345Sdim#define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x))
114221345Sdim#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r))
115224145Sdim
116221345Sdimstatic void fwohci_ibr __P((struct firewire_comm *));
117221345Sdimstatic void fwohci_db_init __P((struct fwohci_softc *, struct fwohci_dbch *));
118226633Sdimstatic void fwohci_db_free __P((struct fwohci_dbch *));
119221345Sdimstatic void fwohci_arcv __P((struct fwohci_softc *, struct fwohci_dbch *, int));
120221345Sdimstatic void fwohci_txd __P((struct fwohci_softc *, struct fwohci_dbch *));
121224145Sdimstatic void fwohci_start_atq __P((struct firewire_comm *));
122221345Sdimstatic void fwohci_start_ats __P((struct firewire_comm *));
123221345Sdimstatic void fwohci_start __P((struct fwohci_softc *, struct fwohci_dbch *));
124221345Sdimstatic u_int32_t fwphy_wrdata __P(( struct fwohci_softc *, u_int32_t, u_int32_t));
125221345Sdimstatic u_int32_t fwphy_rddata __P(( struct fwohci_softc *, u_int32_t));
126221345Sdimstatic int fwohci_rx_enable __P((struct fwohci_softc *, struct fwohci_dbch *));
127224145Sdimstatic int fwohci_tx_enable __P((struct fwohci_softc *, struct fwohci_dbch *));
128221345Sdimstatic int fwohci_irx_enable __P((struct firewire_comm *, int));
129221345Sdimstatic int fwohci_irx_disable __P((struct firewire_comm *, int));
130221345Sdim#if BYTE_ORDER == BIG_ENDIAN
131221345Sdimstatic void fwohci_irx_post __P((struct firewire_comm *, u_int32_t *));
132224145Sdim#endif
133221345Sdimstatic int fwohci_itxbuf_enable __P((struct firewire_comm *, int));
134221345Sdimstatic int fwohci_itx_disable __P((struct firewire_comm *, int));
135226633Sdimstatic void fwohci_timeout __P((void *));
136221345Sdimstatic void fwohci_set_intr __P((struct firewire_comm *, int));
137221345Sdim
138204643Srdivackystatic int fwohci_add_rx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *));
139221345Sdimstatic int fwohci_add_tx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int));
140224145Sdimstatic void	dump_db __P((struct fwohci_softc *, u_int32_t));
141221345Sdimstatic void 	print_db __P((struct fwohcidb_tr *, volatile struct fwohcidb *, u_int32_t , u_int32_t));
142221345Sdimstatic void	dump_dma __P((struct fwohci_softc *, u_int32_t));
143221345Sdimstatic u_int32_t fwohci_cyctimer __P((struct firewire_comm *));
144224145Sdimstatic void fwohci_rbuf_update __P((struct fwohci_softc *, int));
145221345Sdimstatic void fwohci_tbuf_update __P((struct fwohci_softc *, int));
146221345Sdimvoid fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *));
147221345Sdim#if FWOHCI_TASKQUEUE
148224145Sdimstatic void fwohci_complete(void *, int);
149221345Sdim#endif
150226633Sdim
151226633Sdim/*
152226633Sdim * memory allocated for DMA programs
153221345Sdim */
154226633Sdim#define DMA_PROG_ALLOC		(8 * PAGE_SIZE)
155221345Sdim
156221345Sdim/* #define NDB 1024 */
157226633Sdim#define NDB FWMAXQUEUE
158221345Sdim#define NDVDB (DVBUF * NDB)
159226633Sdim
160226633Sdim#define	OHCI_VERSION		0x00
161226633Sdim#define	OHCI_ATRETRY		0x08
162226633Sdim#define	OHCI_CROMHDR		0x18
163226633Sdim#define	OHCI_BUS_OPT		0x20
164221345Sdim#define	OHCI_BUSIRMC		(1 << 31)
165221345Sdim#define	OHCI_BUSCMC		(1 << 30)
166221345Sdim#define	OHCI_BUSISC		(1 << 29)
167221345Sdim#define	OHCI_BUSBMC		(1 << 28)
168221345Sdim#define	OHCI_BUSPMC		(1 << 27)
169221345Sdim#define OHCI_BUSFNC		OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\
170221345Sdim				OHCI_BUSBMC | OHCI_BUSPMC
171221345Sdim
172221345Sdim#define	OHCI_EUID_HI		0x24
173221345Sdim#define	OHCI_EUID_LO		0x28
174226633Sdim
175221345Sdim#define	OHCI_CROMPTR		0x34
176221345Sdim#define	OHCI_HCCCTL		0x50
177221345Sdim#define	OHCI_HCCCTLCLR		0x54
178221345Sdim#define	OHCI_AREQHI		0x100
179221345Sdim#define	OHCI_AREQHICLR		0x104
180221345Sdim#define	OHCI_AREQLO		0x108
181221345Sdim#define	OHCI_AREQLOCLR		0x10c
182221345Sdim#define	OHCI_PREQHI		0x110
183221345Sdim#define	OHCI_PREQHICLR		0x114
184221345Sdim#define	OHCI_PREQLO		0x118
185234353Sdim#define	OHCI_PREQLOCLR		0x11c
186221345Sdim#define	OHCI_PREQUPPER		0x120
187221345Sdim
188221345Sdim#define	OHCI_SID_BUF		0x64
189226633Sdim#define	OHCI_SID_CNT		0x68
190221345Sdim#define OHCI_SID_ERR		(1 << 31)
191221345Sdim#define OHCI_SID_CNT_MASK	0xffc
192221345Sdim
193221345Sdim#define	OHCI_IT_STAT		0x90
194226633Sdim#define	OHCI_IT_STATCLR		0x94
195249423Sdim#define	OHCI_IT_MASK		0x98
196226633Sdim#define	OHCI_IT_MASKCLR		0x9c
197221345Sdim
198221345Sdim#define	OHCI_IR_STAT		0xa0
199221345Sdim#define	OHCI_IR_STATCLR		0xa4
200221345Sdim#define	OHCI_IR_MASK		0xa8
201221345Sdim#define	OHCI_IR_MASKCLR		0xac
202221345Sdim
203221345Sdim#define	OHCI_LNKCTL		0xe0
204221345Sdim#define	OHCI_LNKCTLCLR		0xe4
205221345Sdim
206226633Sdim#define	OHCI_PHYACCESS		0xec
207249423Sdim#define	OHCI_CYCLETIMER		0xf0
208226633Sdim
209221345Sdim#define	OHCI_DMACTL(off)	(off)
210221345Sdim#define	OHCI_DMACTLCLR(off)	(off + 4)
211221345Sdim#define	OHCI_DMACMD(off)	(off + 0xc)
212221345Sdim#define	OHCI_DMAMATCH(off)	(off + 0x10)
213221345Sdim
214221345Sdim#define OHCI_ATQOFF		0x180
215221345Sdim#define OHCI_ATQCTL		OHCI_ATQOFF
216221345Sdim#define OHCI_ATQCTLCLR		(OHCI_ATQOFF + 4)
217226633Sdim#define OHCI_ATQCMD		(OHCI_ATQOFF + 0xc)
218249423Sdim#define OHCI_ATQMATCH		(OHCI_ATQOFF + 0x10)
219226633Sdim
220221345Sdim#define OHCI_ATSOFF		0x1a0
221221345Sdim#define OHCI_ATSCTL		OHCI_ATSOFF
222221345Sdim#define OHCI_ATSCTLCLR		(OHCI_ATSOFF + 4)
223221345Sdim#define OHCI_ATSCMD		(OHCI_ATSOFF + 0xc)
224221345Sdim#define OHCI_ATSMATCH		(OHCI_ATSOFF + 0x10)
225243830Sdim
226243830Sdim#define OHCI_ARQOFF		0x1c0
227243830Sdim#define OHCI_ARQCTL		OHCI_ARQOFF
228249423Sdim#define OHCI_ARQCTLCLR		(OHCI_ARQOFF + 4)
229243830Sdim#define OHCI_ARQCMD		(OHCI_ARQOFF + 0xc)
230243830Sdim#define OHCI_ARQMATCH		(OHCI_ARQOFF + 0x10)
231243830Sdim
232243830Sdim#define OHCI_ARSOFF		0x1e0
233243830Sdim#define OHCI_ARSCTL		OHCI_ARSOFF
234243830Sdim#define OHCI_ARSCTLCLR		(OHCI_ARSOFF + 4)
235243830Sdim#define OHCI_ARSCMD		(OHCI_ARSOFF + 0xc)
236243830Sdim#define OHCI_ARSMATCH		(OHCI_ARSOFF + 0x10)
237243830Sdim
238243830Sdim#define OHCI_ITOFF(CH)		(0x200 + 0x10 * (CH))
239249423Sdim#define OHCI_ITCTL(CH)		(OHCI_ITOFF(CH))
240243830Sdim#define OHCI_ITCTLCLR(CH)	(OHCI_ITOFF(CH) + 4)
241243830Sdim#define OHCI_ITCMD(CH)		(OHCI_ITOFF(CH) + 0xc)
242243830Sdim
243243830Sdim#define OHCI_IROFF(CH)		(0x400 + 0x20 * (CH))
244243830Sdim#define OHCI_IRCTL(CH)		(OHCI_IROFF(CH))
245249423Sdim#define OHCI_IRCTLCLR(CH)	(OHCI_IROFF(CH) + 4)
246249423Sdim#define OHCI_IRCMD(CH)		(OHCI_IROFF(CH) + 0xc)
247249423Sdim#define OHCI_IRMATCH(CH)	(OHCI_IROFF(CH) + 0x10)
248249423Sdim
249249423Sdimd_ioctl_t fwohci_ioctl;
250249423Sdim
251249423Sdim/*
252249423Sdim * Communication with PHY device
253249423Sdim */
254249423Sdimstatic u_int32_t
255249423Sdimfwphy_wrdata( struct fwohci_softc *sc, u_int32_t addr, u_int32_t data)
256249423Sdim{
257249423Sdim	u_int32_t fun;
258249423Sdim
259249423Sdim	addr &= 0xf;
260249423Sdim	data &= 0xff;
261249423Sdim
262249423Sdim	fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA));
263249423Sdim	OWRITE(sc, OHCI_PHYACCESS, fun);
264249423Sdim	DELAY(100);
265249423Sdim
266249423Sdim	return(fwphy_rddata( sc, addr));
267249423Sdim}
268249423Sdim
269249423Sdimstatic u_int32_t
270249423Sdimfwohci_set_bus_manager(struct firewire_comm *fc, u_int node)
271249423Sdim{
272249423Sdim	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
273221345Sdim	int i;
274221345Sdim	u_int32_t bm;
275221345Sdim
276249423Sdim#define OHCI_CSR_DATA	0x0c
277221345Sdim#define OHCI_CSR_COMP	0x10
278221345Sdim#define OHCI_CSR_CONT	0x14
279221345Sdim#define OHCI_BUS_MANAGER_ID	0
280221345Sdim
281221345Sdim	OWRITE(sc, OHCI_CSR_DATA, node);
282221345Sdim	OWRITE(sc, OHCI_CSR_COMP, 0x3f);
283221345Sdim	OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID);
284221345Sdim 	for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++)
285221345Sdim		DELAY(10);
286221345Sdim	bm = OREAD(sc, OHCI_CSR_DATA);
287221345Sdim	if((bm & 0x3f) == 0x3f)
288221345Sdim		bm = node;
289221345Sdim	if (bootverbose)
290221345Sdim		device_printf(sc->fc.dev,
291193326Sed			"fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i);
292221345Sdim
293221345Sdim	return(bm);
294221345Sdim}
295221345Sdim
296193326Sedstatic u_int32_t
297221345Sdimfwphy_rddata(struct fwohci_softc *sc,  u_int addr)
298193326Sed{
299221345Sdim	u_int32_t fun, stat;
300193326Sed	u_int i, retry = 0;
301221345Sdim
302221345Sdim	addr &= 0xf;
303193326Sed#define MAX_RETRY 100
304221345Sdimagain:
305221345Sdim	OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL);
306221345Sdim	fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR);
307203955Srdivacky	OWRITE(sc, OHCI_PHYACCESS, fun);
308221345Sdim	for ( i = 0 ; i < MAX_RETRY ; i ++ ){
309193326Sed		fun = OREAD(sc, OHCI_PHYACCESS);
310221345Sdim		if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0)
311221345Sdim			break;
312221345Sdim		DELAY(100);
313221345Sdim	}
314221345Sdim	if(i >= MAX_RETRY) {
315221345Sdim		if (bootverbose)
316221345Sdim			device_printf(sc->fc.dev, "phy read failed(1).\n");
317221345Sdim		if (++retry < MAX_RETRY) {
318221345Sdim			DELAY(100);
319226633Sdim			goto again;
320221345Sdim		}
321221345Sdim	}
322221345Sdim	/* Make sure that SCLK is started */
323221345Sdim	stat = OREAD(sc, FWOHCI_INTSTAT);
324221345Sdim	if ((stat & OHCI_INT_REG_FAIL) != 0 ||
325221345Sdim			((fun >> PHYDEV_REGADDR) & 0xf) != addr) {
326221345Sdim		if (bootverbose)
327203955Srdivacky			device_printf(sc->fc.dev, "phy read failed(2).\n");
328221345Sdim		if (++retry < MAX_RETRY) {
329221345Sdim			DELAY(100);
330221345Sdim			goto again;
331221345Sdim		}
332221345Sdim	}
333221345Sdim	if (bootverbose || retry >= MAX_RETRY)
334234353Sdim		device_printf(sc->fc.dev,
335234353Sdim			"fwphy_rddata: loop=%d, retry=%d\n", i, retry);
336234353Sdim#undef MAX_RETRY
337234353Sdim	return((fun >> PHYDEV_RDDATA )& 0xff);
338221345Sdim}
339221345Sdim/* Device specific ioctl. */
340221345Sdimint
341239462Sdimfwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
342239462Sdim{
343221345Sdim	struct firewire_softc *sc;
344221345Sdim	struct fwohci_softc *fc;
345221345Sdim	int unit = DEV2UNIT(dev);
346221345Sdim	int err = 0;
347221345Sdim	struct fw_reg_req_t *reg  = (struct fw_reg_req_t *) data;
348221345Sdim	u_int32_t *dmach = (u_int32_t *) data;
349221345Sdim
350239462Sdim	sc = devclass_get_softc(firewire_devclass, unit);
351221345Sdim	if(sc == NULL){
352239462Sdim		return(EINVAL);
353221345Sdim	}
354221345Sdim	fc = (struct fwohci_softc *)sc->fc;
355193326Sed
356221345Sdim	if (!data)
357221345Sdim		return(EINVAL);
358221345Sdim
359221345Sdim	switch (cmd) {
360221345Sdim	case FWOHCI_WRREG:
361221345Sdim#define OHCI_MAX_REG 0x800
362221345Sdim		if(reg->addr <= OHCI_MAX_REG){
363221345Sdim			OWRITE(fc, reg->addr, reg->data);
364221345Sdim			reg->data = OREAD(fc, reg->addr);
365221345Sdim		}else{
366221345Sdim			err = EINVAL;
367221345Sdim		}
368221345Sdim		break;
369221345Sdim	case FWOHCI_RDREG:
370221345Sdim		if(reg->addr <= OHCI_MAX_REG){
371221345Sdim			reg->data = OREAD(fc, reg->addr);
372221345Sdim		}else{
373223017Sdim			err = EINVAL;
374221345Sdim		}
375221345Sdim		break;
376221345Sdim/* Read DMA descriptors for debug  */
377221345Sdim	case DUMPDMA:
378221345Sdim		if(*dmach <= OHCI_MAX_DMA_CH ){
379221345Sdim			dump_dma(fc, *dmach);
380221345Sdim			dump_db(fc, *dmach);
381221345Sdim		}else{
382221345Sdim			err = EINVAL;
383221345Sdim		}
384221345Sdim		break;
385221345Sdim	default:
386234353Sdim		break;
387234353Sdim	}
388234353Sdim	return err;
389221345Sdim}
390221345Sdim
391221345Sdimstatic int
392221345Sdimfwohci_probe_phy(struct fwohci_softc *sc, device_t dev)
393221345Sdim{
394226633Sdim	u_int32_t reg, reg2;
395226633Sdim	int e1394a = 1;
396234353Sdim/*
397234353Sdim * probe PHY parameters
398193326Sed * 0. to prove PHY version, whether compliance of 1394a.
399239462Sdim * 1. to probe maximum speed supported by the PHY and
400221345Sdim *    number of port supported by core-logic.
401221345Sdim *    It is not actually available port on your PC .
402193326Sed */
403221345Sdim	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
404221345Sdim	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
405198092Srdivacky
406226633Sdim	if((reg >> 5) != 7 ){
407226633Sdim		sc->fc.mode &= ~FWPHYASYST;
408221345Sdim		sc->fc.nport = reg & FW_PHY_NP;
409221345Sdim		sc->fc.speed = reg & FW_PHY_SPD >> 6;
410234353Sdim		if (sc->fc.speed > MAX_SPEED) {
411221345Sdim			device_printf(dev, "invalid speed %d (fixed to %d).\n",
412221345Sdim				sc->fc.speed, MAX_SPEED);
413221345Sdim			sc->fc.speed = MAX_SPEED;
414221345Sdim		}
415249423Sdim		device_printf(dev,
416221345Sdim			"Phy 1394 only %s, %d ports.\n",
417193326Sed			linkspeed[sc->fc.speed], sc->fc.nport);
418193326Sed	}else{
419193326Sed		reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG);
420193326Sed		sc->fc.mode |= FWPHYASYST;
421193326Sed		sc->fc.nport = reg & FW_PHY_NP;
422193326Sed		sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5;
423193326Sed		if (sc->fc.speed > MAX_SPEED) {
424193326Sed			device_printf(dev, "invalid speed %d (fixed to %d).\n",
425193326Sed				sc->fc.speed, MAX_SPEED);
426198092Srdivacky			sc->fc.speed = MAX_SPEED;
427198092Srdivacky		}
428207619Srdivacky		device_printf(dev,
429226633Sdim			"Phy 1394a available %s, %d ports.\n",
430226633Sdim			linkspeed[sc->fc.speed], sc->fc.nport);
431207619Srdivacky
432221345Sdim		/* check programPhyEnable */
433221345Sdim		reg2 = fwphy_rddata(sc, 5);
434193326Sed#if 0
435234353Sdim		if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) {
436234353Sdim#else	/* XXX force to enable 1394a */
437221345Sdim		if (e1394a) {
438221345Sdim#endif
439249423Sdim			if (bootverbose)
440221345Sdim				device_printf(dev,
441221345Sdim					"Enable 1394a Enhancements\n");
442193326Sed			/* enable EAA EMC */
443193326Sed			reg2 |= 0x03;
444221345Sdim			/* set aPhyEnhanceEnable */
445221345Sdim			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN);
446239462Sdim			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY);
447194613Sed		} else {
448224145Sdim			/* for safe */
449249423Sdim			reg2 &= ~0x83;
450239462Sdim		}
451221345Sdim		reg2 = fwphy_wrdata(sc, 5, reg2);
452221345Sdim	}
453221345Sdim
454221345Sdim	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
455221345Sdim	if((reg >> 5) == 7 ){
456221345Sdim		reg = fwphy_rddata(sc, 4);
457263508Sdim		reg |= 1 << 6;
458263508Sdim		fwphy_wrdata(sc, 4, reg);
459226633Sdim		reg = fwphy_rddata(sc, 4);
460226633Sdim	}
461226633Sdim	return 0;
462221345Sdim}
463221345Sdim
464263508Sdim
465263508Sdimvoid
466226633Sdimfwohci_reset(struct fwohci_softc *sc, device_t dev)
467226633Sdim{
468226633Sdim	int i, max_rec, speed;
469226633Sdim	u_int32_t reg, reg2;
470226633Sdim	struct fwohcidb_tr *db_tr;
471226633Sdim
472226633Sdim	/* Disable interrupt */
473226633Sdim	OWRITE(sc, FWOHCI_INTMASKCLR, ~0);
474226633Sdim
475226633Sdim	/* Now stopping all DMA channel */
476226633Sdim	OWRITE(sc,  OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
477234353Sdim	OWRITE(sc,  OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
478193326Sed	OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
479221345Sdim	OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
480221345Sdim
481221345Sdim	OWRITE(sc,  OHCI_IR_MASKCLR, ~0);
482202879Srdivacky	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
483221345Sdim		OWRITE(sc,  OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
484221345Sdim		OWRITE(sc,  OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
485221345Sdim	}
486208600Srdivacky
487193326Sed	/* FLUSH FIFO and reset Transmitter/Reciever */
488193326Sed	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET);
489193326Sed	if (bootverbose)
490193326Sed		device_printf(dev, "resetting OHCI...");
491207619Srdivacky	i = 0;
492193326Sed	while(OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) {
493221345Sdim		if (i++ > 100) break;
494221345Sdim		DELAY(1000);
495208600Srdivacky	}
496193326Sed	if (bootverbose)
497193326Sed		printf("done (loop=%d)\n", i);
498193326Sed
499193326Sed	/* Probe phy */
500193326Sed	fwohci_probe_phy(sc, dev);
501193326Sed
502198092Srdivacky	/* Probe link */
503198092Srdivacky	reg = OREAD(sc,  OHCI_BUS_OPT);
504249423Sdim	reg2 = reg | OHCI_BUSFNC;
505193326Sed	max_rec = (reg & 0x0000f000) >> 12;
506249423Sdim	speed = (reg & 0x00000007);
507210299Sed	device_printf(dev, "Link %s, max_rec %d bytes.\n",
508249423Sdim			linkspeed[speed], MAXREC(max_rec));
509193326Sed	/* XXX fix max_rec */
510212904Sdim	sc->fc.maxrec = sc->fc.speed + 8;
511198092Srdivacky	if (max_rec != sc->fc.maxrec) {
512198092Srdivacky		reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12);
513193326Sed		device_printf(dev, "max_rec %d -> %d\n",
514193326Sed				MAXREC(max_rec), MAXREC(sc->fc.maxrec));
515193326Sed	}
516234353Sdim	if (bootverbose)
517249423Sdim		device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2);
518193326Sed	OWRITE(sc,  OHCI_BUS_OPT, reg2);
519193326Sed
520193326Sed	/* Initialize registers */
521223017Sdim	OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]);
522223017Sdim	OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr);
523234353Sdim	OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND);
524234353Sdim	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
525223017Sdim	OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
526223017Sdim	OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
527249423Sdim	fw_busreset(&sc->fc);
528249423Sdim
529198092Srdivacky	/* Enable link */
530198092Srdivacky	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN);
531221345Sdim
532210299Sed	/* Force to start async RX DMA */
533221345Sdim	sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING;
534210299Sed	sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING;
535221345Sdim	fwohci_rx_enable(sc, &sc->arrq);
536249423Sdim	fwohci_rx_enable(sc, &sc->arrs);
537249423Sdim
538221345Sdim	/* Initialize async TX */
539193326Sed	OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
540221345Sdim	OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
541193326Sed
542221345Sdim	/* AT Retries */
543212904Sdim	OWRITE(sc, FWOHCI_RETRY,
544212904Sdim		/* CycleLimit   PhyRespRetries ATRespRetries ATReqRetries */
545221345Sdim		(0xffff << 16 ) | (0x0f << 8) | (0x0f << 4) | 0x0f) ;
546198092Srdivacky
547198092Srdivacky	sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq);
548221345Sdim	sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq);
549193326Sed	sc->atrq.bottom = sc->atrq.top;
550221345Sdim	sc->atrs.bottom = sc->atrs.top;
551198092Srdivacky
552198092Srdivacky	for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ;
553210299Sed				i ++, db_tr = STAILQ_NEXT(db_tr, link)){
554221345Sdim		db_tr->xfer = NULL;
555193326Sed	}
556193326Sed	for( i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb ;
557193326Sed				i ++, db_tr = STAILQ_NEXT(db_tr, link)){
558193326Sed		db_tr->xfer = NULL;
559221345Sdim	}
560193326Sed
561193326Sed
562249423Sdim	/* Enable interrupt */
563221345Sdim	OWRITE(sc, FWOHCI_INTMASK,
564218893Sdim			OHCI_INT_ERR  | OHCI_INT_PHY_SID
565212904Sdim			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
566212904Sdim			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
567243830Sdim			| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
568243830Sdim	fwohci_set_intr(&sc->fc, 1);
569243830Sdim
570243830Sdim}
571249423Sdim
572249423Sdimint
573249423Sdimfwohci_init(struct fwohci_softc *sc, device_t dev)
574249423Sdim{
575249423Sdim	int i;
576249423Sdim	u_int32_t reg;
577223017Sdim	u_int8_t ui[8];
578223017Sdim
579223017Sdim#if FWOHCI_TASKQUEUE
580193326Sed	TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
581221345Sdim#endif
582221345Sdim
583221345Sdim	reg = OREAD(sc, OHCI_VERSION);
584221345Sdim	device_printf(dev, "OHCI version %x.%x (ROM=%d)\n",
585221345Sdim			(reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1);
586221345Sdim
587221345Sdim/* Available Isochrounous DMA channel probe */
588221345Sdim	OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
589221345Sdim	OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
590221345Sdim	reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
591221345Sdim	OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
592221345Sdim	OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
593221345Sdim	for (i = 0; i < 0x20; i++)
594221345Sdim		if ((reg & (1 << i)) == 0)
595221345Sdim			break;
596221345Sdim	sc->fc.nisodma = i;
597221345Sdim	device_printf(dev, "No. of Isochronous channel is %d.\n", i);
598221345Sdim
599221345Sdim	sc->fc.arq = &sc->arrq.xferq;
600221345Sdim	sc->fc.ars = &sc->arrs.xferq;
601263508Sdim	sc->fc.atq = &sc->atrq.xferq;
602263508Sdim	sc->fc.ats = &sc->atrs.xferq;
603221345Sdim
604228379Sdim	sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
605234353Sdim	sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
606234353Sdim	sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
607249423Sdim	sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE);
608228379Sdim
609228379Sdim	sc->arrq.xferq.start = NULL;
610221345Sdim	sc->arrs.xferq.start = NULL;
611221345Sdim	sc->atrq.xferq.start = fwohci_start_atq;
612221345Sdim	sc->atrs.xferq.start = fwohci_start_ats;
613263508Sdim
614263508Sdim	sc->arrq.xferq.buf = NULL;
615221345Sdim	sc->arrs.xferq.buf = NULL;
616221345Sdim	sc->atrq.xferq.buf = NULL;
617221345Sdim	sc->atrs.xferq.buf = NULL;
618249423Sdim
619221345Sdim	sc->arrq.xferq.dmach = -1;
620221345Sdim	sc->arrs.xferq.dmach = -1;
621221345Sdim	sc->atrq.xferq.dmach = -1;
622221345Sdim	sc->atrs.xferq.dmach = -1;
623221345Sdim
624221345Sdim	sc->arrq.ndesc = 1;
625221345Sdim	sc->arrs.ndesc = 1;
626221345Sdim	sc->atrq.ndesc = 8;	/* equal to maximum of mbuf chains */
627221345Sdim	sc->atrs.ndesc = 2;
628221345Sdim
629221345Sdim	sc->arrq.ndb = NDB;
630221345Sdim	sc->arrs.ndb = NDB / 2;
631221345Sdim	sc->atrq.ndb = NDB;
632221345Sdim	sc->atrs.ndb = NDB / 2;
633221345Sdim
634221345Sdim	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
635221345Sdim		sc->fc.it[i] = &sc->it[i].xferq;
636221345Sdim		sc->fc.ir[i] = &sc->ir[i].xferq;
637221345Sdim		sc->it[i].xferq.dmach = i;
638221345Sdim		sc->ir[i].xferq.dmach = i;
639249423Sdim		sc->it[i].ndb = 0;
640249423Sdim		sc->ir[i].ndb = 0;
641249423Sdim	}
642249423Sdim
643249423Sdim	sc->fc.tcode = tinfo;
644249423Sdim	sc->fc.dev = dev;
645249423Sdim
646249423Sdim	sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE,
647249423Sdim						&sc->crom_dma, BUS_DMA_WAITOK);
648249423Sdim	if(sc->fc.config_rom == NULL){
649249423Sdim		device_printf(dev, "config_rom alloc failed.");
650249423Sdim		return ENOMEM;
651249423Sdim	}
652249423Sdim
653221345Sdim#if 0
654221345Sdim	bzero(&sc->fc.config_rom[0], CROMSIZE);
655221345Sdim	sc->fc.config_rom[1] = 0x31333934;
656243830Sdim	sc->fc.config_rom[2] = 0xf000a002;
657243830Sdim	sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
658221345Sdim	sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO);
659221345Sdim	sc->fc.config_rom[5] = 0;
660221345Sdim	sc->fc.config_rom[0] = (4 << 24) | (5 << 16);
661221345Sdim
662263508Sdim	sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4);
663263508Sdim#endif
664221345Sdim
665221345Sdim
666221345Sdim/* SID recieve buffer must allign 2^11 */
667221345Sdim#define	OHCI_SIDSIZE	(1 << 11)
668221345Sdim	sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE,
669221345Sdim						&sc->sid_dma, BUS_DMA_WAITOK);
670221345Sdim	if (sc->sid_buf == NULL) {
671221345Sdim		device_printf(dev, "sid_buf alloc failed.");
672221345Sdim		return ENOMEM;
673221345Sdim	}
674221345Sdim
675221345Sdim	fwdma_malloc(&sc->fc, sizeof(u_int32_t), sizeof(u_int32_t),
676221345Sdim					&sc->dummy_dma, BUS_DMA_WAITOK);
677221345Sdim
678221345Sdim	if (sc->dummy_dma.v_addr == NULL) {
679221345Sdim		device_printf(dev, "dummy_dma alloc failed.");
680221345Sdim		return ENOMEM;
681221345Sdim	}
682228379Sdim
683234353Sdim	fwohci_db_init(sc, &sc->arrq);
684234353Sdim	if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0)
685234353Sdim		return ENOMEM;
686249423Sdim
687228379Sdim	fwohci_db_init(sc, &sc->arrs);
688221345Sdim	if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0)
689221345Sdim		return ENOMEM;
690221345Sdim
691228379Sdim	fwohci_db_init(sc, &sc->atrq);
692228379Sdim	if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0)
693221345Sdim		return ENOMEM;
694221345Sdim
695221345Sdim	fwohci_db_init(sc, &sc->atrs);
696221345Sdim	if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0)
697221345Sdim		return ENOMEM;
698221345Sdim
699221345Sdim	sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H);
700221345Sdim	sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L);
701263508Sdim	for( i = 0 ; i < 8 ; i ++)
702263508Sdim		ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i);
703221345Sdim	device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
704221345Sdim		ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]);
705221345Sdim
706249423Sdim	sc->fc.ioctl = fwohci_ioctl;
707249423Sdim	sc->fc.cyctimer = fwohci_cyctimer;
708221345Sdim	sc->fc.set_bmr = fwohci_set_bus_manager;
709221345Sdim	sc->fc.ibr = fwohci_ibr;
710221345Sdim	sc->fc.irx_enable = fwohci_irx_enable;
711221345Sdim	sc->fc.irx_disable = fwohci_irx_disable;
712221345Sdim
713221345Sdim	sc->fc.itx_enable = fwohci_itxbuf_enable;
714249423Sdim	sc->fc.itx_disable = fwohci_itx_disable;
715249423Sdim#if BYTE_ORDER == BIG_ENDIAN
716224145Sdim	sc->fc.irx_post = fwohci_irx_post;
717221345Sdim#else
718221345Sdim	sc->fc.irx_post = NULL;
719221345Sdim#endif
720221345Sdim	sc->fc.itx_post = NULL;
721221345Sdim	sc->fc.timeout = fwohci_timeout;
722221345Sdim	sc->fc.poll = fwohci_poll;
723221345Sdim	sc->fc.set_intr = fwohci_set_intr;
724221345Sdim
725221345Sdim	sc->intmask = sc->irstat = sc->itstat = 0;
726234353Sdim
727224145Sdim	fw_init(&sc->fc);
728221345Sdim	fwohci_reset(sc, dev);
729221345Sdim
730221345Sdim	return 0;
731226633Sdim}
732221345Sdim
733249423Sdimvoid
734249423Sdimfwohci_timeout(void *arg)
735249423Sdim{
736249423Sdim	struct fwohci_softc *sc;
737249423Sdim
738249423Sdim	sc = (struct fwohci_softc *)arg;
739249423Sdim}
740249423Sdim
741249423Sdimu_int32_t
742249423Sdimfwohci_cyctimer(struct firewire_comm *fc)
743249423Sdim{
744221345Sdim	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
745249423Sdim	return(OREAD(sc, OHCI_CYCLETIMER));
746249423Sdim}
747249423Sdim
748249423Sdimint
749249423Sdimfwohci_detach(struct fwohci_softc *sc, device_t dev)
750249423Sdim{
751249423Sdim	int i;
752249423Sdim
753249423Sdim	if (sc->sid_buf != NULL)
754249423Sdim		fwdma_free(&sc->fc, &sc->sid_dma);
755249423Sdim	if (sc->fc.config_rom != NULL)
756249423Sdim		fwdma_free(&sc->fc, &sc->crom_dma);
757249423Sdim
758249423Sdim	fwohci_db_free(&sc->arrq);
759249423Sdim	fwohci_db_free(&sc->arrs);
760249423Sdim
761249423Sdim	fwohci_db_free(&sc->atrq);
762221345Sdim	fwohci_db_free(&sc->atrs);
763249423Sdim
764249423Sdim	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
765249423Sdim		fwohci_db_free(&sc->it[i]);
766249423Sdim		fwohci_db_free(&sc->ir[i]);
767249423Sdim	}
768249423Sdim
769249423Sdim	return 0;
770249423Sdim}
771249423Sdim
772249423Sdim#define LAST_DB(dbtr, db) do {						\
773249423Sdim	struct fwohcidb_tr *_dbtr = (dbtr);				\
774249423Sdim	int _cnt = _dbtr->dbcnt;					\
775249423Sdim	db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0];			\
776249423Sdim} while (0)
777249423Sdim
778249423Sdimstatic void
779249423Sdimfwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error)
780249423Sdim{
781249423Sdim	struct fwohcidb_tr *db_tr;
782249423Sdim	volatile struct fwohcidb *db;
783249423Sdim	bus_dma_segment_t *s;
784249423Sdim	int i;
785249423Sdim
786249423Sdim	db_tr = (struct fwohcidb_tr *)arg;
787249423Sdim	db = &db_tr->db[db_tr->dbcnt];
788249423Sdim	if (error) {
789249423Sdim		if (firewire_debug || error != EFBIG)
790249423Sdim			printf("fwohci_execute_db: error=%d\n", error);
791249423Sdim		return;
792249423Sdim	}
793249423Sdim	for (i = 0; i < nseg; i++) {
794249423Sdim		s = &segs[i];
795249423Sdim		FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr);
796249423Sdim		FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len);
797221345Sdim 		FWOHCI_DMA_WRITE(db->db.desc.res, 0);
798221345Sdim		db++;
799263508Sdim		db_tr->dbcnt++;
800243830Sdim	}
801243830Sdim}
802243830Sdim
803243830Sdimstatic void
804243830Sdimfwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg,
805263508Sdim						bus_size_t size, int error)
806263508Sdim{
807263508Sdim	fwohci_execute_db(arg, segs, nseg, error);
808243830Sdim}
809243830Sdim
810243830Sdimstatic void
811263508Sdimfwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
812243830Sdim{
813243830Sdim	int i, s;
814243830Sdim	int tcode, hdr_len, pl_off, pl_len;
815243830Sdim	int fsegment = -1;
816263508Sdim	u_int32_t off;
817263508Sdim	struct fw_xfer *xfer;
818243830Sdim	struct fw_pkt *fp;
819243830Sdim	volatile struct fwohci_txpkthdr *ohcifp;
820243830Sdim	struct fwohcidb_tr *db_tr;
821243830Sdim	volatile struct fwohcidb *db;
822263508Sdim	struct tcode_info *info;
823263508Sdim	static int maxdesc=0;
824263508Sdim
825263508Sdim	if(&sc->atrq == dbch){
826263508Sdim		off = OHCI_ATQOFF;
827263508Sdim	}else if(&sc->atrs == dbch){
828263508Sdim		off = OHCI_ATSOFF;
829243830Sdim	}else{
830243830Sdim		return;
831243830Sdim	}
832243830Sdim
833243830Sdim	if (dbch->flags & FWOHCI_DBCH_FULL)
834243830Sdim		return;
835263508Sdim
836263508Sdim	s = splfw();
837243830Sdim	db_tr = dbch->top;
838243830Sdimtxloop:
839243830Sdim	xfer = STAILQ_FIRST(&dbch->xferq.q);
840263508Sdim	if(xfer == NULL){
841263508Sdim		goto kick;
842263508Sdim	}
843263508Sdim	if(dbch->xferq.queued == 0 ){
844263508Sdim		device_printf(sc->fc.dev, "TX queue empty\n");
845243830Sdim	}
846243830Sdim	STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
847249423Sdim	db_tr->xfer = xfer;
848239462Sdim	xfer->state = FWXF_START;
849239462Sdim
850249423Sdim	fp = (struct fw_pkt *)xfer->send.buf;
851239462Sdim	tcode = fp->mode.common.tcode;
852239462Sdim
853239462Sdim	ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
854239462Sdim	info = &tinfo[tcode];
855239462Sdim	hdr_len = pl_off = info->hdr_len;
856239462Sdim	for( i = 0 ; i < pl_off ; i+= 4){
857239462Sdim		ohcifp->mode.ld[i/4] = fp->mode.ld[i/4];
858239462Sdim	}
859239462Sdim	ohcifp->mode.common.spd = xfer->spd;
860239462Sdim	if (tcode == FWTCODE_STREAM ){
861239462Sdim		hdr_len = 8;
862239462Sdim		ohcifp->mode.stream.len = fp->mode.stream.len;
863239462Sdim	} else if (tcode == FWTCODE_PHY) {
864239462Sdim		hdr_len = 12;
865239462Sdim		ohcifp->mode.ld[1] = fp->mode.ld[1];
866239462Sdim		ohcifp->mode.ld[2] = fp->mode.ld[2];
867243830Sdim		ohcifp->mode.common.spd = 0;
868243830Sdim		ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
869243830Sdim	} else {
870263508Sdim		ohcifp->mode.asycomm.dst = fp->mode.hdr.dst;
871263508Sdim		ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS;
872243830Sdim		ohcifp->mode.asycomm.tlrt |= FWRETRY_X;
873243830Sdim	}
874243830Sdim	db = &db_tr->db[0];
875263508Sdim 	FWOHCI_DMA_WRITE(db->db.desc.cmd,
876263508Sdim			OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
877243830Sdim 	FWOHCI_DMA_WRITE(db->db.desc.res, 0);
878239462Sdim/* Specify bound timer of asy. responce */
879193326Sed	if(&sc->atrs == dbch){
880193326Sed 		FWOHCI_DMA_WRITE(db->db.desc.res,
881193326Sed			 (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13));
882194613Sed	}
883194613Sed#if BYTE_ORDER == BIG_ENDIAN
884194613Sed	if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
885198092Srdivacky		hdr_len = 12;
886194613Sed	for (i = 0; i < hdr_len/4; i ++)
887194613Sed		FWOHCI_DMA_WRITE(ohcifp->mode.ld[i], ohcifp->mode.ld[i]);
888198092Srdivacky#endif
889198092Srdivacky
890194613Sedagain:
891194613Sed	db_tr->dbcnt = 2;
892194613Sed	db = &db_tr->db[db_tr->dbcnt];
893198092Srdivacky	pl_len = xfer->send.len - pl_off;
894198092Srdivacky	if (pl_len > 0) {
895194613Sed		int err;
896198092Srdivacky		/* handle payload */
897198092Srdivacky		if (xfer->mbuf == NULL) {
898194613Sed			caddr_t pl_addr;
899193326Sed
900226633Sdim			pl_addr = xfer->send.buf + pl_off;
901226633Sdim			err = bus_dmamap_load(dbch->dmat, db_tr->dma_map,
902221345Sdim				pl_addr, pl_len,
903221345Sdim				fwohci_execute_db, db_tr,
904202379Srdivacky				/*flags*/0);
905202379Srdivacky		} else {
906226633Sdim			/* XXX we can handle only 6 (=8-2) mbuf chains */
907221345Sdim			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
908193326Sed				xfer->mbuf,
909193326Sed				fwohci_execute_db2, db_tr,
910221345Sdim				/* flags */0);
911221345Sdim			if (err == EFBIG) {
912234353Sdim				struct mbuf *m0;
913234353Sdim
914234353Sdim				if (firewire_debug)
915207619Srdivacky					device_printf(sc->fc.dev, "EFBIG.\n");
916207619Srdivacky				m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
917207619Srdivacky				if (m0 != NULL) {
918221345Sdim					m_copydata(xfer->mbuf, 0,
919193326Sed						xfer->mbuf->m_pkthdr.len,
920221345Sdim						mtod(m0, caddr_t));
921193326Sed					m0->m_len = m0->m_pkthdr.len =
922221345Sdim						xfer->mbuf->m_pkthdr.len;
923218893Sdim					m_freem(xfer->mbuf);
924221345Sdim					xfer->mbuf = m0;
925218893Sdim					goto again;
926221345Sdim				}
927218893Sdim				device_printf(sc->fc.dev, "m_getcl failed.\n");
928198092Srdivacky			}
929198092Srdivacky		}
930198092Srdivacky		if (err)
931198092Srdivacky			printf("dmamap_load: err=%d\n", err);
932198092Srdivacky		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
933193326Sed						BUS_DMASYNC_PREWRITE);
934193326Sed#if 0 /* OHCI_OUTPUT_MODE == 0 */
935198092Srdivacky		for (i = 2; i < db_tr->dbcnt; i++)
936193326Sed			FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd,
937202879Srdivacky						OHCI_OUTPUT_MORE);
938202879Srdivacky#endif
939202879Srdivacky	}
940202879Srdivacky	if (maxdesc < db_tr->dbcnt) {
941202879Srdivacky		maxdesc = db_tr->dbcnt;
942202879Srdivacky		if (bootverbose)
943193326Sed			device_printf(sc->fc.dev, "maxdesc: %d\n", maxdesc);
944193326Sed	}
945193326Sed	/* last db */
946198092Srdivacky	LAST_DB(db_tr, db);
947226633Sdim 	FWOHCI_DMA_SET(db->db.desc.cmd,
948226633Sdim		OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
949226633Sdim 	FWOHCI_DMA_WRITE(db->db.desc.depend,
950226633Sdim			STAILQ_NEXT(db_tr, link)->bus_addr);
951226633Sdim
952226633Sdim	if(fsegment == -1 )
953193326Sed		fsegment = db_tr->dbcnt;
954221345Sdim	if (dbch->pdb_tr != NULL) {
955221345Sdim		LAST_DB(dbch->pdb_tr, db);
956221345Sdim 		FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
957221345Sdim	}
958221345Sdim	dbch->pdb_tr = db_tr;
959221345Sdim	db_tr = STAILQ_NEXT(db_tr, link);
960202879Srdivacky	if(db_tr != dbch->bottom){
961202879Srdivacky		goto txloop;
962203955Srdivacky	} else {
963198092Srdivacky		device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n");
964224145Sdim		dbch->flags |= FWOHCI_DBCH_FULL;
965221345Sdim	}
966221345Sdimkick:
967224145Sdim	/* kick asy q */
968221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
969221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
970221345Sdim
971221345Sdim	if(dbch->xferq.flag & FWXFERQ_RUNNING) {
972221345Sdim		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
973221345Sdim	} else {
974221345Sdim		if (bootverbose)
975221345Sdim			device_printf(sc->fc.dev, "start AT DMA status=%x\n",
976221345Sdim					OREAD(sc, OHCI_DMACTL(off)));
977221345Sdim		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment);
978221345Sdim		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
979221345Sdim		dbch->xferq.flag |= FWXFERQ_RUNNING;
980221345Sdim	}
981221345Sdim
982221345Sdim	dbch->top = db_tr;
983221345Sdim	splx(s);
984221345Sdim	return;
985221345Sdim}
986221345Sdim
987221345Sdimstatic void
988221345Sdimfwohci_start_atq(struct firewire_comm *fc)
989221345Sdim{
990221345Sdim	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
991221345Sdim	fwohci_start( sc, &(sc->atrq));
992221345Sdim	return;
993221345Sdim}
994193326Sed
995224145Sdimstatic void
996221345Sdimfwohci_start_ats(struct firewire_comm *fc)
997221345Sdim{
998203955Srdivacky	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
999234353Sdim	fwohci_start( sc, &(sc->atrs));
1000226633Sdim	return;
1001224145Sdim}
1002224145Sdim
1003221345Sdimvoid
1004226633Sdimfwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1005223017Sdim{
1006223017Sdim	int s, ch, err = 0;
1007223017Sdim	struct fwohcidb_tr *tr;
1008203955Srdivacky	volatile struct fwohcidb *db;
1009203955Srdivacky	struct fw_xfer *xfer;
1010203955Srdivacky	u_int32_t off;
1011203955Srdivacky	u_int stat, status;
1012203955Srdivacky	int	packets;
1013203955Srdivacky	struct firewire_comm *fc = (struct firewire_comm *)sc;
1014203955Srdivacky
1015203955Srdivacky	if(&sc->atrq == dbch){
1016221345Sdim		off = OHCI_ATQOFF;
1017221345Sdim		ch = ATRQ_CH;
1018203955Srdivacky	}else if(&sc->atrs == dbch){
1019221345Sdim		off = OHCI_ATSOFF;
1020221345Sdim		ch = ATRS_CH;
1021203955Srdivacky	}else{
1022221345Sdim		return;
1023221345Sdim	}
1024203955Srdivacky	s = splfw();
1025221345Sdim	tr = dbch->bottom;
1026203955Srdivacky	packets = 0;
1027221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
1028203955Srdivacky	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
1029221345Sdim	while(dbch->xferq.queued > 0){
1030221345Sdim		LAST_DB(tr, db);
1031203955Srdivacky		status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
1032193326Sed		if(!(status & OHCI_CNTL_DMA_ACTIVE)){
1033198092Srdivacky			if (fc->status != FWBUSRESET)
1034249423Sdim				/* maybe out of order?? */
1035224145Sdim				goto out;
1036224145Sdim		}
1037224145Sdim		bus_dmamap_sync(dbch->dmat, tr->dma_map,
1038202379Srdivacky			BUS_DMASYNC_POSTWRITE);
1039202379Srdivacky		bus_dmamap_unload(dbch->dmat, tr->dma_map);
1040202379Srdivacky#if 0
1041202379Srdivacky		dump_db(sc, ch);
1042224145Sdim#endif
1043224145Sdim		if(status & OHCI_CNTL_DMA_DEAD) {
1044224145Sdim			/* Stop DMA */
1045224145Sdim			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
1046224145Sdim			device_printf(sc->fc.dev, "force reset AT FIFO\n");
1047249423Sdim			OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN);
1048193326Sed			OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN);
1049193326Sed			OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN);
1050226633Sdim		}
1051193326Sed		stat = status & FWOHCIEV_MASK;
1052249423Sdim		switch(stat){
1053193326Sed		case FWOHCIEV_ACKPEND:
1054193326Sed		case FWOHCIEV_ACKCOMPL:
1055224145Sdim			err = 0;
1056224145Sdim			break;
1057249423Sdim		case FWOHCIEV_ACKBSA:
1058224145Sdim		case FWOHCIEV_ACKBSB:
1059249423Sdim		case FWOHCIEV_ACKBSX:
1060224145Sdim			device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
1061249423Sdim			err = EBUSY;
1062249423Sdim			break;
1063224145Sdim		case FWOHCIEV_FLUSHED:
1064224145Sdim		case FWOHCIEV_ACKTARD:
1065249423Sdim			device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
1066221345Sdim			err = EAGAIN;
1067221345Sdim			break;
1068263508Sdim		case FWOHCIEV_MISSACK:
1069221345Sdim		case FWOHCIEV_UNDRRUN:
1070221345Sdim		case FWOHCIEV_OVRRUN:
1071221345Sdim		case FWOHCIEV_DESCERR:
1072226633Sdim		case FWOHCIEV_DTRDERR:
1073221345Sdim		case FWOHCIEV_TIMEOUT:
1074221345Sdim		case FWOHCIEV_TCODERR:
1075221345Sdim		case FWOHCIEV_UNKNOWN:
1076221345Sdim		case FWOHCIEV_ACKDERR:
1077221345Sdim		case FWOHCIEV_ACKTERR:
1078221345Sdim		default:
1079221345Sdim			device_printf(sc->fc.dev, "txd err=%2x %s\n",
1080221345Sdim							stat, fwohcicode[stat]);
1081221345Sdim			err = EINVAL;
1082221345Sdim			break;
1083221345Sdim		}
1084221345Sdim		if (tr->xfer != NULL) {
1085221345Sdim			xfer = tr->xfer;
1086221345Sdim			if (xfer->state == FWXF_RCVD) {
1087221345Sdim				if (firewire_debug)
1088249423Sdim					printf("already rcvd\n");
1089249423Sdim				fw_xfer_done(xfer);
1090221345Sdim			} else {
1091221345Sdim				xfer->state = FWXF_SENT;
1092221345Sdim				if (err == EBUSY && fc->status != FWBUSRESET) {
1093221345Sdim					xfer->state = FWXF_BUSY;
1094221345Sdim					xfer->resp = err;
1095249423Sdim					if (xfer->retry_req != NULL)
1096210299Sed						xfer->retry_req(xfer);
1097249423Sdim					else {
1098193326Sed						xfer->recv.len = 0;
1099193326Sed						fw_xfer_done(xfer);
1100249423Sdim					}
1101249423Sdim				} else if (stat != FWOHCIEV_ACKPEND) {
1102193326Sed					if (stat != FWOHCIEV_ACKCOMPL)
1103193326Sed						xfer->state = FWXF_SENTERR;
1104249423Sdim					xfer->resp = err;
1105221345Sdim					xfer->recv.len = 0;
1106193326Sed					fw_xfer_done(xfer);
1107221345Sdim				}
1108243830Sdim			}
1109243830Sdim			/*
1110243830Sdim			 * The watchdog timer takes care of split
1111243830Sdim			 * transcation timeout for ACKPEND case.
1112243830Sdim			 */
1113243830Sdim		} else {
1114243830Sdim			printf("this shouldn't happen\n");
1115243830Sdim		}
1116243830Sdim		dbch->xferq.queued --;
1117243830Sdim		tr->xfer = NULL;
1118243830Sdim
1119221345Sdim		packets ++;
1120243830Sdim		tr = STAILQ_NEXT(tr, link);
1121243830Sdim		dbch->bottom = tr;
1122243830Sdim		if (dbch->bottom == dbch->top) {
1123243830Sdim			/* we reaches the end of context program */
1124243830Sdim			if (firewire_debug && dbch->xferq.queued > 0)
1125243830Sdim				printf("queued > 0\n");
1126243830Sdim			break;
1127243830Sdim		}
1128243830Sdim	}
1129243830Sdimout:
1130243830Sdim	if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
1131243830Sdim		printf("make free slot\n");
1132221345Sdim		dbch->flags &= ~FWOHCI_DBCH_FULL;
1133221345Sdim		fwohci_start(sc, dbch);
1134193326Sed	}
1135221345Sdim	splx(s);
1136221345Sdim}
1137221345Sdim
1138221345Sdimstatic void
1139221345Sdimfwohci_db_free(struct fwohci_dbch *dbch)
1140221345Sdim{
1141221345Sdim	struct fwohcidb_tr *db_tr;
1142221345Sdim	int idb;
1143221345Sdim
1144221345Sdim	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1145221345Sdim		return;
1146221345Sdim
1147221345Sdim	for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb;
1148193326Sed			db_tr = STAILQ_NEXT(db_tr, link), idb++){
1149221345Sdim		if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 &&
1150221345Sdim					db_tr->buf != NULL) {
1151221345Sdim			fwdma_free_size(dbch->dmat, db_tr->dma_map,
1152221345Sdim					db_tr->buf, dbch->xferq.psize);
1153221345Sdim			db_tr->buf = NULL;
1154221345Sdim		} else if (db_tr->dma_map != NULL)
1155193326Sed			bus_dmamap_destroy(dbch->dmat, db_tr->dma_map);
1156221345Sdim	}
1157212904Sdim	dbch->ndb = 0;
1158221345Sdim	db_tr = STAILQ_FIRST(&dbch->db_trq);
1159221345Sdim	fwdma_free_multiseg(dbch->am);
1160234353Sdim	free(db_tr, M_FW);
1161234353Sdim	STAILQ_INIT(&dbch->db_trq);
1162221345Sdim	dbch->flags &= ~FWOHCI_DBCH_INIT;
1163221345Sdim}
1164221345Sdim
1165221345Sdimstatic void
1166221345Sdimfwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1167221345Sdim{
1168221345Sdim	int	idb;
1169221345Sdim	struct fwohcidb_tr *db_tr;
1170221345Sdim
1171221345Sdim	if ((dbch->flags & FWOHCI_DBCH_INIT) != 0)
1172221345Sdim		goto out;
1173198092Srdivacky
1174221345Sdim	/* create dma_tag for buffers */
1175226633Sdim#define MAX_REQCOUNT	0xffff
1176221345Sdim	if (bus_dma_tag_create(/*parent*/ sc->fc.dmat,
1177198092Srdivacky			/*alignment*/ 1, /*boundary*/ 0,
1178221345Sdim			/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
1179221345Sdim			/*highaddr*/ BUS_SPACE_MAXADDR,
1180198092Srdivacky			/*filter*/NULL, /*filterarg*/NULL,
1181221345Sdim			/*maxsize*/ dbch->xferq.psize,
1182221345Sdim			/*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1,
1183221345Sdim			/*maxsegsz*/ MAX_REQCOUNT,
1184221345Sdim			/*flags*/ 0,
1185224145Sdim#if __FreeBSD_version >= 501102
1186221345Sdim			/*lockfunc*/busdma_lock_mutex,
1187221345Sdim			/*lockarg*/&Giant,
1188221345Sdim#endif
1189193326Sed			&dbch->dmat))
1190193326Sed		return;
1191193326Sed
1192202879Srdivacky	/* allocate DB entries and attach one to each DMA channels */
1193203955Srdivacky	/* DB entry must start at 16 bytes bounary. */
1194212904Sdim	STAILQ_INIT(&dbch->db_trq);
1195202879Srdivacky	db_tr = (struct fwohcidb_tr *)
1196203955Srdivacky		malloc(sizeof(struct fwohcidb_tr) * dbch->ndb,
1197203955Srdivacky		M_FW, M_WAITOK | M_ZERO);
1198203955Srdivacky	if(db_tr == NULL){
1199203955Srdivacky		printf("fwohci_db_init: malloc(1) failed\n");
1200203955Srdivacky		return;
1201234353Sdim	}
1202234353Sdim
1203234353Sdim#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc)
1204234353Sdim	dbch->am = fwdma_malloc_multiseg(&sc->fc, DB_SIZE(dbch),
1205234353Sdim		DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK);
1206234353Sdim	if (dbch->am == NULL) {
1207234353Sdim		printf("fwohci_db_init: fwdma_malloc_multiseg failed\n");
1208234353Sdim		return;
1209234353Sdim	}
1210234353Sdim	/* Attach DB to DMA ch. */
1211234353Sdim	for(idb = 0 ; idb < dbch->ndb ; idb++){
1212234353Sdim		db_tr->dbcnt = 0;
1213234353Sdim		db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb);
1214234353Sdim		db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb);
1215234353Sdim		/* create dmamap for buffers */
1216193326Sed		/* XXX do we need 4bytes alignment tag? */
1217234353Sdim		/* XXX don't alloc dma_map for AR */
1218193326Sed		if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) {
1219193326Sed			printf("bus_dmamap_create failed\n");
1220193326Sed			dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */
1221234353Sdim			fwohci_db_free(dbch);
1222193326Sed			return;
1223203955Srdivacky		}
1224203955Srdivacky		STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link);
1225203955Srdivacky		if (dbch->xferq.flag & FWXFERQ_EXTBUF) {
1226193326Sed			if (idb % dbch->xferq.bnpacket == 0)
1227193326Sed				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1228193326Sed						].start = (caddr_t)db_tr;
1229193326Sed			if ((idb + 1) % dbch->xferq.bnpacket == 0)
1230193326Sed				dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket
1231193326Sed						].end = (caddr_t)db_tr;
1232221345Sdim		}
1233221345Sdim		db_tr++;
1234208600Srdivacky	}
1235193326Sed	STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next
1236193326Sed			= STAILQ_FIRST(&dbch->db_trq);
1237193326Sedout:
1238193326Sed	dbch->xferq.queued = 0;
1239193326Sed	dbch->pdb_tr = NULL;
1240193326Sed	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1241198092Srdivacky	dbch->bottom = dbch->top;
1242198092Srdivacky	dbch->flags = FWOHCI_DBCH_INIT;
1243223017Sdim}
1244234353Sdim
1245203955Srdivackystatic int
1246223017Sdimfwohci_itx_disable(struct firewire_comm *fc, int dmach)
1247223017Sdim{
1248203955Srdivacky	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1249203955Srdivacky	int sleepch;
1250203955Srdivacky
1251203955Srdivacky	OWRITE(sc, OHCI_ITCTLCLR(dmach),
1252203955Srdivacky			OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
1253193326Sed	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
1254249423Sdim	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
1255207619Srdivacky	/* XXX we cannot free buffers until the DMA really stops */
1256207619Srdivacky	tsleep((void *)&sleepch, FWPRI, "fwitxd", hz);
1257193326Sed	fwohci_db_free(&sc->it[dmach]);
1258193326Sed	sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
1259221345Sdim	return 0;
1260221345Sdim}
1261224145Sdim
1262193326Sedstatic int
1263234353Sdimfwohci_irx_disable(struct firewire_comm *fc, int dmach)
1264193326Sed{
1265193326Sed	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1266193326Sed	int sleepch;
1267193326Sed
1268193326Sed	OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1269193326Sed	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
1270226633Sdim	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
1271193326Sed	/* XXX we cannot free buffers until the DMA really stops */
1272193326Sed	tsleep((void *)&sleepch, FWPRI, "fwirxd", hz);
1273226633Sdim	fwohci_db_free(&sc->ir[dmach]);
1274193326Sed	sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
1275207619Srdivacky	return 0;
1276193326Sed}
1277193326Sed
1278193326Sed#if BYTE_ORDER == BIG_ENDIAN
1279193326Sedstatic void
1280198092Srdivackyfwohci_irx_post (struct firewire_comm *fc , u_int32_t *qld)
1281198092Srdivacky{
1282193326Sed	qld[0] = FWOHCI_DMA_READ(qld[0]);
1283193326Sed	return;
1284193326Sed}
1285193326Sed#endif
1286193326Sed
1287193326Sedstatic int
1288193326Sedfwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1289193326Sed{
1290193326Sed	int err = 0;
1291193326Sed	int idb, z, i, dmach = 0, ldesc;
1292193326Sed	u_int32_t off = NULL;
1293193326Sed	struct fwohcidb_tr *db_tr;
1294193326Sed	volatile struct fwohcidb *db;
1295193326Sed
1296193326Sed	if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){
1297193326Sed		err = EINVAL;
1298193326Sed		return err;
1299193326Sed	}
1300207619Srdivacky	z = dbch->ndesc;
1301198092Srdivacky	for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){
1302224145Sdim		if( &sc->it[dmach] == dbch){
1303193326Sed			off = OHCI_ITOFF(dmach);
1304207619Srdivacky			break;
1305193326Sed		}
1306207619Srdivacky	}
1307193326Sed	if(off == NULL){
1308224145Sdim		err = EINVAL;
1309198092Srdivacky		return err;
1310207619Srdivacky	}
1311193326Sed	if(dbch->xferq.flag & FWXFERQ_RUNNING)
1312207619Srdivacky		return err;
1313207619Srdivacky	dbch->xferq.flag |= FWXFERQ_RUNNING;
1314193326Sed	for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){
1315221345Sdim		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1316221345Sdim	}
1317193326Sed	db_tr = dbch->top;
1318263508Sdim	for (idb = 0; idb < dbch->ndb; idb ++) {
1319234353Sdim		fwohci_add_tx_buf(dbch, db_tr, idb);
1320207619Srdivacky		if(STAILQ_NEXT(db_tr, link) == NULL){
1321207619Srdivacky			break;
1322207619Srdivacky		}
1323207619Srdivacky		db = db_tr->db;
1324207619Srdivacky		ldesc = db_tr->dbcnt - 1;
1325207619Srdivacky		FWOHCI_DMA_WRITE(db[0].db.desc.depend,
1326221345Sdim				STAILQ_NEXT(db_tr, link)->bus_addr | z);
1327193326Sed		db[ldesc].db.desc.depend = db[0].db.desc.depend;
1328207619Srdivacky		if(dbch->xferq.flag & FWXFERQ_EXTBUF){
1329234353Sdim			if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
1330207619Srdivacky				FWOHCI_DMA_SET(
1331207619Srdivacky					db[ldesc].db.desc.cmd,
1332193326Sed					OHCI_INTERRUPT_ALWAYS);
1333193326Sed				/* OHCI 1.1 and above */
1334198092Srdivacky				FWOHCI_DMA_SET(
1335221345Sdim					db[0].db.desc.cmd,
1336221345Sdim					OHCI_INTERRUPT_ALWAYS);
1337208600Srdivacky			}
1338193326Sed		}
1339193326Sed		db_tr = STAILQ_NEXT(db_tr, link);
1340193326Sed	}
1341193326Sed	FWOHCI_DMA_CLEAR(
1342207619Srdivacky		dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf);
1343193326Sed	return err;
1344223017Sdim}
1345223017Sdim
1346207619Srdivackystatic int
1347234353Sdimfwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
1348203955Srdivacky{
1349223017Sdim	int err = 0;
1350223017Sdim	int idb, z, i, dmach = 0, ldesc;
1351203955Srdivacky	u_int32_t off = NULL;
1352203955Srdivacky	struct fwohcidb_tr *db_tr;
1353203955Srdivacky	volatile struct fwohcidb *db;
1354203955Srdivacky
1355203955Srdivacky	z = dbch->ndesc;
1356207619Srdivacky	if(&sc->arrq == dbch){
1357207619Srdivacky		off = OHCI_ARQOFF;
1358207619Srdivacky	}else if(&sc->arrs == dbch){
1359207619Srdivacky		off = OHCI_ARSOFF;
1360207619Srdivacky	}else{
1361207619Srdivacky		for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){
1362207619Srdivacky			if( &sc->ir[dmach] == dbch){
1363207619Srdivacky				off = OHCI_IROFF(dmach);
1364207619Srdivacky				break;
1365207619Srdivacky			}
1366221345Sdim		}
1367221345Sdim	}
1368221345Sdim	if(off == NULL){
1369221345Sdim		err = EINVAL;
1370207619Srdivacky		return err;
1371207619Srdivacky	}
1372207619Srdivacky	if(dbch->xferq.flag & FWXFERQ_STREAM){
1373208600Srdivacky		if(dbch->xferq.flag & FWXFERQ_RUNNING)
1374207619Srdivacky			return err;
1375207619Srdivacky	}else{
1376207619Srdivacky		if(dbch->xferq.flag & FWXFERQ_RUNNING){
1377207619Srdivacky			err = EBUSY;
1378208600Srdivacky			return err;
1379207619Srdivacky		}
1380207619Srdivacky	}
1381207619Srdivacky	dbch->xferq.flag |= FWXFERQ_RUNNING;
1382208600Srdivacky	dbch->top = STAILQ_FIRST(&dbch->db_trq);
1383207619Srdivacky	for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){
1384207619Srdivacky		dbch->bottom = STAILQ_NEXT(dbch->bottom, link);
1385207619Srdivacky	}
1386198092Srdivacky	db_tr = dbch->top;
1387193326Sed	for (idb = 0; idb < dbch->ndb; idb ++) {
1388193326Sed		fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma);
1389249423Sdim		if (STAILQ_NEXT(db_tr, link) == NULL)
1390193326Sed			break;
1391249423Sdim		db = db_tr->db;
1392221345Sdim		ldesc = db_tr->dbcnt - 1;
1393221345Sdim		FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend,
1394221345Sdim			STAILQ_NEXT(db_tr, link)->bus_addr | z);
1395221345Sdim		if(dbch->xferq.flag & FWXFERQ_EXTBUF){
1396221345Sdim			if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){
1397221345Sdim				FWOHCI_DMA_SET(
1398221345Sdim					db[ldesc].db.desc.cmd,
1399221345Sdim					OHCI_INTERRUPT_ALWAYS);
1400221345Sdim				FWOHCI_DMA_CLEAR(
1401221345Sdim					db[ldesc].db.desc.depend,
1402193326Sed					0xf);
1403221345Sdim			}
1404221345Sdim		}
1405224145Sdim		db_tr = STAILQ_NEXT(db_tr, link);
1406193326Sed	}
1407234353Sdim	FWOHCI_DMA_CLEAR(
1408193326Sed		dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf);
1409234353Sdim	dbch->buf_offset = 0;
1410234353Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1411207619Srdivacky	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1412234353Sdim	if(dbch->xferq.flag & FWXFERQ_STREAM){
1413234353Sdim		return err;
1414234353Sdim	}else{
1415234353Sdim		OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z);
1416234353Sdim	}
1417263508Sdim	OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN);
1418234353Sdim	return err;
1419234353Sdim}
1420234353Sdim
1421234353Sdimstatic int
1422234353Sdimfwohci_next_cycle(struct firewire_comm *fc, int cycle_now)
1423234353Sdim{
1424234353Sdim	int sec, cycle, cycle_match;
1425234353Sdim
1426234353Sdim	cycle = cycle_now & 0x1fff;
1427234353Sdim	sec = cycle_now >> 13;
1428234353Sdim#define CYCLE_MOD	0x10
1429234353Sdim#if 1
1430234353Sdim#define CYCLE_DELAY	8	/* min delay to start DMA */
1431234353Sdim#else
1432234353Sdim#define CYCLE_DELAY	7000	/* min delay to start DMA */
1433234353Sdim#endif
1434234353Sdim	cycle = cycle + CYCLE_DELAY;
1435234353Sdim	if (cycle >= 8000) {
1436234353Sdim		sec ++;
1437234353Sdim		cycle -= 8000;
1438234353Sdim	}
1439234353Sdim	cycle = roundup2(cycle, CYCLE_MOD);
1440207619Srdivacky	if (cycle >= 8000) {
1441263508Sdim		sec ++;
1442207619Srdivacky		if (cycle == 8000)
1443193326Sed			cycle = 0;
1444208600Srdivacky		else
1445207619Srdivacky			cycle = CYCLE_MOD;
1446208600Srdivacky	}
1447208600Srdivacky	cycle_match = ((sec << 13) | cycle) & 0x7ffff;
1448208600Srdivacky
1449207619Srdivacky	return(cycle_match);
1450207619Srdivacky}
1451221345Sdim
1452207619Srdivackystatic int
1453207619Srdivackyfwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
1454207619Srdivacky{
1455207619Srdivacky	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1456207619Srdivacky	int err = 0;
1457221345Sdim	unsigned short tag, ich;
1458226633Sdim	struct fwohci_dbch *dbch;
1459207619Srdivacky	int cycle_match, cycle_now, s, ldesc;
1460207619Srdivacky	u_int32_t stat;
1461207619Srdivacky	struct fw_bulkxfer *first, *chunk, *prev;
1462207619Srdivacky	struct fw_xferq *it;
1463207619Srdivacky
1464207619Srdivacky	dbch = &sc->it[dmach];
1465207619Srdivacky	it = &dbch->xferq;
1466207619Srdivacky
1467207619Srdivacky	tag = (it->flag >> 6) & 3;
1468221345Sdim	ich = it->flag & 0x3f;
1469207619Srdivacky	if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
1470207619Srdivacky		dbch->ndb = it->bnpacket * it->bnchunk;
1471207619Srdivacky		dbch->ndesc = 3;
1472221345Sdim		fwohci_db_init(sc, dbch);
1473207619Srdivacky		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1474207619Srdivacky			return ENOMEM;
1475207619Srdivacky		err = fwohci_tx_enable(sc, dbch);
1476207619Srdivacky	}
1477207619Srdivacky	if(err)
1478207619Srdivacky		return err;
1479207619Srdivacky
1480193326Sed	ldesc = dbch->ndesc - 1;
1481193326Sed	s = splfw();
1482198092Srdivacky	prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
1483193326Sed	while  ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
1484234353Sdim		volatile struct fwohcidb *db;
1485234353Sdim
1486234353Sdim		fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
1487234353Sdim					BUS_DMASYNC_PREWRITE);
1488234353Sdim		fwohci_txbufdb(sc, dmach, chunk);
1489234353Sdim		if (prev != NULL) {
1490198092Srdivacky			db = ((struct fwohcidb_tr *)(prev->end))->db;
1491198092Srdivacky#if 0 /* XXX necessary? */
1492198092Srdivacky			FWOHCI_DMA_SET(db[ldesc].db.desc.cmd,
1493224145Sdim						OHCI_BRANCH_ALWAYS);
1494193326Sed#endif
1495193326Sed#if 0 /* if bulkxfer->npacket changes */
1496221345Sdim			db[ldesc].db.desc.depend = db[0].db.desc.depend =
1497193326Sed				((struct fwohcidb_tr *)
1498193326Sed				(chunk->start))->bus_addr | dbch->ndesc;
1499193326Sed#else
1500193326Sed			FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
1501193326Sed			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
1502221345Sdim#endif
1503193326Sed		}
1504221345Sdim		STAILQ_REMOVE_HEAD(&it->stvalid, link);
1505221345Sdim		STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
1506221345Sdim		prev = chunk;
1507221345Sdim	}
1508221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1509221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1510221345Sdim	splx(s);
1511221345Sdim	stat = OREAD(sc, OHCI_ITCTL(dmach));
1512221345Sdim	if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S))
1513221345Sdim		printf("stat 0x%x\n", stat);
1514193326Sed
1515193326Sed	if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S))
1516193326Sed		return 0;
1517193326Sed
1518193326Sed#if 0
1519193326Sed	OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1520193326Sed#endif
1521193326Sed	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
1522193326Sed	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
1523226633Sdim	OWRITE(sc, OHCI_IT_MASK, 1 << dmach);
1524224145Sdim	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT);
1525224145Sdim
1526198092Srdivacky	first = STAILQ_FIRST(&it->stdma);
1527198092Srdivacky	OWRITE(sc, OHCI_ITCMD(dmach),
1528193326Sed		((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
1529193326Sed	if (firewire_debug) {
1530193326Sed		printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
1531193326Sed#if 1
1532193326Sed		dump_dma(sc, ITX_CH + dmach);
1533193326Sed#endif
1534226633Sdim	}
1535193326Sed	if ((stat & OHCI_CNTL_DMA_RUN) == 0) {
1536198092Srdivacky#if 1
1537193326Sed		/* Don't start until all chunks are buffered */
1538193326Sed		if (STAILQ_FIRST(&it->stfree) != NULL)
1539193326Sed			goto out;
1540193326Sed#endif
1541193326Sed#if 1
1542234353Sdim		/* Clear cycle match counter bits */
1543234353Sdim		OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000);
1544234353Sdim
1545234353Sdim		/* 2bit second + 13bit cycle */
1546199482Srdivacky		cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff;
1547199482Srdivacky		cycle_match = fwohci_next_cycle(fc, cycle_now);
1548198092Srdivacky
1549224145Sdim		OWRITE(sc, OHCI_ITCTL(dmach),
1550193326Sed				OHCI_CNTL_CYCMATCH_S | (cycle_match << 16)
1551193326Sed				| OHCI_CNTL_DMA_RUN);
1552193326Sed#else
1553193326Sed		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
1554193326Sed#endif
1555193326Sed		if (firewire_debug) {
1556193326Sed			printf("cycle_match: 0x%04x->0x%04x\n",
1557193326Sed						cycle_now, cycle_match);
1558198092Srdivacky			dump_dma(sc, ITX_CH + dmach);
1559198092Srdivacky			dump_db(sc, ITX_CH + dmach);
1560193326Sed		}
1561193326Sed	} else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) {
1562193326Sed		device_printf(sc->fc.dev,
1563193326Sed			"IT DMA underrun (0x%08x)\n", stat);
1564193326Sed		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE);
1565193326Sed	}
1566193326Sedout:
1567193326Sed	return err;
1568198092Srdivacky}
1569193326Sed
1570193326Sedstatic int
1571193326Sedfwohci_irx_enable(struct firewire_comm *fc, int dmach)
1572193326Sed{
1573224145Sdim	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
1574193326Sed	int err = 0, s, ldesc;
1575193326Sed	unsigned short tag, ich;
1576193326Sed	u_int32_t stat;
1577193326Sed	struct fwohci_dbch *dbch;
1578193326Sed	struct fwohcidb_tr *db_tr;
1579193326Sed	struct fw_bulkxfer *first, *prev, *chunk;
1580193326Sed	struct fw_xferq *ir;
1581193326Sed
1582193326Sed	dbch = &sc->ir[dmach];
1583193326Sed	ir = &dbch->xferq;
1584193326Sed
1585193326Sed	if ((ir->flag & FWXFERQ_RUNNING) == 0) {
1586193326Sed		tag = (ir->flag >> 6) & 3;
1587193326Sed		ich = ir->flag & 0x3f;
1588193326Sed		OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich);
1589193326Sed
1590193326Sed		ir->queued = 0;
1591198092Srdivacky		dbch->ndb = ir->bnpacket * ir->bnchunk;
1592198092Srdivacky		dbch->ndesc = 2;
1593207619Srdivacky		fwohci_db_init(sc, dbch);
1594226633Sdim		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
1595226633Sdim			return ENOMEM;
1596207619Srdivacky		err = fwohci_rx_enable(sc, dbch);
1597193326Sed	}
1598193326Sed	if(err)
1599193326Sed		return err;
1600198092Srdivacky
1601198092Srdivacky	first = STAILQ_FIRST(&ir->stfree);
1602198092Srdivacky	if (first == NULL) {
1603198092Srdivacky		device_printf(fc->dev, "IR DMA no free chunk\n");
1604224145Sdim		return 0;
1605234353Sdim	}
1606193326Sed
1607193326Sed	ldesc = dbch->ndesc - 1;
1608193326Sed	s = splfw();
1609193326Sed	prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
1610193326Sed	while  ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
1611193326Sed		volatile struct fwohcidb *db;
1612193326Sed
1613198092Srdivacky#if 1 /* XXX for if_fwe */
1614193326Sed		if (chunk->mbuf != NULL) {
1615193326Sed			db_tr = (struct fwohcidb_tr *)(chunk->start);
1616193326Sed			db_tr->dbcnt = 1;
1617193326Sed			err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map,
1618193326Sed					chunk->mbuf, fwohci_execute_db2, db_tr,
1619198092Srdivacky					/* flags */0);
1620198092Srdivacky 			FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd,
1621198092Srdivacky				OHCI_UPDATE | OHCI_INPUT_LAST |
1622198092Srdivacky				OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS);
1623228379Sdim		}
1624228379Sdim#endif
1625193326Sed		db = ((struct fwohcidb_tr *)(chunk->end))->db;
1626193326Sed		FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0);
1627193326Sed		FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf);
1628193326Sed		if (prev != NULL) {
1629193326Sed			db = ((struct fwohcidb_tr *)(prev->end))->db;
1630193326Sed			FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc);
1631193326Sed		}
1632193326Sed		STAILQ_REMOVE_HEAD(&ir->stfree, link);
1633193326Sed		STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
1634219077Sdim		prev = chunk;
1635243830Sdim	}
1636221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
1637221345Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
1638221345Sdim	splx(s);
1639221345Sdim	stat = OREAD(sc, OHCI_IRCTL(dmach));
1640219077Sdim	if (stat & OHCI_CNTL_DMA_ACTIVE)
1641219077Sdim		return 0;
1642193326Sed	if (stat & OHCI_CNTL_DMA_RUN) {
1643193326Sed		OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
1644198092Srdivacky		device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat);
1645198092Srdivacky	}
1646198092Srdivacky
1647193326Sed	if (firewire_debug)
1648198092Srdivacky		printf("start IR DMA 0x%x\n", stat);
1649226633Sdim	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
1650198092Srdivacky	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
1651198092Srdivacky	OWRITE(sc, OHCI_IR_MASK, 1 << dmach);
1652226633Sdim	OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000);
1653226633Sdim	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR);
1654193326Sed	OWRITE(sc, OHCI_IRCMD(dmach),
1655202379Srdivacky		((struct fwohcidb_tr *)(first->start))->bus_addr
1656234353Sdim							| dbch->ndesc);
1657234353Sdim	OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN);
1658234353Sdim	OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR);
1659234353Sdim#if 0
1660234353Sdim	dump_db(sc, IRX_CH + dmach);
1661234353Sdim#endif
1662234353Sdim	return err;
1663234353Sdim}
1664234353Sdim
1665234353Sdimint
1666234353Sdimfwohci_stop(struct fwohci_softc *sc, device_t dev)
1667234353Sdim{
1668234353Sdim	u_int i;
1669234353Sdim
1670193326Sed/* Now stopping all DMA channel */
1671193326Sed	OWRITE(sc,  OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN);
1672234353Sdim	OWRITE(sc,  OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN);
1673234353Sdim	OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
1674234353Sdim	OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
1675198092Srdivacky
1676224145Sdim	for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
1677193326Sed		OWRITE(sc,  OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN);
1678193326Sed		OWRITE(sc,  OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
1679193326Sed	}
1680193326Sed
1681193326Sed/* FLUSH FIFO and reset Transmitter/Reciever */
1682193326Sed	OWRITE(sc,  OHCI_HCCCTL, OHCI_HCC_RESET);
1683193326Sed
1684198092Srdivacky/* Stop interrupt */
1685198092Srdivacky	OWRITE(sc, FWOHCI_INTMASKCLR,
1686193326Sed			OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID
1687193326Sed			| OHCI_INT_PHY_INT
1688193326Sed			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS
1689193326Sed			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
1690198092Srdivacky			| OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS
1691198092Srdivacky			| OHCI_INT_PHY_BUS_R);
1692224145Sdim
1693193326Sed	fw_drain_txq(&sc->fc);
1694193326Sed
1695193326Sed/* XXX Link down?  Bus reset? */
1696193326Sed	return 0;
1697193326Sed}
1698193326Sed
1699198092Srdivackyint
1700193326Sedfwohci_resume(struct fwohci_softc *sc, device_t dev)
1701234353Sdim{
1702193326Sed	int i;
1703193326Sed	struct fw_xferq *ir;
1704224145Sdim	struct fw_bulkxfer *chunk;
1705193326Sed
1706218893Sdim	fwohci_reset(sc, dev);
1707193326Sed	/* XXX resume isochronus receive automatically. (how about TX?) */
1708193326Sed	for(i = 0; i < sc->fc.nisodma; i ++) {
1709198092Srdivacky		ir = &sc->ir[i].xferq;
1710193326Sed		if((ir->flag & FWXFERQ_RUNNING) != 0) {
1711193326Sed			device_printf(sc->fc.dev,
1712199990Srdivacky				"resume iso receive ch: %d\n", i);
1713199990Srdivacky			ir->flag &= ~FWXFERQ_RUNNING;
1714199990Srdivacky			/* requeue stdma to stfree */
1715199990Srdivacky			while((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
1716193326Sed				STAILQ_REMOVE_HEAD(&ir->stdma, link);
1717199990Srdivacky				STAILQ_INSERT_TAIL(&ir->stfree, chunk, link);
1718199990Srdivacky			}
1719199990Srdivacky			sc->fc.irx_enable(&sc->fc, i);
1720198092Srdivacky		}
1721198092Srdivacky	}
1722193326Sed
1723193326Sed	bus_generic_resume(dev);
1724193326Sed	sc->fc.ibr(&sc->fc);
1725193326Sed	return 0;
1726193326Sed}
1727193326Sed
1728193326Sed#define ACK_ALL
1729193326Sedstatic void
1730193326Sedfwohci_intr_body(struct fwohci_softc *sc, u_int32_t stat, int count)
1731193326Sed{
1732193326Sed	u_int32_t irstat, itstat;
1733249423Sdim	u_int i;
1734193326Sed	struct firewire_comm *fc = (struct firewire_comm *)sc;
1735193326Sed
1736226633Sdim#ifdef OHCI_DEBUG
1737193326Sed	if(stat & OREAD(sc, FWOHCI_INTMASK))
1738249423Sdim		device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n",
1739193326Sed			stat & OHCI_INT_EN ? "DMA_EN ":"",
1740193326Sed			stat & OHCI_INT_PHY_REG ? "PHY_REG ":"",
1741193326Sed			stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"",
1742193326Sed			stat & OHCI_INT_ERR ? "INT_ERR ":"",
1743226633Sdim			stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"",
1744226633Sdim			stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"",
1745193326Sed			stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"",
1746193326Sed			stat & OHCI_INT_CYC_START ? "CYC_START ":"",
1747198092Srdivacky			stat & OHCI_INT_PHY_INT ? "PHY_INT ":"",
1748193326Sed			stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"",
1749193326Sed			stat & OHCI_INT_PHY_SID ? "SID ":"",
1750193326Sed			stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"",
1751224145Sdim			stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"",
1752193326Sed			stat & OHCI_INT_DMA_IR ? "DMA_IR ":"",
1753193326Sed			stat & OHCI_INT_DMA_IT  ? "DMA_IT " :"",
1754198092Srdivacky			stat & OHCI_INT_DMA_PRRS  ? "DMA_PRRS " :"",
1755198092Srdivacky			stat & OHCI_INT_DMA_PRRQ  ? "DMA_PRRQ " :"",
1756198092Srdivacky			stat & OHCI_INT_DMA_ARRS  ? "DMA_ARRS " :"",
1757198092Srdivacky			stat & OHCI_INT_DMA_ARRQ  ? "DMA_ARRQ " :"",
1758193326Sed			stat & OHCI_INT_DMA_ATRS  ? "DMA_ATRS " :"",
1759198092Srdivacky			stat & OHCI_INT_DMA_ATRQ  ? "DMA_ATRQ " :"",
1760193326Sed			stat, OREAD(sc, FWOHCI_INTMASK)
1761193326Sed		);
1762193326Sed#endif
1763226633Sdim/* Bus reset */
1764193326Sed	if(stat & OHCI_INT_PHY_BUS_R ){
1765193326Sed		if (fc->status == FWBUSRESET)
1766198092Srdivacky			goto busresetout;
1767198092Srdivacky		/* Disable bus reset interrupt until sid recv. */
1768198092Srdivacky		OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_PHY_BUS_R);
1769198092Srdivacky
1770193326Sed		device_printf(fc->dev, "BUS reset\n");
1771193326Sed		OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_CYC_LOST);
1772193326Sed		OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC);
1773193326Sed
1774193326Sed		OWRITE(sc,  OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN);
1775193326Sed		sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING;
1776234353Sdim		OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
1777234353Sdim		sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
1778234353Sdim
1779234353Sdim#ifndef ACK_ALL
1780234353Sdim		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
1781226633Sdim#endif
1782193326Sed		fw_busreset(fc);
1783193326Sed		OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
1784193326Sed		OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
1785226633Sdim	}
1786226633Sdimbusresetout:
1787226633Sdim	if((stat & OHCI_INT_DMA_IR )){
1788226633Sdim#ifndef ACK_ALL
1789195341Sed		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR);
1790195341Sed#endif
1791193326Sed#if __FreeBSD_version >= 500000
1792193326Sed		irstat = atomic_readandclear_int(&sc->irstat);
1793198092Srdivacky#else
1794243830Sdim		irstat = sc->irstat;
1795243830Sdim		sc->irstat = 0;
1796243830Sdim#endif
1797243830Sdim		for(i = 0; i < fc->nisodma ; i++){
1798198092Srdivacky			struct fwohci_dbch *dbch;
1799198092Srdivacky
1800198092Srdivacky			if((irstat & (1 << i)) != 0){
1801198092Srdivacky				dbch = &sc->ir[i];
1802193326Sed				if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) {
1803193326Sed					device_printf(sc->fc.dev,
1804226633Sdim						"dma(%d) not active\n", i);
1805226633Sdim					continue;
1806226633Sdim				}
1807226633Sdim				fwohci_rbuf_update(sc, i);
1808198092Srdivacky			}
1809195341Sed		}
1810195341Sed	}
1811193326Sed	if((stat & OHCI_INT_DMA_IT )){
1812193326Sed#ifndef ACK_ALL
1813198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT);
1814243830Sdim#endif
1815243830Sdim#if __FreeBSD_version >= 500000
1816243830Sdim		itstat = atomic_readandclear_int(&sc->itstat);
1817243830Sdim#else
1818198092Srdivacky		itstat = sc->itstat;
1819198092Srdivacky		sc->itstat = 0;
1820198092Srdivacky#endif
1821198092Srdivacky		for(i = 0; i < fc->nisodma ; i++){
1822193326Sed			if((itstat & (1 << i)) != 0){
1823193326Sed				fwohci_tbuf_update(sc, i);
1824193326Sed			}
1825193326Sed		}
1826193326Sed	}
1827193326Sed	if((stat & OHCI_INT_DMA_PRRS )){
1828193326Sed#ifndef ACK_ALL
1829198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS);
1830198092Srdivacky#endif
1831198092Srdivacky#if 0
1832198092Srdivacky		dump_dma(sc, ARRS_CH);
1833198092Srdivacky		dump_db(sc, ARRS_CH);
1834198092Srdivacky#endif
1835198092Srdivacky		fwohci_arcv(sc, &sc->arrs, count);
1836198092Srdivacky	}
1837198092Srdivacky	if((stat & OHCI_INT_DMA_PRRQ )){
1838198092Srdivacky#ifndef ACK_ALL
1839198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ);
1840198092Srdivacky#endif
1841224145Sdim#if 0
1842249423Sdim		dump_dma(sc, ARRQ_CH);
1843249423Sdim		dump_db(sc, ARRQ_CH);
1844198092Srdivacky#endif
1845198092Srdivacky		fwohci_arcv(sc, &sc->arrq, count);
1846198092Srdivacky	}
1847198092Srdivacky	if(stat & OHCI_INT_PHY_SID){
1848198092Srdivacky		u_int32_t *buf, node_id;
1849198092Srdivacky		int plen;
1850198092Srdivacky
1851198092Srdivacky#ifndef ACK_ALL
1852198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID);
1853239462Sdim#endif
1854198092Srdivacky		/* Enable bus reset interrupt */
1855249423Sdim		OWRITE(sc, FWOHCI_INTMASK,  OHCI_INT_PHY_BUS_R);
1856249423Sdim		/* Allow async. request to us */
1857243830Sdim		OWRITE(sc, OHCI_AREQHI, 1 << 31);
1858198092Srdivacky		/* XXX insecure ?? */
1859198092Srdivacky		OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
1860198092Srdivacky		OWRITE(sc, OHCI_PREQLO, 0xffffffff);
1861198092Srdivacky		OWRITE(sc, OHCI_PREQUPPER, 0x10000);
1862198092Srdivacky		/* Set ATRetries register */
1863198092Srdivacky		OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
1864198092Srdivacky/*
1865198092Srdivacky** Checking whether the node is root or not. If root, turn on
1866198092Srdivacky** cycle master.
1867198092Srdivacky*/
1868198092Srdivacky		node_id = OREAD(sc, FWOHCI_NODEID);
1869198092Srdivacky		plen = OREAD(sc, OHCI_SID_CNT);
1870198092Srdivacky
1871198092Srdivacky		device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
1872198092Srdivacky			node_id, (plen >> 16) & 0xff);
1873198092Srdivacky		if (!(node_id & OHCI_NODE_VALID)) {
1874198092Srdivacky			printf("Bus reset failure\n");
1875198092Srdivacky			goto sidout;
1876198092Srdivacky		}
1877198092Srdivacky		if (node_id & OHCI_NODE_ROOT) {
1878198092Srdivacky			printf("CYCLEMASTER mode\n");
1879198092Srdivacky			OWRITE(sc, OHCI_LNKCTL,
1880198092Srdivacky				OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
1881198092Srdivacky		} else {
1882198092Srdivacky			printf("non CYCLEMASTER mode\n");
1883198092Srdivacky			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
1884198092Srdivacky			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
1885198092Srdivacky		}
1886198092Srdivacky		fc->nodeid = node_id & 0x3f;
1887198092Srdivacky
1888198092Srdivacky		if (plen & OHCI_SID_ERR) {
1889198092Srdivacky			device_printf(fc->dev, "SID Error\n");
1890198092Srdivacky			goto sidout;
1891198092Srdivacky		}
1892224145Sdim		plen &= OHCI_SID_CNT_MASK;
1893198092Srdivacky		if (plen < 4 || plen > OHCI_SIDSIZE) {
1894198092Srdivacky			device_printf(fc->dev, "invalid SID len = %d\n", plen);
1895198092Srdivacky			goto sidout;
1896198092Srdivacky		}
1897198092Srdivacky		plen -= 4; /* chop control info */
1898198092Srdivacky		buf = (u_int32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
1899198092Srdivacky		if (buf == NULL) {
1900198092Srdivacky			device_printf(fc->dev, "malloc failed\n");
1901198092Srdivacky			goto sidout;
1902198092Srdivacky		}
1903198092Srdivacky		for (i = 0; i < plen / 4; i ++)
1904198092Srdivacky			buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
1905224145Sdim#if 1
1906198092Srdivacky		/* pending all pre-bus_reset packets */
1907198092Srdivacky		fwohci_txd(sc, &sc->atrq);
1908198092Srdivacky		fwohci_txd(sc, &sc->atrs);
1909198092Srdivacky		fwohci_arcv(sc, &sc->arrs, -1);
1910198092Srdivacky		fwohci_arcv(sc, &sc->arrq, -1);
1911193326Sed		fw_drain_txq(fc);
1912193326Sed#endif
1913224145Sdim		fw_sidrcv(fc, buf, plen);
1914193326Sed		free(buf, M_FW);
1915193326Sed	}
1916193326Sedsidout:
1917193326Sed	if((stat & OHCI_INT_DMA_ATRQ )){
1918198092Srdivacky#ifndef ACK_ALL
1919198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ);
1920198092Srdivacky#endif
1921198092Srdivacky		fwohci_txd(sc, &(sc->atrq));
1922193326Sed	}
1923198092Srdivacky	if((stat & OHCI_INT_DMA_ATRS )){
1924193326Sed#ifndef ACK_ALL
1925193326Sed		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS);
1926193326Sed#endif
1927226633Sdim		fwohci_txd(sc, &(sc->atrs));
1928193326Sed	}
1929193326Sed	if((stat & OHCI_INT_PW_ERR )){
1930193326Sed#ifndef ACK_ALL
1931193326Sed		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR);
1932198092Srdivacky#endif
1933198092Srdivacky		device_printf(fc->dev, "posted write error\n");
1934198092Srdivacky	}
1935198092Srdivacky	if((stat & OHCI_INT_ERR )){
1936198092Srdivacky#ifndef ACK_ALL
1937193326Sed		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR);
1938193326Sed#endif
1939193326Sed		device_printf(fc->dev, "unrecoverable error\n");
1940249423Sdim	}
1941198092Srdivacky	if((stat & OHCI_INT_PHY_INT)) {
1942226633Sdim#ifndef ACK_ALL
1943226633Sdim		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT);
1944193326Sed#endif
1945198092Srdivacky		device_printf(fc->dev, "phy int\n");
1946198092Srdivacky	}
1947198092Srdivacky
1948198092Srdivacky	return;
1949198092Srdivacky}
1950198092Srdivacky
1951198092Srdivacky#if FWOHCI_TASKQUEUE
1952198092Srdivackystatic void
1953198092Srdivackyfwohci_complete(void *arg, int pending)
1954198092Srdivacky{
1955198092Srdivacky	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
1956198092Srdivacky	u_int32_t stat;
1957198092Srdivacky
1958198092Srdivackyagain:
1959224145Sdim	stat = atomic_readandclear_int(&sc->intstat);
1960198092Srdivacky	if (stat)
1961218893Sdim		fwohci_intr_body(sc, stat, -1);
1962198092Srdivacky	else
1963198092Srdivacky		return;
1964198092Srdivacky	goto again;
1965198092Srdivacky}
1966198092Srdivacky#endif
1967198092Srdivacky
1968198092Srdivackystatic u_int32_t
1969198092Srdivackyfwochi_check_stat(struct fwohci_softc *sc)
1970198092Srdivacky{
1971198092Srdivacky	u_int32_t stat, irstat, itstat;
1972198092Srdivacky
1973198092Srdivacky	stat = OREAD(sc, FWOHCI_INTSTAT);
1974198092Srdivacky	if (stat == 0xffffffff) {
1975198092Srdivacky		device_printf(sc->fc.dev,
1976198092Srdivacky			"device physically ejected?\n");
1977198092Srdivacky		return(stat);
1978198092Srdivacky	}
1979198092Srdivacky#ifdef ACK_ALL
1980198092Srdivacky	if (stat)
1981198092Srdivacky		OWRITE(sc, FWOHCI_INTSTATCLR, stat);
1982224145Sdim#endif
1983198092Srdivacky	if (stat & OHCI_INT_DMA_IR) {
1984198092Srdivacky		irstat = OREAD(sc, OHCI_IR_STAT);
1985198092Srdivacky		OWRITE(sc, OHCI_IR_STATCLR, irstat);
1986226633Sdim		atomic_set_int(&sc->irstat, irstat);
1987226633Sdim	}
1988226633Sdim	if (stat & OHCI_INT_DMA_IT) {
1989226633Sdim		itstat = OREAD(sc, OHCI_IT_STAT);
1990226633Sdim		OWRITE(sc, OHCI_IT_STATCLR, itstat);
1991226633Sdim		atomic_set_int(&sc->itstat, itstat);
1992226633Sdim	}
1993226633Sdim	return(stat);
1994226633Sdim}
1995226633Sdim
1996226633Sdimvoid
1997234353Sdimfwohci_intr(void *arg)
1998226633Sdim{
1999228379Sdim	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
2000228379Sdim	u_int32_t stat;
2001228379Sdim#if !FWOHCI_TASKQUEUE
2002226633Sdim	u_int32_t bus_reset = 0;
2003226633Sdim#endif
2004226633Sdim
2005226633Sdim	if (!(sc->intmask & OHCI_INT_EN)) {
2006228379Sdim		/* polling mode */
2007226633Sdim		return;
2008249423Sdim	}
2009226633Sdim
2010226633Sdim#if !FWOHCI_TASKQUEUE
2011226633Sdimagain:
2012226633Sdim#endif
2013226633Sdim	stat = fwochi_check_stat(sc);
2014226633Sdim	if (stat == 0 || stat == 0xffffffff)
2015226633Sdim		return;
2016226633Sdim#if FWOHCI_TASKQUEUE
2017226633Sdim	atomic_set_int(&sc->intstat, stat);
2018226633Sdim	/* XXX mask bus reset intr. during bus reset phase */
2019226633Sdim	if (stat)
2020226633Sdim		taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete);
2021226633Sdim#else
2022226633Sdim	/* We cannot clear bus reset event during bus reset phase */
2023226633Sdim	if ((stat & ~bus_reset) == 0)
2024226633Sdim		return;
2025226633Sdim	bus_reset = stat & OHCI_INT_PHY_BUS_R;
2026226633Sdim	fwohci_intr_body(sc, stat, -1);
2027226633Sdim	goto again;
2028226633Sdim#endif
2029193326Sed}
2030193326Sed
2031193326Sedvoid
2032193326Sedfwohci_poll(struct firewire_comm *fc, int quick, int count)
2033226633Sdim{
2034226633Sdim	int s;
2035193326Sed	u_int32_t stat;
2036195341Sed	struct fwohci_softc *sc;
2037193326Sed
2038193326Sed
2039193326Sed	sc = (struct fwohci_softc *)fc;
2040193326Sed	stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT |
2041198092Srdivacky		OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ |
2042193326Sed		OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS;
2043193326Sed#if 0
2044193326Sed	if (!quick) {
2045226633Sdim#else
2046226633Sdim	if (1) {
2047198092Srdivacky#endif
2048195341Sed		stat = fwochi_check_stat(sc);
2049193326Sed		if (stat == 0 || stat == 0xffffffff)
2050193326Sed			return;
2051193326Sed	}
2052193326Sed	s = splfw();
2053198092Srdivacky	fwohci_intr_body(sc, stat, count);
2054193326Sed	splx(s);
2055193326Sed}
2056193326Sed
2057226633Sdimstatic void
2058205219Srdivackyfwohci_set_intr(struct firewire_comm *fc, int enable)
2059205219Srdivacky{
2060193326Sed	struct fwohci_softc *sc;
2061193326Sed
2062193326Sed	sc = (struct fwohci_softc *)fc;
2063193326Sed	if (bootverbose)
2064193326Sed		device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable);
2065193326Sed	if (enable) {
2066193326Sed		sc->intmask |= OHCI_INT_EN;
2067198092Srdivacky		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN);
2068193326Sed	} else {
2069193326Sed		sc->intmask &= ~OHCI_INT_EN;
2070193326Sed		OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN);
2071193326Sed	}
2072193326Sed}
2073193326Sed
2074193326Sedstatic void
2075193326Sedfwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
2076193326Sed{
2077193326Sed	struct firewire_comm *fc = &sc->fc;
2078193326Sed	volatile struct fwohcidb *db;
2079224145Sdim	struct fw_bulkxfer *chunk;
2080198092Srdivacky	struct fw_xferq *it;
2081193326Sed	u_int32_t stat, count;
2082193326Sed	int s, w=0, ldesc;
2083198092Srdivacky
2084226633Sdim	it = fc->it[dmach];
2085226633Sdim	ldesc = sc->it[dmach].ndesc - 1;
2086198092Srdivacky	s = splfw(); /* unnecessary ? */
2087249423Sdim	fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
2088249423Sdim	while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
2089224145Sdim		db = ((struct fwohcidb_tr *)(chunk->end))->db;
2090249423Sdim		stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
2091249423Sdim				>> OHCI_STATUS_SHIFT;
2092198092Srdivacky		db = ((struct fwohcidb_tr *)(chunk->start))->db;
2093198092Srdivacky		count = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
2094198092Srdivacky				& OHCI_COUNT_MASK;
2095198092Srdivacky		if (stat == 0)
2096198092Srdivacky			break;
2097198092Srdivacky		STAILQ_REMOVE_HEAD(&it->stdma, link);
2098198092Srdivacky		switch (stat & FWOHCIEV_MASK){
2099198092Srdivacky		case FWOHCIEV_ACKCOMPL:
2100239462Sdim#if 0
2101204643Srdivacky			device_printf(fc->dev, "0x%08x\n", count);
2102204643Srdivacky#endif
2103204643Srdivacky			break;
2104249423Sdim		default:
2105249423Sdim			device_printf(fc->dev,
2106198092Srdivacky				"Isochronous transmit err %02x(%s)\n",
2107243830Sdim					stat, fwohcicode[stat & 0x1f]);
2108249423Sdim		}
2109198092Srdivacky		STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
2110198092Srdivacky		w++;
2111198092Srdivacky	}
2112198092Srdivacky	splx(s);
2113204643Srdivacky	if (w)
2114204643Srdivacky		wakeup(it);
2115204643Srdivacky}
2116204643Srdivacky
2117198092Srdivackystatic void
2118198092Srdivackyfwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
2119198092Srdivacky{
2120198092Srdivacky	struct firewire_comm *fc = &sc->fc;
2121198092Srdivacky	volatile struct fwohcidb_tr *db_tr;
2122198092Srdivacky	struct fw_bulkxfer *chunk;
2123198092Srdivacky	struct fw_xferq *ir;
2124198092Srdivacky	u_int32_t stat;
2125198092Srdivacky	int s, w=0, ldesc;
2126198092Srdivacky
2127204643Srdivacky	ir = fc->ir[dmach];
2128204643Srdivacky	ldesc = sc->ir[dmach].ndesc - 1;
2129204643Srdivacky#if 0
2130204643Srdivacky	dump_db(sc, dmach);
2131198092Srdivacky#endif
2132198092Srdivacky	s = splfw();
2133198092Srdivacky	fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
2134198092Srdivacky	while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
2135198092Srdivacky		db_tr = (struct fwohcidb_tr *)chunk->end;
2136198092Srdivacky		stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res)
2137198092Srdivacky				>> OHCI_STATUS_SHIFT;
2138198092Srdivacky		if (stat == 0)
2139198092Srdivacky			break;
2140198092Srdivacky
2141198092Srdivacky		if (chunk->mbuf != NULL) {
2142198092Srdivacky			bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map,
2143198092Srdivacky						BUS_DMASYNC_POSTREAD);
2144198092Srdivacky			bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map);
2145198092Srdivacky		} else if (ir->buf != NULL) {
2146198092Srdivacky			fwdma_sync_multiseg(ir->buf, chunk->poffset,
2147224145Sdim				ir->bnpacket, BUS_DMASYNC_POSTREAD);
2148198092Srdivacky		} else {
2149198092Srdivacky			/* XXX */
2150198092Srdivacky			printf("fwohci_rbuf_update: this shouldn't happend\n");
2151198092Srdivacky		}
2152198092Srdivacky
2153234353Sdim		STAILQ_REMOVE_HEAD(&ir->stdma, link);
2154234353Sdim		STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link);
2155234353Sdim		switch (stat & FWOHCIEV_MASK) {
2156234353Sdim		case FWOHCIEV_ACKCOMPL:
2157234353Sdim			chunk->resp = 0;
2158234353Sdim			break;
2159234353Sdim		default:
2160234353Sdim			chunk->resp = EINVAL;
2161234353Sdim			device_printf(fc->dev,
2162193326Sed				"Isochronous receive err %02x(%s)\n",
2163193326Sed					stat, fwohcicode[stat & 0x1f]);
2164193326Sed		}
2165193326Sed		w++;
2166198092Srdivacky	}
2167193326Sed	splx(s);
2168193326Sed	if (w) {
2169194613Sed		if (ir->flag & FWXFERQ_HANDLER)
2170193326Sed			ir->hand(ir);
2171194613Sed		else
2172194613Sed			wakeup(ir);
2173193326Sed	}
2174193326Sed}
2175193326Sed
2176193326Sedvoid
2177193326Seddump_dma(struct fwohci_softc *sc, u_int32_t ch)
2178194613Sed{
2179194613Sed	u_int32_t off, cntl, stat, cmd, match;
2180195341Sed
2181198092Srdivacky	if(ch == 0){
2182195341Sed		off = OHCI_ATQOFF;
2183195341Sed	}else if(ch == 1){
2184195341Sed		off = OHCI_ATSOFF;
2185198092Srdivacky	}else if(ch == 2){
2186198092Srdivacky		off = OHCI_ARQOFF;
2187198092Srdivacky	}else if(ch == 3){
2188195341Sed		off = OHCI_ARSOFF;
2189198092Srdivacky	}else if(ch < IRX_CH){
2190193326Sed		off = OHCI_ITCTL(ch - ITX_CH);
2191218893Sdim	}else{
2192218893Sdim		off = OHCI_IRCTL(ch - IRX_CH);
2193193326Sed	}
2194193326Sed	cntl = stat = OREAD(sc, off);
2195226633Sdim	cmd = OREAD(sc, off + 0xc);
2196226633Sdim	match = OREAD(sc, off + 0x10);
2197226633Sdim
2198198092Srdivacky	device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n",
2199198092Srdivacky		ch,
2200226633Sdim		cntl,
2201226633Sdim		cmd,
2202198092Srdivacky		match);
2203198092Srdivacky	stat &= 0xffff ;
2204218893Sdim	if (stat) {
2205193326Sed		device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n",
2206193326Sed			ch,
2207243830Sdim			stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2208193326Sed			stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2209193326Sed			stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2210207619Srdivacky			stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2211226633Sdim			stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2212226633Sdim			stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2213193326Sed			fwohcicode[stat & 0x1f],
2214207619Srdivacky			stat & 0x1f
2215193326Sed		);
2216193326Sed	}else{
2217207619Srdivacky		device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch);
2218198092Srdivacky	}
2219193326Sed}
2220207619Srdivacky
2221199482Srdivackyvoid
2222243830Sdimdump_db(struct fwohci_softc *sc, u_int32_t ch)
2223198092Srdivacky{
2224193326Sed	struct fwohci_dbch *dbch;
2225224145Sdim	struct fwohcidb_tr *cp = NULL, *pp, *np = NULL;
2226224145Sdim	volatile struct fwohcidb *curr = NULL, *prev, *next = NULL;
2227224145Sdim	int idb, jdb;
2228224145Sdim	u_int32_t cmd, off;
2229224145Sdim	if(ch == 0){
2230224145Sdim		off = OHCI_ATQOFF;
2231224145Sdim		dbch = &sc->atrq;
2232224145Sdim	}else if(ch == 1){
2233224145Sdim		off = OHCI_ATSOFF;
2234224145Sdim		dbch = &sc->atrs;
2235224145Sdim	}else if(ch == 2){
2236224145Sdim		off = OHCI_ARQOFF;
2237224145Sdim		dbch = &sc->arrq;
2238198092Srdivacky	}else if(ch == 3){
2239224145Sdim		off = OHCI_ARSOFF;
2240198092Srdivacky		dbch = &sc->arrs;
2241224145Sdim	}else if(ch < IRX_CH){
2242224145Sdim		off = OHCI_ITCTL(ch - ITX_CH);
2243224145Sdim		dbch = &sc->it[ch - ITX_CH];
2244226633Sdim	}else {
2245226633Sdim		off = OHCI_IRCTL(ch - IRX_CH);
2246226633Sdim		dbch = &sc->ir[ch - IRX_CH];
2247226633Sdim	}
2248226633Sdim	cmd = OREAD(sc, off + 0xc);
2249226633Sdim
2250226633Sdim	if( dbch->ndb == 0 ){
2251226633Sdim		device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch);
2252226633Sdim		return;
2253226633Sdim	}
2254226633Sdim	pp = dbch->top;
2255226633Sdim	prev = pp->db;
2256226633Sdim	for(idb = 0 ; idb < dbch->ndb ; idb ++ ){
2257226633Sdim		if(pp == NULL){
2258193326Sed			curr = NULL;
2259226633Sdim			goto outdb;
2260226633Sdim		}
2261221345Sdim		cp = STAILQ_NEXT(pp, link);
2262221345Sdim		if(cp == NULL){
2263193326Sed			curr = NULL;
2264221345Sdim			goto outdb;
2265193326Sed		}
2266226633Sdim		np = STAILQ_NEXT(cp, link);
2267226633Sdim		for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){
2268198092Srdivacky			if ((cmd  & 0xfffffff0) == cp->bus_addr) {
2269195341Sed				curr = cp->db;
2270193326Sed				if(np != NULL){
2271193326Sed					next = np->db;
2272193326Sed				}else{
2273193326Sed					next = NULL;
2274198092Srdivacky				}
2275193326Sed				goto outdb;
2276193326Sed			}
2277198092Srdivacky		}
2278198092Srdivacky		pp = STAILQ_NEXT(pp, link);
2279198092Srdivacky		prev = pp->db;
2280198092Srdivacky	}
2281193326Sedoutdb:
2282226633Sdim	if( curr != NULL){
2283226633Sdim#if 0
2284193326Sed		printf("Prev DB %d\n", ch);
2285195341Sed		print_db(pp, prev, ch, dbch->ndesc);
2286193326Sed#endif
2287193326Sed		printf("Current DB %d\n", ch);
2288193326Sed		print_db(cp, curr, ch, dbch->ndesc);
2289193326Sed#if 0
2290198092Srdivacky		printf("Next DB %d\n", ch);
2291193326Sed		print_db(np, next, ch, dbch->ndesc);
2292193326Sed#endif
2293226633Sdim	}else{
2294234353Sdim		printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd);
2295234353Sdim	}
2296234353Sdim	return;
2297193326Sed}
2298193326Sed
2299193326Sedvoid
2300193326Sedprint_db(struct fwohcidb_tr *db_tr, volatile struct fwohcidb *db,
2301193326Sed		u_int32_t ch, u_int32_t max)
2302193326Sed{
2303193326Sed	fwohcireg_t stat;
2304193326Sed	int i, key;
2305193326Sed	u_int32_t cmd, res;
2306193326Sed
2307193326Sed	if(db == NULL){
2308193326Sed		printf("No Descriptor is found\n");
2309226633Sdim		return;
2310193326Sed	}
2311193326Sed
2312193326Sed	printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n",
2313193326Sed		ch,
2314193326Sed		"Current",
2315193326Sed		"OP  ",
2316193326Sed		"KEY",
2317198092Srdivacky		"INT",
2318198092Srdivacky		"BR ",
2319198092Srdivacky		"len",
2320198092Srdivacky		"Addr",
2321198092Srdivacky		"Depend",
2322218893Sdim		"Stat",
2323198092Srdivacky		"Cnt");
2324198092Srdivacky	for( i = 0 ; i <= max ; i ++){
2325198092Srdivacky		cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd);
2326198092Srdivacky		res = FWOHCI_DMA_READ(db[i].db.desc.res);
2327226633Sdim		key = cmd & OHCI_KEY_MASK;
2328198092Srdivacky		stat = res >> OHCI_STATUS_SHIFT;
2329198092Srdivacky#if __FreeBSD_version >= 500000
2330198092Srdivacky		printf("%08jx %s %s %s %s %5d %08x %08x %04x:%04x",
2331198092Srdivacky				(uintmax_t)db_tr->bus_addr,
2332226633Sdim#else
2333226633Sdim		printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x",
2334226633Sdim				db_tr->bus_addr,
2335198092Srdivacky#endif
2336218893Sdim				dbcode[(cmd >> 28) & 0xf],
2337226633Sdim				dbkey[(cmd >> 24) & 0x7],
2338198092Srdivacky				dbcond[(cmd >> 20) & 0x3],
2339198092Srdivacky				dbcond[(cmd >> 18) & 0x3],
2340226633Sdim				cmd & OHCI_COUNT_MASK,
2341218893Sdim				FWOHCI_DMA_READ(db[i].db.desc.addr),
2342198092Srdivacky				FWOHCI_DMA_READ(db[i].db.desc.depend),
2343198092Srdivacky				stat,
2344234353Sdim				res & OHCI_COUNT_MASK);
2345234353Sdim		if(stat & 0xff00){
2346234353Sdim			printf(" %s%s%s%s%s%s %s(%x)\n",
2347234353Sdim				stat & OHCI_CNTL_DMA_RUN ? "RUN," : "",
2348234353Sdim				stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "",
2349198092Srdivacky				stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "",
2350234353Sdim				stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "",
2351234353Sdim				stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "",
2352234353Sdim				stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "",
2353234353Sdim				fwohcicode[stat & 0x1f],
2354198092Srdivacky				stat & 0x1f
2355226633Sdim			);
2356198092Srdivacky		}else{
2357228379Sdim			printf(" Nostat\n");
2358193326Sed		}
2359193326Sed		if(key == OHCI_KEY_ST2 ){
2360199482Srdivacky			printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
2361226633Sdim				FWOHCI_DMA_READ(db[i+1].db.immed[0]),
2362228379Sdim				FWOHCI_DMA_READ(db[i+1].db.immed[1]),
2363193326Sed				FWOHCI_DMA_READ(db[i+1].db.immed[2]),
2364193326Sed				FWOHCI_DMA_READ(db[i+1].db.immed[3]));
2365193326Sed		}
2366198092Srdivacky		if(key == OHCI_KEY_DEVICE){
2367193326Sed			return;
2368193326Sed		}
2369198092Srdivacky		if((cmd & OHCI_BRANCH_MASK)
2370226633Sdim				== OHCI_BRANCH_ALWAYS){
2371193326Sed			return;
2372193326Sed		}
2373193326Sed		if((cmd & OHCI_CMD_MASK)
2374218893Sdim				== OHCI_OUTPUT_LAST){
2375193326Sed			return;
2376218893Sdim		}
2377193326Sed		if((cmd & OHCI_CMD_MASK)
2378193326Sed				== OHCI_INPUT_LAST){
2379193326Sed			return;
2380218893Sdim		}
2381193326Sed		if(key == OHCI_KEY_ST2 ){
2382218893Sdim			i++;
2383193326Sed		}
2384193326Sed	}
2385193326Sed	return;
2386193326Sed}
2387193326Sed
2388193326Sedvoid
2389193326Sedfwohci_ibr(struct firewire_comm *fc)
2390193326Sed{
2391195099Sed	struct fwohci_softc *sc;
2392198092Srdivacky	u_int32_t fun;
2393193326Sed
2394193326Sed	device_printf(fc->dev, "Initiate bus reset\n");
2395221345Sdim	sc = (struct fwohci_softc *)fc;
2396193326Sed
2397193326Sed	/*
2398198092Srdivacky	 * Set root hold-off bit so that non cyclemaster capable node
2399198092Srdivacky	 * shouldn't became the root node.
2400198092Srdivacky	 */
2401226633Sdim#if 1
2402193326Sed	fun = fwphy_rddata(sc, FW_PHY_IBR_REG);
2403224145Sdim	fun |= FW_PHY_IBR | FW_PHY_RHB;
2404193326Sed	fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun);
2405224145Sdim#else	/* Short bus reset */
2406193326Sed	fun = fwphy_rddata(sc, FW_PHY_ISBR_REG);
2407193326Sed	fun |= FW_PHY_ISBR | FW_PHY_RHB;
2408193326Sed	fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun);
2409193326Sed#endif
2410193326Sed}
2411193326Sed
2412193326Sedvoid
2413193326Sedfwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
2414193326Sed{
2415193326Sed	struct fwohcidb_tr *db_tr, *fdb_tr;
2416198092Srdivacky	struct fwohci_dbch *dbch;
2417234353Sdim	volatile struct fwohcidb *db;
2418221345Sdim	struct fw_pkt *fp;
2419199990Srdivacky	volatile struct fwohci_txpkthdr *ohcifp;
2420221345Sdim	unsigned short chtag;
2421198092Srdivacky	int idb;
2422198092Srdivacky
2423193326Sed	dbch = &sc->it[dmach];
2424193326Sed	chtag = sc->it[dmach].xferq.flag & 0xff;
2425198092Srdivacky
2426224145Sdim	db_tr = (struct fwohcidb_tr *)(bulkxfer->start);
2427198092Srdivacky	fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end);
2428198092Srdivacky/*
2429193326Seddevice_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr);
2430193326Sed*/
2431193326Sed	for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) {
2432193326Sed		db = db_tr->db;
2433193326Sed		fp = (struct fw_pkt *)db_tr->buf;
2434193326Sed		ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed;
2435193326Sed		ohcifp->mode.ld[0] = fp->mode.ld[0];
2436193326Sed		ohcifp->mode.stream.len = fp->mode.stream.len;
2437193326Sed		ohcifp->mode.stream.chtag = chtag;
2438193326Sed		ohcifp->mode.stream.tcode = 0xa;
2439193326Sed		ohcifp->mode.stream.spd = 0;
2440193326Sed#if BYTE_ORDER == BIG_ENDIAN
2441224145Sdim		FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]);
2442198092Srdivacky		FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]);
2443198092Srdivacky#endif
2444193326Sed
2445193326Sed		FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK);
2446193326Sed		FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len);
2447193326Sed		FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2448193326Sed#if 0 /* if bulkxfer->npackets changes */
2449221345Sdim		db[2].db.desc.cmd = OHCI_OUTPUT_LAST
2450221345Sdim			| OHCI_UPDATE
2451221345Sdim			| OHCI_BRANCH_ALWAYS;
2452221345Sdim		db[0].db.desc.depend =
2453221345Sdim			= db[dbch->ndesc - 1].db.desc.depend
2454221345Sdim			= STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc;
2455221345Sdim#else
2456226633Sdim		FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc);
2457226633Sdim		FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc);
2458221345Sdim#endif
2459221345Sdim		bulkxfer->end = (caddr_t)db_tr;
2460221345Sdim		db_tr = STAILQ_NEXT(db_tr, link);
2461221345Sdim	}
2462221345Sdim	db = ((struct fwohcidb_tr *)bulkxfer->end)->db;
2463221345Sdim	FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf);
2464221345Sdim	FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf);
2465221345Sdim#if 0 /* if bulkxfer->npackets changes */
2466221345Sdim	db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2467221345Sdim	/* OHCI 1.1 and above */
2468221345Sdim	db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS;
2469221345Sdim#endif
2470221345Sdim/*
2471221345Sdim	db_tr = (struct fwohcidb_tr *)bulkxfer->start;
2472193326Sed	fdb_tr = (struct fwohcidb_tr *)bulkxfer->end;
2473221345Sdimdevice_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr);
2474221345Sdim*/
2475221345Sdim	return;
2476221345Sdim}
2477221345Sdim
2478193326Sedstatic int
2479193326Sedfwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2480193326Sed								int poffset)
2481193326Sed{
2482221345Sdim	volatile struct fwohcidb *db = db_tr->db;
2483193326Sed	struct fw_xferq *it;
2484221345Sdim	int err = 0;
2485221345Sdim
2486193326Sed	it = &dbch->xferq;
2487198092Srdivacky	if(it->buf == 0){
2488193326Sed		err = EINVAL;
2489193326Sed		return err;
2490193326Sed	}
2491221345Sdim	db_tr->buf = fwdma_v_addr(it->buf, poffset);
2492221345Sdim	db_tr->dbcnt = 3;
2493193326Sed
2494226633Sdim	FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
2495221345Sdim		OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
2496221345Sdim	FWOHCI_DMA_WRITE(db[2].db.desc.addr,
2497226633Sdim	fwdma_bus_addr(it->buf, poffset) + sizeof(u_int32_t));
2498193326Sed
2499193326Sed	FWOHCI_DMA_WRITE(db[2].db.desc.cmd,
2500221345Sdim		OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS);
2501221345Sdim#if 1
2502221345Sdim	FWOHCI_DMA_WRITE(db[0].db.desc.res, 0);
2503193326Sed	FWOHCI_DMA_WRITE(db[2].db.desc.res, 0);
2504221345Sdim#endif
2505193326Sed	return 0;
2506198092Srdivacky}
2507193326Sed
2508193326Sedint
2509198092Srdivackyfwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
2510193326Sed		int poffset, struct fwdma_alloc *dummy_dma)
2511193326Sed{
2512193326Sed	volatile struct fwohcidb *db = db_tr->db;
2513193326Sed	struct fw_xferq *ir;
2514193326Sed	int i, ldesc;
2515193326Sed	bus_addr_t dbuf[2];
2516193326Sed	int dsiz[2];
2517193326Sed
2518198092Srdivacky	ir = &dbch->xferq;
2519193326Sed	if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) {
2520193326Sed		db_tr->buf = fwdma_malloc_size(dbch->dmat, &db_tr->dma_map,
2521193326Sed			ir->psize, &dbuf[0], BUS_DMA_NOWAIT);
2522193326Sed		if (db_tr->buf == NULL)
2523224145Sdim			return(ENOMEM);
2524223017Sdim		db_tr->dbcnt = 1;
2525224145Sdim		dsiz[0] = ir->psize;
2526193326Sed		bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
2527221345Sdim			BUS_DMASYNC_PREREAD);
2528221345Sdim	} else {
2529193326Sed		db_tr->dbcnt = 0;
2530243830Sdim		if (dummy_dma != NULL) {
2531221345Sdim			dsiz[db_tr->dbcnt] = sizeof(u_int32_t);
2532221345Sdim			dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr;
2533221345Sdim		}
2534221345Sdim		dsiz[db_tr->dbcnt] = ir->psize;
2535221345Sdim		if (ir->buf != NULL) {
2536221345Sdim			db_tr->buf = fwdma_v_addr(ir->buf, poffset);
2537221345Sdim			dbuf[db_tr->dbcnt] = fwdma_bus_addr( ir->buf, poffset);
2538221345Sdim		}
2539221345Sdim		db_tr->dbcnt++;
2540221345Sdim	}
2541221345Sdim	for(i = 0 ; i < db_tr->dbcnt ; i++){
2542223017Sdim		FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]);
2543221345Sdim		FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]);
2544224145Sdim		if (ir->flag & FWXFERQ_STREAM) {
2545234353Sdim			FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE);
2546224145Sdim		}
2547223017Sdim		FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]);
2548223017Sdim	}
2549224145Sdim	ldesc = db_tr->dbcnt - 1;
2550234353Sdim	if (ir->flag & FWXFERQ_STREAM) {
2551224145Sdim		FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST);
2552224145Sdim	}
2553224145Sdim	FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS);
2554224145Sdim	return 0;
2555224145Sdim}
2556224145Sdim
2557224145Sdim
2558224145Sdimstatic int
2559223017Sdimfwohci_arcv_swap(struct fw_pkt *fp, int len)
2560193326Sed{
2561193326Sed	struct fw_pkt *fp0;
2562193326Sed	u_int32_t ld0;
2563193326Sed	int slen;
2564193326Sed#if BYTE_ORDER == BIG_ENDIAN
2565198092Srdivacky	int i;
2566193326Sed#endif
2567193326Sed
2568198092Srdivacky	ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]);
2569198092Srdivacky#if 0
2570198092Srdivacky	printf("ld0: x%08x\n", ld0);
2571193326Sed#endif
2572193326Sed	fp0 = (struct fw_pkt *)&ld0;
2573223017Sdim	switch (fp0->mode.common.tcode) {
2574226633Sdim	case FWTCODE_RREQQ:
2575226633Sdim	case FWTCODE_WRES:
2576223017Sdim	case FWTCODE_WREQQ:
2577193326Sed	case FWTCODE_RRESQ:
2578234353Sdim	case FWOHCITCODE_PHY:
2579234353Sdim		slen = 12;
2580234353Sdim		break;
2581234353Sdim	case FWTCODE_RREQB:
2582234353Sdim	case FWTCODE_WREQB:
2583234353Sdim	case FWTCODE_LREQ:
2584234353Sdim	case FWTCODE_RRESB:
2585234353Sdim	case FWTCODE_LRES:
2586234353Sdim		slen = 16;
2587234353Sdim		break;
2588234353Sdim	default:
2589234353Sdim		printf("Unknown tcode %d\n", fp0->mode.common.tcode);
2590234353Sdim		return(0);
2591234353Sdim	}
2592234353Sdim	if (slen > len) {
2593234353Sdim		if (firewire_debug)
2594234353Sdim			printf("splitted header\n");
2595234353Sdim		return(-slen);
2596234353Sdim	}
2597234353Sdim#if BYTE_ORDER == BIG_ENDIAN
2598234353Sdim	for(i = 0; i < slen/4; i ++)
2599234353Sdim		fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
2600234353Sdim#endif
2601234353Sdim	return(slen);
2602234353Sdim}
2603234353Sdim
2604234353Sdim#define PLEN(x)	roundup2(x, sizeof(u_int32_t))
2605234353Sdimstatic int
2606234353Sdimfwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp)
2607234353Sdim{
2608234353Sdim	int r;
2609234353Sdim
2610234353Sdim	switch(fp->mode.common.tcode){
2611234353Sdim	case FWTCODE_RREQQ:
2612234353Sdim		r = sizeof(fp->mode.rreqq) + sizeof(u_int32_t);
2613234353Sdim		break;
2614234353Sdim	case FWTCODE_WRES:
2615234353Sdim		r = sizeof(fp->mode.wres) + sizeof(u_int32_t);
2616234353Sdim		break;
2617234353Sdim	case FWTCODE_WREQQ:
2618193326Sed		r = sizeof(fp->mode.wreqq) + sizeof(u_int32_t);
2619193326Sed		break;
2620193326Sed	case FWTCODE_RREQB:
2621193326Sed		r = sizeof(fp->mode.rreqb) + sizeof(u_int32_t);
2622193326Sed		break;
2623193326Sed	case FWTCODE_RRESQ:
2624198092Srdivacky		r = sizeof(fp->mode.rresq) + sizeof(u_int32_t);
2625198092Srdivacky		break;
2626193326Sed	case FWTCODE_WREQB:
2627226633Sdim		r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.wreqb.len)
2628226633Sdim						+ sizeof(u_int32_t);
2629221345Sdim		break;
2630193326Sed	case FWTCODE_LREQ:
2631193326Sed		r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lreq.len)
2632193326Sed						+ sizeof(u_int32_t);
2633226633Sdim		break;
2634234353Sdim	case FWTCODE_RRESB:
2635193326Sed		r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.rresb.len)
2636193326Sed						+ sizeof(u_int32_t);
2637193326Sed		break;
2638198092Srdivacky	case FWTCODE_LRES:
2639198092Srdivacky		r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lres.len)
2640198092Srdivacky						+ sizeof(u_int32_t);
2641198092Srdivacky		break;
2642198092Srdivacky	case FWOHCITCODE_PHY:
2643193326Sed		r = 16;
2644193326Sed		break;
2645193326Sed	default:
2646223017Sdim		device_printf(sc->fc.dev, "Unknown tcode %d\n",
2647221345Sdim						fp->mode.common.tcode);
2648193326Sed		r = 0;
2649193326Sed	}
2650223017Sdim	if (r > dbch->xferq.psize) {
2651221345Sdim		device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
2652193326Sed		/* panic ? */
2653193326Sed	}
2654234353Sdim	return r;
2655234353Sdim}
2656234353Sdim
2657234353Sdimstatic void
2658234353Sdimfwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
2659223017Sdim{
2660221345Sdim	volatile struct fwohcidb *db = &db_tr->db[0];
2661207619Srdivacky
2662223017Sdim	FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
2663221345Sdim	FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
2664218893Sdim	FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
2665249423Sdim	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
2666234353Sdim	dbch->bottom = db_tr;
2667234353Sdim}
2668249423Sdim
2669249423Sdimstatic void
2670249423Sdimfwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
2671207619Srdivacky{
2672198092Srdivacky	struct fwohcidb_tr *db_tr;
2673221345Sdim	struct iovec vec[2];
2674193326Sed	struct fw_pkt pktbuf;
2675193326Sed	int nvec;
2676221345Sdim	struct fw_pkt *fp;
2677210299Sed	u_int8_t *ld;
2678221345Sdim	u_int32_t stat, off, status;
2679210299Sed	u_int spd;
2680193326Sed	int len, plen, hlen, pcnt, offset;
2681193326Sed	int s;
2682221345Sdim	caddr_t buf;
2683210299Sed	int resCount;
2684210299Sed
2685210299Sed	if(&sc->arrq == dbch){
2686210299Sed		off = OHCI_ARQOFF;
2687243830Sdim	}else if(&sc->arrs == dbch){
2688210299Sed		off = OHCI_ARSOFF;
2689210299Sed	}else{
2690210299Sed		return;
2691210299Sed	}
2692221345Sdim
2693221345Sdim	s = splfw();
2694221345Sdim	db_tr = dbch->top;
2695221345Sdim	pcnt = 0;
2696221345Sdim	/* XXX we cannot handle a packet which lies in more than two buf */
2697193326Sed	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD);
2698193326Sed	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
2699221345Sdim	status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
2700249423Sdim	resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
2701249423Sdim#if 0
2702193326Sed	printf("status 0x%04x, resCount 0x%04x\n", status, resCount);
2703193326Sed#endif
2704193326Sed	while (status & OHCI_CNTL_DMA_ACTIVE) {
2705226633Sdim		len = dbch->xferq.psize - resCount;
2706193326Sed		ld = (u_int8_t *)db_tr->buf;
2707193326Sed		if (dbch->pdb_tr == NULL) {
2708198092Srdivacky			len -= dbch->buf_offset;
2709193326Sed			ld += dbch->buf_offset;
2710193326Sed		}
2711193326Sed		if (len > 0)
2712226633Sdim			bus_dmamap_sync(dbch->dmat, db_tr->dma_map,
2713243830Sdim					BUS_DMASYNC_POSTREAD);
2714249423Sdim		while (len > 0 ) {
2715243830Sdim			if (count >= 0 && count-- == 0)
2716239462Sdim				goto out;
2717249423Sdim			if(dbch->pdb_tr != NULL){
2718249423Sdim				/* we have a fragment in previous buffer */
2719193326Sed				int rlen;
2720193326Sed
2721221345Sdim				offset = dbch->buf_offset;
2722198092Srdivacky				if (offset < 0)
2723249423Sdim					offset = - offset;
2724223017Sdim				buf = dbch->pdb_tr->buf + offset;
2725203955Srdivacky				rlen = dbch->xferq.psize - offset;
2726193326Sed				if (firewire_debug)
2727193326Sed					printf("rlen=%d, offset=%d\n",
2728221345Sdim						rlen, dbch->buf_offset);
2729198092Srdivacky				if (dbch->buf_offset < 0) {
2730249423Sdim					/* splitted in header, pull up */
2731203955Srdivacky					char *p;
2732203955Srdivacky
2733203955Srdivacky					p = (char *)&pktbuf;
2734193326Sed					bcopy(buf, p, rlen);
2735193326Sed					p += rlen;
2736221345Sdim					/* this must be too long but harmless */
2737212904Sdim					rlen = sizeof(pktbuf) - rlen;
2738212904Sdim					if (rlen < 0)
2739249423Sdim						printf("why rlen < 0\n");
2740203955Srdivacky					bcopy(db_tr->buf, p, rlen);
2741203955Srdivacky					ld += rlen;
2742212904Sdim					len -= rlen;
2743212904Sdim					hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
2744212904Sdim					if (hlen < 0) {
2745212904Sdim						printf("hlen < 0 shouldn't happen");
2746226633Sdim					}
2747193326Sed					offset = sizeof(pktbuf);
2748193326Sed					vec[0].iov_base = (char *)&pktbuf;
2749221345Sdim					vec[0].iov_len = offset;
2750198092Srdivacky				} else {
2751198092Srdivacky					/* splitted in payload */
2752249423Sdim					offset = rlen;
2753203955Srdivacky					vec[0].iov_base = buf;
2754223017Sdim					vec[0].iov_len = rlen;
2755203955Srdivacky				}
2756193326Sed				fp=(struct fw_pkt *)vec[0].iov_base;
2757193326Sed				nvec = 1;
2758221345Sdim			} else {
2759198092Srdivacky				/* no fragment in previous buffer */
2760249423Sdim				fp=(struct fw_pkt *)ld;
2761203955Srdivacky				hlen = fwohci_arcv_swap(fp, len);
2762203955Srdivacky				if (hlen == 0)
2763203955Srdivacky					/* XXX need reset */
2764193326Sed					goto out;
2765193326Sed				if (hlen < 0) {
2766221345Sdim					dbch->pdb_tr = db_tr;
2767198092Srdivacky					dbch->buf_offset = - dbch->buf_offset;
2768198092Srdivacky					/* sanity check */
2769210299Sed					if (resCount != 0)
2770249423Sdim						printf("resCount != 0 !?\n");
2771223017Sdim					goto out;
2772223017Sdim				}
2773203955Srdivacky				offset = 0;
2774210299Sed				nvec = 0;
2775198092Srdivacky			}
2776198092Srdivacky			plen = fwohci_get_plen(sc, dbch, fp) - offset;
2777193326Sed			if (plen < 0) {
2778193326Sed				/* minimum header size + trailer
2779193326Sed				= sizeof(fw_pkt) so this shouldn't happens */
2780193326Sed				printf("plen is negative! offset=%d\n", offset);
2781193326Sed				goto out;
2782193326Sed			}
2783193326Sed			if (plen > 0) {
2784193326Sed				len -= plen;
2785198092Srdivacky				if (len < 0) {
2786198092Srdivacky					dbch->pdb_tr = db_tr;
2787218893Sdim					if (firewire_debug)
2788218893Sdim						printf("splitted payload\n");
2789218893Sdim					/* sanity check */
2790218893Sdim					if (resCount != 0)
2791218893Sdim						printf("resCount != 0 !?\n");
2792218893Sdim					goto out;
2793218893Sdim				}
2794218893Sdim				vec[nvec].iov_base = ld;
2795218893Sdim				vec[nvec].iov_len = plen;
2796218893Sdim				nvec ++;
2797218893Sdim				ld += plen;
2798207619Srdivacky			}
2799207619Srdivacky			dbch->buf_offset = ld - (u_int8_t *)db_tr->buf;
2800207619Srdivacky			if (nvec == 0)
2801226633Sdim				printf("nvec == 0\n");
2802226633Sdim
2803198092Srdivacky/* DMA result-code will be written at the tail of packet */
2804198092Srdivacky#if BYTE_ORDER == BIG_ENDIAN
2805198092Srdivacky			stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16;
2806198092Srdivacky#else
2807234353Sdim			stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
2808198092Srdivacky#endif
2809226633Sdim#if 0
2810198092Srdivacky			printf("plen: %d, stat %x\n", plen ,stat);
2811198092Srdivacky#endif
2812198092Srdivacky			spd = (stat >> 5) & 0x3;
2813198092Srdivacky			stat &= 0x1f;
2814198092Srdivacky			switch(stat){
2815198092Srdivacky			case FWOHCIEV_ACKPEND:
2816198092Srdivacky#if 0
2817198092Srdivacky				printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
2818198092Srdivacky#endif
2819193326Sed				/* fall through */
2820198092Srdivacky			case FWOHCIEV_ACKCOMPL:
2821193326Sed				if ((vec[nvec-1].iov_len -=
2822193326Sed					sizeof(struct fwohci_trailer)) == 0)
2823221345Sdim					nvec--;
2824193326Sed				fw_rcv(&sc->fc, vec, nvec, 0, spd);
2825193326Sed					break;
2826193326Sed			case FWOHCIEV_BUSRST:
2827193326Sed				if (sc->fc.status != FWBUSRESET)
2828208600Srdivacky					printf("got BUSRST packet!?\n");
2829208600Srdivacky				break;
2830193326Sed			default:
2831193326Sed				device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]);
2832193326Sed#if 0 /* XXX */
2833198092Srdivacky				goto out;
2834193326Sed#endif
2835193326Sed				break;
2836193326Sed			}
2837226633Sdim			pcnt ++;
2838226633Sdim			if (dbch->pdb_tr != NULL) {
2839226633Sdim				fwohci_arcv_free_buf(dbch, dbch->pdb_tr);
2840193326Sed				dbch->pdb_tr = NULL;
2841193326Sed			}
2842198092Srdivacky
2843193326Sed		}
2844193326Sedout:
2845193326Sed		if (resCount == 0) {
2846198092Srdivacky			/* done on this buffer */
2847193326Sed			if (dbch->pdb_tr == NULL) {
2848193326Sed				fwohci_arcv_free_buf(dbch, db_tr);
2849193326Sed				dbch->buf_offset = 0;
2850221345Sdim			} else
2851193326Sed				if (dbch->pdb_tr != db_tr)
2852193326Sed					printf("pdb_tr != db_tr\n");
2853239462Sdim			db_tr = STAILQ_NEXT(db_tr, link);
2854193326Sed			status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2855224145Sdim						>> OHCI_STATUS_SHIFT;
2856224145Sdim			resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
2857224145Sdim						& OHCI_COUNT_MASK;
2858224145Sdim			/* XXX check buffer overrun */
2859224145Sdim			dbch->top = db_tr;
2860224145Sdim		} else {
2861224145Sdim			dbch->buf_offset = dbch->xferq.psize - resCount;
2862224145Sdim			break;
2863224145Sdim		}
2864224145Sdim		/* XXX make sure DMA is not dead */
2865226633Sdim	}
2866226633Sdim#if 0
2867234353Sdim	if (pcnt < 1)
2868234353Sdim		printf("fwohci_arcv: no packets\n");
2869234353Sdim#endif
2870234353Sdim	splx(s);
2871193326Sed}
2872193326Sed