diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 96911360a28e7..f3663a2f8439c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -874,6 +874,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, struct acpi_device *device = root->device; int node = acpi_get_node(device->handle); struct pci_bus *bus; + struct pci_host_bridge *host_bridge; + union acpi_object *obj; info->root = root; info->bridge = device; @@ -898,6 +900,19 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, if (!bus) goto out_release_info; + host_bridge = to_pci_host_bridge(bus->bridge); + + /* + * Evaluate the "PCI Boot Configuration" _DSM Function. If it + * exists and returns 0, we must preserve any PCI resource + * assignments made by firmware for this host bridge. + */ + obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, + IGNORE_PCI_BOOT_CONFIG_DSM, NULL); + if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) + host_bridge->preserve_config = 1; + ACPI_FREE(obj); + pci_scan_child_bus(bus); pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge), acpi_pci_root_release_info, info); diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 8082b612f5612..62b7fdcc661c3 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -107,9 +107,10 @@ static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { } #endif extern const guid_t pci_acpi_dsm_guid; -#define DEVICE_LABEL_DSM 0x07 -#define RESET_DELAY_DSM 0x08 -#define FUNCTION_DELAY_DSM 0x09 +#define IGNORE_PCI_BOOT_CONFIG_DSM 0x05 +#define DEVICE_LABEL_DSM 0x07 +#define RESET_DELAY_DSM 0x08 +#define FUNCTION_DELAY_DSM 0x09 #else /* CONFIG_ACPI */ static inline void acpi_pci_add_bus(struct pci_bus *bus) { } diff --git a/include/linux/pci.h b/include/linux/pci.h index e870c0b6cc618..19ccc3e99b8ab 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -488,6 +488,8 @@ struct pci_host_bridge { struct msi_controller *msi; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ unsigned int no_ext_tags:1; /* no Extended Tags */ + unsigned int preserve_config:1; /* Preserve FW resource setup */ + /* Resource alignment requirements */ resource_size_t (*align_resource)(struct pci_dev *dev, const struct resource *res,