~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/xtensa/kernel/s32c1i_selftest.c

Version: ~ [ linux-5.11-rc3 ] ~ [ linux-5.10.7 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.89 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.167 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.215 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.251 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.251 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * S32C1I selftest.
  3  *
  4  * This file is subject to the terms and conditions of the GNU General Public
  5  * License.  See the file "COPYING" in the main directory of this archive
  6  * for more details.
  7  *
  8  * Copyright (C) 2016 Cadence Design Systems Inc.
  9  */
 10 
 11 #include <linux/init.h>
 12 #include <linux/kernel.h>
 13 
 14 #include <asm/traps.h>
 15 
 16 #if XCHAL_HAVE_S32C1I
 17 
 18 static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
 19 
 20 /*
 21  * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
 22  *
 23  * If *v == cmp, set *v = set.  Return previous *v.
 24  */
 25 static inline int probed_compare_swap(int *v, int cmp, int set)
 26 {
 27         int tmp;
 28 
 29         __asm__ __volatile__(
 30                         "       movi    %1, 1f\n"
 31                         "       s32i    %1, %4, 0\n"
 32                         "       wsr     %2, scompare1\n"
 33                         "1:     s32c1i  %0, %3, 0\n"
 34                         : "=a" (set), "=&a" (tmp)
 35                         : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "" (set)
 36                         : "memory"
 37                         );
 38         return set;
 39 }
 40 
 41 /* Handle probed exception */
 42 
 43 static void __init do_probed_exception(struct pt_regs *regs,
 44                                        unsigned long exccause)
 45 {
 46         if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
 47                 regs->pc += 3;          /* skip the s32c1i instruction */
 48                 rcw_exc = exccause;
 49         } else {
 50                 do_unhandled(regs, exccause);
 51         }
 52 }
 53 
 54 /* Simple test of S32C1I (soc bringup assist) */
 55 
 56 static int __init check_s32c1i(void)
 57 {
 58         int n, cause1, cause2;
 59         void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
 60 
 61         rcw_probe_pc = 0;
 62         handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
 63                         do_probed_exception);
 64         handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
 65                         do_probed_exception);
 66         handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
 67                         do_probed_exception);
 68 
 69         /* First try an S32C1I that does not store: */
 70         rcw_exc = 0;
 71         rcw_word = 1;
 72         n = probed_compare_swap(&rcw_word, 0, 2);
 73         cause1 = rcw_exc;
 74 
 75         /* took exception? */
 76         if (cause1 != 0) {
 77                 /* unclean exception? */
 78                 if (n != 2 || rcw_word != 1)
 79                         panic("S32C1I exception error");
 80         } else if (rcw_word != 1 || n != 1) {
 81                 panic("S32C1I compare error");
 82         }
 83 
 84         /* Then an S32C1I that stores: */
 85         rcw_exc = 0;
 86         rcw_word = 0x1234567;
 87         n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
 88         cause2 = rcw_exc;
 89 
 90         if (cause2 != 0) {
 91                 /* unclean exception? */
 92                 if (n != 0xabcde || rcw_word != 0x1234567)
 93                         panic("S32C1I exception error (b)");
 94         } else if (rcw_word != 0xabcde || n != 0x1234567) {
 95                 panic("S32C1I store error");
 96         }
 97 
 98         /* Verify consistency of exceptions: */
 99         if (cause1 || cause2) {
100                 pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
101                 /* If emulation of S32C1I upon bus error gets implemented,
102                  * we can get rid of this panic for single core (not SMP)
103                  */
104                 panic("S32C1I exceptions not currently supported");
105         }
106         if (cause1 != cause2)
107                 panic("inconsistent S32C1I exceptions");
108 
109         trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
110         trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
111         trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
112         return 0;
113 }
114 
115 #else /* XCHAL_HAVE_S32C1I */
116 
117 /* This condition should not occur with a commercially deployed processor.
118  * Display reminder for early engr test or demo chips / FPGA bitstreams
119  */
120 static int __init check_s32c1i(void)
121 {
122         pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
123         return 0;
124 }
125 
126 #endif /* XCHAL_HAVE_S32C1I */
127 
128 early_initcall(check_s32c1i);
129 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp