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

Bug#490694: Stuck back at 2.6.24



There was a change to PowerPC PCI setup between 2.6.24 and .25 which
might conceivably have caused this bug.  The attached patch against
Linux 2.6.26 as packaged in "lenny" is intended to revert that change,
so that we can establish whether that is the case.  As I said, I am
unable to test this myself.

See <http://wiki.debian.org/HowToRebuildAnOfficialDebianKernelPackage>
for instructions on applying this to the kernel package.

Ben.

-- 
Ben Hutchings
When you say `I wrote a program that crashed Windows', people just stare ...
and say `Hey, I got those with the system, *for free*'. - Linus Torvalds
--- arch/powerpc/kernel/pci-common.c.orig	2009-07-03 23:38:09.000000000 +0100
+++ arch/powerpc/kernel/pci-common.c	2009-07-03 23:41:23.000000000 +0100
@@ -709,166 +709,6 @@
 }
 EXPORT_SYMBOL(pcibios_bus_to_resource);
 
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-
-	res->start = (res->start + offset) & mask;
-	res->end = (res->end + offset) & mask;
-
-	pr_debug("PCI:%s            %016llx-%016llx\n",
-		 pci_name(dev),
-		 (unsigned long long)res->start,
-		 (unsigned long long)res->end);
-}
-
-
-/* This header fixup will do the resource fixup for all devices as they are
- * probed, but not for bridge ranges
- */
-static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
-{
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	int i;
-
-	if (!hose) {
-		printk(KERN_ERR "No host bridge for PCI dev %s !\n",
-		       pci_name(dev));
-		return;
-	}
-	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-		struct resource *res = dev->resource + i;
-		if (!res->flags)
-			continue;
-		/* On platforms that have PPC_PCI_PROBE_ONLY set, we don't
-		 * consider 0 as an unassigned BAR value. It's technically
-		 * a valid value, but linux doesn't like it... so when we can
-		 * re-assign things, we do so, but if we can't, we keep it
-		 * around and hope for the best...
-		 */
-		if (res->start == 0 && !(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
-			pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n",
-				 pci_name(dev), i,
-				 (unsigned long long)res->start,
-				 (unsigned long long)res->end,
-				 (unsigned int)res->flags);
-			res->end -= res->start;
-			res->start = 0;
-			res->flags |= IORESOURCE_UNSET;
-			continue;
-		}
-
-		pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
-			 pci_name(dev), i,
-			 (unsigned long long)res->start,\
-			 (unsigned long long)res->end,
-			 (unsigned int)res->flags);
-
-		fixup_resource(res, dev);
-	}
-
-	/* Call machine specific resource fixup */
-	if (ppc_md.pcibios_fixup_resources)
-		ppc_md.pcibios_fixup_resources(dev);
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
-
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
-{
-	struct pci_controller *hose = pci_bus_to_host(bus);
-	struct pci_dev *dev = bus->self;
-
-	pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
-
-	/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
-	 * now differently between 32 and 64 bits.
-	 */
-	if (dev != NULL) {
-		struct resource *res;
-		int i;
-
-		for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
-			if ((res = bus->resource[i]) == NULL)
-				continue;
-			if (!res->flags)
-				continue;
-			if (i >= 3 && bus->self->transparent)
-				continue;
-			/* On PowerMac, Apple leaves bridge windows open over
-			 * an inaccessible region of memory space (0...fffff)
-			 * which is somewhat bogus, but that's what they think
-			 * means disabled...
-			 *
-			 * We clear those to force them to be reallocated later
-			 *
-			 * We detect such regions by the fact that the base is
-			 * equal to the pci_mem_offset of the host bridge and
-			 * their size is smaller than 1M.
-			 */
-			if (res->flags & IORESOURCE_MEM &&
-			    res->start == hose->pci_mem_offset &&
-			    res->end < 0x100000) {
-				printk(KERN_INFO
-				       "PCI: Closing bogus Apple Firmware"
-				       " region %d on bus 0x%02x\n",
-				       i, bus->number);
-				res->flags = 0;
-				continue;
-			}
-
-			pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
-				 pci_name(dev), i,
-				 (unsigned long long)res->start,\
-				 (unsigned long long)res->end,
-				 (unsigned int)res->flags);
-
-			fixup_resource(res, dev);
-		}
-	}
-
-	/* Additional setup that is different between 32 and 64 bits for now */
-	pcibios_do_bus_setup(bus);
-
-	/* Platform specific bus fixups */
-	if (ppc_md.pcibios_fixup_bus)
-		ppc_md.pcibios_fixup_bus(bus);
-
-	/* Read default IRQs and fixup if necessary */
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		pci_read_irq_line(dev);
-		if (ppc_md.pci_irq_fixup)
-			ppc_md.pci_irq_fixup(dev);
-	}
-}
-
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
-{
-	/* When called from the generic PCI probe, read PCI<->PCI bridge
-	 * bases before proceeding
-	 */
-	if (bus->self != NULL)
-		pci_read_bridge_bases(bus);
-	__pcibios_fixup_bus(bus);
-}
-EXPORT_SYMBOL(pcibios_fixup_bus);
-
-/* When building a bus from the OF tree rather than probing, we need a
- * slightly different version of the fixup which doesn't read the
- * bridge bases using config space accesses
- */
-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
-{
-	__pcibios_fixup_bus(bus);
-}
-
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
 	if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
--- arch/powerpc/kernel/pci_32.c.orig	2008-07-13 22:51:29.000000000 +0100
+++ arch/powerpc/kernel/pci_32.c	2009-07-03 23:42:56.000000000 +0100
@@ -38,6 +38,7 @@
 
 void pcibios_make_OF_bus_map(void);
 
+static void pcibios_fixup_resources(struct pci_dev* dev);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_PPC_OF
@@ -94,6 +95,53 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CPC710_PCI64,	fixup_cpc710_pci64);
 
+static void
+pcibios_fixup_resources(struct pci_dev *dev)
+{
+	struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
+	int i;
+	resource_size_t offset, mask;
+
+	if (!hose) {
+		printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev));
+		return;
+	}
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		struct resource *res = dev->resource + i;
+		if (!res->flags)
+			continue;
+		if (res->end == 0xffffffff) {
+			DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
+			    pci_name(dev), i, (u64)res->start, (u64)res->end);
+			res->end -= res->start;
+			res->start = 0;
+			res->flags |= IORESOURCE_UNSET;
+			continue;
+		}
+		offset = 0;
+		mask = (resource_size_t)-1;
+		if (res->flags & IORESOURCE_MEM) {
+			offset = hose->pci_mem_offset;
+		} else if (res->flags & IORESOURCE_IO) {
+			offset = (unsigned long) hose->io_base_virt
+				- isa_io_base;
+			mask = 0xffffffffu;
+		}
+		if (offset != 0) {
+			res->start = (res->start + offset) & mask;
+			res->end = (res->end + offset) & mask;
+			DBG("PCI: Fixup res %d (0x%lx) of dev %s: %llx -> %llx\n",
+			    i, res->flags, pci_name(dev),
+			    (u64)res->start - offset, (u64)res->start);
+		}
+	}
+
+	/* Call machine specific resource fixup */
+	if (ppc_md.pcibios_fixup_resources)
+		ppc_md.pcibios_fixup_resources(dev);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,		PCI_ANY_ID,			pcibios_fixup_resources);
+ 
 #ifdef CONFIG_PPC_OF
 /*
  * Functions below are used on OpenFirmware machines.
@@ -418,14 +466,14 @@
 
 subsys_initcall(pcibios_init);
 
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
 	unsigned long io_offset;
 	struct resource *res;
+	struct pci_dev *dev;
 	int i;
 
-	/* Hookup PHB resources */
 	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
 	if (bus->parent == NULL) {
 		/* This is a host bridge - fill in its resources */
@@ -456,6 +504,37 @@
 			}
 			bus->resource[i+1] = res;
 		}
+	} else {
+		/* This is a subordinate bridge */
+		pci_read_bridge_bases(bus);
+
+		for (i = 0; i < 4; ++i) {
+			if ((res = bus->resource[i]) == NULL)
+				continue;
+			if (!res->flags || bus->self->transparent)
+				continue;
+			if (io_offset && (res->flags & IORESOURCE_IO)) {
+				res->start = (res->start + io_offset) &
+					0xffffffffu;
+				res->end = (res->end + io_offset) &
+					0xffffffffu;
+			} else if (hose->pci_mem_offset
+				   && (res->flags & IORESOURCE_MEM)) {
+				res->start += hose->pci_mem_offset;
+				res->end += hose->pci_mem_offset;
+			}
+		}
+	}
+
+	/* Platform specific bus fixups */
+	if (ppc_md.pcibios_fixup_bus)
+		ppc_md.pcibios_fixup_bus(bus);
+
+	/* Read default IRQs and fixup if necessary */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_read_irq_line(dev);
+		if (ppc_md.pci_irq_fixup)
+			ppc_md.pci_irq_fixup(dev);
 	}
 }
 
--- arch/powerpc/kernel/pci_64.c.orig	2008-07-13 22:51:29.000000000 +0100
+++ arch/powerpc/kernel/pci_64.c	2009-07-03 23:38:28.000000000 +0100
@@ -41,6 +41,9 @@
 
 unsigned long pci_probe_only = 1;
 
+static void fixup_resource(struct resource *res, struct pci_dev *dev);
+static void do_bus_setup(struct pci_bus *bus);
+
 /* pci_io_base -- the base address from which io bars are offsets.
  * This is the lowest I/O base address (so bar values are always positive),
  * and it *must* be the start of ISA space if an ISA bus exists because
@@ -157,6 +160,7 @@
 		res->end = base + size - 1;
 		res->flags = flags;
 		res->name = pci_name(dev);
+		fixup_resource(res, dev);
 	}
 }
 
@@ -225,7 +229,7 @@
 EXPORT_SYMBOL(of_create_pci_dev);
 
 void __devinit of_scan_bus(struct device_node *node,
-			   struct pci_bus *bus)
+				  struct pci_bus *bus)
 {
 	struct device_node *child;
 	const u32 *reg;
@@ -246,26 +250,19 @@
 		dev = of_create_pci_dev(child, bus, devfn);
 		if (!dev)
 			continue;
-		DBG("    dev header type: %x\n", dev->hdr_type);
-	}
-
-	/* Ally all fixups */
-	pcibios_fixup_of_probed_bus(bus);
+		DBG("dev header type: %x\n", dev->hdr_type);
 
-	/* Now scan child busses */
-	list_for_each_entry(dev, &bus->devices, bus_list) {
 		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
-		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
-			struct device_node *child = pci_device_to_OF_node(dev);
-			if (dev)
-				of_scan_pci_bridge(child, dev);
-		}
+		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			of_scan_pci_bridge(child, dev);
 	}
+
+	do_bus_setup(bus);
 }
 EXPORT_SYMBOL(of_scan_bus);
 
 void __devinit of_scan_pci_bridge(struct device_node *node,
-				  struct pci_dev *dev)
+			 	struct pci_dev *dev)
 {
 	struct pci_bus *bus;
 	const u32 *busrange, *ranges;
@@ -335,6 +332,7 @@
 		res->start = of_read_number(&ranges[1], 2);
 		res->end = res->start + size - 1;
 		res->flags = flags;
+		fixup_resource(res, dev);
 	}
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
 		bus->number);
@@ -548,13 +546,51 @@
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
+static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
+{
+	struct pci_controller *hose = pci_bus_to_host(dev->bus);
+	unsigned long offset;
+
+	if (res->flags & IORESOURCE_IO) {
+		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+		res->start += offset;
+		res->end += offset;
+	} else if (res->flags & IORESOURCE_MEM) {
+		res->start += hose->pci_mem_offset;
+		res->end += hose->pci_mem_offset;
+	}
+}
+
+void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
+					      struct pci_bus *bus)
+{
+	/* Update device resources.  */
+	int i;
+
+	DBG("%s: Fixup resources:\n", pci_name(dev));
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = &dev->resource[i];
+		if (!res->flags)
+			continue;
+
+		DBG("  0x%02x < %08lx:0x%016lx...0x%016lx\n",
+		    i, res->flags, res->start, res->end);
+
+		fixup_resource(res, dev);
+
+		DBG("       > %08lx:0x%016lx...0x%016lx\n",
+		    res->flags, res->start, res->end);
+	}
+}
+EXPORT_SYMBOL(pcibios_fixup_device_resources);
+
 void __devinit pcibios_setup_new_device(struct pci_dev *dev)
 {
 	struct dev_archdata *sd = &dev->dev.archdata;
 
 	sd->of_node = pci_device_to_OF_node(dev);
 
-	DBG("PCI: device %s OF node: %s\n", pci_name(dev),
+	DBG("PCI device %s OF node: %s\n", pci_name(dev),
 	    sd->of_node ? sd->of_node->full_name : "<none>");
 
 	sd->dma_ops = pci_dma_ops;
@@ -568,7 +604,7 @@
 }
 EXPORT_SYMBOL(pcibios_setup_new_device);
 
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
+static void __devinit do_bus_setup(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 
@@ -577,7 +613,42 @@
 
 	list_for_each_entry(dev, &bus->devices, bus_list)
 		pcibios_setup_new_device(dev);
+
+	/* Read default IRQs and fixup if necessary */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_read_irq_line(dev);
+		if (ppc_md.pci_irq_fixup)
+			ppc_md.pci_irq_fixup(dev);
+	}
+}
+
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev = bus->self;
+	struct device_node *np;
+
+	np = pci_bus_to_OF_node(bus);
+
+	DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>");
+
+	if (dev && pci_probe_only &&
+	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+		/* This is a subordinate bridge */
+
+		pci_read_bridge_bases(bus);
+		pcibios_fixup_device_resources(dev, bus);
+	}
+
+	do_bus_setup(bus);
+
+	if (!pci_probe_only)
+		return;
+
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+			pcibios_fixup_device_resources(dev, bus);
 }
+EXPORT_SYMBOL(pcibios_fixup_bus);
 
 unsigned long pci_address_to_pio(phys_addr_t address)
 {
--- arch/powerpc/platforms/pseries/pci_dlpar.c.orig	2008-07-13 22:51:29.000000000 +0100
+++ arch/powerpc/platforms/pseries/pci_dlpar.c	2009-07-03 23:38:28.000000000 +0100
@@ -83,7 +83,7 @@
 
 /* Must be called before pci_bus_add_devices */
 void
-pcibios_fixup_new_pci_devices(struct pci_bus *bus)
+pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
 {
 	struct pci_dev *dev;
 
@@ -95,6 +95,8 @@
 			/* Fill device archdata and setup iommu table */
 			pcibios_setup_new_device(dev);
 
+			if(fix_bus)
+				pcibios_fixup_device_resources(dev, bus);
 			pci_read_irq_line(dev);
 			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 				struct resource *r = &dev->resource[i];
@@ -127,8 +129,8 @@
 
 	pci_scan_child_bus(child_bus);
 
-	/* Fixup new pci devices */
-	pcibios_fixup_new_pci_devices(child_bus);
+	/* Fixup new pci devices without touching bus struct */
+	pcibios_fixup_new_pci_devices(child_bus, 0);
 
 	/* Make the discovered devices available */
 	pci_bus_add_devices(child_bus);
@@ -164,7 +166,7 @@
 		/* use ofdt-based probe */
 		of_scan_bus(dn, bus);
 		if (!list_empty(&bus->devices)) {
-			pcibios_fixup_new_pci_devices(bus);
+			pcibios_fixup_new_pci_devices(bus, 0);
 			pci_bus_add_devices(bus);
 			eeh_add_device_tree_late(bus);
 		}
@@ -173,7 +175,7 @@
 		slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
 		num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
 		if (num) {
-			pcibios_fixup_new_pci_devices(bus);
+			pcibios_fixup_new_pci_devices(bus, 1);
 			pci_bus_add_devices(bus);
 			eeh_add_device_tree_late(bus);
 		}
@@ -203,7 +205,7 @@
 		eeh_add_device_tree_early(dn);
 
 	scan_phb(phb);
-	pcibios_fixup_new_pci_devices(phb->bus);
+	pcibios_fixup_new_pci_devices(phb->bus, 0);
 	pci_bus_add_devices(phb->bus);
 	eeh_add_device_tree_late(phb->bus);
 
--- drivers/pci/hotplug/rpadlpar_core.c.orig	2009-07-03 23:47:42.000000000 +0100
+++ drivers/pci/hotplug/rpadlpar_core.c	2009-07-03 23:38:28.000000000 +0100
@@ -155,7 +155,7 @@
 	    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		of_scan_pci_bridge(dn, dev);
 
-	pcibios_fixup_new_pci_devices(dev->subordinate);
+	pcibios_fixup_new_pci_devices(dev->subordinate,0);
 
 	/* Claim new bus resources */
 	pcibios_claim_one_bus(dev->bus);
--- include/asm-powerpc/machdep.h.orig	2008-07-13 22:51:29.000000000 +0100
+++ include/asm-powerpc/machdep.h	2009-07-03 23:45:08.000000000 +0100
@@ -209,8 +209,6 @@
 	/* Called at then very end of pcibios_init() */
 	void (*pcibios_after_init)(void);
 
-#endif /* CONFIG_PPC32 */
-
 	/* Called after PPC generic resource fixup to perform
 	   machine specific fixups */
 	void (*pcibios_fixup_resources)(struct pci_dev *);
@@ -218,6 +216,8 @@
 	/* Called for each PCI bus in the system when it's probed */
 	void (*pcibios_fixup_bus)(struct pci_bus *);
 
+#endif /* CONFIG_PPC32 */
+
 	/* Called when pci_enable_device() is called. Returns 0 to
 	 * allow assignment/enabling of the device. */
 	int  (*pcibios_enable_device_hook)(struct pci_dev *);
--- include/asm-powerpc/pci-bridge.h.orig	2008-07-13 22:51:29.000000000 +0100
+++ include/asm-powerpc/pci-bridge.h	2009-07-03 23:38:28.000000000 +0100
@@ -231,7 +231,7 @@
 
 /** Discover new pci devices under this bus, and add them */
 extern void pcibios_add_pci_devices(struct pci_bus *bus);
-extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus);
+extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
 
 extern int pcibios_remove_root_bus(struct pci_controller *phb);
 
--- include/asm-powerpc/pci.h.orig	2008-07-13 22:51:29.000000000 +0100
+++ include/asm-powerpc/pci.h	2009-07-03 23:38:28.000000000 +0100
@@ -192,6 +192,9 @@
 	return root;
 }
 
+extern void pcibios_fixup_device_resources(struct pci_dev *dev,
+			struct pci_bus *bus);
+
 extern void pcibios_setup_new_device(struct pci_dev *dev);
 
 extern void pcibios_claim_one_bus(struct pci_bus *b);
@@ -221,8 +224,5 @@
 				 const struct resource *rsrc,
 				 resource_size_t *start, resource_size_t *end);
 
-extern void pcibios_do_bus_setup(struct pci_bus *bus);
-extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus);
-
 #endif	/* __KERNEL__ */
 #endif /* __ASM_POWERPC_PCI_H */

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: