in kernel/pci_sun4v.c [1220:1326]
static int pci_sun4v_probe(struct platform_device *op)
{
const struct linux_prom64_registers *regs;
static int hvapi_negotiated = 0;
struct pci_pbm_info *pbm;
struct device_node *dp;
struct iommu *iommu;
struct atu *atu;
u32 devhandle;
int i, err = -ENODEV;
static bool hv_atu = true;
dp = op->dev.of_node;
if (!hvapi_negotiated++) {
for (i = 0; i < ARRAY_SIZE(vpci_versions); i++) {
vpci_major = vpci_versions[i].major;
vpci_minor = vpci_versions[i].minor;
err = sun4v_hvapi_register(HV_GRP_PCI, vpci_major,
&vpci_minor);
if (!err)
break;
}
if (err) {
pr_err(PFX "Could not register hvapi, err=%d\n", err);
return err;
}
pr_info(PFX "Registered hvapi major[%lu] minor[%lu]\n",
vpci_major, vpci_minor);
err = sun4v_hvapi_register(HV_GRP_ATU, vatu_major, &vatu_minor);
if (err) {
/* don't return an error if we fail to register the
* ATU group, but ATU hcalls won't be available.
*/
hv_atu = false;
} else {
pr_info(PFX "Registered hvapi ATU major[%lu] minor[%lu]\n",
vatu_major, vatu_minor);
}
dma_ops = &sun4v_dma_ops;
}
regs = of_get_property(dp, "reg", NULL);
err = -ENODEV;
if (!regs) {
printk(KERN_ERR PFX "Could not find config registers\n");
goto out_err;
}
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
err = -ENOMEM;
if (!iommu_batch_initialized) {
for_each_possible_cpu(i) {
unsigned long page = get_zeroed_page(GFP_KERNEL);
if (!page)
goto out_err;
per_cpu(iommu_batch, i).pglist = (u64 *) page;
}
iommu_batch_initialized = 1;
}
pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
if (!pbm) {
printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
goto out_err;
}
iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
if (!iommu) {
printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
goto out_free_controller;
}
pbm->iommu = iommu;
iommu->atu = NULL;
if (hv_atu) {
atu = kzalloc(sizeof(*atu), GFP_KERNEL);
if (!atu)
pr_err(PFX "Could not allocate atu\n");
else
iommu->atu = atu;
}
err = pci_sun4v_pbm_init(pbm, op, devhandle);
if (err)
goto out_free_iommu;
dev_set_drvdata(&op->dev, pbm);
return 0;
out_free_iommu:
kfree(iommu->atu);
kfree(pbm->iommu);
out_free_controller:
kfree(pbm);
out_err:
return err;
}