aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/pgtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm/pgtable.c')
-rw-r--r--arch/powerpc/mm/pgtable.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 53040931de32..ebc2f38eb381 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -22,6 +22,7 @@
22 */ 22 */
23 23
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/gfp.h>
25#include <linux/mm.h> 26#include <linux/mm.h>
26#include <linux/init.h> 27#include <linux/init.h>
27#include <linux/percpu.h> 28#include <linux/percpu.h>
@@ -49,12 +50,12 @@ struct pte_freelist_batch
49{ 50{
50 struct rcu_head rcu; 51 struct rcu_head rcu;
51 unsigned int index; 52 unsigned int index;
52 pgtable_free_t tables[0]; 53 unsigned long tables[0];
53}; 54};
54 55
55#define PTE_FREELIST_SIZE \ 56#define PTE_FREELIST_SIZE \
56 ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ 57 ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
57 / sizeof(pgtable_free_t)) 58 / sizeof(unsigned long))
58 59
59static void pte_free_smp_sync(void *arg) 60static void pte_free_smp_sync(void *arg)
60{ 61{
@@ -64,13 +65,13 @@ static void pte_free_smp_sync(void *arg)
64/* This is only called when we are critically out of memory 65/* This is only called when we are critically out of memory
65 * (and fail to get a page in pte_free_tlb). 66 * (and fail to get a page in pte_free_tlb).
66 */ 67 */
67static void pgtable_free_now(pgtable_free_t pgf) 68static void pgtable_free_now(void *table, unsigned shift)
68{ 69{
69 pte_freelist_forced_free++; 70 pte_freelist_forced_free++;
70 71
71 smp_call_function(pte_free_smp_sync, NULL, 1); 72 smp_call_function(pte_free_smp_sync, NULL, 1);
72 73
73 pgtable_free(pgf); 74 pgtable_free(table, shift);
74} 75}
75 76
76static void pte_free_rcu_callback(struct rcu_head *head) 77static void pte_free_rcu_callback(struct rcu_head *head)
@@ -79,8 +80,12 @@ static void pte_free_rcu_callback(struct rcu_head *head)
79 container_of(head, struct pte_freelist_batch, rcu); 80 container_of(head, struct pte_freelist_batch, rcu);
80 unsigned int i; 81 unsigned int i;
81 82
82 for (i = 0; i < batch->index; i++) 83 for (i = 0; i < batch->index; i++) {
83 pgtable_free(batch->tables[i]); 84 void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE);
85 unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE;
86
87 pgtable_free(table, shift);
88 }
84 89
85 free_page((unsigned long)batch); 90 free_page((unsigned long)batch);
86} 91}
@@ -91,25 +96,28 @@ static void pte_free_submit(struct pte_freelist_batch *batch)
91 call_rcu(&batch->rcu, pte_free_rcu_callback); 96 call_rcu(&batch->rcu, pte_free_rcu_callback);
92} 97}
93 98
94void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) 99void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
95{ 100{
96 /* This is safe since tlb_gather_mmu has disabled preemption */ 101 /* This is safe since tlb_gather_mmu has disabled preemption */
97 struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); 102 struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
103 unsigned long pgf;
98 104
99 if (atomic_read(&tlb->mm->mm_users) < 2 || 105 if (atomic_read(&tlb->mm->mm_users) < 2 ||
100 cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){ 106 cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
101 pgtable_free(pgf); 107 pgtable_free(table, shift);
102 return; 108 return;
103 } 109 }
104 110
105 if (*batchp == NULL) { 111 if (*batchp == NULL) {
106 *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); 112 *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
107 if (*batchp == NULL) { 113 if (*batchp == NULL) {
108 pgtable_free_now(pgf); 114 pgtable_free_now(table, shift);
109 return; 115 return;
110 } 116 }
111 (*batchp)->index = 0; 117 (*batchp)->index = 0;
112 } 118 }
119 BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
120 pgf = (unsigned long)table | shift;
113 (*batchp)->tables[(*batchp)->index++] = pgf; 121 (*batchp)->tables[(*batchp)->index++] = pgf;
114 if ((*batchp)->index == PTE_FREELIST_SIZE) { 122 if ((*batchp)->index == PTE_FREELIST_SIZE) {
115 pte_free_submit(*batchp); 123 pte_free_submit(*batchp);