aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2014-07-23 19:36:43 -0400
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2015-01-16 11:03:05 -0500
commita166d31ee56e8fc56ce2497d8de9da5359f4ee41 (patch)
treeabe53fe4b25e43ccdf4026f1042e71c848e68dda
parent275f5053c7786285d2f20d2dd12908f834c47ad8 (diff)
iommu/ipmmu-vmsa: Support multiple micro TLBs per device
Devices such as the system DMA controller are connected to multiple micro TLBs of the same IOMMU. Support this. Selective enabling of micro TLBs based on runtime device usage isn't possible at the moment due to lack of support in the IOMMU and DMA mapping APIs. Support for devices connected to different IOMMUs is also unsupported for the same reason. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
-rw-r--r--drivers/iommu/ipmmu-vmsa.c115
1 files changed, 86 insertions, 29 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 368c852d9ee7..5d080cf11ba5 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -47,7 +47,8 @@ struct ipmmu_vmsa_domain {
47 47
48struct ipmmu_vmsa_archdata { 48struct ipmmu_vmsa_archdata {
49 struct ipmmu_vmsa_device *mmu; 49 struct ipmmu_vmsa_device *mmu;
50 unsigned int utlb; 50 unsigned int *utlbs;
51 unsigned int num_utlbs;
51}; 52};
52 53
53static DEFINE_SPINLOCK(ipmmu_devices_lock); 54static DEFINE_SPINLOCK(ipmmu_devices_lock);
@@ -900,6 +901,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
900 struct ipmmu_vmsa_device *mmu = archdata->mmu; 901 struct ipmmu_vmsa_device *mmu = archdata->mmu;
901 struct ipmmu_vmsa_domain *domain = io_domain->priv; 902 struct ipmmu_vmsa_domain *domain = io_domain->priv;
902 unsigned long flags; 903 unsigned long flags;
904 unsigned int i;
903 int ret = 0; 905 int ret = 0;
904 906
905 if (!mmu) { 907 if (!mmu) {
@@ -928,7 +930,8 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
928 if (ret < 0) 930 if (ret < 0)
929 return ret; 931 return ret;
930 932
931 ipmmu_utlb_enable(domain, archdata->utlb); 933 for (i = 0; i < archdata->num_utlbs; ++i)
934 ipmmu_utlb_enable(domain, archdata->utlbs[i]);
932 935
933 return 0; 936 return 0;
934} 937}
@@ -938,8 +941,10 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain,
938{ 941{
939 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; 942 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
940 struct ipmmu_vmsa_domain *domain = io_domain->priv; 943 struct ipmmu_vmsa_domain *domain = io_domain->priv;
944 unsigned int i;
941 945
942 ipmmu_utlb_disable(domain, archdata->utlb); 946 for (i = 0; i < archdata->num_utlbs; ++i)
947 ipmmu_utlb_disable(domain, archdata->utlbs[i]);
943 948
944 /* 949 /*
945 * TODO: Optimize by disabling the context when no device is attached. 950 * TODO: Optimize by disabling the context when no device is attached.
@@ -1003,10 +1008,12 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
1003 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); 1008 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK);
1004} 1009}
1005 1010
1006static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) 1011static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev,
1012 unsigned int **_utlbs)
1007{ 1013{
1008 struct of_phandle_args args; 1014 unsigned int *utlbs;
1009 int ret; 1015 unsigned int i;
1016 int count;
1010 1017
1011 if (mmu->pdata) { 1018 if (mmu->pdata) {
1012 const struct ipmmu_vmsa_master *master = mmu->pdata->masters; 1019 const struct ipmmu_vmsa_master *master = mmu->pdata->masters;
@@ -1014,32 +1021,64 @@ static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev)
1014 unsigned int i; 1021 unsigned int i;
1015 1022
1016 for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { 1023 for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) {
1017 if (strcmp(master->name, devname) == 0) 1024 if (strcmp(master->name, devname) == 0) {
1018 return master->utlb; 1025 utlbs = kmalloc(sizeof(*utlbs), GFP_KERNEL);
1026 if (!utlbs)
1027 return -ENOMEM;
1028
1029 utlbs[0] = master->utlb;
1030
1031 *_utlbs = utlbs;
1032 return 1;
1033 }
1019 } 1034 }
1020 1035
1021 return -1; 1036 return -EINVAL;
1022 } 1037 }
1023 1038
1024 ret = of_parse_phandle_with_args(dev->of_node, "iommus", 1039 count = of_count_phandle_with_args(dev->of_node, "iommus",
1025 "#iommu-cells", 0, &args); 1040 "#iommu-cells");
1026 if (ret < 0) 1041 if (count < 0)
1027 return -1; 1042 return -EINVAL;
1043
1044 utlbs = kcalloc(count, sizeof(*utlbs), GFP_KERNEL);
1045 if (!utlbs)
1046 return -ENOMEM;
1047
1048 for (i = 0; i < count; ++i) {
1049 struct of_phandle_args args;
1050 int ret;
1051
1052 ret = of_parse_phandle_with_args(dev->of_node, "iommus",
1053 "#iommu-cells", i, &args);
1054 if (ret < 0)
1055 goto error;
1056
1057 of_node_put(args.np);
1058
1059 if (args.np != mmu->dev->of_node || args.args_count != 1)
1060 goto error;
1061
1062 utlbs[i] = args.args[0];
1063 }
1028 1064
1029 of_node_put(args.np); 1065 *_utlbs = utlbs;
1030 1066
1031 if (args.np != mmu->dev->of_node || args.args_count != 1) 1067 return count;
1032 return -1;
1033 1068
1034 return args.args[0]; 1069error:
1070 kfree(utlbs);
1071 return -EINVAL;
1035} 1072}
1036 1073
1037static int ipmmu_add_device(struct device *dev) 1074static int ipmmu_add_device(struct device *dev)
1038{ 1075{
1039 struct ipmmu_vmsa_archdata *archdata; 1076 struct ipmmu_vmsa_archdata *archdata;
1040 struct ipmmu_vmsa_device *mmu; 1077 struct ipmmu_vmsa_device *mmu;
1041 struct iommu_group *group; 1078 struct iommu_group *group = NULL;
1042 int utlb = -1; 1079 unsigned int *utlbs = NULL;
1080 unsigned int i;
1081 int num_utlbs = 0;
1043 int ret; 1082 int ret;
1044 1083
1045 if (dev->archdata.iommu) { 1084 if (dev->archdata.iommu) {
@@ -1052,8 +1091,8 @@ static int ipmmu_add_device(struct device *dev)
1052 spin_lock(&ipmmu_devices_lock); 1091 spin_lock(&ipmmu_devices_lock);
1053 1092
1054 list_for_each_entry(mmu, &ipmmu_devices, list) { 1093 list_for_each_entry(mmu, &ipmmu_devices, list) {
1055 utlb = ipmmu_find_utlb(mmu, dev); 1094 num_utlbs = ipmmu_find_utlbs(mmu, dev, &utlbs);
1056 if (utlb >= 0) { 1095 if (num_utlbs) {
1057 /* 1096 /*
1058 * TODO Take a reference to the MMU to protect 1097 * TODO Take a reference to the MMU to protect
1059 * against device removal. 1098 * against device removal.
@@ -1064,17 +1103,22 @@ static int ipmmu_add_device(struct device *dev)
1064 1103
1065 spin_unlock(&ipmmu_devices_lock); 1104 spin_unlock(&ipmmu_devices_lock);
1066 1105
1067 if (utlb < 0) 1106 if (num_utlbs <= 0)
1068 return -ENODEV; 1107 return -ENODEV;
1069 1108
1070 if (utlb >= mmu->num_utlbs) 1109 for (i = 0; i < num_utlbs; ++i) {
1071 return -EINVAL; 1110 if (utlbs[i] >= mmu->num_utlbs) {
1111 ret = -EINVAL;
1112 goto error;
1113 }
1114 }
1072 1115
1073 /* Create a device group and add the device to it. */ 1116 /* Create a device group and add the device to it. */
1074 group = iommu_group_alloc(); 1117 group = iommu_group_alloc();
1075 if (IS_ERR(group)) { 1118 if (IS_ERR(group)) {
1076 dev_err(dev, "Failed to allocate IOMMU group\n"); 1119 dev_err(dev, "Failed to allocate IOMMU group\n");
1077 return PTR_ERR(group); 1120 ret = PTR_ERR(group);
1121 goto error;
1078 } 1122 }
1079 1123
1080 ret = iommu_group_add_device(group, dev); 1124 ret = iommu_group_add_device(group, dev);
@@ -1082,7 +1126,8 @@ static int ipmmu_add_device(struct device *dev)
1082 1126
1083 if (ret < 0) { 1127 if (ret < 0) {
1084 dev_err(dev, "Failed to add device to IPMMU group\n"); 1128 dev_err(dev, "Failed to add device to IPMMU group\n");
1085 return ret; 1129 group = NULL;
1130 goto error;
1086 } 1131 }
1087 1132
1088 archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); 1133 archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
@@ -1092,7 +1137,8 @@ static int ipmmu_add_device(struct device *dev)
1092 } 1137 }
1093 1138
1094 archdata->mmu = mmu; 1139 archdata->mmu = mmu;
1095 archdata->utlb = utlb; 1140 archdata->utlbs = utlbs;
1141 archdata->num_utlbs = num_utlbs;
1096 dev->archdata.iommu = archdata; 1142 dev->archdata.iommu = archdata;
1097 1143
1098 /* 1144 /*
@@ -1129,17 +1175,28 @@ static int ipmmu_add_device(struct device *dev)
1129 1175
1130error: 1176error:
1131 arm_iommu_release_mapping(mmu->mapping); 1177 arm_iommu_release_mapping(mmu->mapping);
1178
1132 kfree(dev->archdata.iommu); 1179 kfree(dev->archdata.iommu);
1180 kfree(utlbs);
1181
1133 dev->archdata.iommu = NULL; 1182 dev->archdata.iommu = NULL;
1134 iommu_group_remove_device(dev); 1183
1184 if (!IS_ERR_OR_NULL(group))
1185 iommu_group_remove_device(dev);
1186
1135 return ret; 1187 return ret;
1136} 1188}
1137 1189
1138static void ipmmu_remove_device(struct device *dev) 1190static void ipmmu_remove_device(struct device *dev)
1139{ 1191{
1192 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
1193
1140 arm_iommu_detach_device(dev); 1194 arm_iommu_detach_device(dev);
1141 iommu_group_remove_device(dev); 1195 iommu_group_remove_device(dev);
1142 kfree(dev->archdata.iommu); 1196
1197 kfree(archdata->utlbs);
1198 kfree(archdata);
1199
1143 dev->archdata.iommu = NULL; 1200 dev->archdata.iommu = NULL;
1144} 1201}
1145 1202