diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-12 22:06:53 -0800 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 01:12:33 -0800 |
commit | 3833789bb2e15eb85fad296d8fb40f1437925645 (patch) | |
tree | 31304e25c2d7c9c5f06b0bc74a5f4e9578de904c /arch/sparc64/kernel | |
parent | cf627156c450cd5a0741b31f55181db3400d4887 (diff) |
[SPARC64]: PCI-SUN4V fixes.
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>
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 699e91e3e42..19a07f0115c 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -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 *)®s, 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 *)®s, 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(); |