acpi_pcib_acpi.c revision 96926
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 96926 2002-05-19 06:16:47Z peter $
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 <pci/pcivar.h>
41#include "pcib_if.h"
42
43/*
44 * Hooks for the ACPI CA debugging infrastructure
45 */
46#define _COMPONENT	ACPI_BUS
47ACPI_MODULE_NAME("PCI")
48
49struct acpi_pcib_softc {
50    device_t		ap_dev;
51    ACPI_HANDLE		ap_handle;
52
53    int			ap_segment;	/* analagous to Alpha 'hose' */
54    int			ap_bus;		/* bios-assigned bus number */
55
56    ACPI_BUFFER		ap_prt;		/* interrupt routing table */
57};
58
59static int		acpi_pcib_probe(device_t bus);
60static int		acpi_pcib_attach(device_t bus);
61static int		acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
62static int		acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
63static int		acpi_pcib_maxslots(device_t dev);
64static u_int32_t	acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
65static void		acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
66					       u_int32_t data, int bytes);
67static int		acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin);
68
69static device_method_t acpi_pcib_methods[] = {
70    /* Device interface */
71    DEVMETHOD(device_probe,		acpi_pcib_probe),
72    DEVMETHOD(device_attach,		acpi_pcib_attach),
73    DEVMETHOD(device_shutdown,		bus_generic_shutdown),
74    DEVMETHOD(device_suspend,		bus_generic_suspend),
75    DEVMETHOD(device_resume,		bus_generic_resume),
76
77    /* Bus interface */
78    DEVMETHOD(bus_print_child,		bus_generic_print_child),
79    DEVMETHOD(bus_read_ivar,		acpi_pcib_read_ivar),
80    DEVMETHOD(bus_write_ivar,		acpi_pcib_write_ivar),
81    DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
82    DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
83    DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
84    DEVMETHOD(bus_deactivate_resource, 	bus_generic_deactivate_resource),
85    DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
86    DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
87
88    /* pcib interface */
89    DEVMETHOD(pcib_maxslots,		acpi_pcib_maxslots),
90    DEVMETHOD(pcib_read_config,		acpi_pcib_read_config),
91    DEVMETHOD(pcib_write_config,	acpi_pcib_write_config),
92    DEVMETHOD(pcib_route_interrupt,	acpi_pcib_route_interrupt),
93
94    {0, 0}
95};
96
97static driver_t acpi_pcib_driver = {
98    "acpi_pcib",
99    acpi_pcib_methods,
100    sizeof(struct acpi_pcib_softc),
101};
102
103static devclass_t acpi_pcib_devclass;
104DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
105
106static int
107acpi_pcib_probe(device_t dev)
108{
109
110    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
111	!acpi_disabled("pci") &&
112	acpi_MatchHid(dev, "PNP0A03")) {
113
114	/*
115	 * Set device description
116	 */
117	device_set_desc(dev, "Host-PCI bridge");
118	return(0);
119    }
120    return(ENXIO);
121}
122
123static int
124acpi_pcib_attach(device_t dev)
125{
126    struct acpi_pcib_softc	*sc;
127    device_t			child;
128    ACPI_STATUS			status;
129    int				result;
130
131    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
132
133    sc = device_get_softc(dev);
134    sc->ap_dev = dev;
135    sc->ap_handle = acpi_get_handle(dev);
136
137    /*
138     * Don't attach if we're not really there.
139     *
140     * XXX this isn't entirely correct, since we may be a PCI bus
141     * on a hot-plug docking station, etc.
142     */
143    if (!acpi_DeviceIsPresent(dev))
144	return_VALUE(ENXIO);
145
146    /*
147     * Get our segment number by evaluating _SEG
148     * It's OK for this to not exist.
149     */
150    if (ACPI_FAILURE(status = acpi_EvaluateInteger(sc->ap_handle, "_SEG", &sc->ap_segment))) {
151	if (status != AE_NOT_FOUND) {
152	    device_printf(dev, "could not evaluate _SEG - %s\n", AcpiFormatException(status));
153	    return_VALUE(ENXIO);
154	}
155	/* if it's not found, assume 0 */
156	sc->ap_segment = 0;
157    }
158
159    /*
160     * Get our base bus number by evaluating _BBN.  If that doesn't work, try _ADR.
161     * If this doesn't work, we assume we're bus number 0.
162     *
163     * XXX note that it may also not exist in the case where we are
164     *     meant to use a private configuration space mechanism for this bus,
165     *     so we should dig out our resources and check to see if we have
166     *     anything like that.  How do we do this?
167     * XXX If we have the requisite information, and if we don't think the
168     *     default PCI configuration space handlers can deal with this bus,
169     *     we should attach our own handler.
170     * XXX invoke _REG on this for the PCI config space address space?
171     */
172    if (ACPI_FAILURE(status = acpi_EvaluateInteger(sc->ap_handle, "_BBN", &sc->ap_bus))) {
173	if (status != AE_NOT_FOUND) {
174	    device_printf(dev, "could not evaluate _BBN - %s\n", AcpiFormatException(status));
175	    return_VALUE(ENXIO);
176	}
177	if (ACPI_FAILURE(status = acpi_EvaluateInteger(sc->ap_handle, "_ADR", &sc->ap_bus))) {
178	    if (status != AE_NOT_FOUND) {
179		device_printf(dev, "could not evaluate _ADR - %s\n", AcpiFormatException(status));
180		return_VALUE(ENXIO);
181	    }
182	} else {
183	    /* if it's not found, assume 0 */
184	    sc->ap_bus = 0;
185	}
186    }
187
188    /*
189     * Make sure that this bus hasn't already been found.
190     */
191    if (devclass_get_device(devclass_find("pci"), sc->ap_bus) != NULL) {
192	device_printf(dev, "we have duplicate bus number %d - not probing bus\n", sc->ap_bus);
193	return_VALUE(0);
194    }
195
196    /*
197     * Get the PCI interrupt routing table for this bus.
198     */
199    sc->ap_prt.Length = ACPI_ALLOCATE_BUFFER;
200    if (ACPI_FAILURE(status = AcpiGetIrqRoutingTable(sc->ap_handle, &sc->ap_prt))) {
201	device_printf(dev, "could not get PCI interrupt routing table - %s\n", AcpiFormatException(status));
202	/* this is not an error, but it may reduce functionality */
203    }
204
205    /*
206     * Attach the PCI bus proper.
207     */
208    if ((child = device_add_child(dev, "pci", sc->ap_bus)) == NULL) {
209	device_printf(device_get_parent(dev), "couldn't attach pci bus");
210	return_VALUE(ENXIO);
211    }
212
213    /*
214     * Now go scan the bus.
215     *
216     * XXX It would be nice to defer this and count on the nexus getting it
217     * after the first pass, but this does not seem to be reliable.
218     */
219    result = bus_generic_attach(dev);
220
221    /*
222     * Now that we have established the device tree, we need to scan our children
223     * and hook them up with their corresponding device nodes.
224     *
225     * This is not trivial.
226     */
227
228    /*
229     * XXX cross-reference our children to attached devices on the child bus
230     *     via _ADR, so we can provide power management.
231     */
232    /* XXX implement */
233
234    return_VALUE(result);
235}
236
237/*
238 * ACPI doesn't tell us how many slots there are, so use the standard
239 * maximum.
240 */
241static int
242acpi_pcib_maxslots(device_t dev)
243{
244    return(PCI_SLOTMAX);
245}
246
247/*
248 * Support for standard PCI bridge ivars.
249 */
250static int
251acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
252{
253    struct acpi_pcib_softc	*sc = device_get_softc(dev);
254
255    switch (which) {
256    case  PCIB_IVAR_BUS:
257	*result = sc->ap_bus;
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_pcib_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
288/*
289 * Route an interrupt for a child of the bridge.
290 *
291 * XXX clean up error messages
292 *
293 * XXX this function is somewhat bulky
294 */
295static int
296acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
297{
298    struct acpi_pcib_softc	*sc;
299    ACPI_PCI_ROUTING_TABLE	*prt;
300    ACPI_HANDLE			lnkdev;
301    ACPI_BUFFER			crsbuf, prsbuf;
302    ACPI_RESOURCE		*crsres, *prsres, resbuf;
303    ACPI_DEVICE_INFO		devinfo;
304    ACPI_STATUS			status;
305    u_int8_t			*prtp;
306    device_t			*devlist;
307    int				devcount;
308    int				bus;
309    int				interrupt;
310    int				i;
311    uintptr_t			up;
312
313    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
314
315    crsbuf.Pointer = NULL;
316    prsbuf.Pointer = NULL;
317    devlist = NULL;
318    interrupt = 255;
319
320    /* ACPI numbers pins 0-3, not 1-4 like the BIOS */
321    pin--;
322
323    /* find the bridge softc */
324    if (devclass_get_devices(acpi_pcib_devclass, &devlist, &devcount))
325	goto out;
326    BUS_READ_IVAR(pcib, pcib, PCIB_IVAR_BUS, &up);
327    bus = up;
328    sc = NULL;
329    for (i = 0; i < devcount; i++) {
330	sc = device_get_softc(*(devlist + i));
331	if (sc->ap_bus == bus)
332	    break;
333	sc = NULL;
334    }
335    if (sc == NULL)			/* not one of ours */
336	goto out;
337    prtp = sc->ap_prt.Pointer;
338    if (prtp == NULL)			/* didn't get routing table */
339	goto out;
340
341    /* scan the table looking for this device */
342    for (;;) {
343	prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
344
345	if (prt->Length == 0)		/* end of table */
346	    goto out;
347
348	/*
349	 * Compare the slot number (high word of Address) and pin number
350	 * (note that ACPI uses 0 for INTA) to check for a match.
351	 *
352	 * Note that the low word of the Address field (function number)
353	 * is required by the specification to be 0xffff.  We don't risk
354	 * checking it here.
355	 */
356	if ((((prt->Address & 0xffff0000) >> 16) == pci_get_slot(dev)) &&
357	    (prt->Pin == pin)) {
358	    if (bootverbose)
359		device_printf(sc->ap_dev, "matched entry for %d.%d.INT%c (source %s)\n",
360			      pci_get_bus(dev), pci_get_slot(dev), 'A' + pin, prt->Source);
361	    break;
362	}
363
364	/* skip to next entry */
365	prtp += prt->Length;
366    }
367
368    /*
369     * If source is empty/NULL, the source index is the global IRQ number.
370     */
371    if ((prt->Source == NULL) || (prt->Source[0] == '\0')) {
372	if (bootverbose)
373	    device_printf(sc->ap_dev, "device is hardwired to IRQ %d\n", prt->SourceIndex);
374	interrupt = prt->SourceIndex;
375	goto out;
376    }
377
378    /*
379     * We have to find the source device (PCI interrupt link device)
380     */
381    if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
382	device_printf(sc->ap_dev, "couldn't find PCI interrupt link device %s\n", prt->Source);
383	goto out;
384    }
385
386    /*
387     * Verify that this is a PCI link device, and that it's present.
388     */
389    if (ACPI_FAILURE(AcpiGetObjectInfo(lnkdev, &devinfo))) {
390	device_printf(sc->ap_dev, "couldn't validate PCI interrupt link device %s\n", prt->Source);
391	goto out;
392    }
393    if (!(devinfo.Valid & ACPI_VALID_HID) || strcmp("PNP0C0F", devinfo.HardwareId)) {
394	device_printf(sc->ap_dev, "PCI interrupt link device %s has wrong _HID (%s)\n",
395		      prt->Source, devinfo.HardwareId);
396	goto out;
397    }
398    if (!acpi_DeviceIsPresent(sc->ap_dev)) {
399	device_printf(sc->ap_dev, "PCI interrupt link device %s not present\n",
400		      prt->Source);
401	goto out;
402    }
403
404    /*
405     * Get the current and possible resources for the interrupt link device.
406     */
407    crsbuf.Length = ACPI_ALLOCATE_BUFFER;
408    if (ACPI_FAILURE(status = AcpiGetCurrentResources(lnkdev, &crsbuf))) {
409	device_printf(sc->ap_dev, "couldn't get PCI interrupt link device _CRS data - %s\n",
410		      AcpiFormatException(status));
411	goto out;	/* this is fatal */
412    }
413    prsbuf.Length = ACPI_ALLOCATE_BUFFER;
414    if (ACPI_FAILURE(status = AcpiGetPossibleResources(lnkdev, &prsbuf))) {
415	device_printf(sc->ap_dev, "couldn't get PCI interrupt link device _PRS data - %s\n",
416		      AcpiFormatException(status));
417	/* this is not fatal, since it may be hardwired */
418    }
419    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "got %d bytes for %s._CRS\n", crsbuf.Length, acpi_name(lnkdev)));
420    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "got %d bytes for %s._PRS\n", prsbuf.Length, acpi_name(lnkdev)));
421
422    /*
423     * The interrupt may already be routed, so check _CRS first.  We don't check the
424     * 'decoding' bit in the _STA result, since there's nothing in the spec that
425     * mandates it be set, however some BIOS' will set it if the decode is active.
426     *
427     * The Source Index points to the particular resource entry we're interested in.
428     */
429    if (ACPI_FAILURE(acpi_FindIndexedResource(&crsbuf, prt->SourceIndex, &crsres))) {
430	device_printf(sc->ap_dev, "_CRS buffer corrupt, cannot route interrupt\n");
431	goto out;
432    }
433
434    /* type-check the resource we've got */
435    if (crsres->Id != ACPI_RSTYPE_IRQ) {    /* XXX ACPI_RSTYPE_EXT_IRQ */
436	device_printf(sc->ap_dev, "_CRS resource entry has unsupported type %d\n", crsres->Id);
437	goto out;
438    }
439
440    /* if there's more than one interrupt, we are confused */
441    if (crsres->Data.Irq.NumberOfInterrupts > 1) {
442	device_printf(sc->ap_dev, "device has too many interrupts (%d)\n", crsres->Data.Irq.NumberOfInterrupts);
443	goto out;
444    }
445
446    /*
447     * If there's only one interrupt, and it's not zero, then we're already routed.
448     *
449     * Note that we could also check the 'decoding' bit in _STA, but can't depend on
450     * it since it's not part of the spec.
451     *
452     * XXX check ASL examples to see if this is an acceptable set of tests
453     */
454    if ((crsres->Data.Irq.NumberOfInterrupts == 1) && (crsres->Data.Irq.Interrupts[0] != 0)) {
455	device_printf(sc->ap_dev, "device is routed to IRQ %d\n", crsres->Data.Irq.Interrupts[0]);
456	interrupt = crsres->Data.Irq.Interrupts[0];
457	goto out;
458    }
459
460    /*
461     * There isn't an interrupt, so we have to look at _PRS to get one.
462     * Get the set of allowed interrupts from the _PRS resource indexed by SourceIndex.
463     */
464    if (prsbuf.Pointer == NULL) {
465	device_printf(sc->ap_dev, "device has no routed interrupt and no _PRS on PCI interrupt link device\n");
466	goto out;
467    }
468    if (ACPI_FAILURE(acpi_FindIndexedResource(&prsbuf, prt->SourceIndex, &prsres))) {
469	device_printf(sc->ap_dev, "_PRS buffer corrupt, cannot route interrupt\n");
470	goto out;
471    }
472
473    /* type-check the resource we've got */
474    if (prsres->Id != ACPI_RSTYPE_IRQ) {    /* XXX ACPI_RSTYPE_EXT_IRQ */
475	device_printf(sc->ap_dev, "_PRS resource entry has unsupported type %d\n", prsres->Id);
476	goto out;
477    }
478
479    /* there has to be at least one interrupt available */
480    if (prsres->Data.Irq.NumberOfInterrupts < 1) {
481	device_printf(sc->ap_dev, "device has no interrupts\n");
482	goto out;
483    }
484
485    /*
486     * Pick an interrupt to use.  Note that a more scientific approach than just
487     * taking the first one available would be desirable.
488     *
489     * The PCI BIOS $PIR table offers "preferred PCI interrupts", but ACPI doesn't
490     * seem to offer a similar mechanism, so picking a "good" interrupt here is a
491     * difficult task.
492     *
493     * Build a resource buffer and pass it to AcpiSetCurrentResources to route the
494     * new interrupt.
495     */
496    device_printf(sc->ap_dev, "possible interrupts:");
497    for (i = 0; i < prsres->Data.Irq.NumberOfInterrupts; i++)
498	printf("  %d", prsres->Data.Irq.Interrupts[i]);
499    printf("\n");
500
501    if (crsbuf.Pointer != NULL)			/* should never happen */
502	AcpiOsFree(crsbuf.Pointer);
503    crsbuf.Pointer = NULL;
504    resbuf.Id = ACPI_RSTYPE_IRQ;
505    resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
506    resbuf.Data.Irq = prsres->Data.Irq;		/* structure copy other fields */
507    resbuf.Data.Irq.NumberOfInterrupts = 1;
508    resbuf.Data.Irq.Interrupts[0] = prsres->Data.Irq.Interrupts[0];	/* just take first... */
509    if (ACPI_FAILURE(status = acpi_AppendBufferResource(&crsbuf, &resbuf))) {
510	device_printf(sc->ap_dev, "couldn't route interrupt %d via %s, interupt resource build failed - %s\n",
511		      prsres->Data.Irq.Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
512	goto out;
513    }
514    if (ACPI_FAILURE(status = AcpiSetCurrentResources(lnkdev, &crsbuf))) {
515	device_printf(sc->ap_dev, "couldn't route interrupt %d via %s - %s\n",
516		      prsres->Data.Irq.Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
517	goto out;
518    }
519
520    /* successful, return the interrupt we just routed */
521    device_printf(sc->ap_dev, "routed interrupt %d via %s\n",
522		  prsres->Data.Irq.Interrupts[0], acpi_name(lnkdev));
523    interrupt = prsres->Data.Irq.Interrupts[0];
524
525 out:
526    if (devlist != NULL)
527	free(devlist, M_TEMP);
528    if (crsbuf.Pointer != NULL)
529	AcpiOsFree(crsbuf.Pointer);
530    if (prsbuf.Pointer != NULL)
531	AcpiOsFree(prsbuf.Pointer);
532
533    /* XXX APIC_IO interrupt mapping? */
534    return_VALUE(interrupt);
535}
536
537