apb.c revision 86231
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 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 86231 2001-11-09 20:19:58Z tmm $
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 <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <sys/bus.h>
48
49#include <machine/resource.h>
50
51#include <pci/pcivar.h>
52#include <pci/pcireg.h>
53#include <pci/pcib.h>
54
55#include "pcib_if.h"
56
57/*
58 * Bridge-specific data.
59 */
60struct apb_softc {
61	u_int8_t	iomap;
62	u_int8_t	memmap;
63};
64
65static int apb_probe(device_t dev);
66static int apb_attach(device_t dev);
67static struct resource *apb_alloc_resource(device_t dev, device_t child,
68    int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
69static int apb_route_interrupt(device_t pcib, device_t dev, int pin);
70
71static device_method_t apb_methods[] = {
72	/* Device interface */
73	DEVMETHOD(device_probe,		apb_probe),
74	DEVMETHOD(device_attach,	apb_attach),
75	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
76	DEVMETHOD(device_suspend,	bus_generic_suspend),
77	DEVMETHOD(device_resume,	bus_generic_resume),
78
79	/* Bus interface */
80	DEVMETHOD(bus_print_child,	bus_generic_print_child),
81	DEVMETHOD(bus_read_ivar,	pcib_read_ivar),
82	DEVMETHOD(bus_write_ivar,	pcib_write_ivar),
83	DEVMETHOD(bus_alloc_resource,	apb_alloc_resource),
84	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
85	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
86	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
87	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
88	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
89
90	/* pcib interface */
91	DEVMETHOD(pcib_maxslots,	pcib_maxslots),
92	DEVMETHOD(pcib_read_config,	pcib_read_config),
93	DEVMETHOD(pcib_write_config,	pcib_write_config),
94	DEVMETHOD(pcib_route_interrupt,	apb_route_interrupt),
95
96	{ 0, 0 }
97};
98
99static driver_t apb_driver = {
100	"pcib",
101	apb_methods,
102	sizeof(struct pcib_softc),
103};
104
105static devclass_t apb_devclass;
106
107DRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0);
108
109#define	APB_SOFTC(sc)	((struct apb_softc *)((sc)->extptr))
110
111/* APB specific registers */
112#define	APBR_IOMAP	0xde
113#define	APBR_MEMMAP	0xdf
114
115/* Definitions for the mapping registers */
116#define	APB_IO_SCALE	0x200000
117#define	APB_MEM_SCALE	0x20000000
118
119/*
120 * Generic device interface
121 */
122static int
123apb_probe(device_t dev)
124{
125
126	if (pci_get_vendor(dev) == 0x108e &&	/* Sun */
127	    pci_get_device(dev) == 0x5000)  {	/* APB */
128		device_set_desc(dev, "APB PCI-PCI bridge");
129		return (0);
130	}
131	return (ENXIO);
132}
133
134static void
135apb_map_print(u_int8_t map, u_long scale)
136{
137	int i, first;
138
139	for (first = 1, i = 0; i < 8; i++) {
140		if ((map & (1 << i)) != 0) {
141			printf("%s0x%lx-0x%lx", first ? "" : ", ",
142			    i * scale, (i + 1) * scale - 1);
143			first = 0;
144		}
145	}
146}
147
148static int
149apb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end)
150{
151	int i, ei;
152
153	i = start / scale;
154	ei = end / scale;
155	if (i > 7 || ei > 7)
156		return (0);
157	for (; i <= ei; i++)
158		if ((map & (1 << i)) == 0)
159			return (0);
160	return (1);
161}
162
163static int
164apb_attach(device_t dev)
165{
166	struct pcib_softc *sc;
167	struct apb_softc *asc;
168	device_t child;
169
170	sc = device_get_softc(dev);
171	sc->dev = dev;
172	sc->extptr = malloc(sizeof(struct apb_softc), M_DEVBUF, M_NOWAIT);
173	asc = APB_SOFTC(sc);
174
175	/*
176	 * Get current bridge configuration.
177	 */
178	sc->command = pci_read_config(dev, PCIR_COMMAND, 1);
179	sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
180	sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
181	sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
182	sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
183	sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
184
185	/* The APB does not implement base/limit registers. */
186	sc->iobase = sc->iolimit = 0;
187	sc->membase = sc->memlimit = 0;
188	sc->pmembase = sc->pmemlimit = 0;
189
190	asc->iomap = pci_read_config(dev, APBR_IOMAP, 1);
191	asc->memmap = pci_read_config(dev, APBR_MEMMAP, 1);
192
193	if (bootverbose) {
194		device_printf(dev, "  secondary bus     %d\n", sc->secbus);
195		device_printf(dev, "  subordinate bus   %d\n", sc->subbus);
196		device_printf(dev, "  I/O decode        ");
197		apb_map_print(asc->iomap, APB_IO_SCALE);
198		printf("\n");
199		device_printf(dev, "  memory decode     ");
200		apb_map_print(asc->memmap, APB_MEM_SCALE);
201		printf("\n");
202	}
203
204	/*
205	 * XXX If the subordinate bus number is less than the secondary bus
206	 * number, we should pick a better value.  One sensible alternative
207	 * would be to pick 255; the only tradeoff here is that configuration
208	 * transactions would be more widely routed than absolutely necessary.
209	 */
210	if (sc->secbus != 0) {
211		child = device_add_child(dev, "pci", -1);
212		if (child != NULL)
213			return (bus_generic_attach(dev));
214	} else
215		panic("apb_attach: APB with uninitialized secbus");
216
217	/* no secondary bus; we should have fixed this */
218	return (0);
219}
220
221/*
222 * We have to trap resource allocation requests and ensure that the bridge
223 * is set up to, or capable of handling them.
224 */
225static struct resource *
226apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
227    u_long start, u_long end, u_long count, u_int flags)
228{
229	struct pcib_softc *sc;
230	struct apb_softc *asc;
231
232	sc = device_get_softc(dev);
233	asc = APB_SOFTC(sc);
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(asc->iomap, APB_IO_SCALE, start,
252			    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->dev, "device %s%d requested "
261				    "decoded I/O range 0x%lx-0x%lx\n",
262				    device_get_name(child),
263				    device_get_unit(child), start, end);
264			break;
265
266		case SYS_RES_MEMORY:
267			if (!apb_map_checkrange(asc->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->dev, "device %s%d requested "
277				    "decoded memory range 0x%lx-0x%lx\n",
278				    device_get_name(child),
279				    device_get_unit(child), start, end);
280			break;
281
282		default:
283			break;
284		}
285	}
286
287	/*
288	 * Bridge is OK decoding this resource, so pass it up.
289	 */
290	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
291	    count, flags));
292}
293
294/*
295 * Route an interrupt across a PCI bridge - the APB does not route interrupts,
296 * and routing of interrupts that are not preinitialized is not supported yet.
297 */
298static int
299apb_route_interrupt(device_t pcib, device_t dev, int pin)
300{
301
302	panic("apb_route_interrupt");
303}
304