powerpc: Add VSX context save/restore, ptrace and signal support
[safe/jmp/linux-2.6] / arch / powerpc / kernel / pci_32.c
index 717c554..88db4ff 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/bootmem.h>
 #include <linux/irq.h>
 #include <linux/list.h>
+#include <linux/of.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -35,13 +36,9 @@ unsigned long isa_io_base     = 0;
 unsigned long pci_dram_offset = 0;
 int pcibios_assign_bus_offset = 1;
 
-/* Default PCI flags is 0 */
-unsigned int ppc_pci_flags;
-
 void pcibios_make_OF_bus_map(void);
 
 static void fixup_broken_pcnet32(struct pci_dev* dev);
-static int reparent_resources(struct resource *parent, struct resource *res);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_PPC_OF
 static u8* pci_to_OF_bus_map;
@@ -97,285 +94,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
 
-static int skip_isa_ioresource_align(struct pci_dev *dev)
-{
-       if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
-           !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
-               return 1;
-       return 0;
-}
-
-/*
- * We need to avoid collisions with `mirrored' VGA ports
- * and other strange ISA hardware, so we always want the
- * addresses to be allocated in the 0x000-0x0ff region
- * modulo 0x400.
- *
- * Why? Because some silly external IO cards only decode
- * the low 10 bits of the IO address. The 0x00-0xff region
- * is reserved for motherboard devices that decode all 16
- * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
- * but we want to try to avoid allocating at 0x2900-0x2bff
- * which might have be mirrored at 0x0100-0x03ff..
- */
-void pcibios_align_resource(void *data, struct resource *res,
-                               resource_size_t size, resource_size_t align)
-{
-       struct pci_dev *dev = data;
-
-       if (res->flags & IORESOURCE_IO) {
-               resource_size_t start = res->start;
-
-               if (skip_isa_ioresource_align(dev))
-                       return;
-               if (start & 0x300) {
-                       start = (start + 0x3ff) & ~0x3ff;
-                       res->start = start;
-               }
-       }
-}
-EXPORT_SYMBOL(pcibios_align_resource);
-
-/*
- *  Handle resources of PCI devices.  If the world were perfect, we could
- *  just allocate all the resource regions and do nothing more.  It isn't.
- *  On the other hand, we cannot just re-allocate all devices, as it would
- *  require us to know lots of host bridge internals.  So we attempt to
- *  keep as much of the original configuration as possible, but tweak it
- *  when it's found to be wrong.
- *
- *  Known BIOS problems we have to work around:
- *     - I/O or memory regions not configured
- *     - regions configured, but not enabled in the command register
- *     - bogus I/O addresses above 64K used
- *     - expansion ROMs left enabled (this may sound harmless, but given
- *       the fact the PCI specs explicitly allow address decoders to be
- *       shared between expansion ROMs and other resource regions, it's
- *       at least dangerous)
- *
- *  Our solution:
- *     (1) Allocate resources for all buses behind PCI-to-PCI bridges.
- *         This gives us fixed barriers on where we can allocate.
- *     (2) Allocate resources for all enabled devices.  If there is
- *         a collision, just mark the resource as unallocated. Also
- *         disable expansion ROMs during this step.
- *     (3) Try to allocate resources for disabled devices.  If the
- *         resources were assigned correctly, everything goes well,
- *         if they weren't, they won't disturb allocation of other
- *         resources.
- *     (4) Assign new addresses to resources which were either
- *         not configured at all or misconfigured.  If explicitly
- *         requested by the user, configure expansion ROM address
- *         as well.
- */
-
-static void __init
-pcibios_allocate_bus_resources(struct list_head *bus_list)
-{
-       struct pci_bus *bus;
-       int i;
-       struct resource *res, *pr;
-
-       /* Depth-First Search on bus tree */
-       list_for_each_entry(bus, bus_list, node) {
-               for (i = 0; i < 4; ++i) {
-                       if ((res = bus->resource[i]) == NULL || !res->flags
-                           || res->start > res->end)
-                               continue;
-                       if (bus->parent == NULL)
-                               pr = (res->flags & IORESOURCE_IO)?
-                                       &ioport_resource : &iomem_resource;
-                       else {
-                               /* Don't bother with non-root busses when
-                                * re-assigning all resources.
-                                */
-                               if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
-                                       continue;
-                               pr = pci_find_parent_resource(bus->self, res);
-                               if (pr == res) {
-                                       /* this happens when the generic PCI
-                                        * code (wrongly) decides that this
-                                        * bridge is transparent  -- paulus
-                                        */
-                                       continue;
-                               }
-                       }
-
-                       DBG("PCI: dev %s (bus 0x%02x) bridge rsrc %d: %016llx..%016llx "
-                           "(f:0x%08lx), parent %p\n",
-                           bus->self ? pci_name(bus->self) : "PHB", bus->number, i,
-                           (u64)res->start, (u64)res->end, res->flags, pr);
-
-                       if (pr && !(pr->flags & IORESOURCE_UNSET)) {
-                               if (request_resource(pr, res) == 0)
-                                       continue;
-                               /*
-                                * Must be a conflict with an existing entry.
-                                * Move that entry (or entries) under the
-                                * bridge resource and try again.
-                                */
-                               if (reparent_resources(pr, res) == 0)
-                                       continue;
-                       }
-                       printk(KERN_WARNING
-                              "PCI: Cannot allocate resource region "
-                              "%d of PCI bridge %d, will remap\n",
-                              i, bus->number);
-                       res->flags |= IORESOURCE_UNSET;
-               }
-               pcibios_allocate_bus_resources(&bus->children);
-       }
-}
-
-/*
- * Reparent resource children of pr that conflict with res
- * under res, and make res replace those children.
- */
-static int __init
-reparent_resources(struct resource *parent, struct resource *res)
-{
-       struct resource *p, **pp;
-       struct resource **firstpp = NULL;
-
-       for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
-               if (p->end < res->start)
-                       continue;
-               if (res->end < p->start)
-                       break;
-               if (p->start < res->start || p->end > res->end)
-                       return -1;      /* not completely contained */
-               if (firstpp == NULL)
-                       firstpp = pp;
-       }
-       if (firstpp == NULL)
-               return -1;      /* didn't find any conflicting entries? */
-       res->parent = parent;
-       res->child = *firstpp;
-       res->sibling = *pp;
-       *firstpp = res;
-       *pp = NULL;
-       for (p = res->child; p != NULL; p = p->sibling) {
-               p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
-                   p->name, (u64)p->start, (u64)p->end, res->name);
-       }
-       return 0;
-}
-
-void __init
-update_bridge_resource(struct pci_dev *dev, struct resource *res)
-{
-       u8 io_base_lo, io_limit_lo;
-       u16 mem_base, mem_limit;
-       u16 cmd;
-       resource_size_t start, end, off;
-       struct pci_controller *hose = dev->sysdata;
-
-       if (!hose) {
-               printk("update_bridge_base: no hose?\n");
-               return;
-       }
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       pci_write_config_word(dev, PCI_COMMAND,
-                             cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
-       if (res->flags & IORESOURCE_IO) {
-               off = (unsigned long) hose->io_base_virt - isa_io_base;
-               start = res->start - off;
-               end = res->end - off;
-               io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK;
-               io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK;
-               if (end > 0xffff)
-                       io_base_lo |= PCI_IO_RANGE_TYPE_32;
-               else
-                       io_base_lo |= PCI_IO_RANGE_TYPE_16;
-               pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
-                               start >> 16);
-               pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
-                               end >> 16);
-               pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
-               pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
-
-       } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
-                  == IORESOURCE_MEM) {
-               off = hose->pci_mem_offset;
-               mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK;
-               mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK;
-               pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
-               pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
-
-       } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
-                  == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) {
-               off = hose->pci_mem_offset;
-               mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK;
-               mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK;
-               pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base);
-               pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit);
-
-       } else {
-               DBG(KERN_ERR "PCI: ugh, bridge %s res has flags=%lx\n",
-                   pci_name(dev), res->flags);
-       }
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
-}
-
-static inline void alloc_resource(struct pci_dev *dev, int idx)
-{
-       struct resource *pr, *r = &dev->resource[idx];
-
-       DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx (f=%lx)\n",
-           pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags);
-       pr = pci_find_parent_resource(dev, r);
-       if (!pr || (pr->flags & IORESOURCE_UNSET) ||  request_resource(pr, r) < 0) {
-               printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
-                      " of device %s, will remap\n", idx, pci_name(dev));
-               if (pr)
-                       DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",
-                           pr, (u64)pr->start, (u64)pr->end, pr->flags);
-               /* We'll assign a new address later */
-               r->flags |= IORESOURCE_UNSET;
-               r->end -= r->start;
-               r->start = 0;
-       }
-}
-
-static void __init
-pcibios_allocate_resources(int pass)
-{
-       struct pci_dev *dev = NULL;
-       int idx, disabled;
-       u16 command;
-       struct resource *r;
-
-       for_each_pci_dev(dev) {
-               pci_read_config_word(dev, PCI_COMMAND, &command);
-               for (idx = 0; idx < 6; idx++) {
-                       r = &dev->resource[idx];
-                       if (r->parent)          /* Already allocated */
-                               continue;
-                       if (!r->flags || (r->flags & IORESOURCE_UNSET))
-                               continue;       /* Not assigned at all */
-                       if (r->flags & IORESOURCE_IO)
-                               disabled = !(command & PCI_COMMAND_IO);
-                       else
-                               disabled = !(command & PCI_COMMAND_MEMORY);
-                       if (pass == disabled)
-                               alloc_resource(dev, idx);
-               }
-               if (pass)
-                       continue;
-               r = &dev->resource[PCI_ROM_RESOURCE];
-               if (r->flags & IORESOURCE_ROM_ENABLE) {
-                       /* Turn the ROM off, leave the resource region, but keep it unregistered. */
-                       u32 reg;
-                       DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
-                       r->flags &= ~IORESOURCE_ROM_ENABLE;
-                       pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-                       pci_write_config_dword(dev, dev->rom_base_reg,
-                                              reg & ~PCI_ROM_ADDRESS_ENABLE);
-               }
-       }
-}
-
 #ifdef CONFIG_PPC_OF
 /*
  * Functions below are used on OpenFirmware machines.
@@ -396,7 +114,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
        } else
                pci_to_OF_bus_map[pci_bus] = bus_range[0];
 
-       for (node=node->child; node != 0;node = node->sibling) {
+       for_each_child_of_node(node, node) {
                struct pci_dev* dev;
                const unsigned int *class_code, *reg;
        
@@ -465,15 +183,18 @@ pcibios_make_OF_bus_map(void)
 typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);
 
 static struct device_node*
-scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data)
+scan_OF_pci_childs(struct device_node *parent, pci_OF_scan_iterator filter, void* data)
 {
+       struct device_node *node;
        struct device_node* sub_node;
 
-       for (; node != 0;node = node->sibling) {
+       for_each_child_of_node(parent, node) {
                const unsigned int *class_code;
        
-               if (filter(node, data))
+               if (filter(node, data)) {
+                       of_node_put(node);
                        return node;
+               }
 
                /* For PCI<->PCI bridges or CardBus bridges, we go down
                 * Note: some OFs create a parent node "multifunc-device" as
@@ -485,9 +206,11 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
                        (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
                        strcmp(node->name, "multifunc-device"))
                        continue;
-               sub_node = scan_OF_pci_childs(node->child, filter, data);
-               if (sub_node)
+               sub_node = scan_OF_pci_childs(node, filter, data);
+               if (sub_node) {
+                       of_node_put(node);
                        return sub_node;
+               }
        }
        return NULL;
 }
@@ -495,11 +218,11 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
 static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
                                               unsigned int devfn)
 {
-       struct device_node *np = NULL;
+       struct device_node *np;
        const u32 *reg;
        unsigned int psize;
 
-       while ((np = of_get_next_child(parent, np)) != NULL) {
+       for_each_child_of_node(parent, np) {
                reg = of_get_property(np, "reg", &psize);
                if (reg == NULL || psize < 4)
                        continue;
@@ -591,7 +314,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
        hose = pci_find_hose_for_OF_device(node);
        if (!hose || !hose->dn)
                return -ENODEV;
-       if (!scan_OF_pci_childs(hose->dn->child,
+       if (!scan_OF_pci_childs(hose->dn,
                        find_OF_pci_device_filter, (void *)node))
                return -ENODEV;
        reg = of_get_property(node, "reg", NULL);
@@ -649,8 +372,7 @@ void pcibios_make_OF_bus_map(void)
 }
 #endif /* CONFIG_PPC_OF */
 
-static int __init
-pcibios_init(void)
+static int __init pcibios_init(void)
 {
        struct pci_controller *hose, *tmp;
        struct pci_bus *bus;
@@ -668,9 +390,10 @@ pcibios_init(void)
                hose->last_busno = 0xff;
                bus = pci_scan_bus_parented(hose->parent, hose->first_busno,
                                            hose->ops, hose);
-               if (bus)
+               if (bus) {
                        pci_bus_add_devices(bus);
-               hose->last_busno = bus->subordinate;
+                       hose->last_busno = bus->subordinate;
+               }
                if (pci_assign_all_buses || next_busno <= hose->last_busno)
                        next_busno = hose->last_busno + pcibios_assign_bus_offset;
        }
@@ -683,22 +406,8 @@ pcibios_init(void)
        if (pci_assign_all_buses && have_of)
                pcibios_make_OF_bus_map();
 
-       /* Call machine dependent fixup */
-       if (ppc_md.pcibios_fixup)
-               ppc_md.pcibios_fixup();
-
-       /* Allocate and assign resources. If we re-assign everything, then
-        * we skip the allocate phase
-        */
-       pcibios_allocate_bus_resources(&pci_root_buses);
-       if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
-               pcibios_allocate_resources(0);
-               pcibios_allocate_resources(1);
-       }
-       if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
-               DBG("PCI: Assigning unassigned resouces...\n");
-               pci_assign_unassigned_resources();
-       }
+       /* Call common code to handle resource allocation */
+       pcibios_resource_survey();
 
        /* Call machine dependent post-init code */
        if (ppc_md.pcibios_after_init)
@@ -758,37 +467,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
        /* XXX FIXME - update OF device tree node interrupt property */
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
-       if (ppc_md.pcibios_enable_device_hook)
-               if (ppc_md.pcibios_enable_device_hook(dev, 0))
-                       return -EINVAL;
-               
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for (idx=0; idx<6; idx++) {
-               r = &dev->resource[idx];
-               if (r->flags & IORESOURCE_UNSET) {
-                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
-                       return -EINVAL;
-               }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       if (cmd != old_cmd) {
-               printk("PCI: Enabling device %s (%04x -> %04x)\n",
-                      pci_name(dev), old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-       return 0;
-}
-
 static struct pci_controller*
 pci_bus_to_hose(int bus)
 {