xref: /freebsd/sys/dev/acpica/acpi_pcib.c (revision ee2ea5ceafed78a5bd9810beb9e3ca927180c226)
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$
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
47 ACPI_MODULE_NAME("PCI")
48 
49 struct 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 
59 static int		acpi_pcib_probe(device_t bus);
60 static int		acpi_pcib_attach(device_t bus);
61 static int		acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
62 static int		acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
63 static int		acpi_pcib_maxslots(device_t dev);
64 static u_int32_t	acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
65 static void		acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
66 					       u_int32_t data, int bytes);
67 static int		acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin);
68 
69 static 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 
97 static driver_t acpi_pcib_driver = {
98     "acpi_pcib",
99     acpi_pcib_methods,
100     sizeof(struct acpi_pcib_softc),
101 };
102 
103 static devclass_t acpi_pcib_devclass;
104 DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
105 
106 static int
107 acpi_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 
123 static int
124 acpi_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(__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  */
241 static int
242 acpi_pcib_maxslots(device_t dev)
243 {
244     return(PCI_SLOTMAX);
245 }
246 
247 /*
248  * Support for standard PCI bridge ivars.
249  */
250 static int
251 acpi_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 
263 static int
264 acpi_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 
276 static u_int32_t
277 acpi_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 
282 static void
283 acpi_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  */
295 static int
296 acpi_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(__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