Commit 159fbfd0 authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by Bjorn Helgaas
Browse files

PCI: Pass bridge window to pci_bus_release_bridge_resources()



pci_bus_release_bridge_resources() takes type, which is converted into a
bridge window resource in pci_bridge_release_resources().

Find out the correct bridge window for resource whose assignment failed.
Pass that bridge window to pci_bus_release_bridge_resources() instead of
passing the type. When recursing to subordinate, check which bridge windows
have to be released and recurse for each.

For now, use pbus_select_window_for_type() instead of pbus_select_window()
because non-bridge window resources still have their flags reset which
destroys the type information from the struct resource. The struct
pci_dev_resource holds a copy of the flags which are used instead.

Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20250829131113.36754-24-ilpo.jarvinen@linux.intel.com
parent ebbebd88
Loading
Loading
Loading
Loading
+27 −42
Original line number Diff line number Diff line
@@ -1800,51 +1800,24 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
}

static void pci_bridge_release_resources(struct pci_bus *bus,
					 unsigned long type)
					 struct resource *b_win)
{
	struct pci_dev *dev = bus->self;
	struct resource *r;
	struct resource *b_res;
	int idx, ret;

	b_res = &dev->resource[PCI_BRIDGE_RESOURCES];

	/*
	 * 1. If IO port assignment fails, release bridge IO port.
	 * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO.
	 * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit,
	 *    release bridge pref MMIO.
	 * 4. If pref MMIO assignment fails, and bridge pref is 32bit,
	 *    release bridge pref MMIO.
	 * 5. If pref MMIO assignment fails, and bridge pref is not
	 *    assigned, release bridge nonpref MMIO.
	 */
	if (type & IORESOURCE_IO)
		idx = 0;
	else if (!(type & IORESOURCE_PREFETCH))
		idx = 1;
	else if ((type & IORESOURCE_MEM_64) &&
		 (b_res[2].flags & IORESOURCE_MEM_64))
		idx = 2;
	else if (!(b_res[2].flags & IORESOURCE_MEM_64) &&
		 (b_res[2].flags & IORESOURCE_PREFETCH))
		idx = 2;
	else
		idx = 1;

	r = &b_res[idx];

	if (!r->parent)
	if (!b_win->parent)
		return;

	idx = pci_resource_num(dev, b_win);

	/* If there are children, release them all */
	release_child_resources(r);
	release_child_resources(b_win);

	ret = pci_release_resource(dev, PCI_BRIDGE_RESOURCES + idx);
	ret = pci_release_resource(dev, idx);
	if (ret)
		return;

	pci_setup_one_bridge_window(dev, PCI_BRIDGE_RESOURCES + idx);
	pci_setup_one_bridge_window(dev, idx);
}

enum release_type {
@@ -1857,7 +1830,7 @@ enum release_type {
 * a larger window later.
 */
static void pci_bus_release_bridge_resources(struct pci_bus *bus,
					     unsigned long type,
					     struct resource *b_win,
					     enum release_type rel_type)
{
	struct pci_dev *dev;
@@ -1865,6 +1838,8 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus,

	list_for_each_entry(dev, &bus->devices, bus_list) {
		struct pci_bus *b = dev->subordinate;
		struct resource *res;

		if (!b)
			continue;

@@ -1873,9 +1848,15 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus,
		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
			continue;

		if (rel_type == whole_subtree)
			pci_bus_release_bridge_resources(b, type,
						 whole_subtree);
		if (rel_type != whole_subtree)
			continue;

		pci_bus_for_each_resource(b, res) {
			if (res->parent != b_win)
				continue;

			pci_bus_release_bridge_resources(b, res, whole_subtree);
		}
	}

	if (pci_is_root_bus(bus))
@@ -1885,7 +1866,7 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus,
		return;

	if ((rel_type == whole_subtree) || is_leaf_bridge)
		pci_bridge_release_resources(bus, type);
		pci_bridge_release_resources(bus, b_win);
}

static void pci_bus_dump_res(struct pci_bus *bus)
@@ -2282,9 +2263,13 @@ static void pci_prepare_next_assign_round(struct list_head *fail_head,
	 * enough to contain child device resources.
	 */
	list_for_each_entry(fail_res, fail_head, list) {
		pci_bus_release_bridge_resources(fail_res->dev->bus,
						 fail_res->flags & PCI_RES_TYPE_MASK,
						 rel_type);
		struct pci_bus *bus = fail_res->dev->bus;
		struct resource *b_win;

		b_win = pbus_select_window_for_type(bus, fail_res->flags);
		if (!b_win)
			continue;
		pci_bus_release_bridge_resources(bus, b_win, rel_type);
	}

	/* Restore size and flags */