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