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
- Lines: 282
- Date:
Tue Nov 23 10:10:38 1999
- Orig file:
v2.3.28/linux/arch/alpha/kernel/pci.c
- Orig date:
Sat Oct 9 11:47:50 1999
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 & 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)