diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 14:30:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 14:30:20 -0400 |
commit | cab0d85c8dfcad4d799f9c294571440c6f1db091 (patch) | |
tree | ba7b348832673f6c7433b9d7481bfcd415f7a7b5 /arch | |
parent | 57ed609d4b64139b4d2cf5f3b4880a573a7905d2 (diff) | |
parent | 3c5cffb66d8ea94832650fcb55194715b0229088 (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6:
[S390] mm: fix mmu_gather rework
[S390] mm: fix storage key handling
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 16 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 23 |
2 files changed, 24 insertions, 15 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index c4773a2ef3d3..e4efacfe1b63 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -577,16 +577,16 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) | |||
577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) | 577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) |
578 | { | 578 | { |
579 | #ifdef CONFIG_PGSTE | 579 | #ifdef CONFIG_PGSTE |
580 | unsigned long pfn, bits; | 580 | unsigned long address, bits; |
581 | unsigned char skey; | 581 | unsigned char skey; |
582 | 582 | ||
583 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | 583 | address = pte_val(*ptep) & PAGE_MASK; |
584 | skey = page_get_storage_key(pfn); | 584 | skey = page_get_storage_key(address); |
585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); | 585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
586 | /* Clear page changed & referenced bit in the storage key */ | 586 | /* Clear page changed & referenced bit in the storage key */ |
587 | if (bits) { | 587 | if (bits) { |
588 | skey ^= bits; | 588 | skey ^= bits; |
589 | page_set_storage_key(pfn, skey, 1); | 589 | page_set_storage_key(address, skey, 1); |
590 | } | 590 | } |
591 | /* Transfer page changed & referenced bit to guest bits in pgste */ | 591 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ | 592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ |
@@ -628,16 +628,16 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | |||
628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) | 628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) |
629 | { | 629 | { |
630 | #ifdef CONFIG_PGSTE | 630 | #ifdef CONFIG_PGSTE |
631 | unsigned long pfn; | 631 | unsigned long address; |
632 | unsigned long okey, nkey; | 632 | unsigned long okey, nkey; |
633 | 633 | ||
634 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | 634 | address = pte_val(*ptep) & PAGE_MASK; |
635 | okey = nkey = page_get_storage_key(pfn); | 635 | okey = nkey = page_get_storage_key(address); |
636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); | 636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); |
637 | /* Set page access key and fetch protection bit from pgste */ | 637 | /* Set page access key and fetch protection bit from pgste */ |
638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; | 638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; |
639 | if (okey != nkey) | 639 | if (okey != nkey) |
640 | page_set_storage_key(pfn, nkey, 1); | 640 | page_set_storage_key(address, nkey, 1); |
641 | #endif | 641 | #endif |
642 | } | 642 | } |
643 | 643 | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 14c6fae6fe6b..b09763fe5da1 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -71,12 +71,15 @@ static void rcu_table_freelist_callback(struct rcu_head *head) | |||
71 | 71 | ||
72 | void rcu_table_freelist_finish(void) | 72 | void rcu_table_freelist_finish(void) |
73 | { | 73 | { |
74 | struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist); | 74 | struct rcu_table_freelist **batchp = &get_cpu_var(rcu_table_freelist); |
75 | struct rcu_table_freelist *batch = *batchp; | ||
75 | 76 | ||
76 | if (!batch) | 77 | if (!batch) |
77 | return; | 78 | goto out; |
78 | call_rcu(&batch->rcu, rcu_table_freelist_callback); | 79 | call_rcu(&batch->rcu, rcu_table_freelist_callback); |
79 | __get_cpu_var(rcu_table_freelist) = NULL; | 80 | *batchp = NULL; |
81 | out: | ||
82 | put_cpu_var(rcu_table_freelist); | ||
80 | } | 83 | } |
81 | 84 | ||
82 | static void smp_sync(void *arg) | 85 | static void smp_sync(void *arg) |
@@ -141,20 +144,23 @@ void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
141 | { | 144 | { |
142 | struct rcu_table_freelist *batch; | 145 | struct rcu_table_freelist *batch; |
143 | 146 | ||
147 | preempt_disable(); | ||
144 | if (atomic_read(&mm->mm_users) < 2 && | 148 | if (atomic_read(&mm->mm_users) < 2 && |
145 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 149 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
146 | crst_table_free(mm, table); | 150 | crst_table_free(mm, table); |
147 | return; | 151 | goto out; |
148 | } | 152 | } |
149 | batch = rcu_table_freelist_get(mm); | 153 | batch = rcu_table_freelist_get(mm); |
150 | if (!batch) { | 154 | if (!batch) { |
151 | smp_call_function(smp_sync, NULL, 1); | 155 | smp_call_function(smp_sync, NULL, 1); |
152 | crst_table_free(mm, table); | 156 | crst_table_free(mm, table); |
153 | return; | 157 | goto out; |
154 | } | 158 | } |
155 | batch->table[--batch->crst_index] = table; | 159 | batch->table[--batch->crst_index] = table; |
156 | if (batch->pgt_index >= batch->crst_index) | 160 | if (batch->pgt_index >= batch->crst_index) |
157 | rcu_table_freelist_finish(); | 161 | rcu_table_freelist_finish(); |
162 | out: | ||
163 | preempt_enable(); | ||
158 | } | 164 | } |
159 | 165 | ||
160 | #ifdef CONFIG_64BIT | 166 | #ifdef CONFIG_64BIT |
@@ -323,16 +329,17 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
323 | struct page *page; | 329 | struct page *page; |
324 | unsigned long bits; | 330 | unsigned long bits; |
325 | 331 | ||
332 | preempt_disable(); | ||
326 | if (atomic_read(&mm->mm_users) < 2 && | 333 | if (atomic_read(&mm->mm_users) < 2 && |
327 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 334 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
328 | page_table_free(mm, table); | 335 | page_table_free(mm, table); |
329 | return; | 336 | goto out; |
330 | } | 337 | } |
331 | batch = rcu_table_freelist_get(mm); | 338 | batch = rcu_table_freelist_get(mm); |
332 | if (!batch) { | 339 | if (!batch) { |
333 | smp_call_function(smp_sync, NULL, 1); | 340 | smp_call_function(smp_sync, NULL, 1); |
334 | page_table_free(mm, table); | 341 | page_table_free(mm, table); |
335 | return; | 342 | goto out; |
336 | } | 343 | } |
337 | bits = (mm->context.has_pgste) ? 3UL : 1UL; | 344 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
338 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 345 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
@@ -345,6 +352,8 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
345 | batch->table[batch->pgt_index++] = table; | 352 | batch->table[batch->pgt_index++] = table; |
346 | if (batch->pgt_index >= batch->crst_index) | 353 | if (batch->pgt_index >= batch->crst_index) |
347 | rcu_table_freelist_finish(); | 354 | rcu_table_freelist_finish(); |
355 | out: | ||
356 | preempt_enable(); | ||
348 | } | 357 | } |
349 | 358 | ||
350 | /* | 359 | /* |