#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcib_private.h>
#include <x86/mptable.h>
#include <x86/legacyvar.h>
#include <machine/pci_cfgreg.h>
#include "pcib_if.h"
static int
mptable_hostb_probe(device_t dev)
{
if (pci_cfgregopen() == 0)
return (ENXIO);
if (mptable_pci_probe_table(legacy_get_pcibus(dev)) != 0)
return (ENXIO);
device_set_desc(dev, "MPTable Host-PCI bridge");
return (0);
}
static int
mptable_hostb_attach(device_t dev)
{
mptable_pci_host_res_init(dev);
device_add_child(dev, "pci", DEVICE_UNIT_ANY);
bus_attach_children(dev);
return (0);
}
static int
mptable_is_isa_range(rman_res_t start, rman_res_t end)
{
if (end >= 0x10000)
return (0);
if ((start & 0xfc00) != (end & 0xfc00))
return (0);
start &= ~0xfc00;
end &= ~0xfc00;
return (start >= 0x100 && end <= 0x3ff);
}
static int
mptable_is_vga_range(rman_res_t start, rman_res_t end)
{
if (end >= 0x10000)
return (0);
if ((start & 0xfc00) != (end & 0xfc00))
return (0);
start &= ~0xfc00;
end &= ~0xfc00;
return (pci_is_vga_ioport_range(start, end));
}
static struct resource *
mptable_hostb_alloc_resource(device_t dev, device_t child, int type, int rid,
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
{
struct mptable_hostb_softc *sc;
if (type == PCI_RES_BUS)
return (pci_domain_alloc_bus(0, child, rid, start, end, count,
flags));
sc = device_get_softc(dev);
if (type == SYS_RES_IOPORT && start + count - 1 == end) {
if (mptable_is_isa_range(start, end)) {
switch (sc->sc_decodes_isa_io) {
case -1:
return (NULL);
case 1:
return (bus_generic_alloc_resource(dev, child,
type, rid, start, end, count, flags));
default:
break;
}
}
if (mptable_is_vga_range(start, end)) {
switch (sc->sc_decodes_vga_io) {
case -1:
return (NULL);
case 1:
return (bus_generic_alloc_resource(dev, child,
type, rid, start, end, count, flags));
default:
break;
}
}
}
start = hostb_alloc_start(type, start, end, count);
return (pcib_host_res_alloc(&sc->sc_host_res, child, type, rid, start,
end, count, flags));
}
static int
mptable_hostb_adjust_resource(device_t dev, device_t child,
struct resource *r, rman_res_t start, rman_res_t end)
{
struct mptable_hostb_softc *sc;
if (rman_get_type(r) == PCI_RES_BUS)
return (pci_domain_adjust_bus(0, child, r, start, end));
sc = device_get_softc(dev);
return (pcib_host_res_adjust(&sc->sc_host_res, child, r, start, end));
}
static device_method_t mptable_hostb_methods[] = {
DEVMETHOD(device_probe, mptable_hostb_probe),
DEVMETHOD(device_attach, mptable_hostb_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar),
DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, mptable_hostb_alloc_resource),
DEVMETHOD(bus_adjust_resource, mptable_hostb_adjust_resource),
DEVMETHOD(bus_release_resource, legacy_pcib_release_resource),
DEVMETHOD(bus_activate_resource, legacy_pcib_activate_resource),
DEVMETHOD(bus_deactivate_resource, legacy_pcib_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots),
DEVMETHOD(pcib_read_config, legacy_pcib_read_config),
DEVMETHOD(pcib_write_config, legacy_pcib_write_config),
DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt),
DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi),
DEVMETHOD(pcib_release_msi, pcib_release_msi),
DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix),
DEVMETHOD(pcib_release_msix, pcib_release_msix),
DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi),
DEVMETHOD_END
};
DEFINE_CLASS_0(pcib, mptable_hostb_driver, mptable_hostb_methods,
sizeof(struct mptable_hostb_softc));
DRIVER_MODULE(mptable_pcib, legacy, mptable_hostb_driver, 0, 0);
static int
mptable_pcib_probe(device_t dev)
{
int bus;
if ((pci_get_class(dev) != PCIC_BRIDGE) ||
(pci_get_subclass(dev) != PCIS_BRIDGE_PCI))
return (ENXIO);
bus = pci_read_config(dev, PCIR_SECBUS_1, 1);
if (bus == 0)
return (ENXIO);
if (mptable_pci_probe_table(bus) != 0)
return (ENXIO);
device_set_desc(dev, "MPTable PCI-PCI bridge");
return (-1000);
}
static device_method_t mptable_pcib_pci_methods[] = {
DEVMETHOD(device_probe, mptable_pcib_probe),
DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt),
{0, 0}
};
DEFINE_CLASS_1(pcib, mptable_pcib_driver, mptable_pcib_pci_methods,
sizeof(struct pcib_softc), pcib_driver);
DRIVER_MODULE(mptable_pcib, pci, mptable_pcib_driver, 0, 0);