pci_machdep.c revision 1.27
1/*	$NetBSD: pci_machdep.c,v 1.27 2002/05/06 22:18:51 eeh 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
335pcitag_t
336ofpci_make_tag(pc, node, b, d, f)
337	pci_chipset_tag_t pc;
338	int node;
339	int b;
340	int d;
341	int f;
342{
343	pcitag_t tag;
344
345	tag = PCITAG_CREATE(node, b, d, f);
346
347	/*
348	 * Record the node.  This has two effects:
349	 *
350	 * 1) We don't have to search as far.
351	 * 2) pci_bus_devorder will scan the right bus.
352	 */
353	pc->curnode = node;
354
355	/* Enable all the different spaces for this device */
356	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
357		PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|
358		PCI_COMMAND_IO_ENABLE);
359	return (tag);
360}
361
362/* assume we are mapped little-endian/side-effect */
363pcireg_t
364pci_conf_read(pc, tag, reg)
365	pci_chipset_tag_t pc;
366	pcitag_t tag;
367	int reg;
368{
369	struct psycho_pbm *pp = pc->cookie;
370	struct psycho_softc *sc = pp->pp_sc;
371	pcireg_t val = (pcireg_t)~0;
372
373	DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ",
374		(long)tag, reg));
375	if (PCITAG_NODE(tag) != -1) {
376		DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...",
377			sc->sc_configaddr._asi,
378			(long long)(sc->sc_configaddr._ptr +
379				PCITAG_OFFSET(tag) + reg),
380			(int)PCITAG_OFFSET(tag) + reg));
381
382		val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr,
383			PCITAG_OFFSET(tag) + reg);
384	}
385#ifdef DEBUG
386	else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n",
387		(int)PCITAG_OFFSET(tag)));
388#endif
389	DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val));
390
391	return (val);
392}
393
394void
395pci_conf_write(pc, tag, reg, data)
396	pci_chipset_tag_t pc;
397	pcitag_t tag;
398	int reg;
399	pcireg_t data;
400{
401	struct psycho_pbm *pp = pc->cookie;
402	struct psycho_softc *sc = pp->pp_sc;
403
404	DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ",
405		(long)PCITAG_OFFSET(tag), reg, (int)data));
406	DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n",
407		sc->sc_configaddr._asi,
408		(long long)(sc->sc_configaddr._ptr + PCITAG_OFFSET(tag) + reg),
409		(int)PCITAG_OFFSET(tag) + reg));
410
411	/* If we don't know it, just punt it.  */
412	if (PCITAG_NODE(tag) == -1) {
413		DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr"));
414		return;
415	}
416
417	bus_space_write_4(sc->sc_configtag, sc->sc_configaddr,
418		PCITAG_OFFSET(tag) + reg, data);
419}
420
421/*
422 * interrupt mapping foo.
423 * XXX: how does this deal with multiple interrupts for a device?
424 */
425int
426pci_intr_map(pa, ihp)
427	struct pci_attach_args *pa;
428	pci_intr_handle_t *ihp;
429{
430	pcitag_t tag = pa->pa_tag;
431	int interrupts;
432	int len, node = PCITAG_NODE(tag);
433	char devtype[30];
434
435	len = OF_getproplen(node, "interrupts");
436	if (len < sizeof(interrupts)) {
437		DPRINTF(SPDB_INTMAP,
438			("pci_intr_map: interrupts len %d too small\n", len));
439		return (ENODEV);
440	}
441	if (OF_getprop(node, "interrupts", (void *)&interrupts,
442		sizeof(interrupts)) != len) {
443		DPRINTF(SPDB_INTMAP,
444			("pci_intr_map: could not read interrupts\n"));
445		return (ENODEV);
446	}
447
448	if (OF_mapintr(node, &interrupts, sizeof(interrupts),
449		sizeof(interrupts)) < 0) {
450		printf("OF_mapintr failed\n");
451	}
452	/* Try to find an IPL for this type of device. */
453	if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) {
454		for (len = 0;  intrmap[len].in_class; len++)
455			if (strcmp(intrmap[len].in_class, devtype) == 0) {
456				interrupts |= INTLEVENCODE(intrmap[len].in_lev);
457				break;
458			}
459	}
460
461	/* XXXX -- we use the ino.  What if there is a valid IGN? */
462	*ihp = interrupts;
463	return (0);
464}
465
466const char *
467pci_intr_string(pc, ih)
468	pci_chipset_tag_t pc;
469	pci_intr_handle_t ih;
470{
471	static char str[16];
472
473	DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
474	sprintf(str, "ivec %x", ih);
475	DPRINTF(SPDB_INTR, ("; returning %s\n", str));
476
477	return (str);
478}
479
480const struct evcnt *
481pci_intr_evcnt(pc, ih)
482	pci_chipset_tag_t pc;
483	pci_intr_handle_t ih;
484{
485
486	/* XXX for now, no evcnt parent reported */
487	return NULL;
488}
489
490void *
491pci_intr_establish(pc, ih, level, func, arg)
492	pci_chipset_tag_t pc;
493	pci_intr_handle_t ih;
494	int level;
495	int (*func) __P((void *));
496	void *arg;
497{
498	void *cookie;
499	struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie;
500
501	DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level));
502	cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg);
503
504	DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
505	return (cookie);
506}
507
508void
509pci_intr_disestablish(pc, cookie)
510	pci_chipset_tag_t pc;
511	void *cookie;
512{
513
514	DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
515
516	/* XXX */
517	panic("can't disestablish PCI interrupts yet");
518}
519