diff options
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r-- | arch/sparc/mm/init_64.c | 101 | ||||
-rw-r--r-- | arch/sparc/mm/tsb.c | 9 |
2 files changed, 110 insertions, 0 deletions
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 809eecf6c797..12ef4ea60c88 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -2467,3 +2467,104 @@ void __flush_tlb_all(void) | |||
2467 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | 2467 | __asm__ __volatile__("wrpr %0, 0, %%pstate" |
2468 | : : "r" (pstate)); | 2468 | : : "r" (pstate)); |
2469 | } | 2469 | } |
2470 | |||
2471 | static pte_t *get_from_cache(struct mm_struct *mm) | ||
2472 | { | ||
2473 | struct page *page; | ||
2474 | pte_t *ret; | ||
2475 | |||
2476 | spin_lock(&mm->page_table_lock); | ||
2477 | page = mm->context.pgtable_page; | ||
2478 | ret = NULL; | ||
2479 | if (page) { | ||
2480 | void *p = page_address(page); | ||
2481 | |||
2482 | mm->context.pgtable_page = NULL; | ||
2483 | |||
2484 | ret = (pte_t *) (p + (PAGE_SIZE / 2)); | ||
2485 | } | ||
2486 | spin_unlock(&mm->page_table_lock); | ||
2487 | |||
2488 | return ret; | ||
2489 | } | ||
2490 | |||
2491 | static struct page *__alloc_for_cache(struct mm_struct *mm) | ||
2492 | { | ||
2493 | struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | | ||
2494 | __GFP_REPEAT | __GFP_ZERO); | ||
2495 | |||
2496 | if (page) { | ||
2497 | spin_lock(&mm->page_table_lock); | ||
2498 | if (!mm->context.pgtable_page) { | ||
2499 | atomic_set(&page->_count, 2); | ||
2500 | mm->context.pgtable_page = page; | ||
2501 | } | ||
2502 | spin_unlock(&mm->page_table_lock); | ||
2503 | } | ||
2504 | return page; | ||
2505 | } | ||
2506 | |||
2507 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | ||
2508 | unsigned long address) | ||
2509 | { | ||
2510 | struct page *page; | ||
2511 | pte_t *pte; | ||
2512 | |||
2513 | pte = get_from_cache(mm); | ||
2514 | if (pte) | ||
2515 | return pte; | ||
2516 | |||
2517 | page = __alloc_for_cache(mm); | ||
2518 | if (page) | ||
2519 | pte = (pte_t *) page_address(page); | ||
2520 | |||
2521 | return pte; | ||
2522 | } | ||
2523 | |||
2524 | pgtable_t pte_alloc_one(struct mm_struct *mm, | ||
2525 | unsigned long address) | ||
2526 | { | ||
2527 | struct page *page; | ||
2528 | pte_t *pte; | ||
2529 | |||
2530 | pte = get_from_cache(mm); | ||
2531 | if (pte) | ||
2532 | return pte; | ||
2533 | |||
2534 | page = __alloc_for_cache(mm); | ||
2535 | if (page) { | ||
2536 | pgtable_page_ctor(page); | ||
2537 | pte = (pte_t *) page_address(page); | ||
2538 | } | ||
2539 | |||
2540 | return pte; | ||
2541 | } | ||
2542 | |||
2543 | void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
2544 | { | ||
2545 | struct page *page = virt_to_page(pte); | ||
2546 | if (put_page_testzero(page)) | ||
2547 | free_hot_cold_page(page, 0); | ||
2548 | } | ||
2549 | |||
2550 | static void __pte_free(pgtable_t pte) | ||
2551 | { | ||
2552 | struct page *page = virt_to_page(pte); | ||
2553 | if (put_page_testzero(page)) { | ||
2554 | pgtable_page_dtor(page); | ||
2555 | free_hot_cold_page(page, 0); | ||
2556 | } | ||
2557 | } | ||
2558 | |||
2559 | void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
2560 | { | ||
2561 | __pte_free(pte); | ||
2562 | } | ||
2563 | |||
2564 | void pgtable_free(void *table, bool is_page) | ||
2565 | { | ||
2566 | if (is_page) | ||
2567 | __pte_free(table); | ||
2568 | else | ||
2569 | kmem_cache_free(pgtable_cache, table); | ||
2570 | } | ||
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 70e50ea2a5b6..a35ee832baf3 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c | |||
@@ -445,6 +445,8 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |||
445 | mm->context.huge_pte_count = 0; | 445 | mm->context.huge_pte_count = 0; |
446 | #endif | 446 | #endif |
447 | 447 | ||
448 | mm->context.pgtable_page = NULL; | ||
449 | |||
448 | /* copy_mm() copies over the parent's mm_struct before calling | 450 | /* copy_mm() copies over the parent's mm_struct before calling |
449 | * us, so we need to zero out the TSB pointer or else tsb_grow() | 451 | * us, so we need to zero out the TSB pointer or else tsb_grow() |
450 | * will be confused and think there is an older TSB to free up. | 452 | * will be confused and think there is an older TSB to free up. |
@@ -483,10 +485,17 @@ static void tsb_destroy_one(struct tsb_config *tp) | |||
483 | void destroy_context(struct mm_struct *mm) | 485 | void destroy_context(struct mm_struct *mm) |
484 | { | 486 | { |
485 | unsigned long flags, i; | 487 | unsigned long flags, i; |
488 | struct page *page; | ||
486 | 489 | ||
487 | for (i = 0; i < MM_NUM_TSBS; i++) | 490 | for (i = 0; i < MM_NUM_TSBS; i++) |
488 | tsb_destroy_one(&mm->context.tsb_block[i]); | 491 | tsb_destroy_one(&mm->context.tsb_block[i]); |
489 | 492 | ||
493 | page = mm->context.pgtable_page; | ||
494 | if (page && put_page_testzero(page)) { | ||
495 | pgtable_page_dtor(page); | ||
496 | free_hot_cold_page(page, 0); | ||
497 | } | ||
498 | |||
490 | spin_lock_irqsave(&ctx_alloc_lock, flags); | 499 | spin_lock_irqsave(&ctx_alloc_lock, flags); |
491 | 500 | ||
492 | if (CTX_VALID(mm->context)) { | 501 | if (CTX_VALID(mm->context)) { |