aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/hash_low_64.S8
-rw-r--r--arch/powerpc/mm/hash_native_64.c18
-rw-r--r--arch/powerpc/mm/hash_utils_64.c62
-rw-r--r--arch/powerpc/mm/hugetlbpage.c2
-rw-r--r--arch/powerpc/mm/mmu_context_hash64.c214
-rw-r--r--arch/powerpc/mm/mmu_context_nohash.c18
-rw-r--r--arch/powerpc/mm/numa.c17
-rw-r--r--arch/powerpc/mm/pgtable_32.c12
-rw-r--r--arch/powerpc/mm/pgtable_64.c15
-rw-r--r--arch/powerpc/mm/slb.c10
-rw-r--r--arch/powerpc/mm/slb_low.S8
-rw-r--r--arch/powerpc/mm/stab.c2
12 files changed, 317 insertions, 69 deletions
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 5b7dd4ea02b5..a242b5d7cbe4 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -118,7 +118,7 @@ _GLOBAL(__hash_page_4K)
118BEGIN_FTR_SECTION 118BEGIN_FTR_SECTION
119 cmpdi r9,0 /* check segment size */ 119 cmpdi r9,0 /* check segment size */
120 bne 3f 120 bne 3f
121END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) 121END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
122 /* Calc va and put it in r29 */ 122 /* Calc va and put it in r29 */
123 rldicr r29,r5,28,63-28 123 rldicr r29,r5,28,63-28
124 rldicl r3,r3,0,36 124 rldicl r3,r3,0,36
@@ -401,7 +401,7 @@ _GLOBAL(__hash_page_4K)
401BEGIN_FTR_SECTION 401BEGIN_FTR_SECTION
402 cmpdi r9,0 /* check segment size */ 402 cmpdi r9,0 /* check segment size */
403 bne 3f 403 bne 3f
404END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) 404END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
405 /* Calc va and put it in r29 */ 405 /* Calc va and put it in r29 */
406 rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */ 406 rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */
407 rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */ 407 rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */
@@ -715,7 +715,7 @@ BEGIN_FTR_SECTION
715 andi. r0,r31,_PAGE_NO_CACHE 715 andi. r0,r31,_PAGE_NO_CACHE
716 /* If so, bail out and refault as a 4k page */ 716 /* If so, bail out and refault as a 4k page */
717 bne- ht64_bail_ok 717 bne- ht64_bail_ok
718END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) 718END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
719 /* Prepare new PTE value (turn access RW into DIRTY, then 719 /* Prepare new PTE value (turn access RW into DIRTY, then
720 * add BUSY and ACCESSED) 720 * add BUSY and ACCESSED)
721 */ 721 */
@@ -736,7 +736,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
736BEGIN_FTR_SECTION 736BEGIN_FTR_SECTION
737 cmpdi r9,0 /* check segment size */ 737 cmpdi r9,0 /* check segment size */
738 bne 3f 738 bne 3f
739END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) 739END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
740 /* Calc va and put it in r29 */ 740 /* Calc va and put it in r29 */
741 rldicr r29,r5,28,63-28 741 rldicr r29,r5,28,63-28
742 rldicl r3,r3,0,36 742 rldicl r3,r3,0,36
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 784a400e0781..dfd764896db0 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -50,9 +50,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize)
50 case MMU_PAGE_4K: 50 case MMU_PAGE_4K:
51 va &= ~0xffful; 51 va &= ~0xffful;
52 va |= ssize << 8; 52 va |= ssize << 8;
53 asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), 53 asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2)
54 %2) 54 : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206)
55 : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206)
56 : "memory"); 55 : "memory");
57 break; 56 break;
58 default: 57 default:
@@ -61,9 +60,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize)
61 va |= penc << 12; 60 va |= penc << 12;
62 va |= ssize << 8; 61 va |= ssize << 8;
63 va |= 1; /* L */ 62 va |= 1; /* L */
64 asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), 63 asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2)
65 %2) 64 : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206)
66 : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206)
67 : "memory"); 65 : "memory");
68 break; 66 break;
69 } 67 }
@@ -98,8 +96,8 @@ static inline void __tlbiel(unsigned long va, int psize, int ssize)
98 96
99static inline void tlbie(unsigned long va, int psize, int ssize, int local) 97static inline void tlbie(unsigned long va, int psize, int ssize, int local)
100{ 98{
101 unsigned int use_local = local && cpu_has_feature(CPU_FTR_TLBIEL); 99 unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL);
102 int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); 100 int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
103 101
104 if (use_local) 102 if (use_local)
105 use_local = mmu_psize_defs[psize].tlbiel; 103 use_local = mmu_psize_defs[psize].tlbiel;
@@ -503,7 +501,7 @@ static void native_flush_hash_range(unsigned long number, int local)
503 } pte_iterate_hashed_end(); 501 } pte_iterate_hashed_end();
504 } 502 }
505 503
506 if (cpu_has_feature(CPU_FTR_TLBIEL) && 504 if (mmu_has_feature(MMU_FTR_TLBIEL) &&
507 mmu_psize_defs[psize].tlbiel && local) { 505 mmu_psize_defs[psize].tlbiel && local) {
508 asm volatile("ptesync":::"memory"); 506 asm volatile("ptesync":::"memory");
509 for (i = 0; i < number; i++) { 507 for (i = 0; i < number; i++) {
@@ -517,7 +515,7 @@ static void native_flush_hash_range(unsigned long number, int local)
517 } 515 }
518 asm volatile("ptesync":::"memory"); 516 asm volatile("ptesync":::"memory");
519 } else { 517 } else {
520 int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); 518 int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
521 519
522 if (lock_tlbie) 520 if (lock_tlbie)
523 raw_spin_lock(&native_tlbie_lock); 521 raw_spin_lock(&native_tlbie_lock);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 58a022d0f463..26b2872b3d00 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -53,6 +53,7 @@
53#include <asm/sections.h> 53#include <asm/sections.h>
54#include <asm/spu.h> 54#include <asm/spu.h>
55#include <asm/udbg.h> 55#include <asm/udbg.h>
56#include <asm/code-patching.h>
56 57
57#ifdef DEBUG 58#ifdef DEBUG
58#define DBG(fmt...) udbg_printf(fmt) 59#define DBG(fmt...) udbg_printf(fmt)
@@ -258,11 +259,11 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node,
258 for (; size >= 4; size -= 4, ++prop) { 259 for (; size >= 4; size -= 4, ++prop) {
259 if (prop[0] == 40) { 260 if (prop[0] == 40) {
260 DBG("1T segment support detected\n"); 261 DBG("1T segment support detected\n");
261 cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; 262 cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT;
262 return 1; 263 return 1;
263 } 264 }
264 } 265 }
265 cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B; 266 cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B;
266 return 0; 267 return 0;
267} 268}
268 269
@@ -288,7 +289,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
288 if (prop != NULL) { 289 if (prop != NULL) {
289 DBG("Page sizes from device-tree:\n"); 290 DBG("Page sizes from device-tree:\n");
290 size /= 4; 291 size /= 4;
291 cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE); 292 cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
292 while(size > 0) { 293 while(size > 0) {
293 unsigned int shift = prop[0]; 294 unsigned int shift = prop[0];
294 unsigned int slbenc = prop[1]; 295 unsigned int slbenc = prop[1];
@@ -316,7 +317,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
316 break; 317 break;
317 case 0x18: 318 case 0x18:
318 idx = MMU_PAGE_16M; 319 idx = MMU_PAGE_16M;
319 cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE; 320 cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
320 break; 321 break;
321 case 0x22: 322 case 0x22:
322 idx = MMU_PAGE_16G; 323 idx = MMU_PAGE_16G;
@@ -411,7 +412,7 @@ static void __init htab_init_page_sizes(void)
411 * Not in the device-tree, let's fallback on known size 412 * Not in the device-tree, let's fallback on known size
412 * list for 16M capable GP & GR 413 * list for 16M capable GP & GR
413 */ 414 */
414 if (cpu_has_feature(CPU_FTR_16M_PAGE)) 415 if (mmu_has_feature(MMU_FTR_16M_PAGE))
415 memcpy(mmu_psize_defs, mmu_psize_defaults_gp, 416 memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
416 sizeof(mmu_psize_defaults_gp)); 417 sizeof(mmu_psize_defaults_gp));
417 found: 418 found:
@@ -441,7 +442,7 @@ static void __init htab_init_page_sizes(void)
441 mmu_vmalloc_psize = MMU_PAGE_64K; 442 mmu_vmalloc_psize = MMU_PAGE_64K;
442 if (mmu_linear_psize == MMU_PAGE_4K) 443 if (mmu_linear_psize == MMU_PAGE_4K)
443 mmu_linear_psize = MMU_PAGE_64K; 444 mmu_linear_psize = MMU_PAGE_64K;
444 if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) { 445 if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) {
445 /* 446 /*
446 * Don't use 64k pages for ioremap on pSeries, since 447 * Don't use 64k pages for ioremap on pSeries, since
447 * that would stop us accessing the HEA ethernet. 448 * that would stop us accessing the HEA ethernet.
@@ -547,15 +548,7 @@ int remove_section_mapping(unsigned long start, unsigned long end)
547} 548}
548#endif /* CONFIG_MEMORY_HOTPLUG */ 549#endif /* CONFIG_MEMORY_HOTPLUG */
549 550
550static inline void make_bl(unsigned int *insn_addr, void *func) 551#define FUNCTION_TEXT(A) ((*(unsigned long *)(A)))
551{
552 unsigned long funcp = *((unsigned long *)func);
553 int offset = funcp - (unsigned long)insn_addr;
554
555 *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
556 flush_icache_range((unsigned long)insn_addr, 4+
557 (unsigned long)insn_addr);
558}
559 552
560static void __init htab_finish_init(void) 553static void __init htab_finish_init(void)
561{ 554{
@@ -570,16 +563,33 @@ static void __init htab_finish_init(void)
570 extern unsigned int *ht64_call_hpte_remove; 563 extern unsigned int *ht64_call_hpte_remove;
571 extern unsigned int *ht64_call_hpte_updatepp; 564 extern unsigned int *ht64_call_hpte_updatepp;
572 565
573 make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert); 566 patch_branch(ht64_call_hpte_insert1,
574 make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert); 567 FUNCTION_TEXT(ppc_md.hpte_insert),
575 make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove); 568 BRANCH_SET_LINK);
576 make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp); 569 patch_branch(ht64_call_hpte_insert2,
570 FUNCTION_TEXT(ppc_md.hpte_insert),
571 BRANCH_SET_LINK);
572 patch_branch(ht64_call_hpte_remove,
573 FUNCTION_TEXT(ppc_md.hpte_remove),
574 BRANCH_SET_LINK);
575 patch_branch(ht64_call_hpte_updatepp,
576 FUNCTION_TEXT(ppc_md.hpte_updatepp),
577 BRANCH_SET_LINK);
578
577#endif /* CONFIG_PPC_HAS_HASH_64K */ 579#endif /* CONFIG_PPC_HAS_HASH_64K */
578 580
579 make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert); 581 patch_branch(htab_call_hpte_insert1,
580 make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert); 582 FUNCTION_TEXT(ppc_md.hpte_insert),
581 make_bl(htab_call_hpte_remove, ppc_md.hpte_remove); 583 BRANCH_SET_LINK);
582 make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp); 584 patch_branch(htab_call_hpte_insert2,
585 FUNCTION_TEXT(ppc_md.hpte_insert),
586 BRANCH_SET_LINK);
587 patch_branch(htab_call_hpte_remove,
588 FUNCTION_TEXT(ppc_md.hpte_remove),
589 BRANCH_SET_LINK);
590 patch_branch(htab_call_hpte_updatepp,
591 FUNCTION_TEXT(ppc_md.hpte_updatepp),
592 BRANCH_SET_LINK);
583} 593}
584 594
585static void __init htab_initialize(void) 595static void __init htab_initialize(void)
@@ -598,7 +608,7 @@ static void __init htab_initialize(void)
598 /* Initialize page sizes */ 608 /* Initialize page sizes */
599 htab_init_page_sizes(); 609 htab_init_page_sizes();
600 610
601 if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { 611 if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) {
602 mmu_kernel_ssize = MMU_SEGSIZE_1T; 612 mmu_kernel_ssize = MMU_SEGSIZE_1T;
603 mmu_highuser_ssize = MMU_SEGSIZE_1T; 613 mmu_highuser_ssize = MMU_SEGSIZE_1T;
604 printk(KERN_INFO "Using 1TB segments\n"); 614 printk(KERN_INFO "Using 1TB segments\n");
@@ -739,7 +749,7 @@ void __init early_init_mmu(void)
739 749
740 /* Initialize stab / SLB management except on iSeries 750 /* Initialize stab / SLB management except on iSeries
741 */ 751 */
742 if (cpu_has_feature(CPU_FTR_SLB)) 752 if (mmu_has_feature(MMU_FTR_SLB))
743 slb_initialize(); 753 slb_initialize();
744 else if (!firmware_has_feature(FW_FEATURE_ISERIES)) 754 else if (!firmware_has_feature(FW_FEATURE_ISERIES))
745 stab_initialize(get_paca()->stab_real); 755 stab_initialize(get_paca()->stab_real);
@@ -756,7 +766,7 @@ void __cpuinit early_init_mmu_secondary(void)
756 * in real mode on pSeries and we want a virtual address on 766 * in real mode on pSeries and we want a virtual address on
757 * iSeries anyway 767 * iSeries anyway
758 */ 768 */
759 if (cpu_has_feature(CPU_FTR_SLB)) 769 if (mmu_has_feature(MMU_FTR_SLB))
760 slb_initialize(); 770 slb_initialize();
761 else 771 else
762 stab_initialize(get_paca()->stab_addr); 772 stab_initialize(get_paca()->stab_addr);
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 9bb249c3046e..0b9a5c1901b9 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -529,7 +529,7 @@ static int __init hugetlbpage_init(void)
529{ 529{
530 int psize; 530 int psize;
531 531
532 if (!cpu_has_feature(CPU_FTR_16M_PAGE)) 532 if (!mmu_has_feature(MMU_FTR_16M_PAGE))
533 return -ENODEV; 533 return -ENODEV;
534 534
535 for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { 535 for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 2535828aa84b..3bafc3deca6d 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -20,9 +20,205 @@
20#include <linux/idr.h> 20#include <linux/idr.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/gfp.h> 22#include <linux/gfp.h>
23#include <linux/slab.h>
23 24
24#include <asm/mmu_context.h> 25#include <asm/mmu_context.h>
25 26
27#ifdef CONFIG_PPC_ICSWX
28/*
29 * The processor and its L2 cache cause the icswx instruction to
30 * generate a COP_REQ transaction on PowerBus. The transaction has
31 * no address, and the processor does not perform an MMU access
32 * to authenticate the transaction. The command portion of the
33 * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
34 * the coprocessor Process ID (PID), which the coprocessor compares
35 * to the authorized LPID and PID held in the coprocessor, to determine
36 * if the process is authorized to generate the transaction.
37 * The data of the COP_REQ transaction is 128-byte or less and is
38 * placed in cacheable memory on a 128-byte cache line boundary.
39 *
40 * The task to use a coprocessor should use use_cop() to allocate
41 * a coprocessor PID before executing icswx instruction. use_cop()
42 * also enables the coprocessor context switching. Drop_cop() is
43 * used to free the coprocessor PID.
44 *
45 * Example:
46 * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
47 * Each HFI have multiple windows. Each HFI window serves as a
48 * network device sending to and receiving from HFI network.
49 * HFI immediate send function uses icswx instruction. The immediate
50 * send function allows small (single cache-line) packets be sent
51 * without using the regular HFI send FIFO and doorbell, which are
52 * much slower than immediate send.
53 *
54 * For each task intending to use HFI immediate send, the HFI driver
55 * calls use_cop() to obtain a coprocessor PID for the task.
56 * The HFI driver then allocate a free HFI window and save the
57 * coprocessor PID to the HFI window to allow the task to use the
58 * HFI window.
59 *
60 * The HFI driver repeatedly creates immediate send packets and
61 * issues icswx instruction to send data through the HFI window.
62 * The HFI compares the coprocessor PID in the CPU PID register
63 * to the PID held in the HFI window to determine if the transaction
64 * is allowed.
65 *
66 * When the task to release the HFI window, the HFI driver calls
67 * drop_cop() to release the coprocessor PID.
68 */
69
70#define COP_PID_NONE 0
71#define COP_PID_MIN (COP_PID_NONE + 1)
72#define COP_PID_MAX (0xFFFF)
73
74static DEFINE_SPINLOCK(mmu_context_acop_lock);
75static DEFINE_IDA(cop_ida);
76
77void switch_cop(struct mm_struct *next)
78{
79 mtspr(SPRN_PID, next->context.cop_pid);
80 mtspr(SPRN_ACOP, next->context.acop);
81}
82
83static int new_cop_pid(struct ida *ida, int min_id, int max_id,
84 spinlock_t *lock)
85{
86 int index;
87 int err;
88
89again:
90 if (!ida_pre_get(ida, GFP_KERNEL))
91 return -ENOMEM;
92
93 spin_lock(lock);
94 err = ida_get_new_above(ida, min_id, &index);
95 spin_unlock(lock);
96
97 if (err == -EAGAIN)
98 goto again;
99 else if (err)
100 return err;
101
102 if (index > max_id) {
103 spin_lock(lock);
104 ida_remove(ida, index);
105 spin_unlock(lock);
106 return -ENOMEM;
107 }
108
109 return index;
110}
111
112static void sync_cop(void *arg)
113{
114 struct mm_struct *mm = arg;
115
116 if (mm == current->active_mm)
117 switch_cop(current->active_mm);
118}
119
120/**
121 * Start using a coprocessor.
122 * @acop: mask of coprocessor to be used.
123 * @mm: The mm the coprocessor to associate with. Most likely current mm.
124 *
125 * Return a positive PID if successful. Negative errno otherwise.
126 * The returned PID will be fed to the coprocessor to determine if an
127 * icswx transaction is authenticated.
128 */
129int use_cop(unsigned long acop, struct mm_struct *mm)
130{
131 int ret;
132
133 if (!cpu_has_feature(CPU_FTR_ICSWX))
134 return -ENODEV;
135
136 if (!mm || !acop)
137 return -EINVAL;
138
139 /* We need to make sure mm_users doesn't change */
140 down_read(&mm->mmap_sem);
141 spin_lock(mm->context.cop_lockp);
142
143 if (mm->context.cop_pid == COP_PID_NONE) {
144 ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
145 &mmu_context_acop_lock);
146 if (ret < 0)
147 goto out;
148
149 mm->context.cop_pid = ret;
150 }
151 mm->context.acop |= acop;
152
153 sync_cop(mm);
154
155 /*
156 * If this is a threaded process then there might be other threads
157 * running. We need to send an IPI to force them to pick up any
158 * change in PID and ACOP.
159 */
160 if (atomic_read(&mm->mm_users) > 1)
161 smp_call_function(sync_cop, mm, 1);
162
163 ret = mm->context.cop_pid;
164
165out:
166 spin_unlock(mm->context.cop_lockp);
167 up_read(&mm->mmap_sem);
168
169 return ret;
170}
171EXPORT_SYMBOL_GPL(use_cop);
172
173/**
174 * Stop using a coprocessor.
175 * @acop: mask of coprocessor to be stopped.
176 * @mm: The mm the coprocessor associated with.
177 */
178void drop_cop(unsigned long acop, struct mm_struct *mm)
179{
180 int free_pid = COP_PID_NONE;
181
182 if (!cpu_has_feature(CPU_FTR_ICSWX))
183 return;
184
185 if (WARN_ON_ONCE(!mm))
186 return;
187
188 /* We need to make sure mm_users doesn't change */
189 down_read(&mm->mmap_sem);
190 spin_lock(mm->context.cop_lockp);
191
192 mm->context.acop &= ~acop;
193
194 if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
195 free_pid = mm->context.cop_pid;
196 mm->context.cop_pid = COP_PID_NONE;
197 }
198
199 sync_cop(mm);
200
201 /*
202 * If this is a threaded process then there might be other threads
203 * running. We need to send an IPI to force them to pick up any
204 * change in PID and ACOP.
205 */
206 if (atomic_read(&mm->mm_users) > 1)
207 smp_call_function(sync_cop, mm, 1);
208
209 if (free_pid != COP_PID_NONE) {
210 spin_lock(&mmu_context_acop_lock);
211 ida_remove(&cop_ida, free_pid);
212 spin_unlock(&mmu_context_acop_lock);
213 }
214
215 spin_unlock(mm->context.cop_lockp);
216 up_read(&mm->mmap_sem);
217}
218EXPORT_SYMBOL_GPL(drop_cop);
219
220#endif /* CONFIG_PPC_ICSWX */
221
26static DEFINE_SPINLOCK(mmu_context_lock); 222static DEFINE_SPINLOCK(mmu_context_lock);
27static DEFINE_IDA(mmu_context_ida); 223static DEFINE_IDA(mmu_context_ida);
28 224
@@ -31,7 +227,6 @@ static DEFINE_IDA(mmu_context_ida);
31 * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, 227 * Each segment contains 2^28 bytes. Each context maps 2^44 bytes,
32 * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). 228 * so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
33 */ 229 */
34#define NO_CONTEXT 0
35#define MAX_CONTEXT ((1UL << 19) - 1) 230#define MAX_CONTEXT ((1UL << 19) - 1)
36 231
37int __init_new_context(void) 232int __init_new_context(void)
@@ -79,6 +274,16 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
79 slice_set_user_psize(mm, mmu_virtual_psize); 274 slice_set_user_psize(mm, mmu_virtual_psize);
80 subpage_prot_init_new_context(mm); 275 subpage_prot_init_new_context(mm);
81 mm->context.id = index; 276 mm->context.id = index;
277#ifdef CONFIG_PPC_ICSWX
278 mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
279 if (!mm->context.cop_lockp) {
280 __destroy_context(index);
281 subpage_prot_free(mm);
282 mm->context.id = MMU_NO_CONTEXT;
283 return -ENOMEM;
284 }
285 spin_lock_init(mm->context.cop_lockp);
286#endif /* CONFIG_PPC_ICSWX */
82 287
83 return 0; 288 return 0;
84} 289}
@@ -93,7 +298,12 @@ EXPORT_SYMBOL_GPL(__destroy_context);
93 298
94void destroy_context(struct mm_struct *mm) 299void destroy_context(struct mm_struct *mm)
95{ 300{
301#ifdef CONFIG_PPC_ICSWX
302 drop_cop(mm->context.acop, mm);
303 kfree(mm->context.cop_lockp);
304 mm->context.cop_lockp = NULL;
305#endif /* CONFIG_PPC_ICSWX */
96 __destroy_context(mm->context.id); 306 __destroy_context(mm->context.id);
97 subpage_prot_free(mm); 307 subpage_prot_free(mm);
98 mm->context.id = NO_CONTEXT; 308 mm->context.id = MMU_NO_CONTEXT;
99} 309}
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index c0aab52da3a5..336807de550e 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -338,12 +338,14 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
338 return NOTIFY_OK; 338 return NOTIFY_OK;
339 339
340 switch (action) { 340 switch (action) {
341 case CPU_ONLINE: 341 case CPU_UP_PREPARE:
342 case CPU_ONLINE_FROZEN: 342 case CPU_UP_PREPARE_FROZEN:
343 pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu); 343 pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu);
344 stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL); 344 stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL);
345 break; 345 break;
346#ifdef CONFIG_HOTPLUG_CPU 346#ifdef CONFIG_HOTPLUG_CPU
347 case CPU_UP_CANCELED:
348 case CPU_UP_CANCELED_FROZEN:
347 case CPU_DEAD: 349 case CPU_DEAD:
348 case CPU_DEAD_FROZEN: 350 case CPU_DEAD_FROZEN:
349 pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu); 351 pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu);
@@ -407,7 +409,17 @@ void __init mmu_context_init(void)
407 } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { 409 } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) {
408 first_context = 1; 410 first_context = 1;
409 last_context = 65535; 411 last_context = 65535;
410 } else { 412 } else
413#ifdef CONFIG_PPC_BOOK3E_MMU
414 if (mmu_has_feature(MMU_FTR_TYPE_3E)) {
415 u32 mmucfg = mfspr(SPRN_MMUCFG);
416 u32 pid_bits = (mmucfg & MMUCFG_PIDSIZE_MASK)
417 >> MMUCFG_PIDSIZE_SHIFT;
418 first_context = 1;
419 last_context = (1UL << (pid_bits + 1)) - 1;
420 } else
421#endif
422 {
411 first_context = 1; 423 first_context = 1;
412 last_context = 255; 424 last_context = 255;
413 } 425 }
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 5ec1dad2a19d..2164006fe170 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -311,14 +311,13 @@ EXPORT_SYMBOL_GPL(of_node_to_nid);
311static int __init find_min_common_depth(void) 311static int __init find_min_common_depth(void)
312{ 312{
313 int depth; 313 int depth;
314 struct device_node *rtas_root;
315 struct device_node *chosen; 314 struct device_node *chosen;
315 struct device_node *root;
316 const char *vec5; 316 const char *vec5;
317 317
318 rtas_root = of_find_node_by_path("/rtas"); 318 root = of_find_node_by_path("/rtas");
319 319 if (!root)
320 if (!rtas_root) 320 root = of_find_node_by_path("/");
321 return -1;
322 321
323 /* 322 /*
324 * This property is a set of 32-bit integers, each representing 323 * This property is a set of 32-bit integers, each representing
@@ -332,7 +331,7 @@ static int __init find_min_common_depth(void)
332 * NUMA boundary and the following are progressively less significant 331 * NUMA boundary and the following are progressively less significant
333 * boundaries. There can be more than one level of NUMA. 332 * boundaries. There can be more than one level of NUMA.
334 */ 333 */
335 distance_ref_points = of_get_property(rtas_root, 334 distance_ref_points = of_get_property(root,
336 "ibm,associativity-reference-points", 335 "ibm,associativity-reference-points",
337 &distance_ref_points_depth); 336 &distance_ref_points_depth);
338 337
@@ -376,11 +375,11 @@ static int __init find_min_common_depth(void)
376 distance_ref_points_depth = MAX_DISTANCE_REF_POINTS; 375 distance_ref_points_depth = MAX_DISTANCE_REF_POINTS;
377 } 376 }
378 377
379 of_node_put(rtas_root); 378 of_node_put(root);
380 return depth; 379 return depth;
381 380
382err: 381err:
383 of_node_put(rtas_root); 382 of_node_put(root);
384 return -1; 383 return -1;
385} 384}
386 385
@@ -1453,7 +1452,7 @@ int arch_update_cpu_topology(void)
1453 unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0}; 1452 unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
1454 struct sys_device *sysdev; 1453 struct sys_device *sysdev;
1455 1454
1456 for_each_cpu_mask(cpu, cpu_associativity_changes_mask) { 1455 for_each_cpu(cpu,&cpu_associativity_changes_mask) {
1457 vphn_get_associativity(cpu, associativity); 1456 vphn_get_associativity(cpu, associativity);
1458 nid = associativity_to_nid(associativity); 1457 nid = associativity_to_nid(associativity);
1459 1458
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 8dc41c0157fe..51f87956f8f8 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -133,7 +133,15 @@ ioremap(phys_addr_t addr, unsigned long size)
133EXPORT_SYMBOL(ioremap); 133EXPORT_SYMBOL(ioremap);
134 134
135void __iomem * 135void __iomem *
136ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) 136ioremap_wc(phys_addr_t addr, unsigned long size)
137{
138 return __ioremap_caller(addr, size, _PAGE_NO_CACHE,
139 __builtin_return_address(0));
140}
141EXPORT_SYMBOL(ioremap_wc);
142
143void __iomem *
144ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
137{ 145{
138 /* writeable implies dirty for kernel addresses */ 146 /* writeable implies dirty for kernel addresses */
139 if (flags & _PAGE_RW) 147 if (flags & _PAGE_RW)
@@ -152,7 +160,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
152 160
153 return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); 161 return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
154} 162}
155EXPORT_SYMBOL(ioremap_flags); 163EXPORT_SYMBOL(ioremap_prot);
156 164
157void __iomem * 165void __iomem *
158__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) 166__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 88927a05cdc2..6e595f6496d4 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -255,7 +255,17 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size)
255 return __ioremap_caller(addr, size, flags, caller); 255 return __ioremap_caller(addr, size, flags, caller);
256} 256}
257 257
258void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, 258void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size)
259{
260 unsigned long flags = _PAGE_NO_CACHE;
261 void *caller = __builtin_return_address(0);
262
263 if (ppc_md.ioremap)
264 return ppc_md.ioremap(addr, size, flags, caller);
265 return __ioremap_caller(addr, size, flags, caller);
266}
267
268void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size,
259 unsigned long flags) 269 unsigned long flags)
260{ 270{
261 void *caller = __builtin_return_address(0); 271 void *caller = __builtin_return_address(0);
@@ -311,7 +321,8 @@ void iounmap(volatile void __iomem *token)
311} 321}
312 322
313EXPORT_SYMBOL(ioremap); 323EXPORT_SYMBOL(ioremap);
314EXPORT_SYMBOL(ioremap_flags); 324EXPORT_SYMBOL(ioremap_wc);
325EXPORT_SYMBOL(ioremap_prot);
315EXPORT_SYMBOL(__ioremap); 326EXPORT_SYMBOL(__ioremap);
316EXPORT_SYMBOL(__ioremap_at); 327EXPORT_SYMBOL(__ioremap_at);
317EXPORT_SYMBOL(iounmap); 328EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 1d98ecc8eecd..e22276cb67a4 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -24,6 +24,7 @@
24#include <asm/firmware.h> 24#include <asm/firmware.h>
25#include <linux/compiler.h> 25#include <linux/compiler.h>
26#include <asm/udbg.h> 26#include <asm/udbg.h>
27#include <asm/code-patching.h>
27 28
28 29
29extern void slb_allocate_realmode(unsigned long ea); 30extern void slb_allocate_realmode(unsigned long ea);
@@ -166,7 +167,7 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2)
166 int esid_1t_count; 167 int esid_1t_count;
167 168
168 /* System is not 1T segment size capable. */ 169 /* System is not 1T segment size capable. */
169 if (!cpu_has_feature(CPU_FTR_1T_SEGMENT)) 170 if (!mmu_has_feature(MMU_FTR_1T_SEGMENT))
170 return (GET_ESID(addr1) == GET_ESID(addr2)); 171 return (GET_ESID(addr1) == GET_ESID(addr2));
171 172
172 esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + 173 esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) +
@@ -201,7 +202,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
201 */ 202 */
202 hard_irq_disable(); 203 hard_irq_disable();
203 offset = get_paca()->slb_cache_ptr; 204 offset = get_paca()->slb_cache_ptr;
204 if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) && 205 if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) &&
205 offset <= SLB_CACHE_ENTRIES) { 206 offset <= SLB_CACHE_ENTRIES) {
206 int i; 207 int i;
207 asm volatile("isync" : : : "memory"); 208 asm volatile("isync" : : : "memory");
@@ -249,9 +250,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
249static inline void patch_slb_encoding(unsigned int *insn_addr, 250static inline void patch_slb_encoding(unsigned int *insn_addr,
250 unsigned int immed) 251 unsigned int immed)
251{ 252{
252 *insn_addr = (*insn_addr & 0xffff0000) | immed; 253 int insn = (*insn_addr & 0xffff0000) | immed;
253 flush_icache_range((unsigned long)insn_addr, 4+ 254 patch_instruction(insn_addr, insn);
254 (unsigned long)insn_addr);
255} 255}
256 256
257void slb_set_size(u16 size) 257void slb_set_size(u16 size)
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 95ce35581696..ef653dc95b65 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -58,7 +58,7 @@ _GLOBAL(slb_miss_kernel_load_linear)
58 li r11,0 58 li r11,0
59BEGIN_FTR_SECTION 59BEGIN_FTR_SECTION
60 b slb_finish_load 60 b slb_finish_load
61END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) 61END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
62 b slb_finish_load_1T 62 b slb_finish_load_1T
63 63
641: 641:
@@ -87,7 +87,7 @@ _GLOBAL(slb_miss_kernel_load_vmemmap)
876: 876:
88BEGIN_FTR_SECTION 88BEGIN_FTR_SECTION
89 b slb_finish_load 89 b slb_finish_load
90END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) 90END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
91 b slb_finish_load_1T 91 b slb_finish_load_1T
92 92
930: /* user address: proto-VSID = context << 15 | ESID. First check 930: /* user address: proto-VSID = context << 15 | ESID. First check
@@ -138,11 +138,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT)
138 ld r9,PACACONTEXTID(r13) 138 ld r9,PACACONTEXTID(r13)
139BEGIN_FTR_SECTION 139BEGIN_FTR_SECTION
140 cmpldi r10,0x1000 140 cmpldi r10,0x1000
141END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) 141END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
142 rldimi r10,r9,USER_ESID_BITS,0 142 rldimi r10,r9,USER_ESID_BITS,0
143BEGIN_FTR_SECTION 143BEGIN_FTR_SECTION
144 bge slb_finish_load_1T 144 bge slb_finish_load_1T
145END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) 145END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
146 b slb_finish_load 146 b slb_finish_load
147 147
1488: /* invalid EA */ 1488: /* invalid EA */
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 446a01842a73..41e31642a86a 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -243,7 +243,7 @@ void __init stabs_alloc(void)
243{ 243{
244 int cpu; 244 int cpu;
245 245
246 if (cpu_has_feature(CPU_FTR_SLB)) 246 if (mmu_has_feature(MMU_FTR_SLB))
247 return; 247 return;
248 248
249 for_each_possible_cpu(cpu) { 249 for_each_possible_cpu(cpu) {