aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/include/resource.h3
-rw-r--r--sys/dev/acpica/acpi_pcib_acpi.c87
-rw-r--r--sys/dev/acpica/acpi_pcib_pci.c2
-rw-r--r--sys/dev/cardbus/cardbus.c19
-rw-r--r--sys/dev/cardbus/cardbusvar.h3
-rw-r--r--sys/dev/pccbb/pccbb.c7
-rw-r--r--sys/dev/pccbb/pccbb_isa.c3
-rw-r--r--sys/dev/pccbb/pccbb_pci.c95
-rw-r--r--sys/dev/pccbb/pccbbvar.h3
-rw-r--r--sys/dev/pci/pci.c216
-rw-r--r--sys/dev/pci/pci_pci.c238
-rw-r--r--sys/dev/pci/pci_private.h3
-rw-r--r--sys/dev/pci/pci_subr.c99
-rw-r--r--sys/dev/pci/pcib_private.h34
-rw-r--r--sys/i386/include/resource.h3
-rw-r--r--sys/sparc64/pci/apb.c12
-rw-r--r--sys/x86/include/legacyvar.h4
-rw-r--r--sys/x86/pci/pci_bus.c38
-rw-r--r--sys/x86/pci/qpi.c20
-rw-r--r--sys/x86/x86/mptable_pci.c13
20 files changed, 835 insertions, 67 deletions
diff --git a/sys/amd64/include/resource.h b/sys/amd64/include/resource.h
index edde5eb29908..dfcc902a7316 100644
--- a/sys/amd64/include/resource.h
+++ b/sys/amd64/include/resource.h
@@ -40,5 +40,8 @@
#define SYS_RES_DRQ 2 /* isa dma lines */
#define SYS_RES_MEMORY 3 /* i/o memory */
#define SYS_RES_IOPORT 4 /* i/o ports */
+#ifdef NEW_PCIB
+#define PCI_RES_BUS 5 /* PCI bus numbers */
+#endif
#endif /* !_MACHINE_RESOURCE_H_ */
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c
index 882834df61d9..545f6411ecb4 100644
--- a/sys/dev/acpica/acpi_pcib_acpi.c
+++ b/sys/dev/acpica/acpi_pcib_acpi.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <dev/acpica/acpivar.h>
#include <machine/pci_cfgreg.h>
+#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcib_private.h>
#include "pcib_if.h"
@@ -96,6 +97,11 @@ static struct resource *acpi_pcib_acpi_alloc_resource(device_t dev,
static int acpi_pcib_acpi_adjust_resource(device_t dev,
device_t child, int type, struct resource *r,
u_long start, u_long end);
+#ifdef PCI_RES_BUS
+static int acpi_pcib_acpi_release_resource(device_t dev,
+ device_t child, int type, int rid,
+ struct resource *r);
+#endif
#endif
static device_method_t acpi_pcib_acpi_methods[] = {
@@ -115,7 +121,11 @@ static device_method_t acpi_pcib_acpi_methods[] = {
#else
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
#endif
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ DEVMETHOD(bus_release_resource, acpi_pcib_acpi_release_resource),
+#else
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
@@ -271,6 +281,20 @@ acpi_pcib_producer_handler(ACPI_RESOURCE *res, void *context)
}
#endif
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static int
+first_decoded_bus(struct acpi_hpcib_softc *sc, u_long *startp)
+{
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(&sc->ap_host_res.hr_rl, PCI_RES_BUS, 0);
+ if (rle == NULL)
+ return (ENXIO);
+ *startp = rle->start;
+ return (0);
+}
+#endif
+
static int
acpi_pcib_acpi_attach(device_t dev)
{
@@ -278,6 +302,11 @@ acpi_pcib_acpi_attach(device_t dev)
ACPI_STATUS status;
static int bus0_seen = 0;
u_int slot, func, busok;
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ struct resource *bus_res;
+ u_long start;
+ int rid;
+#endif
uint8_t busno;
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -389,6 +418,39 @@ acpi_pcib_acpi_attach(device_t dev)
}
}
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ /*
+ * If nothing else worked, hope that ACPI at least lays out the
+ * Host-PCI bridges in order and that as a result the next free
+ * bus number is our bus number.
+ */
+ if (busok == 0) {
+ /*
+ * If we have a region of bus numbers, use the first
+ * number for our bus.
+ */
+ if (first_decoded_bus(sc, &start) == 0)
+ sc->ap_bus = start;
+ else {
+ rid = 0;
+ bus_res = pci_domain_alloc_bus(sc->ap_segment, dev, &rid, 0,
+ PCI_BUSMAX, 1, 0);
+ if (bus_res == NULL) {
+ device_printf(dev,
+ "could not allocate bus number\n");
+ pcib_host_res_free(dev, &sc->ap_host_res);
+ return (ENXIO);
+ }
+ sc->ap_bus = rman_get_start(bus_res);
+ pci_domain_release_bus(sc->ap_segment, dev, rid, bus_res);
+ }
+ } else {
+#ifdef INVARIANTS
+ if (first_decoded_bus(sc, &start) == 0)
+ KASSERT(start == sc->ap_bus, ("bus number mismatch"));
+#endif
+ }
+#else
/*
* If nothing else worked, hope that ACPI at least lays out the
* host-PCI bridges in order and that as a result our unit number
@@ -399,6 +461,7 @@ acpi_pcib_acpi_attach(device_t dev)
sc->ap_bus = device_get_unit(dev);
device_printf(dev, "trying bus number %d\n", sc->ap_bus);
}
+#endif
/* If this is bus 0 on segment 0, note that it has been seen already. */
if (sc->ap_segment == 0 && sc->ap_bus == 0)
@@ -534,6 +597,11 @@ acpi_pcib_acpi_alloc_resource(device_t dev, device_t child, int type, int *rid,
#ifdef NEW_PCIB
sc = device_get_softc(dev);
+#ifdef PCI_RES_BUS
+ if (type == PCI_RES_BUS)
+ return (pci_domain_alloc_bus(sc->ap_segment, child, rid, start, end,
+ count, flags));
+#endif
res = pcib_host_res_alloc(&sc->ap_host_res, child, type, rid, start, end,
count, flags);
@@ -562,7 +630,26 @@ acpi_pcib_acpi_adjust_resource(device_t dev, device_t child, int type,
struct acpi_hpcib_softc *sc;
sc = device_get_softc(dev);
+#ifdef PCI_RES_BUS
+ if (type == PCI_RES_BUS)
+ return (pci_domain_adjust_bus(sc->ap_segment, child, r, start,
+ end));
+#endif
return (pcib_host_res_adjust(&sc->ap_host_res, child, type, r, start,
end));
}
+
+#ifdef PCI_RES_BUS
+int
+acpi_pcib_acpi_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct acpi_hpcib_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (type == PCI_RES_BUS)
+ return (pci_domain_release_bus(sc->ap_segment, child, rid, r));
+ return (bus_generic_release_resource(dev, child, type, rid, r));
+}
+#endif
#endif
diff --git a/sys/dev/acpica/acpi_pcib_pci.c b/sys/dev/acpica/acpi_pcib_pci.c
index de26a4a55fd6..d3f4cbca3b2b 100644
--- a/sys/dev/acpica/acpi_pcib_pci.c
+++ b/sys/dev/acpica/acpi_pcib_pci.c
@@ -120,7 +120,7 @@ acpi_pcib_pci_attach(device_t dev)
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));
+ return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.bus.sec));
}
static int
diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c
index 608c1fe1d3f8..00d4a19e8cf6 100644
--- a/sys/dev/cardbus/cardbus.c
+++ b/sys/dev/cardbus/cardbus.c
@@ -96,17 +96,36 @@ static int
cardbus_attach(device_t cbdev)
{
struct cardbus_softc *sc;
+#ifdef PCI_RES_BUS
+ int rid;
+#endif
sc = device_get_softc(cbdev);
sc->sc_dev = cbdev;
+#ifdef PCI_RES_BUS
+ rid = 0;
+ sc->sc_bus = bus_alloc_resource(cbdev, PCI_RES_BUS, &rid,
+ pcib_get_bus(cbdev), pcib_get_bus(cbdev), 1, 0);
+ if (sc->sc_bus == NULL) {
+ device_printf(cbdev, "failed to allocate bus number\n");
+ return (ENXIO);
+ }
+#endif
return (0);
}
static int
cardbus_detach(device_t cbdev)
{
+#ifdef PCI_RES_BUS
+ struct cardbus_softc *sc;
+#endif
cardbus_detach_card(cbdev);
+#ifdef PCI_RES_BUS
+ sc = device_get_softc(cbdev);
+ (void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus);
+#endif
return (0);
}
diff --git a/sys/dev/cardbus/cardbusvar.h b/sys/dev/cardbus/cardbusvar.h
index 6264f6945af9..7730ffdb3396 100644
--- a/sys/dev/cardbus/cardbusvar.h
+++ b/sys/dev/cardbus/cardbusvar.h
@@ -69,6 +69,9 @@ struct cardbus_devinfo
struct cardbus_softc
{
device_t sc_dev;
+#ifdef PCI_RES_BUS
+ struct resource *sc_bus;
+#endif
};
/*
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 5715df3e6571..092d3efae773 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -97,6 +97,7 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
#include <dev/pccard/pccardreg.h>
#include <dev/pccard/pccardvar.h>
@@ -1548,7 +1549,7 @@ cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
*result = sc->domain;
return (0);
case PCIB_IVAR_BUS:
- *result = sc->secbus;
+ *result = sc->bus.sec;
return (0);
}
return (ENOENT);
@@ -1557,14 +1558,12 @@ cbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
int
cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
{
- struct cbb_softc *sc = device_get_softc(brdev);
switch (which) {
case PCIB_IVAR_DOMAIN:
return (EINVAL);
case PCIB_IVAR_BUS:
- sc->secbus = value;
- return (0);
+ return (EINVAL);
}
return (ENOENT);
}
diff --git a/sys/dev/pccbb/pccbb_isa.c b/sys/dev/pccbb/pccbb_isa.c
index fa990e00eea1..1d0a698da78b 100644
--- a/sys/dev/pccbb/pccbb_isa.c
+++ b/sys/dev/pccbb/pccbb_isa.c
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
#include <isa/isavar.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+
#include <dev/pccard/pccardreg.h>
#include <dev/pccard/pccardvar.h>
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index 0b02286f97cb..85928f9dfcc0 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
#include <dev/pccard/pccardreg.h>
#include <dev/pccard/pccardvar.h>
@@ -303,13 +304,15 @@ cbb_print_config(device_t dev)
static int
cbb_pci_attach(device_t brdev)
{
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
+ uint32_t pribus;
+#endif
struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
struct sysctl_ctx_list *sctx;
struct sysctl_oid *soid;
int rid;
device_t parent;
- uint32_t pribus;
parent = device_get_parent(brdev);
mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
@@ -318,9 +321,13 @@ cbb_pci_attach(device_t brdev)
sc->cbdev = NULL;
sc->exca[0].pccarddev = NULL;
sc->domain = pci_get_domain(brdev);
- sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
- sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
+ sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1);
+ sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
sc->pribus = pcib_get_bus(parent);
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
+ pcib_setup_secbus(brdev, &sc->bus, 1);
+#endif
SLIST_INIT(&sc->rl);
cbb_powerstate_d0(brdev);
@@ -352,9 +359,9 @@ cbb_pci_attach(device_t brdev)
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
- CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
+ CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
- CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
+ CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number");
#if 0
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory",
CTLFLAG_RD, &sc->subbus, 0, "Memory window open");
@@ -366,15 +373,16 @@ cbb_pci_attach(device_t brdev)
CTLFLAG_RD, &sc->subbus, 0, "io range 2 open");
#endif
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
/*
* This is a gross hack. We should be scanning the entire pci
* tree, assigning bus numbers in a way such that we (1) can
* reserve 1 extra bus just in case and (2) all sub busses
* are in an appropriate range.
*/
- DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus));
+ DEVPRINTF((brdev, "Secondary bus is %d\n", sc->bus.sec));
pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
- if (sc->secbus == 0 || sc->pribus != pribus) {
+ if (sc->bus.sec == 0 || sc->pribus != pribus) {
if (curr_bus_number <= sc->pribus)
curr_bus_number = sc->pribus + 1;
if (pribus != sc->pribus) {
@@ -382,13 +390,14 @@ cbb_pci_attach(device_t brdev)
sc->pribus));
pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
}
- sc->secbus = curr_bus_number++;
- sc->subbus = curr_bus_number++;
+ sc->bus.sec = curr_bus_number++;
+ sc->bus.sub = curr_bus_number++;
DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n",
- sc->secbus, sc->subbus));
- pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1);
- pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1);
+ sc->bus.sec, sc->bus.sub));
+ pci_write_config(brdev, PCIR_SECBUS_2, sc->bus.sec, 1);
+ pci_write_config(brdev, PCIR_SUBBUS_2, sc->bus.sub, 1);
}
+#endif
/* attach children */
sc->cbdev = device_add_child(brdev, "cardbus", -1);
@@ -467,8 +476,8 @@ cbb_chipinit(struct cbb_softc *sc)
/* Restore bus configuration */
pci_write_config(sc->dev, PCIR_PRIBUS_2, sc->pribus, 1);
- pci_write_config(sc->dev, PCIR_SECBUS_2, sc->secbus, 1);
- pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->subbus, 1);
+ pci_write_config(sc->dev, PCIR_SECBUS_2, sc->bus.sec, 1);
+ pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->bus.sub, 1);
/* Enable memory access */
pci_enable_busmaster(sc->dev);
@@ -783,6 +792,58 @@ cbb_pci_filt(void *arg)
return retval;
}
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static struct resource *
+cbb_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct cbb_softc *sc;
+
+ sc = device_get_softc(bus);
+ if (type == PCI_RES_BUS)
+ return (pcib_alloc_subbus(&sc->bus, child, rid, start, end,
+ count, flags));
+ return (cbb_alloc_resource(bus, child, type, rid, start, end, count,
+ flags));
+}
+
+static int
+cbb_pci_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *r, u_long start, u_long end)
+{
+ struct cbb_softc *sc;
+
+ sc = device_get_softc(bus);
+ if (type == PCI_RES_BUS) {
+ if (!rman_is_region_manager(r, &sc->bus.rman))
+ return (EINVAL);
+ return (rman_adjust_resource(r, start, end));
+ }
+ return (bus_generic_adjust_resource(bus, child, type, r, start, end));
+}
+
+static int
+cbb_pci_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct cbb_softc *sc;
+ int error;
+
+ sc = device_get_softc(bus);
+ if (type == PCI_RES_BUS) {
+ if (!rman_is_region_manager(r, &sc->bus.rman))
+ return (EINVAL);
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type, rid, r);
+ if (error)
+ return (error);
+ }
+ return (rman_release_resource(r));
+ }
+ return (cbb_release_resource(bus, child, type, rid, r));
+}
+#endif
+
/************************************************************************/
/* PCI compat methods */
/************************************************************************/
@@ -826,8 +887,14 @@ static device_method_t cbb_methods[] = {
/* bus methods */
DEVMETHOD(bus_read_ivar, cbb_read_ivar),
DEVMETHOD(bus_write_ivar, cbb_write_ivar),
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ DEVMETHOD(bus_alloc_resource, cbb_pci_alloc_resource),
+ DEVMETHOD(bus_adjust_resource, cbb_pci_adjust_resource),
+ DEVMETHOD(bus_release_resource, cbb_pci_release_resource),
+#else
DEVMETHOD(bus_alloc_resource, cbb_alloc_resource),
DEVMETHOD(bus_release_resource, cbb_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, cbb_activate_resource),
DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource),
DEVMETHOD(bus_driver_added, cbb_driver_added),
diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h
index 64e0727c355e..c3e2d24b14c6 100644
--- a/sys/dev/pccbb/pccbbvar.h
+++ b/sys/dev/pccbb/pccbbvar.h
@@ -64,8 +64,7 @@ struct cbb_softc {
bus_space_handle_t bsh;
uint32_t domain;
unsigned int pribus;
- unsigned int secbus;
- unsigned int subbus;
+ struct pcib_secbus bus;
struct mtx mtx;
int cardok;
u_int32_t flags;
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index f1cbe6c1bb10..41bb4b11b1fc 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -92,6 +92,9 @@ static int pci_add_map(device_t bus, device_t dev, int reg,
struct resource_list *rl, int force, int prefetch);
static int pci_probe(device_t dev);
static int pci_attach(device_t dev);
+#ifdef PCI_RES_BUS
+static int pci_detach(device_t dev);
+#endif
static void pci_load_vendor_data(void);
static int pci_describe_parse_line(char **ptr, int *vendor,
int *device, char **desc);
@@ -125,7 +128,11 @@ static device_method_t pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pci_probe),
DEVMETHOD(device_attach, pci_attach),
+#ifdef PCI_RES_BUS
+ DEVMETHOD(device_detach, pci_detach),
+#else
DEVMETHOD(device_detach, bus_generic_detach),
+#endif
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, pci_suspend),
DEVMETHOD(device_resume, pci_resume),
@@ -337,6 +344,13 @@ TUNABLE_INT("hw.pci.clear_bars", &pci_clear_bars);
SYSCTL_INT(_hw_pci, OID_AUTO, clear_bars, CTLFLAG_RDTUN, &pci_clear_bars, 0,
"Ignore firmware-assigned resources for BARs.");
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static int pci_clear_buses;
+TUNABLE_INT("hw.pci.clear_buses", &pci_clear_buses);
+SYSCTL_INT(_hw_pci, OID_AUTO, clear_buses, CTLFLAG_RDTUN, &pci_clear_buses, 0,
+ "Ignore firmware-assigned bus numbers.");
+#endif
+
static int
pci_has_quirk(uint32_t devid, int quirk)
{
@@ -3197,6 +3211,164 @@ xhci_early_takeover(device_t self)
bus_release_resource(self, SYS_RES_MEMORY, rid, res);
}
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static void
+pci_reserve_secbus(device_t bus, device_t dev, pcicfgregs *cfg,
+ struct resource_list *rl)
+{
+ struct resource *res;
+ char *cp;
+ u_long start, end, count;
+ int rid, sec_bus, sec_reg, sub_bus, sub_reg, sup_bus;
+
+ switch (cfg->hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_BRIDGE:
+ sec_reg = PCIR_SECBUS_1;
+ sub_reg = PCIR_SUBBUS_1;
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ sec_reg = PCIR_SECBUS_2;
+ sub_reg = PCIR_SUBBUS_2;
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * If the existing bus range is valid, attempt to reserve it
+ * from our parent. If this fails for any reason, clear the
+ * secbus and subbus registers.
+ *
+ * XXX: Should we reset sub_bus to sec_bus if it is < sec_bus?
+ * This would at least preserve the existing sec_bus if it is
+ * valid.
+ */
+ sec_bus = PCI_READ_CONFIG(bus, dev, sec_reg, 1);
+ sub_bus = PCI_READ_CONFIG(bus, dev, sub_reg, 1);
+
+ /* Quirk handling. */
+ switch (pci_get_devid(dev)) {
+ case 0x12258086: /* Intel 82454KX/GX (Orion) */
+ sup_bus = pci_read_config(dev, 0x41, 1);
+ if (sup_bus != 0xff) {
+ sec_bus = sup_bus + 1;
+ sub_bus = sup_bus + 1;
+ PCI_WRITE_CONFIG(bus, dev, sec_reg, sec_bus, 1);
+ PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1);
+ }
+ break;
+
+ case 0x00dd10de:
+ /* Compaq R3000 BIOS sets wrong subordinate bus number. */
+ if ((cp = getenv("smbios.planar.maker")) == NULL)
+ break;
+ if (strncmp(cp, "Compal", 6) != 0) {
+ freeenv(cp);
+ break;
+ }
+ freeenv(cp);
+ if ((cp = getenv("smbios.planar.product")) == NULL)
+ break;
+ if (strncmp(cp, "08A0", 4) != 0) {
+ freeenv(cp);
+ break;
+ }
+ freeenv(cp);
+ if (sub_bus < 0xa) {
+ sub_bus = 0xa;
+ PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1);
+ }
+ break;
+ }
+
+ if (bootverbose)
+ printf("\tsecbus=%d, subbus=%d\n", sec_bus, sub_bus);
+ if (sec_bus > 0 && sub_bus >= sec_bus) {
+ start = sec_bus;
+ end = sub_bus;
+ count = end - start + 1;
+
+ resource_list_add(rl, PCI_RES_BUS, 0, 0ul, ~0ul, count);
+
+ /*
+ * If requested, clear secondary bus registers in
+ * bridge devices to force a complete renumbering
+ * rather than reserving the existing range. However,
+ * preserve the existing size.
+ */
+ if (pci_clear_buses)
+ goto clear;
+
+ rid = 0;
+ res = resource_list_reserve(rl, bus, dev, PCI_RES_BUS, &rid,
+ start, end, count, 0);
+ if (res != NULL)
+ return;
+
+ if (bootverbose)
+ device_printf(bus,
+ "pci%d:%d:%d:%d secbus failed to allocate\n",
+ pci_get_domain(dev), pci_get_bus(dev),
+ pci_get_slot(dev), pci_get_function(dev));
+ }
+
+clear:
+ PCI_WRITE_CONFIG(bus, dev, sec_reg, 0, 1);
+ PCI_WRITE_CONFIG(bus, dev, sub_reg, 0, 1);
+}
+
+static struct resource *
+pci_alloc_secbus(device_t dev, device_t child, int *rid, u_long start,
+ u_long end, u_long count, u_int flags)
+{
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+ struct resource_list *rl;
+ struct resource *res;
+ int sec_reg, sub_reg;
+
+ dinfo = device_get_ivars(child);
+ cfg = &dinfo->cfg;
+ rl = &dinfo->resources;
+ switch (cfg->hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_BRIDGE:
+ sec_reg = PCIR_SECBUS_1;
+ sub_reg = PCIR_SUBBUS_1;
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ sec_reg = PCIR_SECBUS_2;
+ sub_reg = PCIR_SUBBUS_2;
+ break;
+ default:
+ return (NULL);
+ }
+
+ if (*rid != 0)
+ return (NULL);
+
+ if (resource_list_find(rl, PCI_RES_BUS, *rid) == NULL)
+ resource_list_add(rl, PCI_RES_BUS, *rid, start, end, count);
+ if (!resource_list_reserved(rl, PCI_RES_BUS, *rid)) {
+ res = resource_list_reserve(rl, dev, child, PCI_RES_BUS, rid,
+ start, end, count, flags & ~RF_ACTIVE);
+ if (res == NULL) {
+ resource_list_delete(rl, PCI_RES_BUS, *rid);
+ device_printf(child, "allocating %lu bus%s failed\n",
+ count, count == 1 ? "" : "es");
+ return (NULL);
+ }
+ if (bootverbose)
+ device_printf(child,
+ "Lazy allocation of %lu bus%s at %lu\n", count,
+ count == 1 ? "" : "es", rman_get_start(res));
+ PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1);
+ PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1);
+ }
+ return (resource_list_alloc(rl, dev, child, PCI_RES_BUS, rid, start,
+ end, count, flags));
+}
+#endif
+
void
pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
{
@@ -3269,6 +3441,14 @@ pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_UHCI)
uhci_early_takeover(dev);
}
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ /*
+ * Reserve resources for secondary bus ranges behind bridge
+ * devices.
+ */
+ pci_reserve_secbus(bus, dev, cfg, rl);
+#endif
}
void
@@ -3334,10 +3514,22 @@ pci_attach_common(device_t dev)
#ifdef PCI_DMA_BOUNDARY
int error, tag_valid;
#endif
+#ifdef PCI_RES_BUS
+ int rid;
+#endif
sc = device_get_softc(dev);
domain = pcib_get_domain(dev);
busno = pcib_get_bus(dev);
+#ifdef PCI_RES_BUS
+ rid = 0;
+ sc->sc_bus = bus_alloc_resource(dev, PCI_RES_BUS, &rid, busno, busno,
+ 1, 0);
+ if (sc->sc_bus == NULL) {
+ device_printf(dev, "failed to allocate bus number\n");
+ return (ENXIO);
+ }
+#endif
if (bootverbose)
device_printf(dev, "domain=%d, physical bus=%d\n",
domain, busno);
@@ -3382,6 +3574,21 @@ pci_attach(device_t dev)
return (bus_generic_attach(dev));
}
+#ifdef PCI_RES_BUS
+static int
+pci_detach(device_t dev)
+{
+ struct pci_softc *sc;
+ int error;
+
+ error = bus_generic_detach(dev);
+ if (error)
+ return (error);
+ sc = device_get_softc(dev);
+ return (bus_release_resource(dev, PCI_RES_BUS, 0, sc->sc_bus));
+}
+#endif
+
static void
pci_set_power_children(device_t dev, device_t *devlist, int numdevs,
int state)
@@ -3879,6 +4086,10 @@ pci_child_detached(device_t dev, device_t child)
pci_printf(&dinfo->cfg, "Device leaked memory resources\n");
if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0)
pci_printf(&dinfo->cfg, "Device leaked I/O resources\n");
+#ifdef PCI_RES_BUS
+ if (resource_list_release_active(rl, dev, child, PCI_RES_BUS) != 0)
+ pci_printf(&dinfo->cfg, "Device leaked PCI bus numbers\n");
+#endif
pci_cfg_save(child, dinfo, 1);
}
@@ -4295,6 +4506,11 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
rl = &dinfo->resources;
cfg = &dinfo->cfg;
switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ case PCI_RES_BUS:
+ return (pci_alloc_secbus(dev, child, rid, start, end, count,
+ flags));
+#endif
case SYS_RES_IRQ:
/*
* Can't alloc legacy interrupt once MSI messages have
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 5fa886e19f99..684e6b71fc1b 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -119,6 +119,10 @@ pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r)
{
switch (type) {
+#ifdef PCI_RES_BUS
+ case PCI_RES_BUS:
+ return (rman_is_region_manager(r, &sc->bus.rman));
+#endif
case SYS_RES_IOPORT:
return (rman_is_region_manager(r, &sc->io.rman));
case SYS_RES_MEMORY:
@@ -523,6 +527,173 @@ pcib_probe_windows(struct pcib_softc *sc)
}
}
+#ifdef PCI_RES_BUS
+/*
+ * Allocate a suitable secondary bus for this bridge if needed and
+ * initialize the resource manager for the secondary bus range. Note
+ * that the minimum count is a desired value and this may allocate a
+ * smaller range.
+ */
+void
+pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
+{
+ char buf[64];
+ int error, rid;
+
+ switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_BRIDGE:
+ bus->sub_reg = PCIR_SUBBUS_1;
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ bus->sub_reg = PCIR_SUBBUS_2;
+ break;
+ default:
+ panic("not a PCI bridge");
+ }
+ bus->dev = dev;
+ bus->rman.rm_start = 0;
+ bus->rman.rm_end = PCI_BUSMAX;
+ bus->rman.rm_type = RMAN_ARRAY;
+ snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev));
+ bus->rman.rm_descr = strdup(buf, M_DEVBUF);
+ error = rman_init(&bus->rman);
+ if (error)
+ panic("Failed to initialize %s bus number rman",
+ device_get_nameunit(dev));
+
+ /*
+ * Allocate a bus range. This will return an existing bus range
+ * if one exists, or a new bus range if one does not.
+ */
+ rid = 0;
+ bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
+ min_count, 0);
+ if (bus->res == NULL) {
+ /*
+ * Fall back to just allocating a range of a single bus
+ * number.
+ */
+ bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
+ 1, 0);
+ } else if (rman_get_size(bus->res) < min_count)
+ /*
+ * Attempt to grow the existing range to satisfy the
+ * minimum desired count.
+ */
+ (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res,
+ rman_get_start(bus->res), rman_get_start(bus->res) +
+ min_count - 1);
+
+ /*
+ * Add the initial resource to the rman.
+ */
+ if (bus->res != NULL) {
+ error = rman_manage_region(&bus->rman, rman_get_start(bus->res),
+ rman_get_end(bus->res));
+ if (error)
+ panic("Failed to add resource to rman");
+ bus->sec = rman_get_start(bus->res);
+ bus->sub = rman_get_end(bus->res);
+ }
+}
+
+static struct resource *
+pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *res;
+
+ res = rman_reserve_resource(&bus->rman, start, end, count, flags,
+ child);
+ if (res == NULL)
+ return (NULL);
+
+ if (bootverbose)
+ device_printf(bus->dev,
+ "allocated bus range (%lu-%lu) for rid %d of %s\n",
+ rman_get_start(res), rman_get_end(res), *rid,
+ pcib_child_name(child));
+ rman_set_rid(res, *rid);
+ return (res);
+}
+
+/*
+ * Attempt to grow the secondary bus range. This is much simpler than
+ * for I/O windows as the range can only be grown by increasing
+ * subbus.
+ */
+static int
+pcib_grow_subbus(struct pcib_secbus *bus, u_long new_end)
+{
+ u_long old_end;
+ int error;
+
+ old_end = rman_get_end(bus->res);
+ KASSERT(new_end > old_end, ("attempt to shrink subbus"));
+ error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res,
+ rman_get_start(bus->res), new_end);
+ if (error)
+ return (error);
+ if (bootverbose)
+ device_printf(bus->dev, "grew bus range to %lu-%lu\n",
+ rman_get_start(bus->res), rman_get_end(bus->res));
+ error = rman_manage_region(&bus->rman, old_end + 1,
+ rman_get_end(bus->res));
+ if (error)
+ panic("Failed to add resource to rman");
+ bus->sub = rman_get_end(bus->res);
+ pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1);
+ return (0);
+}
+
+struct resource *
+pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *res;
+ u_long start_free, end_free, new_end;
+
+ /*
+ * First, see if the request can be satisified by the existing
+ * bus range.
+ */
+ res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags);
+ if (res != NULL)
+ return (res);
+
+ /*
+ * Figure out a range to grow the bus range. First, find the
+ * first bus number after the last allocated bus in the rman and
+ * enforce that as a minimum starting point for the range.
+ */
+ if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 ||
+ end_free != bus->sub)
+ start_free = bus->sub + 1;
+ if (start_free < start)
+ start_free = start;
+ new_end = start_free + count - 1;
+
+ /*
+ * See if this new range would satisfy the request if it
+ * succeeds.
+ */
+ if (new_end > end)
+ return (NULL);
+
+ /* Finally, attempt to grow the existing resource. */
+ if (bootverbose) {
+ device_printf(bus->dev,
+ "attempting to grow bus range for %lu buses\n", count);
+ printf("\tback candidate range: %lu-%lu\n", start_free,
+ new_end);
+ }
+ if (pcib_grow_subbus(bus, new_end) == 0)
+ return (pcib_suballoc_bus(bus, child, rid, start, end, count,
+ flags));
+ return (NULL);
+}
+#endif
+
#else
/*
@@ -669,8 +840,8 @@ pcib_cfg_save(struct pcib_softc *sc)
sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1);
- sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
- sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+ sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
+ sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
#ifndef NEW_PCIB
@@ -693,8 +864,8 @@ pcib_cfg_restore(struct pcib_softc *sc)
pci_write_config(dev, PCIR_COMMAND, sc->command, 2);
pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
- pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1);
- pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1);
+ pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1);
+ pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1);
pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2);
pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1);
#ifdef NEW_PCIB
@@ -740,6 +911,13 @@ pcib_attach_common(device_t dev)
pcib_cfg_save(sc);
/*
+ * The primary bus register should always be the bus of the
+ * parent.
+ */
+ sc->pribus = pci_get_bus(dev);
+ pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
+
+ /*
* Setup sysctl reporting nodes
*/
sctx = device_get_sysctl_ctx(dev);
@@ -749,25 +927,27 @@ pcib_attach_common(device_t dev)
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
- CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
+ CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
- CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
+ CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number");
/*
* Quirk handling.
*/
switch (pci_get_devid(dev)) {
+#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
case 0x12258086: /* Intel 82454KX/GX (Orion) */
{
uint8_t supbus;
supbus = pci_read_config(dev, 0x41, 1);
if (supbus != 0xff) {
- sc->secbus = supbus + 1;
- sc->subbus = supbus + 1;
+ sc->bus.sec = supbus + 1;
+ sc->bus.sub = supbus + 1;
}
break;
}
+#endif
/*
* The i82380FB mobile docking controller is a PCI-PCI bridge,
@@ -781,6 +961,7 @@ pcib_attach_common(device_t dev)
sc->flags |= PCIB_SUBTRACTIVE;
break;
+#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
/* Compaq R3000 BIOS sets wrong subordinate bus number. */
case 0x00dd10de:
{
@@ -800,12 +981,13 @@ pcib_attach_common(device_t dev)
break;
}
freeenv(cp);
- if (sc->subbus < 0xa) {
+ if (sc->bus.sub < 0xa) {
pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1);
- sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+ sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
}
break;
}
+#endif
}
if (pci_msi_device_blacklisted(dev))
@@ -827,12 +1009,15 @@ pcib_attach_common(device_t dev)
sc->flags |= PCIB_SUBTRACTIVE;
#ifdef NEW_PCIB
+#ifdef PCI_RES_BUS
+ pcib_setup_secbus(dev, &sc->bus, 1);
+#endif
pcib_probe_windows(sc);
#endif
if (bootverbose) {
device_printf(dev, " domain %d\n", sc->domain);
- device_printf(dev, " secondary bus %d\n", sc->secbus);
- device_printf(dev, " subordinate bus %d\n", sc->subbus);
+ device_printf(dev, " secondary bus %d\n", sc->bus.sec);
+ device_printf(dev, " subordinate bus %d\n", sc->bus.sub);
#ifdef NEW_PCIB
if (pcib_is_window_open(&sc->io))
device_printf(dev, " I/O decode 0x%jx-0x%jx\n",
@@ -873,20 +1058,6 @@ pcib_attach_common(device_t dev)
}
/*
- * XXX If the secondary bus number is zero, we should assign a bus number
- * since the BIOS hasn't, then initialise the bridge. A simple
- * bus_alloc_resource with the a couple of busses seems like the right
- * approach, but we don't know what busses the BIOS might have already
- * assigned to other bridges on this bus that probe later than we do.
- *
- * If the subordinate bus number is less than the secondary bus number,
- * we should pick a better value. One sensible alternative would be to
- * pick 255; the only tradeoff here is that configuration transactions
- * would be more widely routed than absolutely necessary. We could
- * then do a walk of the tree later and fix it.
- */
-
- /*
* Always enable busmastering on bridges so that transactions
* initiated on the secondary bus are passed through to the
* primary bus.
@@ -902,8 +1073,8 @@ pcib_attach(device_t dev)
pcib_attach_common(dev);
sc = device_get_softc(dev);
- if (sc->secbus != 0) {
- child = device_add_child(dev, "pci", sc->secbus);
+ if (sc->bus.sec != 0) {
+ child = device_add_child(dev, "pci", sc->bus.sec);
if (child != NULL)
return(bus_generic_attach(dev));
}
@@ -953,7 +1124,7 @@ pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
*result = sc->domain;
return(0);
case PCIB_IVAR_BUS:
- *result = sc->secbus;
+ *result = sc->bus.sec;
return(0);
}
return(ENOENT);
@@ -962,14 +1133,12 @@ pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
int
pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
- struct pcib_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_DOMAIN:
return(EINVAL);
case PCIB_IVAR_BUS:
- sc->secbus = value;
- return(0);
+ return(EINVAL);
}
return(ENOENT);
}
@@ -1379,6 +1548,11 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
}
switch (type) {
+#ifdef PCI_RES_BUS
+ case PCI_RES_BUS:
+ return (pcib_alloc_subbus(&sc->bus, child, rid, start, end,
+ count, flags));
+#endif
case SYS_RES_IOPORT:
if (pcib_is_isa_range(sc, start, end, count))
return (NULL);
diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h
index 1502288146f1..0223ee864b27 100644
--- a/sys/dev/pci/pci_private.h
+++ b/sys/dev/pci/pci_private.h
@@ -40,6 +40,9 @@ DECLARE_CLASS(pci_driver);
struct pci_softc {
bus_dma_tag_t sc_dma_tag;
+#ifdef PCI_RES_BUS
+ struct resource *sc_bus;
+#endif
};
extern int pci_do_power_resume;
diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c
index 3d13fb99da54..5d0db3665c6b 100644
--- a/sys/dev/pci/pci_subr.c
+++ b/sys/dev/pci/pci_subr.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
+#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/systm.h>
@@ -282,4 +283,102 @@ pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type,
}
return (ERANGE);
}
+
+#ifdef PCI_RES_BUS
+struct pci_domain {
+ int pd_domain;
+ struct rman pd_bus_rman;
+ TAILQ_ENTRY(pci_domain) pd_link;
+};
+
+static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains);
+
+/*
+ * Each PCI domain maintains its own resource manager for PCI bus
+ * numbers in that domain. Domain objects are created on first use.
+ * Host to PCI bridge drivers and PCI-PCI bridge drivers should
+ * allocate their bus ranges from their domain.
+ */
+static struct pci_domain *
+pci_find_domain(int domain)
+{
+ struct pci_domain *d;
+ char buf[64];
+ int error;
+
+ TAILQ_FOREACH(d, &domains, pd_link) {
+ if (d->pd_domain == domain)
+ return (d);
+ }
+
+ snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain);
+ d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO);
+ d->pd_domain = domain;
+ d->pd_bus_rman.rm_start = 0;
+ d->pd_bus_rman.rm_end = PCI_BUSMAX;
+ d->pd_bus_rman.rm_type = RMAN_ARRAY;
+ strcpy((char *)(d + 1), buf);
+ d->pd_bus_rman.rm_descr = (char *)(d + 1);
+ error = rman_init(&d->pd_bus_rman);
+ if (error == 0)
+ error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX);
+ if (error)
+ panic("Failed to initialize PCI domain %d rman", domain);
+ TAILQ_INSERT_TAIL(&domains, d, pd_link);
+ return (d);
+}
+
+struct resource *
+pci_domain_alloc_bus(int domain, device_t dev, int *rid, u_long start,
+ u_long end, u_long count, u_int flags)
+{
+ struct pci_domain *d;
+ struct resource *res;
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (NULL);
+ d = pci_find_domain(domain);
+ res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags,
+ dev);
+ if (res == NULL)
+ return (NULL);
+
+ rman_set_rid(res, *rid);
+ return (res);
+}
+
+int
+pci_domain_adjust_bus(int domain, device_t dev, struct resource *r,
+ u_long start, u_long end)
+{
+#ifdef INVARIANTS
+ struct pci_domain *d;
+#endif
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (EINVAL);
+#ifdef INVARIANTS
+ d = pci_find_domain(domain);
+ KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+ return (rman_adjust_resource(r, start, end));
+}
+
+int
+pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r)
+{
+#ifdef INVARIANTS
+ struct pci_domain *d;
+#endif
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (EINVAL);
+#ifdef INVARIANTS
+ d = pci_find_domain(domain);
+ KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+ return (rman_release_resource(r));
+}
+#endif /* PCI_RES_BUS */
+
#endif /* NEW_PCIB */
diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h
index e9d4c4bf542d..e74f1493dfbe 100644
--- a/sys/dev/pci/pcib_private.h
+++ b/sys/dev/pci/pcib_private.h
@@ -83,6 +83,18 @@ struct pcib_window {
};
#endif
+struct pcib_secbus {
+ u_int sec;
+ u_int sub;
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ device_t dev;
+ struct rman rman;
+ struct resource *res;
+ const char *name;
+ int sub_reg;
+#endif
+};
+
/*
* Bridge-specific data.
*/
@@ -96,8 +108,7 @@ struct pcib_softc
uint16_t command; /* command register */
u_int domain; /* domain number */
u_int pribus; /* primary bus number */
- u_int secbus; /* secondary bus number */
- u_int subbus; /* subordinate bus number */
+ struct pcib_secbus bus; /* secondary bus numbers */
#ifdef NEW_PCIB
struct pcib_window io; /* I/O port window */
struct pcib_window mem; /* memory window */
@@ -117,13 +128,26 @@ struct pcib_softc
typedef uint32_t pci_read_config_fn(int b, int s, int f, int reg, int width);
-#ifdef NEW_PCIB
-const char *pcib_child_name(device_t child);
-#endif
int host_pcib_get_busno(pci_read_config_fn read_config, int bus,
int slot, int func, uint8_t *busnum);
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+struct resource *pci_domain_alloc_bus(int domain, device_t dev, int *rid,
+ u_long start, u_long end, u_long count, u_int flags);
+int pci_domain_adjust_bus(int domain, device_t dev,
+ struct resource *r, u_long start, u_long end);
+int pci_domain_release_bus(int domain, device_t dev, int rid,
+ struct resource *r);
+struct resource *pcib_alloc_subbus(struct pcib_secbus *bus, device_t child,
+ int *rid, u_long start, u_long end, u_long count,
+ u_int flags);
+void pcib_setup_secbus(device_t dev, struct pcib_secbus *bus,
+ int min_count);
+#endif
int pcib_attach(device_t dev);
void pcib_attach_common(device_t dev);
+#ifdef NEW_PCIB
+const char *pcib_child_name(device_t child);
+#endif
int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
diff --git a/sys/i386/include/resource.h b/sys/i386/include/resource.h
index edde5eb29908..dfcc902a7316 100644
--- a/sys/i386/include/resource.h
+++ b/sys/i386/include/resource.h
@@ -40,5 +40,8 @@
#define SYS_RES_DRQ 2 /* isa dma lines */
#define SYS_RES_MEMORY 3 /* i/o memory */
#define SYS_RES_IOPORT 4 /* i/o ports */
+#ifdef NEW_PCIB
+#define PCI_RES_BUS 5 /* PCI bus numbers */
+#endif
#endif /* !_MACHINE_RESOURCE_H_ */
diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c
index a6854e9a3054..9b3fa4427265 100644
--- a/sys/sparc64/pci/apb.c
+++ b/sys/sparc64/pci/apb.c
@@ -177,9 +177,9 @@ apb_attach(device_t dev)
pci_read_config(dev, PCIR_COMMAND, 2);
sc->sc_bsc.ops_pcib_sc.pribus =
pci_read_config(dev, PCIR_PRIBUS_1, 1);
- sc->sc_bsc.ops_pcib_sc.secbus =
+ sc->sc_bsc.ops_pcib_sc.bus.sec =
pci_read_config(dev, PCIR_SECBUS_1, 1);
- sc->sc_bsc.ops_pcib_sc.subbus =
+ sc->sc_bsc.ops_pcib_sc.bus.sub =
pci_read_config(dev, PCIR_SUBBUS_1, 1);
sc->sc_bsc.ops_pcib_sc.bridgectl =
pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
@@ -200,10 +200,10 @@ apb_attach(device_t dev)
CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0,
"Primary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
- CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.secbus, 0,
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sec, 0,
"Secondary bus number");
SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
- CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.subbus, 0,
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sub, 0,
"Subordinate bus number");
ofw_pcib_gen_setup(dev);
@@ -212,9 +212,9 @@ apb_attach(device_t dev)
device_printf(dev, " domain %d\n",
sc->sc_bsc.ops_pcib_sc.domain);
device_printf(dev, " secondary bus %d\n",
- sc->sc_bsc.ops_pcib_sc.secbus);
+ sc->sc_bsc.ops_pcib_sc.bus.sec);
device_printf(dev, " subordinate bus %d\n",
- sc->sc_bsc.ops_pcib_sc.subbus);
+ sc->sc_bsc.ops_pcib_sc.bus.sub);
device_printf(dev, " I/O decode ");
apb_map_print(sc->sc_iomap, APB_IO_SCALE);
printf("\n");
diff --git a/sys/x86/include/legacyvar.h b/sys/x86/include/legacyvar.h
index 5f2e29c62595..856b352d8672 100644
--- a/sys/x86/include/legacyvar.h
+++ b/sys/x86/include/legacyvar.h
@@ -57,6 +57,10 @@ int legacy_pcib_write_ivar(device_t dev, device_t child, int which,
uintptr_t value);
struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child,
int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
+int legacy_pcib_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, u_long start, u_long end);
+int legacy_pcib_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r);
int legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count,
int maxcount, int *irqs);
int legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq);
diff --git a/sys/x86/pci/pci_bus.c b/sys/x86/pci/pci_bus.c
index 53be8c20310b..88cabc724fe3 100644
--- a/sys/x86/pci/pci_bus.c
+++ b/sys/x86/pci/pci_bus.c
@@ -597,10 +597,37 @@ legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
- start = hostb_alloc_start(type, start, end, count);
- return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
- count, flags));
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS)
+ return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+ flags));
+#endif
+ start = hostb_alloc_start(type, start, end, count);
+ return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
+ count, flags));
+}
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+int
+legacy_pcib_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, u_long start, u_long end)
+{
+
+ if (type == PCI_RES_BUS)
+ return (pci_domain_adjust_bus(0, child, r, start, end));
+ return (bus_generic_adjust_resource(dev, child, type, r, start, end));
+}
+
+int
+legacy_pcib_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ if (type == PCI_RES_BUS)
+ return (pci_domain_release_bus(0, child, rid, r));
+ return (bus_generic_release_resource(dev, child, type, rid, r));
}
+#endif
static device_method_t legacy_pcib_methods[] = {
/* Device interface */
@@ -615,8 +642,13 @@ static device_method_t legacy_pcib_methods[] = {
DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar),
DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource),
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ DEVMETHOD(bus_adjust_resource, legacy_pcib_adjust_resource),
+ DEVMETHOD(bus_release_resource, legacy_pcib_release_resource),
+#else
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
diff --git a/sys/x86/pci/qpi.c b/sys/x86/pci/qpi.c
index 21b2c4301cfd..2f8889100d94 100644
--- a/sys/x86/pci/qpi.c
+++ b/sys/x86/pci/qpi.c
@@ -238,6 +238,20 @@ qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
}
}
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static struct resource *
+qpi_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+
+ if (type == PCI_RES_BUS)
+ return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+ flags));
+ return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
+ count, flags));
+}
+#endif
+
static int
qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
uint32_t *data)
@@ -258,8 +272,14 @@ static device_method_t qpi_pcib_methods[] = {
/* Bus interface */
DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar),
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ DEVMETHOD(bus_alloc_resource, qpi_pcib_alloc_resource),
+ DEVMETHOD(bus_adjust_resource, legacy_pcib_adjust_resource),
+ DEVMETHOD(bus_release_resource, legacy_pcib_release_resource),
+#else
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
diff --git a/sys/x86/x86/mptable_pci.c b/sys/x86/x86/mptable_pci.c
index 2110b10736f6..3e2c1cbe145f 100644
--- a/sys/x86/x86/mptable_pci.c
+++ b/sys/x86/x86/mptable_pci.c
@@ -105,6 +105,11 @@ mptable_hostb_alloc_resource(device_t dev, device_t child, int type, int *rid,
{
struct mptable_hostb_softc *sc;
+#ifdef PCI_RES_BUS
+ if (type == PCI_RES_BUS)
+ return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+ flags));
+#endif
sc = device_get_softc(dev);
if (type == SYS_RES_IOPORT && start + count - 1 == end) {
if (mptable_is_isa_range(start, end)) {
@@ -141,6 +146,10 @@ mptable_hostb_adjust_resource(device_t dev, device_t child, int type,
{
struct mptable_hostb_softc *sc;
+#ifdef PCI_RES_BUS
+ if (type == PCI_RES_BUS)
+ return (pci_domain_adjust_bus(0, child, r, start, end));
+#endif
sc = device_get_softc(dev);
return (pcib_host_res_adjust(&sc->sc_host_res, child, type, r, start,
end));
@@ -165,7 +174,11 @@ static device_method_t mptable_hostb_methods[] = {
DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource),
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
#endif
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ DEVMETHOD(bus_release_resource, legacy_pcib_release_resource),
+#else
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+#endif
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),