apb.c revision 119291
1/*-
2 * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
3 * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
4 * Copyright (c) 2000 BSDi
5 * Copyright (c) 2001, 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, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13
32 *
33 * $FreeBSD: head/sys/sparc64/pci/apb.c 119291 2003-08-22 07:39:05Z imp $
34 */
35
36/*
37 * Support for the Sun APB (Advanced PCI Bridge) PCI-PCI bridge.
38 * This bridge does not fully comply to the PCI bridge specification, and is
39 * therefore not supported by the generic driver.
40 * We can use some pf the pcib methods anyway.
41 */
42
43#include "opt_ofw_pci.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/bus.h>
50
51#include <dev/ofw/openfirm.h>
52#include <dev/ofw/ofw_pci.h>
53
54#include <machine/bus.h>
55#include <machine/ofw_bus.h>
56#include <machine/resource.h>
57
58#include <dev/pci/pcireg.h>
59#include <dev/pci/pcivar.h>
60#include <dev/pci/pcib_private.h>
61
62#include "pcib_if.h"
63
64#include <sparc64/pci/ofw_pci.h>
65#include <sparc64/pci/ofw_pcib_subr.h>
66
67/*
68 * Bridge-specific data.
69 */
70struct apb_softc {
71	struct ofw_pcib_gen_softc	sc_bsc;
72	u_int8_t	sc_iomap;
73	u_int8_t	sc_memmap;
74};
75
76static device_probe_t apb_probe;
77static device_attach_t apb_attach;
78static bus_alloc_resource_t apb_alloc_resource;
79#ifndef OFW_NEWPCI
80static pcib_route_interrupt_t apb_route_interrupt;
81#endif
82
83static device_method_t apb_methods[] = {
84	/* Device interface */
85	DEVMETHOD(device_probe,		apb_probe),
86	DEVMETHOD(device_attach,	apb_attach),
87	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
88	DEVMETHOD(device_suspend,	bus_generic_suspend),
89	DEVMETHOD(device_resume,	bus_generic_resume),
90
91	/* Bus interface */
92	DEVMETHOD(bus_print_child,	bus_generic_print_child),
93	DEVMETHOD(bus_read_ivar,	pcib_read_ivar),
94	DEVMETHOD(bus_write_ivar,	pcib_write_ivar),
95	DEVMETHOD(bus_alloc_resource,	apb_alloc_resource),
96	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
97	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
98	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
99	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
100	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
101
102	/* pcib interface */
103	DEVMETHOD(pcib_maxslots,	pcib_maxslots),
104	DEVMETHOD(pcib_read_config,	pcib_read_config),
105	DEVMETHOD(pcib_write_config,	pcib_write_config),
106#ifdef OFW_NEWPCI
107	DEVMETHOD(pcib_route_interrupt,	ofw_pcib_gen_route_interrupt),
108#else
109	DEVMETHOD(pcib_route_interrupt,	apb_route_interrupt),
110#endif
111
112	/* ofw_pci interface */
113#ifdef OFW_NEWPCI
114	DEVMETHOD(ofw_pci_get_node,	ofw_pcib_gen_get_node),
115	DEVMETHOD(ofw_pci_adjust_busrange,	ofw_pcib_gen_adjust_busrange),
116#endif
117
118	{ 0, 0 }
119};
120
121static driver_t apb_driver = {
122	"pcib",
123	apb_methods,
124	sizeof(struct apb_softc),
125};
126
127DRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0);
128
129/* APB specific registers */
130#define	APBR_IOMAP	0xde
131#define	APBR_MEMMAP	0xdf
132
133/* Definitions for the mapping registers */
134#define	APB_IO_SCALE	0x200000
135#define	APB_MEM_SCALE	0x20000000
136
137/*
138 * Generic device interface
139 */
140static int
141apb_probe(device_t dev)
142{
143
144	if (pci_get_vendor(dev) == 0x108e &&	/* Sun */
145	    pci_get_device(dev) == 0x5000)  {	/* APB */
146		device_set_desc(dev, "APB PCI-PCI bridge");
147		return (0);
148	}
149	return (ENXIO);
150}
151
152static void
153apb_map_print(u_int8_t map, u_long scale)
154{
155	int i, first;
156
157	for (first = 1, i = 0; i < 8; i++) {
158		if ((map & (1 << i)) != 0) {
159			printf("%s0x%lx-0x%lx", first ? "" : ", ",
160			    i * scale, (i + 1) * scale - 1);
161			first = 0;
162		}
163	}
164}
165
166static int
167apb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end)
168{
169	int i, ei;
170
171	i = start / scale;
172	ei = end / scale;
173	if (i > 7 || ei > 7)
174		return (0);
175	for (; i <= ei; i++)
176		if ((map & (1 << i)) == 0)
177			return (0);
178	return (1);
179}
180
181static int
182apb_attach(device_t dev)
183{
184	struct apb_softc *sc;
185
186	sc = device_get_softc(dev);
187
188	/*
189	 * Get current bridge configuration.
190	 */
191	sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
192	sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
193#ifdef OFW_NEWPCI
194	ofw_pcib_gen_setup(dev);
195#else
196	sc->sc_bsc.ops_pcib_sc.dev = dev;
197	sc->sc_bsc.ops_pcib_sc.secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
198	sc->sc_bsc.ops_pcib_sc.subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
199#endif
200
201	if (bootverbose) {
202		device_printf(dev, "  secondary bus     %d\n",
203		    sc->sc_bsc.ops_pcib_sc.secbus);
204		device_printf(dev, "  subordinate bus   %d\n",
205		    sc->sc_bsc.ops_pcib_sc.subbus);
206		device_printf(dev, "  I/O decode        ");
207		apb_map_print(sc->sc_iomap, APB_IO_SCALE);
208		printf("\n");
209		device_printf(dev, "  memory decode     ");
210		apb_map_print(sc->sc_memmap, APB_MEM_SCALE);
211		printf("\n");
212	}
213
214#ifndef OFW_NEWPCI
215	if (sc->sc_bsc.ops_pcib_sc.secbus == 0)
216		panic("apb_attach: APB with uninitialized secbus");
217#endif
218
219	device_add_child(dev, "pci", sc->sc_bsc.ops_pcib_sc.secbus);
220	return (bus_generic_attach(dev));
221}
222
223/*
224 * We have to trap resource allocation requests and ensure that the bridge
225 * is set up to, or capable of handling them.
226 */
227static struct resource *
228apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
229    u_long start, u_long end, u_long count, u_int flags)
230{
231	struct apb_softc *sc;
232
233	sc = device_get_softc(dev);
234	/*
235	 * If this is a "default" allocation against this rid, we can't work
236	 * out where it's coming from (we should actually never see these) so we
237	 * just have to punt.
238	 */
239	if ((start == 0) && (end == ~0)) {
240		device_printf(dev, "can't decode default resource id %d for "
241		    "%s%d, bypassing\n", *rid, device_get_name(child),
242		    device_get_unit(child));
243	} else {
244		/*
245		 * Fail the allocation for this range if it's not supported.
246		 * XXX we should probably just fix up the bridge decode and
247		 * soldier on.
248		 */
249		switch (type) {
250		case SYS_RES_IOPORT:
251			if (!apb_map_checkrange(sc->sc_iomap, APB_IO_SCALE,
252			    start, end)) {
253				device_printf(dev, "device %s%d requested "
254				    "unsupported I/O range 0x%lx-0x%lx\n",
255				    device_get_name(child),
256				    device_get_unit(child), start, end);
257				return (NULL);
258			}
259			if (bootverbose)
260				device_printf(sc->sc_bsc.ops_pcib_sc.dev,
261				    "device %s%d requested decoded I/O range "
262				    "0x%lx-0x%lx\n", device_get_name(child),
263				    device_get_unit(child), start, end);
264			break;
265
266		case SYS_RES_MEMORY:
267			if (!apb_map_checkrange(sc->sc_memmap, APB_MEM_SCALE,
268			    start, end)) {
269				device_printf(dev, "device %s%d requested "
270				    "unsupported memory range 0x%lx-0x%lx\n",
271				    device_get_name(child),
272				    device_get_unit(child), start, end);
273				return (NULL);
274			}
275			if (bootverbose)
276				device_printf(sc->sc_bsc.ops_pcib_sc.dev,
277				    "device %s%d requested decoded memory "
278				    "range 0x%lx-0x%lx\n",
279				    device_get_name(child),
280				    device_get_unit(child), start, end);
281			break;
282
283		default:
284			break;
285		}
286	}
287
288	/*
289	 * Bridge is OK decoding this resource, so pass it up.
290	 */
291	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
292	    count, flags));
293}
294
295#ifndef OFW_NEWPCI
296/*
297 * Route an interrupt across a PCI bridge - we need to rely on the firmware
298 * here.
299 */
300static int
301apb_route_interrupt(device_t pcib, device_t dev, int pin)
302{
303
304	/*
305	 * XXX: ugly loathsome hack:
306	 * We can't use ofw_pci_route_intr() here; the device passed may be
307	 * the one of a bridge, so the original device can't be recovered.
308	 *
309	 * We need to use the firmware to route interrupts, however it has
310	 * no interface which could be used to interpret intpins; instead,
311	 * all assignments are done by device.
312	 *
313	 * The MI pci code will try to reroute interrupts of 0, although they
314	 * are correct; all other interrupts are preinitialized, so if we
315	 * get here, the intline is either 0 (so return 0), or we hit a
316	 * device which was not preinitialized (e.g. hotplugged stuff), in
317	 * which case we are lost.
318	 */
319	return (0);
320}
321#endif /* !OFW_NEWPCI */
322