Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148497325
D45434.1787120707.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D45434.1787120707.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D45434: pci_host_generic: Permit multiple bridges to share the same I/O window
Attached
Detach File
Event Timeline
Log In to Comment