aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-09 00:57:43 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-14 00:13:53 -0400
commitf2b26c923518e03959142715a2b7615cb161cd16 (patch)
treeffccea3aa71c68a143ef151dfa5673cb0aa3a9b4
parent03247157f73912c98baa918cf46b98ee5483d7f8 (diff)
powerpc/book3e: Adjust the page sizes list based on MMU config
Use the MMU config registers to scan for available direct and indirect page sizes and print out the result. Will be needed for future hugetlbfs implementation. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h4
-rw-r--r--arch/powerpc/include/asm/reg_booke.h1
-rw-r--r--arch/powerpc/mm/tlb_nohash.c136
3 files changed, 109 insertions, 32 deletions
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 74695816205..87a1d787c5b 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -193,6 +193,10 @@ struct mmu_psize_def
193{ 193{
194 unsigned int shift; /* number of bits */ 194 unsigned int shift; /* number of bits */
195 unsigned int enc; /* PTE encoding */ 195 unsigned int enc; /* PTE encoding */
196 unsigned int ind; /* Corresponding indirect page size shift */
197 unsigned int flags;
198#define MMU_PAGE_SIZE_DIRECT 0x1 /* Supported as a direct size */
199#define MMU_PAGE_SIZE_INDIRECT 0x2 /* Supported as an indirect size */
196}; 200};
197extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; 201extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
198 202
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 66dc6f0d3ad..667a498eaee 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -62,6 +62,7 @@
62#define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ 62#define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */
63#define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ 63#define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */
64#define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ 64#define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */
65#define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */
65#define SPRN_MAS7_MAS3 0x174 /* MMU Assist Register 7 || 3 */ 66#define SPRN_MAS7_MAS3 0x174 /* MMU Assist Register 7 || 3 */
66#define SPRN_MAS0_MAS1 0x175 /* MMU Assist Register 0 || 1 */ 67#define SPRN_MAS0_MAS1 0x175 /* MMU Assist Register 0 || 1 */
67#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */ 68#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index 2ce42bf1f67..3b10f804b73 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -46,6 +46,7 @@
46struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { 46struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
47 [MMU_PAGE_4K] = { 47 [MMU_PAGE_4K] = {
48 .shift = 12, 48 .shift = 12,
49 .ind = 20,
49 .enc = BOOK3E_PAGESZ_4K, 50 .enc = BOOK3E_PAGESZ_4K,
50 }, 51 },
51 [MMU_PAGE_16K] = { 52 [MMU_PAGE_16K] = {
@@ -54,6 +55,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
54 }, 55 },
55 [MMU_PAGE_64K] = { 56 [MMU_PAGE_64K] = {
56 .shift = 16, 57 .shift = 16,
58 .ind = 28,
57 .enc = BOOK3E_PAGESZ_64K, 59 .enc = BOOK3E_PAGESZ_64K,
58 }, 60 },
59 [MMU_PAGE_1M] = { 61 [MMU_PAGE_1M] = {
@@ -62,6 +64,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
62 }, 64 },
63 [MMU_PAGE_16M] = { 65 [MMU_PAGE_16M] = {
64 .shift = 24, 66 .shift = 24,
67 .ind = 36,
65 .enc = BOOK3E_PAGESZ_16M, 68 .enc = BOOK3E_PAGESZ_16M,
66 }, 69 },
67 [MMU_PAGE_256M] = { 70 [MMU_PAGE_256M] = {
@@ -344,16 +347,108 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
344 } 347 }
345} 348}
346 349
347/* 350static void setup_page_sizes(void)
348 * Early initialization of the MMU TLB code 351{
349 */ 352 unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
350static void __early_init_mmu(int boot_cpu) 353 unsigned int tlb0ps = mfspr(SPRN_TLB0PS);
354 unsigned int eptcfg = mfspr(SPRN_EPTCFG);
355 int i, psize;
356
357 /* Look for supported direct sizes */
358 for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
359 struct mmu_psize_def *def = &mmu_psize_defs[psize];
360
361 if (tlb0ps & (1U << (def->shift - 10)))
362 def->flags |= MMU_PAGE_SIZE_DIRECT;
363 }
364
365 /* Indirect page sizes supported ? */
366 if ((tlb0cfg & TLBnCFG_IND) == 0)
367 goto no_indirect;
368
369 /* Now, we only deal with one IND page size for each
370 * direct size. Hopefully all implementations today are
371 * unambiguous, but we might want to be careful in the
372 * future.
373 */
374 for (i = 0; i < 3; i++) {
375 unsigned int ps, sps;
376
377 sps = eptcfg & 0x1f;
378 eptcfg >>= 5;
379 ps = eptcfg & 0x1f;
380 eptcfg >>= 5;
381 if (!ps || !sps)
382 continue;
383 for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
384 struct mmu_psize_def *def = &mmu_psize_defs[psize];
385
386 if (ps == (def->shift - 10))
387 def->flags |= MMU_PAGE_SIZE_INDIRECT;
388 if (sps == (def->shift - 10))
389 def->ind = ps + 10;
390 }
391 }
392 no_indirect:
393
394 /* Cleanup array and print summary */
395 pr_info("MMU: Supported page sizes\n");
396 for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
397 struct mmu_psize_def *def = &mmu_psize_defs[psize];
398 const char *__page_type_names[] = {
399 "unsupported",
400 "direct",
401 "indirect",
402 "direct & indirect"
403 };
404 if (def->flags == 0) {
405 def->shift = 0;
406 continue;
407 }
408 pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10),
409 __page_type_names[def->flags & 0x3]);
410 }
411}
412
413static void setup_mmu_htw(void)
351{ 414{
352 extern unsigned int interrupt_base_book3e; 415 extern unsigned int interrupt_base_book3e;
353 extern unsigned int exc_data_tlb_miss_htw_book3e; 416 extern unsigned int exc_data_tlb_miss_htw_book3e;
354 extern unsigned int exc_instruction_tlb_miss_htw_book3e; 417 extern unsigned int exc_instruction_tlb_miss_htw_book3e;
355 418
356 unsigned int *ibase = &interrupt_base_book3e; 419 unsigned int *ibase = &interrupt_base_book3e;
420
421 /* Check if HW tablewalk is present, and if yes, enable it by:
422 *
423 * - patching the TLB miss handlers to branch to the
424 * one dedicates to it
425 *
426 * - setting the global book3e_htw_enabled
427 */
428 unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
429
430 if ((tlb0cfg & TLBnCFG_IND) &&
431 (tlb0cfg & TLBnCFG_PT)) {
432 /* Our exceptions vectors start with a NOP and -then- a branch
433 * to deal with single stepping from userspace which stops on
434 * the second instruction. Thus we need to patch the second
435 * instruction of the exception, not the first one
436 */
437 patch_branch(ibase + (0x1c0 / 4) + 1,
438 (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
439 patch_branch(ibase + (0x1e0 / 4) + 1,
440 (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
441 book3e_htw_enabled = 1;
442 }
443 pr_info("MMU: Book3E Page Tables %s\n",
444 book3e_htw_enabled ? "Enabled" : "Disabled");
445}
446
447/*
448 * Early initialization of the MMU TLB code
449 */
450static void __early_init_mmu(int boot_cpu)
451{
357 unsigned int mas4; 452 unsigned int mas4;
358 453
359 /* XXX This will have to be decided at runtime, but right 454 /* XXX This will have to be decided at runtime, but right
@@ -370,40 +465,17 @@ static void __early_init_mmu(int boot_cpu)
370 */ 465 */
371 mmu_vmemmap_psize = MMU_PAGE_16M; 466 mmu_vmemmap_psize = MMU_PAGE_16M;
372 467
373 /* Check if HW tablewalk is present, and if yes, enable it by:
374 *
375 * - patching the TLB miss handlers to branch to the
376 * one dedicates to it
377 *
378 * - setting the global book3e_htw_enabled
379 *
380 * - Set MAS4:INDD and default page size
381 */
382
383 /* XXX This code only checks for TLB 0 capabilities and doesn't 468 /* XXX This code only checks for TLB 0 capabilities and doesn't
384 * check what page size combos are supported by the HW. It 469 * check what page size combos are supported by the HW. It
385 * also doesn't handle the case where a separate array holds 470 * also doesn't handle the case where a separate array holds
386 * the IND entries from the array loaded by the PT. 471 * the IND entries from the array loaded by the PT.
387 */ 472 */
388 if (boot_cpu) { 473 if (boot_cpu) {
389 unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG); 474 /* Look for supported page sizes */
390 475 setup_page_sizes();
391 /* Check if HW loader is supported */ 476
392 if ((tlb0cfg & TLBnCFG_IND) && 477 /* Look for HW tablewalk support */
393 (tlb0cfg & TLBnCFG_PT)) { 478 setup_mmu_htw();
394 /* Our exceptions vectors start with a NOP and -then- a branch
395 * to deal with single stepping from userspace which stops on
396 * the second instruction. Thus we need to patch the second
397 * instruction of the exception, not the first one
398 */
399 patch_branch(ibase + (0x1c0 / 4) + 1,
400 (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
401 patch_branch(ibase + (0x1e0 / 4) + 1,
402 (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
403 book3e_htw_enabled = 1;
404 }
405 pr_info("MMU: Book3E Page Tables %s\n",
406 book3e_htw_enabled ? "Enabled" : "Disabled");
407 } 479 }
408 480
409 /* Set MAS4 based on page table setting */ 481 /* Set MAS4 based on page table setting */