diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2013-03-12 23:34:54 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-03-16 21:39:06 -0400 |
commit | c60ac5693c47df32a2b4b18af97fca5635def015 (patch) | |
tree | 34da014c89f9a941f5c901fc06f4c3f5bca6ad43 /arch | |
parent | e39d1a471484662620651cd9520250d33843f235 (diff) |
powerpc: Update kernel VSID range
This patch change the kernel VSID range so that we limit VSID_BITS to 37.
This enables us to support 64TB with 65 bit VA (37+28). Without this patch
we have boot hangs on platforms that only support 65 bit VA.
With this patch we now have proto vsid generated as below:
We first generate a 37-bit "proto-VSID". Proto-VSIDs are generated
from mmu context id and effective segment id of the address.
For user processes max context id is limited to ((1ul << 19) - 5)
for kernel space, we use the top 4 context ids to map address as below
0x7fffc - [ 0xc000000000000000 - 0xc0003fffffffffff ]
0x7fffd - [ 0xd000000000000000 - 0xd0003fffffffffff ]
0x7fffe - [ 0xe000000000000000 - 0xe0003fffffffffff ]
0x7ffff - [ 0xf000000000000000 - 0xf0003fffffffffff ]
Acked-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Tested-by: Geoff Levand <geoff@infradead.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: <stable@vger.kernel.org> [v3.8]
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/mmu-hash64.h | 115 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 34 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 20 | ||||
-rw-r--r-- | arch/powerpc/mm/mmu_context_hash64.c | 11 | ||||
-rw-r--r-- | arch/powerpc/mm/slb_low.S | 50 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_hash64.c | 2 |
6 files changed, 126 insertions, 106 deletions
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 5f8c2bd58818..a32461f9d825 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -343,17 +343,16 @@ extern void slb_set_size(u16 size); | |||
343 | /* | 343 | /* |
344 | * VSID allocation (256MB segment) | 344 | * VSID allocation (256MB segment) |
345 | * | 345 | * |
346 | * We first generate a 38-bit "proto-VSID". For kernel addresses this | 346 | * We first generate a 37-bit "proto-VSID". Proto-VSIDs are generated |
347 | * is equal to the ESID | 1 << 37, for user addresses it is: | 347 | * from mmu context id and effective segment id of the address. |
348 | * (context << USER_ESID_BITS) | (esid & ((1U << USER_ESID_BITS) - 1) | ||
349 | * | 348 | * |
350 | * This splits the proto-VSID into the below range | 349 | * For user processes max context id is limited to ((1ul << 19) - 5) |
351 | * 0 - (2^(CONTEXT_BITS + USER_ESID_BITS) - 1) : User proto-VSID range | 350 | * for kernel space, we use the top 4 context ids to map address as below |
352 | * 2^(CONTEXT_BITS + USER_ESID_BITS) - 2^(VSID_BITS) : Kernel proto-VSID range | 351 | * NOTE: each context only support 64TB now. |
353 | * | 352 | * 0x7fffc - [ 0xc000000000000000 - 0xc0003fffffffffff ] |
354 | * We also have CONTEXT_BITS + USER_ESID_BITS = VSID_BITS - 1 | 353 | * 0x7fffd - [ 0xd000000000000000 - 0xd0003fffffffffff ] |
355 | * That is, we assign half of the space to user processes and half | 354 | * 0x7fffe - [ 0xe000000000000000 - 0xe0003fffffffffff ] |
356 | * to the kernel. | 355 | * 0x7ffff - [ 0xf000000000000000 - 0xf0003fffffffffff ] |
357 | * | 356 | * |
358 | * The proto-VSIDs are then scrambled into real VSIDs with the | 357 | * The proto-VSIDs are then scrambled into real VSIDs with the |
359 | * multiplicative hash: | 358 | * multiplicative hash: |
@@ -363,22 +362,19 @@ extern void slb_set_size(u16 size); | |||
363 | * VSID_MULTIPLIER is prime, so in particular it is | 362 | * VSID_MULTIPLIER is prime, so in particular it is |
364 | * co-prime to VSID_MODULUS, making this a 1:1 scrambling function. | 363 | * co-prime to VSID_MODULUS, making this a 1:1 scrambling function. |
365 | * Because the modulus is 2^n-1 we can compute it efficiently without | 364 | * Because the modulus is 2^n-1 we can compute it efficiently without |
366 | * a divide or extra multiply (see below). | 365 | * a divide or extra multiply (see below). The scramble function gives |
367 | * | 366 | * robust scattering in the hash table (at least based on some initial |
368 | * This scheme has several advantages over older methods: | 367 | * results). |
369 | * | 368 | * |
370 | * - We have VSIDs allocated for every kernel address | 369 | * We also consider VSID 0 special. We use VSID 0 for slb entries mapping |
371 | * (i.e. everything above 0xC000000000000000), except the very top | 370 | * bad address. This enables us to consolidate bad address handling in |
372 | * segment, which simplifies several things. | 371 | * hash_page. |
373 | * | 372 | * |
374 | * - We allow for USER_ESID_BITS significant bits of ESID and | 373 | * We also need to avoid the last segment of the last context, because that |
375 | * CONTEXT_BITS bits of context for user addresses. | 374 | * would give a protovsid of 0x1fffffffff. That will result in a VSID 0 |
376 | * i.e. 64T (46 bits) of address space for up to half a million contexts. | 375 | * because of the modulo operation in vsid scramble. But the vmemmap |
377 | * | 376 | * (which is what uses region 0xf) will never be close to 64TB in size |
378 | * - The scramble function gives robust scattering in the hash | 377 | * (it's 56 bytes per page of system memory). |
379 | * table (at least based on some initial results). The previous | ||
380 | * method was more susceptible to pathological cases giving excessive | ||
381 | * hash collisions. | ||
382 | */ | 378 | */ |
383 | 379 | ||
384 | #define CONTEXT_BITS 19 | 380 | #define CONTEXT_BITS 19 |
@@ -386,15 +382,25 @@ extern void slb_set_size(u16 size); | |||
386 | #define USER_ESID_BITS_1T 6 | 382 | #define USER_ESID_BITS_1T 6 |
387 | 383 | ||
388 | /* | 384 | /* |
385 | * 256MB segment | ||
386 | * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments | ||
387 | * available for user + kernel mapping. The top 4 contexts are used for | ||
388 | * kernel mapping. Each segment contains 2^28 bytes. Each | ||
389 | * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts | ||
390 | * (19 == 37 + 28 - 46). | ||
391 | */ | ||
392 | #define MAX_USER_CONTEXT ((ASM_CONST(1) << CONTEXT_BITS) - 5) | ||
393 | |||
394 | /* | ||
389 | * This should be computed such that protovosid * vsid_mulitplier | 395 | * This should be computed such that protovosid * vsid_mulitplier |
390 | * doesn't overflow 64 bits. It should also be co-prime to vsid_modulus | 396 | * doesn't overflow 64 bits. It should also be co-prime to vsid_modulus |
391 | */ | 397 | */ |
392 | #define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */ | 398 | #define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */ |
393 | #define VSID_BITS_256M (CONTEXT_BITS + USER_ESID_BITS + 1) | 399 | #define VSID_BITS_256M (CONTEXT_BITS + USER_ESID_BITS) |
394 | #define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1) | 400 | #define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1) |
395 | 401 | ||
396 | #define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */ | 402 | #define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */ |
397 | #define VSID_BITS_1T (CONTEXT_BITS + USER_ESID_BITS_1T + 1) | 403 | #define VSID_BITS_1T (CONTEXT_BITS + USER_ESID_BITS_1T) |
398 | #define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1) | 404 | #define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1) |
399 | 405 | ||
400 | 406 | ||
@@ -422,7 +428,8 @@ extern void slb_set_size(u16 size); | |||
422 | srdi rx,rt,VSID_BITS_##size; \ | 428 | srdi rx,rt,VSID_BITS_##size; \ |
423 | clrldi rt,rt,(64-VSID_BITS_##size); \ | 429 | clrldi rt,rt,(64-VSID_BITS_##size); \ |
424 | add rt,rt,rx; /* add high and low bits */ \ | 430 | add rt,rt,rx; /* add high and low bits */ \ |
425 | /* Now, r3 == VSID (mod 2^36-1), and lies between 0 and \ | 431 | /* NOTE: explanation based on VSID_BITS_##size = 36 \ |
432 | * Now, r3 == VSID (mod 2^36-1), and lies between 0 and \ | ||
426 | * 2^36-1+2^28-1. That in particular means that if r3 >= \ | 433 | * 2^36-1+2^28-1. That in particular means that if r3 >= \ |
427 | * 2^36-1, then r3+1 has the 2^36 bit set. So, if r3+1 has \ | 434 | * 2^36-1, then r3+1 has the 2^36 bit set. So, if r3+1 has \ |
428 | * the bit clear, r3 already has the answer we want, if it \ | 435 | * the bit clear, r3 already has the answer we want, if it \ |
@@ -514,34 +521,6 @@ typedef struct { | |||
514 | }) | 521 | }) |
515 | #endif /* 1 */ | 522 | #endif /* 1 */ |
516 | 523 | ||
517 | /* | ||
518 | * This is only valid for addresses >= PAGE_OFFSET | ||
519 | * The proto-VSID space is divided into two class | ||
520 | * User: 0 to 2^(CONTEXT_BITS + USER_ESID_BITS) -1 | ||
521 | * kernel: 2^(CONTEXT_BITS + USER_ESID_BITS) to 2^(VSID_BITS) - 1 | ||
522 | * | ||
523 | * With KERNEL_START at 0xc000000000000000, the proto vsid for | ||
524 | * the kernel ends up with 0xc00000000 (36 bits). With 64TB | ||
525 | * support we need to have kernel proto-VSID in the | ||
526 | * [2^37 to 2^38 - 1] range due to the increased USER_ESID_BITS. | ||
527 | */ | ||
528 | static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize) | ||
529 | { | ||
530 | unsigned long proto_vsid; | ||
531 | /* | ||
532 | * We need to make sure proto_vsid for the kernel is | ||
533 | * >= 2^(CONTEXT_BITS + USER_ESID_BITS[_1T]) | ||
534 | */ | ||
535 | if (ssize == MMU_SEGSIZE_256M) { | ||
536 | proto_vsid = ea >> SID_SHIFT; | ||
537 | proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS)); | ||
538 | return vsid_scramble(proto_vsid, 256M); | ||
539 | } | ||
540 | proto_vsid = ea >> SID_SHIFT_1T; | ||
541 | proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS_1T)); | ||
542 | return vsid_scramble(proto_vsid, 1T); | ||
543 | } | ||
544 | |||
545 | /* Returns the segment size indicator for a user address */ | 524 | /* Returns the segment size indicator for a user address */ |
546 | static inline int user_segment_size(unsigned long addr) | 525 | static inline int user_segment_size(unsigned long addr) |
547 | { | 526 | { |
@@ -551,10 +530,15 @@ static inline int user_segment_size(unsigned long addr) | |||
551 | return MMU_SEGSIZE_256M; | 530 | return MMU_SEGSIZE_256M; |
552 | } | 531 | } |
553 | 532 | ||
554 | /* This is only valid for user addresses (which are below 2^44) */ | ||
555 | static inline unsigned long get_vsid(unsigned long context, unsigned long ea, | 533 | static inline unsigned long get_vsid(unsigned long context, unsigned long ea, |
556 | int ssize) | 534 | int ssize) |
557 | { | 535 | { |
536 | /* | ||
537 | * Bad address. We return VSID 0 for that | ||
538 | */ | ||
539 | if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) | ||
540 | return 0; | ||
541 | |||
558 | if (ssize == MMU_SEGSIZE_256M) | 542 | if (ssize == MMU_SEGSIZE_256M) |
559 | return vsid_scramble((context << USER_ESID_BITS) | 543 | return vsid_scramble((context << USER_ESID_BITS) |
560 | | (ea >> SID_SHIFT), 256M); | 544 | | (ea >> SID_SHIFT), 256M); |
@@ -562,6 +546,25 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea, | |||
562 | | (ea >> SID_SHIFT_1T), 1T); | 546 | | (ea >> SID_SHIFT_1T), 1T); |
563 | } | 547 | } |
564 | 548 | ||
549 | /* | ||
550 | * This is only valid for addresses >= PAGE_OFFSET | ||
551 | * | ||
552 | * For kernel space, we use the top 4 context ids to map address as below | ||
553 | * 0x7fffc - [ 0xc000000000000000 - 0xc0003fffffffffff ] | ||
554 | * 0x7fffd - [ 0xd000000000000000 - 0xd0003fffffffffff ] | ||
555 | * 0x7fffe - [ 0xe000000000000000 - 0xe0003fffffffffff ] | ||
556 | * 0x7ffff - [ 0xf000000000000000 - 0xf0003fffffffffff ] | ||
557 | */ | ||
558 | static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize) | ||
559 | { | ||
560 | unsigned long context; | ||
561 | |||
562 | /* | ||
563 | * kernel take the top 4 context from the available range | ||
564 | */ | ||
565 | context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1; | ||
566 | return get_vsid(context, ea, ssize); | ||
567 | } | ||
565 | #endif /* __ASSEMBLY__ */ | 568 | #endif /* __ASSEMBLY__ */ |
566 | 569 | ||
567 | #endif /* _ASM_POWERPC_MMU_HASH64_H_ */ | 570 | #endif /* _ASM_POWERPC_MMU_HASH64_H_ */ |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 87ef8f5ee5bc..b112359ea7a8 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -1452,20 +1452,36 @@ do_ste_alloc: | |||
1452 | _GLOBAL(do_stab_bolted) | 1452 | _GLOBAL(do_stab_bolted) |
1453 | stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ | 1453 | stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ |
1454 | std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ | 1454 | std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ |
1455 | mfspr r11,SPRN_DAR /* ea */ | ||
1455 | 1456 | ||
1457 | /* | ||
1458 | * check for bad kernel/user address | ||
1459 | * (ea & ~REGION_MASK) >= PGTABLE_RANGE | ||
1460 | */ | ||
1461 | rldicr. r9,r11,4,(63 - 46 - 4) | ||
1462 | li r9,0 /* VSID = 0 for bad address */ | ||
1463 | bne- 0f | ||
1464 | |||
1465 | /* | ||
1466 | * Calculate VSID: | ||
1467 | * This is the kernel vsid, we take the top for context from | ||
1468 | * the range. context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1 | ||
1469 | * Here we know that (ea >> 60) == 0xc | ||
1470 | */ | ||
1471 | lis r9,(MAX_USER_CONTEXT + 1)@ha | ||
1472 | addi r9,r9,(MAX_USER_CONTEXT + 1)@l | ||
1473 | |||
1474 | srdi r10,r11,SID_SHIFT | ||
1475 | rldimi r10,r9,USER_ESID_BITS,0 /* proto vsid */ | ||
1476 | ASM_VSID_SCRAMBLE(r10, r9, 256M) | ||
1477 | rldic r9,r10,12,16 /* r9 = vsid << 12 */ | ||
1478 | |||
1479 | 0: | ||
1456 | /* Hash to the primary group */ | 1480 | /* Hash to the primary group */ |
1457 | ld r10,PACASTABVIRT(r13) | 1481 | ld r10,PACASTABVIRT(r13) |
1458 | mfspr r11,SPRN_DAR | 1482 | srdi r11,r11,SID_SHIFT |
1459 | srdi r11,r11,28 | ||
1460 | rldimi r10,r11,7,52 /* r10 = first ste of the group */ | 1483 | rldimi r10,r11,7,52 /* r10 = first ste of the group */ |
1461 | 1484 | ||
1462 | /* Calculate VSID */ | ||
1463 | /* This is a kernel address, so protovsid = ESID | 1 << 37 */ | ||
1464 | li r9,0x1 | ||
1465 | rldimi r11,r9,(CONTEXT_BITS + USER_ESID_BITS),0 | ||
1466 | ASM_VSID_SCRAMBLE(r11, r9, 256M) | ||
1467 | rldic r9,r11,12,16 /* r9 = vsid << 12 */ | ||
1468 | |||
1469 | /* Search the primary group for a free entry */ | 1485 | /* Search the primary group for a free entry */ |
1470 | 1: ld r11,0(r10) /* Test valid bit of the current ste */ | 1486 | 1: ld r11,0(r10) /* Test valid bit of the current ste */ |
1471 | andi. r11,r11,0x80 | 1487 | andi. r11,r11,0x80 |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 6ec6c1997b3a..f410c3e12c1e 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -195,6 +195,11 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
195 | unsigned long vpn = hpt_vpn(vaddr, vsid, ssize); | 195 | unsigned long vpn = hpt_vpn(vaddr, vsid, ssize); |
196 | unsigned long tprot = prot; | 196 | unsigned long tprot = prot; |
197 | 197 | ||
198 | /* | ||
199 | * If we hit a bad address return error. | ||
200 | */ | ||
201 | if (!vsid) | ||
202 | return -1; | ||
198 | /* Make kernel text executable */ | 203 | /* Make kernel text executable */ |
199 | if (overlaps_kernel_text(vaddr, vaddr + step)) | 204 | if (overlaps_kernel_text(vaddr, vaddr + step)) |
200 | tprot &= ~HPTE_R_N; | 205 | tprot &= ~HPTE_R_N; |
@@ -924,11 +929,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
924 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", | 929 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", |
925 | ea, access, trap); | 930 | ea, access, trap); |
926 | 931 | ||
927 | if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) { | ||
928 | DBG_LOW(" out of pgtable range !\n"); | ||
929 | return 1; | ||
930 | } | ||
931 | |||
932 | /* Get region & vsid */ | 932 | /* Get region & vsid */ |
933 | switch (REGION_ID(ea)) { | 933 | switch (REGION_ID(ea)) { |
934 | case USER_REGION_ID: | 934 | case USER_REGION_ID: |
@@ -959,6 +959,11 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
959 | } | 959 | } |
960 | DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); | 960 | DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); |
961 | 961 | ||
962 | /* Bad address. */ | ||
963 | if (!vsid) { | ||
964 | DBG_LOW("Bad address!\n"); | ||
965 | return 1; | ||
966 | } | ||
962 | /* Get pgdir */ | 967 | /* Get pgdir */ |
963 | pgdir = mm->pgd; | 968 | pgdir = mm->pgd; |
964 | if (pgdir == NULL) | 969 | if (pgdir == NULL) |
@@ -1128,6 +1133,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1128 | /* Get VSID */ | 1133 | /* Get VSID */ |
1129 | ssize = user_segment_size(ea); | 1134 | ssize = user_segment_size(ea); |
1130 | vsid = get_vsid(mm->context.id, ea, ssize); | 1135 | vsid = get_vsid(mm->context.id, ea, ssize); |
1136 | if (!vsid) | ||
1137 | return; | ||
1131 | 1138 | ||
1132 | /* Hash doesn't like irqs */ | 1139 | /* Hash doesn't like irqs */ |
1133 | local_irq_save(flags); | 1140 | local_irq_save(flags); |
@@ -1235,6 +1242,9 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) | |||
1235 | hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); | 1242 | hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); |
1236 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | 1243 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); |
1237 | 1244 | ||
1245 | /* Don't create HPTE entries for bad address */ | ||
1246 | if (!vsid) | ||
1247 | return; | ||
1238 | ret = ppc_md.hpte_insert(hpteg, vpn, __pa(vaddr), | 1248 | ret = ppc_md.hpte_insert(hpteg, vpn, __pa(vaddr), |
1239 | mode, HPTE_V_BOLTED, | 1249 | mode, HPTE_V_BOLTED, |
1240 | mmu_linear_psize, mmu_kernel_ssize); | 1250 | mmu_linear_psize, mmu_kernel_ssize); |
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 40bc5b0ace54..d1d1b92c5b99 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c | |||
@@ -29,15 +29,6 @@ | |||
29 | static DEFINE_SPINLOCK(mmu_context_lock); | 29 | static DEFINE_SPINLOCK(mmu_context_lock); |
30 | static DEFINE_IDA(mmu_context_ida); | 30 | static DEFINE_IDA(mmu_context_ida); |
31 | 31 | ||
32 | /* | ||
33 | * 256MB segment | ||
34 | * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments | ||
35 | * available for user mappings. Each segment contains 2^28 bytes. Each | ||
36 | * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts | ||
37 | * (19 == 37 + 28 - 46). | ||
38 | */ | ||
39 | #define MAX_CONTEXT ((1UL << CONTEXT_BITS) - 1) | ||
40 | |||
41 | int __init_new_context(void) | 32 | int __init_new_context(void) |
42 | { | 33 | { |
43 | int index; | 34 | int index; |
@@ -56,7 +47,7 @@ again: | |||
56 | else if (err) | 47 | else if (err) |
57 | return err; | 48 | return err; |
58 | 49 | ||
59 | if (index > MAX_CONTEXT) { | 50 | if (index > MAX_USER_CONTEXT) { |
60 | spin_lock(&mmu_context_lock); | 51 | spin_lock(&mmu_context_lock); |
61 | ida_remove(&mmu_context_ida, index); | 52 | ida_remove(&mmu_context_ida, index); |
62 | spin_unlock(&mmu_context_lock); | 53 | spin_unlock(&mmu_context_lock); |
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 1a16ca227757..77aafaa1ab09 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S | |||
@@ -31,10 +31,15 @@ | |||
31 | * No other registers are examined or changed. | 31 | * No other registers are examined or changed. |
32 | */ | 32 | */ |
33 | _GLOBAL(slb_allocate_realmode) | 33 | _GLOBAL(slb_allocate_realmode) |
34 | /* r3 = faulting address */ | 34 | /* |
35 | * check for bad kernel/user address | ||
36 | * (ea & ~REGION_MASK) >= PGTABLE_RANGE | ||
37 | */ | ||
38 | rldicr. r9,r3,4,(63 - 46 - 4) | ||
39 | bne- 8f | ||
35 | 40 | ||
36 | srdi r9,r3,60 /* get region */ | 41 | srdi r9,r3,60 /* get region */ |
37 | srdi r10,r3,28 /* get esid */ | 42 | srdi r10,r3,SID_SHIFT /* get esid */ |
38 | cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ | 43 | cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ |
39 | 44 | ||
40 | /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ | 45 | /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ |
@@ -56,12 +61,14 @@ _GLOBAL(slb_allocate_realmode) | |||
56 | */ | 61 | */ |
57 | _GLOBAL(slb_miss_kernel_load_linear) | 62 | _GLOBAL(slb_miss_kernel_load_linear) |
58 | li r11,0 | 63 | li r11,0 |
59 | li r9,0x1 | ||
60 | /* | 64 | /* |
61 | * for 1T we shift 12 bits more. slb_finish_load_1T will do | 65 | * context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1 |
62 | * the necessary adjustment | 66 | * r9 = region id. |
63 | */ | 67 | */ |
64 | rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0 | 68 | addis r9,r9,(MAX_USER_CONTEXT - 0xc + 1)@ha |
69 | addi r9,r9,(MAX_USER_CONTEXT - 0xc + 1)@l | ||
70 | |||
71 | |||
65 | BEGIN_FTR_SECTION | 72 | BEGIN_FTR_SECTION |
66 | b slb_finish_load | 73 | b slb_finish_load |
67 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) | 74 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) |
@@ -91,24 +98,19 @@ _GLOBAL(slb_miss_kernel_load_vmemmap) | |||
91 | _GLOBAL(slb_miss_kernel_load_io) | 98 | _GLOBAL(slb_miss_kernel_load_io) |
92 | li r11,0 | 99 | li r11,0 |
93 | 6: | 100 | 6: |
94 | li r9,0x1 | ||
95 | /* | 101 | /* |
96 | * for 1T we shift 12 bits more. slb_finish_load_1T will do | 102 | * context = (MAX_USER_CONTEXT) + ((ea >> 60) - 0xc) + 1 |
97 | * the necessary adjustment | 103 | * r9 = region id. |
98 | */ | 104 | */ |
99 | rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0 | 105 | addis r9,r9,(MAX_USER_CONTEXT - 0xc + 1)@ha |
106 | addi r9,r9,(MAX_USER_CONTEXT - 0xc + 1)@l | ||
107 | |||
100 | BEGIN_FTR_SECTION | 108 | BEGIN_FTR_SECTION |
101 | b slb_finish_load | 109 | b slb_finish_load |
102 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) | 110 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) |
103 | b slb_finish_load_1T | 111 | b slb_finish_load_1T |
104 | 112 | ||
105 | 0: /* user address: proto-VSID = context << 15 | ESID. First check | 113 | 0: |
106 | * if the address is within the boundaries of the user region | ||
107 | */ | ||
108 | srdi. r9,r10,USER_ESID_BITS | ||
109 | bne- 8f /* invalid ea bits set */ | ||
110 | |||
111 | |||
112 | /* when using slices, we extract the psize off the slice bitmaps | 114 | /* when using slices, we extract the psize off the slice bitmaps |
113 | * and then we need to get the sllp encoding off the mmu_psize_defs | 115 | * and then we need to get the sllp encoding off the mmu_psize_defs |
114 | * array. | 116 | * array. |
@@ -164,15 +166,13 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) | |||
164 | ld r9,PACACONTEXTID(r13) | 166 | ld r9,PACACONTEXTID(r13) |
165 | BEGIN_FTR_SECTION | 167 | BEGIN_FTR_SECTION |
166 | cmpldi r10,0x1000 | 168 | cmpldi r10,0x1000 |
167 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) | ||
168 | rldimi r10,r9,USER_ESID_BITS,0 | ||
169 | BEGIN_FTR_SECTION | ||
170 | bge slb_finish_load_1T | 169 | bge slb_finish_load_1T |
171 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) | 170 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) |
172 | b slb_finish_load | 171 | b slb_finish_load |
173 | 172 | ||
174 | 8: /* invalid EA */ | 173 | 8: /* invalid EA */ |
175 | li r10,0 /* BAD_VSID */ | 174 | li r10,0 /* BAD_VSID */ |
175 | li r9,0 /* BAD_VSID */ | ||
176 | li r11,SLB_VSID_USER /* flags don't much matter */ | 176 | li r11,SLB_VSID_USER /* flags don't much matter */ |
177 | b slb_finish_load | 177 | b slb_finish_load |
178 | 178 | ||
@@ -221,8 +221,6 @@ _GLOBAL(slb_allocate_user) | |||
221 | 221 | ||
222 | /* get context to calculate proto-VSID */ | 222 | /* get context to calculate proto-VSID */ |
223 | ld r9,PACACONTEXTID(r13) | 223 | ld r9,PACACONTEXTID(r13) |
224 | rldimi r10,r9,USER_ESID_BITS,0 | ||
225 | |||
226 | /* fall through slb_finish_load */ | 224 | /* fall through slb_finish_load */ |
227 | 225 | ||
228 | #endif /* __DISABLED__ */ | 226 | #endif /* __DISABLED__ */ |
@@ -231,9 +229,10 @@ _GLOBAL(slb_allocate_user) | |||
231 | /* | 229 | /* |
232 | * Finish loading of an SLB entry and return | 230 | * Finish loading of an SLB entry and return |
233 | * | 231 | * |
234 | * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET | 232 | * r3 = EA, r9 = context, r10 = ESID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET |
235 | */ | 233 | */ |
236 | slb_finish_load: | 234 | slb_finish_load: |
235 | rldimi r10,r9,USER_ESID_BITS,0 | ||
237 | ASM_VSID_SCRAMBLE(r10,r9,256M) | 236 | ASM_VSID_SCRAMBLE(r10,r9,256M) |
238 | /* | 237 | /* |
239 | * bits above VSID_BITS_256M need to be ignored from r10 | 238 | * bits above VSID_BITS_256M need to be ignored from r10 |
@@ -298,10 +297,11 @@ _GLOBAL(slb_compare_rr_to_size) | |||
298 | /* | 297 | /* |
299 | * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. | 298 | * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. |
300 | * | 299 | * |
301 | * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 | 300 | * r3 = EA, r9 = context, r10 = ESID(256MB), r11 = flags, clobbers r9 |
302 | */ | 301 | */ |
303 | slb_finish_load_1T: | 302 | slb_finish_load_1T: |
304 | srdi r10,r10,40-28 /* get 1T ESID */ | 303 | srdi r10,r10,(SID_SHIFT_1T - SID_SHIFT) /* get 1T ESID */ |
304 | rldimi r10,r9,USER_ESID_BITS_1T,0 | ||
305 | ASM_VSID_SCRAMBLE(r10,r9,1T) | 305 | ASM_VSID_SCRAMBLE(r10,r9,1T) |
306 | /* | 306 | /* |
307 | * bits above VSID_BITS_1T need to be ignored from r10 | 307 | * bits above VSID_BITS_1T need to be ignored from r10 |
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c index 0d82ef50dc3f..023ec8a13f38 100644 --- a/arch/powerpc/mm/tlb_hash64.c +++ b/arch/powerpc/mm/tlb_hash64.c | |||
@@ -82,11 +82,11 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, | |||
82 | if (!is_kernel_addr(addr)) { | 82 | if (!is_kernel_addr(addr)) { |
83 | ssize = user_segment_size(addr); | 83 | ssize = user_segment_size(addr); |
84 | vsid = get_vsid(mm->context.id, addr, ssize); | 84 | vsid = get_vsid(mm->context.id, addr, ssize); |
85 | WARN_ON(vsid == 0); | ||
86 | } else { | 85 | } else { |
87 | vsid = get_kernel_vsid(addr, mmu_kernel_ssize); | 86 | vsid = get_kernel_vsid(addr, mmu_kernel_ssize); |
88 | ssize = mmu_kernel_ssize; | 87 | ssize = mmu_kernel_ssize; |
89 | } | 88 | } |
89 | WARN_ON(vsid == 0); | ||
90 | vpn = hpt_vpn(addr, vsid, ssize); | 90 | vpn = hpt_vpn(addr, vsid, ssize); |
91 | rpte = __real_pte(__pte(pte), ptep); | 91 | rpte = __real_pte(__pte(pte), ptep); |
92 | 92 | ||