]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/platforms/iseries/pci.c
Merge branch 'isdn-cleanups' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / iseries / pci.c
index 68f248b4c6960ca771b610c6c2d9a5e633fe69bf..02a634faedbeb23007488513c4a51d98150edd9f 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
+
+#undef DEBUG
+
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/of.h>
 
 #include <asm/types.h>
 #include <asm/io.h>
@@ -58,6 +63,7 @@ static int limit_pci_retries = 1;     /* Set Retry Error on. */
 #define IOMM_TABLE_MAX_ENTRIES 1024
 #define IOMM_TABLE_ENTRY_SIZE  0x0000000000400000UL
 #define BASE_IO_MEMORY         0xE000000000000000UL
+#define END_IO_MEMORY          0xEFFFFFFFFFFFFFFFUL
 
 static unsigned long max_io_memory = BASE_IO_MEMORY;
 static long current_iomm_table_entry;
@@ -66,9 +72,8 @@ static long current_iomm_table_entry;
  * Lookup Tables.
  */
 static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
-static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
+static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];
 
-static const char pci_io_text[] = "iSeries PCI I/O";
 static DEFINE_SPINLOCK(iomm_table_lock);
 
 /*
@@ -77,8 +82,9 @@ static DEFINE_SPINLOCK(iomm_table_lock);
 static inline u64 iseries_ds_addr(struct device_node *node)
 {
        struct pci_dn *pdn = PCI_DN(node);
+       const u32 *sbp = of_get_property(node, "linux,subbus", NULL);
 
-       return ((u64)pdn->busno << 48) + ((u64)pdn->bussubno << 40)
+       return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)
                        + ((u64)0x10 << 32);
 }
 
@@ -279,8 +285,8 @@ out_free:
  * PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet
  * controller
  */
-static void __init iseries_device_information(struct pci_dev *pdev, int count,
-               u16 bus, HvSubBusNumber subbus)
+static void __init iseries_device_information(struct pci_dev *pdev,
+                                             u16 bus, HvSubBusNumber subbus)
 {
        u8 frame = 0;
        char card[4];
@@ -290,10 +296,9 @@ static void __init iseries_device_information(struct pci_dev *pdev, int count,
                        ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
 
        if (iseries_get_location_code(bus, agent, &frame, card)) {
-               printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
-                       "Card %4s  0x%04X\n", count, bus,
-                       PCI_SLOT(pdev->devfn), pdev->vendor, frame,
-                       card, (int)(pdev->class >> 8));
+               printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
+                      "Card %4s  0x%04X\n", pci_name(pdev), pdev->vendor,
+                      frame, card, (int)(pdev->class >> 8));
        }
 }
 
@@ -323,7 +328,6 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
         * Set Resource values.
         */
        spin_lock(&iomm_table_lock);
-       bar_res->name = pci_io_text;
        bar_res->start = BASE_IO_MEMORY +
                IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
        bar_res->end = bar_res->start + bar_size - 1;
@@ -332,7 +336,8 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
         */
        while (bar_size > 0 ) {
                iomm_table[current_iomm_table_entry] = dev->sysdata;
-               iobar_table[current_iomm_table_entry] = bar_num;
+               ds_addr_table[current_iomm_table_entry] =
+                       iseries_ds_addr(dev->sysdata) | (bar_num << 24);
                bar_size -= IOMM_TABLE_ENTRY_SIZE;
                ++current_iomm_table_entry;
        }
@@ -393,61 +398,62 @@ static struct device_node *find_device_node(int bus, int devfn)
 }
 
 /*
- * iSeries_pci_final_fixup(void)
+ * iSeries_pcibios_fixup_resources
+ *
+ * Fixes up all resources for devices
  */
-void __init iSeries_pci_final_fixup(void)
+void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = NULL;
+       const u32 *agent;
+       const u32 *sub_bus;
+       unsigned char bus = pdev->bus->number;
        struct device_node *node;
-       int num_dev = 0;
-
-       /* Fix up at the device node and pci_dev relationship */
-       mf_display_src(0xC9000100);
-
-       printk("pcibios_final_fixup\n");
-       for_each_pci_dev(pdev) {
-               const u32 *agent;
-               const u32 *sub_bus;
-               unsigned char bus = pdev->bus->number;
-
-               node = find_device_node(bus, pdev->devfn);
-               printk("pci dev %p (%x.%x), node %p\n", pdev, bus,
-                       pdev->devfn, node);
-               if (!node) {
-                       printk("PCI: Device Tree not found for 0x%016lX\n",
-                                       (unsigned long)pdev);
-                       continue;
-               }
-
-               agent = of_get_property(node, "linux,agent-id", NULL);
-               sub_bus = of_get_property(node, "linux,subbus", NULL);
-               if (agent && sub_bus) {
-                       u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
-                       int err;
-
-                       err = HvCallXm_connectBusUnit(bus, *sub_bus,
-                                       *agent, irq);
-                       if (err)
-                               pci_log_error("Connect Bus Unit",
-                                       bus, *sub_bus, *agent, err);
-                       else {
-                               err = HvCallPci_configStore8(bus, *sub_bus,
+       int i;
+
+       node = find_device_node(bus, pdev->devfn);
+       pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
+                pci_name(pdev), pdev, node);
+       if (!node) {
+               printk("PCI: %s disabled, device tree entry not found !\n",
+                      pci_name(pdev));
+               for (i = 0; i <= PCI_ROM_RESOURCE; i++)
+                       pdev->resource[i].flags = 0;
+               return;
+       }
+       sub_bus = of_get_property(node, "linux,subbus", NULL);
+       agent = of_get_property(node, "linux,agent-id", NULL);
+       if (agent && sub_bus) {
+               u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
+               int err;
+
+               err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
+               if (err)
+                       pci_log_error("Connect Bus Unit",
+                                     bus, *sub_bus, *agent, err);
+               else {
+                       err = HvCallPci_configStore8(bus, *sub_bus,
                                        *agent, PCI_INTERRUPT_LINE, irq);
-                               if (err)
-                                       pci_log_error("PciCfgStore Irq Failed!",
+                       if (err)
+                               pci_log_error("PciCfgStore Irq Failed!",
                                                bus, *sub_bus, *agent, err);
-                               else
-                                       pdev->irq = irq;
-                       }
+                       else
+                               pdev->irq = irq;
                }
-
-               num_dev++;
-               pdev->sysdata = node;
-               PCI_DN(node)->pcidev = pdev;
-               allocate_device_bars(pdev);
-               iseries_device_information(pdev, num_dev, bus, *sub_bus);
-               iommu_devnode_init_iSeries(pdev, node);
        }
+
+       pdev->sysdata = node;
+       allocate_device_bars(pdev);
+       iseries_device_information(pdev, bus, *sub_bus);
+       iommu_devnode_init_iSeries(pdev, node);
+}
+
+/*
+ * iSeries_pci_final_fixup(void)
+ */
+void __init iSeries_pci_final_fixup(void)
+{
+       /* Fix up at the device node and pci_dev relationship */
+       mf_display_src(0xC9000100);
        iSeries_activate_IRQs();
        mf_display_src(0xC9000200);
 }
@@ -581,7 +587,7 @@ static inline struct device_node *xlate_iomm_address(
                static unsigned long last_jiffies;
                static int num_printed;
 
-               if ((jiffies - last_jiffies) > 60 * HZ) {
+               if (time_after(jiffies, last_jiffies + 60 * HZ)) {
                        last_jiffies = jiffies;
                        num_printed = 0;
                }
@@ -596,8 +602,7 @@ static inline struct device_node *xlate_iomm_address(
        dn = iomm_table[ind];
 
        if (dn != NULL) {
-               int barnum = iobar_table[ind];
-               *dsaptr = iseries_ds_addr(dn) | (barnum << 24);
+               *dsaptr = ds_addr_table[ind];
                *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
        } else
                panic("PCI: Invalid PCI IO address detected!\n");
@@ -894,10 +899,18 @@ void __init iSeries_pcibios_init(void)
                /* All legacy iSeries PHBs are in domain zero */
                phb->global_number = 0;
 
-               phb->pci_mem_offset = bus;
                phb->first_busno = bus;
                phb->last_busno = bus;
                phb->ops = &iSeries_pci_ops;
+               phb->io_base_virt = (void __iomem *)_IO_BASE;
+               phb->io_resource.flags = IORESOURCE_IO;
+               phb->io_resource.start = BASE_IO_MEMORY;
+               phb->io_resource.end = END_IO_MEMORY;
+               phb->io_resource.name = "iSeries PCI IO";
+               phb->mem_resources[0].flags = IORESOURCE_MEM;
+               phb->mem_resources[0].start = BASE_IO_MEMORY;
+               phb->mem_resources[0].end = END_IO_MEMORY;
+               phb->mem_resources[0].name = "Series PCI MEM";
        }
 
        of_node_put(root);