aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/ipmmu-vmsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/ipmmu-vmsa.c')
-rw-r--r--drivers/iommu/ipmmu-vmsa.c91
1 files changed, 64 insertions, 27 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index b98a03189580..7a4529c61c19 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -1,6 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2/* 2/*
3 * IPMMU VMSA 3 * IOMMU API for Renesas VMSA-compatible IPMMU
4 * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
4 * 5 *
5 * Copyright (C) 2014 Renesas Electronics Corporation 6 * Copyright (C) 2014 Renesas Electronics Corporation
6 */ 7 */
@@ -11,10 +12,10 @@
11#include <linux/dma-mapping.h> 12#include <linux/dma-mapping.h>
12#include <linux/err.h> 13#include <linux/err.h>
13#include <linux/export.h> 14#include <linux/export.h>
15#include <linux/init.h>
14#include <linux/interrupt.h> 16#include <linux/interrupt.h>
15#include <linux/io.h> 17#include <linux/io.h>
16#include <linux/iommu.h> 18#include <linux/iommu.h>
17#include <linux/module.h>
18#include <linux/of.h> 19#include <linux/of.h>
19#include <linux/of_device.h> 20#include <linux/of_device.h>
20#include <linux/of_iommu.h> 21#include <linux/of_iommu.h>
@@ -81,7 +82,9 @@ static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom)
81 82
82static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) 83static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
83{ 84{
84 return dev->iommu_fwspec ? dev->iommu_fwspec->iommu_priv : NULL; 85 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
86
87 return fwspec ? fwspec->iommu_priv : NULL;
85} 88}
86 89
87#define TLB_LOOP_TIMEOUT 100 /* 100us */ 90#define TLB_LOOP_TIMEOUT 100 /* 100us */
@@ -498,6 +501,9 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
498 501
499static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain) 502static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
500{ 503{
504 if (!domain->mmu)
505 return;
506
501 /* 507 /*
502 * Disable the context. Flush the TLB as required when modifying the 508 * Disable the context. Flush the TLB as required when modifying the
503 * context registers. 509 * context registers.
@@ -640,7 +646,7 @@ static void ipmmu_domain_free(struct iommu_domain *io_domain)
640static int ipmmu_attach_device(struct iommu_domain *io_domain, 646static int ipmmu_attach_device(struct iommu_domain *io_domain,
641 struct device *dev) 647 struct device *dev)
642{ 648{
643 struct iommu_fwspec *fwspec = dev->iommu_fwspec; 649 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
644 struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); 650 struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
645 struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); 651 struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
646 unsigned int i; 652 unsigned int i;
@@ -689,7 +695,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
689static void ipmmu_detach_device(struct iommu_domain *io_domain, 695static void ipmmu_detach_device(struct iommu_domain *io_domain,
690 struct device *dev) 696 struct device *dev)
691{ 697{
692 struct iommu_fwspec *fwspec = dev->iommu_fwspec; 698 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
693 struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); 699 struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
694 unsigned int i; 700 unsigned int i;
695 701
@@ -741,36 +747,71 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
741static int ipmmu_init_platform_device(struct device *dev, 747static int ipmmu_init_platform_device(struct device *dev,
742 struct of_phandle_args *args) 748 struct of_phandle_args *args)
743{ 749{
750 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
744 struct platform_device *ipmmu_pdev; 751 struct platform_device *ipmmu_pdev;
745 752
746 ipmmu_pdev = of_find_device_by_node(args->np); 753 ipmmu_pdev = of_find_device_by_node(args->np);
747 if (!ipmmu_pdev) 754 if (!ipmmu_pdev)
748 return -ENODEV; 755 return -ENODEV;
749 756
750 dev->iommu_fwspec->iommu_priv = platform_get_drvdata(ipmmu_pdev); 757 fwspec->iommu_priv = platform_get_drvdata(ipmmu_pdev);
751 return 0;
752}
753 758
754static bool ipmmu_slave_whitelist(struct device *dev) 759 return 0;
755{
756 /* By default, do not allow use of IPMMU */
757 return false;
758} 760}
759 761
760static const struct soc_device_attribute soc_rcar_gen3[] = { 762static const struct soc_device_attribute soc_rcar_gen3[] = {
763 { .soc_id = "r8a774a1", },
764 { .soc_id = "r8a774c0", },
761 { .soc_id = "r8a7795", }, 765 { .soc_id = "r8a7795", },
762 { .soc_id = "r8a7796", }, 766 { .soc_id = "r8a7796", },
763 { .soc_id = "r8a77965", }, 767 { .soc_id = "r8a77965", },
764 { .soc_id = "r8a77970", }, 768 { .soc_id = "r8a77970", },
769 { .soc_id = "r8a77990", },
770 { .soc_id = "r8a77995", },
771 { /* sentinel */ }
772};
773
774static const struct soc_device_attribute soc_rcar_gen3_whitelist[] = {
775 { .soc_id = "r8a774c0", },
776 { .soc_id = "r8a7795", .revision = "ES3.*" },
777 { .soc_id = "r8a77965", },
778 { .soc_id = "r8a77990", },
765 { .soc_id = "r8a77995", }, 779 { .soc_id = "r8a77995", },
766 { /* sentinel */ } 780 { /* sentinel */ }
767}; 781};
768 782
783static const char * const rcar_gen3_slave_whitelist[] = {
784};
785
786static bool ipmmu_slave_whitelist(struct device *dev)
787{
788 unsigned int i;
789
790 /*
791 * For R-Car Gen3 use a white list to opt-in slave devices.
792 * For Other SoCs, this returns true anyway.
793 */
794 if (!soc_device_match(soc_rcar_gen3))
795 return true;
796
797 /* Check whether this R-Car Gen3 can use the IPMMU correctly or not */
798 if (!soc_device_match(soc_rcar_gen3_whitelist))
799 return false;
800
801 /* Check whether this slave device can work with the IPMMU */
802 for (i = 0; i < ARRAY_SIZE(rcar_gen3_slave_whitelist); i++) {
803 if (!strcmp(dev_name(dev), rcar_gen3_slave_whitelist[i]))
804 return true;
805 }
806
807 /* Otherwise, do not allow use of IPMMU */
808 return false;
809}
810
769static int ipmmu_of_xlate(struct device *dev, 811static int ipmmu_of_xlate(struct device *dev,
770 struct of_phandle_args *spec) 812 struct of_phandle_args *spec)
771{ 813{
772 /* For R-Car Gen3 use a white list to opt-in slave devices */ 814 if (!ipmmu_slave_whitelist(dev))
773 if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev))
774 return -ENODEV; 815 return -ENODEV;
775 816
776 iommu_fwspec_add_ids(dev, spec->args, 1); 817 iommu_fwspec_add_ids(dev, spec->args, 1);
@@ -938,6 +979,12 @@ static const struct of_device_id ipmmu_of_ids[] = {
938 .compatible = "renesas,ipmmu-vmsa", 979 .compatible = "renesas,ipmmu-vmsa",
939 .data = &ipmmu_features_default, 980 .data = &ipmmu_features_default,
940 }, { 981 }, {
982 .compatible = "renesas,ipmmu-r8a774a1",
983 .data = &ipmmu_features_rcar_gen3,
984 }, {
985 .compatible = "renesas,ipmmu-r8a774c0",
986 .data = &ipmmu_features_rcar_gen3,
987 }, {
941 .compatible = "renesas,ipmmu-r8a7795", 988 .compatible = "renesas,ipmmu-r8a7795",
942 .data = &ipmmu_features_rcar_gen3, 989 .data = &ipmmu_features_rcar_gen3,
943 }, { 990 }, {
@@ -950,6 +997,9 @@ static const struct of_device_id ipmmu_of_ids[] = {
950 .compatible = "renesas,ipmmu-r8a77970", 997 .compatible = "renesas,ipmmu-r8a77970",
951 .data = &ipmmu_features_rcar_gen3, 998 .data = &ipmmu_features_rcar_gen3,
952 }, { 999 }, {
1000 .compatible = "renesas,ipmmu-r8a77990",
1001 .data = &ipmmu_features_rcar_gen3,
1002 }, {
953 .compatible = "renesas,ipmmu-r8a77995", 1003 .compatible = "renesas,ipmmu-r8a77995",
954 .data = &ipmmu_features_rcar_gen3, 1004 .data = &ipmmu_features_rcar_gen3,
955 }, { 1005 }, {
@@ -957,8 +1007,6 @@ static const struct of_device_id ipmmu_of_ids[] = {
957 }, 1007 },
958}; 1008};
959 1009
960MODULE_DEVICE_TABLE(of, ipmmu_of_ids);
961
962static int ipmmu_probe(struct platform_device *pdev) 1010static int ipmmu_probe(struct platform_device *pdev)
963{ 1011{
964 struct ipmmu_vmsa_device *mmu; 1012 struct ipmmu_vmsa_device *mmu;
@@ -1129,15 +1177,4 @@ static int __init ipmmu_init(void)
1129 setup_done = true; 1177 setup_done = true;
1130 return 0; 1178 return 0;
1131} 1179}
1132
1133static void __exit ipmmu_exit(void)
1134{
1135 return platform_driver_unregister(&ipmmu_driver);
1136}
1137
1138subsys_initcall(ipmmu_init); 1180subsys_initcall(ipmmu_init);
1139module_exit(ipmmu_exit);
1140
1141MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU");
1142MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
1143MODULE_LICENSE("GPL v2");