aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/parisc/include/asm/alternative.h47
-rw-r--r--arch/parisc/include/asm/cache.h22
-rw-r--r--arch/parisc/include/asm/pgtable.h3
-rw-r--r--arch/parisc/include/asm/sections.h2
-rw-r--r--arch/parisc/include/asm/tlbflush.h3
-rw-r--r--arch/parisc/kernel/cache.c12
-rw-r--r--arch/parisc/kernel/entry.S10
-rw-r--r--arch/parisc/kernel/pacache.S64
-rw-r--r--arch/parisc/kernel/setup.c81
-rw-r--r--arch/parisc/kernel/signal.c1
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S6
-rw-r--r--arch/parisc/mm/init.c15
-rw-r--r--drivers/parisc/ccio-dma.c12
-rw-r--r--drivers/parisc/sba_iommu.c17
14 files changed, 233 insertions, 62 deletions
diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h
new file mode 100644
index 000000000000..bf485a94d0b4
--- /dev/null
+++ b/arch/parisc/include/asm/alternative.h
@@ -0,0 +1,47 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __ASM_PARISC_ALTERNATIVE_H
3#define __ASM_PARISC_ALTERNATIVE_H
4
5#define ALT_COND_NO_SMP 0x01 /* when running UP instead of SMP */
6#define ALT_COND_NO_DCACHE 0x02 /* if system has no d-cache */
7#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
8#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
9#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
10
11#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
12#define INSN_NOP 0x08000240 /* nop */
13
14#ifndef __ASSEMBLY__
15
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/stddef.h>
19#include <linux/stringify.h>
20
21struct alt_instr {
22 s32 orig_offset; /* offset to original instructions */
23 u32 len; /* end of original instructions */
24 u32 cond; /* see ALT_COND_XXX */
25 u32 replacement; /* replacement instruction or code */
26};
27
28void set_kernel_text_rw(int enable_read_write);
29
30/* Alternative SMP implementation. */
31#define ALTERNATIVE(cond, replacement) "!0:" \
32 ".section .altinstructions, \"aw\" !" \
33 ".word (0b-4-.), 1, " __stringify(cond) "," \
34 __stringify(replacement) " !" \
35 ".previous"
36
37#else
38
39#define ALTERNATIVE(from, to, cond, replacement)\
40 .section .altinstructions, "aw" ! \
41 .word (from - .), (to - from)/4 ! \
42 .word cond, replacement ! \
43 .previous
44
45#endif /* __ASSEMBLY__ */
46
47#endif /* __ASM_PARISC_ALTERNATIVE_H */
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
index 150b7f30ea90..006fb939cac8 100644
--- a/arch/parisc/include/asm/cache.h
+++ b/arch/parisc/include/asm/cache.h
@@ -6,6 +6,7 @@
6#ifndef __ARCH_PARISC_CACHE_H 6#ifndef __ARCH_PARISC_CACHE_H
7#define __ARCH_PARISC_CACHE_H 7#define __ARCH_PARISC_CACHE_H
8 8
9#include <asm/alternative.h>
9 10
10/* 11/*
11 * PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors 12 * PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors
@@ -41,9 +42,24 @@ extern int icache_stride;
41extern struct pdc_cache_info cache_info; 42extern struct pdc_cache_info cache_info;
42void parisc_setup_cache_timing(void); 43void parisc_setup_cache_timing(void);
43 44
44#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr)); 45#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" \
45#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr)); 46 ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
46#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr)); 47 : : "r" (addr))
48#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" \
49 ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
50 ALTERNATIVE(ALT_COND_NO_SPLIT_TLB, INSN_NOP) \
51 : : "r" (addr))
52#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" \
53 ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
54 : : "r" (addr))
55
56#define asm_io_fdc(addr) asm volatile("fdc %%r0(%0)" \
57 ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
58 ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) \
59 : : "r" (addr))
60#define asm_io_sync() asm volatile("sync" \
61 ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
62 ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) :: )
47 63
48#endif /* ! __ASSEMBLY__ */ 64#endif /* ! __ASSEMBLY__ */
49 65
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index b86c31291f0a..94c0ef7a9e03 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -43,8 +43,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
43{ 43{
44 mtsp(mm->context, 1); 44 mtsp(mm->context, 1);
45 pdtlb(addr); 45 pdtlb(addr);
46 if (unlikely(split_tlb)) 46 pitlb(addr);
47 pitlb(addr);
48} 47}
49 48
50/* Certain architectures need to do special things when PTEs 49/* Certain architectures need to do special things when PTEs
diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h
index 5a40b51df80c..bb52aea0cb21 100644
--- a/arch/parisc/include/asm/sections.h
+++ b/arch/parisc/include/asm/sections.h
@@ -5,6 +5,8 @@
5/* nothing to see, move along */ 5/* nothing to see, move along */
6#include <asm-generic/sections.h> 6#include <asm-generic/sections.h>
7 7
8extern char __alt_instructions[], __alt_instructions_end[];
9
8#ifdef CONFIG_64BIT 10#ifdef CONFIG_64BIT
9 11
10#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1 12#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index 14668bd52d60..6804374efa66 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -85,8 +85,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
85 purge_tlb_start(flags); 85 purge_tlb_start(flags);
86 mtsp(sid, 1); 86 mtsp(sid, 1);
87 pdtlb(addr); 87 pdtlb(addr);
88 if (unlikely(split_tlb)) 88 pitlb(addr);
89 pitlb(addr);
90 purge_tlb_end(flags); 89 purge_tlb_end(flags);
91} 90}
92#endif 91#endif
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 9f1c29d06574..56dc9791ee23 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -479,18 +479,6 @@ int __flush_tlb_range(unsigned long sid, unsigned long start,
479 /* Purge TLB entries for small ranges using the pdtlb and 479 /* Purge TLB entries for small ranges using the pdtlb and
480 pitlb instructions. These instructions execute locally 480 pitlb instructions. These instructions execute locally
481 but cause a purge request to be broadcast to other TLBs. */ 481 but cause a purge request to be broadcast to other TLBs. */
482 if (likely(!split_tlb)) {
483 while (start < end) {
484 purge_tlb_start(flags);
485 mtsp(sid, 1);
486 pdtlb(start);
487 purge_tlb_end(flags);
488 start += PAGE_SIZE;
489 }
490 return 0;
491 }
492
493 /* split TLB case */
494 while (start < end) { 482 while (start < end) {
495 purge_tlb_start(flags); 483 purge_tlb_start(flags);
496 mtsp(sid, 1); 484 mtsp(sid, 1);
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 7c85a91b4710..d3e2633cd688 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -38,6 +38,7 @@
38#include <asm/ldcw.h> 38#include <asm/ldcw.h>
39#include <asm/traps.h> 39#include <asm/traps.h>
40#include <asm/thread_info.h> 40#include <asm/thread_info.h>
41#include <asm/alternative.h>
41 42
42#include <linux/linkage.h> 43#include <linux/linkage.h>
43 44
@@ -464,7 +465,7 @@
464 /* Acquire pa_tlb_lock lock and check page is present. */ 465 /* Acquire pa_tlb_lock lock and check page is present. */
465 .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault 466 .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault
466#ifdef CONFIG_SMP 467#ifdef CONFIG_SMP
467 cmpib,COND(=),n 0,\spc,2f 46898: cmpib,COND(=),n 0,\spc,2f
468 load_pa_tlb_lock \tmp 469 load_pa_tlb_lock \tmp
4691: LDCW 0(\tmp),\tmp1 4701: LDCW 0(\tmp),\tmp1
470 cmpib,COND(=) 0,\tmp1,1b 471 cmpib,COND(=) 0,\tmp1,1b
@@ -473,6 +474,7 @@
473 bb,<,n \pte,_PAGE_PRESENT_BIT,3f 474 bb,<,n \pte,_PAGE_PRESENT_BIT,3f
474 b \fault 475 b \fault
475 stw,ma \spc,0(\tmp) 476 stw,ma \spc,0(\tmp)
47799: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
476#endif 478#endif
4772: LDREG 0(\ptp),\pte 4792: LDREG 0(\ptp),\pte
478 bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault 480 bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
@@ -482,15 +484,17 @@
482 /* Release pa_tlb_lock lock without reloading lock address. */ 484 /* Release pa_tlb_lock lock without reloading lock address. */
483 .macro tlb_unlock0 spc,tmp 485 .macro tlb_unlock0 spc,tmp
484#ifdef CONFIG_SMP 486#ifdef CONFIG_SMP
485 or,COND(=) %r0,\spc,%r0 48798: or,COND(=) %r0,\spc,%r0
486 stw,ma \spc,0(\tmp) 488 stw,ma \spc,0(\tmp)
48999: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
487#endif 490#endif
488 .endm 491 .endm
489 492
490 /* Release pa_tlb_lock lock. */ 493 /* Release pa_tlb_lock lock. */
491 .macro tlb_unlock1 spc,tmp 494 .macro tlb_unlock1 spc,tmp
492#ifdef CONFIG_SMP 495#ifdef CONFIG_SMP
493 load_pa_tlb_lock \tmp 49698: load_pa_tlb_lock \tmp
49799: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
494 tlb_unlock0 \spc,\tmp 498 tlb_unlock0 \spc,\tmp
495#endif 499#endif
496 .endm 500 .endm
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index f33bf2d306d6..b41c0136a05f 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -37,6 +37,7 @@
37#include <asm/pgtable.h> 37#include <asm/pgtable.h>
38#include <asm/cache.h> 38#include <asm/cache.h>
39#include <asm/ldcw.h> 39#include <asm/ldcw.h>
40#include <asm/alternative.h>
40#include <linux/linkage.h> 41#include <linux/linkage.h>
41#include <linux/init.h> 42#include <linux/init.h>
42 43
@@ -190,7 +191,7 @@ ENDPROC_CFI(flush_tlb_all_local)
190 .import cache_info,data 191 .import cache_info,data
191 192
192ENTRY_CFI(flush_instruction_cache_local) 193ENTRY_CFI(flush_instruction_cache_local)
193 load32 cache_info, %r1 19488: load32 cache_info, %r1
194 195
195 /* Flush Instruction Cache */ 196 /* Flush Instruction Cache */
196 197
@@ -243,6 +244,7 @@ fioneloop2:
243fisync: 244fisync:
244 sync 245 sync
245 mtsm %r22 /* restore I-bit */ 246 mtsm %r22 /* restore I-bit */
24789: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
246 bv %r0(%r2) 248 bv %r0(%r2)
247 nop 249 nop
248ENDPROC_CFI(flush_instruction_cache_local) 250ENDPROC_CFI(flush_instruction_cache_local)
@@ -250,7 +252,7 @@ ENDPROC_CFI(flush_instruction_cache_local)
250 252
251 .import cache_info, data 253 .import cache_info, data
252ENTRY_CFI(flush_data_cache_local) 254ENTRY_CFI(flush_data_cache_local)
253 load32 cache_info, %r1 25588: load32 cache_info, %r1
254 256
255 /* Flush Data Cache */ 257 /* Flush Data Cache */
256 258
@@ -304,6 +306,7 @@ fdsync:
304 syncdma 306 syncdma
305 sync 307 sync
306 mtsm %r22 /* restore I-bit */ 308 mtsm %r22 /* restore I-bit */
30989: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
307 bv %r0(%r2) 310 bv %r0(%r2)
308 nop 311 nop
309ENDPROC_CFI(flush_data_cache_local) 312ENDPROC_CFI(flush_data_cache_local)
@@ -312,6 +315,7 @@ ENDPROC_CFI(flush_data_cache_local)
312 315
313 .macro tlb_lock la,flags,tmp 316 .macro tlb_lock la,flags,tmp
314#ifdef CONFIG_SMP 317#ifdef CONFIG_SMP
31898:
315#if __PA_LDCW_ALIGNMENT > 4 319#if __PA_LDCW_ALIGNMENT > 4
316 load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la 320 load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la
317 depi 0,31,__PA_LDCW_ALIGN_ORDER, \la 321 depi 0,31,__PA_LDCW_ALIGN_ORDER, \la
@@ -326,15 +330,17 @@ ENDPROC_CFI(flush_data_cache_local)
326 nop 330 nop
327 b,n 2b 331 b,n 2b
3283: 3323:
33399: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
329#endif 334#endif
330 .endm 335 .endm
331 336
332 .macro tlb_unlock la,flags,tmp 337 .macro tlb_unlock la,flags,tmp
333#ifdef CONFIG_SMP 338#ifdef CONFIG_SMP
334 ldi 1,\tmp 33998: ldi 1,\tmp
335 sync 340 sync
336 stw \tmp,0(\la) 341 stw \tmp,0(\la)
337 mtsm \flags 342 mtsm \flags
34399: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
338#endif 344#endif
339 .endm 345 .endm
340 346
@@ -596,9 +602,11 @@ ENTRY_CFI(copy_user_page_asm)
596 pdtlb,l %r0(%r29) 602 pdtlb,l %r0(%r29)
597#else 603#else
598 tlb_lock %r20,%r21,%r22 604 tlb_lock %r20,%r21,%r22
599 pdtlb %r0(%r28) 6050: pdtlb %r0(%r28)
600 pdtlb %r0(%r29) 6061: pdtlb %r0(%r29)
601 tlb_unlock %r20,%r21,%r22 607 tlb_unlock %r20,%r21,%r22
608 ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
609 ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB)
602#endif 610#endif
603 611
604#ifdef CONFIG_64BIT 612#ifdef CONFIG_64BIT
@@ -736,8 +744,9 @@ ENTRY_CFI(clear_user_page_asm)
736 pdtlb,l %r0(%r28) 744 pdtlb,l %r0(%r28)
737#else 745#else
738 tlb_lock %r20,%r21,%r22 746 tlb_lock %r20,%r21,%r22
739 pdtlb %r0(%r28) 7470: pdtlb %r0(%r28)
740 tlb_unlock %r20,%r21,%r22 748 tlb_unlock %r20,%r21,%r22
749 ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
741#endif 750#endif
742 751
743#ifdef CONFIG_64BIT 752#ifdef CONFIG_64BIT
@@ -813,11 +822,12 @@ ENTRY_CFI(flush_dcache_page_asm)
813 pdtlb,l %r0(%r28) 822 pdtlb,l %r0(%r28)
814#else 823#else
815 tlb_lock %r20,%r21,%r22 824 tlb_lock %r20,%r21,%r22
816 pdtlb %r0(%r28) 8250: pdtlb %r0(%r28)
817 tlb_unlock %r20,%r21,%r22 826 tlb_unlock %r20,%r21,%r22
827 ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
818#endif 828#endif
819 829
820 ldil L%dcache_stride, %r1 83088: ldil L%dcache_stride, %r1
821 ldw R%dcache_stride(%r1), r31 831 ldw R%dcache_stride(%r1), r31
822 832
823#ifdef CONFIG_64BIT 833#ifdef CONFIG_64BIT
@@ -847,6 +857,7 @@ ENTRY_CFI(flush_dcache_page_asm)
847 cmpb,COND(<<) %r28, %r25,1b 857 cmpb,COND(<<) %r28, %r25,1b
848 fdc,m r31(%r28) 858 fdc,m r31(%r28)
849 859
86089: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
850 sync 861 sync
851 bv %r0(%r2) 862 bv %r0(%r2)
852 nop 863 nop
@@ -874,15 +885,19 @@ ENTRY_CFI(flush_icache_page_asm)
874 885
875#ifdef CONFIG_PA20 886#ifdef CONFIG_PA20
876 pdtlb,l %r0(%r28) 887 pdtlb,l %r0(%r28)
877 pitlb,l %r0(%sr4,%r28) 8881: pitlb,l %r0(%sr4,%r28)
889 ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
878#else 890#else
879 tlb_lock %r20,%r21,%r22 891 tlb_lock %r20,%r21,%r22
880 pdtlb %r0(%r28) 8920: pdtlb %r0(%r28)
881 pitlb %r0(%sr4,%r28) 8931: pitlb %r0(%sr4,%r28)
882 tlb_unlock %r20,%r21,%r22 894 tlb_unlock %r20,%r21,%r22
895 ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
896 ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB)
897 ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
883#endif 898#endif
884 899
885 ldil L%icache_stride, %r1 90088: ldil L%icache_stride, %r1
886 ldw R%icache_stride(%r1), %r31 901 ldw R%icache_stride(%r1), %r31
887 902
888#ifdef CONFIG_64BIT 903#ifdef CONFIG_64BIT
@@ -914,13 +929,14 @@ ENTRY_CFI(flush_icache_page_asm)
914 cmpb,COND(<<) %r28, %r25,1b 929 cmpb,COND(<<) %r28, %r25,1b
915 fic,m %r31(%sr4,%r28) 930 fic,m %r31(%sr4,%r28)
916 931
93289: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
917 sync 933 sync
918 bv %r0(%r2) 934 bv %r0(%r2)
919 nop 935 nop
920ENDPROC_CFI(flush_icache_page_asm) 936ENDPROC_CFI(flush_icache_page_asm)
921 937
922ENTRY_CFI(flush_kernel_dcache_page_asm) 938ENTRY_CFI(flush_kernel_dcache_page_asm)
923 ldil L%dcache_stride, %r1 93988: ldil L%dcache_stride, %r1
924 ldw R%dcache_stride(%r1), %r23 940 ldw R%dcache_stride(%r1), %r23
925 941
926#ifdef CONFIG_64BIT 942#ifdef CONFIG_64BIT
@@ -950,13 +966,14 @@ ENTRY_CFI(flush_kernel_dcache_page_asm)
950 cmpb,COND(<<) %r26, %r25,1b 966 cmpb,COND(<<) %r26, %r25,1b
951 fdc,m %r23(%r26) 967 fdc,m %r23(%r26)
952 968
96989: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
953 sync 970 sync
954 bv %r0(%r2) 971 bv %r0(%r2)
955 nop 972 nop
956ENDPROC_CFI(flush_kernel_dcache_page_asm) 973ENDPROC_CFI(flush_kernel_dcache_page_asm)
957 974
958ENTRY_CFI(purge_kernel_dcache_page_asm) 975ENTRY_CFI(purge_kernel_dcache_page_asm)
959 ldil L%dcache_stride, %r1 97688: ldil L%dcache_stride, %r1
960 ldw R%dcache_stride(%r1), %r23 977 ldw R%dcache_stride(%r1), %r23
961 978
962#ifdef CONFIG_64BIT 979#ifdef CONFIG_64BIT
@@ -985,13 +1002,14 @@ ENTRY_CFI(purge_kernel_dcache_page_asm)
985 cmpb,COND(<<) %r26, %r25, 1b 1002 cmpb,COND(<<) %r26, %r25, 1b
986 pdc,m %r23(%r26) 1003 pdc,m %r23(%r26)
987 1004
100589: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
988 sync 1006 sync
989 bv %r0(%r2) 1007 bv %r0(%r2)
990 nop 1008 nop
991ENDPROC_CFI(purge_kernel_dcache_page_asm) 1009ENDPROC_CFI(purge_kernel_dcache_page_asm)
992 1010
993ENTRY_CFI(flush_user_dcache_range_asm) 1011ENTRY_CFI(flush_user_dcache_range_asm)
994 ldil L%dcache_stride, %r1 101288: ldil L%dcache_stride, %r1
995 ldw R%dcache_stride(%r1), %r23 1013 ldw R%dcache_stride(%r1), %r23
996 ldo -1(%r23), %r21 1014 ldo -1(%r23), %r21
997 ANDCM %r26, %r21, %r26 1015 ANDCM %r26, %r21, %r26
@@ -999,13 +1017,14 @@ ENTRY_CFI(flush_user_dcache_range_asm)
9991: cmpb,COND(<<),n %r26, %r25, 1b 10171: cmpb,COND(<<),n %r26, %r25, 1b
1000 fdc,m %r23(%sr3, %r26) 1018 fdc,m %r23(%sr3, %r26)
1001 1019
102089: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
1002 sync 1021 sync
1003 bv %r0(%r2) 1022 bv %r0(%r2)
1004 nop 1023 nop
1005ENDPROC_CFI(flush_user_dcache_range_asm) 1024ENDPROC_CFI(flush_user_dcache_range_asm)
1006 1025
1007ENTRY_CFI(flush_kernel_dcache_range_asm) 1026ENTRY_CFI(flush_kernel_dcache_range_asm)
1008 ldil L%dcache_stride, %r1 102788: ldil L%dcache_stride, %r1
1009 ldw R%dcache_stride(%r1), %r23 1028 ldw R%dcache_stride(%r1), %r23
1010 ldo -1(%r23), %r21 1029 ldo -1(%r23), %r21
1011 ANDCM %r26, %r21, %r26 1030 ANDCM %r26, %r21, %r26
@@ -1014,13 +1033,14 @@ ENTRY_CFI(flush_kernel_dcache_range_asm)
1014 fdc,m %r23(%r26) 1033 fdc,m %r23(%r26)
1015 1034
1016 sync 1035 sync
103689: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
1017 syncdma 1037 syncdma
1018 bv %r0(%r2) 1038 bv %r0(%r2)
1019 nop 1039 nop
1020ENDPROC_CFI(flush_kernel_dcache_range_asm) 1040ENDPROC_CFI(flush_kernel_dcache_range_asm)
1021 1041
1022ENTRY_CFI(purge_kernel_dcache_range_asm) 1042ENTRY_CFI(purge_kernel_dcache_range_asm)
1023 ldil L%dcache_stride, %r1 104388: ldil L%dcache_stride, %r1
1024 ldw R%dcache_stride(%r1), %r23 1044 ldw R%dcache_stride(%r1), %r23
1025 ldo -1(%r23), %r21 1045 ldo -1(%r23), %r21
1026 ANDCM %r26, %r21, %r26 1046 ANDCM %r26, %r21, %r26
@@ -1029,13 +1049,14 @@ ENTRY_CFI(purge_kernel_dcache_range_asm)
1029 pdc,m %r23(%r26) 1049 pdc,m %r23(%r26)
1030 1050
1031 sync 1051 sync
105289: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
1032 syncdma 1053 syncdma
1033 bv %r0(%r2) 1054 bv %r0(%r2)
1034 nop 1055 nop
1035ENDPROC_CFI(purge_kernel_dcache_range_asm) 1056ENDPROC_CFI(purge_kernel_dcache_range_asm)
1036 1057
1037ENTRY_CFI(flush_user_icache_range_asm) 1058ENTRY_CFI(flush_user_icache_range_asm)
1038 ldil L%icache_stride, %r1 105988: ldil L%icache_stride, %r1
1039 ldw R%icache_stride(%r1), %r23 1060 ldw R%icache_stride(%r1), %r23
1040 ldo -1(%r23), %r21 1061 ldo -1(%r23), %r21
1041 ANDCM %r26, %r21, %r26 1062 ANDCM %r26, %r21, %r26
@@ -1043,13 +1064,14 @@ ENTRY_CFI(flush_user_icache_range_asm)
10431: cmpb,COND(<<),n %r26, %r25,1b 10641: cmpb,COND(<<),n %r26, %r25,1b
1044 fic,m %r23(%sr3, %r26) 1065 fic,m %r23(%sr3, %r26)
1045 1066
106789: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
1046 sync 1068 sync
1047 bv %r0(%r2) 1069 bv %r0(%r2)
1048 nop 1070 nop
1049ENDPROC_CFI(flush_user_icache_range_asm) 1071ENDPROC_CFI(flush_user_icache_range_asm)
1050 1072
1051ENTRY_CFI(flush_kernel_icache_page) 1073ENTRY_CFI(flush_kernel_icache_page)
1052 ldil L%icache_stride, %r1 107488: ldil L%icache_stride, %r1
1053 ldw R%icache_stride(%r1), %r23 1075 ldw R%icache_stride(%r1), %r23
1054 1076
1055#ifdef CONFIG_64BIT 1077#ifdef CONFIG_64BIT
@@ -1079,13 +1101,14 @@ ENTRY_CFI(flush_kernel_icache_page)
1079 cmpb,COND(<<) %r26, %r25, 1b 1101 cmpb,COND(<<) %r26, %r25, 1b
1080 fic,m %r23(%sr4, %r26) 1102 fic,m %r23(%sr4, %r26)
1081 1103
110489: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
1082 sync 1105 sync
1083 bv %r0(%r2) 1106 bv %r0(%r2)
1084 nop 1107 nop
1085ENDPROC_CFI(flush_kernel_icache_page) 1108ENDPROC_CFI(flush_kernel_icache_page)
1086 1109
1087ENTRY_CFI(flush_kernel_icache_range_asm) 1110ENTRY_CFI(flush_kernel_icache_range_asm)
1088 ldil L%icache_stride, %r1 111188: ldil L%icache_stride, %r1
1089 ldw R%icache_stride(%r1), %r23 1112 ldw R%icache_stride(%r1), %r23
1090 ldo -1(%r23), %r21 1113 ldo -1(%r23), %r21
1091 ANDCM %r26, %r21, %r26 1114 ANDCM %r26, %r21, %r26
@@ -1093,6 +1116,7 @@ ENTRY_CFI(flush_kernel_icache_range_asm)
10931: cmpb,COND(<<),n %r26, %r25, 1b 11161: cmpb,COND(<<),n %r26, %r25, 1b
1094 fic,m %r23(%sr4, %r26) 1117 fic,m %r23(%sr4, %r26)
1095 1118
111989: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
1096 sync 1120 sync
1097 bv %r0(%r2) 1121 bv %r0(%r2)
1098 nop 1122 nop
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 4e87c35c22b7..db6e7957f9a3 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -305,6 +305,86 @@ static int __init parisc_init_resources(void)
305 return 0; 305 return 0;
306} 306}
307 307
308static int no_alternatives __initdata;
309static int __init setup_no_alternatives(char *str)
310{
311 no_alternatives = 1;
312 return 1;
313}
314__setup("no-alternatives", setup_no_alternatives);
315
316static void __init apply_alternatives_all(void)
317{
318 struct alt_instr *entry;
319 int index = 0, applied = 0;
320
321
322 pr_info("alternatives: %spatching kernel code\n",
323 no_alternatives ? "NOT " : "");
324 if (no_alternatives)
325 return;
326
327 set_kernel_text_rw(1);
328
329 for (entry = (struct alt_instr *) &__alt_instructions;
330 entry < (struct alt_instr *) &__alt_instructions_end;
331 entry++, index++) {
332
333 u32 *from, len, cond, replacement;
334
335 from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
336 len = entry->len;
337 cond = entry->cond;
338 replacement = entry->replacement;
339
340 WARN_ON(!cond);
341 pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
342 index, cond, len, from, replacement);
343
344 if ((cond & ALT_COND_NO_SMP) && (num_online_cpus() != 1))
345 continue;
346 if ((cond & ALT_COND_NO_DCACHE) && (cache_info.dc_size != 0))
347 continue;
348 if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
349 continue;
350
351 /*
352 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
353 * set (bit #61, big endian), we have to flush and sync every
354 * time IO-PDIR is changed in Ike/Astro.
355 */
356 if ((cond & ALT_COND_NO_IOC_FDC) &&
357 (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC))
358 continue;
359
360 /* Want to replace pdtlb by a pdtlb,l instruction? */
361 if (replacement == INSN_PxTLB) {
362 replacement = *from;
363 if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
364 replacement |= (1 << 10); /* set el bit */
365 }
366
367 /*
368 * Replace instruction with NOPs?
369 * For long distance insert a branch instruction instead.
370 */
371 if (replacement == INSN_NOP && len > 1)
372 replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
373
374 pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
375 index, cond, len, from, replacement);
376
377 /* Replace instruction */
378 *from = replacement;
379 applied++;
380 }
381
382 pr_info("alternatives: applied %d out of %d patches\n", applied, index);
383
384 set_kernel_text_rw(0);
385}
386
387
308extern void gsc_init(void); 388extern void gsc_init(void);
309extern void processor_init(void); 389extern void processor_init(void);
310extern void ccio_init(void); 390extern void ccio_init(void);
@@ -346,6 +426,7 @@ static int __init parisc_init(void)
346 boot_cpu_data.cpu_hz / 1000000, 426 boot_cpu_data.cpu_hz / 1000000,
347 boot_cpu_data.cpu_hz % 1000000 ); 427 boot_cpu_data.cpu_hz % 1000000 );
348 428
429 apply_alternatives_all();
349 parisc_setup_cache_timing(); 430 parisc_setup_cache_timing();
350 431
351 /* These are in a non-obvious order, will fix when we have an iotree */ 432 /* These are in a non-obvious order, will fix when we have an iotree */
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 342073f44d3f..848c1934680b 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -65,7 +65,6 @@
65#define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ 65#define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */
66#define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ 66#define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */
67#define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ 67#define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
68#define INSN_NOP 0x08000240 /* nop */
69/* For debugging */ 68/* For debugging */
70#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ 69#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
71 70
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index da2e31190efa..c3b1b9c24ede 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -61,6 +61,12 @@ SECTIONS
61 EXIT_DATA 61 EXIT_DATA
62 } 62 }
63 PERCPU_SECTION(8) 63 PERCPU_SECTION(8)
64 . = ALIGN(4);
65 .altinstructions : {
66 __alt_instructions = .;
67 *(.altinstructions)
68 __alt_instructions_end = .;
69 }
64 . = ALIGN(HUGEPAGE_SIZE); 70 . = ALIGN(HUGEPAGE_SIZE);
65 __init_end = .; 71 __init_end = .;
66 /* freed after init ends here */ 72 /* freed after init ends here */
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index aae9b0d71c1e..e7e626bcd0be 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -511,6 +511,21 @@ static void __init map_pages(unsigned long start_vaddr,
511 } 511 }
512} 512}
513 513
514void __init set_kernel_text_rw(int enable_read_write)
515{
516 unsigned long start = (unsigned long)_stext;
517 unsigned long end = (unsigned long)_etext;
518
519 map_pages(start, __pa(start), end-start,
520 PAGE_KERNEL_RWX, enable_read_write ? 1:0);
521
522 /* force the kernel to see the new TLB entries */
523 __flush_tlb_range(0, start, end);
524
525 /* dump old cached instructions */
526 flush_icache_range(start, end);
527}
528
514void __ref free_initmem(void) 529void __ref free_initmem(void)
515{ 530{
516 unsigned long init_begin = (unsigned long)__init_begin; 531 unsigned long init_begin = (unsigned long)__init_begin;
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 614823617b8b..701a7d6a74d5 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -609,14 +609,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
609 ** PCX-T'? Don't know. (eg C110 or similar K-class) 609 ** PCX-T'? Don't know. (eg C110 or similar K-class)
610 ** 610 **
611 ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". 611 ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit".
612 ** Hopefully we can patch (NOP) these out at boot time somehow.
613 ** 612 **
614 ** "Since PCX-U employs an offset hash that is incompatible with 613 ** "Since PCX-U employs an offset hash that is incompatible with
615 ** the real mode coherence index generation of U2, the PDIR entry 614 ** the real mode coherence index generation of U2, the PDIR entry
616 ** must be flushed to memory to retain coherence." 615 ** must be flushed to memory to retain coherence."
617 */ 616 */
618 asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); 617 asm_io_fdc(pdir_ptr);
619 asm volatile("sync"); 618 asm_io_sync();
620} 619}
621 620
622/** 621/**
@@ -682,17 +681,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
682 ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) 681 ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
683 ** PCX-U/U+ do. (eg C200/C240) 682 ** PCX-U/U+ do. (eg C200/C240)
684 ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". 683 ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
685 **
686 ** Hopefully someone figures out how to patch (NOP) the
687 ** FDC/SYNC out at boot time.
688 */ 684 */
689 asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); 685 asm_io_fdc(pdir_ptr);
690 686
691 iovp += IOVP_SIZE; 687 iovp += IOVP_SIZE;
692 byte_cnt -= IOVP_SIZE; 688 byte_cnt -= IOVP_SIZE;
693 } 689 }
694 690
695 asm volatile("sync"); 691 asm_io_sync();
696 ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); 692 ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
697} 693}
698 694
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 11de0eccf968..c1e599a429af 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -587,8 +587,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
587 * (bit #61, big endian), we have to flush and sync every time 587 * (bit #61, big endian), we have to flush and sync every time
588 * IO-PDIR is changed in Ike/Astro. 588 * IO-PDIR is changed in Ike/Astro.
589 */ 589 */
590 if (ioc_needs_fdc) 590 asm_io_fdc(pdir_ptr);
591 asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
592} 591}
593 592
594 593
@@ -641,8 +640,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
641 do { 640 do {
642 /* clear I/O Pdir entry "valid" bit first */ 641 /* clear I/O Pdir entry "valid" bit first */
643 ((u8 *) pdir_ptr)[7] = 0; 642 ((u8 *) pdir_ptr)[7] = 0;
643 asm_io_fdc(pdir_ptr);
644 if (ioc_needs_fdc) { 644 if (ioc_needs_fdc) {
645 asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
646#if 0 645#if 0
647 entries_per_cacheline = L1_CACHE_SHIFT - 3; 646 entries_per_cacheline = L1_CACHE_SHIFT - 3;
648#endif 647#endif
@@ -661,8 +660,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
661 ** could dump core on HPMC. 660 ** could dump core on HPMC.
662 */ 661 */
663 ((u8 *) pdir_ptr)[7] = 0; 662 ((u8 *) pdir_ptr)[7] = 0;
664 if (ioc_needs_fdc) 663 asm_io_fdc(pdir_ptr);
665 asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
666 664
667 WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); 665 WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM);
668} 666}
@@ -773,8 +771,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
773 } 771 }
774 772
775 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ 773 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */
776 if (ioc_needs_fdc) 774 asm_io_sync();
777 asm volatile("sync" : : );
778 775
779#ifdef ASSERT_PDIR_SANITY 776#ifdef ASSERT_PDIR_SANITY
780 sba_check_pdir(ioc,"Check after sba_map_single()"); 777 sba_check_pdir(ioc,"Check after sba_map_single()");
@@ -858,8 +855,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
858 sba_free_range(ioc, iova, size); 855 sba_free_range(ioc, iova, size);
859 856
860 /* If fdc's were issued, force fdc's to be visible now */ 857 /* If fdc's were issued, force fdc's to be visible now */
861 if (ioc_needs_fdc) 858 asm_io_sync();
862 asm volatile("sync" : : );
863 859
864 READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ 860 READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
865#endif /* DELAYED_RESOURCE_CNT == 0 */ 861#endif /* DELAYED_RESOURCE_CNT == 0 */
@@ -1008,8 +1004,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
1008 filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); 1004 filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
1009 1005
1010 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ 1006 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */
1011 if (ioc_needs_fdc) 1007 asm_io_sync();
1012 asm volatile("sync" : : );
1013 1008
1014#ifdef ASSERT_PDIR_SANITY 1009#ifdef ASSERT_PDIR_SANITY
1015 if (sba_check_pdir(ioc,"Check after sba_map_sg()")) 1010 if (sba_check_pdir(ioc,"Check after sba_map_sg()"))