aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2015-03-12 20:02:37 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-16 15:44:56 -0400
commit671d773297969bebb1732e1cdc1ec03aa53c6be2 (patch)
treed3bc9387c3d86187c870e967e887513c61d156b4 /arch/sparc
parentf1600e549b948a32ad7672e069b2915314637ae3 (diff)
sparc: Make LDC use common iommu poll management functions
Note that this conversion is only being done to consolidate the code and ensure that the common code provides the sufficient abstraction. It is not expected to result in any noticeable performance improvement, as there is typically one ldc_iommu per vnet_port, and each one has 8k entries, with a typical request for 1-4 pages. Thus LDC uses npools == 1. Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/ldc.c185
1 files changed, 97 insertions, 88 deletions
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 274a9f59d95c..d485697c37c0 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -15,6 +15,8 @@
15#include <linux/list.h> 15#include <linux/list.h>
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/bitmap.h> 17#include <linux/bitmap.h>
18#include <linux/hash.h>
19#include <linux/iommu-common.h>
18 20
19#include <asm/hypervisor.h> 21#include <asm/hypervisor.h>
20#include <asm/iommu.h> 22#include <asm/iommu.h>
@@ -27,6 +29,11 @@
27#define DRV_MODULE_VERSION "1.1" 29#define DRV_MODULE_VERSION "1.1"
28#define DRV_MODULE_RELDATE "July 22, 2008" 30#define DRV_MODULE_RELDATE "July 22, 2008"
29 31
32#define COOKIE_PGSZ_CODE 0xf000000000000000ULL
33#define COOKIE_PGSZ_CODE_SHIFT 60ULL
34
35static DEFINE_PER_CPU(unsigned int, ldc_pool_hash);
36
30static char version[] = 37static char version[] =
31 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 38 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
32#define LDC_PACKET_SIZE 64 39#define LDC_PACKET_SIZE 64
@@ -98,10 +105,10 @@ static const struct ldc_mode_ops stream_ops;
98int ldom_domaining_enabled; 105int ldom_domaining_enabled;
99 106
100struct ldc_iommu { 107struct ldc_iommu {
101 /* Protects arena alloc/free. */ 108 /* Protects ldc_unmap. */
102 spinlock_t lock; 109 spinlock_t lock;
103 struct iommu_arena arena;
104 struct ldc_mtable_entry *page_table; 110 struct ldc_mtable_entry *page_table;
111 struct iommu_table iommu_table;
105}; 112};
106 113
107struct ldc_channel { 114struct ldc_channel {
@@ -998,31 +1005,85 @@ static void free_queue(unsigned long num_entries, struct ldc_packet *q)
998 free_pages((unsigned long)q, order); 1005 free_pages((unsigned long)q, order);
999} 1006}
1000 1007
1008static unsigned long ldc_cookie_to_index(u64 cookie, void *arg)
1009{
1010 u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT;
1011 /* struct ldc_iommu *ldc_iommu = (struct ldc_iommu *)arg; */
1012
1013 cookie &= ~COOKIE_PGSZ_CODE;
1014
1015 return (cookie >> (13ULL + (szcode * 3ULL)));
1016}
1017
1018struct ldc_demap_arg {
1019 struct ldc_iommu *ldc_iommu;
1020 u64 cookie;
1021 unsigned long id;
1022};
1023
1024static void ldc_demap(void *arg, unsigned long entry, unsigned long npages)
1025{
1026 struct ldc_demap_arg *ldc_demap_arg = arg;
1027 struct ldc_iommu *iommu = ldc_demap_arg->ldc_iommu;
1028 unsigned long id = ldc_demap_arg->id;
1029 u64 cookie = ldc_demap_arg->cookie;
1030 struct ldc_mtable_entry *base;
1031 unsigned long i, shift;
1032
1033 shift = (cookie >> COOKIE_PGSZ_CODE_SHIFT) * 3;
1034 base = iommu->page_table + entry;
1035 for (i = 0; i < npages; i++) {
1036 if (base->cookie)
1037 sun4v_ldc_revoke(id, cookie + (i << shift),
1038 base->cookie);
1039 base->mte = 0;
1040 }
1041}
1042
1001/* XXX Make this configurable... XXX */ 1043/* XXX Make this configurable... XXX */
1002#define LDC_IOTABLE_SIZE (8 * 1024) 1044#define LDC_IOTABLE_SIZE (8 * 1024)
1003 1045
1004static int ldc_iommu_init(struct ldc_channel *lp) 1046struct iommu_tbl_ops ldc_iommu_ops = {
1047 .cookie_to_index = ldc_cookie_to_index,
1048 .demap = ldc_demap,
1049};
1050
1051static void setup_ldc_pool_hash(void)
1052{
1053 unsigned int i;
1054 static bool do_once;
1055
1056 if (do_once)
1057 return;
1058 do_once = true;
1059 for_each_possible_cpu(i)
1060 per_cpu(ldc_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS);
1061}
1062
1063
1064static int ldc_iommu_init(const char *name, struct ldc_channel *lp)
1005{ 1065{
1006 unsigned long sz, num_tsb_entries, tsbsize, order; 1066 unsigned long sz, num_tsb_entries, tsbsize, order;
1007 struct ldc_iommu *iommu = &lp->iommu; 1067 struct ldc_iommu *ldc_iommu = &lp->iommu;
1068 struct iommu_table *iommu = &ldc_iommu->iommu_table;
1008 struct ldc_mtable_entry *table; 1069 struct ldc_mtable_entry *table;
1009 unsigned long hv_err; 1070 unsigned long hv_err;
1010 int err; 1071 int err;
1011 1072
1012 num_tsb_entries = LDC_IOTABLE_SIZE; 1073 num_tsb_entries = LDC_IOTABLE_SIZE;
1013 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); 1074 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
1014 1075 setup_ldc_pool_hash();
1015 spin_lock_init(&iommu->lock); 1076 spin_lock_init(&ldc_iommu->lock);
1016 1077
1017 sz = num_tsb_entries / 8; 1078 sz = num_tsb_entries / 8;
1018 sz = (sz + 7UL) & ~7UL; 1079 sz = (sz + 7UL) & ~7UL;
1019 iommu->arena.map = kzalloc(sz, GFP_KERNEL); 1080 iommu->map = kzalloc(sz, GFP_KERNEL);
1020 if (!iommu->arena.map) { 1081 if (!iommu->map) {
1021 printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz); 1082 printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz);
1022 return -ENOMEM; 1083 return -ENOMEM;
1023 } 1084 }
1024 1085 iommu_tbl_pool_init(iommu, num_tsb_entries, PAGE_SHIFT,
1025 iommu->arena.limit = num_tsb_entries; 1086 &ldc_iommu_ops, false, 1);
1026 1087
1027 order = get_order(tsbsize); 1088 order = get_order(tsbsize);
1028 1089
@@ -1037,7 +1098,7 @@ static int ldc_iommu_init(struct ldc_channel *lp)
1037 1098
1038 memset(table, 0, PAGE_SIZE << order); 1099 memset(table, 0, PAGE_SIZE << order);
1039 1100
1040 iommu->page_table = table; 1101 ldc_iommu->page_table = table;
1041 1102
1042 hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table), 1103 hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table),
1043 num_tsb_entries); 1104 num_tsb_entries);
@@ -1049,31 +1110,32 @@ static int ldc_iommu_init(struct ldc_channel *lp)
1049 1110
1050out_free_table: 1111out_free_table:
1051 free_pages((unsigned long) table, order); 1112 free_pages((unsigned long) table, order);
1052 iommu->page_table = NULL; 1113 ldc_iommu->page_table = NULL;
1053 1114
1054out_free_map: 1115out_free_map:
1055 kfree(iommu->arena.map); 1116 kfree(iommu->map);
1056 iommu->arena.map = NULL; 1117 iommu->map = NULL;
1057 1118
1058 return err; 1119 return err;
1059} 1120}
1060 1121
1061static void ldc_iommu_release(struct ldc_channel *lp) 1122static void ldc_iommu_release(struct ldc_channel *lp)
1062{ 1123{
1063 struct ldc_iommu *iommu = &lp->iommu; 1124 struct ldc_iommu *ldc_iommu = &lp->iommu;
1125 struct iommu_table *iommu = &ldc_iommu->iommu_table;
1064 unsigned long num_tsb_entries, tsbsize, order; 1126 unsigned long num_tsb_entries, tsbsize, order;
1065 1127
1066 (void) sun4v_ldc_set_map_table(lp->id, 0, 0); 1128 (void) sun4v_ldc_set_map_table(lp->id, 0, 0);
1067 1129
1068 num_tsb_entries = iommu->arena.limit; 1130 num_tsb_entries = iommu->poolsize * iommu->nr_pools;
1069 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); 1131 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
1070 order = get_order(tsbsize); 1132 order = get_order(tsbsize);
1071 1133
1072 free_pages((unsigned long) iommu->page_table, order); 1134 free_pages((unsigned long) ldc_iommu->page_table, order);
1073 iommu->page_table = NULL; 1135 ldc_iommu->page_table = NULL;
1074 1136
1075 kfree(iommu->arena.map); 1137 kfree(iommu->map);
1076 iommu->arena.map = NULL; 1138 iommu->map = NULL;
1077} 1139}
1078 1140
1079struct ldc_channel *ldc_alloc(unsigned long id, 1141struct ldc_channel *ldc_alloc(unsigned long id,
@@ -1140,7 +1202,7 @@ struct ldc_channel *ldc_alloc(unsigned long id,
1140 1202
1141 lp->id = id; 1203 lp->id = id;
1142 1204
1143 err = ldc_iommu_init(lp); 1205 err = ldc_iommu_init(name, lp);
1144 if (err) 1206 if (err)
1145 goto out_free_ldc; 1207 goto out_free_ldc;
1146 1208
@@ -1885,40 +1947,6 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
1885} 1947}
1886EXPORT_SYMBOL(ldc_read); 1948EXPORT_SYMBOL(ldc_read);
1887 1949
1888static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages)
1889{
1890 struct iommu_arena *arena = &iommu->arena;
1891 unsigned long n, start, end, limit;
1892 int pass;
1893
1894 limit = arena->limit;
1895 start = arena->hint;
1896 pass = 0;
1897
1898again:
1899 n = bitmap_find_next_zero_area(arena->map, limit, start, npages, 0);
1900 end = n + npages;
1901 if (unlikely(end >= limit)) {
1902 if (likely(pass < 1)) {
1903 limit = start;
1904 start = 0;
1905 pass++;
1906 goto again;
1907 } else {
1908 /* Scanned the whole thing, give up. */
1909 return -1;
1910 }
1911 }
1912 bitmap_set(arena->map, n, npages);
1913
1914 arena->hint = end;
1915
1916 return n;
1917}
1918
1919#define COOKIE_PGSZ_CODE 0xf000000000000000ULL
1920#define COOKIE_PGSZ_CODE_SHIFT 60ULL
1921
1922static u64 pagesize_code(void) 1950static u64 pagesize_code(void)
1923{ 1951{
1924 switch (PAGE_SIZE) { 1952 switch (PAGE_SIZE) {
@@ -1945,23 +1973,14 @@ static u64 make_cookie(u64 index, u64 pgsz_code, u64 page_offset)
1945 page_offset); 1973 page_offset);
1946} 1974}
1947 1975
1948static u64 cookie_to_index(u64 cookie, unsigned long *shift)
1949{
1950 u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT;
1951
1952 cookie &= ~COOKIE_PGSZ_CODE;
1953
1954 *shift = szcode * 3;
1955
1956 return (cookie >> (13ULL + (szcode * 3ULL)));
1957}
1958 1976
1959static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu, 1977static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu,
1960 unsigned long npages) 1978 unsigned long npages)
1961{ 1979{
1962 long entry; 1980 long entry;
1963 1981
1964 entry = arena_alloc(iommu, npages); 1982 entry = iommu_tbl_range_alloc(NULL, &iommu->iommu_table, npages,
1983 NULL, __this_cpu_read(ldc_pool_hash));
1965 if (unlikely(entry < 0)) 1984 if (unlikely(entry < 0))
1966 return NULL; 1985 return NULL;
1967 1986
@@ -2090,7 +2109,7 @@ int ldc_map_sg(struct ldc_channel *lp,
2090 struct ldc_trans_cookie *cookies, int ncookies, 2109 struct ldc_trans_cookie *cookies, int ncookies,
2091 unsigned int map_perm) 2110 unsigned int map_perm)
2092{ 2111{
2093 unsigned long i, npages, flags; 2112 unsigned long i, npages;
2094 struct ldc_mtable_entry *base; 2113 struct ldc_mtable_entry *base;
2095 struct cookie_state state; 2114 struct cookie_state state;
2096 struct ldc_iommu *iommu; 2115 struct ldc_iommu *iommu;
@@ -2109,9 +2128,7 @@ int ldc_map_sg(struct ldc_channel *lp,
2109 2128
2110 iommu = &lp->iommu; 2129 iommu = &lp->iommu;
2111 2130
2112 spin_lock_irqsave(&iommu->lock, flags);
2113 base = alloc_npages(iommu, npages); 2131 base = alloc_npages(iommu, npages);
2114 spin_unlock_irqrestore(&iommu->lock, flags);
2115 2132
2116 if (!base) 2133 if (!base)
2117 return -ENOMEM; 2134 return -ENOMEM;
@@ -2136,7 +2153,7 @@ int ldc_map_single(struct ldc_channel *lp,
2136 struct ldc_trans_cookie *cookies, int ncookies, 2153 struct ldc_trans_cookie *cookies, int ncookies,
2137 unsigned int map_perm) 2154 unsigned int map_perm)
2138{ 2155{
2139 unsigned long npages, pa, flags; 2156 unsigned long npages, pa;
2140 struct ldc_mtable_entry *base; 2157 struct ldc_mtable_entry *base;
2141 struct cookie_state state; 2158 struct cookie_state state;
2142 struct ldc_iommu *iommu; 2159 struct ldc_iommu *iommu;
@@ -2152,9 +2169,7 @@ int ldc_map_single(struct ldc_channel *lp,
2152 2169
2153 iommu = &lp->iommu; 2170 iommu = &lp->iommu;
2154 2171
2155 spin_lock_irqsave(&iommu->lock, flags);
2156 base = alloc_npages(iommu, npages); 2172 base = alloc_npages(iommu, npages);
2157 spin_unlock_irqrestore(&iommu->lock, flags);
2158 2173
2159 if (!base) 2174 if (!base)
2160 return -ENOMEM; 2175 return -ENOMEM;
@@ -2172,35 +2187,29 @@ int ldc_map_single(struct ldc_channel *lp,
2172} 2187}
2173EXPORT_SYMBOL(ldc_map_single); 2188EXPORT_SYMBOL(ldc_map_single);
2174 2189
2190
2175static void free_npages(unsigned long id, struct ldc_iommu *iommu, 2191static void free_npages(unsigned long id, struct ldc_iommu *iommu,
2176 u64 cookie, u64 size) 2192 u64 cookie, u64 size)
2177{ 2193{
2178 struct iommu_arena *arena = &iommu->arena; 2194 unsigned long npages;
2179 unsigned long i, shift, index, npages; 2195 struct ldc_demap_arg demap_arg;
2180 struct ldc_mtable_entry *base;
2181 2196
2182 npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT; 2197 demap_arg.ldc_iommu = iommu;
2183 index = cookie_to_index(cookie, &shift); 2198 demap_arg.cookie = cookie;
2184 base = iommu->page_table + index; 2199 demap_arg.id = id;
2185 2200
2186 BUG_ON(index > arena->limit || 2201 npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT;
2187 (index + npages) > arena->limit); 2202 iommu_tbl_range_free(&iommu->iommu_table, cookie, npages, true,
2203 &demap_arg);
2188 2204
2189 for (i = 0; i < npages; i++) {
2190 if (base->cookie)
2191 sun4v_ldc_revoke(id, cookie + (i << shift),
2192 base->cookie);
2193 base->mte = 0;
2194 __clear_bit(index + i, arena->map);
2195 }
2196} 2205}
2197 2206
2198void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, 2207void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies,
2199 int ncookies) 2208 int ncookies)
2200{ 2209{
2201 struct ldc_iommu *iommu = &lp->iommu; 2210 struct ldc_iommu *iommu = &lp->iommu;
2202 unsigned long flags;
2203 int i; 2211 int i;
2212 unsigned long flags;
2204 2213
2205 spin_lock_irqsave(&iommu->lock, flags); 2214 spin_lock_irqsave(&iommu->lock, flags);
2206 for (i = 0; i < ncookies; i++) { 2215 for (i = 0; i < ncookies; i++) {