aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r--arch/sparc/mm/init_64.c101
-rw-r--r--arch/sparc/mm/tsb.c9
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
2471static 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
2491static 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
2507pte_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
2524pgtable_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
2543void 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
2550static 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
2559void pte_free(struct mm_struct *mm, pgtable_t pte)
2560{
2561 __pte_free(pte);
2562}
2563
2564void 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)
483void destroy_context(struct mm_struct *mm) 485void 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)) {