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

microblaze: Add custom break vector handler for mb manager

When the TMR Manager detects a fault Lockstep state it is signaled to the
MicroBlaze processors by asserting a break signal, When Microblaze gets
a break vector from tmr Microblaze it's needed to clear/block the break
bit in the tmr manager before performing recovery.
In order to perform recovery need to perform the following steps.
1) Store all internal MicroBlaze registers in RAM
2) Execute a suspend instruction which asserts the reset signal
3) Restore all registers from RAM and execute an RTBD instruction to
return from the reset handler, to resume execution at the place
where the break occurred.

This API supports getting called from kernel space only.

Signed-off-by: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>
Link: https://lore.kernel.org/r/20220627064024.771037-3-appana.durga.rao@xilinx.com
Signed-off-by: Michal Simek <michal.simek@amd.com>

authored by

Appana Durga Kedareswara rao and committed by
Michal Simek
88707ebe a5e3aaa6

+212 -1
+7
arch/microblaze/kernel/asm-offsets.c
··· 120 120 DEFINE(CC_FSR, offsetof(struct cpu_context, fsr)); 121 121 BLANK(); 122 122 123 + /* struct cpuinfo */ 124 + DEFINE(CI_DCS, offsetof(struct cpuinfo, dcache_size)); 125 + DEFINE(CI_DCL, offsetof(struct cpuinfo, dcache_line_length)); 126 + DEFINE(CI_ICS, offsetof(struct cpuinfo, icache_size)); 127 + DEFINE(CI_ICL, offsetof(struct cpuinfo, icache_line_length)); 128 + BLANK(); 129 + 123 130 return 0; 124 131 }
+205 -1
arch/microblaze/kernel/entry.S
··· 30 30 31 31 #include <linux/errno.h> 32 32 #include <asm/signal.h> 33 + #include <asm/mmu.h> 33 34 34 35 #undef DEBUG 35 36 ··· 287 286 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); 288 287 289 288 .text 289 + 290 + .extern cpuinfo 291 + 292 + C_ENTRY(mb_flush_dcache): 293 + addik r1, r1, -PT_SIZE 294 + SAVE_REGS 295 + 296 + addik r3, r0, cpuinfo 297 + lwi r7, r3, CI_DCS 298 + lwi r8, r3, CI_DCL 299 + sub r9, r7, r8 300 + 1: 301 + wdc.flush r9, r0 302 + bgtid r9, 1b 303 + addk r9, r9, r8 304 + 305 + RESTORE_REGS 306 + addik r1, r1, PT_SIZE 307 + rtsd r15, 8 308 + nop 309 + 310 + C_ENTRY(mb_invalidate_icache): 311 + addik r1, r1, -PT_SIZE 312 + SAVE_REGS 313 + 314 + addik r3, r0, cpuinfo 315 + lwi r7, r3, CI_ICS 316 + lwi r8, r3, CI_ICL 317 + sub r9, r7, r8 318 + 1: 319 + wic r9, r0 320 + bgtid r9, 1b 321 + addk r9, r9, r8 322 + 323 + RESTORE_REGS 324 + addik r1, r1, PT_SIZE 325 + rtsd r15, 8 326 + nop 290 327 291 328 /* 292 329 * User trap. ··· 792 753 rtid r14, 0 793 754 nop 794 755 756 + #ifdef CONFIG_MB_MANAGER 757 + 758 + #define PT_PID PT_SIZE 759 + #define PT_TLBI PT_SIZE + 4 760 + #define PT_ZPR PT_SIZE + 8 761 + #define PT_TLBL0 PT_SIZE + 12 762 + #define PT_TLBH0 PT_SIZE + 16 763 + 764 + C_ENTRY(_xtmr_manager_reset): 765 + lwi r1, r0, xmb_manager_stackpointer 766 + 767 + /* Restore MSR */ 768 + lwi r2, r1, PT_MSR 769 + mts rmsr, r2 770 + bri 4 771 + 772 + /* restore Special purpose registers */ 773 + lwi r2, r1, PT_PID 774 + mts rpid, r2 775 + 776 + lwi r2, r1, PT_TLBI 777 + mts rtlbx, r2 778 + 779 + lwi r2, r1, PT_ZPR 780 + mts rzpr, r2 781 + 782 + #if CONFIG_XILINX_MICROBLAZE0_USE_FPU 783 + lwi r2, r1, PT_FSR 784 + mts rfsr, r2 785 + #endif 786 + 787 + /* restore all the tlb's */ 788 + addik r3, r0, TOPHYS(tlb_skip) 789 + addik r6, r0, PT_TLBL0 790 + addik r7, r0, PT_TLBH0 791 + restore_tlb: 792 + add r6, r6, r1 793 + add r7, r7, r1 794 + lwi r2, r6, 0 795 + mts rtlblo, r2 796 + lwi r2, r7, 0 797 + mts rtlbhi, r2 798 + addik r6, r6, 4 799 + addik r7, r7, 4 800 + bgtid r3, restore_tlb 801 + addik r3, r3, -1 802 + 803 + lwi r5, r0, TOPHYS(xmb_manager_dev) 804 + lwi r8, r0, TOPHYS(xmb_manager_reset_callback) 805 + set_vms 806 + /* return from reset need -8 to adjust for rtsd r15, 8 */ 807 + addik r15, r0, ret_from_reset - 8 808 + rtbd r8, 0 809 + nop 810 + 811 + ret_from_reset: 812 + set_bip /* Ints masked for state restore */ 813 + VM_OFF 814 + /* MS: Restore all regs */ 815 + RESTORE_REGS 816 + lwi r14, r1, PT_R14 817 + lwi r16, r1, PT_PC 818 + addik r1, r1, PT_SIZE + 36 819 + rtbd r16, 0 820 + nop 821 + 822 + /* 823 + * Break handler for MB Manager. Enter to _xmb_manager_break by 824 + * injecting fault in one of the TMR Microblaze core. 825 + * FIXME: This break handler supports getting 826 + * called from kernel space only. 827 + */ 828 + C_ENTRY(_xmb_manager_break): 829 + /* 830 + * Reserve memory in the stack for context store/restore 831 + * (which includes memory for storing tlbs (max two tlbs)) 832 + */ 833 + addik r1, r1, -PT_SIZE - 36 834 + swi r1, r0, xmb_manager_stackpointer 835 + SAVE_REGS 836 + swi r14, r1, PT_R14 /* rewrite saved R14 value */ 837 + swi r16, r1, PT_PC; /* PC and r16 are the same */ 838 + 839 + lwi r6, r0, TOPHYS(xmb_manager_baseaddr) 840 + lwi r7, r0, TOPHYS(xmb_manager_crval) 841 + /* 842 + * When the break vector gets asserted because of error injection, 843 + * the break signal must be blocked before exiting from the 844 + * break handler, below code configures the tmr manager 845 + * control register to block break signal. 846 + */ 847 + swi r7, r6, 0 848 + 849 + /* Save the special purpose registers */ 850 + mfs r2, rpid 851 + swi r2, r1, PT_PID 852 + 853 + mfs r2, rtlbx 854 + swi r2, r1, PT_TLBI 855 + 856 + mfs r2, rzpr 857 + swi r2, r1, PT_ZPR 858 + 859 + #if CONFIG_XILINX_MICROBLAZE0_USE_FPU 860 + mfs r2, rfsr 861 + swi r2, r1, PT_FSR 862 + #endif 863 + mfs r2, rmsr 864 + swi r2, r1, PT_MSR 865 + 866 + /* Save all the tlb's */ 867 + addik r3, r0, TOPHYS(tlb_skip) 868 + addik r6, r0, PT_TLBL0 869 + addik r7, r0, PT_TLBH0 870 + save_tlb: 871 + add r6, r6, r1 872 + add r7, r7, r1 873 + mfs r2, rtlblo 874 + swi r2, r6, 0 875 + mfs r2, rtlbhi 876 + swi r2, r7, 0 877 + addik r6, r6, 4 878 + addik r7, r7, 4 879 + bgtid r3, save_tlb 880 + addik r3, r3, -1 881 + 882 + lwi r5, r0, TOPHYS(xmb_manager_dev) 883 + lwi r8, r0, TOPHYS(xmb_manager_callback) 884 + /* return from break need -8 to adjust for rtsd r15, 8 */ 885 + addik r15, r0, ret_from_break - 8 886 + rtbd r8, 0 887 + nop 888 + 889 + ret_from_break: 890 + /* flush the d-cache */ 891 + bralid r15, mb_flush_dcache 892 + nop 893 + 894 + /* 895 + * To make sure microblaze i-cache is in a proper state 896 + * invalidate the i-cache. 897 + */ 898 + bralid r15, mb_invalidate_icache 899 + nop 900 + 901 + set_bip; /* Ints masked for state restore */ 902 + VM_OFF; 903 + mbar 1 904 + mbar 2 905 + bri 4 906 + suspend 907 + nop 908 + #endif 909 + 795 910 /* 796 911 * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18 797 912 * and call handling function with saved pt_regs ··· 1157 964 .global xmb_manager_crval 1158 965 .global xmb_manager_callback 1159 966 .global xmb_manager_reset_callback 967 + .global xmb_manager_stackpointer 1160 968 .align 4 1161 969 xmb_manager_dev: 1162 970 .long 0 ··· 1168 974 xmb_manager_callback: 1169 975 .long 0 1170 976 xmb_manager_reset_callback: 977 + .long 0 978 + xmb_manager_stackpointer: 1171 979 .long 0 1172 980 1173 981 /* ··· 1204 1008 /* These are compiled and loaded into high memory, then 1205 1009 * copied into place in mach_early_setup */ 1206 1010 .section .init.ivt, "ax" 1207 - #if CONFIG_MANUAL_RESET_VECTOR 1011 + #if CONFIG_MANUAL_RESET_VECTOR && !defined(CONFIG_MB_MANAGER) 1208 1012 .org 0x0 1209 1013 brai CONFIG_MANUAL_RESET_VECTOR 1014 + #elif defined(CONFIG_MB_MANAGER) 1015 + .org 0x0 1016 + brai TOPHYS(_xtmr_manager_reset); 1210 1017 #endif 1211 1018 .org 0x8 1212 1019 brai TOPHYS(_user_exception); /* syscall handler */ 1213 1020 .org 0x10 1214 1021 brai TOPHYS(_interrupt); /* Interrupt handler */ 1022 + #ifdef CONFIG_MB_MANAGER 1023 + .org 0x18 1024 + brai TOPHYS(_xmb_manager_break); /* microblaze manager break handler */ 1025 + #else 1215 1026 .org 0x18 1216 1027 brai TOPHYS(_debug_exception); /* debug trap handler */ 1028 + #endif 1217 1029 .org 0x20 1218 1030 brai TOPHYS(_hw_exception_handler); /* HW exception handler */ 1219 1031