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

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

 



On Thu, Dec 4, 2014 at 2:24 PM, Yinghai Lu <yinghai@xxxxxxxxxx> wrote:
> On Thu, Dec 4, 2014 at 8:37 AM, Bjorn Helgaas <bhelgaas@xxxxxxxxxx> 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(+)

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,
---
 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,

[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