patch-2.3.29 linux/arch/alpha/kernel/pci.c

Next file: linux/arch/alpha/kernel/pci_impl.h
Previous file: linux/arch/alpha/kernel/machvec_impl.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.28/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
@@ -6,10 +6,14 @@
  *	David Mosberger (davidm@cs.arizona.edu)
  */
 
+/* 2.3.x PCI/resources, 1999 Andrea Arcangeli <andrea@suse.de> */
+
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
 #include <asm/machvec.h>
 
 #include "proto.h"
@@ -36,7 +40,6 @@
  */
 
 struct pci_controler *hose_head, **hose_tail = &hose_head;
-struct pci_controler *probing_hose;
 
 /*
  * Quirks.
@@ -62,24 +65,93 @@
 	{ 0 }
 };
 
+#define MAX(val1, val2)		((val1) > (val2) ? (val1) : (val2))
+#define ALIGN(val,align)	(((val) + ((align) - 1)) & ~((align) - 1))
+#define KB			1024
+#define MB			(1024*KB)
+#define GB			(1024*MB)
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+			     unsigned long start, unsigned long size)
+{
+	unsigned long alignto;
+
+	if (res->flags & IORESOURCE_IO)
+	{
+		/*
+		 * Aligning to 0x800 rather than the minimum base of
+		 * 0x400 is an attempt to avoid having devices in 
+		 * any 0x?C?? range, which is where the de4x5 driver
+		 * probes for EISA cards.
+		 *
+		 * Adaptecs, especially, resent such intrusions.
+		 */
+		alignto = MAX(0x800, size);
+		start = ALIGN(start, alignto);
+	}
+	else if	(res->flags & IORESOURCE_MEM)
+	{
+		/*
+		 * The following holds at least for the Low Cost
+		 * Alpha implementation of the PCI interface:
+		 *
+		 * In sparse memory address space, the first
+		 * octant (16MB) of every 128MB segment is
+		 * aliased to the very first 16 MB of the
+		 * address space (i.e., it aliases the ISA
+		 * memory address space).  Thus, we try to
+		 * avoid allocating PCI devices in that range.
+		 * Can be allocated in 2nd-7th octant only.
+		 * Devices that need more than 112MB of
+		 * address space must be accessed through
+		 * dense memory space only!
+		 */
+		/* align to multiple of size of minimum base */
+		alignto = MAX(0x1000, size);
+		start = ALIGN(start, alignto);
+		if (size > 7 * 16*MB)
+			printk(KERN_WARNING "PCI: dev %s "
+			       "requests %ld bytes of contiguous "
+			       "address space---don't use sparse "
+			       "memory accesses on this device!\n",
+			       dev->name, size);
+		else
+		{
+			if (((start / (16*MB)) & 0x7) == 0) {
+				start &= ~(128*MB - 1);
+				start += 16*MB;
+				start  = ALIGN(start, alignto);
+			}
+			if (start/(128*MB) != (start + size)/(128*MB)) {
+				start &= ~(128*MB - 1);
+				start += (128 + 16)*MB;
+				start  = ALIGN(start, alignto);
+			}
+		}
+	}
+
+	return start;
+}
+#undef MAX
+#undef ALIGN
+#undef KB
+#undef MB
+#undef GB
 
 /* 
  * Pre-layout host-independant device initialization.
  */
 
 static void __init
-pcibios_assign_special(void)
+pcibios_assign_special(struct pci_dev * dev)
 {
-	struct pci_dev *dev;
-	int i;
-
 	/* The first three resources of an IDE controler are often magic, 
 	   so leave them unchanged.  This is true, for instance, of the
 	   Contaq 82C693 as seen on SX164 and DP264.  */
 
-	for (dev = pci_devices; dev; dev = dev->next) {
-		if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
-			continue;
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE)
+	{
+		int i;
+
 		/* Resource 1 of IDE controller is the address of HD_CMD
 		   register which actually occupies a single byte (0x3f6
 		   for ide0) in reported 0x3f4-3f7 range. We have to fix
@@ -87,10 +159,9 @@
 		   controller. */
 		dev->resource[1].start += 2;
 		dev->resource[1].end = dev->resource[1].start;
-	        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-			if (dev->resource[i].flags)
+		for (i = 0; i < PCI_NUM_RESOURCES; i++)
+			if (dev->resource[i].flags && dev->resource[i].start)
 				pci_claim_resource(dev, i);
-		}
 	}
 }
 
@@ -110,31 +181,63 @@
 }
 
 void __init
+pcibios_fixup_resource(struct resource *res, struct resource *root)
+{
+	res->start += root->start;
+	res->end += root->start;
+}
+
+void __init
+pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+{
+	/* Update device resources.  */
+
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (!dev->resource[i].start)
+			continue;
+		if (dev->resource[i].flags & IORESOURCE_IO)
+			pcibios_fixup_resource(&dev->resource[i],
+					       bus->resource[0]);
+		else if (dev->resource[i].flags & IORESOURCE_MEM)
+			pcibios_fixup_resource(&dev->resource[i],
+					       bus->resource[1]);
+	}
+	pcibios_assign_special(dev);
+}
+
+void __init
 pcibios_fixup_bus(struct pci_bus *bus)
 {
 	/* Propogate hose info into the subordinate devices.  */
 
-	struct pci_controler *hose = probing_hose;
+	struct pci_controler *hose = (struct pci_controler *) bus->sysdata;
 	struct pci_dev *dev;
 
 	bus->resource[0] = hose->io_space;
 	bus->resource[1] = hose->mem_space;
 	for (dev = bus->devices; dev; dev = dev->sibling)
-		dev->sysdata = hose;
+		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+			pcibios_fixup_device_resources(dev, bus);
 }
 
 void __init
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			struct resource *res, int resource)
 {
-        unsigned long where, size;
-        u32 reg;
+	int where;
+	u32 reg;
 
-        where = PCI_BASE_ADDRESS_0 + (resource * 4);
-        size = res->end - res->start;
-        pci_read_config_dword(dev, where, &reg);
-        reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
-        pci_write_config_dword(dev, where, reg);
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	reg = (res->start - root->start) | (res->flags & 0xf);
+	pci_write_config_dword(dev, where, reg);
+	if ((res->flags & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+	    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64))
+	{
+		pci_write_config_dword(dev, where+4, 0);
+		printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+	}
 
 	/* ??? FIXME -- record old value for shutdown.  */
 }
@@ -170,6 +273,15 @@
 }
 
 void __init
+pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
+{
+	ranges->io_start -= bus->resource[0]->start;
+	ranges->io_end -= bus->resource[0]->start;
+	ranges->mem_start -= bus->resource[1]->start;
+	ranges->mem_end -= bus->resource[1]->start;
+}
+
+void __init
 common_init_pci(void)
 {
 	struct pci_controler *hose;
@@ -180,15 +292,12 @@
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
 		hose->first_busno = next_busno;
 		hose->last_busno = 0xff;
-		probing_hose = hose;
 		bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
 		hose->bus = bus;
 		next_busno = hose->last_busno = bus->subordinate;
 		next_busno += 1;
 	}
-	probing_hose = NULL;
 
-	pcibios_assign_special();
 	pci_assign_unassigned_resources(alpha_mv.min_io_address,
 				        alpha_mv.min_mem_address);
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
@@ -197,17 +306,11 @@
 
 
 struct pci_controler * __init
-alloc_pci_controler(unsigned long *mem_start)
+alloc_pci_controler(void)
 {
-	unsigned long start = *mem_start;
 	struct pci_controler *hose;
-	if (start & 31)
-		start = (start | 31) + 1;
-	hose = (void *) start;
-	start = (unsigned long) (hose + 1);
-	*mem_start = start;
 
-	memset(hose, 0, sizeof(*hose));
+	hose = alloc_bootmem(sizeof(*hose));
 
 	*hose_tail = hose;
 	hose_tail = &hose->next;
@@ -216,17 +319,11 @@
 }
 
 struct resource * __init
-alloc_resource(unsigned long *mem_start)
+alloc_resource(void)
 {
-	unsigned long start = *mem_start;
 	struct resource *res;
-	if (start & 31)
-		start = (start | 31) + 1;
-	res = (void *) start;
-	start = (unsigned long) (res + 1);
-	*mem_start = start;
 
-	memset(res, 0, sizeof(*res));
+	res = alloc_bootmem(sizeof(*res));
 
 	return res;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)