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
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#define BOUNCE_BUFFER_TEST	0
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/module.h>
44#include <sys/bus.h>
45#include <sys/queue.h>
46#include <machine/bus.h>
47#include <sys/rman.h>
48#include <sys/malloc.h>
49#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
50#include <sys/lock.h>
51#include <sys/mutex.h>
52#endif
53#include <machine/resource.h>
54
55#if defined(__DragonFly__) || __FreeBSD_version < 500000
56#include <machine/clock.h>		/* for DELAY() */
57#endif
58
59#ifdef __DragonFly__
60#include <bus/pci/pcivar.h>
61#include <bus/pci/pcireg.h>
62
63#include "firewire.h"
64#include "firewirereg.h"
65
66#include "fwdma.h"
67#include "fwohcireg.h"
68#include "fwohcivar.h"
69#else
70#if __FreeBSD_version < 500000
71#include <pci/pcivar.h>
72#include <pci/pcireg.h>
73#else
74#include <dev/pci/pcivar.h>
75#include <dev/pci/pcireg.h>
76#endif
77
78#include <dev/firewire/firewire.h>
79#include <dev/firewire/firewirereg.h>
80
81#include <dev/firewire/fwdma.h>
82#include <dev/firewire/fwohcireg.h>
83#include <dev/firewire/fwohcivar.h>
84#endif
85
86static int fwohci_pci_attach(device_t self);
87static int fwohci_pci_detach(device_t self);
88
89/*
90 * The probe routine.
91 */
92static int
93fwohci_pci_probe( device_t dev )
94{
95#if 1
96	uint32_t id;
97
98	id = pci_get_devid(dev);
99	if (id == (FW_VENDORID_NATSEMI | FW_DEVICE_CS4210)) {
100		device_set_desc(dev, "National Semiconductor CS4210");
101		return BUS_PROBE_DEFAULT;
102	}
103	if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD861)) {
104		device_set_desc(dev, "NEC uPD72861");
105		return BUS_PROBE_DEFAULT;
106	}
107	if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD871)) {
108		device_set_desc(dev, "NEC uPD72871/2");
109		return BUS_PROBE_DEFAULT;
110	}
111	if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD72870)) {
112		device_set_desc(dev, "NEC uPD72870");
113		return BUS_PROBE_DEFAULT;
114	}
115	if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD72873)) {
116		device_set_desc(dev, "NEC uPD72873");
117		return BUS_PROBE_DEFAULT;
118	}
119	if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD72874)) {
120		device_set_desc(dev, "NEC uPD72874");
121		return BUS_PROBE_DEFAULT;
122	}
123	if (id == (FW_VENDORID_SIS | FW_DEVICE_7007)) {
124		/* It has no real identifier, using device id. */
125		device_set_desc(dev, "SiS 7007");
126		return BUS_PROBE_DEFAULT;
127	}
128	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB22)) {
129		device_set_desc(dev, "Texas Instruments TSB12LV22");
130		return BUS_PROBE_DEFAULT;
131	}
132	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB23)) {
133		device_set_desc(dev, "Texas Instruments TSB12LV23");
134		return BUS_PROBE_DEFAULT;
135	}
136	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB26)) {
137		device_set_desc(dev, "Texas Instruments TSB12LV26");
138		return BUS_PROBE_DEFAULT;
139	}
140	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43)) {
141		device_set_desc(dev, "Texas Instruments TSB43AA22");
142		return BUS_PROBE_DEFAULT;
143	}
144	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43A)) {
145		device_set_desc(dev, "Texas Instruments TSB43AB22/A");
146		return BUS_PROBE_DEFAULT;
147	}
148	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43AB21)) {
149		device_set_desc(dev, "Texas Instruments TSB43AB21/A/AI/A-EP");
150		return BUS_PROBE_DEFAULT;
151	}
152	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43AB23)) {
153		device_set_desc(dev, "Texas Instruments TSB43AB23");
154		return BUS_PROBE_DEFAULT;
155	}
156	if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB82AA2)) {
157		device_set_desc(dev, "Texas Instruments TSB82AA2");
158		return BUS_PROBE_DEFAULT;
159	}
160	if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4450)) {
161		device_set_desc(dev, "Texas Instruments PCI4450");
162		return BUS_PROBE_DEFAULT;
163	}
164	if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4410A)) {
165		device_set_desc(dev, "Texas Instruments PCI4410A");
166		return BUS_PROBE_DEFAULT;
167	}
168	if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4451)) {
169		device_set_desc(dev, "Texas Instruments PCI4451");
170		return BUS_PROBE_DEFAULT;
171	}
172	if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD1947)) {
173		device_printf(dev, "Sony i.LINK (CXD1947) not supported\n");
174		return ENXIO;
175	}
176	if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD3222)) {
177		device_set_desc(dev, "Sony i.LINK (CXD3222)");
178		return BUS_PROBE_DEFAULT;
179	}
180	if (id == (FW_VENDORID_VIA | FW_DEVICE_VT6306)) {
181		device_set_desc(dev, "VIA Fire II (VT6306)");
182		return BUS_PROBE_DEFAULT;
183	}
184	if (id == (FW_VENDORID_RICOH | FW_DEVICE_R5C551)) {
185		device_set_desc(dev, "Ricoh R5C551");
186		return BUS_PROBE_DEFAULT;
187	}
188	if (id == (FW_VENDORID_RICOH | FW_DEVICE_R5C552)) {
189		device_set_desc(dev, "Ricoh R5C552");
190		return BUS_PROBE_DEFAULT;
191	}
192	if (id == (FW_VENDORID_APPLE | FW_DEVICE_PANGEA)) {
193		device_set_desc(dev, "Apple Pangea");
194		return BUS_PROBE_DEFAULT;
195	}
196	if (id == (FW_VENDORID_APPLE | FW_DEVICE_UNINORTH)) {
197		device_set_desc(dev, "Apple UniNorth");
198		return BUS_PROBE_DEFAULT;
199	}
200	if (id == (FW_VENDORID_LUCENT | FW_DEVICE_FW322)) {
201		device_set_desc(dev, "Lucent FW322/323");
202		return BUS_PROBE_DEFAULT;
203	}
204	if (id == (FW_VENDORID_INTEL | FW_DEVICE_82372FB)) {
205		device_set_desc(dev, "Intel 82372FB");
206		return BUS_PROBE_DEFAULT;
207	}
208	if (id == (FW_VENDORID_ADAPTEC | FW_DEVICE_AIC5800)) {
209		device_set_desc(dev, "Adaptec AHA-894x/AIC-5800");
210		return BUS_PROBE_DEFAULT;
211	}
212	if (id == (FW_VENDORID_SUN | FW_DEVICE_PCIO2FW)) {
213		device_set_desc(dev, "Sun PCIO-2");
214		return BUS_PROBE_DEFAULT;
215	}
216#endif
217	if (pci_get_class(dev) == PCIC_SERIALBUS
218			&& pci_get_subclass(dev) == PCIS_SERIALBUS_FW
219			&& pci_get_progif(dev) == PCI_INTERFACE_OHCI) {
220		if (bootverbose)
221			device_printf(dev, "vendor=%x, dev=%x\n",
222			    pci_get_vendor(dev), pci_get_device(dev));
223		device_set_desc(dev, "1394 Open Host Controller Interface");
224		return BUS_PROBE_DEFAULT;
225	}
226
227	return ENXIO;
228}
229
230#if defined(__DragonFly__) || __FreeBSD_version < 500000
231static void
232fwohci_dummy_intr(void *arg)
233{
234	/* XXX do nothing */
235}
236#endif
237
238static int
239fwohci_pci_init(device_t self)
240{
241	int olatency, latency, ocache_line, cache_line;
242	uint16_t cmd;
243
244	cmd = pci_read_config(self, PCIR_COMMAND, 2);
245	cmd |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN;
246#if 1  /* for broken hardware */
247	cmd &= ~PCIM_CMD_MWRICEN;
248#endif
249	pci_write_config(self, PCIR_COMMAND, cmd, 2);
250
251	/*
252	 * Some Sun PCIO-2 FireWire controllers have their intpin register
253	 * bogusly set to 0, although it should be 3. Correct that.
254	 */
255	if (pci_get_devid(self) == (FW_VENDORID_SUN | FW_DEVICE_PCIO2FW) &&
256	    pci_get_intpin(self) == 0)
257		pci_set_intpin(self, 3);
258
259	latency = olatency = pci_read_config(self, PCIR_LATTIMER, 1);
260#define DEF_LATENCY 0x20
261	if (olatency < DEF_LATENCY) {
262		latency = DEF_LATENCY;
263		pci_write_config(self, PCIR_LATTIMER, latency, 1);
264	}
265
266	cache_line = ocache_line = pci_read_config(self, PCIR_CACHELNSZ, 1);
267#define DEF_CACHE_LINE 8
268	if (ocache_line < DEF_CACHE_LINE) {
269		cache_line = DEF_CACHE_LINE;
270		pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1);
271	}
272
273	if (firewire_debug) {
274		device_printf(self, "latency timer %d -> %d.\n",
275			olatency, latency);
276		device_printf(self, "cache size %d -> %d.\n",
277			ocache_line, cache_line);
278	}
279
280	return 0;
281}
282
283static int
284fwohci_pci_attach(device_t self)
285{
286	fwohci_softc_t *sc = device_get_softc(self);
287	int err;
288	int rid;
289#if defined(__DragonFly__) || __FreeBSD_version < 500000
290	int intr;
291	/* For the moment, put in a message stating what is wrong */
292	intr = pci_read_config(self, PCIR_INTLINE, 1);
293	if (intr == 0 || intr == 255) {
294		device_printf(self, "Invalid irq %d\n", intr);
295#ifdef __i386__
296		device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n");
297#endif
298	}
299#endif
300
301#if 0
302	if (bootverbose)
303		firewire_debug = bootverbose;
304#endif
305
306	mtx_init(FW_GMTX(&sc->fc), "firewire", NULL, MTX_DEF);
307	fwohci_pci_init(self);
308
309	rid = PCI_CBMEM;
310#if __FreeBSD_version >= 502109
311	sc->bsr = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
312#else
313	sc->bsr = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
314	    0, ~0, 1, RF_ACTIVE);
315#endif
316	if (!sc->bsr) {
317		device_printf(self, "Could not map memory\n");
318		return ENXIO;
319        }
320
321	sc->bst = rman_get_bustag(sc->bsr);
322	sc->bsh = rman_get_bushandle(sc->bsr);
323
324	rid = 0;
325#if __FreeBSD_version >= 502109
326	sc->irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
327				     RF_SHAREABLE | RF_ACTIVE);
328#else
329	sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0, 1,
330				     RF_SHAREABLE | RF_ACTIVE);
331#endif
332	if (sc->irq_res == NULL) {
333		device_printf(self, "Could not allocate irq\n");
334		fwohci_pci_detach(self);
335		return ENXIO;
336	}
337
338	err = bus_setup_intr(self, sc->irq_res,
339				INTR_TYPE_NET | INTR_MPSAFE,
340				NULL, (driver_intr_t *) fwohci_intr,
341				sc, &sc->ih);
342
343#if defined(__DragonFly__) || __FreeBSD_version < 500000
344	/* XXX splcam() should mask this irq for sbp.c*/
345	err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM,
346		     (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_cam);
347	/* XXX splbio() should mask this irq for physio()/fwmem_strategy() */
348	err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
349		     (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_bio);
350#endif
351	if (err) {
352		device_printf(self, "Could not setup irq, %d\n", err);
353		fwohci_pci_detach(self);
354		return ENXIO;
355	}
356
357	err = bus_dma_tag_create(
358#if defined(__FreeBSD__) && __FreeBSD_version >= 700020
359				/*parent*/bus_get_dma_tag(self),
360#else
361				/*parent*/NULL,
362#endif
363				/*alignment*/1,
364				/*boundary*/0,
365#if BOUNCE_BUFFER_TEST
366				/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
367#else
368				/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
369#endif
370				/*highaddr*/BUS_SPACE_MAXADDR,
371				/*filter*/NULL, /*filterarg*/NULL,
372				/*maxsize*/0x100000,
373				/*nsegments*/0x20,
374				/*maxsegsz*/0x8000,
375				/*flags*/BUS_DMA_ALLOCNOW,
376#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
377				/*lockfunc*/busdma_lock_mutex,
378				/*lockarg*/FW_GMTX(&sc->fc),
379#endif
380				&sc->fc.dmat);
381	if (err != 0) {
382		printf("fwohci_pci_attach: Could not allocate DMA tag "
383			"- error %d\n", err);
384			return (ENOMEM);
385	}
386
387	err = fwohci_init(sc, self);
388
389	if (err) {
390		device_printf(self, "fwohci_init failed with err=%d\n", err);
391		fwohci_pci_detach(self);
392		return EIO;
393	}
394
395	/* probe and attach a child device(firewire) */
396	bus_generic_probe(self);
397	bus_generic_attach(self);
398
399	return 0;
400}
401
402static int
403fwohci_pci_detach(device_t self)
404{
405	fwohci_softc_t *sc = device_get_softc(self);
406	int s;
407
408
409	s = splfw();
410
411	if (sc->bsr)
412		fwohci_stop(sc, self);
413
414	bus_generic_detach(self);
415	if (sc->fc.bdev) {
416		device_delete_child(self, sc->fc.bdev);
417		sc->fc.bdev = NULL;
418	}
419
420	/* disable interrupts that might have been switched on */
421	if (sc->bst && sc->bsh)
422		bus_space_write_4(sc->bst, sc->bsh,
423				  FWOHCI_INTMASKCLR, OHCI_INT_EN);
424
425	if (sc->irq_res) {
426		int err;
427		if (sc->ih) {
428			err = bus_teardown_intr(self, sc->irq_res, sc->ih);
429			if (err)
430				device_printf(self,
431					 "Could not tear down irq, %d\n", err);
432#if defined(__DragonFly__) || __FreeBSD_version < 500000
433			bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
434			bus_teardown_intr(self, sc->irq_res, sc->ih_bio);
435#endif
436			sc->ih = NULL;
437		}
438		bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
439		sc->irq_res = NULL;
440	}
441
442	if (sc->bsr) {
443		bus_release_resource(self, SYS_RES_MEMORY,PCI_CBMEM,sc->bsr);
444		sc->bsr = NULL;
445		sc->bst = 0;
446		sc->bsh = 0;
447	}
448
449	fwohci_detach(sc, self);
450	mtx_destroy(FW_GMTX(&sc->fc));
451	splx(s);
452
453	return 0;
454}
455
456static int
457fwohci_pci_suspend(device_t dev)
458{
459	fwohci_softc_t *sc = device_get_softc(dev);
460	int err;
461
462	device_printf(dev, "fwohci_pci_suspend\n");
463	err = bus_generic_suspend(dev);
464	if (err)
465		return err;
466	fwohci_stop(sc, dev);
467	return 0;
468}
469
470static int
471fwohci_pci_resume(device_t dev)
472{
473	fwohci_softc_t *sc = device_get_softc(dev);
474
475	fwohci_pci_init(dev);
476	fwohci_resume(sc, dev);
477	return 0;
478}
479
480static int
481fwohci_pci_shutdown(device_t dev)
482{
483	fwohci_softc_t *sc = device_get_softc(dev);
484
485	bus_generic_shutdown(dev);
486	fwohci_stop(sc, dev);
487	return 0;
488}
489
490static device_t
491fwohci_pci_add_child(device_t dev, u_int order, const char *name, int unit)
492{
493	struct fwohci_softc *sc;
494	device_t child;
495	int err = 0;
496
497	sc = (struct fwohci_softc *)device_get_softc(dev);
498	child = device_add_child(dev, name, unit);
499	if (child == NULL)
500		return (child);
501
502	sc->fc.bdev = child;
503	device_set_ivars(child, (void *)&sc->fc);
504
505	err = device_probe_and_attach(child);
506	if (err) {
507		device_printf(dev, "probe_and_attach failed with err=%d\n",
508		    err);
509		fwohci_pci_detach(dev);
510		device_delete_child(dev, child);
511		return NULL;
512	}
513
514	/* XXX
515	 * Clear the bus reset event flag to start transactions even when
516	 * interrupt is disabled during the boot process.
517	 */
518	if (cold) {
519		int s;
520		DELAY(250); /* 2 cycles */
521		s = splfw();
522		fwohci_poll((void *)sc, 0, -1);
523		splx(s);
524	}
525
526	return (child);
527}
528
529static device_method_t fwohci_methods[] = {
530	/* Device interface */
531	DEVMETHOD(device_probe,		fwohci_pci_probe),
532	DEVMETHOD(device_attach,	fwohci_pci_attach),
533	DEVMETHOD(device_detach,	fwohci_pci_detach),
534	DEVMETHOD(device_suspend,	fwohci_pci_suspend),
535	DEVMETHOD(device_resume,	fwohci_pci_resume),
536	DEVMETHOD(device_shutdown,	fwohci_pci_shutdown),
537
538	/* Bus interface */
539	DEVMETHOD(bus_add_child,	fwohci_pci_add_child),
540
541	DEVMETHOD_END
542};
543
544static driver_t fwohci_driver = {
545	"fwohci",
546	fwohci_methods,
547	sizeof(fwohci_softc_t),
548};
549
550static devclass_t fwohci_devclass;
551
552#ifdef FWOHCI_MODULE
553MODULE_DEPEND(fwohci, firewire, 1, 1, 1);
554#endif
555DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0);
556