aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/ps3/htab.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/ps3/htab.c')
-rw-r--r--arch/powerpc/platforms/ps3/htab.c269
1 files changed, 91 insertions, 178 deletions
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 1cf901fa9031..6eb1d4d182c9 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -29,138 +29,75 @@
29 29
30#include "platform.h" 30#include "platform.h"
31 31
32#if defined(DEBUG) 32/**
33#define DBG udbg_printf 33 * enum lpar_vas_id - id of LPAR virtual address space.
34#else 34 * @lpar_vas_id_current: Current selected virtual address space
35#define DBG pr_debug 35 *
36#endif 36 * Identify the target LPAR address space.
37 37 */
38static struct hash_pte *htab; 38
39static unsigned long htab_addr; 39enum ps3_lpar_vas_id {
40static unsigned char *bolttab; 40 PS3_LPAR_VAS_ID_CURRENT = 0,
41static unsigned char *inusetab; 41};
42 42
43static DEFINE_SPINLOCK(ps3_bolttab_lock); 43
44 44static DEFINE_SPINLOCK(ps3_htab_lock);
45#define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
46 _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
47static void _debug_dump_hpte(unsigned long pa, unsigned long va,
48 unsigned long group, unsigned long bitmap, struct hash_pte lhpte,
49 int psize, unsigned long slot, const char* func, int line)
50{
51 DBG("%s:%d: pa = %lxh\n", func, line, pa);
52 DBG("%s:%d: lpar = %lxh\n", func, line,
53 ps3_mm_phys_to_lpar(pa));
54 DBG("%s:%d: va = %lxh\n", func, line, va);
55 DBG("%s:%d: group = %lxh\n", func, line, group);
56 DBG("%s:%d: bitmap = %lxh\n", func, line, bitmap);
57 DBG("%s:%d: hpte.v = %lxh\n", func, line, lhpte.v);
58 DBG("%s:%d: hpte.r = %lxh\n", func, line, lhpte.r);
59 DBG("%s:%d: psize = %xh\n", func, line, psize);
60 DBG("%s:%d: slot = %lxh\n", func, line, slot);
61}
62 45
63static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, 46static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,
64 unsigned long pa, unsigned long rflags, unsigned long vflags, 47 unsigned long pa, unsigned long rflags, unsigned long vflags,
65 int psize, int ssize) 48 int psize, int ssize)
66{ 49{
67 unsigned long slot; 50 int result;
68 struct hash_pte lhpte; 51 u64 hpte_v, hpte_r;
69 int secondary = 0; 52 u64 inserted_index;
70 unsigned long result; 53 u64 evicted_v, evicted_r;
71 unsigned long bitmap; 54 u64 hpte_v_array[4], hpte_rs;
72 unsigned long flags; 55 unsigned long flags;
73 unsigned long p_pteg, s_pteg, b_index, b_mask, cb, ci; 56 long ret = -1;
74
75 vflags &= ~HPTE_V_SECONDARY; /* this bit is ignored */
76
77 lhpte.v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) |
78 vflags | HPTE_V_VALID;
79 lhpte.r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
80
81 p_pteg = hpte_group / HPTES_PER_GROUP;
82 s_pteg = ~p_pteg & htab_hash_mask;
83
84 spin_lock_irqsave(&ps3_bolttab_lock, flags);
85
86 BUG_ON(bolttab[p_pteg] == 0xff && bolttab[s_pteg] == 0xff);
87 57
88 bitmap = (inusetab[p_pteg] << 8) | inusetab[s_pteg]; 58 /*
59 * lv1_insert_htab_entry() will search for victim
60 * entry in both primary and secondary pte group
61 */
62 vflags &= ~HPTE_V_SECONDARY;
89 63
90 if (bitmap == 0xffff) { 64 hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID;
91 /* 65 hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
92 * PTEG is full. Search for victim.
93 */
94 bitmap &= ~((bolttab[p_pteg] << 8) | bolttab[s_pteg]);
95 do {
96 ci = mftb() & 15;
97 cb = 0x8000UL >> ci;
98 } while ((cb & bitmap) == 0);
99 } else {
100 /*
101 * search free slot in hardware order
102 * [primary] 0, 2, 4, 6, 1, 3, 5, 7
103 * [secondary] 0, 2, 4, 6, 1, 3, 5, 7
104 */
105 for (ci = 0; ci < HPTES_PER_GROUP; ci += 2) {
106 cb = 0x8000UL >> ci;
107 if ((cb & bitmap) == 0)
108 goto found;
109 }
110 for (ci = 1; ci < HPTES_PER_GROUP; ci += 2) {
111 cb = 0x8000UL >> ci;
112 if ((cb & bitmap) == 0)
113 goto found;
114 }
115 for (ci = HPTES_PER_GROUP; ci < HPTES_PER_GROUP*2; ci += 2) {
116 cb = 0x8000UL >> ci;
117 if ((cb & bitmap) == 0)
118 goto found;
119 }
120 for (ci = HPTES_PER_GROUP+1; ci < HPTES_PER_GROUP*2; ci += 2) {
121 cb = 0x8000UL >> ci;
122 if ((cb & bitmap) == 0)
123 goto found;
124 }
125 }
126 66
127found: 67 spin_lock_irqsave(&ps3_htab_lock, flags);
128 if (ci < HPTES_PER_GROUP) {
129 slot = p_pteg * HPTES_PER_GROUP + ci;
130 } else {
131 slot = s_pteg * HPTES_PER_GROUP + (ci & 7);
132 /* lhpte.dw0.dw0.h = 1; */
133 vflags |= HPTE_V_SECONDARY;
134 lhpte.v |= HPTE_V_SECONDARY;
135 }
136 68
137 result = lv1_write_htab_entry(0, slot, lhpte.v, lhpte.r); 69 /* talk hvc to replace entries BOLTED == 0 */
70 result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
71 hpte_v, hpte_r,
72 HPTE_V_BOLTED, 0,
73 &inserted_index,
74 &evicted_v, &evicted_r);
138 75
139 if (result) { 76 if (result) {
140 debug_dump_hpte(pa, va, hpte_group, bitmap, lhpte, psize, slot); 77 /* all entries bolted !*/
78 pr_info("%s:result=%d va=%lx pa=%lx ix=%lx v=%lx r=%lx\n",
79 __func__, result, va, pa, hpte_group, hpte_v, hpte_r);
141 BUG(); 80 BUG();
142 } 81 }
143 82
144 /* 83 /*
145 * If used slot is not in primary HPTE group, 84 * see if the entry is inserted into secondary pteg
146 * the slot should be in secondary HPTE group.
147 */ 85 */
86 result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT,
87 inserted_index & ~0x3UL,
88 &hpte_v_array[0], &hpte_v_array[1],
89 &hpte_v_array[2], &hpte_v_array[3],
90 &hpte_rs);
91 BUG_ON(result);
148 92
149 if ((hpte_group ^ slot) & ~(HPTES_PER_GROUP - 1)) { 93 if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY)
150 secondary = 1; 94 ret = (inserted_index & 7) | (1 << 3);
151 b_index = s_pteg; 95 else
152 } else { 96 ret = inserted_index & 7;
153 secondary = 0;
154 b_index = p_pteg;
155 }
156 97
157 b_mask = (lhpte.v & HPTE_V_BOLTED) ? 1 << 7 : 0 << 7; 98 spin_unlock_irqrestore(&ps3_htab_lock, flags);
158 bolttab[b_index] |= b_mask >> (slot & 7);
159 b_mask = 1 << 7;
160 inusetab[b_index] |= b_mask >> (slot & 7);
161 spin_unlock_irqrestore(&ps3_bolttab_lock, flags);
162 99
163 return (slot & 7) | (secondary << 3); 100 return ret;
164} 101}
165 102
166static long ps3_hpte_remove(unsigned long hpte_group) 103static long ps3_hpte_remove(unsigned long hpte_group)
@@ -172,39 +109,48 @@ static long ps3_hpte_remove(unsigned long hpte_group)
172static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, 109static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
173 unsigned long va, int psize, int ssize, int local) 110 unsigned long va, int psize, int ssize, int local)
174{ 111{
112 int result;
113 u64 hpte_v, want_v, hpte_rs;
114 u64 hpte_v_array[4];
175 unsigned long flags; 115 unsigned long flags;
176 unsigned long result; 116 long ret;
177 unsigned long pteg, bit;
178 unsigned long hpte_v, want_v;
179 117
180 want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); 118 want_v = hpte_encode_v(va, psize, ssize);
181 119
182 spin_lock_irqsave(&ps3_bolttab_lock, flags); 120 spin_lock_irqsave(&ps3_htab_lock, flags);
183 121
184 hpte_v = htab[slot].v; 122 result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL,
185 if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) { 123 &hpte_v_array[0], &hpte_v_array[1],
186 spin_unlock_irqrestore(&ps3_bolttab_lock, flags); 124 &hpte_v_array[2], &hpte_v_array[3],
187 125 &hpte_rs);
188 /* ps3_hpte_insert() will be used to update PTE */
189 return -1;
190 }
191
192 result = lv1_write_htab_entry(0, slot, 0, 0);
193 126
194 if (result) { 127 if (result) {
195 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n", 128 pr_info("%s: res=%d read va=%lx slot=%lx psize=%d\n",
196 __func__, va, slot, psize, result, result); 129 __func__, result, va, slot, psize);
197 BUG(); 130 BUG();
198 } 131 }
199 132
200 pteg = slot / HPTES_PER_GROUP; 133 hpte_v = hpte_v_array[slot % 4];
201 bit = slot % HPTES_PER_GROUP;
202 inusetab[pteg] &= ~(0x80 >> bit);
203 134
204 spin_unlock_irqrestore(&ps3_bolttab_lock, flags); 135 /*
136 * As lv1_read_htab_entries() does not give us the RPN, we can
137 * not synthesize the new hpte_r value here, and therefore can
138 * not update the hpte with lv1_insert_htab_entry(), so we
139 * insted invalidate it and ask the caller to update it via
140 * ps3_hpte_insert() by returning a -1 value.
141 */
142 if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
143 /* not found */
144 ret = -1;
145 } else {
146 /* entry found, just invalidate it */
147 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT,
148 slot, 0, 0);
149 ret = -1;
150 }
205 151
206 /* ps3_hpte_insert() will be used to update PTE */ 152 spin_unlock_irqrestore(&ps3_htab_lock, flags);
207 return -1; 153 return ret;
208} 154}
209 155
210static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, 156static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
@@ -217,45 +163,35 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,
217 int psize, int ssize, int local) 163 int psize, int ssize, int local)
218{ 164{
219 unsigned long flags; 165 unsigned long flags;
220 unsigned long result; 166 int result;
221 unsigned long pteg, bit; 167
168 spin_lock_irqsave(&ps3_htab_lock, flags);
222 169
223 spin_lock_irqsave(&ps3_bolttab_lock, flags); 170 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
224 result = lv1_write_htab_entry(0, slot, 0, 0);
225 171
226 if (result) { 172 if (result) {
227 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n", 173 pr_info("%s: res=%d va=%lx slot=%lx psize=%d\n",
228 __func__, va, slot, psize, result, result); 174 __func__, result, va, slot, psize);
229 BUG(); 175 BUG();
230 } 176 }
231 177
232 pteg = slot / HPTES_PER_GROUP; 178 spin_unlock_irqrestore(&ps3_htab_lock, flags);
233 bit = slot % HPTES_PER_GROUP;
234 inusetab[pteg] &= ~(0x80 >> bit);
235 spin_unlock_irqrestore(&ps3_bolttab_lock, flags);
236} 179}
237 180
238static void ps3_hpte_clear(void) 181static void ps3_hpte_clear(void)
239{ 182{
240 int result; 183 unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4;
241 184 u64 i;
242 DBG(" -> %s:%d\n", __func__, __LINE__);
243 185
244 result = lv1_unmap_htab(htab_addr); 186 for (i = 0; i < hpte_count; i++)
245 BUG_ON(result); 187 lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0);
246 188
247 ps3_mm_shutdown(); 189 ps3_mm_shutdown();
248 ps3_mm_vas_destroy(); 190 ps3_mm_vas_destroy();
249
250 DBG(" <- %s:%d\n", __func__, __LINE__);
251} 191}
252 192
253void __init ps3_hpte_init(unsigned long htab_size) 193void __init ps3_hpte_init(unsigned long htab_size)
254{ 194{
255 long bitmap_size;
256
257 DBG(" -> %s:%d\n", __func__, __LINE__);
258
259 ppc_md.hpte_invalidate = ps3_hpte_invalidate; 195 ppc_md.hpte_invalidate = ps3_hpte_invalidate;
260 ppc_md.hpte_updatepp = ps3_hpte_updatepp; 196 ppc_md.hpte_updatepp = ps3_hpte_updatepp;
261 ppc_md.hpte_updateboltedpp = ps3_hpte_updateboltedpp; 197 ppc_md.hpte_updateboltedpp = ps3_hpte_updateboltedpp;
@@ -264,28 +200,5 @@ void __init ps3_hpte_init(unsigned long htab_size)
264 ppc_md.hpte_clear_all = ps3_hpte_clear; 200 ppc_md.hpte_clear_all = ps3_hpte_clear;
265 201
266 ppc64_pft_size = __ilog2(htab_size); 202 ppc64_pft_size = __ilog2(htab_size);
267
268 bitmap_size = htab_size / sizeof(struct hash_pte) / 8;
269
270 bolttab = __va(lmb_alloc(bitmap_size, 1));
271 inusetab = __va(lmb_alloc(bitmap_size, 1));
272
273 memset(bolttab, 0, bitmap_size);
274 memset(inusetab, 0, bitmap_size);
275
276 DBG(" <- %s:%d\n", __func__, __LINE__);
277} 203}
278 204
279void __init ps3_map_htab(void)
280{
281 long result;
282 unsigned long htab_size = (1UL << ppc64_pft_size);
283
284 result = lv1_map_htab(0, &htab_addr);
285
286 htab = (__force struct hash_pte *)ioremap_flags(htab_addr, htab_size,
287 pgprot_val(PAGE_READONLY_X));
288
289 DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__,
290 htab_addr, (unsigned long)htab);
291}