fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / sh / drivers / pci / pci.c
index c166990..d439336 100644 (file)
@@ -1,21 +1,45 @@
-/* arch/sh/kernel/pci.c
- * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $
+/*
+ * arch/sh/drivers/pci/pci.c
  *
  * Copyright (c) 2002 M. R. Brown  <mrbrown@linux-sh.org>
- * 
- * 
+ * Copyright (c) 2004 - 2006 Paul Mundt  <lethal@linux-sh.org>
+ *
  * These functions are collected here to reduce duplication of common
  * code amongst the many platform-specific PCI support code files.
- * 
+ *
  * These routines require the following board-specific routines:
  * void pcibios_fixup_irqs();
  *
  * See include/asm-sh/pci.h for more information.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <asm/io.h>
+
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+       return (((pin - 1) + slot) % 4) + 1;
+}
+
+static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+       u8 pin = *pinp;
+
+       while (dev->bus->parent) {
+               pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+               /* Move up the chain of bridges. */
+               dev = dev->bus->self;
+       }
+       *pinp = pin;
+
+       /* The slot is the slot of the last bridge. */
+       return PCI_SLOT(dev->devfn);
+}
 
 static int __init pcibios_init(void)
 {
@@ -26,26 +50,32 @@ static int __init pcibios_init(void)
 #ifdef CONFIG_PCI_AUTO
        /* assign resources */
        busno = 0;
-       for (p = board_pci_channels; p->pci_ops != NULL; p++) {
+       for (p = board_pci_channels; p->pci_ops != NULL; p++)
                busno = pciauto_assign_resources(busno, p) + 1;
-       }
 #endif
 
        /* scan the buses */
        busno = 0;
-       for (p= board_pci_channels; p->pci_ops != NULL; p++) {
+       for (p = board_pci_channels; p->pci_ops != NULL; p++) {
                bus = pci_scan_bus(busno, p->pci_ops, p);
-               busno = bus->subordinate+1;
+               busno = bus->subordinate + 1;
        }
 
-       /* board-specific fixups */
-       pcibios_fixup_irqs();
+       pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq);
 
        return 0;
 }
-
 subsys_initcall(pcibios_init);
 
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+       pci_read_bridge_bases(bus);
+}
+
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
                        struct resource *res, int resource)
@@ -61,13 +91,17 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
                new |= PCI_ROM_ADDRESS_ENABLE;
                reg = dev->rom_base_reg;
        } else {
-               /* Somebody might have asked allocation of a non-standard resource */
+               /*
+                * Somebody might have asked allocation of a non-standard
+                * resource
+                */
                return;
        }
-       
+
        pci_write_config_dword(dev, reg, new);
        pci_read_config_dword(dev, reg, &check);
-       if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+       if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ?
+               PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
                printk(KERN_ERR "PCI: Error while updating region "
                       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
                       new, check);
@@ -75,7 +109,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
                            __attribute__ ((weak));
 
 /*
@@ -85,10 +119,10 @@ void pcibios_align_resource(void *data, struct resource *res,
  * modulo 0x400.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
@@ -145,7 +179,8 @@ void pcibios_set_master(struct pci_dev *dev)
                lat = pcibios_max_latency;
        else
                return;
-       printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+       printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n",
+              pci_name(dev), lat);
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
 
@@ -153,3 +188,39 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
 {
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (unlikely(!len || !start))
+               return NULL;
+       if (maxlen && len > maxlen)
+               len = maxlen;
+
+       /*
+        * Presently the IORESOURCE_MEM case is a bit special, most
+        * SH7751 style PCI controllers have PCI memory at a fixed
+        * location in the address space where no remapping is desired
+        * (typically at 0xfd000000, but is_pci_memaddr() will know
+        * best). With the IORESOURCE_MEM case more care has to be taken
+        * to inhibit page table mapping for legacy cores, but this is
+        * punted off to __ioremap().
+        *                                      -- PFM.
+        */
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM)
+               return ioremap(start, len);
+
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);