ofw_pcibus.c revision 182108
1/*-
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
4 * Copyright (c) 2000, BSDi
5 * Copyright (c) 2003, Thomas Moestl <tmm@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice unmodified, this list of conditions, and the following
13 *    disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
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, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/sparc64/pci/ofw_pcibus.c 182108 2008-08-24 15:05:46Z marius $");
32
33#include "opt_ofw_pci.h"
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/kernel.h>
38#include <sys/libkern.h>
39#include <sys/module.h>
40#include <sys/pciio.h>
41
42#include <dev/ofw/ofw_bus.h>
43#include <dev/ofw/ofw_bus_subr.h>
44#include <dev/ofw/ofw_pci.h>
45#include <dev/ofw/openfirm.h>
46
47#include <machine/bus.h>
48#ifndef SUN4V
49#include <machine/bus_common.h>
50#include <machine/iommureg.h>
51#endif
52#include <machine/resource.h>
53
54#include <dev/pci/pcireg.h>
55#include <dev/pci/pcivar.h>
56#include <dev/pci/pci_private.h>
57
58#include <sparc64/pci/ofw_pci.h>
59
60#include "pcib_if.h"
61#include "pci_if.h"
62
63/* Helper functions */
64static void ofw_pcibus_setup_device(device_t bridge, uint32_t clock,
65    u_int busno, u_int slot, u_int func);
66
67/* Methods */
68static device_probe_t ofw_pcibus_probe;
69static device_attach_t ofw_pcibus_attach;
70static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
71static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo;
72
73static device_method_t ofw_pcibus_methods[] = {
74	/* Device interface */
75	DEVMETHOD(device_probe,		ofw_pcibus_probe),
76	DEVMETHOD(device_attach,	ofw_pcibus_attach),
77
78	/* Bus interface */
79
80	/* PCI interface */
81	DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt),
82
83	/* ofw_bus interface */
84	DEVMETHOD(ofw_bus_get_devinfo,	ofw_pcibus_get_devinfo),
85	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
86	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
87	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
88	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
89	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
90
91	{ 0, 0 }
92};
93
94struct ofw_pcibus_devinfo {
95	struct pci_devinfo	opd_dinfo;
96	struct ofw_bus_devinfo	opd_obdinfo;
97};
98
99static devclass_t pci_devclass;
100
101DEFINE_CLASS_1(pci, ofw_pcibus_driver, ofw_pcibus_methods, 1 /* no softc */,
102    pci_driver);
103DRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0);
104MODULE_VERSION(ofw_pcibus, 1);
105MODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1);
106
107static int
108ofw_pcibus_probe(device_t dev)
109{
110
111	if (ofw_bus_get_node(dev) == 0)
112		return (ENXIO);
113	device_set_desc(dev, "OFW PCI bus");
114
115	return (0);
116}
117
118/*
119 * Perform miscellaneous setups the firmware usually does not do for us.
120 */
121static void
122ofw_pcibus_setup_device(device_t bridge, uint32_t clock, u_int busno,
123    u_int slot, u_int func)
124{
125#ifndef SUN4V
126	uint32_t reg;
127
128	/*
129	 * Initialize the latency timer register for busmaster devices to
130	 * work properly.  This is another task which the firmware doesn't
131	 * always perform.  The Min_Gnt register can be used to compute its
132	 * recommended value: it contains the desired latency in units of
133	 * 1/4 us assuming a clock rate of 33MHz.  To calculate the correct
134	 * latency timer value, the clock frequency of the bus (defaulting
135	 * to 33MHz) should be used and no wait states assumed.
136	 * For bridges, we additionally set up the bridge control and the
137	 * secondary latency registers.
138	 */
139	if ((PCIB_READ_CONFIG(bridge, busno, slot, func, PCIR_HDRTYPE, 1) &
140	    PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) {
141		reg = PCIB_READ_CONFIG(bridge, busno, slot, func,
142		    PCIR_BRIDGECTL_1, 1);
143		reg |= PCIB_BCR_MASTER_ABORT_MODE | PCIB_BCR_SERR_ENABLE |
144		    PCIB_BCR_PERR_ENABLE;
145#ifdef OFW_PCI_DEBUG
146		device_printf(bridge,
147		    "bridge %d/%d/%d: control 0x%x -> 0x%x\n",
148		    busno, slot, func, PCIB_READ_CONFIG(bridge, busno, slot,
149		    func, PCIR_BRIDGECTL_1, 1), reg);
150#endif /* OFW_PCI_DEBUG */
151		PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_BRIDGECTL_1,
152		    reg, 1);
153
154		reg = OFW_PCI_LATENCY;
155#ifdef OFW_PCI_DEBUG
156		device_printf(bridge,
157		    "bridge %d/%d/%d: latency timer %d -> %d\n",
158		    busno, slot, func, PCIB_READ_CONFIG(bridge, busno, slot,
159		    func, PCIR_SECLAT_1, 1), reg);
160#endif /* OFW_PCI_DEBUG */
161		PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_SECLAT_1,
162		    reg, 1);
163	} else {
164		reg = PCIB_READ_CONFIG(bridge, busno, slot, func,
165		    PCIR_MINGNT, 1);
166		if (reg != 0) {
167			switch (clock) {
168			case 33000000:
169				reg *= 8;
170				break;
171			case 66000000:
172				reg *= 4;
173				break;
174			}
175			reg = min(reg, 255);
176		} else
177			reg = OFW_PCI_LATENCY;
178	}
179#ifdef OFW_PCI_DEBUG
180	device_printf(bridge, "device %d/%d/%d: latency timer %d -> %d\n",
181	    busno, slot, func, PCIB_READ_CONFIG(bridge, busno, slot, func,
182	    PCIR_LATTIMER, 1), reg);
183#endif /* OFW_PCI_DEBUG */
184	PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_LATTIMER, reg, 1);
185
186	/*
187	 * Compute a value to write into the cache line size register.
188	 * The role of the streaming cache is unclear in write invalidate
189	 * transfers, so it is made sure that it's line size is always
190	 * reached.  Generally, the cache line size is fixed at 64 bytes
191	 * by Fireplane/Safari, JBus and UPA.
192	 */
193	PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_CACHELNSZ,
194	    STRBUF_LINESZ / sizeof(uint32_t), 1);
195#endif
196
197	/*
198	 * The preset in the intline register is usually wrong.  Reset
199	 * it to 255, so that the PCI code will reroute the interrupt if
200	 * needed.
201	 */
202	PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_INTLINE,
203	    PCI_INVALID_IRQ, 1);
204}
205
206static int
207ofw_pcibus_attach(device_t dev)
208{
209	device_t pcib;
210	struct ofw_pci_register pcir;
211	struct ofw_pcibus_devinfo *dinfo;
212	phandle_t node, child;
213	uint32_t clock;
214	u_int busno, domain, func, slot;
215
216	pcib = device_get_parent(dev);
217	domain = pcib_get_domain(dev);
218	busno = pcib_get_bus(dev);
219	if (bootverbose)
220		device_printf(dev, "domain=%d, physical bus=%d\n",
221		    domain, busno);
222	node = ofw_bus_get_node(dev);
223
224#ifndef SUN4V
225	/* Add the PCI side of the HOST-PCI bridge itself to the bus. */
226	if (strcmp(device_get_name(device_get_parent(pcib)), "nexus") == 0 &&
227	    (dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
228	    domain, busno, 0, 0, sizeof(*dinfo))) != NULL) {
229		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0)
230			pci_freecfg((struct pci_devinfo *)dinfo);
231		else
232			pci_add_child(dev, (struct pci_devinfo *)dinfo);
233	}
234#endif
235
236	if (OF_getprop(ofw_bus_get_node(pcib), "clock-frequency", &clock,
237	    sizeof(clock)) == -1)
238		clock = 33000000;
239	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
240		if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
241			continue;
242		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
243		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
244		/* Some OFW device trees contain dupes. */
245		if (pci_find_dbsf(domain, busno, slot, func) != NULL)
246			continue;
247		ofw_pcibus_setup_device(pcib, clock, busno, slot, func);
248		dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
249		    domain, busno, slot, func, sizeof(*dinfo));
250		if (dinfo == NULL)
251			continue;
252		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
253		    0) {
254			pci_freecfg((struct pci_devinfo *)dinfo);
255			continue;
256		}
257		pci_add_child(dev, (struct pci_devinfo *)dinfo);
258	}
259
260	return (bus_generic_attach(dev));
261}
262
263static int
264ofw_pcibus_assign_interrupt(device_t dev, device_t child)
265{
266	ofw_pci_intr_t intr;
267	int isz;
268
269	isz = OF_getprop(ofw_bus_get_node(child), "interrupts", &intr,
270	    sizeof(intr));
271	if (isz != sizeof(intr)) {
272		/* No property; our best guess is the intpin. */
273		intr = pci_get_intpin(child);
274#ifndef SUN4V
275	} else if (intr >= 255) {
276		/*
277		 * A fully specified interrupt (including IGN), as present on
278		 * SPARCengine Ultra AX and E450.  Extract the INO and return
279		 * it.
280		 */
281		return (INTINO(intr));
282#endif
283	}
284	/*
285	 * If we got intr from a property, it may or may not be an intpin.
286	 * For on-board devices, it frequently is not, and is completely out
287	 * of the valid intpin range.  For PCI slots, it hopefully is,
288	 * otherwise we will have trouble interfacing with non-OFW buses
289	 * such as cardbus.
290	 * Since we cannot tell which it is without violating layering, we
291	 * will always use the route_interrupt method, and treat exceptions
292	 * on the level they become apparent.
293	 */
294	return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr));
295}
296
297static const struct ofw_bus_devinfo *
298ofw_pcibus_get_devinfo(device_t bus, device_t dev)
299{
300	struct ofw_pcibus_devinfo *dinfo;
301
302	dinfo = device_get_ivars(dev);
303	return (&dinfo->opd_obdinfo);
304}
305