Page MenuHomeFreeBSD

D45434.1787120707.diff
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None

D45434.1787120707.diff

diff --git a/sys/dev/pci/pci_host_generic.h b/sys/dev/pci/pci_host_generic.h
--- a/sys/dev/pci/pci_host_generic.h
+++ b/sys/dev/pci/pci_host_generic.h
@@ -89,6 +89,8 @@
#define PCIE_ECAM_DESIGNWARE_QUIRK (1 << 0)
/* Child will map resources to access config registers */
#define PCIE_CUSTOM_CONFIG_SPACE_QUIRK (1 << 1)
+/* Use shared I/O resource window. */
+#define PCIE_SHARED_IO_WINDOW (1 << 2)
DECLARE_CLASS(generic_pcie_core_driver);
diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c
--- a/sys/dev/pci/pci_host_generic.c
+++ b/sys/dev/pci/pci_host_generic.c
@@ -76,6 +76,64 @@
static int generic_pcie_write_ivar(device_t dev, device_t child, int index,
uintptr_t value);
+/*
+ * Some systems share a single window for I/O resources across
+ * multiple bridges. The first bridge allocates the rman and parent
+ * resource for the shared window.
+ */
+static device_t io_window_bridge;
+
+static bool
+generic_pcie_contains_range(struct generic_pcie_core_softc *sc,
+ const struct pcie_range *range)
+{
+ for (int tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
+ if (sc->ranges[tuple].pci_base == range->pci_base &&
+ sc->ranges[tuple].phys_base == range->phys_base &&
+ sc->ranges[tuple].size == range->size &&
+ sc->ranges[tuple].flags == range->flags)
+ return (true);
+ }
+ return (false);
+}
+
+static bool
+use_shared_io_window(struct generic_pcie_core_softc *sc)
+{
+ struct generic_pcie_core_softc *sc2;
+ int tuple, matches, count;
+
+ if (io_window_bridge == NULL)
+ return (false);
+
+ /*
+ * First, verify that all I/O windows in the new bridge match
+ * I/O windows in the shared bridge.
+ */
+ sc2 = device_get_softc(io_window_bridge);
+ matches = 0;
+ for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
+ if (FLAG_TYPE(sc->ranges[tuple].flags) != FLAG_TYPE_IO)
+ continue;
+ if (!generic_pcie_contains_range(sc2, &sc->ranges[tuple]))
+ return (false);
+ matches++;
+ }
+
+ /*
+ * Second, ensure that the new bridge decodes all of the I/O
+ * window ranges decoded by the shared bridge.
+ */
+ count = 0;
+ for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
+ if (FLAG_TYPE(sc2->ranges[tuple].flags) != FLAG_TYPE_IO)
+ continue;
+ count++;
+ }
+
+ return (matches == count);
+}
+
int
pci_host_generic_core_attach(device_t dev)
{
@@ -140,6 +198,9 @@
#endif
}
+ if (use_shared_io_window(sc))
+ sc->quirks |= PCIE_SHARED_IO_WINDOW;
+
sc->has_pmem = false;
sc->pmem_rman.rm_type = RMAN_ARRAY;
snprintf(buf, sizeof(buf), "%s prefetch window",
@@ -209,6 +270,9 @@
device_printf(dev,
"PCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Type: %s\n",
pci_base, phys_base, size, range_descr);
+ if (type == SYS_RES_IOPORT &&
+ (sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ continue;
error = bus_set_resource(dev, type, rid, phys_base, size);
if (error != 0) {
device_printf(dev,
@@ -230,6 +294,8 @@
"error = %d\n", error);
continue;
}
+ if (type == SYS_RES_IOPORT && io_window_bridge == NULL)
+ io_window_bridge = dev;
}
return (0);
@@ -257,6 +323,9 @@
sc = device_get_softc(dev);
+ if (dev == io_window_bridge)
+ return (EBUSY);
+
error = bus_generic_detach(dev);
if (error != 0)
return (error);
@@ -275,6 +344,8 @@
type = SYS_RES_MEMORY;
break;
case FLAG_TYPE_IO:
+ if ((sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ continue;
type = SYS_RES_IOPORT;
break;
default:
@@ -408,6 +479,8 @@
switch (type) {
case SYS_RES_IOPORT:
+ if ((sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ sc = device_get_softc(io_window_bridge);
return (&sc->io_rman);
case SYS_RES_MEMORY:
if (sc->has_pmem && (flags & RF_PREFETCHABLE) != 0)
@@ -449,6 +522,9 @@
switch (type) {
case SYS_RES_IOPORT:
+ if ((sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ sc = device_get_softc(io_window_bridge);
+ break;
case SYS_RES_MEMORY:
break;
default:
@@ -598,6 +674,7 @@
generic_pcie_map_resource(device_t dev, device_t child, struct resource *r,
struct resource_map_request *argsp, struct resource_map *map)
{
+ struct generic_pcie_core_softc *sc = device_get_softc(dev);
struct resource_map_request args;
struct pcie_range *range;
rman_res_t length, start;
@@ -630,6 +707,8 @@
args.offset = start - range->pci_base;
args.length = length;
+ if ((sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ dev = io_window_bridge;
return (bus_map_resource(dev, range->res, &args, map));
}
@@ -637,6 +716,7 @@
generic_pcie_unmap_resource(device_t dev, device_t child, struct resource *r,
struct resource_map *map)
{
+ struct generic_pcie_core_softc *sc = device_get_softc(dev);
struct pcie_range *range;
int type;
@@ -655,6 +735,8 @@
rman_get_end(r));
if (range == NULL || range->res == NULL)
return (ENOENT);
+ if ((sc->quirks & PCIE_SHARED_IO_WINDOW) != 0)
+ dev = io_window_bridge;
return (bus_unmap_resource(dev, range->res, map));
}

File Metadata

Mime Type
text/plain
Expires
Wed, Aug 19, 6:25 AM (6 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29430943
Default Alt Text
D45434.1787120707.diff (4 KB)

Event Timeline