#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/rman.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpi_pcibvar.h>
#include <bus/pci/pcivar.h>
#include <bus/pci/pcireg.h>
#include <bus/pci/pcib_private.h>
#include "pcib_if.h"
#define _COMPONENT ACPI_BUS
ACPI_MODULE_NAME("PCI_PCI")
struct acpi_pcib_softc {
struct pcib_softc ap_pcibsc;
ACPI_HANDLE ap_handle;
ACPI_BUFFER ap_prt;
};
static int acpi_pcib_pci_probe(device_t bus);
static int acpi_pcib_pci_attach(device_t bus);
static int acpi_pcib_pci_resume(device_t bus);
static int acpi_pcib_read_ivar(device_t dev, device_t child,
int which, uintptr_t *result);
static int acpi_pcib_pci_route_interrupt(device_t pcib,
device_t dev, int pin);
static device_method_t acpi_pcib_pci_methods[] = {
DEVMETHOD(device_probe, acpi_pcib_pci_probe),
DEVMETHOD(device_attach, acpi_pcib_pci_attach),
DEVMETHOD(device_resume, acpi_pcib_pci_resume),
DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar),
DEVMETHOD(pcib_route_interrupt, acpi_pcib_pci_route_interrupt),
DEVMETHOD_END
};
static devclass_t pcib_devclass;
DEFINE_CLASS_1(pcib, acpi_pcib_pci_driver, acpi_pcib_pci_methods,
sizeof(struct acpi_pcib_softc), pcib_driver);
DRIVER_MODULE(acpi_pcib, pci, acpi_pcib_pci_driver, pcib_devclass, NULL, NULL);
MODULE_DEPEND(acpi_pcib, acpi, 1, 1, 1);
static int
acpi_pcib_pci_probe(device_t dev)
{
int error;
if (pci_get_class(dev) != PCIC_BRIDGE ||
pci_get_subclass(dev) != PCIS_BRIDGE_PCI ||
acpi_disabled("pci"))
return (ENXIO);
error = acpi_pcib_probe(dev);
if (error)
return (error);
device_set_desc(dev, "ACPI PCI-PCI bridge");
return (-100);
}
static int
acpi_pcib_pci_attach(device_t dev)
{
struct acpi_pcib_softc *sc;
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
pcib_attach_common(dev);
sc = device_get_softc(dev);
sc->ap_handle = acpi_get_handle(dev);
return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.secbus));
}
static int
acpi_pcib_pci_resume(device_t dev)
{
return (acpi_pcib_resume(dev));
}
static int
acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct acpi_pcib_softc *sc = device_get_softc(dev);
switch (which) {
case ACPI_IVAR_HANDLE:
*result = (uintptr_t)sc->ap_handle;
return (0);
}
return (pcib_read_ivar(dev, child, which, result));
}
static int
acpi_pcib_pci_route_interrupt(device_t pcib, device_t dev, int pin)
{
struct acpi_pcib_softc *sc = device_get_softc(pcib);
if (sc->ap_prt.Pointer == NULL) {
device_printf(pcib, "No _PRT found, routing with pci\n");
return (pcib_route_interrupt(pcib, dev, pin));
} else {
return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt));
}
}