ofw_pci.c revision 111119
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 111119 2003-02-19 05:47:46Z imp $
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/cache.h>
50#include <machine/iommureg.h>
51#include <machine/ofw_bus.h>
52#include <machine/ver.h>
53
54#include "pcib_if.h"
55
56u_int8_t pci_bus_cnt;
57phandle_t *pci_bus_map;
58int pci_bus_map_sz;
59
60#define	OPQ_NO_SWIZZLE	1
61static struct ofw_pci_quirk {
62	char	*opq_model;
63	int	opq_quirks;
64} ofw_pci_quirks[] = {
65	{ "SUNW,Ultra-4", OPQ_NO_SWIZZLE },
66	{ "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE },
67};
68#define	OPQ_NENT	(sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0]))
69
70static int pci_quirks;
71
72#define	OFW_PCI_PCIBUS	"pci"
73#define	PCI_BUS_MAP_INC	10
74
75int
76ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
77    u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate)
78{
79	struct ofw_pci_register preg;
80	u_int32_t pintr, intr;
81	char type[32];
82
83	if (pintsz != sizeof(u_int32_t))
84		return (-1);
85	bcopy(pintptr, &pintr, sizeof(pintr));
86	if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) &&
87	    OF_getprop(node, "device_type", type, sizeof(type)) != -1 &&
88	    strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) {
89		/*
90		 * Handle a quirk found on some Netra t1 models: there exist
91		 * PCI bridges without interrupt maps, where we apparently must
92		 * do the PCI swizzle and continue to map on at the parent.
93		 */
94		bcopy(pregptr, &preg, sizeof(preg));
95		intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) %
96		    4 + 1;
97		*rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK);
98		bcopy(&intr, *rintr, sizeof(intr));
99		*terminate = 0;
100		return (sizeof(intr));
101	}
102	return (-1);
103}
104
105u_int32_t
106ofw_pci_route_intr(phandle_t node, u_int32_t ign)
107{
108	u_int32_t rv;
109
110	rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback);
111	if (rv == ORIR_NOTFOUND)
112		return (255);
113	/*
114	 * Some machines (notably the SPARCengine Ultra AX) have no mappings
115	 * at all, but use complete interrupt vector number including the IGN.
116	 * Catch this case and remove the IGN.
117	 */
118	if (rv > ign)
119		rv -= ign;
120	return (rv);
121}
122
123u_int8_t
124ofw_pci_alloc_busno(phandle_t node)
125{
126	phandle_t *om;
127	int osz;
128	u_int8_t n;
129
130	n = pci_bus_cnt++;
131	/* Establish a mapping between bus numbers and device nodes. */
132	if (n >= pci_bus_map_sz) {
133		osz = pci_bus_map_sz;
134		om = pci_bus_map;
135		pci_bus_map_sz = n + PCI_BUS_MAP_INC;
136		pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz,
137		    M_DEVBUF, M_WAITOK | M_ZERO);
138		if (om != NULL) {
139			bcopy(om, pci_bus_map, sizeof(*om) * osz);
140			free(om, M_DEVBUF);
141		}
142	}
143	pci_bus_map[n] = node;
144	return (n);
145}
146
147/*
148 * Initialize bridge bus numbers for bridges that implement the primary,
149 * secondary and subordinate bus number registers.
150 */
151void
152ofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd)
153{
154
155#ifdef OFW_PCI_DEBUG
156	printf("PCI-PCI bridge at %u/%u/%u: setting bus #s to %u/%u/%u\n",
157	    obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus,
158	    obd->obd_secbus, obd->obd_subbus);
159#endif /* OFW_PCI_DEBUG */
160	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
161	    PCIR_PRIBUS_1, obd->obd_bus, 1);
162	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
163	    PCIR_SECBUS_1, obd->obd_secbus, 1);
164	PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
165	    PCIR_SUBBUS_1, obd->obd_subbus, 1);
166}
167
168/*
169 * Walk the PCI bus hierarchy, starting with the root PCI bus and descending
170 * through bridges, and initialize the interrupt line and latency timer
171 * configuration registers of attached devices using firmware information,
172 * as well as the the bus numbers and ranges of the bridges.
173 */
174void
175ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
176    struct ofw_pci_bdesc *obd)
177{
178	struct ofw_pci_register pcir;
179	struct ofw_pci_bdesc subobd, *tobd;
180	phandle_t node;
181	char type[32];
182	int i, intr, freemap;
183	u_int slot, busno, func, sub, lat;
184	u_int8_t clnsz;
185
186	/* Initialize the quirk list. */
187	for (i = 0; i < OPQ_NENT; i++) {
188		if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) {
189			pci_quirks = ofw_pci_quirks[i].opq_quirks;
190			break;
191		}
192	}
193
194	if ((node = OF_child(bushdl)) == 0)
195		return;
196	freemap = 0;
197	busno = obd->obd_secbus;
198	/*
199	 * Compute the value to write into the cache line size register.
200	 * The role of the streaming cache is unclear in write invalidate
201	 * transfers, so it is made sure that it's line size is always reached.
202	 */
203	clnsz = imax(cache.ec_linesize, STRBUF_LINESZ);
204	KASSERT((clnsz / STRBUF_LINESZ) * STRBUF_LINESZ == clnsz &&
205	    (clnsz / cache.ec_linesize) * cache.ec_linesize == clnsz &&
206	    (clnsz / 4) * 4 == clnsz, ("bogus cache line size %d", clnsz));
207
208	do {
209		if (node == -1)
210			panic("ofw_pci_init_intr: OF_child failed");
211		if (OF_getprop(node, "device_type", type, sizeof(type)) == -1)
212			type[0] = '\0';
213		else
214			type[sizeof(type) - 1] = '\0';
215		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
216			panic("ofw_pci_init: OF_getprop failed");
217		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
218		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
219		if (strcmp(type, OFW_PCI_PCIBUS) == 0) {
220			/*
221			 * This is a pci-pci bridge, initalize the bus number and
222			 * recurse to initialize the child bus. The hierarchy is
223			 * usually at most 2 levels deep, so recursion is
224			 * feasible.
225			 */
226			subobd.obd_bus = busno;
227			subobd.obd_slot = slot;
228			subobd.obd_func = func;
229			sub = ofw_pci_alloc_busno(node);
230			subobd.obd_secbus = subobd.obd_subbus = sub;
231			/* Assume this bridge is mostly standard conforming. */
232			subobd.obd_init = ofw_pci_binit;
233			subobd.obd_super = obd;
234			/*
235			 * Need to change all subordinate bus registers of the
236			 * bridges above this one now so that configuration
237			 * transactions will get through.
238			 */
239			for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) {
240				tobd->obd_subbus = sub;
241				tobd->obd_init(dev, tobd);
242			}
243			subobd.obd_init(dev, &subobd);
244#ifdef OFW_PCI_DEBUG
245			device_printf(dev, "%s: descending to "
246			    "subordinate PCI bus\n", __func__);
247#endif /* OFW_PCI_DEBUG */
248			ofw_pci_init(dev, node, ign, &subobd);
249		} else {
250			/*
251			 * Initialize the latency timer register for
252			 * busmaster devices to work properly. This is another
253			 * task which the firmware does not always perform.
254			 * The Min_Gnt register can be used to compute it's
255			 * recommended value: it contains the desired latency
256			 * in units of 1/4 us. To calculate the correct latency
257			 * timer value, a bus clock of 33 and no wait states
258			 * should be assumed.
259			 */
260			lat = PCIB_READ_CONFIG(dev, busno, slot, func,
261			    PCIR_MINGNT, 1) * 33 / 4;
262			if (lat != 0) {
263#ifdef OFW_PCI_DEBUG
264				printf("device %d/%d/%d: latency timer %d -> "
265				    "%d\n", busno, slot, func,
266				    PCIB_READ_CONFIG(dev, busno, slot, func,
267					PCIR_LATTIMER, 1), lat);
268#endif /* OFW_PCI_DEBUG */
269				PCIB_WRITE_CONFIG(dev, busno, slot, func,
270				    PCIR_LATTIMER, imin(lat, 255), 1);
271			}
272			PCIB_WRITE_CONFIG(dev, busno, slot, func,
273			    PCIR_CACHELNSZ, clnsz / 4, 1);
274
275			/* Initialize the intline registers. */
276			if ((intr = ofw_pci_route_intr(node, ign)) != 255) {
277#ifdef OFW_PCI_DEBUG
278				device_printf(dev, "%s: mapping intr for "
279				    "%d/%d/%d to %d (preset was %d)\n",
280				    __func__, busno, slot, func, intr,
281				    (int)PCIB_READ_CONFIG(dev, busno, slot,
282					func, PCIR_INTLINE, 1));
283#endif /* OFW_PCI_DEBUG */
284				PCIB_WRITE_CONFIG(dev, busno, slot, func,
285				    PCIR_INTLINE, intr, 1);
286			} else {
287#ifdef OFW_PCI_DEBUG
288				device_printf(dev, "%s: no interrupt "
289				    "mapping found for %d/%d/%d (preset %d)\n",
290				    __func__, busno, slot, func,
291				    (int)PCIB_READ_CONFIG(dev, busno, slot,
292					func, PCIR_INTLINE, 1));
293#endif /* OFW_PCI_DEBUG */
294				/*
295				 * The firmware initializes to 0 instead of
296				 * 255.
297				 */
298				PCIB_WRITE_CONFIG(dev, busno, slot, func,
299				    PCIR_INTLINE, 255, 1);
300			}
301		}
302	} while ((node = OF_peer(node)) != 0);
303}
304
305phandle_t
306ofw_pci_find_node(int bus, int slot, int func)
307{
308	phandle_t node, bnode;
309	struct ofw_pci_register pcir;
310
311	/*
312	 * Retrieve the bus node from the mapping that was created on
313	 * initialization. The bus numbers the firmware uses cannot be trusted,
314	 * so they might have needed to be changed and this is necessary.
315	 */
316	if (bus >= pci_bus_map_sz)
317		return (0);
318	bnode = pci_bus_map[bus];
319	if (bnode == 0)
320		return (0);
321	for (node = OF_child(bnode); node != 0 && node != -1;
322	     node = OF_peer(node)) {
323		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
324			continue;
325		if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot &&
326		    OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func)
327			return (node);
328	}
329	return (0);
330}
331
332phandle_t
333ofw_pci_node(device_t dev)
334{
335
336	return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev),
337	    pci_get_function(dev)));
338}
339