aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include/asm/mmu-hash64.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/include/asm/mmu-hash64.h')
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h128
1 files changed, 66 insertions, 62 deletions
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 2fdb47a19efd..b59e06f507ea 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,41 +362,49 @@ 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 *
370 * - We have VSIDs allocated for every kernel address
371 * (i.e. everything above 0xC000000000000000), except the very top
372 * segment, which simplifies several things.
373 * 368 *
374 * - We allow for USER_ESID_BITS significant bits of ESID and 369 * We also consider VSID 0 special. We use VSID 0 for slb entries mapping
375 * CONTEXT_BITS bits of context for user addresses. 370 * bad address. This enables us to consolidate bad address handling in
376 * i.e. 64T (46 bits) of address space for up to half a million contexts. 371 * hash_page.
377 * 372 *
378 * - The scramble function gives robust scattering in the hash 373 * We also need to avoid the last segment of the last context, because that
379 * table (at least based on some initial results). The previous 374 * would give a protovsid of 0x1fffffffff. That will result in a VSID 0
380 * method was more susceptible to pathological cases giving excessive 375 * because of the modulo operation in vsid scramble. But the vmemmap
381 * hash collisions. 376 * (which is what uses region 0xf) will never be close to 64TB in size
377 * (it's 56 bytes per page of system memory).
382 */ 378 */
383 379
380#define CONTEXT_BITS 19
381#define ESID_BITS 18
382#define ESID_BITS_1T 6
383
384/*
385 * 256MB segment
386 * The proto-VSID space has 2^(CONTEX_BITS + 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
384/* 394/*
385 * This should be computed such that protovosid * vsid_mulitplier 395 * This should be computed such that protovosid * vsid_mulitplier
386 * 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
387 */ 397 */
388#define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */ 398#define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */
389#define VSID_BITS_256M 38 399#define VSID_BITS_256M (CONTEXT_BITS + ESID_BITS)
390#define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1) 400#define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1)
391 401
392#define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */ 402#define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */
393#define VSID_BITS_1T 26 403#define VSID_BITS_1T (CONTEXT_BITS + ESID_BITS_1T)
394#define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1) 404#define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1)
395 405
396#define CONTEXT_BITS 19
397#define USER_ESID_BITS 18
398#define USER_ESID_BITS_1T 6
399 406
400#define USER_VSID_RANGE (1UL << (USER_ESID_BITS + SID_SHIFT)) 407#define USER_VSID_RANGE (1UL << (ESID_BITS + SID_SHIFT))
401 408
402/* 409/*
403 * This macro generates asm code to compute the VSID scramble 410 * This macro generates asm code to compute the VSID scramble
@@ -421,7 +428,8 @@ extern void slb_set_size(u16 size);
421 srdi rx,rt,VSID_BITS_##size; \ 428 srdi rx,rt,VSID_BITS_##size; \
422 clrldi rt,rt,(64-VSID_BITS_##size); \ 429 clrldi rt,rt,(64-VSID_BITS_##size); \
423 add rt,rt,rx; /* add high and low bits */ \ 430 add rt,rt,rx; /* add high and low bits */ \
424 /* 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 \
425 * 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 >= \
426 * 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 \
427 * 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 \
@@ -513,34 +521,6 @@ typedef struct {
513 }) 521 })
514#endif /* 1 */ 522#endif /* 1 */
515 523
516/*
517 * This is only valid for addresses >= PAGE_OFFSET
518 * The proto-VSID space is divided into two class
519 * User: 0 to 2^(CONTEXT_BITS + USER_ESID_BITS) -1
520 * kernel: 2^(CONTEXT_BITS + USER_ESID_BITS) to 2^(VSID_BITS) - 1
521 *
522 * With KERNEL_START at 0xc000000000000000, the proto vsid for
523 * the kernel ends up with 0xc00000000 (36 bits). With 64TB
524 * support we need to have kernel proto-VSID in the
525 * [2^37 to 2^38 - 1] range due to the increased USER_ESID_BITS.
526 */
527static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize)
528{
529 unsigned long proto_vsid;
530 /*
531 * We need to make sure proto_vsid for the kernel is
532 * >= 2^(CONTEXT_BITS + USER_ESID_BITS[_1T])
533 */
534 if (ssize == MMU_SEGSIZE_256M) {
535 proto_vsid = ea >> SID_SHIFT;
536 proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS));
537 return vsid_scramble(proto_vsid, 256M);
538 }
539 proto_vsid = ea >> SID_SHIFT_1T;
540 proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS_1T));
541 return vsid_scramble(proto_vsid, 1T);
542}
543
544/* Returns the segment size indicator for a user address */ 524/* Returns the segment size indicator for a user address */
545static inline int user_segment_size(unsigned long addr) 525static inline int user_segment_size(unsigned long addr)
546{ 526{
@@ -550,17 +530,41 @@ static inline int user_segment_size(unsigned long addr)
550 return MMU_SEGSIZE_256M; 530 return MMU_SEGSIZE_256M;
551} 531}
552 532
553/* This is only valid for user addresses (which are below 2^44) */
554static inline unsigned long get_vsid(unsigned long context, unsigned long ea, 533static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
555 int ssize) 534 int ssize)
556{ 535{
536 /*
537 * Bad address. We return VSID 0 for that
538 */
539 if ((ea & ~REGION_MASK) >= PGTABLE_RANGE)
540 return 0;
541
557 if (ssize == MMU_SEGSIZE_256M) 542 if (ssize == MMU_SEGSIZE_256M)
558 return vsid_scramble((context << USER_ESID_BITS) 543 return vsid_scramble((context << ESID_BITS)
559 | (ea >> SID_SHIFT), 256M); 544 | (ea >> SID_SHIFT), 256M);
560 return vsid_scramble((context << USER_ESID_BITS_1T) 545 return vsid_scramble((context << ESID_BITS_1T)
561 | (ea >> SID_SHIFT_1T), 1T); 546 | (ea >> SID_SHIFT_1T), 1T);
562} 547}
563 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 */
558static 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}
564#endif /* __ASSEMBLY__ */ 568#endif /* __ASSEMBLY__ */
565 569
566#endif /* _ASM_POWERPC_MMU_HASH64_H_ */ 570#endif /* _ASM_POWERPC_MMU_HASH64_H_ */