patch-2.4.21 linux-2.4.21/arch/ia64/kernel/pci.c
Next file: linux-2.4.21/arch/ia64/kernel/perfmon.c
Previous file: linux-2.4.21/arch/ia64/kernel/pal.S
Back to the patch index
Back to the overall index
- Lines: 342
- Date:
2003-06-13 07:51:29.000000000 -0700
- Orig file:
linux-2.4.20/arch/ia64/kernel/pci.c
- Orig date:
2002-11-28 15:53:09.000000000 -0800
diff -urN linux-2.4.20/arch/ia64/kernel/pci.c linux-2.4.21/arch/ia64/kernel/pci.c
@@ -43,6 +43,8 @@
extern void ia64_mca_check_errors( void );
#endif
+static unsigned int acpi_root_bridges;
+
struct pci_fixup pcibios_fixups[1];
struct pci_ops *pci_root_ops;
@@ -167,7 +169,7 @@
*/
static struct pci_controller *
-alloc_pci_controller(int seg)
+alloc_pci_controller (int seg)
{
struct pci_controller *controller;
@@ -181,7 +183,7 @@
}
static struct pci_bus *
-scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
+scan_root_bus (int bus, struct pci_ops *ops, void *sysdata)
{
struct pci_bus *b;
@@ -211,24 +213,152 @@
return b;
}
+static void
+alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags)
+{
+ struct resource *res;
+
+ res = kmalloc(sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return;
+
+ memset(res, 0, sizeof(*res));
+ res->name = name;
+ res->start = start;
+ res->end = end;
+ res->flags = flags;
+
+ request_resource(root, res);
+}
+
+static u64
+add_io_space (acpi_resource_address64 *addr)
+{
+ u64 offset;
+ int sparse = 0;
+ int i;
+
+ if (addr->address_translation_offset == 0)
+ return IO_SPACE_BASE(0); /* part of legacy IO space */
+
+ if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
+ sparse = 1;
+
+ offset = (u64) ioremap(addr->address_translation_offset, 0);
+ for (i = 0; i < num_io_spaces; i++)
+ if (io_space[i].mmio_base == offset &&
+ io_space[i].sparse == sparse)
+ return IO_SPACE_BASE(i);
+
+ if (num_io_spaces == MAX_IO_SPACES) {
+ printk("Too many IO port spaces\n");
+ return ~0;
+ }
+
+ i = num_io_spaces++;
+ io_space[i].mmio_base = offset;
+ io_space[i].sparse = sparse;
+
+ return IO_SPACE_BASE(i);
+}
+
+static acpi_status
+count_window (acpi_resource *resource, void *data)
+{
+ unsigned int *windows = (unsigned int *) data;
+ acpi_resource_address64 addr;
+ acpi_status status;
+
+ status = acpi_resource_to_address64(resource, &addr);
+ if (ACPI_SUCCESS(status))
+ if (addr.resource_type == ACPI_MEMORY_RANGE ||
+ addr.resource_type == ACPI_IO_RANGE)
+ (*windows)++;
+
+ return AE_OK;
+}
+
+struct pci_root_info {
+ struct pci_controller *controller;
+ char *name;
+};
+
+static acpi_status
+add_window (acpi_resource *res, void *data)
+{
+ struct pci_root_info *info = (struct pci_root_info *) data;
+ struct pci_window *window;
+ acpi_resource_address64 addr;
+ acpi_status status;
+ unsigned long flags, offset = 0;
+ struct resource *root;
+
+ status = acpi_resource_to_address64(res, &addr);
+ if (ACPI_SUCCESS(status)) {
+ if (addr.resource_type == ACPI_MEMORY_RANGE) {
+ flags = IORESOURCE_MEM;
+ root = &iomem_resource;
+ offset = addr.address_translation_offset;
+ } else if (addr.resource_type == ACPI_IO_RANGE) {
+ flags = IORESOURCE_IO;
+ root = &ioport_resource;
+ offset = add_io_space(&addr);
+ if (offset == ~0)
+ return AE_OK;
+ } else
+ return AE_OK;
+
+ window = &info->controller->window[info->controller->windows++];
+ window->resource.flags |= flags;
+ window->resource.start = addr.min_address_range;
+ window->resource.end = addr.max_address_range;
+ window->offset = offset;
+
+ alloc_resource(info->name, root, addr.min_address_range + offset,
+ addr.max_address_range + offset, flags);
+ }
+
+ return AE_OK;
+}
+
struct pci_bus *
-pcibios_scan_root(void *handle, int seg, int bus)
+pcibios_scan_root (void *handle, int seg, int bus)
{
+ struct pci_root_info info;
struct pci_controller *controller;
- u64 base, size, offset;
+ unsigned int windows = 0;
+ char *name;
- printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+ acpi_root_bridges++;
controller = alloc_pci_controller(seg);
if (!controller)
- return NULL;
+ goto out1;
controller->acpi_handle = handle;
- acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
- controller->mem_offset = offset;
+ acpi_walk_resources(handle, METHOD_NAME__CRS, count_window, &windows);
+ controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL);
+ if (!controller->window)
+ goto out2;
+
+ name = kmalloc(16, GFP_KERNEL);
+ if (!name)
+ goto out3;
+
+ sprintf(name, "PCI Bus %02x:%02x", seg, bus);
+ info.controller = controller;
+ info.name = name;
+ acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info);
return scan_root_bus(bus, pci_root_ops, controller);
+
+out3:
+ kfree(controller->window);
+out2:
+ kfree(controller);
+out1:
+ return NULL;
}
void __init
@@ -249,7 +379,7 @@
void __init
pcibios_init (void)
{
-# define PCI_BUSES_TO_SCAN 255
+# define PCI_BUSES_TO_SCAN 256
int i = 0;
struct pci_controller *controller;
@@ -261,43 +391,52 @@
platform_pci_fixup(0); /* phase 0 fixups (before buses scanned) */
- printk("PCI: Probing PCI hardware\n");
- controller = alloc_pci_controller(0);
- if (controller)
- for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
- pci_scan_bus(i, pci_root_ops, controller);
+ /* Only probe blindly if ACPI didn't tell us about root bridges */
+ if (!acpi_root_bridges) {
+ printk("PCI: Probing PCI hardware\n");
+ controller = alloc_pci_controller(0);
+ if (controller)
+ for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+ pci_scan_bus(i, pci_root_ops, controller);
+ }
platform_pci_fixup(1); /* phase 1 fixups (after buses scanned) */
return;
}
-static void __init
-pcibios_fixup_resource(struct resource *res, u64 offset)
-{
- res->start += offset;
- res->end += offset;
-}
-
void __init
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus)
{
- int i;
+ struct pci_controller *controller = PCI_CONTROLLER(dev);
+ struct pci_window *window;
+ int i, j;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (!dev->resource[i].start)
continue;
- if (dev->resource[i].flags & IORESOURCE_MEM)
- pcibios_fixup_resource(&dev->resource[i],
- PCI_CONTROLLER(dev)->mem_offset);
+
+#define contains(win, res) ((res)->start >= (win)->start && \
+ (res)->end <= (win)->end)
+
+ for (j = 0; j < controller->windows; j++) {
+ window = &controller->window[j];
+ if (((dev->resource[i].flags & IORESOURCE_MEM &&
+ window->resource.flags & IORESOURCE_MEM) ||
+ (dev->resource[i].flags & IORESOURCE_IO &&
+ window->resource.flags & IORESOURCE_IO)) &&
+ contains(&window->resource, &dev->resource[i])) {
+ dev->resource[i].start += window->offset;
+ dev->resource[i].end += window->offset;
+ }
+ }
}
}
/*
- * Called after each bus is probed, but before its children
- * are examined.
+ * Called after each bus is probed, but before its children are examined.
*/
-void __init
+void __devinit
pcibios_fixup_bus (struct pci_bus *b)
{
struct list_head *ln;
@@ -306,7 +445,7 @@
pcibios_fixup_device_resources(pci_dev_b(ln), b);
}
-void __init
+void __devinit
pcibios_update_resource (struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
@@ -322,7 +461,7 @@
/* ??? FIXME -- record old value for shutdown. */
}
-void __init
+void __devinit
pcibios_update_irq (struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -330,7 +469,7 @@
/* ??? FIXME -- record old value for shutdown. */
}
-void __init
+void __devinit
pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{
ranges->io_start -= bus->resource[0]->start;
@@ -339,8 +478,8 @@
ranges->mem_end -= bus->resource[1]->start;
}
-int
-pcibios_enable_device (struct pci_dev *dev)
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
int idx;
@@ -349,11 +488,13 @@
if (!dev)
return -EINVAL;
- platform_pci_enable_device(dev);
-
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx=0; idx<6; idx++) {
+ /* Only set up the desired resources. */
+ if (!(mask & (1 << idx)))
+ continue;
+
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR
@@ -372,6 +513,19 @@
printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
+ return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+ int ret;
+
+ ret = pcibios_enable_resources(dev, mask);
+ if (ret < 0)
+ return ret;
+
+ platform_pci_enable_device(dev);
printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)