Commit 8c6af6f0 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 3306e99e 6a381ea6
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
	struct acpi_pci_generic_root_info *ri;
	struct pci_bus *bus, *child;
	struct acpi_pci_root_ops *root_ops;
	struct pci_host_bridge *host;

	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
	if (!ri)
@@ -193,8 +194,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
	if (!bus)
		return NULL;

	pci_bus_size_bridges(bus);
	pci_bus_assign_resources(bus);
	/* If we must preserve the resource configuration, claim now */
	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)
		pcie_bus_configure_settings(child);
+12 −0
Original line number Diff line number Diff line
@@ -894,6 +894,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
	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;
@@ -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))
		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_set_host_bridge_release(host_bridge, acpi_pci_root_release_info,
				    info);
+33 −27
Original line number Diff line number Diff line
@@ -1684,10 +1684,15 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus,
					   enum enable_type enable_local)
{
	bool unassigned = false;
	struct pci_host_bridge *host;

	if (enable_local != undefined)
		return enable_local;

	host = pci_find_host_bridge(bus);
	if (host->preserve_config)
		return auto_disabled;

	pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
	if (unassigned)
		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,
			     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
	 * 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++;
	}

	/*
	 * 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) {
		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);
	}

	/*
	 * 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
	 * 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
		 * hotplug-capable downstream ports taking alignment into
		 * account.
		 *
		 * Here hotplug_bridges is always != 0.
		 */
		align = pci_resource_alignment(bridge, io_res);
		io = div64_ul(available_io, hotplug_bridges);
+4 −3
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
#endif

extern const guid_t pci_acpi_dsm_guid;
#define IGNORE_PCI_BOOT_CONFIG_DSM	0x05
#define DEVICE_LABEL_DSM		0x07
#define RESET_DELAY_DSM			0x08
#define FUNCTION_DELAY_DSM		0x09
+2 −0
Original line number Diff line number Diff line
@@ -508,6 +508,8 @@ struct pci_host_bridge {
	unsigned int	native_shpc_hotplug:1;	/* OS may use SHPC hotplug */
	unsigned int	native_pme:1;		/* OS may use PCIe PME */
	unsigned int	native_ltr:1;		/* OS may use PCIe LTR */
	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,