acpi_pcib_acpi.c revision 128071
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * 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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *	$FreeBSD: head/sys/dev/acpica/acpi_pcib_acpi.c 128071 2004-04-09 18:14:32Z njl $
28 */
29#include "opt_acpi.h"
30#include <sys/param.h>
31#include <sys/bus.h>
32#include <sys/malloc.h>
33#include <sys/kernel.h>
34
35#include "acpi.h"
36
37#include <dev/acpica/acpivar.h>
38
39#include <machine/pci_cfgreg.h>
40#include <dev/pci/pcivar.h>
41#include <dev/pci/pcib_private.h>
42#include "pcib_if.h"
43
44#include <dev/acpica/acpi_pcibvar.h>
45
46/*
47 * Hooks for the ACPI CA debugging infrastructure
48 */
49#define _COMPONENT	ACPI_BUS
50ACPI_MODULE_NAME("PCI_ACPI")
51
52struct acpi_hpcib_softc {
53    device_t		ap_dev;
54    ACPI_HANDLE		ap_handle;
55
56    int			ap_segment;	/* analagous to Alpha 'hose' */
57    int			ap_bus;		/* bios-assigned bus number */
58
59    ACPI_BUFFER		ap_prt;		/* interrupt routing table */
60};
61
62
63static int		acpi_pcib_acpi_probe(device_t bus);
64static int		acpi_pcib_acpi_attach(device_t bus);
65static int		acpi_pcib_acpi_resume(device_t bus);
66static int		acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
67static int		acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
68static u_int32_t	acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
69static void		acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
70					       u_int32_t data, int bytes);
71static int		acpi_pcib_acpi_route_interrupt(device_t pcib,
72    device_t dev, int pin);
73static struct resource *acpi_pcib_acpi_alloc_resource(device_t dev,
74  			    device_t child, int type, int *rid,
75			    u_long start, u_long end, u_long count,
76			    u_int flags);
77
78static device_method_t acpi_pcib_acpi_methods[] = {
79    /* Device interface */
80    DEVMETHOD(device_probe,		acpi_pcib_acpi_probe),
81    DEVMETHOD(device_attach,		acpi_pcib_acpi_attach),
82    DEVMETHOD(device_shutdown,		bus_generic_shutdown),
83    DEVMETHOD(device_suspend,		bus_generic_suspend),
84    DEVMETHOD(device_resume,		acpi_pcib_acpi_resume),
85
86    /* Bus interface */
87    DEVMETHOD(bus_print_child,		bus_generic_print_child),
88    DEVMETHOD(bus_read_ivar,		acpi_pcib_read_ivar),
89    DEVMETHOD(bus_write_ivar,		acpi_pcib_write_ivar),
90    DEVMETHOD(bus_alloc_resource,	acpi_pcib_acpi_alloc_resource),
91    DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
92    DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
93    DEVMETHOD(bus_deactivate_resource, 	bus_generic_deactivate_resource),
94    DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
95    DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
96
97    /* pcib interface */
98    DEVMETHOD(pcib_maxslots,		pcib_maxslots),
99    DEVMETHOD(pcib_read_config,		acpi_pcib_read_config),
100    DEVMETHOD(pcib_write_config,	acpi_pcib_write_config),
101    DEVMETHOD(pcib_route_interrupt,	acpi_pcib_acpi_route_interrupt),
102
103    {0, 0}
104};
105
106static driver_t acpi_pcib_acpi_driver = {
107    "pcib",
108    acpi_pcib_acpi_methods,
109    sizeof(struct acpi_hpcib_softc),
110};
111
112DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_acpi_driver, pcib_devclass, 0, 0);
113MODULE_DEPEND(acpi_pcib, acpi, 1, 1, 1);
114
115static int
116acpi_pcib_acpi_probe(device_t dev)
117{
118
119    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
120	!acpi_disabled("pci") &&
121	acpi_MatchHid(dev, "PNP0A03")) {
122
123	if (!pci_cfgregopen())
124		return(ENXIO);
125
126	/*
127	 * Set device description
128	 */
129	device_set_desc(dev, "ACPI Host-PCI bridge");
130	return(0);
131    }
132    return(ENXIO);
133}
134
135static int
136acpi_pcib_acpi_attach(device_t dev)
137{
138    struct acpi_hpcib_softc	*sc;
139    ACPI_STATUS			status;
140    u_int addr, slot, func, busok;
141    uint8_t busno;
142
143    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
144
145    sc = device_get_softc(dev);
146    sc->ap_dev = dev;
147    sc->ap_handle = acpi_get_handle(dev);
148
149    /*
150     * Get our base bus number by evaluating _BBN.
151     * If this doesn't work, we assume we're bus number 0.
152     *
153     * XXX note that it may also not exist in the case where we are
154     *     meant to use a private configuration space mechanism for this bus,
155     *     so we should dig out our resources and check to see if we have
156     *     anything like that.  How do we do this?
157     * XXX If we have the requisite information, and if we don't think the
158     *     default PCI configuration space handlers can deal with this bus,
159     *     we should attach our own handler.
160     * XXX invoke _REG on this for the PCI config space address space?
161     * XXX It seems many BIOS's with multiple Host-PCI bridges do not set
162     *     _BBN correctly.  They set _BBN to zero for all bridges.  Thus,
163     *     if _BBN is zero and pcib0 already exists, we try to read our
164     *     bus number from the configuration registers at address _ADR.
165     */
166    status = acpi_GetInteger(sc->ap_handle, "_BBN", &sc->ap_bus);
167    if (ACPI_FAILURE(status)) {
168	if (status != AE_NOT_FOUND) {
169	    device_printf(dev, "could not evaluate _BBN - %s\n",
170		AcpiFormatException(status));
171	    return_VALUE(ENXIO);
172	} else {
173	    /* if it's not found, assume 0 */
174	    sc->ap_bus = 0;
175	}
176    }
177
178    /*
179     * If the bus is zero and pcib0 already exists, read the bus number
180     * via PCI config space.
181     */
182    busok = 1;
183    if (sc->ap_bus == 0 && devclass_get_device(pcib_devclass, 0) != dev) {
184	busok = 0;
185	status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr);
186	if (ACPI_FAILURE(status)) {
187	    if (status != AE_NOT_FOUND) {
188		device_printf(dev, "could not evaluate _ADR - %s\n",
189		    AcpiFormatException(status));
190		return_VALUE(ENXIO);
191	    } else
192		device_printf(dev, "could not determine config space address\n");
193	} else {
194	    /* XXX: We assume bus 0. */
195	    slot = addr >> 16;
196	    func = addr & 0xffff;
197	    if (bootverbose)
198		device_printf(dev, "reading config registers from 0:%d:%d\n",
199		    slot, func);
200	    if (host_pcib_get_busno(pci_cfgregread, 0, slot, func, &busno) == 0)
201		device_printf(dev, "could not read bus number from config space\n");
202	    else {
203		sc->ap_bus = busno;
204		busok = 1;
205	    }
206	}
207    }
208
209    /*
210     * If nothing else worked, hope that ACPI at least lays out the
211     * host-PCI bridges in order and that as a result our unit number
212     * is actually our bus number.  There are several reasons this
213     * might not be true.
214     */
215    if (busok == 0) {
216	sc->ap_bus = device_get_unit(dev);
217	device_printf(dev, "trying bus number %d\n", sc->ap_bus);
218    }
219
220    /*
221     * Get our segment number by evaluating _SEG
222     * It's OK for this to not exist.
223     */
224    if (ACPI_FAILURE(status = acpi_GetInteger(sc->ap_handle, "_SEG", &sc->ap_segment))) {
225	if (status != AE_NOT_FOUND) {
226	    device_printf(dev, "could not evaluate _SEG - %s\n", AcpiFormatException(status));
227	    return_VALUE(ENXIO);
228	}
229	/* if it's not found, assume 0 */
230	sc->ap_segment = 0;
231    }
232
233    return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus));
234}
235
236static int
237acpi_pcib_acpi_resume(device_t dev)
238{
239    struct acpi_hpcib_softc	*sc = device_get_softc(dev);
240
241    return (acpi_pcib_resume(dev, &sc->ap_prt, sc->ap_bus));
242}
243
244/*
245 * Support for standard PCI bridge ivars.
246 */
247static int
248acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
249{
250    struct acpi_hpcib_softc	*sc = device_get_softc(dev);
251
252    switch (which) {
253    case  PCIB_IVAR_BUS:
254	*result = sc->ap_bus;
255	return(0);
256    case  ACPI_IVAR_HANDLE:
257	*result = (uintptr_t)sc->ap_handle;
258	return(0);
259    }
260    return(ENOENT);
261}
262
263static int
264acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
265{
266    struct acpi_hpcib_softc 	*sc = device_get_softc(dev);
267
268    switch (which) {
269    case  PCIB_IVAR_BUS:
270	sc->ap_bus = value;
271	return(0);
272    }
273    return(ENOENT);
274}
275
276static u_int32_t
277acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes)
278{
279    return(pci_cfgregread(bus, slot, func, reg, bytes));
280}
281
282static void
283acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg, u_int32_t data, int bytes)
284{
285    pci_cfgregwrite(bus, slot, func, reg, data, bytes);
286}
287
288static int
289acpi_pcib_acpi_route_interrupt(device_t pcib, device_t dev, int pin)
290{
291    struct acpi_hpcib_softc *sc;
292
293    /* find the bridge softc */
294    sc = device_get_softc(pcib);
295    return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt));
296}
297
298struct resource *
299acpi_pcib_acpi_alloc_resource(device_t dev, device_t child, int type, int *rid,
300  u_long start, u_long end, u_long count, u_int flags)
301{
302	/*
303	 * If no memory preference is given, use upper 256MB slot most
304	 * bioses use for their memory window.  Typically other bridges
305	 * before us get in the way to assert their preferences on memory.
306	 * Hardcoding like this sucks, so a more MD/MI way needs to be
307	 * found to do it.
308	 */
309	if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL)
310		start = 0xf0000000;
311	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
312	    count, flags));
313}
314