Altix: Initial ACPI support - ROM shadowing.
[sfrench/cifs-2.6.git] / arch / ia64 / sn / kernel / io_init.c
index dfb3f2902379d3bbd0e5342bfea6b3f0905ae47f..9ad843e0383b53a1745591defbf2497461a73471 100644 (file)
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2006 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/bootmem.h>
-#include <linux/nodemask.h>
 #include <asm/sn/types.h>
 #include <asm/sn/addrs.h>
-#include <asm/sn/sn_feature_sets.h>
-#include <asm/sn/geo.h>
 #include <asm/sn/io.h>
-#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/module.h>
+#include <asm/sn/intr.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include <asm/sn/simulator.h>
 #include <asm/sn/sn_sal.h>
-#include <asm/sn/tioca_provider.h>
-#include <asm/sn/tioce_provider.h>
 #include "xtalk/hubdev.h"
-#include "xtalk/xwidgetdev.h"
-
-
-extern void sn_init_cpei_timer(void);
-extern void register_sn_procfs(void);
-
-static struct list_head sn_sysdata_list;
-
-/* sysdata list struct */
-struct sysdata_el {
-       struct list_head entry;
-       void *sysdata;
-};
-
-struct slab_info {
-       struct hubdev_info hubdev;
-};
-
-struct brick {
-       moduleid_t id;          /* Module ID of this module        */
-       struct slab_info slab_info[MAX_SLABS + 1];
-};
-
-int sn_ioif_inited;            /* SN I/O infrastructure initialized? */
-
-struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];      /* indexed by asic type */
-
-static int max_segment_number;          /* Default highest segment number */
-static int max_pcibus_number = 255;    /* Default highest pci bus number */
 
 /*
- * Hooks and struct for unsupported pci providers
+ * The code in this file will only be executed when running with
+ * a PROM that does _not_ have base ACPI IO support.
+ * (i.e., SN_ACPI_BASE_SUPPORT() == 0)
  */
 
-static dma_addr_t
-sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
-{
-       return 0;
-}
-
-static void
-sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction)
-{
-       return;
-}
-
-static void *
-sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller)
-{
-       return NULL;
-}
-
-static struct sn_pcibus_provider sn_pci_default_provider = {
-       .dma_map = sn_default_pci_map,
-       .dma_map_consistent = sn_default_pci_map,
-       .dma_unmap = sn_default_pci_unmap,
-       .bus_fixup = sn_default_pci_bus_fixup,
-};
-
-/*
- * Retrieve the DMA Flush List given nasid, widget, and device.
- * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
- */
-static inline u64
-sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
-                            u64 address)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
+static int max_segment_number;          /* Default highest segment number */
+static int max_pcibus_number = 255;    /* Default highest pci bus number */
 
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
-                       (u64) nasid, (u64) widget_num,
-                       (u64) device_num, (u64) address, 0, 0, 0);
-       return ret_stuff.status;
-}
 
 /*
  * Retrieve the hub device info structure for the given nasid.
@@ -129,93 +56,20 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
        return ret_stuff.v0;
 }
 
-/*
- * Retrieve the pci device information given the bus and device|function number.
- */
-static inline u64
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
-                   u64 sn_irq_info)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
-                       (u64) segment, (u64) bus_number, (u64) devfn,
-                       (u64) pci_dev,
-                       sn_irq_info, 0, 0);
-       return ret_stuff.v0;
-}
-
-/*
- * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
- *                       device.
- */
-inline struct pcidev_info *
-sn_pcidev_info_get(struct pci_dev *dev)
-{
-       struct pcidev_info *pcidev;
-
-       list_for_each_entry(pcidev,
-                           &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) {
-               if (pcidev->pdi_linux_pcidev == dev) {
-                       return pcidev;
-               }
-       }
-       return NULL;
-}
-
-/* Older PROM flush WAR
- *
- * 01/16/06 -- This war will be in place until a new official PROM is released.
- * Additionally note that the struct sn_flush_device_war also has to be
- * removed from arch/ia64/sn/include/xtalk/hubdev.h
- */
-static u8 war_implemented = 0;
-
-static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
-                              struct sn_flush_device_common *common)
-{
-       struct sn_flush_device_war *war_list;
-       struct sn_flush_device_war *dev_entry;
-       struct ia64_sal_retval isrv = {0,0,0,0};
-
-       if (!war_implemented) {
-               printk(KERN_WARNING "PROM version < 4.50 -- implementing old "
-                      "PROM flush WAR\n");
-               war_implemented = 1;
-       }
-
-       war_list = kzalloc(DEV_PER_WIDGET * sizeof(*war_list), GFP_KERNEL);
-       if (!war_list)
-               BUG();
-
-       SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
-                       nasid, widget, __pa(war_list), 0, 0, 0 ,0);
-       if (isrv.status)
-               panic("sn_device_fixup_war failed: %s\n",
-                     ia64_sal_strerror(isrv.status));
-
-       dev_entry = war_list + device;
-       memcpy(common,dev_entry, sizeof(*common));
-       kfree(war_list);
-
-       return isrv.status;
-}
 
 /*
- * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for
- *     each node in the system.
+ * sn_fixup_ionodes() - This routine initializes the HUB data structure for
+ *                     each node in the system. This function is only
+ *                     executed when running with a non-ACPI capable PROM.
  */
 static void __init sn_fixup_ionodes(void)
 {
-       struct sn_flush_device_kernel *sn_flush_device_kernel;
-       struct sn_flush_device_kernel *dev_entry;
+
        struct hubdev_info *hubdev;
        u64 status;
        u64 nasid;
-       int i, widget, device, size;
+       int i;
+       extern void sn_common_hubdev_init(struct hubdev_info *);
 
        /*
         * Get SGI Specific HUB chipset information.
@@ -238,70 +92,47 @@ static void __init sn_fixup_ionodes(void)
                        max_segment_number = hubdev->max_segment_number;
                        max_pcibus_number = hubdev->max_pcibus_number;
                }
+               sn_common_hubdev_init(hubdev);
+       }
+}
 
-               /* Attach the error interrupt handlers */
-               if (nasid & 1)
-                       ice_error_init(hubdev);
-               else
-                       hub_error_init(hubdev);
-
-               for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
-                       hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;
-
-               if (!hubdev->hdi_flush_nasid_list.widget_p)
-                       continue;
-
-               size = (HUB_WIDGET_ID_MAX + 1) *
-                       sizeof(struct sn_flush_device_kernel *);
-               hubdev->hdi_flush_nasid_list.widget_p =
-                       kzalloc(size, GFP_KERNEL);
-               if (!hubdev->hdi_flush_nasid_list.widget_p)
+/*
+ * sn_pci_legacy_window_fixup - Create PCI controller windows for
+ *                             legacy IO and MEM space. This needs to
+ *                             be done here, as the PROM does not have
+ *                             ACPI support defining the root buses
+ *                             and their resources (_CRS),
+ */
+static void
+sn_legacy_pci_window_fixup(struct pci_controller *controller,
+                          u64 legacy_io, u64 legacy_mem)
+{
+               controller->window = kcalloc(2, sizeof(struct pci_window),
+                                            GFP_KERNEL);
+               if (controller->window == NULL)
                        BUG();
-
-               for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
-                       size = DEV_PER_WIDGET *
-                               sizeof(struct sn_flush_device_kernel);
-                       sn_flush_device_kernel = kzalloc(size, GFP_KERNEL);
-                       if (!sn_flush_device_kernel)
-                               BUG();
-
-                       dev_entry = sn_flush_device_kernel;
-                       for (device = 0; device < DEV_PER_WIDGET;
-                            device++,dev_entry++) {
-                               size = sizeof(struct sn_flush_device_common);
-                               dev_entry->common = kzalloc(size, GFP_KERNEL);
-                               if (!dev_entry->common)
-                                       BUG();
-
-                               if (sn_prom_feature_available(
-                                                      PRF_DEVICE_FLUSH_LIST))
-                                       status = sal_get_device_dmaflush_list(
-                                                    nasid, widget, device,
-                                                    (u64)(dev_entry->common));
-                               else
-                                       status = sn_device_fixup_war(nasid,
-                                                    widget, device,
-                                                    dev_entry->common);
-                               if (status != SALRET_OK)
-                                       panic("SAL call failed: %s\n",
-                                             ia64_sal_strerror(status));
-
-                               spin_lock_init(&dev_entry->sfdl_flush_lock);
-                       }
-
-                       if (sn_flush_device_kernel)
-                               hubdev->hdi_flush_nasid_list.widget_p[widget] =
-                                                      sn_flush_device_kernel;
-               }
-       }
+               controller->window[0].offset = legacy_io;
+               controller->window[0].resource.name = "legacy_io";
+               controller->window[0].resource.flags = IORESOURCE_IO;
+               controller->window[0].resource.start = legacy_io;
+               controller->window[0].resource.end =
+                               controller->window[0].resource.start + 0xffff;
+               controller->window[0].resource.parent = &ioport_resource;
+               controller->window[1].offset = legacy_mem;
+               controller->window[1].resource.name = "legacy_mem";
+               controller->window[1].resource.flags = IORESOURCE_MEM;
+               controller->window[1].resource.start = legacy_mem;
+               controller->window[1].resource.end =
+                      controller->window[1].resource.start + (1024 * 1024) - 1;
+               controller->window[1].resource.parent = &iomem_resource;
+               controller->windows = 2;
 }
 
 /*
  * sn_pci_window_fixup() - Create a pci_window for each device resource.
- *                        Until ACPI support is added, we need this code
- *                        to setup pci_windows for use by
- *                        pcibios_bus_to_resource(),
- *                        pcibios_resource_to_bus(), etc.
+ *                        It will setup pci_windows for use by
+ *                        pcibios_bus_to_resource(), pcibios_resource_to_bus(),
+ *                        etc.
  */
 static void
 sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
@@ -340,60 +171,22 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
        controller->window = new_window;
 }
 
-void sn_pci_unfixup_slot(struct pci_dev *dev)
-{
-       struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
-
-       sn_irq_unfixup(dev);
-       pci_dev_put(host_pci_dev);
-       pci_dev_put(dev);
-}
-
 /*
- * sn_pci_fixup_slot() - This routine sets up a slot's resources
- * consistent with the Linux PCI abstraction layer.  Resources acquired
- * from our PCI provider include PIO maps to BAR space and interrupt
- * objects.
+ * sn_more_slot_fixup() - We are not running with an ACPI capable PROM,
+ *                       and need to convert the pci_dev->resource
+ *                       'start' and 'end' addresses to mapped addresses,
+ *                       and setup the pci_controller->window array entries.
  */
-void sn_pci_fixup_slot(struct pci_dev *dev)
+void
+sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
 {
        unsigned int count = 0;
        int idx;
-       int segment = pci_domain_nr(dev->bus);
-       int status = 0;
-       struct pcibus_bussoft *bs;
-       struct pci_bus *host_pci_bus;
-       struct pci_dev *host_pci_dev;
-       struct pcidev_info *pcidev_info;
        s64 pci_addrs[PCI_ROM_RESOURCE + 1];
-       struct sn_irq_info *sn_irq_info;
-       unsigned long size;
-       unsigned int bus_no, devfn;
-
-       pci_dev_get(dev); /* for the sysdata pointer */
-       pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-       if (!pcidev_info)
-               BUG();          /* Cannot afford to run out of memory */
-
-       sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (!sn_irq_info)
-               BUG();          /* Cannot afford to run out of memory */
-
-       /* Call to retrieve pci device information needed by kernel. */
-       status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
-                                    dev->devfn,
-                                    (u64) __pa(pcidev_info),
-                                    (u64) __pa(sn_irq_info));
-       if (status)
-               BUG(); /* Cannot get platform pci device information */
-
-       /* Add pcidev_info to list in sn_pci_controller struct */
-       list_add_tail(&pcidev_info->pdi_list,
-                     &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info));
+       unsigned long addr, end, size, start;
 
        /* Copy over PIO Mapped Addresses */
        for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
-               unsigned long start, end, addr;
 
                if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
                        pci_addrs[idx] = -1;
@@ -417,67 +210,28 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
                        dev->resource[idx].parent = &ioport_resource;
                else
                        dev->resource[idx].parent = &iomem_resource;
+               /* If ROM, mark as shadowed in PROM */
+               if (idx == PCI_ROM_RESOURCE)
+                       dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY;
        }
        /* Create a pci_window in the pci_controller struct for
         * each device resource.
         */
        if (count > 0)
                sn_pci_window_fixup(dev, count, pci_addrs);
-
-       /*
-        * Using the PROMs values for the PCI host bus, get the Linux
-        * PCI host_pci_dev struct and set up host bus linkages
-        */
-
-       bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
-       devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
-       host_pci_bus = pci_find_bus(segment, bus_no);
-       host_pci_dev = pci_get_slot(host_pci_bus, devfn);
-
-       pcidev_info->host_pci_dev = host_pci_dev;
-       pcidev_info->pdi_linux_pcidev = dev;
-       pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
-       bs = SN_PCIBUS_BUSSOFT(dev->bus);
-       pcidev_info->pdi_pcibus_info = bs;
-
-       if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
-               SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
-       } else {
-               SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider;
-       }
-
-       /* Only set up IRQ stuff if this device has a host bus context */
-       if (bs && sn_irq_info->irq_irq) {
-               pcidev_info->pdi_sn_irq_info = sn_irq_info;
-               dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
-               sn_irq_fixup(dev, sn_irq_info);
-       } else {
-               pcidev_info->pdi_sn_irq_info = NULL;
-               kfree(sn_irq_info);
-       }
-
-       /*
-        * MSI currently not supported on altix.  Remove this when
-        * the MSI abstraction patches are integrated into the kernel
-        * (sometime after 2.6.16 releases)
-        */
-       dev->no_msi = 1;
 }
 
 /*
  * sn_pci_controller_fixup() - This routine sets up a bus's resources
- * consistent with the Linux PCI abstraction layer.
+ *                            consistent with the Linux PCI abstraction layer.
  */
-void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
+static void
+sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
 {
-       int status;
-       int nasid, cnode;
+       s64 status = 0;
        struct pci_controller *controller;
-       struct sn_pci_controller *sn_controller;
        struct pcibus_bussoft *prom_bussoft_ptr;
-       struct hubdev_info *hubdev_info;
-       void *provider_soft;
-       struct sn_pcibus_provider *provider;
+
 
        status = sal_get_pcibus_info((u64) segment, (u64) busnum,
                                     (u64) ia64_tpa(&prom_bussoft_ptr));
@@ -485,234 +239,77 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
                return;         /*bus # does not exist */
        prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
-       /* Allocate a sn_pci_controller, which has a pci_controller struct
-        * as the first member.
-        */
-       sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL);
-       if (!sn_controller)
+       controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+       if (!controller)
                BUG();
-       INIT_LIST_HEAD(&sn_controller->pcidev_info);
-       controller = &sn_controller->pci_controller;
        controller->segment = segment;
 
-       if (bus == NULL) {
-               bus = pci_scan_bus(busnum, &pci_root_ops, controller);
-               if (bus == NULL)
-                       goto error_return; /* error, or bus already scanned */
-               bus->sysdata = NULL;
-       }
-
-       if (bus->sysdata)
-               goto error_return; /* sysdata already alloc'd */
-
        /*
-        * Per-provider fixup.  Copies the contents from prom to local
-        * area and links SN_PCIBUS_BUSSOFT().
+        * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup().
+        * (platform_data will be overwritten later in sn_common_bus_fixup())
         */
+       controller->platform_data = prom_bussoft_ptr;
 
-       if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
-               goto error_return; /* unsupported asic type */
-
-       if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
-               goto error_return; /* no further fixup necessary */
-
-       provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
-       if (provider == NULL)
-               goto error_return; /* no provider registerd for this asic */
+       bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+       if (bus == NULL)
+               goto error_return; /* error, or bus already scanned */
 
        bus->sysdata = controller;
-       if (provider->bus_fixup)
-               provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller);
-       else
-               provider_soft = NULL;
-
-       if (provider_soft == NULL) {
-               /* fixup failed or not applicable */
-               bus->sysdata = NULL;
-               goto error_return;
-       }
-
-       /*
-        * Setup pci_windows for legacy IO and MEM space.
-        * (Temporary until ACPI support is in place.)
-        */
-       controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL);
-       if (controller->window == NULL)
-               BUG();
-       controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io;
-       controller->window[0].resource.name = "legacy_io";
-       controller->window[0].resource.flags = IORESOURCE_IO;
-       controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io;
-       controller->window[0].resource.end =
-           controller->window[0].resource.start + 0xffff;
-       controller->window[0].resource.parent = &ioport_resource;
-       controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem;
-       controller->window[1].resource.name = "legacy_mem";
-       controller->window[1].resource.flags = IORESOURCE_MEM;
-       controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem;
-       controller->window[1].resource.end =
-           controller->window[1].resource.start + (1024 * 1024) - 1;
-       controller->window[1].resource.parent = &iomem_resource;
-       controller->windows = 2;
-
-       /*
-        * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
-        * after this point.
-        */
-
-       PCI_CONTROLLER(bus)->platform_data = provider_soft;
-       nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
-       cnode = nasid_to_cnodeid(nasid);
-       hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
-       SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
-           &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
 
-       /*
-        * If the node information we obtained during the fixup phase is invalid
-        * then set controller->node to -1 (undetermined)
-        */
-       if (controller->node >= num_online_nodes()) {
-               struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
-
-               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
-                                   "L_IO=%lx L_MEM=%lx BASE=%lx\n",
-                       b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
-                       b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
-               printk(KERN_WARNING "on node %d but only %d nodes online."
-                       "Association set to undetermined.\n",
-                       controller->node, num_online_nodes());
-               controller->node = -1;
-       }
        return;
 
 error_return:
 
-       kfree(sn_controller);
+       kfree(controller);
        return;
 }
 
-void sn_bus_store_sysdata(struct pci_dev *dev)
+/*
+ * sn_bus_fixup
+ */
+void
+sn_bus_fixup(struct pci_bus *bus)
 {
-       struct sysdata_el *element;
-
-       element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
-       if (!element) {
-               dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
-               return;
-       }
-       element->sysdata = SN_PCIDEV_INFO(dev);
-       list_add(&element->entry, &sn_sysdata_list);
-}
+       struct pci_dev *pci_dev = NULL;
+       struct pcibus_bussoft *prom_bussoft_ptr;
+       extern void sn_common_bus_fixup(struct pci_bus *,
+                                       struct pcibus_bussoft *);
+
+
+       if (!bus->parent) {  /* If root bus */
+               prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
+               if (prom_bussoft_ptr == NULL) {
+                       printk(KERN_ERR
+                              "sn_bus_fixup: 0x%04x:0x%02x Unable to "
+                              "obtain prom_bussoft_ptr\n",
+                              pci_domain_nr(bus), bus->number);
+                       return;
+               }
+               sn_common_bus_fixup(bus, prom_bussoft_ptr);
+               sn_legacy_pci_window_fixup(PCI_CONTROLLER(bus),
+                                          prom_bussoft_ptr->bs_legacy_io,
+                                          prom_bussoft_ptr->bs_legacy_mem);
+        }
+        list_for_each_entry(pci_dev, &bus->devices, bus_list) {
+                sn_pci_fixup_slot(pci_dev);
+        }
 
-void sn_bus_free_sysdata(void)
-{
-       struct sysdata_el *element;
-       struct list_head *list, *safe;
-
-       list_for_each_safe(list, safe, &sn_sysdata_list) {
-               element = list_entry(list, struct sysdata_el, entry);
-               list_del(&element->entry);
-               list_del(&(((struct pcidev_info *)
-                            (element->sysdata))->pdi_list));
-               kfree(element->sysdata);
-               kfree(element);
-       }
-       return;
 }
 
 /*
- * Ugly hack to get PCI setup until we have a proper ACPI namespace.
+ * sn_io_init - PROM does not have ACPI support to define nodes or root buses,
+ *             so we need to do things the hard way, including initiating the
+ *             bus scanning ourselves.
  */
 
-#define PCI_BUSES_TO_SCAN 256
-
-static int __init sn_pci_init(void)
+void __init sn_io_init(void)
 {
        int i, j;
-       struct pci_dev *pci_dev = NULL;
 
-       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
-               return 0;
-
-       /*
-        * prime sn_pci_provider[].  Individial provider init routines will
-        * override their respective default entries.
-        */
-
-       for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++)
-               sn_pci_provider[i] = &sn_pci_default_provider;
-
-       pcibr_init_provider();
-       tioca_init_provider();
-       tioce_init_provider();
-
-       /*
-        * This is needed to avoid bounce limit checks in the blk layer
-        */
-       ia64_max_iommu_merge_mask = ~PAGE_MASK;
        sn_fixup_ionodes();
-       sn_irq_lh_init();
-       INIT_LIST_HEAD(&sn_sysdata_list);
-       sn_init_cpei_timer();
-
-#ifdef CONFIG_PROC_FS
-       register_sn_procfs();
-#endif
 
        /* busses are not known yet ... */
        for (i = 0; i <= max_segment_number; i++)
                for (j = 0; j <= max_pcibus_number; j++)
                        sn_pci_controller_fixup(i, j, NULL);
-
-       /*
-        * Generic Linux PCI Layer has created the pci_bus and pci_dev 
-        * structures - time for us to add our SN PLatform specific 
-        * information.
-        */
-
-       while ((pci_dev =
-               pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
-               sn_pci_fixup_slot(pci_dev);
-
-       sn_ioif_inited = 1;     /* sn I/O infrastructure now initialized */
-
-       return 0;
 }
-
-/*
- * hubdev_init_node() - Creates the HUB data structure and link them to it's 
- *     own NODE specific data area.
- */
-void hubdev_init_node(nodepda_t * npda, cnodeid_t node)
-{
-       struct hubdev_info *hubdev_info;
-       int size;
-       pg_data_t *pg;
-
-       size = sizeof(struct hubdev_info);
-
-       if (node >= num_online_nodes()) /* Headless/memless IO nodes */
-               pg = NODE_DATA(0);
-       else
-               pg = NODE_DATA(node);
-
-       hubdev_info = (struct hubdev_info *)alloc_bootmem_node(pg, size);
-
-       npda->pdinfo = (void *)hubdev_info;
-}
-
-geoid_t
-cnodeid_get_geoid(cnodeid_t cnode)
-{
-       struct hubdev_info *hubdev;
-
-       hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
-       return hubdev->hdi_geoid;
-}
-
-subsys_initcall(sn_pci_init);
-EXPORT_SYMBOL(sn_pci_fixup_slot);
-EXPORT_SYMBOL(sn_pci_unfixup_slot);
-EXPORT_SYMBOL(sn_pci_controller_fixup);
-EXPORT_SYMBOL(sn_bus_store_sysdata);
-EXPORT_SYMBOL(sn_bus_free_sysdata);