Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] Celleb: htab routines

Adds htab routines for Celleb platform.

Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Ishizaki Kou and committed by
Paul Mackerras
fe4a0cf1 97a9b584

+312
+311
arch/powerpc/platforms/celleb/htab.c
··· 1 + /* 2 + * "Cell Reference Set" HTAB support. 3 + * 4 + * (C) Copyright 2006-2007 TOSHIBA CORPORATION 5 + * 6 + * This code is based on arch/powerpc/platforms/pseries/lpar.c: 7 + * Copyright (C) 2001 Todd Inglett, IBM Corporation 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along 20 + * with this program; if not, write to the Free Software Foundation, Inc., 21 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 + */ 23 + 24 + #undef DEBUG_LOW 25 + 26 + #include <linux/kernel.h> 27 + #include <linux/spinlock.h> 28 + 29 + #include <asm/mmu.h> 30 + #include <asm/page.h> 31 + #include <asm/pgtable.h> 32 + #include <asm/machdep.h> 33 + #include <asm/udbg.h> 34 + 35 + #include "beat_wrapper.h" 36 + 37 + #ifdef DEBUG_LOW 38 + #define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) 39 + #else 40 + #define DBG_LOW(fmt...) do { } while(0) 41 + #endif 42 + 43 + static DEFINE_SPINLOCK(beat_htab_lock); 44 + 45 + static inline unsigned int beat_read_mask(unsigned hpte_group) 46 + { 47 + unsigned long hpte_v[5]; 48 + unsigned long rmask = 0; 49 + 50 + beat_read_htab_entries(0, hpte_group + 0, hpte_v); 51 + if (!(hpte_v[0] & HPTE_V_BOLTED)) 52 + rmask |= 0x8000; 53 + if (!(hpte_v[1] & HPTE_V_BOLTED)) 54 + rmask |= 0x4000; 55 + if (!(hpte_v[2] & HPTE_V_BOLTED)) 56 + rmask |= 0x2000; 57 + if (!(hpte_v[3] & HPTE_V_BOLTED)) 58 + rmask |= 0x1000; 59 + beat_read_htab_entries(0, hpte_group + 4, hpte_v); 60 + if (!(hpte_v[0] & HPTE_V_BOLTED)) 61 + rmask |= 0x0800; 62 + if (!(hpte_v[1] & HPTE_V_BOLTED)) 63 + rmask |= 0x0400; 64 + if (!(hpte_v[2] & HPTE_V_BOLTED)) 65 + rmask |= 0x0200; 66 + if (!(hpte_v[3] & HPTE_V_BOLTED)) 67 + rmask |= 0x0100; 68 + hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP); 69 + beat_read_htab_entries(0, hpte_group + 0, hpte_v); 70 + if (!(hpte_v[0] & HPTE_V_BOLTED)) 71 + rmask |= 0x80; 72 + if (!(hpte_v[1] & HPTE_V_BOLTED)) 73 + rmask |= 0x40; 74 + if (!(hpte_v[2] & HPTE_V_BOLTED)) 75 + rmask |= 0x20; 76 + if (!(hpte_v[3] & HPTE_V_BOLTED)) 77 + rmask |= 0x10; 78 + beat_read_htab_entries(0, hpte_group + 4, hpte_v); 79 + if (!(hpte_v[0] & HPTE_V_BOLTED)) 80 + rmask |= 0x08; 81 + if (!(hpte_v[1] & HPTE_V_BOLTED)) 82 + rmask |= 0x04; 83 + if (!(hpte_v[2] & HPTE_V_BOLTED)) 84 + rmask |= 0x02; 85 + if (!(hpte_v[3] & HPTE_V_BOLTED)) 86 + rmask |= 0x01; 87 + return rmask; 88 + } 89 + 90 + static long beat_lpar_hpte_insert(unsigned long hpte_group, 91 + unsigned long va, unsigned long pa, 92 + unsigned long rflags, unsigned long vflags, 93 + int psize) 94 + { 95 + unsigned long lpar_rc; 96 + unsigned long slot; 97 + unsigned long hpte_v, hpte_r; 98 + unsigned long flags; 99 + 100 + /* same as iseries */ 101 + if (vflags & HPTE_V_SECONDARY) 102 + return -1; 103 + 104 + if (!(vflags & HPTE_V_BOLTED)) 105 + DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " 106 + "rflags=%lx, vflags=%lx, psize=%d)\n", 107 + hpte_group, va, pa, rflags, vflags, psize); 108 + 109 + hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; 110 + hpte_r = hpte_encode_r(pa, psize) | rflags; 111 + 112 + if (!(vflags & HPTE_V_BOLTED)) 113 + DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); 114 + 115 + if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) 116 + hpte_r &= ~_PAGE_COHERENT; 117 + 118 + spin_lock_irqsave(&beat_htab_lock, flags); 119 + if ((lpar_rc = beat_read_mask(hpte_group)) == 0) { 120 + if (!(vflags & HPTE_V_BOLTED)) 121 + DBG_LOW(" full\n"); 122 + spin_unlock_irqrestore(&beat_htab_lock, flags); 123 + return -1; 124 + } 125 + 126 + lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48, 127 + hpte_v, hpte_r, &slot); 128 + spin_unlock_irqrestore(&beat_htab_lock, flags); 129 + 130 + /* 131 + * Since we try and ioremap PHBs we don't own, the pte insert 132 + * will fail. However we must catch the failure in hash_page 133 + * or we will loop forever, so return -2 in this case. 134 + */ 135 + if (unlikely(lpar_rc != 0)) { 136 + if (!(vflags & HPTE_V_BOLTED)) 137 + DBG_LOW(" lpar err %lx\n", lpar_rc); 138 + return -2; 139 + } 140 + if (!(vflags & HPTE_V_BOLTED)) 141 + DBG_LOW(" -> slot: %lx\n", slot); 142 + 143 + /* We have to pass down the secondary bucket bit here as well */ 144 + return (slot ^ hpte_group) & 15; 145 + } 146 + 147 + static long beat_lpar_hpte_remove(unsigned long hpte_group) 148 + { 149 + DBG_LOW("hpte_remove(group=%lx)\n", hpte_group); 150 + return -1; 151 + } 152 + 153 + static unsigned long beat_lpar_hpte_getword0(unsigned long slot) 154 + { 155 + unsigned long dword0, dword[5]; 156 + unsigned long lpar_rc; 157 + 158 + lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword); 159 + 160 + dword0 = dword[slot&3]; 161 + 162 + BUG_ON(lpar_rc != 0); 163 + 164 + return dword0; 165 + } 166 + 167 + static void beat_lpar_hptab_clear(void) 168 + { 169 + unsigned long size_bytes = 1UL << ppc64_pft_size; 170 + unsigned long hpte_count = size_bytes >> 4; 171 + int i; 172 + unsigned long dummy0, dummy1; 173 + 174 + /* TODO: Use bulk call */ 175 + for (i = 0; i < hpte_count; i++) 176 + beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1); 177 + } 178 + 179 + /* 180 + * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and 181 + * the low 3 bits of flags happen to line up. So no transform is needed. 182 + * We can probably optimize here and assume the high bits of newpp are 183 + * already zero. For now I am paranoid. 184 + */ 185 + static long beat_lpar_hpte_updatepp(unsigned long slot, 186 + unsigned long newpp, 187 + unsigned long va, 188 + int psize, int local) 189 + { 190 + unsigned long lpar_rc; 191 + unsigned long dummy0, dummy1, want_v; 192 + unsigned long flags; 193 + 194 + want_v = hpte_encode_v(va, psize); 195 + 196 + DBG_LOW(" update: " 197 + "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", 198 + want_v & HPTE_V_AVPN, slot, psize, newpp); 199 + 200 + spin_lock_irqsave(&beat_htab_lock, flags); 201 + dummy0 = beat_lpar_hpte_getword0(slot); 202 + if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) { 203 + DBG_LOW("not found !\n"); 204 + spin_unlock_irqrestore(&beat_htab_lock, flags); 205 + return -1; 206 + } 207 + 208 + lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0, 209 + &dummy1); 210 + spin_unlock_irqrestore(&beat_htab_lock, flags); 211 + if (lpar_rc != 0 || dummy0 == 0) { 212 + DBG_LOW("not found !\n"); 213 + return -1; 214 + } 215 + 216 + DBG_LOW("ok %lx %lx\n", dummy0, dummy1); 217 + 218 + BUG_ON(lpar_rc != 0); 219 + 220 + return 0; 221 + } 222 + 223 + static long beat_lpar_hpte_find(unsigned long va, int psize) 224 + { 225 + unsigned long hash; 226 + unsigned long i, j; 227 + long slot; 228 + unsigned long want_v, hpte_v; 229 + 230 + hash = hpt_hash(va, mmu_psize_defs[psize].shift); 231 + want_v = hpte_encode_v(va, psize); 232 + 233 + for (j = 0; j < 2; j++) { 234 + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 235 + for (i = 0; i < HPTES_PER_GROUP; i++) { 236 + hpte_v = beat_lpar_hpte_getword0(slot); 237 + 238 + if (HPTE_V_COMPARE(hpte_v, want_v) 239 + && (hpte_v & HPTE_V_VALID) 240 + && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { 241 + /* HPTE matches */ 242 + if (j) 243 + slot = -slot; 244 + return slot; 245 + } 246 + ++slot; 247 + } 248 + hash = ~hash; 249 + } 250 + 251 + return -1; 252 + } 253 + 254 + static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, 255 + unsigned long ea, 256 + int psize) 257 + { 258 + unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; 259 + unsigned long flags; 260 + 261 + vsid = get_kernel_vsid(ea); 262 + va = (vsid << 28) | (ea & 0x0fffffff); 263 + 264 + spin_lock_irqsave(&beat_htab_lock, flags); 265 + slot = beat_lpar_hpte_find(va, psize); 266 + BUG_ON(slot == -1); 267 + 268 + lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, 269 + &dummy0, &dummy1); 270 + spin_unlock_irqrestore(&beat_htab_lock, flags); 271 + 272 + BUG_ON(lpar_rc != 0); 273 + } 274 + 275 + static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, 276 + int psize, int local) 277 + { 278 + unsigned long want_v; 279 + unsigned long lpar_rc; 280 + unsigned long dummy1, dummy2; 281 + unsigned long flags; 282 + 283 + DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", 284 + slot, va, psize, local); 285 + want_v = hpte_encode_v(va, psize); 286 + 287 + spin_lock_irqsave(&beat_htab_lock, flags); 288 + dummy1 = beat_lpar_hpte_getword0(slot); 289 + 290 + if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) { 291 + DBG_LOW("not found !\n"); 292 + spin_unlock_irqrestore(&beat_htab_lock, flags); 293 + return; 294 + } 295 + 296 + lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0, 297 + &dummy1, &dummy2); 298 + spin_unlock_irqrestore(&beat_htab_lock, flags); 299 + 300 + BUG_ON(lpar_rc != 0); 301 + } 302 + 303 + void __init hpte_init_beat(void) 304 + { 305 + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate; 306 + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp; 307 + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; 308 + ppc_md.hpte_insert = beat_lpar_hpte_insert; 309 + ppc_md.hpte_remove = beat_lpar_hpte_remove; 310 + ppc_md.hpte_clear_all = beat_lpar_hptab_clear; 311 + }
+1
include/asm-powerpc/mmu.h
··· 247 247 extern void hpte_init_native(void); 248 248 extern void hpte_init_lpar(void); 249 249 extern void hpte_init_iSeries(void); 250 + extern void hpte_init_beat(void); 250 251 251 252 extern void stabs_alloc(void); 252 253 extern void slb_initialize(void);