diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:23:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:23:15 -0400 |
commit | 9e2d8656f5e8aa214e66b462680cf86b210b74a8 (patch) | |
tree | f67d62e896cedf75599ea45f9ecf9999c6ad24cd /arch/sparc/mm | |
parent | 1ea4f4f8405cc1ceec23f2d261bc3775785e6712 (diff) | |
parent | 9e695d2ecc8451cc2c1603d60b5c8e7f5581923a (diff) |
Merge branch 'akpm' (Andrew's patch-bomb)
Merge patches from Andrew Morton:
"A few misc things and very nearly all of the MM tree. A tremendous
amount of stuff (again), including a significant rbtree library
rework."
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (160 commits)
sparc64: Support transparent huge pages.
mm: thp: Use more portable PMD clearing sequenece in zap_huge_pmd().
mm: Add and use update_mmu_cache_pmd() in transparent huge page code.
sparc64: Document PGD and PMD layout.
sparc64: Eliminate PTE table memory wastage.
sparc64: Halve the size of PTE tables
sparc64: Only support 4MB huge pages and 8KB base pages.
memory-hotplug: suppress "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY>" warning
mm: memcg: clean up mm_match_cgroup() signature
mm: document PageHuge somewhat
mm: use %pK for /proc/vmallocinfo
mm, thp: fix mlock statistics
mm, thp: fix mapped pages avoiding unevictable list on mlock
memory-hotplug: update memory block's state and notify userspace
memory-hotplug: preparation to notify memory block's state at memory hot remove
mm: avoid section mismatch warning for memblock_type_name
make GFP_NOTRACK definition unconditional
cma: decrease cc.nr_migratepages after reclaiming pagelist
CMA: migrate mlocked pages
kpageflags: fix wrong KPF_THP on non-huge compound pages
...
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r-- | arch/sparc/mm/fault_32.c | 1 | ||||
-rw-r--r-- | arch/sparc/mm/fault_64.c | 5 | ||||
-rw-r--r-- | arch/sparc/mm/hugetlbpage.c | 50 | ||||
-rw-r--r-- | arch/sparc/mm/init_64.c | 314 | ||||
-rw-r--r-- | arch/sparc/mm/tlb.c | 118 | ||||
-rw-r--r-- | arch/sparc/mm/tsb.c | 40 |
6 files changed, 420 insertions, 108 deletions
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 77ac917be152..e98bfda205a2 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c | |||
@@ -265,6 +265,7 @@ good_area: | |||
265 | } | 265 | } |
266 | if (fault & VM_FAULT_RETRY) { | 266 | if (fault & VM_FAULT_RETRY) { |
267 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | 267 | flags &= ~FAULT_FLAG_ALLOW_RETRY; |
268 | flags |= FAULT_FLAG_TRIED; | ||
268 | 269 | ||
269 | /* No need to up_read(&mm->mmap_sem) as we would | 270 | /* No need to up_read(&mm->mmap_sem) as we would |
270 | * have already released it in __lock_page_or_retry | 271 | * have already released it in __lock_page_or_retry |
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 1fe0429b6314..2976dba1ebaf 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c | |||
@@ -452,6 +452,7 @@ good_area: | |||
452 | } | 452 | } |
453 | if (fault & VM_FAULT_RETRY) { | 453 | if (fault & VM_FAULT_RETRY) { |
454 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | 454 | flags &= ~FAULT_FLAG_ALLOW_RETRY; |
455 | flags |= FAULT_FLAG_TRIED; | ||
455 | 456 | ||
456 | /* No need to up_read(&mm->mmap_sem) as we would | 457 | /* No need to up_read(&mm->mmap_sem) as we would |
457 | * have already released it in __lock_page_or_retry | 458 | * have already released it in __lock_page_or_retry |
@@ -464,13 +465,13 @@ good_area: | |||
464 | up_read(&mm->mmap_sem); | 465 | up_read(&mm->mmap_sem); |
465 | 466 | ||
466 | mm_rss = get_mm_rss(mm); | 467 | mm_rss = get_mm_rss(mm); |
467 | #ifdef CONFIG_HUGETLB_PAGE | 468 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
468 | mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE)); | 469 | mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE)); |
469 | #endif | 470 | #endif |
470 | if (unlikely(mm_rss > | 471 | if (unlikely(mm_rss > |
471 | mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) | 472 | mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) |
472 | tsb_grow(mm, MM_TSB_BASE, mm_rss); | 473 | tsb_grow(mm, MM_TSB_BASE, mm_rss); |
473 | #ifdef CONFIG_HUGETLB_PAGE | 474 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
474 | mm_rss = mm->context.huge_pte_count; | 475 | mm_rss = mm->context.huge_pte_count; |
475 | if (unlikely(mm_rss > | 476 | if (unlikely(mm_rss > |
476 | mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) | 477 | mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) |
diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 07e14535375c..f76f83d5ac63 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c | |||
@@ -303,53 +303,3 @@ struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, | |||
303 | { | 303 | { |
304 | return NULL; | 304 | return NULL; |
305 | } | 305 | } |
306 | |||
307 | static void context_reload(void *__data) | ||
308 | { | ||
309 | struct mm_struct *mm = __data; | ||
310 | |||
311 | if (mm == current->mm) | ||
312 | load_secondary_context(mm); | ||
313 | } | ||
314 | |||
315 | void hugetlb_prefault_arch_hook(struct mm_struct *mm) | ||
316 | { | ||
317 | struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE]; | ||
318 | |||
319 | if (likely(tp->tsb != NULL)) | ||
320 | return; | ||
321 | |||
322 | tsb_grow(mm, MM_TSB_HUGE, 0); | ||
323 | tsb_context_switch(mm); | ||
324 | smp_tsb_sync(mm); | ||
325 | |||
326 | /* On UltraSPARC-III+ and later, configure the second half of | ||
327 | * the Data-TLB for huge pages. | ||
328 | */ | ||
329 | if (tlb_type == cheetah_plus) { | ||
330 | unsigned long ctx; | ||
331 | |||
332 | spin_lock(&ctx_alloc_lock); | ||
333 | ctx = mm->context.sparc64_ctx_val; | ||
334 | ctx &= ~CTX_PGSZ_MASK; | ||
335 | ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT; | ||
336 | ctx |= CTX_PGSZ_HUGE << CTX_PGSZ1_SHIFT; | ||
337 | |||
338 | if (ctx != mm->context.sparc64_ctx_val) { | ||
339 | /* When changing the page size fields, we | ||
340 | * must perform a context flush so that no | ||
341 | * stale entries match. This flush must | ||
342 | * occur with the original context register | ||
343 | * settings. | ||
344 | */ | ||
345 | do_flush_tlb_mm(mm); | ||
346 | |||
347 | /* Reload the context register of all processors | ||
348 | * also executing in this address space. | ||
349 | */ | ||
350 | mm->context.sparc64_ctx_val = ctx; | ||
351 | on_each_cpu(context_reload, mm, 0); | ||
352 | } | ||
353 | spin_unlock(&ctx_alloc_lock); | ||
354 | } | ||
355 | } | ||
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 7a9b788c6ced..9e28a118e6a4 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -276,7 +276,6 @@ static inline void tsb_insert(struct tsb *ent, unsigned long tag, unsigned long | |||
276 | } | 276 | } |
277 | 277 | ||
278 | unsigned long _PAGE_ALL_SZ_BITS __read_mostly; | 278 | unsigned long _PAGE_ALL_SZ_BITS __read_mostly; |
279 | unsigned long _PAGE_SZBITS __read_mostly; | ||
280 | 279 | ||
281 | static void flush_dcache(unsigned long pfn) | 280 | static void flush_dcache(unsigned long pfn) |
282 | { | 281 | { |
@@ -307,12 +306,24 @@ static void flush_dcache(unsigned long pfn) | |||
307 | } | 306 | } |
308 | } | 307 | } |
309 | 308 | ||
309 | /* mm->context.lock must be held */ | ||
310 | static void __update_mmu_tsb_insert(struct mm_struct *mm, unsigned long tsb_index, | ||
311 | unsigned long tsb_hash_shift, unsigned long address, | ||
312 | unsigned long tte) | ||
313 | { | ||
314 | struct tsb *tsb = mm->context.tsb_block[tsb_index].tsb; | ||
315 | unsigned long tag; | ||
316 | |||
317 | tsb += ((address >> tsb_hash_shift) & | ||
318 | (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL)); | ||
319 | tag = (address >> 22UL); | ||
320 | tsb_insert(tsb, tag, tte); | ||
321 | } | ||
322 | |||
310 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) | 323 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) |
311 | { | 324 | { |
325 | unsigned long tsb_index, tsb_hash_shift, flags; | ||
312 | struct mm_struct *mm; | 326 | struct mm_struct *mm; |
313 | struct tsb *tsb; | ||
314 | unsigned long tag, flags; | ||
315 | unsigned long tsb_index, tsb_hash_shift; | ||
316 | pte_t pte = *ptep; | 327 | pte_t pte = *ptep; |
317 | 328 | ||
318 | if (tlb_type != hypervisor) { | 329 | if (tlb_type != hypervisor) { |
@@ -329,7 +340,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t * | |||
329 | 340 | ||
330 | spin_lock_irqsave(&mm->context.lock, flags); | 341 | spin_lock_irqsave(&mm->context.lock, flags); |
331 | 342 | ||
332 | #ifdef CONFIG_HUGETLB_PAGE | 343 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
333 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) { | 344 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) { |
334 | if ((tlb_type == hypervisor && | 345 | if ((tlb_type == hypervisor && |
335 | (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || | 346 | (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || |
@@ -341,11 +352,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t * | |||
341 | } | 352 | } |
342 | #endif | 353 | #endif |
343 | 354 | ||
344 | tsb = mm->context.tsb_block[tsb_index].tsb; | 355 | __update_mmu_tsb_insert(mm, tsb_index, tsb_hash_shift, |
345 | tsb += ((address >> tsb_hash_shift) & | 356 | address, pte_val(pte)); |
346 | (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL)); | ||
347 | tag = (address >> 22UL); | ||
348 | tsb_insert(tsb, tag, pte_val(pte)); | ||
349 | 357 | ||
350 | spin_unlock_irqrestore(&mm->context.lock, flags); | 358 | spin_unlock_irqrestore(&mm->context.lock, flags); |
351 | } | 359 | } |
@@ -2275,8 +2283,7 @@ static void __init sun4u_pgprot_init(void) | |||
2275 | __ACCESS_BITS_4U | _PAGE_E_4U); | 2283 | __ACCESS_BITS_4U | _PAGE_E_4U); |
2276 | 2284 | ||
2277 | #ifdef CONFIG_DEBUG_PAGEALLOC | 2285 | #ifdef CONFIG_DEBUG_PAGEALLOC |
2278 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^ | 2286 | kern_linear_pte_xor[0] = _PAGE_VALID ^ 0xfffff80000000000UL; |
2279 | 0xfffff80000000000UL; | ||
2280 | #else | 2287 | #else |
2281 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^ | 2288 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^ |
2282 | 0xfffff80000000000UL; | 2289 | 0xfffff80000000000UL; |
@@ -2287,7 +2294,6 @@ static void __init sun4u_pgprot_init(void) | |||
2287 | for (i = 1; i < 4; i++) | 2294 | for (i = 1; i < 4; i++) |
2288 | kern_linear_pte_xor[i] = kern_linear_pte_xor[0]; | 2295 | kern_linear_pte_xor[i] = kern_linear_pte_xor[0]; |
2289 | 2296 | ||
2290 | _PAGE_SZBITS = _PAGE_SZBITS_4U; | ||
2291 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ4MB_4U | _PAGE_SZ512K_4U | | 2297 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ4MB_4U | _PAGE_SZ512K_4U | |
2292 | _PAGE_SZ64K_4U | _PAGE_SZ8K_4U | | 2298 | _PAGE_SZ64K_4U | _PAGE_SZ8K_4U | |
2293 | _PAGE_SZ32MB_4U | _PAGE_SZ256MB_4U); | 2299 | _PAGE_SZ32MB_4U | _PAGE_SZ256MB_4U); |
@@ -2324,8 +2330,7 @@ static void __init sun4v_pgprot_init(void) | |||
2324 | _PAGE_CACHE = _PAGE_CACHE_4V; | 2330 | _PAGE_CACHE = _PAGE_CACHE_4V; |
2325 | 2331 | ||
2326 | #ifdef CONFIG_DEBUG_PAGEALLOC | 2332 | #ifdef CONFIG_DEBUG_PAGEALLOC |
2327 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^ | 2333 | kern_linear_pte_xor[0] = _PAGE_VALID ^ 0xfffff80000000000UL; |
2328 | 0xfffff80000000000UL; | ||
2329 | #else | 2334 | #else |
2330 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^ | 2335 | kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^ |
2331 | 0xfffff80000000000UL; | 2336 | 0xfffff80000000000UL; |
@@ -2339,7 +2344,6 @@ static void __init sun4v_pgprot_init(void) | |||
2339 | pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4V | __DIRTY_BITS_4V | | 2344 | pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4V | __DIRTY_BITS_4V | |
2340 | __ACCESS_BITS_4V | _PAGE_E_4V); | 2345 | __ACCESS_BITS_4V | _PAGE_E_4V); |
2341 | 2346 | ||
2342 | _PAGE_SZBITS = _PAGE_SZBITS_4V; | ||
2343 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ16GB_4V | _PAGE_SZ2GB_4V | | 2347 | _PAGE_ALL_SZ_BITS = (_PAGE_SZ16GB_4V | _PAGE_SZ2GB_4V | |
2344 | _PAGE_SZ256MB_4V | _PAGE_SZ32MB_4V | | 2348 | _PAGE_SZ256MB_4V | _PAGE_SZ32MB_4V | |
2345 | _PAGE_SZ4MB_4V | _PAGE_SZ512K_4V | | 2349 | _PAGE_SZ4MB_4V | _PAGE_SZ512K_4V | |
@@ -2472,3 +2476,281 @@ void __flush_tlb_all(void) | |||
2472 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | 2476 | __asm__ __volatile__("wrpr %0, 0, %%pstate" |
2473 | : : "r" (pstate)); | 2477 | : : "r" (pstate)); |
2474 | } | 2478 | } |
2479 | |||
2480 | static pte_t *get_from_cache(struct mm_struct *mm) | ||
2481 | { | ||
2482 | struct page *page; | ||
2483 | pte_t *ret; | ||
2484 | |||
2485 | spin_lock(&mm->page_table_lock); | ||
2486 | page = mm->context.pgtable_page; | ||
2487 | ret = NULL; | ||
2488 | if (page) { | ||
2489 | void *p = page_address(page); | ||
2490 | |||
2491 | mm->context.pgtable_page = NULL; | ||
2492 | |||
2493 | ret = (pte_t *) (p + (PAGE_SIZE / 2)); | ||
2494 | } | ||
2495 | spin_unlock(&mm->page_table_lock); | ||
2496 | |||
2497 | return ret; | ||
2498 | } | ||
2499 | |||
2500 | static struct page *__alloc_for_cache(struct mm_struct *mm) | ||
2501 | { | ||
2502 | struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | | ||
2503 | __GFP_REPEAT | __GFP_ZERO); | ||
2504 | |||
2505 | if (page) { | ||
2506 | spin_lock(&mm->page_table_lock); | ||
2507 | if (!mm->context.pgtable_page) { | ||
2508 | atomic_set(&page->_count, 2); | ||
2509 | mm->context.pgtable_page = page; | ||
2510 | } | ||
2511 | spin_unlock(&mm->page_table_lock); | ||
2512 | } | ||
2513 | return page; | ||
2514 | } | ||
2515 | |||
2516 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | ||
2517 | unsigned long address) | ||
2518 | { | ||
2519 | struct page *page; | ||
2520 | pte_t *pte; | ||
2521 | |||
2522 | pte = get_from_cache(mm); | ||
2523 | if (pte) | ||
2524 | return pte; | ||
2525 | |||
2526 | page = __alloc_for_cache(mm); | ||
2527 | if (page) | ||
2528 | pte = (pte_t *) page_address(page); | ||
2529 | |||
2530 | return pte; | ||
2531 | } | ||
2532 | |||
2533 | pgtable_t pte_alloc_one(struct mm_struct *mm, | ||
2534 | unsigned long address) | ||
2535 | { | ||
2536 | struct page *page; | ||
2537 | pte_t *pte; | ||
2538 | |||
2539 | pte = get_from_cache(mm); | ||
2540 | if (pte) | ||
2541 | return pte; | ||
2542 | |||
2543 | page = __alloc_for_cache(mm); | ||
2544 | if (page) { | ||
2545 | pgtable_page_ctor(page); | ||
2546 | pte = (pte_t *) page_address(page); | ||
2547 | } | ||
2548 | |||
2549 | return pte; | ||
2550 | } | ||
2551 | |||
2552 | void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
2553 | { | ||
2554 | struct page *page = virt_to_page(pte); | ||
2555 | if (put_page_testzero(page)) | ||
2556 | free_hot_cold_page(page, 0); | ||
2557 | } | ||
2558 | |||
2559 | static void __pte_free(pgtable_t pte) | ||
2560 | { | ||
2561 | struct page *page = virt_to_page(pte); | ||
2562 | if (put_page_testzero(page)) { | ||
2563 | pgtable_page_dtor(page); | ||
2564 | free_hot_cold_page(page, 0); | ||
2565 | } | ||
2566 | } | ||
2567 | |||
2568 | void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
2569 | { | ||
2570 | __pte_free(pte); | ||
2571 | } | ||
2572 | |||
2573 | void pgtable_free(void *table, bool is_page) | ||
2574 | { | ||
2575 | if (is_page) | ||
2576 | __pte_free(table); | ||
2577 | else | ||
2578 | kmem_cache_free(pgtable_cache, table); | ||
2579 | } | ||
2580 | |||
2581 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
2582 | static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot, bool for_modify) | ||
2583 | { | ||
2584 | if (pgprot_val(pgprot) & _PAGE_VALID) | ||
2585 | pmd_val(pmd) |= PMD_HUGE_PRESENT; | ||
2586 | if (tlb_type == hypervisor) { | ||
2587 | if (pgprot_val(pgprot) & _PAGE_WRITE_4V) | ||
2588 | pmd_val(pmd) |= PMD_HUGE_WRITE; | ||
2589 | if (pgprot_val(pgprot) & _PAGE_EXEC_4V) | ||
2590 | pmd_val(pmd) |= PMD_HUGE_EXEC; | ||
2591 | |||
2592 | if (!for_modify) { | ||
2593 | if (pgprot_val(pgprot) & _PAGE_ACCESSED_4V) | ||
2594 | pmd_val(pmd) |= PMD_HUGE_ACCESSED; | ||
2595 | if (pgprot_val(pgprot) & _PAGE_MODIFIED_4V) | ||
2596 | pmd_val(pmd) |= PMD_HUGE_DIRTY; | ||
2597 | } | ||
2598 | } else { | ||
2599 | if (pgprot_val(pgprot) & _PAGE_WRITE_4U) | ||
2600 | pmd_val(pmd) |= PMD_HUGE_WRITE; | ||
2601 | if (pgprot_val(pgprot) & _PAGE_EXEC_4U) | ||
2602 | pmd_val(pmd) |= PMD_HUGE_EXEC; | ||
2603 | |||
2604 | if (!for_modify) { | ||
2605 | if (pgprot_val(pgprot) & _PAGE_ACCESSED_4U) | ||
2606 | pmd_val(pmd) |= PMD_HUGE_ACCESSED; | ||
2607 | if (pgprot_val(pgprot) & _PAGE_MODIFIED_4U) | ||
2608 | pmd_val(pmd) |= PMD_HUGE_DIRTY; | ||
2609 | } | ||
2610 | } | ||
2611 | |||
2612 | return pmd; | ||
2613 | } | ||
2614 | |||
2615 | pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) | ||
2616 | { | ||
2617 | pmd_t pmd; | ||
2618 | |||
2619 | pmd_val(pmd) = (page_nr << ((PAGE_SHIFT - PMD_PADDR_SHIFT))); | ||
2620 | pmd_val(pmd) |= PMD_ISHUGE; | ||
2621 | pmd = pmd_set_protbits(pmd, pgprot, false); | ||
2622 | return pmd; | ||
2623 | } | ||
2624 | |||
2625 | pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) | ||
2626 | { | ||
2627 | pmd_val(pmd) &= ~(PMD_HUGE_PRESENT | | ||
2628 | PMD_HUGE_WRITE | | ||
2629 | PMD_HUGE_EXEC); | ||
2630 | pmd = pmd_set_protbits(pmd, newprot, true); | ||
2631 | return pmd; | ||
2632 | } | ||
2633 | |||
2634 | pgprot_t pmd_pgprot(pmd_t entry) | ||
2635 | { | ||
2636 | unsigned long pte = 0; | ||
2637 | |||
2638 | if (pmd_val(entry) & PMD_HUGE_PRESENT) | ||
2639 | pte |= _PAGE_VALID; | ||
2640 | |||
2641 | if (tlb_type == hypervisor) { | ||
2642 | if (pmd_val(entry) & PMD_HUGE_PRESENT) | ||
2643 | pte |= _PAGE_PRESENT_4V; | ||
2644 | if (pmd_val(entry) & PMD_HUGE_EXEC) | ||
2645 | pte |= _PAGE_EXEC_4V; | ||
2646 | if (pmd_val(entry) & PMD_HUGE_WRITE) | ||
2647 | pte |= _PAGE_W_4V; | ||
2648 | if (pmd_val(entry) & PMD_HUGE_ACCESSED) | ||
2649 | pte |= _PAGE_ACCESSED_4V; | ||
2650 | if (pmd_val(entry) & PMD_HUGE_DIRTY) | ||
2651 | pte |= _PAGE_MODIFIED_4V; | ||
2652 | pte |= _PAGE_CP_4V|_PAGE_CV_4V; | ||
2653 | } else { | ||
2654 | if (pmd_val(entry) & PMD_HUGE_PRESENT) | ||
2655 | pte |= _PAGE_PRESENT_4U; | ||
2656 | if (pmd_val(entry) & PMD_HUGE_EXEC) | ||
2657 | pte |= _PAGE_EXEC_4U; | ||
2658 | if (pmd_val(entry) & PMD_HUGE_WRITE) | ||
2659 | pte |= _PAGE_W_4U; | ||
2660 | if (pmd_val(entry) & PMD_HUGE_ACCESSED) | ||
2661 | pte |= _PAGE_ACCESSED_4U; | ||
2662 | if (pmd_val(entry) & PMD_HUGE_DIRTY) | ||
2663 | pte |= _PAGE_MODIFIED_4U; | ||
2664 | pte |= _PAGE_CP_4U|_PAGE_CV_4U; | ||
2665 | } | ||
2666 | |||
2667 | return __pgprot(pte); | ||
2668 | } | ||
2669 | |||
2670 | void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, | ||
2671 | pmd_t *pmd) | ||
2672 | { | ||
2673 | unsigned long pte, flags; | ||
2674 | struct mm_struct *mm; | ||
2675 | pmd_t entry = *pmd; | ||
2676 | pgprot_t prot; | ||
2677 | |||
2678 | if (!pmd_large(entry) || !pmd_young(entry)) | ||
2679 | return; | ||
2680 | |||
2681 | pte = (pmd_val(entry) & ~PMD_HUGE_PROTBITS); | ||
2682 | pte <<= PMD_PADDR_SHIFT; | ||
2683 | pte |= _PAGE_VALID; | ||
2684 | |||
2685 | prot = pmd_pgprot(entry); | ||
2686 | |||
2687 | if (tlb_type == hypervisor) | ||
2688 | pgprot_val(prot) |= _PAGE_SZHUGE_4V; | ||
2689 | else | ||
2690 | pgprot_val(prot) |= _PAGE_SZHUGE_4U; | ||
2691 | |||
2692 | pte |= pgprot_val(prot); | ||
2693 | |||
2694 | mm = vma->vm_mm; | ||
2695 | |||
2696 | spin_lock_irqsave(&mm->context.lock, flags); | ||
2697 | |||
2698 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) | ||
2699 | __update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT, | ||
2700 | addr, pte); | ||
2701 | |||
2702 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
2703 | } | ||
2704 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
2705 | |||
2706 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | ||
2707 | static void context_reload(void *__data) | ||
2708 | { | ||
2709 | struct mm_struct *mm = __data; | ||
2710 | |||
2711 | if (mm == current->mm) | ||
2712 | load_secondary_context(mm); | ||
2713 | } | ||
2714 | |||
2715 | void hugetlb_setup(struct mm_struct *mm) | ||
2716 | { | ||
2717 | struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE]; | ||
2718 | |||
2719 | if (likely(tp->tsb != NULL)) | ||
2720 | return; | ||
2721 | |||
2722 | tsb_grow(mm, MM_TSB_HUGE, 0); | ||
2723 | tsb_context_switch(mm); | ||
2724 | smp_tsb_sync(mm); | ||
2725 | |||
2726 | /* On UltraSPARC-III+ and later, configure the second half of | ||
2727 | * the Data-TLB for huge pages. | ||
2728 | */ | ||
2729 | if (tlb_type == cheetah_plus) { | ||
2730 | unsigned long ctx; | ||
2731 | |||
2732 | spin_lock(&ctx_alloc_lock); | ||
2733 | ctx = mm->context.sparc64_ctx_val; | ||
2734 | ctx &= ~CTX_PGSZ_MASK; | ||
2735 | ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT; | ||
2736 | ctx |= CTX_PGSZ_HUGE << CTX_PGSZ1_SHIFT; | ||
2737 | |||
2738 | if (ctx != mm->context.sparc64_ctx_val) { | ||
2739 | /* When changing the page size fields, we | ||
2740 | * must perform a context flush so that no | ||
2741 | * stale entries match. This flush must | ||
2742 | * occur with the original context register | ||
2743 | * settings. | ||
2744 | */ | ||
2745 | do_flush_tlb_mm(mm); | ||
2746 | |||
2747 | /* Reload the context register of all processors | ||
2748 | * also executing in this address space. | ||
2749 | */ | ||
2750 | mm->context.sparc64_ctx_val = ctx; | ||
2751 | on_each_cpu(context_reload, mm, 0); | ||
2752 | } | ||
2753 | spin_unlock(&ctx_alloc_lock); | ||
2754 | } | ||
2755 | } | ||
2756 | #endif | ||
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index b1f279cd00bf..3e8fec391fe0 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c | |||
@@ -43,16 +43,37 @@ void flush_tlb_pending(void) | |||
43 | put_cpu_var(tlb_batch); | 43 | put_cpu_var(tlb_batch); |
44 | } | 44 | } |
45 | 45 | ||
46 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | 46 | static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, |
47 | pte_t *ptep, pte_t orig, int fullmm) | 47 | bool exec) |
48 | { | 48 | { |
49 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); | 49 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); |
50 | unsigned long nr; | 50 | unsigned long nr; |
51 | 51 | ||
52 | vaddr &= PAGE_MASK; | 52 | vaddr &= PAGE_MASK; |
53 | if (pte_exec(orig)) | 53 | if (exec) |
54 | vaddr |= 0x1UL; | 54 | vaddr |= 0x1UL; |
55 | 55 | ||
56 | nr = tb->tlb_nr; | ||
57 | |||
58 | if (unlikely(nr != 0 && mm != tb->mm)) { | ||
59 | flush_tlb_pending(); | ||
60 | nr = 0; | ||
61 | } | ||
62 | |||
63 | if (nr == 0) | ||
64 | tb->mm = mm; | ||
65 | |||
66 | tb->vaddrs[nr] = vaddr; | ||
67 | tb->tlb_nr = ++nr; | ||
68 | if (nr >= TLB_BATCH_NR) | ||
69 | flush_tlb_pending(); | ||
70 | |||
71 | put_cpu_var(tlb_batch); | ||
72 | } | ||
73 | |||
74 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | ||
75 | pte_t *ptep, pte_t orig, int fullmm) | ||
76 | { | ||
56 | if (tlb_type != hypervisor && | 77 | if (tlb_type != hypervisor && |
57 | pte_dirty(orig)) { | 78 | pte_dirty(orig)) { |
58 | unsigned long paddr, pfn = pte_pfn(orig); | 79 | unsigned long paddr, pfn = pte_pfn(orig); |
@@ -77,26 +98,91 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | |||
77 | } | 98 | } |
78 | 99 | ||
79 | no_cache_flush: | 100 | no_cache_flush: |
101 | if (!fullmm) | ||
102 | tlb_batch_add_one(mm, vaddr, pte_exec(orig)); | ||
103 | } | ||
104 | |||
105 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
106 | static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr, | ||
107 | pmd_t pmd, bool exec) | ||
108 | { | ||
109 | unsigned long end; | ||
110 | pte_t *pte; | ||
111 | |||
112 | pte = pte_offset_map(&pmd, vaddr); | ||
113 | end = vaddr + HPAGE_SIZE; | ||
114 | while (vaddr < end) { | ||
115 | if (pte_val(*pte) & _PAGE_VALID) | ||
116 | tlb_batch_add_one(mm, vaddr, exec); | ||
117 | pte++; | ||
118 | vaddr += PAGE_SIZE; | ||
119 | } | ||
120 | pte_unmap(pte); | ||
121 | } | ||
80 | 122 | ||
81 | if (fullmm) { | 123 | void set_pmd_at(struct mm_struct *mm, unsigned long addr, |
82 | put_cpu_var(tlb_batch); | 124 | pmd_t *pmdp, pmd_t pmd) |
125 | { | ||
126 | pmd_t orig = *pmdp; | ||
127 | |||
128 | *pmdp = pmd; | ||
129 | |||
130 | if (mm == &init_mm) | ||
83 | return; | 131 | return; |
132 | |||
133 | if ((pmd_val(pmd) ^ pmd_val(orig)) & PMD_ISHUGE) { | ||
134 | if (pmd_val(pmd) & PMD_ISHUGE) | ||
135 | mm->context.huge_pte_count++; | ||
136 | else | ||
137 | mm->context.huge_pte_count--; | ||
138 | if (mm->context.huge_pte_count == 1) | ||
139 | hugetlb_setup(mm); | ||
84 | } | 140 | } |
85 | 141 | ||
86 | nr = tb->tlb_nr; | 142 | if (!pmd_none(orig)) { |
143 | bool exec = ((pmd_val(orig) & PMD_HUGE_EXEC) != 0); | ||
87 | 144 | ||
88 | if (unlikely(nr != 0 && mm != tb->mm)) { | 145 | addr &= HPAGE_MASK; |
89 | flush_tlb_pending(); | 146 | if (pmd_val(orig) & PMD_ISHUGE) |
90 | nr = 0; | 147 | tlb_batch_add_one(mm, addr, exec); |
148 | else | ||
149 | tlb_batch_pmd_scan(mm, addr, orig, exec); | ||
91 | } | 150 | } |
151 | } | ||
92 | 152 | ||
93 | if (nr == 0) | 153 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable) |
94 | tb->mm = mm; | 154 | { |
155 | struct list_head *lh = (struct list_head *) pgtable; | ||
95 | 156 | ||
96 | tb->vaddrs[nr] = vaddr; | 157 | assert_spin_locked(&mm->page_table_lock); |
97 | tb->tlb_nr = ++nr; | ||
98 | if (nr >= TLB_BATCH_NR) | ||
99 | flush_tlb_pending(); | ||
100 | 158 | ||
101 | put_cpu_var(tlb_batch); | 159 | /* FIFO */ |
160 | if (!mm->pmd_huge_pte) | ||
161 | INIT_LIST_HEAD(lh); | ||
162 | else | ||
163 | list_add(lh, (struct list_head *) mm->pmd_huge_pte); | ||
164 | mm->pmd_huge_pte = pgtable; | ||
165 | } | ||
166 | |||
167 | pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm) | ||
168 | { | ||
169 | struct list_head *lh; | ||
170 | pgtable_t pgtable; | ||
171 | |||
172 | assert_spin_locked(&mm->page_table_lock); | ||
173 | |||
174 | /* FIFO */ | ||
175 | pgtable = mm->pmd_huge_pte; | ||
176 | lh = (struct list_head *) pgtable; | ||
177 | if (list_empty(lh)) | ||
178 | mm->pmd_huge_pte = NULL; | ||
179 | else { | ||
180 | mm->pmd_huge_pte = (pgtable_t) lh->next; | ||
181 | list_del(lh); | ||
182 | } | ||
183 | pte_val(pgtable[0]) = 0; | ||
184 | pte_val(pgtable[1]) = 0; | ||
185 | |||
186 | return pgtable; | ||
102 | } | 187 | } |
188 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index c52add79b83d..7f6474347491 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c | |||
@@ -78,7 +78,7 @@ void flush_tsb_user(struct tlb_batch *tb) | |||
78 | base = __pa(base); | 78 | base = __pa(base); |
79 | __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); | 79 | __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); |
80 | 80 | ||
81 | #ifdef CONFIG_HUGETLB_PAGE | 81 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
82 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { | 82 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { |
83 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; | 83 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; |
84 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; | 84 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; |
@@ -90,29 +90,12 @@ void flush_tsb_user(struct tlb_batch *tb) | |||
90 | spin_unlock_irqrestore(&mm->context.lock, flags); | 90 | spin_unlock_irqrestore(&mm->context.lock, flags); |
91 | } | 91 | } |
92 | 92 | ||
93 | #if defined(CONFIG_SPARC64_PAGE_SIZE_8KB) | ||
94 | #define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_8K | 93 | #define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_8K |
95 | #define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_8K | 94 | #define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_8K |
96 | #elif defined(CONFIG_SPARC64_PAGE_SIZE_64KB) | ||
97 | #define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_64K | ||
98 | #define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_64K | ||
99 | #else | ||
100 | #error Broken base page size setting... | ||
101 | #endif | ||
102 | 95 | ||
103 | #ifdef CONFIG_HUGETLB_PAGE | 96 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
104 | #if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) | ||
105 | #define HV_PGSZ_IDX_HUGE HV_PGSZ_IDX_64K | ||
106 | #define HV_PGSZ_MASK_HUGE HV_PGSZ_MASK_64K | ||
107 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K) | ||
108 | #define HV_PGSZ_IDX_HUGE HV_PGSZ_IDX_512K | ||
109 | #define HV_PGSZ_MASK_HUGE HV_PGSZ_MASK_512K | ||
110 | #elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) | ||
111 | #define HV_PGSZ_IDX_HUGE HV_PGSZ_IDX_4MB | 97 | #define HV_PGSZ_IDX_HUGE HV_PGSZ_IDX_4MB |
112 | #define HV_PGSZ_MASK_HUGE HV_PGSZ_MASK_4MB | 98 | #define HV_PGSZ_MASK_HUGE HV_PGSZ_MASK_4MB |
113 | #else | ||
114 | #error Broken huge page size setting... | ||
115 | #endif | ||
116 | #endif | 99 | #endif |
117 | 100 | ||
118 | static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsigned long tsb_bytes) | 101 | static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsigned long tsb_bytes) |
@@ -207,7 +190,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign | |||
207 | case MM_TSB_BASE: | 190 | case MM_TSB_BASE: |
208 | hp->pgsz_idx = HV_PGSZ_IDX_BASE; | 191 | hp->pgsz_idx = HV_PGSZ_IDX_BASE; |
209 | break; | 192 | break; |
210 | #ifdef CONFIG_HUGETLB_PAGE | 193 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
211 | case MM_TSB_HUGE: | 194 | case MM_TSB_HUGE: |
212 | hp->pgsz_idx = HV_PGSZ_IDX_HUGE; | 195 | hp->pgsz_idx = HV_PGSZ_IDX_HUGE; |
213 | break; | 196 | break; |
@@ -222,7 +205,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign | |||
222 | case MM_TSB_BASE: | 205 | case MM_TSB_BASE: |
223 | hp->pgsz_mask = HV_PGSZ_MASK_BASE; | 206 | hp->pgsz_mask = HV_PGSZ_MASK_BASE; |
224 | break; | 207 | break; |
225 | #ifdef CONFIG_HUGETLB_PAGE | 208 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
226 | case MM_TSB_HUGE: | 209 | case MM_TSB_HUGE: |
227 | hp->pgsz_mask = HV_PGSZ_MASK_HUGE; | 210 | hp->pgsz_mask = HV_PGSZ_MASK_HUGE; |
228 | break; | 211 | break; |
@@ -444,7 +427,7 @@ retry_tsb_alloc: | |||
444 | 427 | ||
445 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | 428 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) |
446 | { | 429 | { |
447 | #ifdef CONFIG_HUGETLB_PAGE | 430 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
448 | unsigned long huge_pte_count; | 431 | unsigned long huge_pte_count; |
449 | #endif | 432 | #endif |
450 | unsigned int i; | 433 | unsigned int i; |
@@ -453,7 +436,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |||
453 | 436 | ||
454 | mm->context.sparc64_ctx_val = 0UL; | 437 | mm->context.sparc64_ctx_val = 0UL; |
455 | 438 | ||
456 | #ifdef CONFIG_HUGETLB_PAGE | 439 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
457 | /* We reset it to zero because the fork() page copying | 440 | /* We reset it to zero because the fork() page copying |
458 | * will re-increment the counters as the parent PTEs are | 441 | * will re-increment the counters as the parent PTEs are |
459 | * copied into the child address space. | 442 | * copied into the child address space. |
@@ -462,6 +445,8 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |||
462 | mm->context.huge_pte_count = 0; | 445 | mm->context.huge_pte_count = 0; |
463 | #endif | 446 | #endif |
464 | 447 | ||
448 | mm->context.pgtable_page = NULL; | ||
449 | |||
465 | /* copy_mm() copies over the parent's mm_struct before calling | 450 | /* copy_mm() copies over the parent's mm_struct before calling |
466 | * 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() |
467 | * 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. |
@@ -474,7 +459,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | |||
474 | */ | 459 | */ |
475 | tsb_grow(mm, MM_TSB_BASE, get_mm_rss(mm)); | 460 | tsb_grow(mm, MM_TSB_BASE, get_mm_rss(mm)); |
476 | 461 | ||
477 | #ifdef CONFIG_HUGETLB_PAGE | 462 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
478 | if (unlikely(huge_pte_count)) | 463 | if (unlikely(huge_pte_count)) |
479 | tsb_grow(mm, MM_TSB_HUGE, huge_pte_count); | 464 | tsb_grow(mm, MM_TSB_HUGE, huge_pte_count); |
480 | #endif | 465 | #endif |
@@ -500,10 +485,17 @@ static void tsb_destroy_one(struct tsb_config *tp) | |||
500 | void destroy_context(struct mm_struct *mm) | 485 | void destroy_context(struct mm_struct *mm) |
501 | { | 486 | { |
502 | unsigned long flags, i; | 487 | unsigned long flags, i; |
488 | struct page *page; | ||
503 | 489 | ||
504 | for (i = 0; i < MM_NUM_TSBS; i++) | 490 | for (i = 0; i < MM_NUM_TSBS; i++) |
505 | tsb_destroy_one(&mm->context.tsb_block[i]); | 491 | tsb_destroy_one(&mm->context.tsb_block[i]); |
506 | 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 | |||
507 | spin_lock_irqsave(&ctx_alloc_lock, flags); | 499 | spin_lock_irqsave(&ctx_alloc_lock, flags); |
508 | 500 | ||
509 | if (CTX_VALID(mm->context)) { | 501 | if (CTX_VALID(mm->context)) { |