diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 153 |
1 files changed, 96 insertions, 57 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index a104c80..6bed2f6 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -13,12 +13,10 @@ #include <linux/irq.h> #include <linux/msi.h> #include <linux/log2.h> +#include <linux/of_device.h> #include <asm/iommu.h> #include <asm/irq.h> -#include <asm/upa.h> -#include <asm/pstate.h> -#include <asm/oplib.h> #include <asm/hypervisor.h> #include <asm/prom.h> @@ -27,6 +25,9 @@ #include "pci_sun4v.h" +#define DRIVER_NAME "pci_sun4v" +#define PFX DRIVER_NAME ": " + static unsigned long vpci_major = 1; static unsigned long vpci_minor = 1; @@ -542,7 +543,8 @@ static const struct dma_ops sun4v_dma_ops = { .sync_sg_for_cpu = dma_4v_sync_sg_for_cpu, }; -static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm) +static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm, + struct device *parent) { struct property *prop; struct device_node *dp; @@ -550,7 +552,7 @@ static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm) dp = pbm->prom_node; prop = of_find_property(dp, "66mhz-capable", NULL); pbm->is_66mhz_capable = (prop != NULL); - pbm->pci_bus = pci_scan_one_pbm(pbm); + pbm->pci_bus = pci_scan_one_pbm(pbm, parent); /* XXX register error interrupt handlers XXX */ } @@ -583,29 +585,22 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm, return cnt; } -static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) +static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { + static const u32 vdma_default[] = { 0x80000000, 0x80000000 }; struct iommu *iommu = pbm->iommu; - struct property *prop; unsigned long num_tsb_entries, sz, tsbsize; - u32 vdma[2], dma_mask, dma_offset; - - prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); - if (prop) { - u32 *val = prop->value; - - vdma[0] = val[0]; - vdma[1] = val[1]; - } else { - /* No property, use default values. */ - vdma[0] = 0x80000000; - vdma[1] = 0x80000000; - } + u32 dma_mask, dma_offset; + const u32 *vdma; + + vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); + if (!vdma) + vdma = vdma_default; if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { - prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n", - vdma[0], vdma[1]); - prom_halt(); + printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n", + vdma[0], vdma[1]); + return -EINVAL; }; dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); @@ -625,8 +620,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { - prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); - prom_halt(); + printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n"); + return -ENOMEM; } iommu->arena.limit = num_tsb_entries; @@ -634,6 +629,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) if (sz) printk("%s: Imported %lu TSB entries from OBP\n", pbm->name, sz); + + return 0; } #ifdef CONFIG_PCI_MSI @@ -890,10 +887,12 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) } #endif /* !(CONFIG_PCI_MSI) */ -static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, - struct device_node *dp, u32 devhandle) +static int __init pci_sun4v_pbm_init(struct pci_controller_info *p, + struct of_device *op, u32 devhandle) { + struct device_node *dp = op->node; struct pci_pbm_info *pbm; + int err; if (devhandle & 0x40) pbm = &p->pbm_B; @@ -905,7 +904,6 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, pbm->numa_node = of_node_to_nid(dp); - pbm->scan_bus = pci_sun4v_scan_bus; pbm->pci_ops = &sun4v_pci_ops; pbm->config_space_reg_bits = 12; @@ -924,20 +922,31 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, pci_determine_mem_io_space(pbm); pci_get_pbm_props(pbm); - pci_sun4v_iommu_init(pbm); + + err = pci_sun4v_iommu_init(pbm); + if (err) + return err; + pci_sun4v_msi_init(pbm); + + pci_sun4v_scan_bus(pbm, &op->dev); + + return 0; } -void __init sun4v_pci_init(struct device_node *dp, char *model_name) +static int __devinit pci_sun4v_probe(struct of_device *op, + const struct of_device_id *match) { + const struct linux_prom64_registers *regs; static int hvapi_negotiated = 0; struct pci_controller_info *p; struct pci_pbm_info *pbm; + struct device_node *dp; struct iommu *iommu; - struct property *prop; - struct linux_prom64_registers *regs; u32 devhandle; - int i; + int i, err; + + dp = op->node; if (!hvapi_negotiated++) { int err = sun4v_hvapi_register(HV_GRP_PCI, @@ -945,61 +954,91 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name) &vpci_minor); if (err) { - prom_printf("SUN4V_PCI: Could not register hvapi, " - "err=%d\n", err); - prom_halt(); + printk(KERN_ERR PFX "Could not register hvapi, " + "err=%d\n", err); + return err; } - printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", + printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n", vpci_major, vpci_minor); dma_ops = &sun4v_dma_ops; } - prop = of_find_property(dp, "reg", NULL); - if (!prop) { - prom_printf("SUN4V_PCI: Could not find config registers\n"); - prom_halt(); + regs = of_get_property(dp, "reg", NULL); + err = -ENODEV; + if (!regs) { + printk(KERN_ERR PFX "Could not find config registers\n"); + goto out_err; } - regs = prop->value; - devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { if (pbm->devhandle == (devhandle ^ 0x40)) { - pci_sun4v_pbm_init(pbm->parent, dp, devhandle); - return; + return pci_sun4v_pbm_init(pbm->parent, op, devhandle); } } + err = -ENOMEM; for_each_possible_cpu(i) { unsigned long page = get_zeroed_page(GFP_ATOMIC); if (!page) - goto fatal_memory_error; + goto out_err; per_cpu(iommu_batch, i).pglist = (u64 *) page; } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); - if (!p) - goto fatal_memory_error; + if (!p) { + printk(KERN_ERR PFX "Could not allocate pci_controller_info\n"); + goto out_err; + } iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); - if (!iommu) - goto fatal_memory_error; + if (!iommu) { + printk(KERN_ERR PFX "Could not allocate pbm A iommu\n"); + goto out_free_controller; + } p->pbm_A.iommu = iommu; iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); - if (!iommu) - goto fatal_memory_error; + if (!iommu) { + printk(KERN_ERR PFX "Could not allocate pbm B iommu\n"); + goto out_free_iommu_A; + } p->pbm_B.iommu = iommu; - pci_sun4v_pbm_init(p, dp, devhandle); - return; + return pci_sun4v_pbm_init(p, op, devhandle); + +out_free_iommu_A: + kfree(p->pbm_A.iommu); + +out_free_controller: + kfree(p); -fatal_memory_error: - prom_printf("SUN4V_PCI: Fatal memory allocation error.\n"); - prom_halt(); +out_err: + return err; } + +static struct of_device_id __initdata pci_sun4v_match[] = { + { + .name = "pci", + .compatible = "SUNW,sun4v-pci", + }, + {}, +}; + +static struct of_platform_driver pci_sun4v_driver = { + .name = DRIVER_NAME, + .match_table = pci_sun4v_match, + .probe = pci_sun4v_probe, +}; + +static int __init pci_sun4v_init(void) +{ + return of_register_driver(&pci_sun4v_driver, &of_bus_type); +} + +subsys_initcall(pci_sun4v_init); |