ofw_pci.c revision 98148
1/*
2 * Copyright (c) 1999, 2000 Matthew R. Green
3 * All rights reserved.
4 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  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. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp
30 *
31 * $FreeBSD: head/sys/sparc64/pci/ofw_pci.c 98148 2002-06-12 19:20:57Z tmm $
32 */
33
34#include "opt_ofw_pci.h"
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/bus.h>
40
41#include <dev/pci/pcivar.h>
42#include <dev/pci/pcireg.h>
43
44#include <dev/ofw/ofw_pci.h>
45#include <dev/ofw/openfirm.h>
46
47#include <sparc64/pci/ofw_pci.h>
48
49#include <machine/ofw_bus.h>
50
51#include "pcib_if.h"
52
53u_int8_t pci_bus_cnt;
54phandle_t *pci_bus_map;
55int pci_bus_map_sz;
56
57#define	PCI_BUS_MAP_INC	10
58
59u_int32_t
60ofw_pci_route_intr(phandle_t node)
61{
62	u_int32_t rv;
63
64	rv = ofw_bus_route_intr(node, ORIP_NOINT);
65	if (rv == ORIR_NOTFOUND)
66		return (255);
67	return (rv);
68}
69
70u_int8_t
71ofw_pci_alloc_busno(phandle_t node)
72{
73	phandle_t *om;
74	int osz;
75	u_int8_t n;
76
77	n = pci_bus_cnt++;
78	/* Establish a mapping between bus numbers and device nodes. */
79	if (n >= pci_bus_map_sz) {
80		osz = pci_bus_map_sz;
81		om = pci_bus_map;
82		pci_bus_map_sz = n + PCI_BUS_MAP_INC;
83		pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz,
84		    M_DEVBUF, M_WAITOK | M_ZERO);
85		if (om != NULL) {
86			bcopy(om, pci_bus_map, sizeof(*om) * osz);
87			free(om, M_DEVBUF);
88		}
89	}
90	pci_bus_map[n] = node;
91	return (n);
92}
93
94/*
95 * Initialize bridge bus numbers for bridges that implement the primary,
96 * secondary and subordinate bus number registers.
97 */
98void
99ofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd)
100{
101
102#ifdef OFW_PCI_DEBUG
103	printf("PCI-PCI bridge at %u/%u/%u: setting bus #s to %u/%u/%u\n",
104	    obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus,
105	    obd->obd_secbus, obd->obd_subbus);
106#endif /* OFW_PCI_DEBUG */
107	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
108	    PCIR_PRIBUS_1, obd->obd_bus, 1);
109	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
110	    PCIR_SECBUS_1, obd->obd_secbus, 1);
111	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
112	    PCIR_SUBBUS_1, obd->obd_subbus, 1);
113}
114
115#define	OFW_PCI_PCIBUS	"pci"
116/*
117 * Walk the PCI bus hierarchy, starting with the root PCI bus and descending
118 * through bridges, and initialize the interrupt line and latency timer
119 * configuration registers of attached devices using firmware information,
120 * as well as the the bus numbers and ranges of the bridges.
121 */
122void
123ofw_pci_init(device_t dev, phandle_t bushdl, struct ofw_pci_bdesc *obd)
124{
125	struct ofw_pci_register pcir;
126	struct ofw_pci_bdesc subobd, *tobd;
127	phandle_t node;
128	char type[32];
129	int intr, freemap;
130	u_int slot, busno, func, sub, lat;
131
132	if ((node = OF_child(bushdl)) == 0)
133		return;
134	freemap = 0;
135	busno = obd->obd_secbus;
136	do {
137		if (node == -1)
138			panic("ofw_pci_init_intr: OF_child failed");
139		if (OF_getprop(node, "device_type", type, sizeof(type)) == -1)
140			type[0] = '\0';
141		else
142			type[sizeof(type) - 1] = '\0';
143		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
144			panic("ofw_pci_route_intr: OF_getprop failed");
145		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
146		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
147		if (strcmp(type, OFW_PCI_PCIBUS) == 0) {
148			/*
149			 * This is a pci-pci bridge, initalize the bus number and
150			 * recurse to initialize the child bus. The hierarchy is
151			 * usually at most 2 levels deep, so recursion is
152			 * feasible.
153			 */
154			subobd.obd_bus = busno;
155			subobd.obd_slot = slot;
156			subobd.obd_func = func;
157			sub = ofw_pci_alloc_busno(node);
158			subobd.obd_secbus = subobd.obd_subbus = sub;
159			/* Assume this bridge is mostly standard conforming. */
160			subobd.obd_init = ofw_pci_binit;
161			subobd.obd_super = obd;
162			/*
163			 * Need to change all subordinate bus registers of the
164			 * bridges above this one now so that configuration
165			 * transactions will get through.
166			 */
167			for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) {
168				tobd->obd_subbus = sub;
169				tobd->obd_init(dev, tobd);
170			}
171			subobd.obd_init(dev, &subobd);
172#ifdef OFW_PCI_DEBUG
173			device_printf(dev, "%s: descending to "
174			    "subordinate PCI bus\n", __func__);
175#endif /* OFW_PCI_DEBUG */
176			ofw_pci_init(dev, node, &subobd);
177		} else {
178			/*
179			 * Initialize the latency timer register for
180			 * busmaster devices to work properly. This is another
181			 * task which the firmware does not always perform.
182			 * The Min_Gnt register can be used to compute it's
183			 * recommended value: it contains the desired latency
184			 * in units of 1/4 us. To calculate the correct latency
185			 * timer value, a bus clock of 33 and no wait states
186			 * should be assumed.
187			 */
188			lat = PCIB_READ_CONFIG(dev, busno, slot, func,
189			    PCIR_MINGNT, 1) * 33 / 4;
190			if (lat != 0) {
191#ifdef OFW_PCI_DEBUG
192				printf("device %d/%d/%d: latency timer %d -> "
193				    "%d\n", busno, slot, func,
194				    PCIB_READ_CONFIG(dev, busno, slot, func,
195					PCIR_LATTIMER, 1), lat);
196#endif /* OFW_PCI_DEBUG */
197				PCIB_WRITE_CONFIG(dev, busno, slot, func,
198				    PCIR_LATTIMER, imin(lat, 255), 1);
199			}
200
201			/* Initialize the intline registers. */
202			if ((intr = ofw_pci_route_intr(node)) != 255) {
203#ifdef OFW_PCI_DEBUG
204				device_printf(dev, "%s: mapping intr for "
205				    "%d/%d/%d to %d (preset was %d)\n",
206				    __func__, busno, slot, func, intr,
207				    (int)PCIB_READ_CONFIG(dev, busno, slot,
208					func, PCIR_INTLINE, 1));
209#endif /* OFW_PCI_DEBUG */
210				PCIB_WRITE_CONFIG(dev, busno, slot, func,
211				    PCIR_INTLINE, intr, 1);
212			} else {
213#ifdef OFW_PCI_DEBUG
214				device_printf(dev, "%s: no interrupt "
215				    "mapping found for %d/%d/%d (preset %d)\n",
216				    __func__, busno, slot, func,
217				    (int)PCIB_READ_CONFIG(dev, busno, slot,
218					func, PCIR_INTLINE, 1));
219#endif /* OFW_PCI_DEBUG */
220				/*
221				 * The firmware initializes to 0 instead of
222				 * 255.
223				 */
224				PCIB_WRITE_CONFIG(dev, busno, slot, func,
225				    PCIR_INTLINE, 255, 1);
226			}
227		}
228	} while ((node = OF_peer(node)) != 0);
229}
230
231phandle_t
232ofw_pci_find_node(int bus, int slot, int func)
233{
234	phandle_t node, bnode;
235	struct ofw_pci_register pcir;
236
237	/*
238	 * Retrieve the bus node from the mapping that was created on
239	 * initialization. The bus numbers the firmware uses cannot be trusted,
240	 * so they might have needed to be changed and this is necessary.
241	 */
242	if (bus >= pci_bus_map_sz)
243		return (0);
244	bnode = pci_bus_map[bus];
245	if (bnode == 0)
246		return (0);
247	for (node = OF_child(bnode); node != 0 && node != -1;
248	     node = OF_peer(node)) {
249		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
250			continue;
251		if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot &&
252		    OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func)
253			return (node);
254	}
255	return (0);
256}
257
258phandle_t
259ofw_pci_node(device_t dev)
260{
261
262	return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev),
263	    pci_get_function(dev)));
264}
265