sh: pci: New-style controller registration.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 20 Apr 2009 09:29:22 +0000 (18:29 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 20 Apr 2009 09:29:22 +0000 (18:29 +0900)
This moves off of the board_pci_channels[] approach for bus registration
and over to a cleaner register_pci_controller(), all derived from the
MIPS code.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/drivers/pci/pci-new.c
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/include/asm/pci.h

index c92e650..78b7292 100644 (file)
 #include <linux/init.h>
 #include <linux/dma-debug.h>
 #include <linux/io.h>
+#include <linux/mutex.h>
 
-static int __init pcibios_init(void)
+/*
+ * The PCI controller list.
+ */
+static struct pci_channel *hose_head, **hose_tail = &hose_head;
+
+static int pci_initialized;
+
+static void __devinit pcibios_scanbus(struct pci_channel *hose)
 {
-       struct pci_channel *p;
+       static int next_busno;
        struct pci_bus *bus;
-       int busno;
-
-       /* init channels */
-       busno = 0;
-       for (p = board_pci_channels; p->init; p++) {
-               if (p->init(p) == 0)
-                       p->enabled = 1;
-               else
-                       pr_err("Unable to init pci channel %d\n", busno);
-               busno++;
+
+       /* Catch botched conversion attempts */
+       BUG_ON(hose->init);
+
+       bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+       if (bus) {
+               next_busno = bus->subordinate + 1;
+               /* Don't allow 8-bit bus number overflow inside the hose -
+                  reserve some space for bridges. */
+               if (next_busno > 224)
+                       next_busno = 0;
+
+               pci_bus_size_bridges(bus);
+               pci_bus_assign_resources(bus);
+               pci_enable_bridges(bus);
        }
+}
 
-       /* scan the buses */
-       busno = 0;
-       for (p = board_pci_channels; p->init; p++) {
-               if (p->enabled) {
-                       bus = pci_scan_bus(busno, p->pci_ops, p);
-                       busno = bus->subordinate + 1;
+static DEFINE_MUTEX(pci_scan_mutex);
 
-                       pci_bus_size_bridges(bus);
-                       pci_bus_assign_resources(bus);
-                       pci_enable_bridges(bus);
-               }
+void __devinit register_pci_controller(struct pci_channel *hose)
+{
+       if (request_resource(&iomem_resource, hose->mem_resource) < 0)
+               goto out;
+       if (request_resource(&ioport_resource, hose->io_resource) < 0) {
+               release_resource(hose->mem_resource);
+               goto out;
+       }
+
+       *hose_tail = hose;
+       hose_tail = &hose->next;
+
+       /*
+        * Do not panic here but later - this might hapen before console init.
+        */
+       if (!hose->io_map_base) {
+               printk(KERN_WARNING
+                      "registering PCI controller with io_map_base unset\n");
+       }
+
+       /*
+        * Scan the bus if it is register after the PCI subsystem
+        * initialization.
+        */
+       if (pci_initialized) {
+               mutex_lock(&pci_scan_mutex);
+               pcibios_scanbus(hose);
+               mutex_unlock(&pci_scan_mutex);
        }
 
+       return;
+
+out:
+       printk(KERN_WARNING
+              "Skipping PCI bus scan due to resource conflict\n");
+}
+
+static int __init pcibios_init(void)
+{
+       struct pci_channel *hose;
+
+       /* Scan all of the recorded PCI controllers.  */
+       for (hose = hose_head; hose; hose = hose->next)
+               pcibios_scanbus(hose);
+
        pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
 
        dma_debug_add_bus(&pci_bus_type);
 
+       pci_initialized = 1;
+
        return 0;
 }
 subsys_initcall(pcibios_init);
@@ -74,7 +124,6 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev,
        }
 }
 
-
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
@@ -186,5 +235,3 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
 {
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
-
-EXPORT_SYMBOL(board_pci_channels);
index f02d9df..4dd6e3b 100644 (file)
 #include <linux/delay.h>
 #include "pci-sh4.h"
 
-static int __init sh7780_pci_init(struct pci_channel *chan)
+extern u8 pci_cache_line_size;
+
+static struct resource sh7785_io_resource = {
+       .name   = "SH7785_IO",
+       .start  = SH7780_PCI_IO_BASE,
+       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
+       .flags  = IORESOURCE_IO
+};
+
+static struct resource sh7785_mem_resource = {
+       .name   = "SH7785_mem",
+       .start  = SH7780_PCI_MEMORY_BASE,
+       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
+};
+
+static struct pci_channel sh7780_pci_controller = {
+       .pci_ops        = &sh4_pci_ops,
+       .mem_resource   = &sh7785_mem_resource,
+       .io_resource    = &sh7785_io_resource,
+};
+
+static struct sh4_pci_address_map sh7780_pci_map = {
+       .window0        = {
+#if defined(CONFIG_32BIT)
+               .base   = SH7780_32BIT_DDR_BASE_ADDR,
+               .size   = 0x40000000,
+#else
+               .base   = SH7780_CS0_BASE_ADDR,
+               .size   = 0x20000000,
+#endif
+       },
+};
+
+static int __init sh7780_pci_init(void)
 {
+       struct pci_channel *chan = &sh7780_pci_controller;
        unsigned int id;
        const char *type = NULL;
        int ret;
+       u32 word;
 
        printk(KERN_NOTICE "PCI: Starting intialization.\n");
 
@@ -55,52 +91,6 @@ static int __init sh7780_pci_init(struct pci_channel *chan)
                return ret;
 
        /*
-        * Platform specific initialization (BSC registers, and memory space
-        * mapping) will be called via the platform defined function
-        * pcibios_init_platform().
-        */
-       return pcibios_init_platform();
-}
-
-extern u8 pci_cache_line_size;
-
-static struct resource sh7785_io_resource = {
-       .name   = "SH7785_IO",
-       .start  = SH7780_PCI_IO_BASE,
-       .end    = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7785_mem_resource = {
-       .name   = "SH7785_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
-       { sh7780_pci_init, &sh4_pci_ops, &sh7785_io_resource, &sh7785_mem_resource, 0, 0xff },
-       { NULL, NULL, NULL, 0, 0 },
-};
-
-static struct sh4_pci_address_map sh7780_pci_map = {
-       .window0        = {
-#if defined(CONFIG_32BIT)
-               .base   = SH7780_32BIT_DDR_BASE_ADDR,
-               .size   = 0x40000000,
-#else
-               .base   = SH7780_CS0_BASE_ADDR,
-               .size   = 0x20000000,
-#endif
-       },
-};
-
-int __init pcibios_init_platform(void)
-{
-       struct pci_channel *chan = &board_pci_channels[0];
-       u32 word;
-
-       /*
         * Set the class and sub-class codes.
         */
        __raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8,
@@ -153,5 +143,8 @@ int __init pcibios_init_platform(void)
 
        __set_io_port_base(SH7780_PCI_IO_BASE);
 
+       register_pci_controller(chan);
+
        return 0;
 }
+arch_initcall(sh7780_pci_init);
index 82a9369..e057ebd 100644 (file)
  * external) PCI controllers.
  */
 struct pci_channel {
-       int (*init)(struct pci_channel *chan);
-       struct pci_ops *pci_ops;
-       struct resource *io_resource;
-       struct resource *mem_resource;
-       int first_devfn;
-       int last_devfn;
-       int enabled;
-       unsigned long reg_base;
-       unsigned long io_base;
-
-       unsigned long io_map_base;
+       struct pci_channel      *next;
+
+       int                     (*init)(struct pci_channel *chan);
+
+       struct pci_ops          *pci_ops;
+       struct resource         *io_resource;
+       struct resource         *mem_resource;
+
+       int                     first_devfn;
+       int                     last_devfn;
+       int                     enabled;
+
+       unsigned long           reg_base;
+       unsigned long           io_base;
+
+       unsigned long           io_map_base;
 };
 
 /*
@@ -35,6 +40,8 @@ struct pci_channel {
  */
 extern struct pci_channel board_pci_channels[];
 
+extern void register_pci_controller(struct pci_channel *hose);
+
 extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
 
 struct pci_dev;