powerpc32, ftrace: save and restore mcount regs with macro
[safe/jmp/linux-2.6] / arch / powerpc / kernel / pci-common.c
index 780db38..2ad1731 100644 (file)
@@ -16,8 +16,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#undef DEBUG
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
+#include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
+LIST_HEAD(hose_list);
 
 /* XXX kill that some day ... */
 static int global_phb_number;          /* Global phb counter */
@@ -114,19 +114,24 @@ void pcibios_free_controller(struct pci_controller *phb)
                kfree(phb);
 }
 
+static resource_size_t pcibios_io_size(const struct pci_controller *hose)
+{
+#ifdef CONFIG_PPC64
+       return hose->pci_io_size;
+#else
+       return hose->io_resource.end - hose->io_resource.start + 1;
+#endif
+}
+
 int pcibios_vaddr_is_ioport(void __iomem *address)
 {
        int ret = 0;
        struct pci_controller *hose;
-       unsigned long size;
+       resource_size_t size;
 
        spin_lock(&hose_spinlock);
        list_for_each_entry(hose, &hose_list, list_node) {
-#ifdef CONFIG_PPC64
-               size = hose->pci_io_size;
-#else
-               size = hose->io_resource.end - hose->io_resource.start + 1;
-#endif
+               size = pcibios_io_size(hose);
                if (address >= hose->io_base_virt &&
                    address < (hose->io_base_virt + size)) {
                        ret = 1;
@@ -137,6 +142,29 @@ int pcibios_vaddr_is_ioport(void __iomem *address)
        return ret;
 }
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose;
+       resource_size_t size;
+       unsigned long ret = ~0;
+
+       spin_lock(&hose_spinlock);
+       list_for_each_entry(hose, &hose_list, list_node) {
+               size = pcibios_io_size(hose);
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       ret = base + (address - hose->io_base_phys);
+                       break;
+               }
+       }
+       spin_unlock(&hose_spinlock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 /*
  * Return the domain number for this bus.
  */
@@ -159,8 +187,6 @@ EXPORT_SYMBOL(pci_domain_nr);
  */
 struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
 {
-       if (!have_of)
-               return NULL;
        while(node) {
                struct pci_controller *hose, *tmp;
                list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
@@ -202,26 +228,6 @@ char __devinit *pcibios_setup(char *str)
        return str;
 }
 
-void __devinit pcibios_setup_new_device(struct pci_dev *dev)
-{
-       struct dev_archdata *sd = &dev->dev.archdata;
-
-       sd->of_node = pci_device_to_OF_node(dev);
-
-       pr_debug("PCI: device %s OF node: %s\n", pci_name(dev),
-                sd->of_node ? sd->of_node->full_name : "<none>");
-
-       sd->dma_ops = pci_dma_ops;
-#ifdef CONFIG_PPC32
-       sd->dma_data = (void *)PCI_DRAM_OFFSET;
-#endif
-       set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
-
-       if (ppc_md.pci_dma_dev_setup)
-               ppc_md.pci_dma_dev_setup(dev);
-}
-EXPORT_SYMBOL(pcibios_setup_new_device);
-
 /*
  * Reads the interrupt pin to determine if interrupt is use by card.
  * If the interrupt is used, then gets the interrupt line from the
@@ -279,7 +285,8 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
        } else {
                pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
                         oirq.size, oirq.specifier[0], oirq.specifier[1],
-                   oirq.controller->full_name);
+                        oirq.controller ? oirq.controller->full_name :
+                        "<default>");
 
                virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
                                             oirq.size);
@@ -391,13 +398,10 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        }
 
        /* XXX would be nice to have a way to ask for write-through */
-       prot |= _PAGE_NO_CACHE;
        if (write_combine)
-               prot &= ~_PAGE_GUARDED;
+               return pgprot_noncached_wc(prot);
        else
-               prot |= _PAGE_GUARDED;
-
-       return __pgprot(prot);
+               return pgprot_noncached(prot);
 }
 
 /*
@@ -408,19 +412,17 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
 pgprot_t pci_phys_mem_access_prot(struct file *file,
                                  unsigned long pfn,
                                  unsigned long size,
-                                 pgprot_t protection)
+                                 pgprot_t prot)
 {
        struct pci_dev *pdev = NULL;
        struct resource *found = NULL;
-       unsigned long prot = pgprot_val(protection);
        resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
        int i;
 
        if (page_is_ram(pfn))
-               return __pgprot(prot);
-
-       prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+               return prot;
 
+       prot = pgprot_noncached(prot);
        for_each_pci_dev(pdev) {
                for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
                        struct resource *rp = &pdev->resource[i];
@@ -441,14 +443,14 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
        }
        if (found) {
                if (found->flags & IORESOURCE_PREFETCH)
-                       prot &= ~_PAGE_GUARDED;
+                       prot = pgprot_noncached_wc(prot);
                pci_dev_put(pdev);
        }
 
        pr_debug("PCI: Non-PCI map for %llx, prot: %lx\n",
-                (unsigned long long)offset, prot);
+                (unsigned long long)offset, pgprot_val(prot));
 
-       return __pgprot(prot);
+       return prot;
 }
 
 
@@ -588,8 +590,21 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus,
                 (unsigned long long)(offset + size - 1));
 
        if (mmap_state == pci_mmap_mem) {
-               if ((offset + size) > hose->isa_mem_size)
-                       return -ENXIO;
+               /* Hack alert !
+                *
+                * Because X is lame and can fail starting if it gets an error trying
+                * to mmap legacy_mem (instead of just moving on without legacy memory
+                * access) we fake it here by giving it anonymous memory, effectively
+                * behaving just like /dev/zero
+                */
+               if ((offset + size) > hose->isa_mem_size) {
+                       printk(KERN_DEBUG
+                              "Process %s (pid:%d) mapped non-existing PCI legacy memory for 0%04x:%02x\n",
+                              current->comm, current->pid, pci_domain_nr(bus), bus->number);
+                       if (vma->vm_flags & VM_SHARED)
+                               return shmem_zero_setup(vma);
+                       return 0;
+               }
                offset += hose->isa_mem_phys;
        } else {
                unsigned long io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
@@ -604,8 +619,7 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus,
        pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset);
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start,
                               vma->vm_page_prot);
@@ -1074,33 +1088,50 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
        }
 }
 
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
 {
-       struct pci_dev *dev;
-
-       pr_debug("PCI: Fixup bus %d (%s)\n",
-                bus->number, bus->self ? pci_name(bus->self) : "PHB");
-
-       /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
-        * now differently between 32 and 64 bits.
-        */
+       /* Fix up the bus resources for P2P bridges */
        if (bus->self != NULL)
                pcibios_fixup_bridge(bus);
 
+       /* Platform specific bus fixups. This is currently only used
+        * by fsl_pci and I'm hoping to get rid of it at some point
+        */
+       if (ppc_md.pcibios_fixup_bus)
+               ppc_md.pcibios_fixup_bus(bus);
+
        /* Setup bus DMA mappings */
        if (ppc_md.pci_dma_bus_setup)
                ppc_md.pci_dma_bus_setup(bus);
+}
 
-       /* Setup DMA for all PCI devices on that bus */
-       list_for_each_entry(dev, &bus->devices, bus_list)
-               pcibios_setup_new_device(dev);
+void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
 
-       /* Platform specific bus fixups */
-       if (ppc_md.pcibios_fixup_bus)
-               ppc_md.pcibios_fixup_bus(bus);
+       pr_debug("PCI: Fixup bus devices %d (%s)\n",
+                bus->number, bus->self ? pci_name(bus->self) : "PHB");
 
-       /* Read default IRQs and fixup if necessary */
        list_for_each_entry(dev, &bus->devices, bus_list) {
+               struct dev_archdata *sd = &dev->dev.archdata;
+
+               /* Setup OF node pointer in archdata */
+               sd->of_node = pci_device_to_OF_node(dev);
+
+               /* Fixup NUMA node as it may not be setup yet by the generic
+                * code and is needed by the DMA init
+                */
+               set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+               /* Hook up default DMA ops */
+               sd->dma_ops = pci_dma_ops;
+               sd->dma_data = (void *)PCI_DRAM_OFFSET;
+
+               /* Additional platform DMA/iommu setup */
+               if (ppc_md.pci_dma_dev_setup)
+                       ppc_md.pci_dma_dev_setup(dev);
+
+               /* Read default IRQs and fixup if necessary */
                pci_read_irq_line(dev);
                if (ppc_md.pci_irq_fixup)
                        ppc_md.pci_irq_fixup(dev);
@@ -1110,22 +1141,19 @@ static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* When called from the generic PCI probe, read PCI<->PCI bridge
-        * bases before proceeding
+        * bases. This is -not- called when generating the PCI tree from
+        * the OF device-tree.
         */
        if (bus->self != NULL)
                pci_read_bridge_bases(bus);
-       __pcibios_fixup_bus(bus);
-}
-EXPORT_SYMBOL(pcibios_fixup_bus);
 
-/* When building a bus from the OF tree rather than probing, we need a
- * slightly different version of the fixup which doesn't read the
- * bridge bases using config space accesses
- */
-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
-{
-       __pcibios_fixup_bus(bus);
+       /* Now fixup the bus bus */
+       pcibios_setup_bus_self(bus);
+
+       /* Now fixup devices on that bus */
+       pcibios_setup_bus_devices(bus);
 }
+EXPORT_SYMBOL(pcibios_fixup_bus);
 
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
@@ -1242,9 +1270,12 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
        int i;
        struct resource *res, *pr;
 
+       pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
+                pci_domain_nr(bus), bus->number);
+
        for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
                if ((res = bus->resource[i]) == NULL || !res->flags
-                   || res->start > res->end)
+                   || res->start > res->end || res->parent)
                        continue;
                if (bus->parent == NULL)
                        pr = (res->flags & IORESOURCE_IO) ?
@@ -1366,6 +1397,63 @@ static void __init pcibios_allocate_resources(int pass)
        }
 }
 
+static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       resource_size_t offset;
+       struct resource *res, *pres;
+       int i;
+
+       pr_debug("Reserving legacy ranges for domain %04x\n", pci_domain_nr(bus));
+
+       /* Check for IO */
+       if (!(hose->io_resource.flags & IORESOURCE_IO))
+               goto no_io;
+       offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy IO";
+       res->flags = IORESOURCE_IO;
+       res->start = offset;
+       res->end = (offset + 0xfff) & 0xfffffffful;
+       pr_debug("Candidate legacy IO: %pR\n", res);
+       if (request_resource(&hose->io_resource, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve Legacy IO %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+
+ no_io:
+       /* Check for memory */
+       offset = hose->pci_mem_offset;
+       pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
+       for (i = 0; i < 3; i++) {
+               pres = &hose->mem_resources[i];
+               if (!(pres->flags & IORESOURCE_MEM))
+                       continue;
+               pr_debug("hose mem res: %pR\n", pres);
+               if ((pres->start - offset) <= 0xa0000 &&
+                   (pres->end - offset) >= 0xbffff)
+                       break;
+       }
+       if (i >= 3)
+               return;
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(res == NULL);
+       res->name = "Legacy VGA memory";
+       res->flags = IORESOURCE_MEM;
+       res->start = 0xa0000 + offset;
+       res->end = 0xbffff + offset;
+       pr_debug("Candidate VGA memory: %pR\n", res);
+       if (request_resource(pres, res)) {
+               printk(KERN_DEBUG
+                      "PCI %04x:%02x Cannot reserve VGA memory %pR\n",
+                      pci_domain_nr(bus), bus->number, res);
+               kfree(res);
+       }
+}
+
 void __init pcibios_resource_survey(void)
 {
        struct pci_bus *b;
@@ -1381,6 +1469,18 @@ void __init pcibios_resource_survey(void)
                pcibios_allocate_resources(1);
        }
 
+       /* Before we start assigning unassigned resource, we try to reserve
+        * the low IO area and the VGA memory area if they intersect the
+        * bus available resources to avoid allocating things on top of them
+        */
+       if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
+               list_for_each_entry(b, &pci_root_buses, node)
+                       pcibios_reserve_legacy_regions(b);
+       }
+
+       /* Now, if the platform didn't decide to blindly trust the firmware,
+        * we proceed to assigning things that were left unassigned
+        */
        if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
                pr_debug("PCI: Assigning unassigned resouces...\n");
                pci_assign_unassigned_resources();
@@ -1392,9 +1492,11 @@ void __init pcibios_resource_survey(void)
 }
 
 #ifdef CONFIG_HOTPLUG
-/* This is used by the pSeries hotplug driver to allocate resource
+
+/* This is used by the PCI hotplug driver to allocate resource
  * of newly plugged busses. We can try to consolidate with the
- * rest of the code later, for now, keep it as-is
+ * rest of the code later, for now, keep it as-is as our main
+ * resource allocation function doesn't deal with sub-trees yet.
  */
 void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
 {
@@ -1409,6 +1511,14 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
 
                        if (r->parent || !r->start || !r->flags)
                                continue;
+
+                       pr_debug("PCI: Claiming %s: "
+                                "Resource %d: %016llx..%016llx [%x]\n",
+                                pci_name(dev), i,
+                                (unsigned long long)r->start,
+                                (unsigned long long)r->end,
+                                (unsigned int)r->flags);
+
                        pci_claim_resource(dev, i);
                }
        }
@@ -1417,6 +1527,31 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
                pcibios_claim_one_bus(child_bus);
 }
 EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
+
+
+/* pcibios_finish_adding_to_bus
+ *
+ * This is to be called by the hotplug code after devices have been
+ * added to a bus, this include calling it for a PHB that is just
+ * being added
+ */
+void pcibios_finish_adding_to_bus(struct pci_bus *bus)
+{
+       pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n",
+                pci_domain_nr(bus), bus->number);
+
+       /* Allocate bus and devices resources */
+       pcibios_allocate_bus_resources(bus);
+       pcibios_claim_one_bus(bus);
+
+       /* Add new devices to global lists.  Register in proc, sysfs. */
+       pci_bus_add_devices(bus);
+
+       /* Fixup EEH */
+       eeh_add_device_tree_late(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
+
 #endif /* CONFIG_HOTPLUG */
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)