[RFC PATCH 1/3] PCI: do not compare CPU address with PCI address

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In resource assignment code, limits are exerted to restrict allocated
resource range. However these limits are PCI address but compared to
CPU address in the end. Translated them before comparing.

We can't just use pcibios_bus_to_resource because the limits may not
included in the host bridge window. Introduce a help function to
do this translation, if address missed, return an approximate one.

Signed-off-by: Guo Chao <yan@xxxxxxxxxxxxxxxxxx>
---
 drivers/pci/bus.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index fc1b740..532c0a4 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -99,6 +99,64 @@ void pci_bus_remove_resources(struct pci_bus *bus)
 }
 
 /**
+ * pci_bus_to_resource
+ *
+ * Much like pcibios_bus_to_resource() except it takes a single address
+ * and returns an approximate one if target address is not included
+ * in the bridge window. The approximate address is smaller than required
+ * one is 'bound' is 1, larger than required one if 'bound' is 0.
+ */
+static resource_size_t pci_bus_to_resource(struct pci_bus *bus, int flags,
+				    int mask, resource_size_t addr, int bound)
+{
+	struct pci_host_bridge *bridge;
+	struct pci_host_bridge_window *window, *match = NULL;
+	resource_size_t max = 0, min = -1;
+	resource_size_t offset = -1, start, end;
+
+	while (bus->parent)
+		bus = bus->parent;
+
+	bridge = to_pci_host_bridge(bus->bridge);
+
+	list_for_each_entry(window, &bridge->windows, list) {
+		if ((flags ^ window->res->flags) & mask)
+			continue;
+
+		start = window->res->start - window->offset;
+		end = window->res->end - window->offset;
+
+		if (addr >= start && addr <= end) {
+			offset = window->offset;
+			break;
+		}
+
+		if (bound && addr > end && end > max) {
+			max = end;
+			match = window;
+		} else if (!bound && addr < start && start < min) {
+			min = start;
+			match = window;
+		}
+	}
+
+	if (offset == -1) {
+		/*
+		 * Not even found the matched type. This may happen,
+		 * for example, if try to translate IO address in a HB
+		 * without IO window. Just return the original address,
+		 * it will fail later anyway.
+		 */
+		if (match == NULL)
+			return addr;
+
+		return (bound ? max : min) + match->offset;
+	}
+
+	return addr + offset;
+}
+
+/**
  * pci_bus_alloc_resource - allocate a resource from a parent bus
  * @bus: PCI bus
  * @res: resource to allocate
@@ -129,9 +187,12 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
 
 	type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
 
-	/* don't allocate too high if the pref mem doesn't support 64bit*/
+	/* don't allocate too high if the pref mem doesn't support 64bit */
 	if (!(res->flags & IORESOURCE_MEM_64))
-		max = PCIBIOS_MAX_MEM_32;
+		max = pci_bus_to_resource(bus, res->flags, type_mask,
+							PCIBIOS_MAX_MEM_32, 1);
+
+	min = pci_bus_to_resource(bus, res->flags, type_mask, min, 0);
 
 	pci_bus_for_each_resource(bus, r, i) {
 		if (!r)
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux