Commit d66ecb72 authored by Jiang Liu's avatar Jiang Liu Committed by Rafael J. Wysocki

PCI / ACPI: Use boot-time resource allocation rules during hotplug

On x86 platforms, the kernel respects PCI resource assignments from
the BIOS and only reassigns resources for unassigned BARs at boot
time.  However, with the ACPI-based hotplug (acpiphp), it ignores the
BIOS' PCI resource assignments completely and reassigns all resources
by itself.  This causes differences in PCI resource allocation
between boot time and runtime hotplug to occur, which is generally
undesirable and sometimes actively breaks things.

Namely, if there are enough resources, reassigning all PCI resources
during runtime hotplug should work, but it may fail if the resources
are constrained.  This may happen, for instance, when some PCI
devices with huge MMIO BARs are involved in the runtime hotplug
operations, because the current PCI MMIO alignment algorithm may
waste huge chunks of MMIO address space in those cases.

On the Alexander's Sony VAIO VPCZ23A4R the BIOS allocates limited
MMIO resources for the dock station which contains a device
(graphics adapter) with a 256MB MMIO BAR.  An attempt to reassign
that during runtime hotplug causes the dock station MMIO window to be
exhausted and acpiphp fails to allocate resources for the majority
of devices on the dock station as a result.

To prevent that from happening, modify acpiphp to follow the boot
time resources allocation behavior so that the BIOS' resource
assignments are respected during runtime hotplug too.

[rjw: Changelog]
References: https://bugzilla.kernel.org/show_bug.cgi?id=56531Reported-and-tested-by: default avatarAlexander E. Patrakov <patrakov@gmail.com>
Tested-by: default avatarIllya Klymov <xanf@xanf.me>
Signed-off-by: default avatarJiang Liu <jiang.liu@huawei.com>
Acked-by: default avatarYinghai Lu <yinghai@kernel.org>
Cc: 3.9+ <stable@vger.kernel.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 94add0f8
...@@ -670,6 +670,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) ...@@ -670,6 +670,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
struct pci_bus *bus = slot->bridge->pci_bus; struct pci_bus *bus = slot->bridge->pci_bus;
struct acpiphp_func *func; struct acpiphp_func *func;
int num, max, pass; int num, max, pass;
LIST_HEAD(add_list);
if (slot->flags & SLOT_ENABLED) if (slot->flags & SLOT_ENABLED)
goto err_exit; goto err_exit;
...@@ -694,13 +695,15 @@ static int __ref enable_device(struct acpiphp_slot *slot) ...@@ -694,13 +695,15 @@ static int __ref enable_device(struct acpiphp_slot *slot)
max = pci_scan_bridge(bus, dev, max, pass); max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate) { if (pass && dev->subordinate) {
check_hotplug_bridge(slot, dev); check_hotplug_bridge(slot, dev);
pci_bus_size_bridges(dev->subordinate); pcibios_resource_survey_bus(dev->subordinate);
__pci_bus_size_bridges(dev->subordinate,
&add_list);
} }
} }
} }
} }
pci_bus_assign_resources(bus); __pci_bus_assign_resources(bus, &add_list, NULL);
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus); acpiphp_set_hpp_values(bus);
acpiphp_set_acpi_region(slot); acpiphp_set_acpi_region(slot);
......
...@@ -202,6 +202,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, ...@@ -202,6 +202,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg); struct resource *res, unsigned int reg);
int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
void pci_configure_ari(struct pci_dev *dev); void pci_configure_ari(struct pci_dev *dev);
void __ref __pci_bus_size_bridges(struct pci_bus *bus,
struct list_head *realloc_head);
void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
struct list_head *realloc_head,
struct list_head *fail_head);
/** /**
* pci_ari_enabled - query ARI forwarding status * pci_ari_enabled - query ARI forwarding status
......
...@@ -1044,7 +1044,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, ...@@ -1044,7 +1044,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
; ;
} }
static void __ref __pci_bus_size_bridges(struct pci_bus *bus, void __ref __pci_bus_size_bridges(struct pci_bus *bus,
struct list_head *realloc_head) struct list_head *realloc_head)
{ {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -1115,9 +1115,9 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) ...@@ -1115,9 +1115,9 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
} }
EXPORT_SYMBOL(pci_bus_size_bridges); EXPORT_SYMBOL(pci_bus_size_bridges);
static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
struct list_head *realloc_head, struct list_head *realloc_head,
struct list_head *fail_head) struct list_head *fail_head)
{ {
struct pci_bus *b; struct pci_bus *b;
struct pci_dev *dev; struct pci_dev *dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment