aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2015-01-19 08:39:45 -0500
committerJoerg Roedel <jroedel@suse.de>2015-01-19 08:39:45 -0500
commit89aa57d15f1833323b001c3764141311ac6179a2 (patch)
tree44f3066289e0a00b1f24e83d87c9750c4fbfcdec
parentec6f34e5b552fb0a52e6aae1a5afbbb1605cc6cc (diff)
parent78e1f974dd351ac82d978e3aac2d27422013f914 (diff)
Merge branch 'iommu/next' of git://linuxtv.org/pinchartl/fbdev into arm/renesas
-rw-r--r--Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt41
-rw-r--r--drivers/iommu/ipmmu-vmsa.c151
-rw-r--r--include/linux/platform_data/ipmmu-vmsa.h24
3 files changed, 154 insertions, 62 deletions
diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
new file mode 100644
index 000000000000..cd29083e16ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
@@ -0,0 +1,41 @@
1* Renesas VMSA-Compatible IOMMU
2
3The IPMMU is an IOMMU implementation compatible with the ARM VMSA page tables.
4It provides address translation for bus masters outside of the CPU, each
5connected to the IPMMU through a port called micro-TLB.
6
7
8Required Properties:
9
10 - compatible: Must contain "renesas,ipmmu-vmsa".
11 - reg: Base address and size of the IPMMU registers.
12 - interrupts: Specifiers for the MMU fault interrupts. For instances that
13 support secure mode two interrupts must be specified, for non-secure and
14 secure mode, in that order. For instances that don't support secure mode a
15 single interrupt must be specified.
16
17 - #iommu-cells: Must be 1.
18
19Each bus master connected to an IPMMU must reference the IPMMU in its device
20node with the following property:
21
22 - iommus: A reference to the IPMMU in two cells. The first cell is a phandle
23 to the IPMMU and the second cell the number of the micro-TLB that the
24 device is connected to.
25
26
27Example: R8A7791 IPMMU-MX and VSP1-D0 bus master
28
29 ipmmu_mx: mmu@fe951000 {
30 compatible = "renasas,ipmmu-vmsa";
31 reg = <0 0xfe951000 0 0x1000>;
32 interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
33 <0 221 IRQ_TYPE_LEVEL_HIGH>;
34 #iommu-cells = <1>;
35 };
36
37 vsp1@fe928000 {
38 ...
39 iommus = <&ipmmu_mx 13>;
40 ...
41 };
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 748693192c20..791c3daec7c0 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -16,7 +16,7 @@
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/iommu.h> 17#include <linux/iommu.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/platform_data/ipmmu-vmsa.h> 19#include <linux/of.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/sizes.h> 21#include <linux/sizes.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
@@ -29,7 +29,6 @@ struct ipmmu_vmsa_device {
29 void __iomem *base; 29 void __iomem *base;
30 struct list_head list; 30 struct list_head list;
31 31
32 const struct ipmmu_vmsa_platform_data *pdata;
33 unsigned int num_utlbs; 32 unsigned int num_utlbs;
34 33
35 struct dma_iommu_mapping *mapping; 34 struct dma_iommu_mapping *mapping;
@@ -46,7 +45,8 @@ struct ipmmu_vmsa_domain {
46 45
47struct ipmmu_vmsa_archdata { 46struct ipmmu_vmsa_archdata {
48 struct ipmmu_vmsa_device *mmu; 47 struct ipmmu_vmsa_device *mmu;
49 unsigned int utlb; 48 unsigned int *utlbs;
49 unsigned int num_utlbs;
50}; 50};
51 51
52static DEFINE_SPINLOCK(ipmmu_devices_lock); 52static DEFINE_SPINLOCK(ipmmu_devices_lock);
@@ -58,6 +58,8 @@ static LIST_HEAD(ipmmu_devices);
58 * Registers Definition 58 * Registers Definition
59 */ 59 */
60 60
61#define IM_NS_ALIAS_OFFSET 0x800
62
61#define IM_CTX_SIZE 0x40 63#define IM_CTX_SIZE 0x40
62 64
63#define IMCTR 0x0000 65#define IMCTR 0x0000
@@ -678,30 +680,33 @@ done:
678 680
679static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud) 681static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud)
680{ 682{
681 /* Free the page table. */
682 pgtable_t table = pud_pgtable(*pud); 683 pgtable_t table = pud_pgtable(*pud);
683 __free_page(table);
684 684
685 /* Clear the PUD. */ 685 /* Clear the PUD. */
686 *pud = __pud(0); 686 *pud = __pud(0);
687 ipmmu_flush_pgtable(mmu, pud, sizeof(*pud)); 687 ipmmu_flush_pgtable(mmu, pud, sizeof(*pud));
688
689 /* Free the page table. */
690 __free_page(table);
688} 691}
689 692
690static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud, 693static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud,
691 pmd_t *pmd) 694 pmd_t *pmd)
692{ 695{
696 pmd_t pmdval = *pmd;
693 unsigned int i; 697 unsigned int i;
694 698
695 /* Free the page table. */
696 if (pmd_table(*pmd)) {
697 pgtable_t table = pmd_pgtable(*pmd);
698 __free_page(table);
699 }
700
701 /* Clear the PMD. */ 699 /* Clear the PMD. */
702 *pmd = __pmd(0); 700 *pmd = __pmd(0);
703 ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); 701 ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
704 702
703 /* Free the page table. */
704 if (pmd_table(pmdval)) {
705 pgtable_t table = pmd_pgtable(pmdval);
706
707 __free_page(table);
708 }
709
705 /* Check whether the PUD is still needed. */ 710 /* Check whether the PUD is still needed. */
706 pmd = pmd_offset(pud, 0); 711 pmd = pmd_offset(pud, 0);
707 for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) { 712 for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) {
@@ -782,7 +787,6 @@ static int ipmmu_clear_mapping(struct ipmmu_vmsa_domain *domain,
782 pud_t *pud; 787 pud_t *pud;
783 pmd_t *pmd; 788 pmd_t *pmd;
784 pte_t *pte; 789 pte_t *pte;
785 int ret = 0;
786 790
787 if (!pgd) 791 if (!pgd)
788 return -EINVAL; 792 return -EINVAL;
@@ -844,8 +848,7 @@ static int ipmmu_clear_mapping(struct ipmmu_vmsa_domain *domain,
844done: 848done:
845 spin_unlock_irqrestore(&domain->lock, flags); 849 spin_unlock_irqrestore(&domain->lock, flags);
846 850
847 if (ret) 851 ipmmu_tlb_invalidate(domain);
848 ipmmu_tlb_invalidate(domain);
849 852
850 return 0; 853 return 0;
851} 854}
@@ -896,6 +899,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
896 struct ipmmu_vmsa_device *mmu = archdata->mmu; 899 struct ipmmu_vmsa_device *mmu = archdata->mmu;
897 struct ipmmu_vmsa_domain *domain = io_domain->priv; 900 struct ipmmu_vmsa_domain *domain = io_domain->priv;
898 unsigned long flags; 901 unsigned long flags;
902 unsigned int i;
899 int ret = 0; 903 int ret = 0;
900 904
901 if (!mmu) { 905 if (!mmu) {
@@ -924,7 +928,8 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
924 if (ret < 0) 928 if (ret < 0)
925 return ret; 929 return ret;
926 930
927 ipmmu_utlb_enable(domain, archdata->utlb); 931 for (i = 0; i < archdata->num_utlbs; ++i)
932 ipmmu_utlb_enable(domain, archdata->utlbs[i]);
928 933
929 return 0; 934 return 0;
930} 935}
@@ -934,8 +939,10 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain,
934{ 939{
935 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; 940 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
936 struct ipmmu_vmsa_domain *domain = io_domain->priv; 941 struct ipmmu_vmsa_domain *domain = io_domain->priv;
942 unsigned int i;
937 943
938 ipmmu_utlb_disable(domain, archdata->utlb); 944 for (i = 0; i < archdata->num_utlbs; ++i)
945 ipmmu_utlb_disable(domain, archdata->utlbs[i]);
939 946
940 /* 947 /*
941 * TODO: Optimize by disabling the context when no device is attached. 948 * TODO: Optimize by disabling the context when no device is attached.
@@ -999,26 +1006,56 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
999 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); 1006 return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK);
1000} 1007}
1001 1008
1002static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) 1009static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev,
1010 unsigned int **_utlbs)
1003{ 1011{
1004 const struct ipmmu_vmsa_master *master = mmu->pdata->masters; 1012 unsigned int *utlbs;
1005 const char *devname = dev_name(dev);
1006 unsigned int i; 1013 unsigned int i;
1014 int count;
1015
1016 count = of_count_phandle_with_args(dev->of_node, "iommus",
1017 "#iommu-cells");
1018 if (count < 0)
1019 return -EINVAL;
1020
1021 utlbs = kcalloc(count, sizeof(*utlbs), GFP_KERNEL);
1022 if (!utlbs)
1023 return -ENOMEM;
1024
1025 for (i = 0; i < count; ++i) {
1026 struct of_phandle_args args;
1027 int ret;
1028
1029 ret = of_parse_phandle_with_args(dev->of_node, "iommus",
1030 "#iommu-cells", i, &args);
1031 if (ret < 0)
1032 goto error;
1033
1034 of_node_put(args.np);
1035
1036 if (args.np != mmu->dev->of_node || args.args_count != 1)
1037 goto error;
1007 1038
1008 for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { 1039 utlbs[i] = args.args[0];
1009 if (strcmp(master->name, devname) == 0)
1010 return master->utlb;
1011 } 1040 }
1012 1041
1013 return -1; 1042 *_utlbs = utlbs;
1043
1044 return count;
1045
1046error:
1047 kfree(utlbs);
1048 return -EINVAL;
1014} 1049}
1015 1050
1016static int ipmmu_add_device(struct device *dev) 1051static int ipmmu_add_device(struct device *dev)
1017{ 1052{
1018 struct ipmmu_vmsa_archdata *archdata; 1053 struct ipmmu_vmsa_archdata *archdata;
1019 struct ipmmu_vmsa_device *mmu; 1054 struct ipmmu_vmsa_device *mmu;
1020 struct iommu_group *group; 1055 struct iommu_group *group = NULL;
1021 int utlb = -1; 1056 unsigned int *utlbs = NULL;
1057 unsigned int i;
1058 int num_utlbs = 0;
1022 int ret; 1059 int ret;
1023 1060
1024 if (dev->archdata.iommu) { 1061 if (dev->archdata.iommu) {
@@ -1031,8 +1068,8 @@ static int ipmmu_add_device(struct device *dev)
1031 spin_lock(&ipmmu_devices_lock); 1068 spin_lock(&ipmmu_devices_lock);
1032 1069
1033 list_for_each_entry(mmu, &ipmmu_devices, list) { 1070 list_for_each_entry(mmu, &ipmmu_devices, list) {
1034 utlb = ipmmu_find_utlb(mmu, dev); 1071 num_utlbs = ipmmu_find_utlbs(mmu, dev, &utlbs);
1035 if (utlb >= 0) { 1072 if (num_utlbs) {
1036 /* 1073 /*
1037 * TODO Take a reference to the MMU to protect 1074 * TODO Take a reference to the MMU to protect
1038 * against device removal. 1075 * against device removal.
@@ -1043,17 +1080,22 @@ static int ipmmu_add_device(struct device *dev)
1043 1080
1044 spin_unlock(&ipmmu_devices_lock); 1081 spin_unlock(&ipmmu_devices_lock);
1045 1082
1046 if (utlb < 0) 1083 if (num_utlbs <= 0)
1047 return -ENODEV; 1084 return -ENODEV;
1048 1085
1049 if (utlb >= mmu->num_utlbs) 1086 for (i = 0; i < num_utlbs; ++i) {
1050 return -EINVAL; 1087 if (utlbs[i] >= mmu->num_utlbs) {
1088 ret = -EINVAL;
1089 goto error;
1090 }
1091 }
1051 1092
1052 /* Create a device group and add the device to it. */ 1093 /* Create a device group and add the device to it. */
1053 group = iommu_group_alloc(); 1094 group = iommu_group_alloc();
1054 if (IS_ERR(group)) { 1095 if (IS_ERR(group)) {
1055 dev_err(dev, "Failed to allocate IOMMU group\n"); 1096 dev_err(dev, "Failed to allocate IOMMU group\n");
1056 return PTR_ERR(group); 1097 ret = PTR_ERR(group);
1098 goto error;
1057 } 1099 }
1058 1100
1059 ret = iommu_group_add_device(group, dev); 1101 ret = iommu_group_add_device(group, dev);
@@ -1061,7 +1103,8 @@ static int ipmmu_add_device(struct device *dev)
1061 1103
1062 if (ret < 0) { 1104 if (ret < 0) {
1063 dev_err(dev, "Failed to add device to IPMMU group\n"); 1105 dev_err(dev, "Failed to add device to IPMMU group\n");
1064 return ret; 1106 group = NULL;
1107 goto error;
1065 } 1108 }
1066 1109
1067 archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); 1110 archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
@@ -1071,7 +1114,8 @@ static int ipmmu_add_device(struct device *dev)
1071 } 1114 }
1072 1115
1073 archdata->mmu = mmu; 1116 archdata->mmu = mmu;
1074 archdata->utlb = utlb; 1117 archdata->utlbs = utlbs;
1118 archdata->num_utlbs = num_utlbs;
1075 dev->archdata.iommu = archdata; 1119 dev->archdata.iommu = archdata;
1076 1120
1077 /* 1121 /*
@@ -1090,7 +1134,8 @@ static int ipmmu_add_device(struct device *dev)
1090 SZ_1G, SZ_2G); 1134 SZ_1G, SZ_2G);
1091 if (IS_ERR(mapping)) { 1135 if (IS_ERR(mapping)) {
1092 dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n"); 1136 dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n");
1093 return PTR_ERR(mapping); 1137 ret = PTR_ERR(mapping);
1138 goto error;
1094 } 1139 }
1095 1140
1096 mmu->mapping = mapping; 1141 mmu->mapping = mapping;
@@ -1106,17 +1151,29 @@ static int ipmmu_add_device(struct device *dev)
1106 return 0; 1151 return 0;
1107 1152
1108error: 1153error:
1154 arm_iommu_release_mapping(mmu->mapping);
1155
1109 kfree(dev->archdata.iommu); 1156 kfree(dev->archdata.iommu);
1157 kfree(utlbs);
1158
1110 dev->archdata.iommu = NULL; 1159 dev->archdata.iommu = NULL;
1111 iommu_group_remove_device(dev); 1160
1161 if (!IS_ERR_OR_NULL(group))
1162 iommu_group_remove_device(dev);
1163
1112 return ret; 1164 return ret;
1113} 1165}
1114 1166
1115static void ipmmu_remove_device(struct device *dev) 1167static void ipmmu_remove_device(struct device *dev)
1116{ 1168{
1169 struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
1170
1117 arm_iommu_detach_device(dev); 1171 arm_iommu_detach_device(dev);
1118 iommu_group_remove_device(dev); 1172 iommu_group_remove_device(dev);
1119 kfree(dev->archdata.iommu); 1173
1174 kfree(archdata->utlbs);
1175 kfree(archdata);
1176
1120 dev->archdata.iommu = NULL; 1177 dev->archdata.iommu = NULL;
1121} 1178}
1122 1179
@@ -1154,7 +1211,7 @@ static int ipmmu_probe(struct platform_device *pdev)
1154 int irq; 1211 int irq;
1155 int ret; 1212 int ret;
1156 1213
1157 if (!pdev->dev.platform_data) { 1214 if (!IS_ENABLED(CONFIG_OF) && !pdev->dev.platform_data) {
1158 dev_err(&pdev->dev, "missing platform data\n"); 1215 dev_err(&pdev->dev, "missing platform data\n");
1159 return -EINVAL; 1216 return -EINVAL;
1160 } 1217 }
@@ -1166,7 +1223,6 @@ static int ipmmu_probe(struct platform_device *pdev)
1166 } 1223 }
1167 1224
1168 mmu->dev = &pdev->dev; 1225 mmu->dev = &pdev->dev;
1169 mmu->pdata = pdev->dev.platform_data;
1170 mmu->num_utlbs = 32; 1226 mmu->num_utlbs = 32;
1171 1227
1172 /* Map I/O memory and request IRQ. */ 1228 /* Map I/O memory and request IRQ. */
@@ -1175,6 +1231,20 @@ static int ipmmu_probe(struct platform_device *pdev)
1175 if (IS_ERR(mmu->base)) 1231 if (IS_ERR(mmu->base))
1176 return PTR_ERR(mmu->base); 1232 return PTR_ERR(mmu->base);
1177 1233
1234 /*
1235 * The IPMMU has two register banks, for secure and non-secure modes.
1236 * The bank mapped at the beginning of the IPMMU address space
1237 * corresponds to the running mode of the CPU. When running in secure
1238 * mode the non-secure register bank is also available at an offset.
1239 *
1240 * Secure mode operation isn't clearly documented and is thus currently
1241 * not implemented in the driver. Furthermore, preliminary tests of
1242 * non-secure operation with the main register bank were not successful.
1243 * Offset the registers base unconditionally to point to the non-secure
1244 * alias space for now.
1245 */
1246 mmu->base += IM_NS_ALIAS_OFFSET;
1247
1178 irq = platform_get_irq(pdev, 0); 1248 irq = platform_get_irq(pdev, 0);
1179 if (irq < 0) { 1249 if (irq < 0) {
1180 dev_err(&pdev->dev, "no IRQ found\n"); 1250 dev_err(&pdev->dev, "no IRQ found\n");
@@ -1220,9 +1290,14 @@ static int ipmmu_remove(struct platform_device *pdev)
1220 return 0; 1290 return 0;
1221} 1291}
1222 1292
1293static const struct of_device_id ipmmu_of_ids[] = {
1294 { .compatible = "renesas,ipmmu-vmsa", },
1295};
1296
1223static struct platform_driver ipmmu_driver = { 1297static struct platform_driver ipmmu_driver = {
1224 .driver = { 1298 .driver = {
1225 .name = "ipmmu-vmsa", 1299 .name = "ipmmu-vmsa",
1300 .of_match_table = of_match_ptr(ipmmu_of_ids),
1226 }, 1301 },
1227 .probe = ipmmu_probe, 1302 .probe = ipmmu_probe,
1228 .remove = ipmmu_remove, 1303 .remove = ipmmu_remove,
diff --git a/include/linux/platform_data/ipmmu-vmsa.h b/include/linux/platform_data/ipmmu-vmsa.h
deleted file mode 100644
index 5275b3ac6d37..000000000000
--- a/include/linux/platform_data/ipmmu-vmsa.h
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * IPMMU VMSA Platform Data
3 *
4 * Copyright (C) 2014 Renesas Electronics Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */
10
11#ifndef __IPMMU_VMSA_H__
12#define __IPMMU_VMSA_H__
13
14struct ipmmu_vmsa_master {
15 const char *name;
16 unsigned int utlb;
17};
18
19struct ipmmu_vmsa_platform_data {
20 const struct ipmmu_vmsa_master *masters;
21 unsigned int num_masters;
22};
23
24#endif /* __IPMMU_VMSA_H__ */