diff options
Diffstat (limited to 'arch/tile/mm')
-rw-r--r-- | arch/tile/mm/fault.c | 22 | ||||
-rw-r--r-- | arch/tile/mm/homecache.c | 1 | ||||
-rw-r--r-- | arch/tile/mm/init.c | 26 | ||||
-rw-r--r-- | arch/tile/mm/pgtable.c | 38 |
4 files changed, 56 insertions, 31 deletions
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index cba30e9547b4..22e58f51ed23 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c | |||
@@ -130,7 +130,7 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Handle a fault on the vmalloc or module mapping area | 133 | * Handle a fault on the vmalloc area. |
134 | */ | 134 | */ |
135 | static inline int vmalloc_fault(pgd_t *pgd, unsigned long address) | 135 | static inline int vmalloc_fault(pgd_t *pgd, unsigned long address) |
136 | { | 136 | { |
@@ -203,9 +203,14 @@ static pgd_t *get_current_pgd(void) | |||
203 | * interrupt or a critical region, and must do as little as possible. | 203 | * interrupt or a critical region, and must do as little as possible. |
204 | * Similarly, we can't use atomic ops here, since we may be handling a | 204 | * Similarly, we can't use atomic ops here, since we may be handling a |
205 | * fault caused by an atomic op access. | 205 | * fault caused by an atomic op access. |
206 | * | ||
207 | * If we find a migrating PTE while we're in an NMI context, and we're | ||
208 | * at a PC that has a registered exception handler, we don't wait, | ||
209 | * since this thread may (e.g.) have been interrupted while migrating | ||
210 | * its own stack, which would then cause us to self-deadlock. | ||
206 | */ | 211 | */ |
207 | static int handle_migrating_pte(pgd_t *pgd, int fault_num, | 212 | static int handle_migrating_pte(pgd_t *pgd, int fault_num, |
208 | unsigned long address, | 213 | unsigned long address, unsigned long pc, |
209 | int is_kernel_mode, int write) | 214 | int is_kernel_mode, int write) |
210 | { | 215 | { |
211 | pud_t *pud; | 216 | pud_t *pud; |
@@ -227,6 +232,8 @@ static int handle_migrating_pte(pgd_t *pgd, int fault_num, | |||
227 | pte_offset_kernel(pmd, address); | 232 | pte_offset_kernel(pmd, address); |
228 | pteval = *pte; | 233 | pteval = *pte; |
229 | if (pte_migrating(pteval)) { | 234 | if (pte_migrating(pteval)) { |
235 | if (in_nmi() && search_exception_tables(pc)) | ||
236 | return 0; | ||
230 | wait_for_migration(pte); | 237 | wait_for_migration(pte); |
231 | return 1; | 238 | return 1; |
232 | } | 239 | } |
@@ -300,7 +307,7 @@ static int handle_page_fault(struct pt_regs *regs, | |||
300 | * rather than trying to patch up the existing PTE. | 307 | * rather than trying to patch up the existing PTE. |
301 | */ | 308 | */ |
302 | pgd = get_current_pgd(); | 309 | pgd = get_current_pgd(); |
303 | if (handle_migrating_pte(pgd, fault_num, address, | 310 | if (handle_migrating_pte(pgd, fault_num, address, regs->pc, |
304 | is_kernel_mode, write)) | 311 | is_kernel_mode, write)) |
305 | return 1; | 312 | return 1; |
306 | 313 | ||
@@ -335,9 +342,12 @@ static int handle_page_fault(struct pt_regs *regs, | |||
335 | /* | 342 | /* |
336 | * If we're trying to touch user-space addresses, we must | 343 | * If we're trying to touch user-space addresses, we must |
337 | * be either at PL0, or else with interrupts enabled in the | 344 | * be either at PL0, or else with interrupts enabled in the |
338 | * kernel, so either way we can re-enable interrupts here. | 345 | * kernel, so either way we can re-enable interrupts here |
346 | * unless we are doing atomic access to user space with | ||
347 | * interrupts disabled. | ||
339 | */ | 348 | */ |
340 | local_irq_enable(); | 349 | if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) |
350 | local_irq_enable(); | ||
341 | 351 | ||
342 | mm = tsk->mm; | 352 | mm = tsk->mm; |
343 | 353 | ||
@@ -665,7 +675,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num, | |||
665 | */ | 675 | */ |
666 | if (fault_num == INT_DTLB_ACCESS) | 676 | if (fault_num == INT_DTLB_ACCESS) |
667 | write = 1; | 677 | write = 1; |
668 | if (handle_migrating_pte(pgd, fault_num, address, 1, write)) | 678 | if (handle_migrating_pte(pgd, fault_num, address, pc, 1, write)) |
669 | return state; | 679 | return state; |
670 | 680 | ||
671 | /* Return zero so that we continue on with normal fault handling. */ | 681 | /* Return zero so that we continue on with normal fault handling. */ |
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c index 1cc6ae477c98..499f73770b05 100644 --- a/arch/tile/mm/homecache.c +++ b/arch/tile/mm/homecache.c | |||
@@ -394,6 +394,7 @@ int page_home(struct page *page) | |||
394 | return pte_to_home(*virt_to_pte(NULL, kva)); | 394 | return pte_to_home(*virt_to_pte(NULL, kva)); |
395 | } | 395 | } |
396 | } | 396 | } |
397 | EXPORT_SYMBOL(page_home); | ||
397 | 398 | ||
398 | void homecache_change_page_home(struct page *page, int order, int home) | 399 | void homecache_change_page_home(struct page *page, int order, int home) |
399 | { | 400 | { |
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index 830c4908ea76..6a9d20ddc34f 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c | |||
@@ -254,11 +254,6 @@ static pgprot_t __init init_pgprot(ulong address) | |||
254 | return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE); | 254 | return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE); |
255 | } | 255 | } |
256 | 256 | ||
257 | /* As a performance optimization, keep the boot init stack here. */ | ||
258 | if (address >= (ulong)&init_thread_union && | ||
259 | address < (ulong)&init_thread_union + THREAD_SIZE) | ||
260 | return construct_pgprot(PAGE_KERNEL, smp_processor_id()); | ||
261 | |||
262 | #ifndef __tilegx__ | 257 | #ifndef __tilegx__ |
263 | #if !ATOMIC_LOCKS_FOUND_VIA_TABLE() | 258 | #if !ATOMIC_LOCKS_FOUND_VIA_TABLE() |
264 | /* Force the atomic_locks[] array page to be hash-for-home. */ | 259 | /* Force the atomic_locks[] array page to be hash-for-home. */ |
@@ -557,6 +552,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
557 | 552 | ||
558 | address = MEM_SV_INTRPT; | 553 | address = MEM_SV_INTRPT; |
559 | pmd = get_pmd(pgtables, address); | 554 | pmd = get_pmd(pgtables, address); |
555 | pfn = 0; /* code starts at PA 0 */ | ||
560 | if (ktext_small) { | 556 | if (ktext_small) { |
561 | /* Allocate an L2 PTE for the kernel text */ | 557 | /* Allocate an L2 PTE for the kernel text */ |
562 | int cpu = 0; | 558 | int cpu = 0; |
@@ -579,10 +575,15 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
579 | } | 575 | } |
580 | 576 | ||
581 | BUG_ON(address != (unsigned long)_stext); | 577 | BUG_ON(address != (unsigned long)_stext); |
582 | pfn = 0; /* code starts at PA 0 */ | 578 | pte = NULL; |
583 | pte = alloc_pte(); | 579 | for (; address < (unsigned long)_einittext; |
584 | for (pte_ofs = 0; address < (unsigned long)_einittext; | 580 | pfn++, address += PAGE_SIZE) { |
585 | pfn++, pte_ofs++, address += PAGE_SIZE) { | 581 | pte_ofs = pte_index(address); |
582 | if (pte_ofs == 0) { | ||
583 | if (pte) | ||
584 | assign_pte(pmd++, pte); | ||
585 | pte = alloc_pte(); | ||
586 | } | ||
586 | if (!ktext_local) { | 587 | if (!ktext_local) { |
587 | prot = set_remote_cache_cpu(prot, cpu); | 588 | prot = set_remote_cache_cpu(prot, cpu); |
588 | cpu = cpumask_next(cpu, &ktext_mask); | 589 | cpu = cpumask_next(cpu, &ktext_mask); |
@@ -591,7 +592,8 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
591 | } | 592 | } |
592 | pte[pte_ofs] = pfn_pte(pfn, prot); | 593 | pte[pte_ofs] = pfn_pte(pfn, prot); |
593 | } | 594 | } |
594 | assign_pte(pmd, pte); | 595 | if (pte) |
596 | assign_pte(pmd, pte); | ||
595 | } else { | 597 | } else { |
596 | pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); | 598 | pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); |
597 | pteval = pte_mkhuge(pteval); | 599 | pteval = pte_mkhuge(pteval); |
@@ -614,7 +616,9 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
614 | else | 616 | else |
615 | pteval = hv_pte_set_mode(pteval, | 617 | pteval = hv_pte_set_mode(pteval, |
616 | HV_PTE_MODE_CACHE_NO_L3); | 618 | HV_PTE_MODE_CACHE_NO_L3); |
617 | *(pte_t *)pmd = pteval; | 619 | for (; address < (unsigned long)_einittext; |
620 | pfn += PFN_DOWN(HPAGE_SIZE), address += HPAGE_SIZE) | ||
621 | *(pte_t *)(pmd++) = pfn_pte(pfn, pteval); | ||
618 | } | 622 | } |
619 | 623 | ||
620 | /* Set swapper_pgprot here so it is flushed to memory right away. */ | 624 | /* Set swapper_pgprot here so it is flushed to memory right away. */ |
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c index 87303693a072..2410aa899b3e 100644 --- a/arch/tile/mm/pgtable.c +++ b/arch/tile/mm/pgtable.c | |||
@@ -177,14 +177,10 @@ void shatter_huge_page(unsigned long addr) | |||
177 | if (!pmd_huge_page(*pmd)) | 177 | if (!pmd_huge_page(*pmd)) |
178 | return; | 178 | return; |
179 | 179 | ||
180 | /* | 180 | spin_lock_irqsave(&init_mm.page_table_lock, flags); |
181 | * Grab the pgd_lock, since we may need it to walk the pgd_list, | ||
182 | * and since we need some kind of lock here to avoid races. | ||
183 | */ | ||
184 | spin_lock_irqsave(&pgd_lock, flags); | ||
185 | if (!pmd_huge_page(*pmd)) { | 181 | if (!pmd_huge_page(*pmd)) { |
186 | /* Lost the race to convert the huge page. */ | 182 | /* Lost the race to convert the huge page. */ |
187 | spin_unlock_irqrestore(&pgd_lock, flags); | 183 | spin_unlock_irqrestore(&init_mm.page_table_lock, flags); |
188 | return; | 184 | return; |
189 | } | 185 | } |
190 | 186 | ||
@@ -194,6 +190,7 @@ void shatter_huge_page(unsigned long addr) | |||
194 | 190 | ||
195 | #ifdef __PAGETABLE_PMD_FOLDED | 191 | #ifdef __PAGETABLE_PMD_FOLDED |
196 | /* Walk every pgd on the system and update the pmd there. */ | 192 | /* Walk every pgd on the system and update the pmd there. */ |
193 | spin_lock(&pgd_lock); | ||
197 | list_for_each(pos, &pgd_list) { | 194 | list_for_each(pos, &pgd_list) { |
198 | pmd_t *copy_pmd; | 195 | pmd_t *copy_pmd; |
199 | pgd = list_to_pgd(pos) + pgd_index(addr); | 196 | pgd = list_to_pgd(pos) + pgd_index(addr); |
@@ -201,6 +198,7 @@ void shatter_huge_page(unsigned long addr) | |||
201 | copy_pmd = pmd_offset(pud, addr); | 198 | copy_pmd = pmd_offset(pud, addr); |
202 | __set_pmd(copy_pmd, *pmd); | 199 | __set_pmd(copy_pmd, *pmd); |
203 | } | 200 | } |
201 | spin_unlock(&pgd_lock); | ||
204 | #endif | 202 | #endif |
205 | 203 | ||
206 | /* Tell every cpu to notice the change. */ | 204 | /* Tell every cpu to notice the change. */ |
@@ -208,7 +206,7 @@ void shatter_huge_page(unsigned long addr) | |||
208 | cpu_possible_mask, NULL, 0); | 206 | cpu_possible_mask, NULL, 0); |
209 | 207 | ||
210 | /* Hold the lock until the TLB flush is finished to avoid races. */ | 208 | /* Hold the lock until the TLB flush is finished to avoid races. */ |
211 | spin_unlock_irqrestore(&pgd_lock, flags); | 209 | spin_unlock_irqrestore(&init_mm.page_table_lock, flags); |
212 | } | 210 | } |
213 | 211 | ||
214 | /* | 212 | /* |
@@ -217,9 +215,13 @@ void shatter_huge_page(unsigned long addr) | |||
217 | * against pageattr.c; it is the unique case in which a valid change | 215 | * against pageattr.c; it is the unique case in which a valid change |
218 | * of kernel pagetables can't be lazily synchronized by vmalloc faults. | 216 | * of kernel pagetables can't be lazily synchronized by vmalloc faults. |
219 | * vmalloc faults work because attached pagetables are never freed. | 217 | * vmalloc faults work because attached pagetables are never freed. |
220 | * The locking scheme was chosen on the basis of manfred's | 218 | * |
221 | * recommendations and having no core impact whatsoever. | 219 | * The lock is always taken with interrupts disabled, unlike on x86 |
222 | * -- wli | 220 | * and other platforms, because we need to take the lock in |
221 | * shatter_huge_page(), which may be called from an interrupt context. | ||
222 | * We are not at risk from the tlbflush IPI deadlock that was seen on | ||
223 | * x86, since we use the flush_remote() API to have the hypervisor do | ||
224 | * the TLB flushes regardless of irq disabling. | ||
223 | */ | 225 | */ |
224 | DEFINE_SPINLOCK(pgd_lock); | 226 | DEFINE_SPINLOCK(pgd_lock); |
225 | LIST_HEAD(pgd_list); | 227 | LIST_HEAD(pgd_list); |
@@ -469,10 +471,18 @@ void __set_pte(pte_t *ptep, pte_t pte) | |||
469 | 471 | ||
470 | void set_pte(pte_t *ptep, pte_t pte) | 472 | void set_pte(pte_t *ptep, pte_t pte) |
471 | { | 473 | { |
472 | struct page *page = pfn_to_page(pte_pfn(pte)); | 474 | if (pte_present(pte) && |
473 | 475 | (!CHIP_HAS_MMIO() || hv_pte_get_mode(pte) != HV_PTE_MODE_MMIO)) { | |
474 | /* Update the home of a PTE if necessary */ | 476 | /* The PTE actually references physical memory. */ |
475 | pte = pte_set_home(pte, page_home(page)); | 477 | unsigned long pfn = pte_pfn(pte); |
478 | if (pfn_valid(pfn)) { | ||
479 | /* Update the home of the PTE from the struct page. */ | ||
480 | pte = pte_set_home(pte, page_home(pfn_to_page(pfn))); | ||
481 | } else if (hv_pte_get_mode(pte) == 0) { | ||
482 | /* remap_pfn_range(), etc, must supply PTE mode. */ | ||
483 | panic("set_pte(): out-of-range PFN and mode 0\n"); | ||
484 | } | ||
485 | } | ||
476 | 486 | ||
477 | __set_pte(ptep, pte); | 487 | __set_pte(ptep, pte); |
478 | } | 488 | } |