aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/lpar.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-06 19:06:55 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-06 19:56:47 -0500
commit3c726f8dee6f55e96475574e9f645327e461884c (patch)
treef67c381e8f57959aa4a94bda4c68e24253cd8171 /arch/powerpc/platforms/pseries/lpar.c
parentf912696ab330bf539231d1f8032320f2a08b850f (diff)
[PATCH] ppc64: support 64k pages
Adds a new CONFIG_PPC_64K_PAGES which, when enabled, changes the kernel base page size to 64K. The resulting kernel still boots on any hardware. On current machines with 4K pages support only, the kernel will maintain 16 "subpages" for each 64K page transparently. Note that while real 64K capable HW has been tested, the current patch will not enable it yet as such hardware is not released yet, and I'm still verifying with the firmware architects the proper to get the information from the newer hypervisors. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c115
1 files changed, 73 insertions, 42 deletions
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index e384a5a9179..ab0c6dd6ec9 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -19,7 +19,7 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22#define DEBUG 22#undef DEBUG_LOW
23 23
24#include <linux/config.h> 24#include <linux/config.h>
25#include <linux/kernel.h> 25#include <linux/kernel.h>
@@ -41,10 +41,10 @@
41 41
42#include "plpar_wrappers.h" 42#include "plpar_wrappers.h"
43 43
44#ifdef DEBUG 44#ifdef DEBUG_LOW
45#define DBG(fmt...) udbg_printf(fmt) 45#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
46#else 46#else
47#define DBG(fmt...) 47#define DBG_LOW(fmt...) do { } while(0)
48#endif 48#endif
49 49
50/* in pSeries_hvCall.S */ 50/* in pSeries_hvCall.S */
@@ -276,8 +276,9 @@ void vpa_init(int cpu)
276} 276}
277 277
278long pSeries_lpar_hpte_insert(unsigned long hpte_group, 278long pSeries_lpar_hpte_insert(unsigned long hpte_group,
279 unsigned long va, unsigned long prpn, 279 unsigned long va, unsigned long pa,
280 unsigned long vflags, unsigned long rflags) 280 unsigned long rflags, unsigned long vflags,
281 int psize)
281{ 282{
282 unsigned long lpar_rc; 283 unsigned long lpar_rc;
283 unsigned long flags; 284 unsigned long flags;
@@ -285,11 +286,28 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
285 unsigned long hpte_v, hpte_r; 286 unsigned long hpte_v, hpte_r;
286 unsigned long dummy0, dummy1; 287 unsigned long dummy0, dummy1;
287 288
288 hpte_v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | vflags | HPTE_V_VALID; 289 if (!(vflags & HPTE_V_BOLTED))
289 if (vflags & HPTE_V_LARGE) 290 DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
290 hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); 291 "rflags=%lx, vflags=%lx, psize=%d)\n",
291 292 hpte_group, va, pa, rflags, vflags, psize);
292 hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; 293
294 hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID;
295 hpte_r = hpte_encode_r(pa, psize) | rflags;
296
297 if (!(vflags & HPTE_V_BOLTED))
298 DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
299
300#if 1
301 {
302 int i;
303 for (i=0;i<8;i++) {
304 unsigned long w0, w1;
305 plpar_pte_read(0, hpte_group, &w0, &w1);
306 BUG_ON (HPTE_V_COMPARE(hpte_v, w0)
307 && (w0 & HPTE_V_VALID));
308 }
309 }
310#endif
293 311
294 /* Now fill in the actual HPTE */ 312 /* Now fill in the actual HPTE */
295 /* Set CEC cookie to 0 */ 313 /* Set CEC cookie to 0 */
@@ -299,23 +317,30 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
299 /* Exact = 0 */ 317 /* Exact = 0 */
300 flags = 0; 318 flags = 0;
301 319
302 /* XXX why is this here? - Anton */ 320 /* Make pHyp happy */
303 if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) 321 if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
304 hpte_r &= ~_PAGE_COHERENT; 322 hpte_r &= ~_PAGE_COHERENT;
305 323
306 lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, 324 lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v,
307 hpte_r, &slot, &dummy0, &dummy1); 325 hpte_r, &slot, &dummy0, &dummy1);
308 326 if (unlikely(lpar_rc == H_PTEG_Full)) {
309 if (unlikely(lpar_rc == H_PTEG_Full)) 327 if (!(vflags & HPTE_V_BOLTED))
328 DBG_LOW(" full\n");
310 return -1; 329 return -1;
330 }
311 331
312 /* 332 /*
313 * Since we try and ioremap PHBs we don't own, the pte insert 333 * Since we try and ioremap PHBs we don't own, the pte insert
314 * will fail. However we must catch the failure in hash_page 334 * will fail. However we must catch the failure in hash_page
315 * or we will loop forever, so return -2 in this case. 335 * or we will loop forever, so return -2 in this case.
316 */ 336 */
317 if (unlikely(lpar_rc != H_Success)) 337 if (unlikely(lpar_rc != H_Success)) {
338 if (!(vflags & HPTE_V_BOLTED))
339 DBG_LOW(" lpar err %d\n", lpar_rc);
318 return -2; 340 return -2;
341 }
342 if (!(vflags & HPTE_V_BOLTED))
343 DBG_LOW(" -> slot: %d\n", slot & 7);
319 344
320 /* Because of iSeries, we have to pass down the secondary 345 /* Because of iSeries, we have to pass down the secondary
321 * bucket bit here as well 346 * bucket bit here as well
@@ -340,10 +365,8 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
340 /* don't remove a bolted entry */ 365 /* don't remove a bolted entry */
341 lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, 366 lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset,
342 (0x1UL << 4), &dummy1, &dummy2); 367 (0x1UL << 4), &dummy1, &dummy2);
343
344 if (lpar_rc == H_Success) 368 if (lpar_rc == H_Success)
345 return i; 369 return i;
346
347 BUG_ON(lpar_rc != H_Not_Found); 370 BUG_ON(lpar_rc != H_Not_Found);
348 371
349 slot_offset++; 372 slot_offset++;
@@ -371,20 +394,28 @@ static void pSeries_lpar_hptab_clear(void)
371 * We can probably optimize here and assume the high bits of newpp are 394 * We can probably optimize here and assume the high bits of newpp are
372 * already zero. For now I am paranoid. 395 * already zero. For now I am paranoid.
373 */ 396 */
374static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, 397static long pSeries_lpar_hpte_updatepp(unsigned long slot,
375 unsigned long va, int large, int local) 398 unsigned long newpp,
399 unsigned long va,
400 int psize, int local)
376{ 401{
377 unsigned long lpar_rc; 402 unsigned long lpar_rc;
378 unsigned long flags = (newpp & 7) | H_AVPN; 403 unsigned long flags = (newpp & 7) | H_AVPN;
379 unsigned long avpn = va >> 23; 404 unsigned long want_v;
380 405
381 if (large) 406 want_v = hpte_encode_v(va, psize);
382 avpn &= ~0x1UL;
383 407
384 lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7)); 408 DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ",
409 want_v & HPTE_V_AVPN, slot, flags, psize);
385 410
386 if (lpar_rc == H_Not_Found) 411 lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN);
412
413 if (lpar_rc == H_Not_Found) {
414 DBG_LOW("not found !\n");
387 return -1; 415 return -1;
416 }
417
418 DBG_LOW("ok\n");
388 419
389 BUG_ON(lpar_rc != H_Success); 420 BUG_ON(lpar_rc != H_Success);
390 421
@@ -410,21 +441,22 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
410 return dword0; 441 return dword0;
411} 442}
412 443
413static long pSeries_lpar_hpte_find(unsigned long vpn) 444static long pSeries_lpar_hpte_find(unsigned long va, int psize)
414{ 445{
415 unsigned long hash; 446 unsigned long hash;
416 unsigned long i, j; 447 unsigned long i, j;
417 long slot; 448 long slot;
418 unsigned long hpte_v; 449 unsigned long want_v, hpte_v;
419 450
420 hash = hpt_hash(vpn, 0); 451 hash = hpt_hash(va, mmu_psize_defs[psize].shift);
452 want_v = hpte_encode_v(va, psize);
421 453
422 for (j = 0; j < 2; j++) { 454 for (j = 0; j < 2; j++) {
423 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 455 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
424 for (i = 0; i < HPTES_PER_GROUP; i++) { 456 for (i = 0; i < HPTES_PER_GROUP; i++) {
425 hpte_v = pSeries_lpar_hpte_getword0(slot); 457 hpte_v = pSeries_lpar_hpte_getword0(slot);
426 458
427 if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11)) 459 if (HPTE_V_COMPARE(hpte_v, want_v)
428 && (hpte_v & HPTE_V_VALID) 460 && (hpte_v & HPTE_V_VALID)
429 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { 461 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
430 /* HPTE matches */ 462 /* HPTE matches */
@@ -441,17 +473,15 @@ static long pSeries_lpar_hpte_find(unsigned long vpn)
441} 473}
442 474
443static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, 475static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
444 unsigned long ea) 476 unsigned long ea,
477 int psize)
445{ 478{
446 unsigned long lpar_rc; 479 unsigned long lpar_rc, slot, vsid, va, flags;
447 unsigned long vsid, va, vpn, flags;
448 long slot;
449 480
450 vsid = get_kernel_vsid(ea); 481 vsid = get_kernel_vsid(ea);
451 va = (vsid << 28) | (ea & 0x0fffffff); 482 va = (vsid << 28) | (ea & 0x0fffffff);
452 vpn = va >> PAGE_SHIFT;
453 483
454 slot = pSeries_lpar_hpte_find(vpn); 484 slot = pSeries_lpar_hpte_find(va, psize);
455 BUG_ON(slot == -1); 485 BUG_ON(slot == -1);
456 486
457 flags = newpp & 7; 487 flags = newpp & 7;
@@ -461,18 +491,18 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
461} 491}
462 492
463static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, 493static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
464 int large, int local) 494 int psize, int local)
465{ 495{
466 unsigned long avpn = va >> 23; 496 unsigned long want_v;
467 unsigned long lpar_rc; 497 unsigned long lpar_rc;
468 unsigned long dummy1, dummy2; 498 unsigned long dummy1, dummy2;
469 499
470 if (large) 500 DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d",
471 avpn &= ~0x1UL; 501 slot, va, psize, local);
472
473 lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1,
474 &dummy2);
475 502
503 want_v = hpte_encode_v(va, psize);
504 lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN,
505 &dummy1, &dummy2);
476 if (lpar_rc == H_Not_Found) 506 if (lpar_rc == H_Not_Found)
477 return; 507 return;
478 508
@@ -494,7 +524,8 @@ void pSeries_lpar_flush_hash_range(unsigned long number, int local)
494 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); 524 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
495 525
496 for (i = 0; i < number; i++) 526 for (i = 0; i < number; i++)
497 flush_hash_page(batch->vaddr[i], batch->pte[i], local); 527 flush_hash_page(batch->vaddr[i], batch->pte[i],
528 batch->psize, local);
498 529
499 if (lock_tlbie) 530 if (lock_tlbie)
500 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); 531 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);