diff options
author | Robin Murphy <robin.murphy@arm.com> | 2016-10-17 07:49:21 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-11-10 05:59:32 -0500 |
commit | 84672f192671e64e473eb535259c910860cab7a9 (patch) | |
tree | 692bc7af604d6ab5dc1e9cc72733a1cfd176afa2 | |
parent | 58f0d1d536bc71718286073aceb819eb0064e4ce (diff) |
iommu/mediatek: Convert M4Uv1 to iommu_fwspec
Our per-device data consists of the M4U instance and firmware-provided
list of LARB IDs, which is a perfect fit for the generic iommu_fwspec
machinery. Use that directly instead of the custom archdata code - while
we can't rely on the of_xlate() mechanism to initialise things until the
32-bit ARM DMA code learns about groups and default domains, it still
results in a reasonable simplification overall.
CC: Honghui Zhang <honghui.zhang@mediatek.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Tested-by: Honghui Zhang <honghui.zhang@mediatek.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/mtk_iommu.h | 6 | ||||
-rw-r--r-- | drivers/iommu/mtk_iommu_v1.c | 95 |
2 files changed, 36 insertions, 65 deletions
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index 3dab13b4a211..f59609f20270 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h | |||
@@ -34,12 +34,6 @@ struct mtk_iommu_suspend_reg { | |||
34 | u32 int_main_control; | 34 | u32 int_main_control; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct mtk_iommu_client_priv { | ||
38 | struct list_head client; | ||
39 | unsigned int mtk_m4u_id; | ||
40 | struct device *m4udev; | ||
41 | }; | ||
42 | |||
43 | struct mtk_iommu_domain; | 37 | struct mtk_iommu_domain; |
44 | 38 | ||
45 | struct mtk_iommu_data { | 39 | struct mtk_iommu_data { |
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index b8aeb0768483..884c80cb795e 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c | |||
@@ -204,14 +204,14 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) | |||
204 | static void mtk_iommu_config(struct mtk_iommu_data *data, | 204 | static void mtk_iommu_config(struct mtk_iommu_data *data, |
205 | struct device *dev, bool enable) | 205 | struct device *dev, bool enable) |
206 | { | 206 | { |
207 | struct mtk_iommu_client_priv *head, *cur, *next; | ||
208 | struct mtk_smi_larb_iommu *larb_mmu; | 207 | struct mtk_smi_larb_iommu *larb_mmu; |
209 | unsigned int larbid, portid; | 208 | unsigned int larbid, portid; |
209 | struct iommu_fwspec *fwspec = dev->iommu_fwspec; | ||
210 | int i; | ||
210 | 211 | ||
211 | head = dev->archdata.iommu; | 212 | for (i = 0; i < fwspec->num_ids; ++i) { |
212 | list_for_each_entry_safe(cur, next, &head->client, client) { | 213 | larbid = mt2701_m4u_to_larb(fwspec->ids[i]); |
213 | larbid = mt2701_m4u_to_larb(cur->mtk_m4u_id); | 214 | portid = mt2701_m4u_to_port(fwspec->ids[i]); |
214 | portid = mt2701_m4u_to_port(cur->mtk_m4u_id); | ||
215 | larb_mmu = &data->smi_imu.larb_imu[larbid]; | 215 | larb_mmu = &data->smi_imu.larb_imu[larbid]; |
216 | 216 | ||
217 | dev_dbg(dev, "%s iommu port: %d\n", | 217 | dev_dbg(dev, "%s iommu port: %d\n", |
@@ -271,14 +271,12 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, | |||
271 | struct device *dev) | 271 | struct device *dev) |
272 | { | 272 | { |
273 | struct mtk_iommu_domain *dom = to_mtk_domain(domain); | 273 | struct mtk_iommu_domain *dom = to_mtk_domain(domain); |
274 | struct mtk_iommu_client_priv *priv = dev->archdata.iommu; | 274 | struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; |
275 | struct mtk_iommu_data *data; | ||
276 | int ret; | 275 | int ret; |
277 | 276 | ||
278 | if (!priv) | 277 | if (!data) |
279 | return -ENODEV; | 278 | return -ENODEV; |
280 | 279 | ||
281 | data = dev_get_drvdata(priv->m4udev); | ||
282 | if (!data->m4u_dom) { | 280 | if (!data->m4u_dom) { |
283 | data->m4u_dom = dom; | 281 | data->m4u_dom = dom; |
284 | ret = mtk_iommu_domain_finalise(data); | 282 | ret = mtk_iommu_domain_finalise(data); |
@@ -295,13 +293,11 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, | |||
295 | static void mtk_iommu_detach_device(struct iommu_domain *domain, | 293 | static void mtk_iommu_detach_device(struct iommu_domain *domain, |
296 | struct device *dev) | 294 | struct device *dev) |
297 | { | 295 | { |
298 | struct mtk_iommu_client_priv *priv = dev->archdata.iommu; | 296 | struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; |
299 | struct mtk_iommu_data *data; | ||
300 | 297 | ||
301 | if (!priv) | 298 | if (!data) |
302 | return; | 299 | return; |
303 | 300 | ||
304 | data = dev_get_drvdata(priv->m4udev); | ||
305 | mtk_iommu_config(data, dev, false); | 301 | mtk_iommu_config(data, dev, false); |
306 | } | 302 | } |
307 | 303 | ||
@@ -366,6 +362,8 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, | |||
366 | return pa; | 362 | return pa; |
367 | } | 363 | } |
368 | 364 | ||
365 | static struct iommu_ops mtk_iommu_ops; | ||
366 | |||
369 | /* | 367 | /* |
370 | * MTK generation one iommu HW only support one iommu domain, and all the client | 368 | * MTK generation one iommu HW only support one iommu domain, and all the client |
371 | * sharing the same iova address space. | 369 | * sharing the same iova address space. |
@@ -373,7 +371,7 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, | |||
373 | static int mtk_iommu_create_mapping(struct device *dev, | 371 | static int mtk_iommu_create_mapping(struct device *dev, |
374 | struct of_phandle_args *args) | 372 | struct of_phandle_args *args) |
375 | { | 373 | { |
376 | struct mtk_iommu_client_priv *head, *priv, *next; | 374 | struct mtk_iommu_data *data; |
377 | struct platform_device *m4updev; | 375 | struct platform_device *m4updev; |
378 | struct dma_iommu_mapping *mtk_mapping; | 376 | struct dma_iommu_mapping *mtk_mapping; |
379 | struct device *m4udev; | 377 | struct device *m4udev; |
@@ -385,41 +383,37 @@ static int mtk_iommu_create_mapping(struct device *dev, | |||
385 | return -EINVAL; | 383 | return -EINVAL; |
386 | } | 384 | } |
387 | 385 | ||
388 | if (!dev->archdata.iommu) { | 386 | if (!dev->iommu_fwspec) { |
387 | ret = iommu_fwspec_init(dev, &args->np->fwnode, &mtk_iommu_ops); | ||
388 | if (ret) | ||
389 | return ret; | ||
390 | } else if (dev->iommu_fwspec->ops != &mtk_iommu_ops) { | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | if (!dev->iommu_fwspec->iommu_priv) { | ||
389 | /* Get the m4u device */ | 395 | /* Get the m4u device */ |
390 | m4updev = of_find_device_by_node(args->np); | 396 | m4updev = of_find_device_by_node(args->np); |
391 | if (WARN_ON(!m4updev)) | 397 | if (WARN_ON(!m4updev)) |
392 | return -EINVAL; | 398 | return -EINVAL; |
393 | 399 | ||
394 | head = kzalloc(sizeof(*head), GFP_KERNEL); | 400 | dev->iommu_fwspec->iommu_priv = platform_get_drvdata(m4updev); |
395 | if (!head) | ||
396 | return -ENOMEM; | ||
397 | |||
398 | dev->archdata.iommu = head; | ||
399 | INIT_LIST_HEAD(&head->client); | ||
400 | head->m4udev = &m4updev->dev; | ||
401 | } else { | ||
402 | head = dev->archdata.iommu; | ||
403 | } | 401 | } |
404 | 402 | ||
405 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 403 | ret = iommu_fwspec_add_ids(dev, args->args, 1); |
406 | if (!priv) { | 404 | if (ret) |
407 | ret = -ENOMEM; | 405 | return ret; |
408 | goto err_free_mem; | ||
409 | } | ||
410 | priv->mtk_m4u_id = args->args[0]; | ||
411 | list_add_tail(&priv->client, &head->client); | ||
412 | 406 | ||
413 | m4udev = head->m4udev; | 407 | data = dev->iommu_fwspec->iommu_priv; |
408 | m4udev = data->dev; | ||
414 | mtk_mapping = m4udev->archdata.iommu; | 409 | mtk_mapping = m4udev->archdata.iommu; |
415 | if (!mtk_mapping) { | 410 | if (!mtk_mapping) { |
416 | /* MTK iommu support 4GB iova address space. */ | 411 | /* MTK iommu support 4GB iova address space. */ |
417 | mtk_mapping = arm_iommu_create_mapping(&platform_bus_type, | 412 | mtk_mapping = arm_iommu_create_mapping(&platform_bus_type, |
418 | 0, 1ULL << 32); | 413 | 0, 1ULL << 32); |
419 | if (IS_ERR(mtk_mapping)) { | 414 | if (IS_ERR(mtk_mapping)) |
420 | ret = PTR_ERR(mtk_mapping); | 415 | return PTR_ERR(mtk_mapping); |
421 | goto err_free_mem; | 416 | |
422 | } | ||
423 | m4udev->archdata.iommu = mtk_mapping; | 417 | m4udev->archdata.iommu = mtk_mapping; |
424 | } | 418 | } |
425 | 419 | ||
@@ -432,11 +426,6 @@ static int mtk_iommu_create_mapping(struct device *dev, | |||
432 | err_release_mapping: | 426 | err_release_mapping: |
433 | arm_iommu_release_mapping(mtk_mapping); | 427 | arm_iommu_release_mapping(mtk_mapping); |
434 | m4udev->archdata.iommu = NULL; | 428 | m4udev->archdata.iommu = NULL; |
435 | err_free_mem: | ||
436 | list_for_each_entry_safe(priv, next, &head->client, client) | ||
437 | kfree(priv); | ||
438 | kfree(head); | ||
439 | dev->archdata.iommu = NULL; | ||
440 | return ret; | 429 | return ret; |
441 | } | 430 | } |
442 | 431 | ||
@@ -458,8 +447,8 @@ static int mtk_iommu_add_device(struct device *dev) | |||
458 | of_node_put(iommu_spec.np); | 447 | of_node_put(iommu_spec.np); |
459 | } | 448 | } |
460 | 449 | ||
461 | if (!dev->archdata.iommu) /* Not a iommu client device */ | 450 | if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) |
462 | return -ENODEV; | 451 | return -ENODEV; /* Not a iommu client device */ |
463 | 452 | ||
464 | group = iommu_group_get_for_dev(dev); | 453 | group = iommu_group_get_for_dev(dev); |
465 | if (IS_ERR(group)) | 454 | if (IS_ERR(group)) |
@@ -471,33 +460,21 @@ static int mtk_iommu_add_device(struct device *dev) | |||
471 | 460 | ||
472 | static void mtk_iommu_remove_device(struct device *dev) | 461 | static void mtk_iommu_remove_device(struct device *dev) |
473 | { | 462 | { |
474 | struct mtk_iommu_client_priv *head, *cur, *next; | 463 | if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) |
475 | |||
476 | head = dev->archdata.iommu; | ||
477 | if (!head) | ||
478 | return; | 464 | return; |
479 | 465 | ||
480 | list_for_each_entry_safe(cur, next, &head->client, client) { | ||
481 | list_del(&cur->client); | ||
482 | kfree(cur); | ||
483 | } | ||
484 | kfree(head); | ||
485 | dev->archdata.iommu = NULL; | ||
486 | |||
487 | iommu_group_remove_device(dev); | 466 | iommu_group_remove_device(dev); |
467 | iommu_fwspec_free(dev); | ||
488 | } | 468 | } |
489 | 469 | ||
490 | static struct iommu_group *mtk_iommu_device_group(struct device *dev) | 470 | static struct iommu_group *mtk_iommu_device_group(struct device *dev) |
491 | { | 471 | { |
492 | struct mtk_iommu_data *data; | 472 | struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; |
493 | struct mtk_iommu_client_priv *priv; | ||
494 | 473 | ||
495 | priv = dev->archdata.iommu; | 474 | if (!data) |
496 | if (!priv) | ||
497 | return ERR_PTR(-ENODEV); | 475 | return ERR_PTR(-ENODEV); |
498 | 476 | ||
499 | /* All the client devices are in the same m4u iommu-group */ | 477 | /* All the client devices are in the same m4u iommu-group */ |
500 | data = dev_get_drvdata(priv->m4udev); | ||
501 | if (!data->m4u_group) { | 478 | if (!data->m4u_group) { |
502 | data->m4u_group = iommu_group_alloc(); | 479 | data->m4u_group = iommu_group_alloc(); |
503 | if (IS_ERR(data->m4u_group)) | 480 | if (IS_ERR(data->m4u_group)) |