]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/kernel/pci_64.c
[PATCH] powerpc: properly configure DDR/P5IOC children devs
[linux-2.6-omap-h63xx.git] / arch / powerpc / kernel / pci_64.c
index 3cef1b8f57f01a4d70ff2f376a4cda1289bea7fa..ba92bab7cc2c9188848e43cd220e955537df24f8 100644 (file)
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/machdep.h>
-#include <asm/udbg.h>
 #include <asm/ppc-pci.h>
 
 #ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
+#include <asm/udbg.h>
+#define DBG(fmt...) printk(fmt)
 #else
 #define DBG(fmt...)
 #endif
 
 unsigned long pci_probe_only = 1;
-unsigned long pci_assign_all_buses = 0;
+int pci_assign_all_buses = 0;
 
 /*
  * legal IO pages under MAX_ISA_PORT.  This is to ensure we don't touch
@@ -53,13 +53,9 @@ EXPORT_SYMBOL(io_page_mask);
 #ifdef CONFIG_PPC_MULTIPLATFORM
 static void fixup_resource(struct resource *res, struct pci_dev *dev);
 static void do_bus_setup(struct pci_bus *bus);
+static void phbs_remap_io(void);
 #endif
 
-unsigned int pcibios_assign_all_busses(void)
-{
-       return pci_assign_all_buses;
-}
-
 /* pci_io_base -- the base address from which io bars are offsets.
  * This is the lowest I/O base address (so bar values are always positive),
  * and it *must* be the start of ISA space if an ISA bus exists because
@@ -187,7 +183,7 @@ static DEFINE_SPINLOCK(hose_spinlock);
 /*
  * pci_controller(phb) initialized common variables.
  */
-void __devinit pci_setup_pci_controller(struct pci_controller *hose)
+static void __devinit pci_setup_pci_controller(struct pci_controller *hose)
 {
        memset(hose, 0, sizeof(struct pci_controller));
 
@@ -197,7 +193,67 @@ void __devinit pci_setup_pci_controller(struct pci_controller *hose)
        spin_unlock(&hose_spinlock);
 }
 
-static void __init pcibios_claim_one_bus(struct pci_bus *b)
+static void add_linux_pci_domain(struct device_node *dev,
+                                struct pci_controller *phb)
+{
+       struct property *of_prop;
+       unsigned int size;
+
+       of_prop = (struct property *)
+               get_property(dev, "linux,pci-domain", &size);
+       if (of_prop != NULL)
+               return;
+       WARN_ON(of_prop && size < sizeof(int));
+       if (of_prop && size < sizeof(int))
+               of_prop = NULL;
+       size = sizeof(struct property) + sizeof(int);
+       if (of_prop == NULL) {
+               if (mem_init_done)
+                       of_prop = kmalloc(size, GFP_KERNEL);
+               else
+                       of_prop = alloc_bootmem(size);
+       }
+       memset(of_prop, 0, sizeof(struct property));
+       of_prop->name = "linux,pci-domain";
+       of_prop->length = sizeof(int);
+       of_prop->value = (unsigned char *)&of_prop[1];
+       *((int *)of_prop->value) = phb->global_number;
+       prom_add_property(dev, of_prop);
+}
+
+struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
+{
+       struct pci_controller *phb;
+
+       if (mem_init_done)
+               phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
+       else
+               phb = alloc_bootmem(sizeof (struct pci_controller));
+       if (phb == NULL)
+               return NULL;
+       pci_setup_pci_controller(phb);
+       phb->arch_data = dev;
+       phb->is_dynamic = mem_init_done;
+       if (dev)
+               add_linux_pci_domain(dev, phb);
+       return phb;
+}
+
+void pcibios_free_controller(struct pci_controller *phb)
+{
+       if (phb->arch_data) {
+               struct device_node *np = phb->arch_data;
+               int *domain = (int *)get_property(np,
+                                                 "linux,pci-domain", NULL);
+               if (domain)
+                       *domain = -1;
+       }
+       if (phb->is_dynamic)
+               kfree(phb);
+}
+
+#ifndef CONFIG_PPC_ISERIES
+void __devinit pcibios_claim_one_bus(struct pci_bus *b)
 {
        struct pci_dev *dev;
        struct pci_bus *child_bus;
@@ -217,8 +273,10 @@ static void __init pcibios_claim_one_bus(struct pci_bus *b)
        list_for_each_entry(child_bus, &b->children, node)
                pcibios_claim_one_bus(child_bus);
 }
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
+#endif
 
-#ifndef CONFIG_PPC_ISERIES
 static void __init pcibios_claim_of_setup(void)
 {
        struct pci_bus *b;
@@ -269,6 +327,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
        addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
        if (!addrs)
                return;
+       DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
        for (; proplen >= 20; proplen -= 20, addrs += 5) {
                flags = pci_parse_of_flags(addrs[0]);
                if (!flags)
@@ -278,6 +337,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
                if (!size)
                        continue;
                i = addrs[0] & 0xff;
+               DBG("  base: %llx, size: %llx, i: %x\n",
+                   (unsigned long long)base, (unsigned long long)size, i);
+
                if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
                        res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
                } else if (i == dev->rom_base_reg) {
@@ -308,6 +370,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        if (type == NULL)
                type = "";
 
+       DBG("    create device, devfn: %x, type: %s\n", devfn, type);
+
        memset(dev, 0, sizeof(struct pci_dev));
        dev->bus = bus;
        dev->sysdata = node;
@@ -321,12 +385,14 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
        dev->subsystem_device = get_int_prop(node, "subsystem-id", 0);
 
-       dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/
+       dev->cfg_size = pci_cfg_space_size(dev);
 
        sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
                dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
        dev->class = get_int_prop(node, "class-code", 0);
 
+       DBG("    class: 0x%x\n", dev->class);
+
        dev->current_state = 4;         /* unknown power state */
 
        if (!strcmp(type, "pci")) {
@@ -348,6 +414,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
 
        pci_parse_of_addrs(node, dev);
 
+       DBG("    adding to system ...\n");
+
        pci_device_add(dev, bus);
 
        /* XXX pci_scan_msi_device(dev); */
@@ -364,15 +432,21 @@ void __devinit of_scan_bus(struct device_node *node,
        int reglen, devfn;
        struct pci_dev *dev;
 
+       DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+
        while ((child = of_get_next_child(node, child)) != NULL) {
+               DBG("  * %s\n", child->full_name);
                reg = (u32 *) get_property(child, "reg", &reglen);
                if (reg == NULL || reglen < 20)
                        continue;
                devfn = (reg[0] >> 8) & 0xff;
+
                /* create a new pci_dev for this device */
                dev = of_create_pci_dev(child, bus, devfn);
                if (!dev)
                        continue;
+               DBG("dev header type: %x\n", dev->hdr_type);
+
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                        of_scan_pci_bridge(child, dev);
@@ -392,16 +466,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        unsigned int flags;
        u64 size;
 
+       DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
        /* parse bus-range property */
        busrange = (u32 *) get_property(node, "bus-range", &len);
        if (busrange == NULL || len != 8) {
-               printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+               printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
                       node->full_name);
                return;
        }
        ranges = (u32 *) get_property(node, "ranges", &len);
        if (ranges == NULL) {
-               printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+               printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
                       node->full_name);
                return;
        }
@@ -455,10 +531,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
        }
        sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
                bus->number);
+       DBG("    bus name: %s\n", bus->name);
 
        mode = PCI_PROBE_NORMAL;
        if (ppc_md.pci_probe_mode)
                mode = ppc_md.pci_probe_mode(bus);
+       DBG("    probe mode: %d\n", mode);
+
        if (mode == PCI_PROBE_DEVTREE)
                of_scan_bus(node, bus);
        else if (mode == PCI_PROBE_NORMAL)
@@ -474,6 +553,8 @@ void __devinit scan_phb(struct pci_controller *hose)
        int i, mode;
        struct resource *res;
 
+       DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+
        bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
        if (bus == NULL) {
                printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
@@ -498,8 +579,9 @@ void __devinit scan_phb(struct pci_controller *hose)
 
        mode = PCI_PROBE_NORMAL;
 #ifdef CONFIG_PPC_MULTIPLATFORM
-       if (ppc_md.pci_probe_mode)
+       if (node && ppc_md.pci_probe_mode)
                mode = ppc_md.pci_probe_mode(bus);
+       DBG("    probe mode: %d\n", mode);
        if (mode == PCI_PROBE_DEVTREE) {
                bus->subordinate = hose->last_busno;
                of_scan_bus(node, bus);
@@ -507,7 +589,6 @@ void __devinit scan_phb(struct pci_controller *hose)
 #endif /* CONFIG_PPC_MULTIPLATFORM */
        if (mode == PCI_PROBE_NORMAL)
                hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
-       pci_bus_add_devices(bus);
 }
 
 static int __init pcibios_init(void)
@@ -526,8 +607,10 @@ static int __init pcibios_init(void)
        printk("PCI: Probing PCI hardware\n");
 
        /* Scan all of the recorded PCI controllers.  */
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
                scan_phb(hose);
+               pci_bus_add_devices(hose->bus);
+       }
 
 #ifndef CONFIG_PPC_ISERIES
        if (pci_probe_only)
@@ -788,8 +871,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
  * Returns a negative error code on failure, zero on success.
  */
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state,
-                       int write_combine)
+                       enum pci_mmap_state mmap_state, int write_combine)
 {
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
@@ -842,6 +924,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
                                      unsigned long phb_io_base_phys,
                                      void __iomem * phb_io_base_virt)
 {
+       /* Remove these asap */
+
+       struct pci_address {
+               u32 a_hi;
+               u32 a_mid;
+               u32 a_lo;
+       };
+
+       struct isa_address {
+               u32 a_hi;
+               u32 a_lo;
+       };
+
+       struct isa_range {
+               struct isa_address isa_addr;
+               struct pci_address pci_addr;
+               unsigned int size;
+       };
+
        struct isa_range *range;
        unsigned long pci_addr;
        unsigned int isa_addr;
@@ -907,9 +1008,10 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
         *                      (size depending on dev->n_addr_cells)
         *   cells 4+5 or 5+6:  the size of the range
         */
-       rlen = 0;
-       hose->io_base_phys = 0;
        ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+       if (ranges == NULL)
+               return;
+       hose->io_base_phys = 0;
        while ((rlen -= np * sizeof(unsigned int)) >= 0) {
                res = NULL;
                pci_space = ranges[0];
@@ -1107,6 +1209,8 @@ int remap_bus_range(struct pci_bus *bus)
        
        if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
                return 1;
+       if (start_phys == 0)
+               return 1;
        printk("mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
        if (__ioremap_explicit(start_phys, start_virt, size,
                               _PAGE_NO_CACHE | _PAGE_GUARDED))
@@ -1116,7 +1220,7 @@ int remap_bus_range(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(remap_bus_range);
 
-void phbs_remap_io(void)
+static void phbs_remap_io(void)
 {
        struct pci_controller *hose, *tmp;
 
@@ -1124,17 +1228,6 @@ void phbs_remap_io(void)
                remap_bus_range(hose->bus);
 }
 
-/*
- * ppc64 can have multifunction devices that do not respond to function 0.
- * In this case we must scan all functions.
- * XXX this can go now, we use the OF device tree in all the
- * cases that caused problems. -- paulus
- */
-int pcibios_scan_all_fns(struct pci_bus *bus, int devfn)
-{
-       return 0;
-}
-
 static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -1177,6 +1270,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
+
 static void __devinit do_bus_setup(struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -1260,8 +1354,38 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
        *end = rsrc->end + offset;
 }
 
+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)
+                       if (hose->arch_data == node)
+                               return hose;
+               node = node->parent;
+       }
+       return NULL;
+}
+
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller *hose, *tmp;
+
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + hose->pci_io_size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - pci_io_base;
+                       return base + (address - hose->io_base_phys);
+               }
+       }
+       return (unsigned int)-1;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
 
 #define IOBASE_BRIDGE_NUMBER   0
 #define IOBASE_MEMORY          1