diff options
author | Yinghai Lu <yinghai@kernel.org> | 2016-02-24 17:51:30 -0800 |
---|---|---|
committer | Yinghai Lu <yinghai@kernel.org> | 2016-02-24 17:51:30 -0800 |
commit | 647317309d4d572732d2c3bb5192b7a9e2614a98 (patch) | |
tree | d56043dfeabd5be24cf6021191048a83674c58e0 | |
parent | 35ae5d9cbffb19c7126919da303dd8261e1f4ac9 (diff) | |
download | linux-yinghai-for-pci-v4.6-next.tar.gz |
PCI: Only try to assign io port only for root bus that support itfor-pci-v4.6-next
The PCI subsystem always assumes that I/O is supported on root bus and
tries to assign an I/O window to each child bus even if that is not the
case.
The use cases is on Intel 8 socket system that have 8 root buses,
last two root buses would not have io port resources from _CRS.
Check if root bus supports I/O, and later during sizing and
assigning, check that flags and skip those resources.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r-- | drivers/pci/probe.c | 6 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 9 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
3 files changed, 16 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 563b784a96ab71..96fda927cdcb29 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -342,6 +342,9 @@ static void pci_read_bridge_io(struct pci_bus *child) struct pci_bus_region region; struct resource *res; + if (!pci_find_host_bridge(child)->has_ioport) + return; + io_mask = PCI_IO_RANGE_MASK; io_granularity = 0x1000; if (dev->io_window_1k) { @@ -2190,6 +2193,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, bus_addr[0] = '\0'; dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr); + if (resource_type(res) == IORESOURCE_IO) + bridge->has_ioport = 1; + if (resource_type(res) == IORESOURCE_MEM) { if ((res->end - offset) > 0xffffffff) bridge->has_mem64 = 1; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index e1d7b7962fb71b..8682522c27b2b7 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -226,6 +226,10 @@ static void pdev_assign_resources_prepare(struct pci_dev *dev, if (resource_disabled(r) || r->parent) continue; + if ((r->flags & IORESOURCE_IO) && + !pci_find_host_bridge(dev->bus)->has_ioport) + continue; + r_align = __pci_resource_alignment(dev, r, realloc_head); if (!r_align) { dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n", @@ -1189,6 +1193,11 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, min_size = 0; } + if (!pci_find_host_bridge(bus)->has_ioport) { + b_res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + return; + } + min_align = window_alignment(bus, IORESOURCE_IO); list_for_each_entry(dev, &bus->devices, bus_list) { int i; diff --git a/include/linux/pci.h b/include/linux/pci.h index 30a4879cac4478..5dc748f6f59213 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -414,6 +414,7 @@ struct pci_host_bridge { void *release_data; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ unsigned int has_mem64:1; + unsigned int has_ioport:1; /* Resource alignment requirements */ resource_size_t (*align_resource)(struct pci_dev *dev, const struct resource *res, |