sparc64: Handle extremely large kernel TLB range flushes more gracefully.
When the vmalloc area gets fragmented, and because the firmware mapping area sits between where modules live and the vmalloc area, we can sometimes receive requests for enormous kernel TLB range flushes. When this happens the cpu just spins flushing billions of pages and this triggers the NMI watchdog and other problems. We took care of this on the TSB side by doing a linear scan of the table once we pass a certain threshold. Do something similar for the TLB flush, however we are limited by the TLB flush facilities provided by the different chip variants. First of all we use an (mostly arbitrary) cut-off of 256K which is about 32 pages. This can be tuned in the future. The huge range code path for each chip works as follows: 1) On spitfire we flush all non-locked TLB entries using diagnostic acceses. 2) On cheetah we use the "flush all" TLB flush. 3) On sun4v/hypervisor we do a TLB context flush on context 0, which unlike previous chips does not remove "permanent" or locked entries. We could probably do something better on spitfire, such as limiting the flush to kernel TLB entries or even doing range comparisons. However that probably isn't worth it since those chips are old and the TLB only had 64 entries. Reported-by: James Clarke <jrtc27@jrtc27.com> Tested-by: James Clarke <jrtc27@jrtc27.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a236441bb6
commit
a74ad5e660
|
@ -113,12 +113,14 @@ __flush_tlb_pending: /* 27 insns */
|
|||
|
||||
.align 32
|
||||
.globl __flush_tlb_kernel_range
|
||||
__flush_tlb_kernel_range: /* 19 insns */
|
||||
__flush_tlb_kernel_range: /* 31 insns */
|
||||
/* %o0=start, %o1=end */
|
||||
cmp %o0, %o1
|
||||
be,pn %xcc, 2f
|
||||
sub %o1, %o0, %o3
|
||||
srlx %o3, 18, %o4
|
||||
brnz,pn %o4, __spitfire_flush_tlb_kernel_range_slow
|
||||
sethi %hi(PAGE_SIZE), %o4
|
||||
sub %o1, %o0, %o3
|
||||
sub %o3, %o4, %o3
|
||||
or %o0, 0x20, %o0 ! Nucleus
|
||||
1: stxa %g0, [%o0 + %o3] ASI_DMMU_DEMAP
|
||||
|
@ -134,6 +136,38 @@ __flush_tlb_kernel_range: /* 19 insns */
|
|||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
__spitfire_flush_tlb_kernel_range_slow:
|
||||
mov 63 * 8, %o4
|
||||
1: ldxa [%o4] ASI_ITLB_DATA_ACCESS, %o3
|
||||
andcc %o3, 0x40, %g0 /* _PAGE_L_4U */
|
||||
bne,pn %xcc, 2f
|
||||
mov TLB_TAG_ACCESS, %o3
|
||||
stxa %g0, [%o3] ASI_IMMU
|
||||
stxa %g0, [%o4] ASI_ITLB_DATA_ACCESS
|
||||
membar #Sync
|
||||
2: ldxa [%o4] ASI_DTLB_DATA_ACCESS, %o3
|
||||
andcc %o3, 0x40, %g0
|
||||
bne,pn %xcc, 2f
|
||||
mov TLB_TAG_ACCESS, %o3
|
||||
stxa %g0, [%o3] ASI_DMMU
|
||||
stxa %g0, [%o4] ASI_DTLB_DATA_ACCESS
|
||||
membar #Sync
|
||||
2: sub %o4, 8, %o4
|
||||
brgez,pt %o4, 1b
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
__spitfire_flush_tlb_mm_slow:
|
||||
rdpr %pstate, %g1
|
||||
|
@ -288,6 +322,40 @@ __cheetah_flush_tlb_pending: /* 27 insns */
|
|||
retl
|
||||
wrpr %g7, 0x0, %pstate
|
||||
|
||||
__cheetah_flush_tlb_kernel_range: /* 31 insns */
|
||||
/* %o0=start, %o1=end */
|
||||
cmp %o0, %o1
|
||||
be,pn %xcc, 2f
|
||||
sub %o1, %o0, %o3
|
||||
srlx %o3, 18, %o4
|
||||
brnz,pn %o4, 3f
|
||||
sethi %hi(PAGE_SIZE), %o4
|
||||
sub %o3, %o4, %o3
|
||||
or %o0, 0x20, %o0 ! Nucleus
|
||||
1: stxa %g0, [%o0 + %o3] ASI_DMMU_DEMAP
|
||||
stxa %g0, [%o0 + %o3] ASI_IMMU_DEMAP
|
||||
membar #Sync
|
||||
brnz,pt %o3, 1b
|
||||
sub %o3, %o4, %o3
|
||||
2: sethi %hi(KERNBASE), %o3
|
||||
flush %o3
|
||||
retl
|
||||
nop
|
||||
3: mov 0x80, %o4
|
||||
stxa %g0, [%o4] ASI_DMMU_DEMAP
|
||||
membar #Sync
|
||||
stxa %g0, [%o4] ASI_IMMU_DEMAP
|
||||
membar #Sync
|
||||
retl
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
__cheetah_flush_dcache_page: /* 11 insns */
|
||||
sethi %hi(PAGE_OFFSET), %g1
|
||||
|
@ -388,13 +456,15 @@ __hypervisor_flush_tlb_pending: /* 27 insns */
|
|||
nop
|
||||
nop
|
||||
|
||||
__hypervisor_flush_tlb_kernel_range: /* 19 insns */
|
||||
__hypervisor_flush_tlb_kernel_range: /* 31 insns */
|
||||
/* %o0=start, %o1=end */
|
||||
cmp %o0, %o1
|
||||
be,pn %xcc, 2f
|
||||
sethi %hi(PAGE_SIZE), %g3
|
||||
mov %o0, %g1
|
||||
sub %o1, %g1, %g2
|
||||
sub %o1, %o0, %g2
|
||||
srlx %g2, 18, %g3
|
||||
brnz,pn %g3, 4f
|
||||
mov %o0, %g1
|
||||
sethi %hi(PAGE_SIZE), %g3
|
||||
sub %g2, %g3, %g2
|
||||
1: add %g1, %g2, %o0 /* ARG0: virtual address */
|
||||
mov 0, %o1 /* ARG1: mmu context */
|
||||
|
@ -409,6 +479,16 @@ __hypervisor_flush_tlb_kernel_range: /* 19 insns */
|
|||
3: sethi %hi(__hypervisor_tlb_tl0_error), %o2
|
||||
jmpl %o2 + %lo(__hypervisor_tlb_tl0_error), %g0
|
||||
nop
|
||||
4: mov 0, %o0 /* ARG0: CPU lists unimplemented */
|
||||
mov 0, %o1 /* ARG1: CPU lists unimplemented */
|
||||
mov 0, %o2 /* ARG2: mmu context == nucleus */
|
||||
mov HV_MMU_ALL, %o3 /* ARG3: flags */
|
||||
mov HV_FAST_MMU_DEMAP_CTX, %o5
|
||||
ta HV_FAST_TRAP
|
||||
brnz,pn %o0, 3b
|
||||
mov HV_FAST_MMU_DEMAP_CTX, %o1
|
||||
retl
|
||||
nop
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
/* XXX Niagara and friends have an 8K cache, so no aliasing is
|
||||
|
@ -431,43 +511,6 @@ tlb_patch_one:
|
|||
retl
|
||||
nop
|
||||
|
||||
.globl cheetah_patch_cachetlbops
|
||||
cheetah_patch_cachetlbops:
|
||||
save %sp, -128, %sp
|
||||
|
||||
sethi %hi(__flush_tlb_mm), %o0
|
||||
or %o0, %lo(__flush_tlb_mm), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_mm), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_mm), %o1
|
||||
call tlb_patch_one
|
||||
mov 19, %o2
|
||||
|
||||
sethi %hi(__flush_tlb_page), %o0
|
||||
or %o0, %lo(__flush_tlb_page), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_page), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_page), %o1
|
||||
call tlb_patch_one
|
||||
mov 22, %o2
|
||||
|
||||
sethi %hi(__flush_tlb_pending), %o0
|
||||
or %o0, %lo(__flush_tlb_pending), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_pending), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_pending), %o1
|
||||
call tlb_patch_one
|
||||
mov 27, %o2
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
sethi %hi(__flush_dcache_page), %o0
|
||||
or %o0, %lo(__flush_dcache_page), %o0
|
||||
sethi %hi(__cheetah_flush_dcache_page), %o1
|
||||
or %o1, %lo(__cheetah_flush_dcache_page), %o1
|
||||
call tlb_patch_one
|
||||
mov 11, %o2
|
||||
#endif /* DCACHE_ALIASING_POSSIBLE */
|
||||
|
||||
ret
|
||||
restore
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* These are all called by the slaves of a cross call, at
|
||||
* trap level 1, with interrupts fully disabled.
|
||||
|
@ -535,13 +578,15 @@ xcall_flush_tlb_page: /* 20 insns */
|
|||
nop
|
||||
|
||||
.globl xcall_flush_tlb_kernel_range
|
||||
xcall_flush_tlb_kernel_range: /* 28 insns */
|
||||
xcall_flush_tlb_kernel_range: /* 44 insns */
|
||||
sethi %hi(PAGE_SIZE - 1), %g2
|
||||
or %g2, %lo(PAGE_SIZE - 1), %g2
|
||||
andn %g1, %g2, %g1
|
||||
andn %g7, %g2, %g7
|
||||
sub %g7, %g1, %g3
|
||||
add %g2, 1, %g2
|
||||
srlx %g3, 18, %g2
|
||||
brnz,pn %g2, 2f
|
||||
add %g2, 1, %g2
|
||||
sub %g3, %g2, %g3
|
||||
or %g1, 0x20, %g1 ! Nucleus
|
||||
1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
|
||||
|
@ -550,11 +595,25 @@ xcall_flush_tlb_kernel_range: /* 28 insns */
|
|||
brnz,pt %g3, 1b
|
||||
sub %g3, %g2, %g3
|
||||
retry
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
2: mov 63 * 8, %g1
|
||||
1: ldxa [%g1] ASI_ITLB_DATA_ACCESS, %g2
|
||||
andcc %g2, 0x40, %g0 /* _PAGE_L_4U */
|
||||
bne,pn %xcc, 2f
|
||||
mov TLB_TAG_ACCESS, %g2
|
||||
stxa %g0, [%g2] ASI_IMMU
|
||||
stxa %g0, [%g1] ASI_ITLB_DATA_ACCESS
|
||||
membar #Sync
|
||||
2: ldxa [%g1] ASI_DTLB_DATA_ACCESS, %g2
|
||||
andcc %g2, 0x40, %g0
|
||||
bne,pn %xcc, 2f
|
||||
mov TLB_TAG_ACCESS, %g2
|
||||
stxa %g0, [%g2] ASI_DMMU
|
||||
stxa %g0, [%g1] ASI_DTLB_DATA_ACCESS
|
||||
membar #Sync
|
||||
2: sub %g1, 8, %g1
|
||||
brgez,pt %g1, 1b
|
||||
nop
|
||||
retry
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
@ -683,6 +742,52 @@ xcall_fetch_glob_pmu_n4:
|
|||
|
||||
retry
|
||||
|
||||
__cheetah_xcall_flush_tlb_kernel_range: /* 44 insns */
|
||||
sethi %hi(PAGE_SIZE - 1), %g2
|
||||
or %g2, %lo(PAGE_SIZE - 1), %g2
|
||||
andn %g1, %g2, %g1
|
||||
andn %g7, %g2, %g7
|
||||
sub %g7, %g1, %g3
|
||||
srlx %g3, 18, %g2
|
||||
brnz,pn %g2, 2f
|
||||
add %g2, 1, %g2
|
||||
sub %g3, %g2, %g3
|
||||
or %g1, 0x20, %g1 ! Nucleus
|
||||
1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
|
||||
stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP
|
||||
membar #Sync
|
||||
brnz,pt %g3, 1b
|
||||
sub %g3, %g2, %g3
|
||||
retry
|
||||
2: mov 0x80, %g2
|
||||
stxa %g0, [%g2] ASI_DMMU_DEMAP
|
||||
membar #Sync
|
||||
stxa %g0, [%g2] ASI_IMMU_DEMAP
|
||||
membar #Sync
|
||||
retry
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
.align 32
|
||||
.globl xcall_flush_dcache_page_cheetah
|
||||
|
@ -798,18 +903,20 @@ __hypervisor_xcall_flush_tlb_page: /* 20 insns */
|
|||
nop
|
||||
|
||||
.globl __hypervisor_xcall_flush_tlb_kernel_range
|
||||
__hypervisor_xcall_flush_tlb_kernel_range: /* 28 insns */
|
||||
__hypervisor_xcall_flush_tlb_kernel_range: /* 44 insns */
|
||||
/* %g1=start, %g7=end, g2,g3,g4,g5,g6=scratch */
|
||||
sethi %hi(PAGE_SIZE - 1), %g2
|
||||
or %g2, %lo(PAGE_SIZE - 1), %g2
|
||||
andn %g1, %g2, %g1
|
||||
andn %g7, %g2, %g7
|
||||
sub %g7, %g1, %g3
|
||||
srlx %g3, 18, %g7
|
||||
add %g2, 1, %g2
|
||||
sub %g3, %g2, %g3
|
||||
mov %o0, %g2
|
||||
mov %o1, %g4
|
||||
mov %o2, %g7
|
||||
brnz,pn %g7, 2f
|
||||
mov %o2, %g7
|
||||
1: add %g1, %g3, %o0 /* ARG0: virtual address */
|
||||
mov 0, %o1 /* ARG1: mmu context */
|
||||
mov HV_MMU_ALL, %o2 /* ARG2: flags */
|
||||
|
@ -820,7 +927,7 @@ __hypervisor_xcall_flush_tlb_kernel_range: /* 28 insns */
|
|||
sethi %hi(PAGE_SIZE), %o2
|
||||
brnz,pt %g3, 1b
|
||||
sub %g3, %o2, %g3
|
||||
mov %g2, %o0
|
||||
5: mov %g2, %o0
|
||||
mov %g4, %o1
|
||||
mov %g7, %o2
|
||||
membar #Sync
|
||||
|
@ -828,6 +935,20 @@ __hypervisor_xcall_flush_tlb_kernel_range: /* 28 insns */
|
|||
1: sethi %hi(__hypervisor_tlb_xcall_error), %g4
|
||||
jmpl %g4 + %lo(__hypervisor_tlb_xcall_error), %g0
|
||||
nop
|
||||
2: mov %o3, %g1
|
||||
mov %o5, %g3
|
||||
mov 0, %o0 /* ARG0: CPU lists unimplemented */
|
||||
mov 0, %o1 /* ARG1: CPU lists unimplemented */
|
||||
mov 0, %o2 /* ARG2: mmu context == nucleus */
|
||||
mov HV_MMU_ALL, %o3 /* ARG3: flags */
|
||||
mov HV_FAST_MMU_DEMAP_CTX, %o5
|
||||
ta HV_FAST_TRAP
|
||||
mov %g1, %o3
|
||||
brz,pt %o0, 5b
|
||||
mov %g3, %o5
|
||||
mov HV_FAST_MMU_DEMAP_CTX, %g6
|
||||
ba,pt %xcc, 1b
|
||||
clr %g5
|
||||
|
||||
/* These just get rescheduled to PIL vectors. */
|
||||
.globl xcall_call_function
|
||||
|
@ -864,6 +985,58 @@ xcall_kgdb_capture:
|
|||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
.globl cheetah_patch_cachetlbops
|
||||
cheetah_patch_cachetlbops:
|
||||
save %sp, -128, %sp
|
||||
|
||||
sethi %hi(__flush_tlb_mm), %o0
|
||||
or %o0, %lo(__flush_tlb_mm), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_mm), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_mm), %o1
|
||||
call tlb_patch_one
|
||||
mov 19, %o2
|
||||
|
||||
sethi %hi(__flush_tlb_page), %o0
|
||||
or %o0, %lo(__flush_tlb_page), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_page), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_page), %o1
|
||||
call tlb_patch_one
|
||||
mov 22, %o2
|
||||
|
||||
sethi %hi(__flush_tlb_pending), %o0
|
||||
or %o0, %lo(__flush_tlb_pending), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_pending), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_pending), %o1
|
||||
call tlb_patch_one
|
||||
mov 27, %o2
|
||||
|
||||
sethi %hi(__flush_tlb_kernel_range), %o0
|
||||
or %o0, %lo(__flush_tlb_kernel_range), %o0
|
||||
sethi %hi(__cheetah_flush_tlb_kernel_range), %o1
|
||||
or %o1, %lo(__cheetah_flush_tlb_kernel_range), %o1
|
||||
call tlb_patch_one
|
||||
mov 31, %o2
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
sethi %hi(__flush_dcache_page), %o0
|
||||
or %o0, %lo(__flush_dcache_page), %o0
|
||||
sethi %hi(__cheetah_flush_dcache_page), %o1
|
||||
or %o1, %lo(__cheetah_flush_dcache_page), %o1
|
||||
call tlb_patch_one
|
||||
mov 11, %o2
|
||||
#endif /* DCACHE_ALIASING_POSSIBLE */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
sethi %hi(xcall_flush_tlb_kernel_range), %o0
|
||||
or %o0, %lo(xcall_flush_tlb_kernel_range), %o0
|
||||
sethi %hi(__cheetah_xcall_flush_tlb_kernel_range), %o1
|
||||
or %o1, %lo(__cheetah_xcall_flush_tlb_kernel_range), %o1
|
||||
call tlb_patch_one
|
||||
mov 44, %o2
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
ret
|
||||
restore
|
||||
|
||||
.globl hypervisor_patch_cachetlbops
|
||||
hypervisor_patch_cachetlbops:
|
||||
|
@ -895,7 +1068,7 @@ hypervisor_patch_cachetlbops:
|
|||
sethi %hi(__hypervisor_flush_tlb_kernel_range), %o1
|
||||
or %o1, %lo(__hypervisor_flush_tlb_kernel_range), %o1
|
||||
call tlb_patch_one
|
||||
mov 19, %o2
|
||||
mov 31, %o2
|
||||
|
||||
#ifdef DCACHE_ALIASING_POSSIBLE
|
||||
sethi %hi(__flush_dcache_page), %o0
|
||||
|
@ -926,7 +1099,7 @@ hypervisor_patch_cachetlbops:
|
|||
sethi %hi(__hypervisor_xcall_flush_tlb_kernel_range), %o1
|
||||
or %o1, %lo(__hypervisor_xcall_flush_tlb_kernel_range), %o1
|
||||
call tlb_patch_one
|
||||
mov 28, %o2
|
||||
mov 44, %o2
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
ret
|
||||
|
|
Loading…
Reference in New Issue