diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 115 |
1 files changed, 73 insertions, 42 deletions
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index e384a5a91796..ab0c6dd6ec94 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 | ||
278 | long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 278 | long 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 | */ |
374 | static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, | 397 | static 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 | ||
413 | static long pSeries_lpar_hpte_find(unsigned long vpn) | 444 | static 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 | ||
443 | static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, | 475 | static 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 | ||
463 | static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | 493 | static 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); |