[parisc-linux-cvs] 2.4.0 PCI patch

Grant Grundler grundler@cup.hp.com
Tue, 20 Feb 2001 17:23:34 -0800 (PST)


Hi all,
This patch reflects my current tree and is known to work on A500.
I expect to test on c3k (32 and 64-bit) tomorrow.
I won't test on any Dino based systems. If someone wants to test
dino PCI, I'll help debug problems (I don't expect any).

The diff for kernel/lba_pci.c, kernel/pci.c, and include/asm-parisc/pci.h
are relative to head. The diff for drivers/pci/* is relative to -rLINUX_240.

Notes:
o changes to arch/parisc code are really minor.
   - still ignore pci_assign_unassigned_resources() and use my
     own pcibios_assign_unassigned_resources(). I prefer to treat
     PCI HBA's as independent objects.

o PCI-PCI bridge support is broken in 2.4.0 (perhaps only for Alpha):
   - Prefetchable Memory window registers were enabled (they shouldn't be).
   - pbus_assign_resources() was clobbering PCI-PCI bridge resources
     which had been allocated in pci_assign_resource().

o hppa specific changes in generic code:
   - don't disable devices before checking resource needs.
     (Kills console output and hangs the machine)
   - assign PCI-PCI bridge IO/MEM window resources in pci_assign_resource()
   - PCI-PCI Bridge Command: set PERR and SERR bits
   - PCI-PCI Bridge Control: don't enable ISA mode
   - PCI-PCI Bridge Control: set PERR and SERR bits
     I want errors propogated back upstream when they occur.

Feedback is welcome.

thanks,
grant


Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.20
diff -u -p -r1.20 lba_pci.c
--- lba_pci.c	2001/01/24 23:59:51	1.20
+++ lba_pci.c	2001/02/20 23:59:18
@@ -801,7 +801,7 @@ lba_fixup_bus(struct pci_bus *bus)
 
 #if 0
 /* FIXME/REVISIT - finish figuring out to set FBB on both
-** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL.
+** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL.
 ** Can't fixup here anyway....garr...
 */
 	if (fbb_enable) {
@@ -1185,7 +1185,7 @@ lba_driver_callback(struct hp_device *d,
 	void *tmp_obj;
 
 	/* from drivers/pci/setup-bus.c */
-	extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
+	extern void __init pci_setup_bridge(struct pci_bus *);
 
 	/* Read HW Rev First */
 	func_class = READ_REG32(d->hpa + LBA_FCLASS);
@@ -1259,16 +1259,15 @@ lba_driver_callback(struct hp_device *d,
 		/* Go ask PDC PAT what resources this LBA has */
 		lba_pat_resources(d, lba_dev);
 
-	} else {
+	} else
 #endif
+	{
 		/* Sprockets PDC uses NPIOP region */
 		pci_port = &lba_astro_port_ops;
 
 		/* Poke the chip a bit for /proc output */
 		lba_legacy_resources(d, lba_dev);
-#ifdef __LP64__
 	}
-#endif
 
 	/* 
 	** Tell PCI support another PCI bus was found.
@@ -1294,10 +1293,6 @@ lba_driver_callback(struct hp_device *d,
 		DBG_PAT("\nLBA LMMIO resource tree\n");
 		lba_dump_res(&lba_dev->hba.mem_space, 2);
 #endif
-
-		/* program *all* PCI-PCI bridge range registers */
-		DBG_PAT("LBA pbus_set_ranges()\n");
-		pbus_set_ranges(lba_bus, NULL);
 	}
 #endif /* __LP64__ */
 
Index: arch/parisc/kernel/pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/pci.c,v
retrieving revision 1.17
diff -u -p -r1.17 pci.c
--- pci.c	2001/01/24 23:59:51	1.17
+++ pci.c	2001/02/20 23:59:18
@@ -6,8 +6,8 @@
  *
  * Copyright (C) 1997, 1998 Ralf Baechle
  * Copyright (C) 1999 SuSE GmbH
- * Copyright (C) 1999 Hewlett-Packard Company
- * Copyright (C) 1999, 2000 Grant Grundler
+ * Copyright (C) 1999-2001 Hewlett-Packard Company
+ * Copyright (C) 1999-2001 Grant Grundler
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -124,17 +124,19 @@ void pcibios_fixup_bus(struct pci_bus *b
 {
 	ASSERT(pci_bios != NULL);
 
-        /* If this is a bridge, get the current bases */
-	if (bus->self) {
+        /* If this is a PCI-PCI bridge, get the current bases */
+	if (bus->self
+#ifdef __LP64__
+	&& !pdc_pat
+#endif
+		) {
 		pci_read_bridge_bases(bus);
 	}
 
-	if (pci_bios) {
-		if (pci_bios->fixup_bus) {
-			(*pci_bios->fixup_bus)(bus);
-		} else {
-			printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
-		}
+	if (pci_bios->fixup_bus) {
+		(*pci_bios->fixup_bus)(bus);
+	} else {
+		printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
 	}
 }
 
@@ -234,7 +236,7 @@ pcibios_update_resource(
 		barnum, res->start, res->end, (int) res->flags);
 
 	if (barnum >= PCI_BRIDGE_RESOURCES) {
-		/* handled in pbus_set_ranges_data() */
+		/* handled in PCI-PCI bridge specific support */
 		return;
 	}
 
@@ -302,7 +304,7 @@ pcibios_set_master(struct pci_dev *dev)
 
 
 /*
-** called by drivers/pci/setup-res.c:pbus_set_ranges().
+** called by drivers/pci/setup-res.c:pci_setup_bridge().
 */
 void pcibios_fixup_pbus_ranges(
 	struct pci_bus *bus,
@@ -422,7 +424,7 @@ pcibios_size_bridge(struct pci_bus *bus,
 	inner.io_end -= inner.io_start - 1;
 	inner.mem_end -= inner.mem_start - 1;
 
-	/* Align the sizes up by bridge rules */
+	/* Align the sizes up by PPB rules (4KB for IO, 1MB for MEM) */
 	inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
 	inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
 
@@ -501,21 +503,23 @@ pcibios_enable_device(struct pci_dev *de
 }
 
 
+#ifdef __LP64__
 void __devinit
 pcibios_assign_unassigned_resources(struct pci_bus *bus)
 {
-	struct list_head *ln;
+	/* from drivers/pci/setup-bus.c */
+	extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
 
-        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next)
-	{
-		pdev_assign_unassigned_resources(pci_dev_b(ln));
-	}
+	struct pbus_set_ranges_data ranges;
 
-        /* And for all of the sub-busses.  */
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-		pcibios_assign_unassigned_resources(pci_bus_b(ln));
-
+	ranges.io_end = ranges.io_start
+				= bus->resource[0]->start;
+	ranges.mem_end = ranges.mem_start
+				= bus->resource[1]->start;
+	ranges.found_vga = 0;
+	pbus_assign_resources(bus, &ranges);
 }
+#endif
 
 /*
 ** PARISC specific (unfortunately)
Index: include/asm-parisc/pci.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/pci.h,v
retrieving revision 1.23
diff -u -p -r1.23 pci.h
--- pci.h       2000/12/05 20:10:21     1.23
+++ pci.h       2001/02/21 00:13:44
@@ -192,8 +192,10 @@ extern struct pci_bios_ops *pci_bios;
 extern int pci_post_reset_delay;       /* delay after de-asserting #RESET */
  
 extern void pcibios_register_hba(struct pci_hba_data *);
+extern void pcibios_set_master(struct pci_dev *);
+#ifdef __LP64__
 extern void pcibios_assign_unassigned_resources(struct pci_bus *);
-
+#endif

 /*
 ** used by drivers/pci/pci.c:pci_do_scan_bus()
Index: drivers/pci/.cvsignore
===================================================================
RCS file: .cvsignore
diff -N .cvsignore
--- /dev/null	Tue May  5 14:32:27 1998
+++ /tmp/cvs13365aaa	Tue Feb 20 17:01:26 2001
@@ -0,0 +1,3 @@
+classlist.h
+devlist.h
+gen-devlist
Index: drivers/pci/Config.in
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/Config.in,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
Index: drivers/pci/Makefile
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/Makefile,v
retrieving revision 1.1.1.4
retrieving revision 1.6
diff -u -p -r1.1.1.4 -r1.6
--- Makefile	2001/01/09 16:57:56	1.1.1.4
+++ Makefile	2001/02/02 15:35:25	1.6
@@ -21,6 +21,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
 #
 obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
 obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+obj-$(CONFIG_PARISC64) += setup-bus.o
 
 ifndef CONFIG_X86
 obj-y += syscall.o
Index: drivers/pci/compat.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/compat.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -p -r1.1.1.2 -r1.2
Index: drivers/pci/gen-devlist.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/gen-devlist.c,v
retrieving revision 1.1.1.5
retrieving revision 1.4
diff -u -p -r1.1.1.5 -r1.4
Index: drivers/pci/names.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/names.c,v
retrieving revision 1.1.1.5
retrieving revision 1.3
diff -u -p -r1.1.1.5 -r1.3
Index: drivers/pci/pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/pci.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 pci.c
--- pci.c	2001/01/09 16:57:56	1.1.1.6
+++ pci.c	2001/02/21 00:01:25
@@ -615,6 +615,7 @@ static void pci_read_bases(struct pci_de
 	}
 }
 
+
 void __init pci_read_bridge_bases(struct pci_bus *child)
 {
 	struct pci_dev *dev = child->self;
@@ -628,7 +629,7 @@ void __init pci_read_bridge_bases(struct
 	if (!dev)		/* It's a host bus, nothing to read */
 		return;
 
-	for(i=0; i<3; i++)
+	for(i=0; i<4; i++)
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
 	res = child->resource[0];
@@ -644,12 +645,16 @@ void __init pci_read_bridge_bases(struct
 		res->end = limit + 0xfff;
 		res->name = child->name;
 	} else {
+		
 		/*
-		 * Ugh. We don't know enough about this bridge. Just assume
-		 * that it's entirely transparent.
+		 * Either this is not a PCI-PCI bridge or it's not
+		 * configured yet. Since this code only supports PCI-PCI
+		 * bridge, we better not be called for any other type.
+		 * Don't muck the resources since it will confuse the
+		 * platform specific code which does that.
 		 */
-		printk("Unknown bridge resource %d: assuming transparent\n", 0);
-		child->resource[0] = child->parent->resource[0];
+		printk("PCI : ignoring %s PCI-PCI bridge (I/O BASE not configured)\n", child->self->slot_name);
+		return;
 	}
 
 	res = child->resource[1];
@@ -664,8 +669,8 @@ void __init pci_read_bridge_bases(struct
 		res->name = child->name;
 	} else {
 		/* See comment above. Same thing */
-		printk("Unknown bridge resource %d: assuming transparent\n", 1);
-		child->resource[1] = child->parent->resource[1];
+		printk("PCI : ignoring %s PCI-PCI bridge (MMIO base not configured)\n", child->self->slot_name);
+		return;
 	}
 
 	res = child->resource[2];
@@ -690,11 +695,10 @@ void __init pci_read_bridge_bases(struct
 		res->end = limit + 0xfffff;
 		res->name = child->name;
 	} else {
-		/* See comments above */
-		printk("Unknown bridge resource %d: assuming transparent\n", 2);
-		child->resource[2] = child->parent->resource[2];
+		/* Base > limit means the prefetchable mem is disabled.*/
 	}
 }
+
 
 static struct pci_bus * __init pci_alloc_bus(void)
 {
Index: drivers/pci/proc.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/proc.c,v
retrieving revision 1.1.1.6
retrieving revision 1.6
diff -u -p -r1.1.1.6 -r1.6
Index: drivers/pci/setup-bus.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/setup-bus.c,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 setup-bus.c
--- setup-bus.c	2001/01/09 16:57:56	1.1.1.2
+++ setup-bus.c	2001/02/21 00:01:26
@@ -32,6 +32,7 @@
 
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 
+
 static int __init
 pbus_assign_resources_sorted(struct pci_bus *bus,
 			     struct pbus_set_ranges_data *ranges)
@@ -46,7 +47,6 @@ pbus_assign_resources_sorted(struct pci_
 	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
 		u16 class = dev->class >> 8;
-		u16 cmd;
 
 		/* First, disable the device to avoid side
 		   effects of possibly overlapping I/O and
@@ -57,12 +57,23 @@ pbus_assign_resources_sorted(struct pci_
 		if (class == PCI_CLASS_DISPLAY_VGA
 				|| class == PCI_CLASS_NOT_DEFINED_VGA)
 			found_vga = 1;
+#ifndef __hppa__
+/*
+** If I/O or MEM ranges are overlapping, that's a BIOS bug.
+** Fix it in quirks?
+**
+** Disabling *all* devices is bad. Console, root, etc get
+** disabled this way.
+** -ggg
+*/
 		else if (class >> 8 != PCI_BASE_CLASS_BRIDGE) {
+			u16 cmd;
 			pci_read_config_word(dev, PCI_COMMAND, &cmd);
 			cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY
 						| PCI_COMMAND_MASTER);
 			pci_write_config_word(dev, PCI_COMMAND, cmd);
 		}
+#endif
 
 		/* Reserve some resources for CardBus.
 		   Are these values reasonable? */
@@ -137,8 +148,10 @@ pci_setup_bridge(struct pci_bus *bus)
 	pcibios_fixup_pbus_ranges(bus, &ranges);
 
 	DBGC(("PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
-	DBGC(("  IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
-	DBGC(("  MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
+	DBGC(("  IO window : %04lx-%04lx\n", ranges.io_start, ranges.io_end));
+	DBGC(("  MEM window: %08lx-%08lx\n", ranges.mem_start,ranges.mem_end));
+	DBGC(("  Pref MEM  : %lx-%lx\n", bus->resource[2]->start,
+		bus->resource[2]->end));
 
 	/* Set up the top and bottom of the PCI I/O segment for this bus. */
 	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
@@ -161,17 +174,57 @@ pci_setup_bridge(struct pci_bus *bus)
 	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 
 	/* Set up PREF base/limit. */
-	l = (bus->resource[2]->start >> 16) & 0xfff0;
-	l |= bus->resource[2]->end & 0xfff00000;
+	if (bus->resource[2]->start == bus->resource[2]->end) {
+		/*
+		** 5.3.2 Prefetchable Memory Base and Limit Address Registers
+		**     (From DEC 21154 Data sheet, page 67)
+		** "To turn off the prefetchable memory address range,
+		** write the prefetchable memory base address register
+		** with a value greater than that of the prefetchable
+		** memory limit address register...."
+		**
+		** We can't otherwise disable Prefetchable mem window
+		** since the PCI_COMMAND_MEMORY bit is shared with
+		** non-prefetchable MEM window register.
+		*/
+		l = 0x0000ffff;
+	} else {
+		l = (bus->resource[2]->start >> 16) & 0xfff0;
+		l |= bus->resource[2]->end & 0xfff00000;
+	}
 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
+#ifdef __hppa__
+/* XXX FIXME
+** PCI_BRIDGE_CONTROL and PCI_COMMAND programming need to be revisited
+** to support FBB.  Make all this crud "configurable" by the arch specific
+** (ie "PCI BIOS") support and the ifdef __hppa__ crap can go away then.
+*/
+	/*
+	** ISA stuff confuses PDC PAT configuration.
+	** VGA will probably crash the system at the moment.
+	** (Fortunately, only _A_ dares install VGA in a parisc box :^)
+	** - ggg
+	*/
+	l = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+#else
 	/* Check if we have VGA behind the bridge.
 	   Enable ISA in either case. */
 	l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
+#endif
 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+
+
+	pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007
+#ifdef __hppa__
+			/* servers definitely want SERR/PERR enabled. */
+			| PCI_COMMAND_SERR | PCI_COMMAND_PARITY
+#endif
+		);
 }
 
-static void __init
+
+void __init
 pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
 {
 	struct list_head *ln;
@@ -183,24 +236,16 @@ pbus_assign_resources(struct pci_bus *bu
 		ranges->found_vga = 1;
 		/* Propogate presence of the VGA to upstream bridges */
 		for (b = bus; b->parent; b = b->parent) {
-#if 0
-			/* ? Do we actually need to enable PF memory? */
-			b->resource[2]->start = 0;
-#endif
 			b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
 		}
 	}
+
 	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
 		struct pci_bus *b = pci_bus_b(ln);
 
-		b->resource[0]->start = ranges->io_start = ranges->io_end;
-		b->resource[1]->start = ranges->mem_start = ranges->mem_end;
-
+		ranges->io_start = ranges->io_end;
+		ranges->mem_start = ranges->mem_end;
 		pbus_assign_resources(b, ranges);
-
-		b->resource[0]->end = ranges->io_end - 1;
-		b->resource[1]->end = ranges->mem_end - 1;
-
 		pci_setup_bridge(b);
 	}
 }
Index: drivers/pci/setup-irq.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/setup-irq.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
Index: drivers/pci/setup-res.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/setup-res.c,v
retrieving revision 1.1.1.3
diff -u -p -r1.1.1.3 setup-res.c
--- setup-res.c	2001/01/09 16:57:56	1.1.1.3
+++ setup-res.c	2001/02/21 00:01:26
@@ -14,6 +14,8 @@
 /*
  * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
  *	     Resource sorting
+ * Feb 2001, Grant Grundler <gurndler@puffin.external.hp.com>
+ *           Fix PCI-PCI bridge support and add __hppa__ support
  */
 
 #include <linux/init.h>
@@ -25,7 +27,7 @@
 #include <linux/slab.h>
 
 
-#define DEBUG_CONFIG 1
+#define DEBUG_CONFIG 0
 #if DEBUG_CONFIG
 # define DBGC(args)     printk args
 #else
@@ -115,7 +117,7 @@ pci_assign_resource(struct pci_dev *dev,
 		 * window (it will just not perform as well).
 		 */
 		if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) {
-			printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name);
+			printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->slot_name);
 			return -EBUSY;
 		}
 	}
@@ -138,11 +140,13 @@ pdev_sort_resources(struct pci_dev *dev,
 		struct resource_list *list, *tmp;
 		unsigned long r_size;
 
+#ifndef __hppa__
 		/* PCI-PCI bridges may have I/O ports or
 		   memory on the primary bus */
 		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI &&
 						i >= PCI_BRIDGE_RESOURCES)
 			continue;
+#endif
 
 		r = &dev->resource[i];
 		r_size = r->end - r->start;
Index: drivers/pci/syscall.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/pci/syscall.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -p -r1.1.1.2 -r1.2