aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2015-04-09 15:33:32 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-18 15:32:59 -0400
commit0ae53ed15d9b87b883b593a9884957cfa4fc2480 (patch)
tree97db422967a6c36b20099beb9fe14e37ab74e3e9 /arch/sparc
parentbb620c3d3925aec0ed4f21010c86df08ec18a8c7 (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> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/ldc.c153
1 files changed, 65 insertions, 88 deletions
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 274a9f59d95c..d2ae0f70059e 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -15,6 +15,7 @@
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/iommu-common.h>
18 19
19#include <asm/hypervisor.h> 20#include <asm/hypervisor.h>
20#include <asm/iommu.h> 21#include <asm/iommu.h>
@@ -27,6 +28,10 @@
27#define DRV_MODULE_VERSION "1.1" 28#define DRV_MODULE_VERSION "1.1"
28#define DRV_MODULE_RELDATE "July 22, 2008" 29#define DRV_MODULE_RELDATE "July 22, 2008"
29 30
31#define COOKIE_PGSZ_CODE 0xf000000000000000ULL
32#define COOKIE_PGSZ_CODE_SHIFT 60ULL
33
34
30static char version[] = 35static char version[] =
31 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 36 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
32#define LDC_PACKET_SIZE 64 37#define LDC_PACKET_SIZE 64
@@ -98,10 +103,10 @@ static const struct ldc_mode_ops stream_ops;
98int ldom_domaining_enabled; 103int ldom_domaining_enabled;
99 104
100struct ldc_iommu { 105struct ldc_iommu {
101 /* Protects arena alloc/free. */ 106 /* Protects ldc_unmap. */
102 spinlock_t lock; 107 spinlock_t lock;
103 struct iommu_arena arena;
104 struct ldc_mtable_entry *page_table; 108 struct ldc_mtable_entry *page_table;
109 struct iommu_map_table iommu_map_table;
105}; 110};
106 111
107struct ldc_channel { 112struct ldc_channel {
@@ -998,31 +1003,59 @@ static void free_queue(unsigned long num_entries, struct ldc_packet *q)
998 free_pages((unsigned long)q, order); 1003 free_pages((unsigned long)q, order);
999} 1004}
1000 1005
1006static unsigned long ldc_cookie_to_index(u64 cookie, void *arg)
1007{
1008 u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT;
1009 /* struct ldc_iommu *ldc_iommu = (struct ldc_iommu *)arg; */
1010
1011 cookie &= ~COOKIE_PGSZ_CODE;
1012
1013 return (cookie >> (13ULL + (szcode * 3ULL)));
1014}
1015
1016static void ldc_demap(struct ldc_iommu *iommu, unsigned long id, u64 cookie,
1017 unsigned long entry, unsigned long npages)
1018{
1019 struct ldc_mtable_entry *base;
1020 unsigned long i, shift;
1021
1022 shift = (cookie >> COOKIE_PGSZ_CODE_SHIFT) * 3;
1023 base = iommu->page_table + entry;
1024 for (i = 0; i < npages; i++) {
1025 if (base->cookie)
1026 sun4v_ldc_revoke(id, cookie + (i << shift),
1027 base->cookie);
1028 base->mte = 0;
1029 }
1030}
1031
1001/* XXX Make this configurable... XXX */ 1032/* XXX Make this configurable... XXX */
1002#define LDC_IOTABLE_SIZE (8 * 1024) 1033#define LDC_IOTABLE_SIZE (8 * 1024)
1003 1034
1004static int ldc_iommu_init(struct ldc_channel *lp) 1035static int ldc_iommu_init(const char *name, struct ldc_channel *lp)
1005{ 1036{
1006 unsigned long sz, num_tsb_entries, tsbsize, order; 1037 unsigned long sz, num_tsb_entries, tsbsize, order;
1007 struct ldc_iommu *iommu = &lp->iommu; 1038 struct ldc_iommu *ldc_iommu = &lp->iommu;
1039 struct iommu_map_table *iommu = &ldc_iommu->iommu_map_table;
1008 struct ldc_mtable_entry *table; 1040 struct ldc_mtable_entry *table;
1009 unsigned long hv_err; 1041 unsigned long hv_err;
1010 int err; 1042 int err;
1011 1043
1012 num_tsb_entries = LDC_IOTABLE_SIZE; 1044 num_tsb_entries = LDC_IOTABLE_SIZE;
1013 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); 1045 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
1014 1046 spin_lock_init(&ldc_iommu->lock);
1015 spin_lock_init(&iommu->lock);
1016 1047
1017 sz = num_tsb_entries / 8; 1048 sz = num_tsb_entries / 8;
1018 sz = (sz + 7UL) & ~7UL; 1049 sz = (sz + 7UL) & ~7UL;
1019 iommu->arena.map = kzalloc(sz, GFP_KERNEL); 1050 iommu->map = kzalloc(sz, GFP_KERNEL);
1020 if (!iommu->arena.map) { 1051 if (!iommu->map) {
1021 printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz); 1052 printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz);
1022 return -ENOMEM; 1053 return -ENOMEM;
1023 } 1054 }
1024 1055 iommu_tbl_pool_init(iommu, num_tsb_entries, PAGE_SHIFT,
1025 iommu->arena.limit = num_tsb_entries; 1056 NULL, false /* no large pool */,
1057 1 /* npools */,
1058 true /* skip span boundary check */);
1026 1059
1027 order = get_order(tsbsize); 1060 order = get_order(tsbsize);
1028 1061
@@ -1037,7 +1070,7 @@ static int ldc_iommu_init(struct ldc_channel *lp)
1037 1070
1038 memset(table, 0, PAGE_SIZE << order); 1071 memset(table, 0, PAGE_SIZE << order);
1039 1072
1040 iommu->page_table = table; 1073 ldc_iommu->page_table = table;
1041 1074
1042 hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table), 1075 hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table),
1043 num_tsb_entries); 1076 num_tsb_entries);
@@ -1049,31 +1082,32 @@ static int ldc_iommu_init(struct ldc_channel *lp)
1049 1082
1050out_free_table: 1083out_free_table:
1051 free_pages((unsigned long) table, order); 1084 free_pages((unsigned long) table, order);
1052 iommu->page_table = NULL; 1085 ldc_iommu->page_table = NULL;
1053 1086
1054out_free_map: 1087out_free_map:
1055 kfree(iommu->arena.map); 1088 kfree(iommu->map);
1056 iommu->arena.map = NULL; 1089 iommu->map = NULL;
1057 1090
1058 return err; 1091 return err;
1059} 1092}
1060 1093
1061static void ldc_iommu_release(struct ldc_channel *lp) 1094static void ldc_iommu_release(struct ldc_channel *lp)
1062{ 1095{
1063 struct ldc_iommu *iommu = &lp->iommu; 1096 struct ldc_iommu *ldc_iommu = &lp->iommu;
1097 struct iommu_map_table *iommu = &ldc_iommu->iommu_map_table;
1064 unsigned long num_tsb_entries, tsbsize, order; 1098 unsigned long num_tsb_entries, tsbsize, order;
1065 1099
1066 (void) sun4v_ldc_set_map_table(lp->id, 0, 0); 1100 (void) sun4v_ldc_set_map_table(lp->id, 0, 0);
1067 1101
1068 num_tsb_entries = iommu->arena.limit; 1102 num_tsb_entries = iommu->poolsize * iommu->nr_pools;
1069 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); 1103 tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
1070 order = get_order(tsbsize); 1104 order = get_order(tsbsize);
1071 1105
1072 free_pages((unsigned long) iommu->page_table, order); 1106 free_pages((unsigned long) ldc_iommu->page_table, order);
1073 iommu->page_table = NULL; 1107 ldc_iommu->page_table = NULL;
1074 1108
1075 kfree(iommu->arena.map); 1109 kfree(iommu->map);
1076 iommu->arena.map = NULL; 1110 iommu->map = NULL;
1077} 1111}
1078 1112
1079struct ldc_channel *ldc_alloc(unsigned long id, 1113struct ldc_channel *ldc_alloc(unsigned long id,
@@ -1140,7 +1174,7 @@ struct ldc_channel *ldc_alloc(unsigned long id,
1140 1174
1141 lp->id = id; 1175 lp->id = id;
1142 1176
1143 err = ldc_iommu_init(lp); 1177 err = ldc_iommu_init(name, lp);
1144 if (err) 1178 if (err)
1145 goto out_free_ldc; 1179 goto out_free_ldc;
1146 1180
@@ -1885,40 +1919,6 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
1885} 1919}
1886EXPORT_SYMBOL(ldc_read); 1920EXPORT_SYMBOL(ldc_read);
1887 1921
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) 1922static u64 pagesize_code(void)
1923{ 1923{
1924 switch (PAGE_SIZE) { 1924 switch (PAGE_SIZE) {
@@ -1945,23 +1945,14 @@ static u64 make_cookie(u64 index, u64 pgsz_code, u64 page_offset)
1945 page_offset); 1945 page_offset);
1946} 1946}
1947 1947
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 1948
1959static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu, 1949static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu,
1960 unsigned long npages) 1950 unsigned long npages)
1961{ 1951{
1962 long entry; 1952 long entry;
1963 1953
1964 entry = arena_alloc(iommu, npages); 1954 entry = iommu_tbl_range_alloc(NULL, &iommu->iommu_map_table,
1955 npages, NULL, (unsigned long)-1, 0);
1965 if (unlikely(entry < 0)) 1956 if (unlikely(entry < 0))
1966 return NULL; 1957 return NULL;
1967 1958
@@ -2090,7 +2081,7 @@ int ldc_map_sg(struct ldc_channel *lp,
2090 struct ldc_trans_cookie *cookies, int ncookies, 2081 struct ldc_trans_cookie *cookies, int ncookies,
2091 unsigned int map_perm) 2082 unsigned int map_perm)
2092{ 2083{
2093 unsigned long i, npages, flags; 2084 unsigned long i, npages;
2094 struct ldc_mtable_entry *base; 2085 struct ldc_mtable_entry *base;
2095 struct cookie_state state; 2086 struct cookie_state state;
2096 struct ldc_iommu *iommu; 2087 struct ldc_iommu *iommu;
@@ -2109,9 +2100,7 @@ int ldc_map_sg(struct ldc_channel *lp,
2109 2100
2110 iommu = &lp->iommu; 2101 iommu = &lp->iommu;
2111 2102
2112 spin_lock_irqsave(&iommu->lock, flags);
2113 base = alloc_npages(iommu, npages); 2103 base = alloc_npages(iommu, npages);
2114 spin_unlock_irqrestore(&iommu->lock, flags);
2115 2104
2116 if (!base) 2105 if (!base)
2117 return -ENOMEM; 2106 return -ENOMEM;
@@ -2136,7 +2125,7 @@ int ldc_map_single(struct ldc_channel *lp,
2136 struct ldc_trans_cookie *cookies, int ncookies, 2125 struct ldc_trans_cookie *cookies, int ncookies,
2137 unsigned int map_perm) 2126 unsigned int map_perm)
2138{ 2127{
2139 unsigned long npages, pa, flags; 2128 unsigned long npages, pa;
2140 struct ldc_mtable_entry *base; 2129 struct ldc_mtable_entry *base;
2141 struct cookie_state state; 2130 struct cookie_state state;
2142 struct ldc_iommu *iommu; 2131 struct ldc_iommu *iommu;
@@ -2152,9 +2141,7 @@ int ldc_map_single(struct ldc_channel *lp,
2152 2141
2153 iommu = &lp->iommu; 2142 iommu = &lp->iommu;
2154 2143
2155 spin_lock_irqsave(&iommu->lock, flags);
2156 base = alloc_npages(iommu, npages); 2144 base = alloc_npages(iommu, npages);
2157 spin_unlock_irqrestore(&iommu->lock, flags);
2158 2145
2159 if (!base) 2146 if (!base)
2160 return -ENOMEM; 2147 return -ENOMEM;
@@ -2172,35 +2159,25 @@ int ldc_map_single(struct ldc_channel *lp,
2172} 2159}
2173EXPORT_SYMBOL(ldc_map_single); 2160EXPORT_SYMBOL(ldc_map_single);
2174 2161
2162
2175static void free_npages(unsigned long id, struct ldc_iommu *iommu, 2163static void free_npages(unsigned long id, struct ldc_iommu *iommu,
2176 u64 cookie, u64 size) 2164 u64 cookie, u64 size)
2177{ 2165{
2178 struct iommu_arena *arena = &iommu->arena; 2166 unsigned long npages, entry;
2179 unsigned long i, shift, index, npages;
2180 struct ldc_mtable_entry *base;
2181 2167
2182 npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT; 2168 npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT;
2183 index = cookie_to_index(cookie, &shift);
2184 base = iommu->page_table + index;
2185 2169
2186 BUG_ON(index > arena->limit || 2170 entry = ldc_cookie_to_index(cookie, iommu);
2187 (index + npages) > arena->limit); 2171 ldc_demap(iommu, id, cookie, entry, npages);
2188 2172 iommu_tbl_range_free(&iommu->iommu_map_table, cookie, npages, entry);
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} 2173}
2197 2174
2198void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, 2175void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies,
2199 int ncookies) 2176 int ncookies)
2200{ 2177{
2201 struct ldc_iommu *iommu = &lp->iommu; 2178 struct ldc_iommu *iommu = &lp->iommu;
2202 unsigned long flags;
2203 int i; 2179 int i;
2180 unsigned long flags;
2204 2181
2205 spin_lock_irqsave(&iommu->lock, flags); 2182 spin_lock_irqsave(&iommu->lock, flags);
2206 for (i = 0; i < ncookies; i++) { 2183 for (i = 0; i < ncookies; i++) {