static int omap_iommu_probe()

in omap-iommu.c [1161:1258]


static int omap_iommu_probe(struct platform_device *pdev)
{
	int err = -ENODEV;
	int irq;
	struct omap_iommu *obj;
	struct resource *res;
	struct device_node *of = pdev->dev.of_node;

	if (!of) {
		pr_err("%s: only DT-based devices are supported\n", __func__);
		return -ENODEV;
	}

	obj = devm_kzalloc(&pdev->dev, sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
	if (!obj)
		return -ENOMEM;

	/*
	 * self-manage the ordering dependencies between omap_device_enable/idle
	 * and omap_device_assert/deassert_hardreset API
	 */
	if (pdev->dev.pm_domain) {
		dev_dbg(&pdev->dev, "device pm_domain is being reset\n");
		pdev->dev.pm_domain = NULL;
	}

	obj->name = dev_name(&pdev->dev);
	obj->nr_tlb_entries = 32;
	err = of_property_read_u32(of, "ti,#tlb-entries", &obj->nr_tlb_entries);
	if (err && err != -EINVAL)
		return err;
	if (obj->nr_tlb_entries != 32 && obj->nr_tlb_entries != 8)
		return -EINVAL;
	if (of_find_property(of, "ti,iommu-bus-err-back", NULL))
		obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN;

	obj->dev = &pdev->dev;
	obj->ctx = (void *)obj + sizeof(*obj);
	obj->cr_ctx = devm_kzalloc(&pdev->dev,
				   sizeof(*obj->cr_ctx) * obj->nr_tlb_entries,
				   GFP_KERNEL);
	if (!obj->cr_ctx)
		return -ENOMEM;

	spin_lock_init(&obj->iommu_lock);
	spin_lock_init(&obj->page_table_lock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	obj->regbase = devm_ioremap_resource(obj->dev, res);
	if (IS_ERR(obj->regbase))
		return PTR_ERR(obj->regbase);

	err = omap_iommu_dra7_get_dsp_system_cfg(pdev, obj);
	if (err)
		return err;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return -ENODEV;

	err = devm_request_irq(obj->dev, irq, iommu_fault_handler, IRQF_SHARED,
			       dev_name(obj->dev), obj);
	if (err < 0)
		return err;
	platform_set_drvdata(pdev, obj);

	if (omap_iommu_can_register(pdev)) {
		obj->group = iommu_group_alloc();
		if (IS_ERR(obj->group))
			return PTR_ERR(obj->group);

		err = iommu_device_sysfs_add(&obj->iommu, obj->dev, NULL,
					     obj->name);
		if (err)
			goto out_group;

		err = iommu_device_register(&obj->iommu, &omap_iommu_ops, &pdev->dev);
		if (err)
			goto out_sysfs;
	}

	pm_runtime_enable(obj->dev);

	omap_iommu_debugfs_add(obj);

	dev_info(&pdev->dev, "%s registered\n", obj->name);

	/* Re-probe bus to probe device attached to this IOMMU */
	bus_iommu_probe(&platform_bus_type);

	return 0;

out_sysfs:
	iommu_device_sysfs_remove(&obj->iommu);
out_group:
	iommu_group_put(obj->group);
	return err;
}