X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fpci_sun4v.c;h=0c08952029707c846fb3e152a16d30edd42b453a;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=03ad4c06758ed95fd59d996a11fcc7784bc2c54b;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 03ad4c067..0c0895202 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "pci_impl.h" #include "iommu_common.h" @@ -647,37 +646,35 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u /* Recursively descend into the OBP device tree, rooted at toplevel_node, * looking for a PCI device matching bus and devfn. */ -static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) +static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn) { - toplevel_node = toplevel_node->child; + toplevel_node = prom_getchild(toplevel_node); - while (toplevel_node != NULL) { - struct linux_prom_pci_registers *regs; - struct property *prop; - int ret; + while (toplevel_node != 0) { + int ret = obp_find(pregs, toplevel_node, bus, devfn); - ret = obp_find(toplevel_node, bus, devfn); if (ret != 0) return ret; - prop = of_find_property(toplevel_node, "reg", NULL); - if (!prop) + ret = prom_getproperty(toplevel_node, "reg", (char *) pregs, + sizeof(*pregs) * PROMREG_MAX); + if (ret == 0 || ret == -1) goto next_sibling; - regs = prop->value; - if (((regs->phys_hi >> 16) & 0xff) == bus && - ((regs->phys_hi >> 8) & 0xff) == devfn) + if (((pregs[0].phys_hi >> 16) & 0xff) == bus && + ((pregs[0].phys_hi >> 8) & 0xff) == devfn) break; next_sibling: - toplevel_node = toplevel_node->sibling; + toplevel_node = prom_getsibling(toplevel_node); } - return toplevel_node != NULL; + return toplevel_node; } static int pdev_htab_populate(struct pci_pbm_info *pbm) { + struct linux_prom_pci_registers pr[PROMREG_MAX]; u32 devhandle = pbm->devhandle; unsigned int bus; @@ -688,7 +685,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm) unsigned int device = PCI_SLOT(devfn); unsigned int func = PCI_FUNC(devfn); - if (obp_find(pbm->prom_node, bus, devfn)) { + if (obp_find(pr, pbm->prom_node, bus, devfn)) { int err = pdev_htab_add(devhandle, bus, device, func); if (err) @@ -814,7 +811,8 @@ static void pbm_scan_bus(struct pci_controller_info *p, pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; #endif - pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, + pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); @@ -824,18 +822,15 @@ static void pbm_scan_bus(struct pci_controller_info *p, static void pci_sun4v_scan_bus(struct pci_controller_info *p) { - struct property *prop; - struct device_node *dp; - - if ((dp = p->pbm_A.prom_node) != NULL) { - prop = of_find_property(dp, "66mhz-capable", NULL); - p->pbm_A.is_66mhz_capable = (prop != NULL); + if (p->pbm_A.prom_node) { + p->pbm_A.is_66mhz_capable = + prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); pbm_scan_bus(p, &p->pbm_A); } - if ((dp = p->pbm_B.prom_node) != NULL) { - prop = of_find_property(dp, "66mhz-capable", NULL); - p->pbm_B.is_66mhz_capable = (prop != NULL); + if (p->pbm_B.prom_node) { + p->pbm_B.is_66mhz_capable = + prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); pbm_scan_bus(p, &p->pbm_B); } @@ -843,6 +838,45 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } +static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int devino) +{ + u32 devhandle = pbm->devhandle; + int pil; + + pil = 5; + if (pdev) { + switch ((pdev->class >> 16) & 0xff) { + case PCI_BASE_CLASS_STORAGE: + pil = 5; + break; + + case PCI_BASE_CLASS_NETWORK: + pil = 6; + break; + + case PCI_BASE_CLASS_DISPLAY: + pil = 9; + break; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: + pil = 10; + break; + + default: + pil = 5; + break; + }; + } + BUG_ON(PIL_RESERVED(pil)); + + return sun4v_build_irq(devhandle, devino, pil, IBF_PCI); +} + static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) { struct pcidev_cookie *pcp = pdev->sysdata; @@ -978,13 +1012,8 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, HV_PCI_TSBID(0, i), &io_attrs, &ra); if (ret == HV_EOK) { - if (page_in_phys_avail(ra)) { - pci_sun4v_iommu_demap(devhandle, - HV_PCI_TSBID(0, i), 1); - } else { - cnt++; - __set_bit(i, arena->map); - } + cnt++; + __set_bit(i, arena->map); } } @@ -994,18 +1023,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { struct pci_iommu *iommu = pbm->iommu; - struct property *prop; unsigned long num_tsb_entries, sz; u32 vdma[2], dma_mask, dma_offset; - int tsbsize; - - prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); - if (prop) { - u32 *val = prop->value; + int err, tsbsize; - vdma[0] = val[0]; - vdma[1] = val[1]; - } else { + err = prom_getproperty(pbm->prom_node, "virtual-dma", + (char *)&vdma[0], sizeof(vdma)); + if (err == 0 || err == -1) { /* No property, use default values. */ vdma[0] = 0x80000000; vdma[1] = 0x80000000; @@ -1057,30 +1081,34 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) iommu->arena.limit = num_tsb_entries; sz = probe_existing_entries(pbm, iommu); - if (sz) - printk("%s: Imported %lu TSB entries from OBP\n", - pbm->name, sz); + + printk("%s: TSB entries [%lu], existing mapings [%lu]\n", + pbm->name, num_tsb_entries, sz); } static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) { - struct property *prop; - unsigned int *busrange; - - prop = of_find_property(pbm->prom_node, "bus-range", NULL); - - busrange = prop->value; + unsigned int busrange[2]; + int prom_node = pbm->prom_node; + int err; + + err = prom_getproperty(prom_node, "bus-range", + (char *)&busrange[0], + sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); + prom_halt(); + } pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; } -static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) +static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle) { struct pci_pbm_info *pbm; - struct property *prop; - int len, i; + int err, i; if (devhandle & 0x40) pbm = &p->pbm_B; @@ -1088,19 +1116,32 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pbm = &p->pbm_A; pbm->parent = p; - pbm->prom_node = dp; + pbm->prom_node = prom_node; pbm->pci_first_slot = 1; pbm->devhandle = devhandle; - pbm->name = dp->full_name; + sprintf(pbm->name, "SUN4V-PCI%d PBM%c", + p->index, (pbm == &p->pbm_A ? 'A' : 'B')); - printk("%s: SUN4V PCI Bus Module\n", pbm->name); + printk("%s: devhandle[%x] prom_node[%x:%x]\n", + pbm->name, pbm->devhandle, + pbm->prom_node, prom_getchild(pbm->prom_node)); + + prom_getstring(prom_node, "name", + pbm->prom_name, sizeof(pbm->prom_name)); + + err = prom_getproperty(prom_node, "ranges", + (char *) pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no ranges property.\n", + pbm->name); + prom_halt(); + } - prop = of_find_property(dp, "ranges", &len); - pbm->pbm_ranges = prop->value; pbm->num_pbm_ranges = - (len / sizeof(struct linux_prom_pci_ranges)); + (err / sizeof(struct linux_prom_pci_ranges)); /* Mask out the top 8 bits of the ranges, leaving the real * physical address. @@ -1111,13 +1152,24 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_sun4v_determine_mem_io_space(pbm); pbm_register_toplevel_resources(p, pbm); - prop = of_find_property(dp, "interrupt-map", &len); - pbm->pbm_intmap = prop->value; - pbm->num_pbm_intmap = - (len / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(prom_node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no interrupt-map property.\n", + pbm->name); + prom_halt(); + } - prop = of_find_property(dp, "interrupt-map-mask", NULL); - pbm->pbm_intmask = prop->value; + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(prom_node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == 0 || err == -1) { + prom_printf("%s: Fatal error, no interrupt-map-mask.\n", + pbm->name); + prom_halt(); + } pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); @@ -1125,19 +1177,16 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pdev_htab_populate(pbm); } -void sun4v_pci_init(struct device_node *dp, char *model_name) +void sun4v_pci_init(int node, char *model_name) { struct pci_controller_info *p; struct pci_iommu *iommu; - struct property *prop; - struct linux_prom64_registers *regs; + struct linux_prom64_registers regs; u32 devhandle; int i; - prop = of_find_property(dp, "reg", NULL); - regs = prop->value; - - devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; + 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; @@ -1150,7 +1199,7 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) &p->pbm_B); if (pbm->devhandle == (devhandle ^ 0x40)) { - pci_sun4v_pbm_init(p, dp, devhandle); + pci_sun4v_pbm_init(p, node, devhandle); return; } } @@ -1191,6 +1240,7 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; + p->irq_build = pci_sun4v_irq_build; p->base_address_update = pci_sun4v_base_address_update; p->resource_adjust = pci_sun4v_resource_adjust; p->pci_ops = &pci_sun4v_ops; @@ -1200,7 +1250,7 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) */ pci_memspace_mask = 0x7fffffffUL; - pci_sun4v_pbm_init(p, dp, devhandle); + pci_sun4v_pbm_init(p, node, devhandle); return; fatal_memory_error: