pci_machdep.c revision 1.28
1/*	$NetBSD: pci_machdep.c,v 1.28 2002/05/15 17:40:11 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 1999, 2000 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * functions expected by the MI PCI code.
33 */
34
35#ifdef DEBUG
36#define SPDB_CONF	0x01
37#define SPDB_INTR	0x04
38#define SPDB_INTMAP	0x08
39#define SPDB_INTFIX	0x10
40#define SPDB_PROBE	0x20
41int sparc_pci_debug = 0x0;
42#define DPRINTF(l, s)	do { if (sparc_pci_debug & l) printf s; } while (0)
43#else
44#define DPRINTF(l, s)
45#endif
46
47#include <sys/types.h>
48#include <sys/param.h>
49#include <sys/time.h>
50#include <sys/systm.h>
51#include <sys/errno.h>
52#include <sys/device.h>
53#include <sys/malloc.h>
54
55#define _SPARC_BUS_DMA_PRIVATE
56#include <machine/bus.h>
57#include <machine/autoconf.h>
58#include <machine/openfirm.h>
59
60#include <dev/pci/pcivar.h>
61#include <dev/pci/pcireg.h>
62
63#include <dev/ofw/ofw_pci.h>
64
65#include <sparc64/dev/ofpcivar.h>
66
67#include <sparc64/dev/iommureg.h>
68#include <sparc64/dev/iommuvar.h>
69#include <sparc64/dev/psychoreg.h>
70#include <sparc64/dev/psychovar.h>
71
72/* this is a base to be copied */
73struct sparc_pci_chipset _sparc_pci_chipset = {
74	NULL,
75};
76
77/*
78 * functions provided to the MI code.
79 */
80
81void
82pci_attach_hook(parent, self, pba)
83	struct device *parent;
84	struct device *self;
85	struct pcibus_attach_args *pba;
86{
87	/* Don't do nothing */
88}
89
90int
91pci_bus_maxdevs(pc, busno)
92	pci_chipset_tag_t pc;
93	int busno;
94{
95
96	return 32;
97}
98
99#ifdef __PCI_BUS_DEVORDER
100int
101pci_bus_devorder(pc, busno, devs)
102	pci_chipset_tag_t pc;
103	int busno;
104	char *devs;
105{
106	struct ofw_pci_register reg;
107	int node, len, device, i = 0;
108	u_int32_t done = 0;
109#ifdef DEBUG
110	char name[80];
111#endif
112
113	node = pc->curnode;
114#ifdef DEBUG
115	if (sparc_pci_debug & SPDB_PROBE) {
116		OF_getprop(node, "name", &name, sizeof(name));
117		printf("pci_bus_devorder: curnode %x %s\n", node, name);
118	}
119#endif
120	/*
121	 * Initially, curnode is the root of the pci tree.  As we
122	 * attach bridges, curnode should be set to that of the bridge.
123	 */
124	for (node = OF_child(node); node; node = OF_peer(node)) {
125		len = OF_getproplen(node, "reg");
126		if (len < sizeof(reg))
127			continue;
128		if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
129			panic("pci_probe_bus: OF_getprop len botch");
130
131		device = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
132
133		if (done & (1 << device))
134			continue;
135
136		devs[i++] = device;
137		done |= 1 << device;
138#ifdef DEBUG
139	if (sparc_pci_debug & SPDB_PROBE) {
140		OF_getprop(node, "name", &name, sizeof(name));
141		printf("pci_bus_devorder: adding %x %s\n", node, name);
142	}
143#endif
144		if (i == 32)
145			break;
146	}
147	if (i < 32)
148		devs[i] = -1;
149
150	return i;
151}
152#endif
153
154#ifdef __PCI_DEV_FUNCORDER
155int
156pci_dev_funcorder(pc, busno, device, funcs)
157	pci_chipset_tag_t pc;
158	int busno;
159	int device;
160	char *funcs;
161{
162	struct ofw_pci_register reg;
163	int node, len, i = 0;
164#ifdef DEBUG
165	char name[80];
166#endif
167
168	node = pc->curnode;
169#ifdef DEBUG
170	if (sparc_pci_debug & SPDB_PROBE) {
171		OF_getprop(node, "name", &name, sizeof(name));
172		printf("pci_bus_funcorder: curnode %x %s\n", node, name);
173	}
174#endif
175	/*
176	 * Initially, curnode is the root of the pci tree.  As we
177	 * attach bridges, curnode should be set to that of the bridge.
178	 *
179	 * Note this search is almost exactly the same as pci_bus_devorder()'s,
180	 * except that we limit the search to only those with a matching
181	 * "device" number.
182	 */
183	for (node = OF_child(node); node; node = OF_peer(node)) {
184		len = OF_getproplen(node, "reg");
185		if (len < sizeof(reg))
186			continue;
187		if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
188			panic("pci_probe_bus: OF_getprop len botch");
189
190		if (device != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
191			continue;
192
193		funcs[i++] = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
194#ifdef DEBUG
195	if (sparc_pci_debug & SPDB_PROBE) {
196		OF_getprop(node, "name", &name, sizeof(name));
197		printf("pci_bus_funcorder: adding %x %s\n", node, name);
198	}
199#endif
200		if (i == 8)
201			break;
202	}
203	if (i < 8)
204		funcs[i] = -1;
205
206	return i;
207}
208#endif
209
210pcitag_t
211pci_make_tag(pc, b, d, f)
212	pci_chipset_tag_t pc;
213	int b;
214	int d;
215	int f;
216{
217	struct ofw_pci_register reg;
218	pcitag_t tag;
219	int busrange[2];
220	int node, len;
221#ifdef DEBUG
222	char name[80];
223	bzero(name, sizeof(name));
224#endif
225
226	/*
227	 * Hunt for the node that corresponds to this device
228	 *
229	 * We could cache this info in an array in the parent
230	 * device... except then we have problems with devices
231	 * attached below pci-pci bridges, and we would need to
232	 * add special code to the pci-pci bridge to cache this
233	 * info.
234	 */
235
236	tag = PCITAG_CREATE(-1, b, d, f);
237	node = pc->rootnode;
238	/*
239	 * First make sure we're on the right bus.  If our parent
240	 * has a bus-range property and we're not in the range,
241	 * then we're obviously on the wrong bus.  So go up one
242	 * level.
243	 */
244#ifdef DEBUG
245	if (sparc_pci_debug & SPDB_PROBE) {
246		OF_getprop(node, "name", &name, sizeof(name));
247		printf("curnode %x %s\n", node, name);
248	}
249#endif
250#if 0
251	while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange,
252		sizeof(busrange)) == sizeof(busrange)) &&
253		(b < busrange[0] || b > busrange[1])) {
254		/* Out of range, go up one */
255		node = OF_parent(node);
256#ifdef DEBUG
257		if (sparc_pci_debug & SPDB_PROBE) {
258			OF_getprop(node, "name", &name, sizeof(name));
259			printf("going up to node %x %s\n", node, name);
260		}
261#endif
262	}
263#endif
264	/*
265	 * Now traverse all peers until we find the node or we find
266	 * the right bridge.
267	 *
268	 * XXX We go up one and down one to make sure nobody's missed.
269	 * but this should not be necessary.
270	 */
271	for (node = ((node)); node; node = OF_peer(node)) {
272
273#ifdef DEBUG
274		if (sparc_pci_debug & SPDB_PROBE) {
275			OF_getprop(node, "name", &name, sizeof(name));
276			printf("checking node %x %s\n", node, name);
277		}
278#endif
279
280#if 1
281		/*
282		 * Check for PCI-PCI bridges.  If the device we want is
283		 * in the bus-range for that bridge, work our way down.
284		 */
285		while ((OF_getprop(node, "bus-range", (void *)&busrange,
286			sizeof(busrange)) == sizeof(busrange)) &&
287			(b >= busrange[0] && b <= busrange[1])) {
288			/* Go down 1 level */
289			node = OF_child(node);
290#ifdef DEBUG
291			if (sparc_pci_debug & SPDB_PROBE) {
292				OF_getprop(node, "name", &name, sizeof(name));
293				printf("going down to node %x %s\n",
294					node, name);
295			}
296#endif
297		}
298#endif
299		/*
300		 * We only really need the first `reg' property.
301		 *
302		 * For simplicity, we'll query the `reg' when we
303		 * need it.  Otherwise we could malloc() it, but
304		 * that gets more complicated.
305		 */
306		len = OF_getproplen(node, "reg");
307		if (len < sizeof(reg))
308			continue;
309		if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
310			panic("pci_probe_bus: OF_getprop len botch");
311
312		if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi))
313			continue;
314		if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
315			continue;
316		if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi))
317			continue;
318
319		/* Got a match */
320		tag = ofpci_make_tag(pc, node, b, d, f);
321
322		/*
323		 * Record the node.  This has two effects:
324		 *
325		 * 1) We don't have to search as far.
326		 * 2) pci_bus_devorder will scan the right bus.
327		 */
328		pc->curnode = node;
329		return (tag);
330	}
331	/* No device found -- return a dead tag */
332	return (tag);
333}
334
335void
336pci_decompose_tag(pc, tag, bp, dp, fp)
337	pci_chipset_tag_t pc;
338	pcitag_t tag;
339	int *bp, *dp, *fp;
340{
341
342	if (bp != NULL)
343		*bp = PCITAG_BUS(tag);
344	if (dp != NULL)
345		*dp = PCITAG_DEV(tag);
346	if (fp != NULL)
347		*fp = PCITAG_FUN(tag);
348}
349
350pcitag_t
351ofpci_make_tag(pc, node, b, d, f)
352	pci_chipset_tag_t pc;
353	int node;
354	int b;
355	int d;
356	int f;
357{
358	pcitag_t tag;
359
360	tag = PCITAG_CREATE(node, b, d, f);
361
362	/*
363	 * Record the node.  This has two effects:
364	 *
365	 * 1) We don't have to search as far.
366	 * 2) pci_bus_devorder will scan the right bus.
367	 */
368	pc->curnode = node;
369
370	/* Enable all the different spaces for this device */
371	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
372		PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|
373		PCI_COMMAND_IO_ENABLE);
374	return (tag);
375}
376
377/* assume we are mapped little-endian/side-effect */
378pcireg_t
379pci_conf_read(pc, tag, reg)
380	pci_chipset_tag_t pc;
381	pcitag_t tag;
382	int reg;
383{
384	struct psycho_pbm *pp = pc->cookie;
385	struct psycho_softc *sc = pp->pp_sc;
386	pcireg_t val = (pcireg_t)~0;
387
388	DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ",
389		(long)tag, reg));
390	if (PCITAG_NODE(tag) != -1) {
391		DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...",
392			sc->sc_configaddr._asi,
393			(long long)(sc->sc_configaddr._ptr +
394				PCITAG_OFFSET(tag) + reg),
395			(int)PCITAG_OFFSET(tag) + reg));
396
397		val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr,
398			PCITAG_OFFSET(tag) + reg);
399	}
400#ifdef DEBUG
401	else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n",
402		(int)PCITAG_OFFSET(tag)));
403#endif
404	DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val));
405
406	return (val);
407}
408
409void
410pci_conf_write(pc, tag, reg, data)
411	pci_chipset_tag_t pc;
412	pcitag_t tag;
413	int reg;
414	pcireg_t data;
415{
416	struct psycho_pbm *pp = pc->cookie;
417	struct psycho_softc *sc = pp->pp_sc;
418
419	DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ",
420		(long)PCITAG_OFFSET(tag), reg, (int)data));
421	DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n",
422		sc->sc_configaddr._asi,
423		(long long)(sc->sc_configaddr._ptr + PCITAG_OFFSET(tag) + reg),
424		(int)PCITAG_OFFSET(tag) + reg));
425
426	/* If we don't know it, just punt it.  */
427	if (PCITAG_NODE(tag) == -1) {
428		DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr"));
429		return;
430	}
431
432	bus_space_write_4(sc->sc_configtag, sc->sc_configaddr,
433		PCITAG_OFFSET(tag) + reg, data);
434}
435
436/*
437 * interrupt mapping foo.
438 * XXX: how does this deal with multiple interrupts for a device?
439 */
440int
441pci_intr_map(pa, ihp)
442	struct pci_attach_args *pa;
443	pci_intr_handle_t *ihp;
444{
445	pcitag_t tag = pa->pa_tag;
446	int interrupts;
447	int len, node = PCITAG_NODE(tag);
448	char devtype[30];
449
450	len = OF_getproplen(node, "interrupts");
451	if (len < sizeof(interrupts)) {
452		DPRINTF(SPDB_INTMAP,
453			("pci_intr_map: interrupts len %d too small\n", len));
454		return (ENODEV);
455	}
456	if (OF_getprop(node, "interrupts", (void *)&interrupts,
457		sizeof(interrupts)) != len) {
458		DPRINTF(SPDB_INTMAP,
459			("pci_intr_map: could not read interrupts\n"));
460		return (ENODEV);
461	}
462
463	if (OF_mapintr(node, &interrupts, sizeof(interrupts),
464		sizeof(interrupts)) < 0) {
465		printf("OF_mapintr failed\n");
466	}
467	/* Try to find an IPL for this type of device. */
468	if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) {
469		for (len = 0;  intrmap[len].in_class; len++)
470			if (strcmp(intrmap[len].in_class, devtype) == 0) {
471				interrupts |= INTLEVENCODE(intrmap[len].in_lev);
472				break;
473			}
474	}
475
476	/* XXXX -- we use the ino.  What if there is a valid IGN? */
477	*ihp = interrupts;
478	return (0);
479}
480
481const char *
482pci_intr_string(pc, ih)
483	pci_chipset_tag_t pc;
484	pci_intr_handle_t ih;
485{
486	static char str[16];
487
488	DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
489	sprintf(str, "ivec %x", ih);
490	DPRINTF(SPDB_INTR, ("; returning %s\n", str));
491
492	return (str);
493}
494
495const struct evcnt *
496pci_intr_evcnt(pc, ih)
497	pci_chipset_tag_t pc;
498	pci_intr_handle_t ih;
499{
500
501	/* XXX for now, no evcnt parent reported */
502	return NULL;
503}
504
505void *
506pci_intr_establish(pc, ih, level, func, arg)
507	pci_chipset_tag_t pc;
508	pci_intr_handle_t ih;
509	int level;
510	int (*func) __P((void *));
511	void *arg;
512{
513	void *cookie;
514	struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie;
515
516	DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level));
517	cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg);
518
519	DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
520	return (cookie);
521}
522
523void
524pci_intr_disestablish(pc, cookie)
525	pci_chipset_tag_t pc;
526	void *cookie;
527{
528
529	DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
530
531	/* XXX */
532	panic("can't disestablish PCI interrupts yet");
533}
534