[PATCH] pSeries - read irqs dynamically
authorJohn Rose <johnrose@austin.ibm.com>
Thu, 23 Jun 2005 07:09:54 +0000 (17:09 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 23 Jun 2005 07:09:54 +0000 (17:09 +1000)
For I/O DLPAR to work properly, the kernel needs to allow for dynamic
assignment of the irq field of the pci_dev structure upon dynamic bus
addition.  This patch moves the assignment of that field from
pSeries_final_fixup() to pcibios_fixup_bus(), which enables dynamic
assignment for the children of a newly added bus.

Currently, pci_devs receive their irq numbers in one of two ways.  The
irq line is either read at boot for all pci_devs, or read by the rpaphp
module at slot enable time.  The latter is no longer sufficient for
DLPAR addition of slots that don't qualify as PCI-hotplug capable.
This solution handles the cases of boot and dynamic add.

Signed-off-by: John Rose <johnrose@austin.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/ppc64/kernel/pSeries_pci.c
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/pci.h
include/asm-ppc64/machdep.h

index dfa6d3d3e9f0e62ddf93d9c61a08bac9259a8870..1f5f141fb7a18633b099c4ad8bb1495cbef5b824 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "pci.h"
 
-static int __initdata s7a_workaround;
+static int __initdata s7a_workaround = -1;
 
 #if 0
 void pcibios_name_device(struct pci_dev *dev)
@@ -65,6 +65,7 @@ static void __init check_s7a(void)
        struct device_node *root;
        char *model;
 
+       s7a_workaround = 0;
        root = of_find_node_by_path("/");
        if (root) {
                model = get_property(root, "model", NULL);
@@ -74,6 +75,24 @@ static void __init check_s7a(void)
        }
 }
 
+void __devinit pSeries_irq_bus_setup(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       if (s7a_workaround < 0)
+               check_s7a();
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               pci_read_irq_line(dev);
+               if (s7a_workaround) {
+                       if (dev->irq > 16) {
+                               dev->irq -= 3;
+                               pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+                                       dev->irq);
+                       }
+               }
+       }
+}
+
 static void __init pSeries_request_regions(void)
 {
        if (!isa_io_base)
@@ -89,20 +108,6 @@ static void __init pSeries_request_regions(void)
 
 void __init pSeries_final_fixup(void)
 {
-       struct pci_dev *dev = NULL;
-
-       check_s7a();
-
-       for_each_pci_dev(dev) {
-               pci_read_irq_line(dev);
-               if (s7a_workaround) {
-                       if (dev->irq > 16) {
-                               dev->irq -= 3;
-                               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-                       }
-               }
-       }
-
        phbs_remap_io();
        pSeries_request_regions();
 
index 41e6de2c915872ebf32e4333e81512bbf6196092..f2b41243342c483a63088c5d5f8228744b09c2ef 100644 (file)
@@ -71,8 +71,6 @@
 #define DBG(fmt...)
 #endif
 
-extern void pSeries_final_fixup(void);
-
 extern void find_udbg_vterm(void);
 extern void system_reset_fwnmi(void);  /* from head.S */
 extern void machine_check_fwnmi(void); /* from head.S */
@@ -425,6 +423,7 @@ struct machdep_calls __initdata pSeries_md = {
        .get_cpuinfo            = pSeries_get_cpuinfo,
        .log_error              = pSeries_log_error,
        .pcibios_fixup          = pSeries_final_fixup,
+       .irq_bus_setup          = pSeries_irq_bus_setup,
        .restart                = rtas_restart,
        .power_off              = rtas_power_off,
        .halt                   = rtas_halt,
index 2bf0513f3eca0a0fa2c53f50640ef312def4cc71..580676f87d23a11a33a85f0b0f21417c52803d84 100644 (file)
@@ -902,6 +902,9 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
        list_for_each_entry(dev, &bus->devices, bus_list)
                ppc_md.iommu_dev_setup(dev);
 
+       if (ppc_md.irq_bus_setup)
+               ppc_md.irq_bus_setup(bus);
+
        if (!pci_probe_only)
                return;
 
index 0fd7d849aa77eb27ec246346085051c595b765ff..26be78b13af1923877c8ea75d764dc39881a0d43 100644 (file)
@@ -40,10 +40,14 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev);
 void pci_addr_cache_insert_device(struct pci_dev *dev);
 void pci_addr_cache_remove_device(struct pci_dev *dev);
 
-/* From pSeries_pci.h */
+/* From rtas_pci.h */
 void init_pci_config_tokens (void);
 unsigned long get_phb_buid (struct device_node *);
 
+/* From pSeries_pci.h */
+extern void pSeries_final_fixup(void);
+extern void pSeries_irq_bus_setup(struct pci_bus *bus);
+
 extern unsigned long pci_probe_only;
 extern unsigned long pci_assign_all_buses;
 extern int pci_read_irq_line(struct pci_dev *pci_dev);
index 5d3cd9d042e29bb0e88a540b4550d3e992d5551e..553b2ea23bedfb324b56dc76347917794f1872b2 100644 (file)
@@ -76,6 +76,7 @@ struct machdep_calls {
        void            (*tce_flush)(struct iommu_table *tbl);
        void            (*iommu_dev_setup)(struct pci_dev *dev);
        void            (*iommu_bus_setup)(struct pci_bus *bus);
+       void            (*irq_bus_setup)(struct pci_bus *bus);
 
        int             (*probe)(int platform);
        void            (*setup_arch)(void);