Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

parisc: Add alternative coding infrastructure

This patch adds the necessary code to patch a running kernel at runtime
to improve performance.

The current implementation offers a few optimizations variants:

- When running a SMP kernel on a single UP processor, unwanted assembler
statements like locking functions are overwritten with NOPs. When
multiple instructions shall be skipped, one branch instruction is used
instead of multiple nop instructions.

- In the UP case, some pdtlb and pitlb instructions are patched to
become pdtlb,l and pitlb,l which only flushes the CPU-local tlb
entries instead of broadcasting the flush to other CPUs in the system
and thus may improve performance.

- fic and fdc instructions are skipped if no I- or D-caches are
installed. This should speed up qemu emulation and cacheless systems.

- If no cache coherence is needed for IO operations, the relevant fdc
and sync instructions in the sba and ccio drivers are replaced by
nops.

- On systems which share I- and D-TLBs and thus don't have a seperate
instruction TLB, the pitlb instruction is replaced by a nop.

Live-patching is done early in the boot process, just after having run
the system inventory. No drivers are running and thus no external
interrupts should arrive. So the hope is that no TLB exceptions will
occur during the patching. If this turns out to be wrong we will
probably need to do the patching in real-mode.

Signed-off-by: Helge Deller <deller@gmx.de>

+233 -62
+47
arch/parisc/include/asm/alternative.h
··· 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 + 21 + struct 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 + 28 + void 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 */
+19 -3
arch/parisc/include/asm/cache.h
··· 6 6 #ifndef __ARCH_PARISC_CACHE_H 7 7 #define __ARCH_PARISC_CACHE_H 8 8 9 + #include <asm/alternative.h> 9 10 10 11 /* 11 12 * PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors ··· 42 41 extern struct pdc_cache_info cache_info; 43 42 void parisc_setup_cache_timing(void); 44 43 45 - #define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr)); 46 - #define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr)); 47 - #define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr)); 44 + #define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" \ 45 + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ 46 + : : "r" (addr)) 47 + #define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" \ 48 + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ 49 + ALTERNATIVE(ALT_COND_NO_SPLIT_TLB, INSN_NOP) \ 50 + : : "r" (addr)) 51 + #define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" \ 52 + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ 53 + : : "r" (addr)) 54 + 55 + #define asm_io_fdc(addr) asm volatile("fdc %%r0(%0)" \ 56 + ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \ 57 + ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) \ 58 + : : "r" (addr)) 59 + #define asm_io_sync() asm volatile("sync" \ 60 + ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \ 61 + ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) :: ) 48 62 49 63 #endif /* ! __ASSEMBLY__ */ 50 64
+1 -2
arch/parisc/include/asm/pgtable.h
··· 43 43 { 44 44 mtsp(mm->context, 1); 45 45 pdtlb(addr); 46 - if (unlikely(split_tlb)) 47 - pitlb(addr); 46 + pitlb(addr); 48 47 } 49 48 50 49 /* Certain architectures need to do special things when PTEs
+2
arch/parisc/include/asm/sections.h
··· 5 5 /* nothing to see, move along */ 6 6 #include <asm-generic/sections.h> 7 7 8 + extern char __alt_instructions[], __alt_instructions_end[]; 9 + 8 10 #ifdef CONFIG_64BIT 9 11 10 12 #define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
+1 -2
arch/parisc/include/asm/tlbflush.h
··· 85 85 purge_tlb_start(flags); 86 86 mtsp(sid, 1); 87 87 pdtlb(addr); 88 - if (unlikely(split_tlb)) 89 - pitlb(addr); 88 + pitlb(addr); 90 89 purge_tlb_end(flags); 91 90 } 92 91 #endif
-12
arch/parisc/kernel/cache.c
··· 479 479 /* Purge TLB entries for small ranges using the pdtlb and 480 480 pitlb instructions. These instructions execute locally 481 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 482 while (start < end) { 495 483 purge_tlb_start(flags); 496 484 mtsp(sid, 1);
+7 -3
arch/parisc/kernel/entry.S
··· 38 38 #include <asm/ldcw.h> 39 39 #include <asm/traps.h> 40 40 #include <asm/thread_info.h> 41 + #include <asm/alternative.h> 41 42 42 43 #include <linux/linkage.h> 43 44 ··· 465 464 /* Acquire pa_tlb_lock lock and check page is present. */ 466 465 .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault 467 466 #ifdef CONFIG_SMP 468 - cmpib,COND(=),n 0,\spc,2f 467 + 98: cmpib,COND(=),n 0,\spc,2f 469 468 load_pa_tlb_lock \tmp 470 469 1: LDCW 0(\tmp),\tmp1 471 470 cmpib,COND(=) 0,\tmp1,1b ··· 474 473 bb,<,n \pte,_PAGE_PRESENT_BIT,3f 475 474 b \fault 476 475 stw,ma \spc,0(\tmp) 476 + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) 477 477 #endif 478 478 2: LDREG 0(\ptp),\pte 479 479 bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault ··· 484 482 /* Release pa_tlb_lock lock without reloading lock address. */ 485 483 .macro tlb_unlock0 spc,tmp 486 484 #ifdef CONFIG_SMP 487 - or,COND(=) %r0,\spc,%r0 485 + 98: or,COND(=) %r0,\spc,%r0 488 486 stw,ma \spc,0(\tmp) 487 + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) 489 488 #endif 490 489 .endm 491 490 492 491 /* Release pa_tlb_lock lock. */ 493 492 .macro tlb_unlock1 spc,tmp 494 493 #ifdef CONFIG_SMP 495 - load_pa_tlb_lock \tmp 494 + 98: load_pa_tlb_lock \tmp 495 + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) 496 496 tlb_unlock0 \spc,\tmp 497 497 #endif 498 498 .endm
+44 -20
arch/parisc/kernel/pacache.S
··· 37 37 #include <asm/pgtable.h> 38 38 #include <asm/cache.h> 39 39 #include <asm/ldcw.h> 40 + #include <asm/alternative.h> 40 41 #include <linux/linkage.h> 41 42 #include <linux/init.h> 42 43 ··· 191 190 .import cache_info,data 192 191 193 192 ENTRY_CFI(flush_instruction_cache_local) 194 - load32 cache_info, %r1 193 + 88: load32 cache_info, %r1 195 194 196 195 /* Flush Instruction Cache */ 197 196 ··· 244 243 fisync: 245 244 sync 246 245 mtsm %r22 /* restore I-bit */ 246 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) 247 247 bv %r0(%r2) 248 248 nop 249 249 ENDPROC_CFI(flush_instruction_cache_local) ··· 252 250 253 251 .import cache_info, data 254 252 ENTRY_CFI(flush_data_cache_local) 255 - load32 cache_info, %r1 253 + 88: load32 cache_info, %r1 256 254 257 255 /* Flush Data Cache */ 258 256 ··· 306 304 syncdma 307 305 sync 308 306 mtsm %r22 /* restore I-bit */ 307 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 309 308 bv %r0(%r2) 310 309 nop 311 310 ENDPROC_CFI(flush_data_cache_local) ··· 315 312 316 313 .macro tlb_lock la,flags,tmp 317 314 #ifdef CONFIG_SMP 315 + 98: 318 316 #if __PA_LDCW_ALIGNMENT > 4 319 317 load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la 320 318 depi 0,31,__PA_LDCW_ALIGN_ORDER, \la ··· 330 326 nop 331 327 b,n 2b 332 328 3: 329 + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) 333 330 #endif 334 331 .endm 335 332 336 333 .macro tlb_unlock la,flags,tmp 337 334 #ifdef CONFIG_SMP 338 - ldi 1,\tmp 335 + 98: ldi 1,\tmp 339 336 sync 340 337 stw \tmp,0(\la) 341 338 mtsm \flags 339 + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) 342 340 #endif 343 341 .endm 344 342 ··· 602 596 pdtlb,l %r0(%r29) 603 597 #else 604 598 tlb_lock %r20,%r21,%r22 605 - pdtlb %r0(%r28) 606 - pdtlb %r0(%r29) 599 + 0: pdtlb %r0(%r28) 600 + 1: pdtlb %r0(%r29) 607 601 tlb_unlock %r20,%r21,%r22 602 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) 603 + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB) 608 604 #endif 609 605 610 606 #ifdef CONFIG_64BIT ··· 744 736 pdtlb,l %r0(%r28) 745 737 #else 746 738 tlb_lock %r20,%r21,%r22 747 - pdtlb %r0(%r28) 739 + 0: pdtlb %r0(%r28) 748 740 tlb_unlock %r20,%r21,%r22 741 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) 749 742 #endif 750 743 751 744 #ifdef CONFIG_64BIT ··· 822 813 pdtlb,l %r0(%r28) 823 814 #else 824 815 tlb_lock %r20,%r21,%r22 825 - pdtlb %r0(%r28) 816 + 0: pdtlb %r0(%r28) 826 817 tlb_unlock %r20,%r21,%r22 818 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) 827 819 #endif 828 820 829 - ldil L%dcache_stride, %r1 821 + 88: ldil L%dcache_stride, %r1 830 822 ldw R%dcache_stride(%r1), r31 831 823 832 824 #ifdef CONFIG_64BIT ··· 857 847 cmpb,COND(<<) %r28, %r25,1b 858 848 fdc,m r31(%r28) 859 849 850 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 860 851 sync 861 852 bv %r0(%r2) 862 853 nop ··· 885 874 886 875 #ifdef CONFIG_PA20 887 876 pdtlb,l %r0(%r28) 888 - pitlb,l %r0(%sr4,%r28) 877 + 1: pitlb,l %r0(%sr4,%r28) 878 + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP) 889 879 #else 890 880 tlb_lock %r20,%r21,%r22 891 - pdtlb %r0(%r28) 892 - pitlb %r0(%sr4,%r28) 881 + 0: pdtlb %r0(%r28) 882 + 1: pitlb %r0(%sr4,%r28) 893 883 tlb_unlock %r20,%r21,%r22 884 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) 885 + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB) 886 + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP) 894 887 #endif 895 888 896 - ldil L%icache_stride, %r1 889 + 88: ldil L%icache_stride, %r1 897 890 ldw R%icache_stride(%r1), %r31 898 891 899 892 #ifdef CONFIG_64BIT ··· 929 914 cmpb,COND(<<) %r28, %r25,1b 930 915 fic,m %r31(%sr4,%r28) 931 916 917 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) 932 918 sync 933 919 bv %r0(%r2) 934 920 nop 935 921 ENDPROC_CFI(flush_icache_page_asm) 936 922 937 923 ENTRY_CFI(flush_kernel_dcache_page_asm) 938 - ldil L%dcache_stride, %r1 924 + 88: ldil L%dcache_stride, %r1 939 925 ldw R%dcache_stride(%r1), %r23 940 926 941 927 #ifdef CONFIG_64BIT ··· 966 950 cmpb,COND(<<) %r26, %r25,1b 967 951 fdc,m %r23(%r26) 968 952 953 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 969 954 sync 970 955 bv %r0(%r2) 971 956 nop 972 957 ENDPROC_CFI(flush_kernel_dcache_page_asm) 973 958 974 959 ENTRY_CFI(purge_kernel_dcache_page_asm) 975 - ldil L%dcache_stride, %r1 960 + 88: ldil L%dcache_stride, %r1 976 961 ldw R%dcache_stride(%r1), %r23 977 962 978 963 #ifdef CONFIG_64BIT ··· 1002 985 cmpb,COND(<<) %r26, %r25, 1b 1003 986 pdc,m %r23(%r26) 1004 987 988 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 1005 989 sync 1006 990 bv %r0(%r2) 1007 991 nop 1008 992 ENDPROC_CFI(purge_kernel_dcache_page_asm) 1009 993 1010 994 ENTRY_CFI(flush_user_dcache_range_asm) 1011 - ldil L%dcache_stride, %r1 995 + 88: ldil L%dcache_stride, %r1 1012 996 ldw R%dcache_stride(%r1), %r23 1013 997 ldo -1(%r23), %r21 1014 998 ANDCM %r26, %r21, %r26 ··· 1017 999 1: cmpb,COND(<<),n %r26, %r25, 1b 1018 1000 fdc,m %r23(%sr3, %r26) 1019 1001 1002 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 1020 1003 sync 1021 1004 bv %r0(%r2) 1022 1005 nop 1023 1006 ENDPROC_CFI(flush_user_dcache_range_asm) 1024 1007 1025 1008 ENTRY_CFI(flush_kernel_dcache_range_asm) 1026 - ldil L%dcache_stride, %r1 1009 + 88: ldil L%dcache_stride, %r1 1027 1010 ldw R%dcache_stride(%r1), %r23 1028 1011 ldo -1(%r23), %r21 1029 1012 ANDCM %r26, %r21, %r26 ··· 1033 1014 fdc,m %r23(%r26) 1034 1015 1035 1016 sync 1017 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 1036 1018 syncdma 1037 1019 bv %r0(%r2) 1038 1020 nop 1039 1021 ENDPROC_CFI(flush_kernel_dcache_range_asm) 1040 1022 1041 1023 ENTRY_CFI(purge_kernel_dcache_range_asm) 1042 - ldil L%dcache_stride, %r1 1024 + 88: ldil L%dcache_stride, %r1 1043 1025 ldw R%dcache_stride(%r1), %r23 1044 1026 ldo -1(%r23), %r21 1045 1027 ANDCM %r26, %r21, %r26 ··· 1049 1029 pdc,m %r23(%r26) 1050 1030 1051 1031 sync 1032 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) 1052 1033 syncdma 1053 1034 bv %r0(%r2) 1054 1035 nop 1055 1036 ENDPROC_CFI(purge_kernel_dcache_range_asm) 1056 1037 1057 1038 ENTRY_CFI(flush_user_icache_range_asm) 1058 - ldil L%icache_stride, %r1 1039 + 88: ldil L%icache_stride, %r1 1059 1040 ldw R%icache_stride(%r1), %r23 1060 1041 ldo -1(%r23), %r21 1061 1042 ANDCM %r26, %r21, %r26 ··· 1064 1043 1: cmpb,COND(<<),n %r26, %r25,1b 1065 1044 fic,m %r23(%sr3, %r26) 1066 1045 1046 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) 1067 1047 sync 1068 1048 bv %r0(%r2) 1069 1049 nop 1070 1050 ENDPROC_CFI(flush_user_icache_range_asm) 1071 1051 1072 1052 ENTRY_CFI(flush_kernel_icache_page) 1073 - ldil L%icache_stride, %r1 1053 + 88: ldil L%icache_stride, %r1 1074 1054 ldw R%icache_stride(%r1), %r23 1075 1055 1076 1056 #ifdef CONFIG_64BIT ··· 1101 1079 cmpb,COND(<<) %r26, %r25, 1b 1102 1080 fic,m %r23(%sr4, %r26) 1103 1081 1082 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) 1104 1083 sync 1105 1084 bv %r0(%r2) 1106 1085 nop 1107 1086 ENDPROC_CFI(flush_kernel_icache_page) 1108 1087 1109 1088 ENTRY_CFI(flush_kernel_icache_range_asm) 1110 - ldil L%icache_stride, %r1 1089 + 88: ldil L%icache_stride, %r1 1111 1090 ldw R%icache_stride(%r1), %r23 1112 1091 ldo -1(%r23), %r21 1113 1092 ANDCM %r26, %r21, %r26 ··· 1116 1093 1: cmpb,COND(<<),n %r26, %r25, 1b 1117 1094 fic,m %r23(%sr4, %r26) 1118 1095 1096 + 89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) 1119 1097 sync 1120 1098 bv %r0(%r2) 1121 1099 nop
+81
arch/parisc/kernel/setup.c
··· 305 305 return 0; 306 306 } 307 307 308 + static int no_alternatives __initdata; 309 + static int __init setup_no_alternatives(char *str) 310 + { 311 + no_alternatives = 1; 312 + return 1; 313 + } 314 + __setup("no-alternatives", setup_no_alternatives); 315 + 316 + static 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 + 308 388 extern void gsc_init(void); 309 389 extern void processor_init(void); 310 390 extern void ccio_init(void); ··· 426 346 boot_cpu_data.cpu_hz / 1000000, 427 347 boot_cpu_data.cpu_hz % 1000000 ); 428 348 349 + apply_alternatives_all(); 429 350 parisc_setup_cache_timing(); 430 351 431 352 /* These are in a non-obvious order, will fix when we have an iotree */
-1
arch/parisc/kernel/signal.c
··· 65 65 #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ 66 66 #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ 67 67 #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ 68 - #define INSN_NOP 0x08000240 /* nop */ 69 68 /* For debugging */ 70 69 #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ 71 70
+6
arch/parisc/kernel/vmlinux.lds.S
··· 61 61 EXIT_DATA 62 62 } 63 63 PERCPU_SECTION(8) 64 + . = ALIGN(4); 65 + .altinstructions : { 66 + __alt_instructions = .; 67 + *(.altinstructions) 68 + __alt_instructions_end = .; 69 + } 64 70 . = ALIGN(HUGEPAGE_SIZE); 65 71 __init_end = .; 66 72 /* freed after init ends here */
+15
arch/parisc/mm/init.c
··· 511 511 } 512 512 } 513 513 514 + void __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 + 514 529 void __ref free_initmem(void) 515 530 { 516 531 unsigned long init_begin = (unsigned long)__init_begin;
+4 -8
drivers/parisc/ccio-dma.c
··· 609 609 ** PCX-T'? Don't know. (eg C110 or similar K-class) 610 610 ** 611 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 613 ** "Since PCX-U employs an offset hash that is incompatible with 615 614 ** the real mode coherence index generation of U2, the PDIR entry 616 615 ** must be flushed to memory to retain coherence." 617 616 */ 618 - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); 619 - asm volatile("sync"); 617 + asm_io_fdc(pdir_ptr); 618 + asm_io_sync(); 620 619 } 621 620 622 621 /** ··· 681 682 ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) 682 683 ** PCX-U/U+ do. (eg C200/C240) 683 684 ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". 684 - ** 685 - ** Hopefully someone figures out how to patch (NOP) the 686 - ** FDC/SYNC out at boot time. 687 685 */ 688 - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); 686 + asm_io_fdc(pdir_ptr); 689 687 690 688 iovp += IOVP_SIZE; 691 689 byte_cnt -= IOVP_SIZE; 692 690 } 693 691 694 - asm volatile("sync"); 692 + asm_io_sync(); 695 693 ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); 696 694 } 697 695
+6 -11
drivers/parisc/sba_iommu.c
··· 587 587 * (bit #61, big endian), we have to flush and sync every time 588 588 * IO-PDIR is changed in Ike/Astro. 589 589 */ 590 - if (ioc_needs_fdc) 591 - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); 590 + asm_io_fdc(pdir_ptr); 592 591 } 593 592 594 593 ··· 640 641 do { 641 642 /* clear I/O Pdir entry "valid" bit first */ 642 643 ((u8 *) pdir_ptr)[7] = 0; 644 + asm_io_fdc(pdir_ptr); 643 645 if (ioc_needs_fdc) { 644 - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); 645 646 #if 0 646 647 entries_per_cacheline = L1_CACHE_SHIFT - 3; 647 648 #endif ··· 660 661 ** could dump core on HPMC. 661 662 */ 662 663 ((u8 *) pdir_ptr)[7] = 0; 663 - if (ioc_needs_fdc) 664 - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); 664 + asm_io_fdc(pdir_ptr); 665 665 666 666 WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); 667 667 } ··· 771 773 } 772 774 773 775 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ 774 - if (ioc_needs_fdc) 775 - asm volatile("sync" : : ); 776 + asm_io_sync(); 776 777 777 778 #ifdef ASSERT_PDIR_SANITY 778 779 sba_check_pdir(ioc,"Check after sba_map_single()"); ··· 855 858 sba_free_range(ioc, iova, size); 856 859 857 860 /* If fdc's were issued, force fdc's to be visible now */ 858 - if (ioc_needs_fdc) 859 - asm volatile("sync" : : ); 861 + asm_io_sync(); 860 862 861 863 READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ 862 864 #endif /* DELAYED_RESOURCE_CNT == 0 */ ··· 1004 1008 filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); 1005 1009 1006 1010 /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ 1007 - if (ioc_needs_fdc) 1008 - asm volatile("sync" : : ); 1011 + asm_io_sync(); 1009 1012 1010 1013 #ifdef ASSERT_PDIR_SANITY 1011 1014 if (sba_check_pdir(ioc,"Check after sba_map_sg()"))