Loading drivers/iommu/arm-smmu.c +116 −39 Original line number Diff line number Diff line Loading @@ -487,6 +487,19 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { 0, NULL}, }; struct arm_iommus_node { struct device_node *master; struct list_head list; struct list_head iommuspec_list; }; struct arm_iommus_spec { struct of_phandle_args iommu_spec; struct list_head list; }; static LIST_HEAD(iommus_nodes); static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_prepare_pgtable(void *addr, void *cookie); Loading Loading @@ -642,39 +655,40 @@ static int register_smmu_master(struct arm_smmu_device *smmu, return insert_smmu_master(smmu, master); } static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, int *num_masters) static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu) { struct of_phandle_args iommuspec; struct device_node *master; struct arm_iommus_node *node, *nex; *num_masters = 0; for_each_node_with_property(master, "iommus") { int arg_ind = 0; struct iommus_entry *entry, *n; list_for_each_entry_safe(node, nex, &iommus_nodes, list) { struct iommus_entry *entry, *next; struct arm_iommus_spec *iommuspec_node, *n; LIST_HEAD(iommus); int node_found = 0; while (!of_parse_phandle_with_args( master, "iommus", "#iommu-cells", arg_ind, &iommuspec)) { if (iommuspec.np != smmu->dev->of_node) { arg_ind++; list_for_each_entry_safe(iommuspec_node, n, &node->iommuspec_list, list) { if (iommuspec_node->iommu_spec.np != smmu->dev->of_node) continue; } /* * Since each master node will have iommu spec(s) of the * same device, we can delete this master node after * the devices are registered. */ node_found = 1; list_for_each_entry(entry, &iommus, list) if (entry->node == master) if (entry->node == node->master) break; if (&entry->list == &iommus) { entry = devm_kzalloc(smmu->dev, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->node = master; entry->node = node->master; list_add(&entry->list, &iommus); } switch (iommuspec.args_count) { switch (iommuspec_node->iommu_spec.args_count) { case 0: /* * For pci-e devices the SIDs are provided Loading @@ -684,25 +698,29 @@ static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, case 1: entry->num_sids++; entry->streamids[entry->num_sids - 1] = iommuspec.args[0]; = iommuspec_node->iommu_spec.args[0]; break; default: BUG(); } arg_ind++; list_del(&iommuspec_node->list); kfree(iommuspec_node); } list_for_each_entry_safe(entry, n, &iommus, list) { list_for_each_entry_safe(entry, next, &iommus, list) { int rc = register_smmu_master(smmu, entry); if (rc) { if (rc) dev_err(smmu->dev, "Couldn't register %s\n", entry->node->name); } else { (*num_masters)++; } list_del(&entry->list); devm_kfree(smmu->dev, entry); } if (node_found) { list_del(&node->list); kfree(node); } } return 0; Loading Loading @@ -3596,7 +3614,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; struct rb_node *node; int num_irqs, i, err, num_masters; int num_irqs, i, err; smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { Loading Loading @@ -3657,32 +3675,33 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } i = 0; smmu->masters = RB_ROOT; err = arm_smmu_parse_iommus_properties(smmu, &num_masters); if (err) goto out_put_masters; dev_dbg(dev, "registered %d master devices\n", num_masters); err = arm_smmu_parse_impl_def_registers(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_regulators(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_clocks(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_bus_scaling(pdev, smmu); if (err) goto out_put_masters; goto out; parse_driver_options(smmu); err = arm_smmu_enable_clocks(smmu); if (err) goto out; /* No probe deferral occurred! Proceed with iommu property parsing. */ smmu->masters = RB_ROOT; err = arm_smmu_parse_iommus_properties(smmu); if (err) goto out_put_masters; Loading Loading @@ -3739,7 +3758,7 @@ out_put_masters: = container_of(node, struct arm_smmu_master, node); of_node_put(master->of_node); } out: return err; } Loading Loading @@ -3790,6 +3809,58 @@ static int arm_smmu_device_remove(struct platform_device *pdev) return 0; } static void arm_smmu_free_master_nodes(void) { struct arm_iommus_node *node, *nex; struct arm_iommus_spec *entry, *n; list_for_each_entry_safe(node, nex, &iommus_nodes, list) { list_for_each_entry_safe(entry, n, &node->iommuspec_list, list) { list_del(&entry->list); kfree(entry); } list_del(&node->list); kfree(node); } } static int arm_smmu_get_master_nodes(void) { struct arm_iommus_node *node; struct device_node *master; struct of_phandle_args iommuspec; struct arm_iommus_spec *entry; for_each_node_with_property(master, "iommus") { int arg_ind = 0; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) goto release_memory; node->master = master; list_add(&node->list, &iommus_nodes); INIT_LIST_HEAD(&node->iommuspec_list); while (!of_parse_phandle_with_args(master, "iommus", "#iommu-cells", arg_ind, &iommuspec)) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto release_memory; entry->iommu_spec = iommuspec; list_add(&entry->list, &node->iommuspec_list); arg_ind++; } } return 0; release_memory: arm_smmu_free_master_nodes(); return -ENOMEM; } static struct platform_driver arm_smmu_driver = { .driver = { .owner = THIS_MODULE, Loading @@ -3816,10 +3887,16 @@ static int __init arm_smmu_init(void) of_node_put(np); ret = platform_driver_register(&arm_smmu_driver); ret = arm_smmu_get_master_nodes(); if (ret) return ret; ret = platform_driver_register(&arm_smmu_driver); if (ret) { arm_smmu_free_master_nodes(); return ret; } /* Oh, for a proper bus abstraction */ if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &arm_smmu_ops); Loading Loading
drivers/iommu/arm-smmu.c +116 −39 Original line number Diff line number Diff line Loading @@ -487,6 +487,19 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { 0, NULL}, }; struct arm_iommus_node { struct device_node *master; struct list_head list; struct list_head iommuspec_list; }; struct arm_iommus_spec { struct of_phandle_args iommu_spec; struct list_head list; }; static LIST_HEAD(iommus_nodes); static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_prepare_pgtable(void *addr, void *cookie); Loading Loading @@ -642,39 +655,40 @@ static int register_smmu_master(struct arm_smmu_device *smmu, return insert_smmu_master(smmu, master); } static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, int *num_masters) static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu) { struct of_phandle_args iommuspec; struct device_node *master; struct arm_iommus_node *node, *nex; *num_masters = 0; for_each_node_with_property(master, "iommus") { int arg_ind = 0; struct iommus_entry *entry, *n; list_for_each_entry_safe(node, nex, &iommus_nodes, list) { struct iommus_entry *entry, *next; struct arm_iommus_spec *iommuspec_node, *n; LIST_HEAD(iommus); int node_found = 0; while (!of_parse_phandle_with_args( master, "iommus", "#iommu-cells", arg_ind, &iommuspec)) { if (iommuspec.np != smmu->dev->of_node) { arg_ind++; list_for_each_entry_safe(iommuspec_node, n, &node->iommuspec_list, list) { if (iommuspec_node->iommu_spec.np != smmu->dev->of_node) continue; } /* * Since each master node will have iommu spec(s) of the * same device, we can delete this master node after * the devices are registered. */ node_found = 1; list_for_each_entry(entry, &iommus, list) if (entry->node == master) if (entry->node == node->master) break; if (&entry->list == &iommus) { entry = devm_kzalloc(smmu->dev, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->node = master; entry->node = node->master; list_add(&entry->list, &iommus); } switch (iommuspec.args_count) { switch (iommuspec_node->iommu_spec.args_count) { case 0: /* * For pci-e devices the SIDs are provided Loading @@ -684,25 +698,29 @@ static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu, case 1: entry->num_sids++; entry->streamids[entry->num_sids - 1] = iommuspec.args[0]; = iommuspec_node->iommu_spec.args[0]; break; default: BUG(); } arg_ind++; list_del(&iommuspec_node->list); kfree(iommuspec_node); } list_for_each_entry_safe(entry, n, &iommus, list) { list_for_each_entry_safe(entry, next, &iommus, list) { int rc = register_smmu_master(smmu, entry); if (rc) { if (rc) dev_err(smmu->dev, "Couldn't register %s\n", entry->node->name); } else { (*num_masters)++; } list_del(&entry->list); devm_kfree(smmu->dev, entry); } if (node_found) { list_del(&node->list); kfree(node); } } return 0; Loading Loading @@ -3596,7 +3614,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; struct rb_node *node; int num_irqs, i, err, num_masters; int num_irqs, i, err; smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { Loading Loading @@ -3657,32 +3675,33 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } i = 0; smmu->masters = RB_ROOT; err = arm_smmu_parse_iommus_properties(smmu, &num_masters); if (err) goto out_put_masters; dev_dbg(dev, "registered %d master devices\n", num_masters); err = arm_smmu_parse_impl_def_registers(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_regulators(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_clocks(smmu); if (err) goto out_put_masters; goto out; err = arm_smmu_init_bus_scaling(pdev, smmu); if (err) goto out_put_masters; goto out; parse_driver_options(smmu); err = arm_smmu_enable_clocks(smmu); if (err) goto out; /* No probe deferral occurred! Proceed with iommu property parsing. */ smmu->masters = RB_ROOT; err = arm_smmu_parse_iommus_properties(smmu); if (err) goto out_put_masters; Loading Loading @@ -3739,7 +3758,7 @@ out_put_masters: = container_of(node, struct arm_smmu_master, node); of_node_put(master->of_node); } out: return err; } Loading Loading @@ -3790,6 +3809,58 @@ static int arm_smmu_device_remove(struct platform_device *pdev) return 0; } static void arm_smmu_free_master_nodes(void) { struct arm_iommus_node *node, *nex; struct arm_iommus_spec *entry, *n; list_for_each_entry_safe(node, nex, &iommus_nodes, list) { list_for_each_entry_safe(entry, n, &node->iommuspec_list, list) { list_del(&entry->list); kfree(entry); } list_del(&node->list); kfree(node); } } static int arm_smmu_get_master_nodes(void) { struct arm_iommus_node *node; struct device_node *master; struct of_phandle_args iommuspec; struct arm_iommus_spec *entry; for_each_node_with_property(master, "iommus") { int arg_ind = 0; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) goto release_memory; node->master = master; list_add(&node->list, &iommus_nodes); INIT_LIST_HEAD(&node->iommuspec_list); while (!of_parse_phandle_with_args(master, "iommus", "#iommu-cells", arg_ind, &iommuspec)) { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto release_memory; entry->iommu_spec = iommuspec; list_add(&entry->list, &node->iommuspec_list); arg_ind++; } } return 0; release_memory: arm_smmu_free_master_nodes(); return -ENOMEM; } static struct platform_driver arm_smmu_driver = { .driver = { .owner = THIS_MODULE, Loading @@ -3816,10 +3887,16 @@ static int __init arm_smmu_init(void) of_node_put(np); ret = platform_driver_register(&arm_smmu_driver); ret = arm_smmu_get_master_nodes(); if (ret) return ret; ret = platform_driver_register(&arm_smmu_driver); if (ret) { arm_smmu_free_master_nodes(); return ret; } /* Oh, for a proper bus abstraction */ if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &arm_smmu_ops); Loading