diff mbox

Regression: bug 85491: radeon 0000:01:00.0: Fatal error during GPU init

Message ID CAE9FiQVKgG64o+8ngqh=7tQ0jWqqSMGkxtuDc-tgqhVmfU+jjw@mail.gmail.com
State Not Applicable
Headers show

Commit Message

Yinghai Lu Dec. 5, 2014, 12:24 a.m. UTC
On Thu, Dec 4, 2014 at 2:24 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> On Thu, Dec 4, 2014 at 8:37 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>>> pci=realloc should workaround the problem, as it would take control of
>>> the bridge mmio BAR, and allocate more range for mmio pref under it.
>>
>> I don't think pci=realloc is the answer because
>>
>>   1) It's a poor user experience.  We should be able to handle this
>>      automatically, without asking the user to do anything.
>
> we can detect that when bridge support 64bit mmio pref, and reject
> child device pref that only
> support mmio pref non-b64bit.
>
>>
>>   2) It puts the radeon framebuffer in the non-prefetchable window, and we
>>      should be able to keep it in the prefetchable window.
>
> clear bridge 64bit flags if all children does not support that?
>
> even that slot supports hotplug.

Please check if attached patch is good for v3.18.

---
 drivers/pci/setup-bus.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

     struct pci_dev *dev;
@@ -1171,6 +1217,10 @@ void __pci_bus_size_bridges(struct pci_b
         b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];
         mask = IORESOURCE_MEM;
         prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+        if (b_res[2].flags & IORESOURCE_MEM_64)
+            pbus_check_mem64(bus, prefmask, prefmask, realloc_head);
+
         if (b_res[2].flags & IORESOURCE_MEM_64) {
             prefmask |= IORESOURCE_MEM_64;
             ret = pbus_size_mem(bus, prefmask, prefmask,
diff mbox

Patch

---
 drivers/pci/setup-bus.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -1118,6 +1118,52 @@  handle_done:
 	;
 }
 
+static void pbus_check_mem64(struct pci_bus *bus, unsigned long mask,
+			 unsigned long type, struct list_head *realloc_head)
+{
+	struct pci_dev *dev;
+	resource_size_t align;
+	resource_size_t aligns[18];	/* Alignments from 1Mb to 128Gb */
+	int order;
+	unsigned int mem64_mask = 0;
+	struct resource *b_res = find_free_bus_resource(bus, mask, type);
+
+	if (!b_res || !(b_res->flags & IORESOURCE_MEM_64))
+		return;
+
+	memset(aligns, 0, sizeof(aligns));
+
+	mem64_mask = IORESOURCE_MEM_64;
+	b_res->flags &= ~IORESOURCE_MEM_64;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		int i;
+
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+
+			if (r->parent || (r->flags & mask) != type)
+				continue;
+#ifdef CONFIG_PCI_IOV
+			if (realloc_head && i >= PCI_IOV_RESOURCES &&
+					i <= PCI_IOV_RESOURCE_END)
+				continue;
+#endif
+			align = pci_resource_alignment(dev, r);
+			order = __ffs(align) - 20;
+			if (order < 0)
+				order = 0;
+			if (order >= ARRAY_SIZE(aligns))
+				continue;
+
+			if (i != PCI_ROM_RESOURCE)
+				mem64_mask &= r->flags & IORESOURCE_MEM_64;
+		}
+	}
+
+	b_res->flags |= mem64_mask;
+}
+
 void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 {
 	struct pci_dev *dev;
@@ -1171,6 +1217,10 @@  void __pci_bus_size_bridges(struct pci_b
 		b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];
 		mask = IORESOURCE_MEM;
 		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+		if (b_res[2].flags & IORESOURCE_MEM_64)
+			pbus_check_mem64(bus, prefmask, prefmask, realloc_head);
+
 		if (b_res[2].flags & IORESOURCE_MEM_64) {
 			prefmask |= IORESOURCE_MEM_64;
 			ret = pbus_size_mem(bus, prefmask, prefmask,