Merge branch 'pci/resource'

- Evaluate ACPI "PCI Boot Configuration"_DSM (Benjamin Herrenschmidt)

  - Don't auto-realloc if we're preserving firmware config (Benjamin
    Herrenschmidt)

  - Allow arm64 to reallocate resources if necessary (Benjamin
    Herrenschmidt)

  - Preserve firmware config on arm64 when desired (Benjamin Herrenschmidt)

  - Simplify resource distribution to hotplug bridges (Nicholas Johnson)

* pci/resource:
  PCI: Skip resource distribution when no hotplug bridges
  PCI: Simplify pci_bus_distribute_available_resources()
  arm64: PCI: Preserve firmware configuration when desired
  arm64: PCI: Allow resource reallocation if necessary
  PCI: Don't auto-realloc if we're preserving firmware config
  PCI/ACPI: Evaluate PCI Boot Configuration _DSM
This commit is contained in:
Bjorn Helgaas 2019-07-12 17:08:28 -05:00
commit 8c6af6f042
5 changed files with 62 additions and 32 deletions

View file

@ -168,6 +168,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
struct acpi_pci_generic_root_info *ri; struct acpi_pci_generic_root_info *ri;
struct pci_bus *bus, *child; struct pci_bus *bus, *child;
struct acpi_pci_root_ops *root_ops; struct acpi_pci_root_ops *root_ops;
struct pci_host_bridge *host;
ri = kzalloc(sizeof(*ri), GFP_KERNEL); ri = kzalloc(sizeof(*ri), GFP_KERNEL);
if (!ri) if (!ri)
@ -193,8 +194,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
if (!bus) if (!bus)
return NULL; return NULL;
pci_bus_size_bridges(bus); /* If we must preserve the resource configuration, claim now */
pci_bus_assign_resources(bus); host = pci_find_host_bridge(bus);
if (host->preserve_config)
pci_bus_claim_resources(bus);
/*
* Assign whatever was left unassigned. If we didn't claim above,
* this will reassign everything.
*/
pci_assign_unassigned_root_bus_resources(bus);
list_for_each_entry(child, &bus->children, node) list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child); pcie_bus_configure_settings(child);

View file

@ -894,6 +894,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
int node = acpi_get_node(device->handle); int node = acpi_get_node(device->handle);
struct pci_bus *bus; struct pci_bus *bus;
struct pci_host_bridge *host_bridge; struct pci_host_bridge *host_bridge;
union acpi_object *obj;
info->root = root; info->root = root;
info->bridge = device; info->bridge = device;
@ -930,6 +931,17 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL))
host_bridge->native_ltr = 0; host_bridge->native_ltr = 0;
/*
* 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_scan_child_bus(bus);
pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info,
info); info);

View file

@ -1684,10 +1684,15 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus,
enum enable_type enable_local) enum enable_type enable_local)
{ {
bool unassigned = false; bool unassigned = false;
struct pci_host_bridge *host;
if (enable_local != undefined) if (enable_local != undefined)
return enable_local; return enable_local;
host = pci_find_host_bridge(bus);
if (host->preserve_config)
return auto_disabled;
pci_walk_bus(bus, iov_resources_unassigned, &unassigned); pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
if (unassigned) if (unassigned)
return auto_enabled; return auto_enabled;
@ -1860,16 +1865,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
extend_bridge_window(bridge, mmio_pref_res, add_list, extend_bridge_window(bridge, mmio_pref_res, add_list,
available_mmio_pref); available_mmio_pref);
/*
* Calculate the total amount of extra resource space we can
* pass to bridges below this one. This is basically the
* extra space reduced by the minimal required space for the
* non-hotplug bridges.
*/
remaining_io = available_io;
remaining_mmio = available_mmio;
remaining_mmio_pref = available_mmio_pref;
/* /*
* Calculate how many hotplug bridges and normal bridges there * Calculate how many hotplug bridges and normal bridges there
* are on this bus. We will distribute the additional available * are on this bus. We will distribute the additional available
@ -1882,6 +1877,34 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
normal_bridges++; normal_bridges++;
} }
/*
* There is only one bridge on the bus so it gets all available
* resources which it can then distribute to the possible hotplug
* bridges below.
*/
if (hotplug_bridges + normal_bridges == 1) {
dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
if (dev->subordinate) {
pci_bus_distribute_available_resources(dev->subordinate,
add_list, available_io, available_mmio,
available_mmio_pref);
}
return;
}
if (hotplug_bridges == 0)
return;
/*
* Calculate the total amount of extra resource space we can
* pass to bridges below this one. This is basically the
* extra space reduced by the minimal required space for the
* non-hotplug bridges.
*/
remaining_io = available_io;
remaining_mmio = available_mmio;
remaining_mmio_pref = available_mmio_pref;
for_each_pci_bridge(dev, bus) { for_each_pci_bridge(dev, bus) {
const struct resource *res; const struct resource *res;
@ -1905,21 +1928,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
remaining_mmio_pref -= resource_size(res); remaining_mmio_pref -= resource_size(res);
} }
/*
* There is only one bridge on the bus so it gets all available
* resources which it can then distribute to the possible hotplug
* bridges below.
*/
if (hotplug_bridges + normal_bridges == 1) {
dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
if (dev->subordinate) {
pci_bus_distribute_available_resources(dev->subordinate,
add_list, available_io, available_mmio,
available_mmio_pref);
}
return;
}
/* /*
* Go over devices on this bus and distribute the remaining * Go over devices on this bus and distribute the remaining
* resource space between hotplug bridges. * resource space between hotplug bridges.
@ -1936,8 +1944,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
* Distribute available extra resources equally between * Distribute available extra resources equally between
* hotplug-capable downstream ports taking alignment into * hotplug-capable downstream ports taking alignment into
* account. * account.
*
* Here hotplug_bridges is always != 0.
*/ */
align = pci_resource_alignment(bridge, io_res); align = pci_resource_alignment(bridge, io_res);
io = div64_ul(available_io, hotplug_bridges); io = div64_ul(available_io, hotplug_bridges);

View file

@ -107,9 +107,10 @@ static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
#endif #endif
extern const guid_t pci_acpi_dsm_guid; extern const guid_t pci_acpi_dsm_guid;
#define DEVICE_LABEL_DSM 0x07 #define IGNORE_PCI_BOOT_CONFIG_DSM 0x05
#define RESET_DELAY_DSM 0x08 #define DEVICE_LABEL_DSM 0x07
#define FUNCTION_DELAY_DSM 0x09 #define RESET_DELAY_DSM 0x08
#define FUNCTION_DELAY_DSM 0x09
#else /* CONFIG_ACPI */ #else /* CONFIG_ACPI */
static inline void acpi_pci_add_bus(struct pci_bus *bus) { } static inline void acpi_pci_add_bus(struct pci_bus *bus) { }

View file

@ -508,6 +508,8 @@ struct pci_host_bridge {
unsigned int native_shpc_hotplug:1; /* OS may use SHPC hotplug */ unsigned int native_shpc_hotplug:1; /* OS may use SHPC hotplug */
unsigned int native_pme:1; /* OS may use PCIe PME */ unsigned int native_pme:1; /* OS may use PCIe PME */
unsigned int native_ltr:1; /* OS may use PCIe LTR */ unsigned int native_ltr:1; /* OS may use PCIe LTR */
unsigned int preserve_config:1; /* Preserve FW resource setup */
/* Resource alignment requirements */ /* Resource alignment requirements */
resource_size_t (*align_resource)(struct pci_dev *dev, resource_size_t (*align_resource)(struct pci_dev *dev,
const struct resource *res, const struct resource *res,