[SPARC64]: PCI-SUN4V fixes.
authorDavid S. Miller <davem@sunset.davemloft.net>
Mon, 13 Feb 2006 06:06:53 +0000 (22:06 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 20 Mar 2006 09:12:33 +0000 (01:12 -0800)
Clear top 8-bits of physical addresses in "ranges" property.
This gives the actual physical address.

Detect PBM-A vs. PBM-B by checking bit 0x40 of the devhandle.

Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc64/kernel/pci_sun4v.c

index 699e91e3e4293553959b7b181926a7cc8c0762c7..19a07f0115ca8b3744297bc929b5b301a87791df 100644 (file)
@@ -776,22 +776,22 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        probe_existing_entries(pbm, iommu);
 }
 
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node)
+static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, unsigned int devhandle)
 {
        struct pci_pbm_info *pbm;
-       struct linux_prom64_registers regs;
        unsigned int busrange[2];
-       int err;
+       int err, i;
 
-       /* XXX */
-       pbm = &p->pbm_A;
+       if (devhandle & 0x40)
+               pbm = &p->pbm_B;
+       else
+               pbm = &p->pbm_A;
 
        pbm->parent = p;
        pbm->prom_node = prom_node;
        pbm->pci_first_slot = 1;
 
-       prom_getproperty(prom_node, "reg", (char *)&regs, sizeof(regs));
-       pbm->devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
+       pbm->devhandle = devhandle;
 
        sprintf(pbm->name, "SUN4V-PCI%d PBM%c",
                p->index, (pbm == &p->pbm_A ? 'A' : 'B'));
@@ -813,6 +813,12 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node)
        pbm->num_pbm_ranges =
                (err / sizeof(struct linux_prom_pci_ranges));
 
+       /* Mask out the top 8 bits of the ranges, leaving the real
+        * physical address.
+        */
+       for (i = 0; i < pbm->num_pbm_ranges; i++)
+               pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff;
+
        pci_sun4v_determine_mem_io_space(pbm);
        pbm_register_toplevel_resources(p, pbm);
 
@@ -851,6 +857,25 @@ void sun4v_pci_init(int node, char *model_name)
 {
        struct pci_controller_info *p;
        struct pci_iommu *iommu;
+       struct linux_prom64_registers regs;
+       unsigned int devhandle;
+
+       prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
+       devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;;
+
+       for (p = pci_controller_root; p; p = p->next) {
+               struct pci_pbm_info *pbm;
+
+               if (p->pbm_A.prom_node && p->pbm_B.prom_node)
+                       continue;
+
+               pbm = (p->pbm_A.prom_node ?
+                      &p->pbm_A :
+                      &p->pbm_B);
+
+               if (pbm->devhandle == (devhandle ^ 0x40))
+                       pci_sun4v_pbm_init(p, node, devhandle);
+       }
 
        p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
        if (!p) {
@@ -892,7 +917,7 @@ void sun4v_pci_init(int node, char *model_name)
         */
        pci_memspace_mask = 0x7fffffffUL;
 
-       pci_sun4v_pbm_init(p, node);
+       pci_sun4v_pbm_init(p, node, devhandle);
 
        prom_printf("sun4v_pci_init: Implement me.\n");
        prom_halt();