|
17 | 17 | #include <linux/sched.h> |
18 | 18 | #include <linux/sched/debug.h> |
19 | 19 | #include <linux/slab.h> |
| 20 | +#include <linux/string.h> |
20 | 21 | #include <linux/clocksource.h> |
21 | 22 |
|
22 | 23 | #include <asm/apic.h> |
@@ -178,65 +179,67 @@ module_param_named(debug, uv_nmi_debug, int, 0644); |
178 | 179 | } while (0) |
179 | 180 |
|
180 | 181 | /* Valid NMI Actions */ |
181 | | -#define ACTION_LEN 16 |
182 | | -static struct nmi_action { |
183 | | - char *action; |
184 | | - char *desc; |
185 | | -} valid_acts[] = { |
186 | | - { "kdump", "do kernel crash dump" }, |
187 | | - { "dump", "dump process stack for each cpu" }, |
188 | | - { "ips", "dump Inst Ptr info for each cpu" }, |
189 | | - { "kdb", "enter KDB (needs kgdboc= assignment)" }, |
190 | | - { "kgdb", "enter KGDB (needs gdb target remote)" }, |
191 | | - { "health", "check if CPUs respond to NMI" }, |
| 182 | +enum action_t { |
| 183 | + nmi_act_kdump, |
| 184 | + nmi_act_dump, |
| 185 | + nmi_act_ips, |
| 186 | + nmi_act_kdb, |
| 187 | + nmi_act_kgdb, |
| 188 | + nmi_act_health, |
| 189 | + nmi_act_max |
192 | 190 | }; |
193 | | -typedef char action_t[ACTION_LEN]; |
194 | | -static action_t uv_nmi_action = { "dump" }; |
| 191 | + |
| 192 | +static const char * const actions[nmi_act_max] = { |
| 193 | + [nmi_act_kdump] = "kdump", |
| 194 | + [nmi_act_dump] = "dump", |
| 195 | + [nmi_act_ips] = "ips", |
| 196 | + [nmi_act_kdb] = "kdb", |
| 197 | + [nmi_act_kgdb] = "kgdb", |
| 198 | + [nmi_act_health] = "health", |
| 199 | +}; |
| 200 | + |
| 201 | +static const char * const actions_desc[nmi_act_max] = { |
| 202 | + [nmi_act_kdump] = "do kernel crash dump", |
| 203 | + [nmi_act_dump] = "dump process stack for each cpu", |
| 204 | + [nmi_act_ips] = "dump Inst Ptr info for each cpu", |
| 205 | + [nmi_act_kdb] = "enter KDB (needs kgdboc= assignment)", |
| 206 | + [nmi_act_kgdb] = "enter KGDB (needs gdb target remote)", |
| 207 | + [nmi_act_health] = "check if CPUs respond to NMI", |
| 208 | +}; |
| 209 | + |
| 210 | +static enum action_t uv_nmi_action = nmi_act_dump; |
195 | 211 |
|
196 | 212 | static int param_get_action(char *buffer, const struct kernel_param *kp) |
197 | 213 | { |
198 | | - return sprintf(buffer, "%s\n", uv_nmi_action); |
| 214 | + return sprintf(buffer, "%s\n", actions[uv_nmi_action]); |
199 | 215 | } |
200 | 216 |
|
201 | 217 | static int param_set_action(const char *val, const struct kernel_param *kp) |
202 | 218 | { |
203 | | - int i; |
204 | | - int n = ARRAY_SIZE(valid_acts); |
205 | | - char arg[ACTION_LEN]; |
206 | | - |
207 | | - /* (remove possible '\n') */ |
208 | | - strscpy(arg, val, strnchrnul(val, sizeof(arg)-1, '\n') - val + 1); |
209 | | - |
210 | | - for (i = 0; i < n; i++) |
211 | | - if (!strcmp(arg, valid_acts[i].action)) |
212 | | - break; |
| 219 | + int i, n = ARRAY_SIZE(actions); |
213 | 220 |
|
214 | | - if (i < n) { |
215 | | - strscpy(uv_nmi_action, arg, sizeof(uv_nmi_action)); |
216 | | - pr_info("UV: New NMI action:%s\n", uv_nmi_action); |
| 221 | + i = sysfs_match_string(actions, val); |
| 222 | + if (i >= 0) { |
| 223 | + uv_nmi_action = i; |
| 224 | + pr_info("UV: New NMI action:%s\n", actions[i]); |
217 | 225 | return 0; |
218 | 226 | } |
219 | 227 |
|
220 | | - pr_err("UV: Invalid NMI action:%s, valid actions are:\n", arg); |
| 228 | + pr_err("UV: Invalid NMI action. Valid actions are:\n"); |
221 | 229 | for (i = 0; i < n; i++) |
222 | | - pr_err("UV: %-8s - %s\n", |
223 | | - valid_acts[i].action, valid_acts[i].desc); |
| 230 | + pr_err("UV: %-8s - %s\n", actions[i], actions_desc[i]); |
| 231 | + |
224 | 232 | return -EINVAL; |
225 | 233 | } |
226 | 234 |
|
227 | 235 | static const struct kernel_param_ops param_ops_action = { |
228 | 236 | .get = param_get_action, |
229 | 237 | .set = param_set_action, |
230 | 238 | }; |
231 | | -#define param_check_action(name, p) __param_check(name, p, action_t) |
| 239 | +#define param_check_action(name, p) __param_check(name, p, enum action_t) |
232 | 240 |
|
233 | 241 | module_param_named(action, uv_nmi_action, action, 0644); |
234 | 242 |
|
235 | | -static inline bool uv_nmi_action_is(const char *action) |
236 | | -{ |
237 | | - return (strncmp(uv_nmi_action, action, strlen(action)) == 0); |
238 | | -} |
239 | | - |
240 | 243 | /* Setup which NMI support is present in system */ |
241 | 244 | static void uv_nmi_setup_mmrs(void) |
242 | 245 | { |
@@ -727,10 +730,10 @@ static void uv_nmi_dump_state_cpu(int cpu, struct pt_regs *regs) |
727 | 730 | if (cpu == 0) |
728 | 731 | uv_nmi_dump_cpu_ip_hdr(); |
729 | 732 |
|
730 | | - if (current->pid != 0 || !uv_nmi_action_is("ips")) |
| 733 | + if (current->pid != 0 || uv_nmi_action != nmi_act_ips) |
731 | 734 | uv_nmi_dump_cpu_ip(cpu, regs); |
732 | 735 |
|
733 | | - if (uv_nmi_action_is("dump")) { |
| 736 | + if (uv_nmi_action == nmi_act_dump) { |
734 | 737 | pr_info("UV:%sNMI process trace for CPU %d\n", dots, cpu); |
735 | 738 | show_regs(regs); |
736 | 739 | } |
@@ -798,7 +801,7 @@ static void uv_nmi_dump_state(int cpu, struct pt_regs *regs, int master) |
798 | 801 | int saved_console_loglevel = console_loglevel; |
799 | 802 |
|
800 | 803 | pr_alert("UV: tracing %s for %d CPUs from CPU %d\n", |
801 | | - uv_nmi_action_is("ips") ? "IPs" : "processes", |
| 804 | + uv_nmi_action == nmi_act_ips ? "IPs" : "processes", |
802 | 805 | atomic_read(&uv_nmi_cpus_in_nmi), cpu); |
803 | 806 |
|
804 | 807 | console_loglevel = uv_nmi_loglevel; |
@@ -874,7 +877,7 @@ static inline int uv_nmi_kdb_reason(void) |
874 | 877 | static inline int uv_nmi_kdb_reason(void) |
875 | 878 | { |
876 | 879 | /* Ensure user is expecting to attach gdb remote */ |
877 | | - if (uv_nmi_action_is("kgdb")) |
| 880 | + if (uv_nmi_action == nmi_act_kgdb) |
878 | 881 | return 0; |
879 | 882 |
|
880 | 883 | pr_err("UV: NMI error: KDB is not enabled in this kernel\n"); |
@@ -950,28 +953,35 @@ static int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) |
950 | 953 | master = (atomic_read(&uv_nmi_cpu) == cpu); |
951 | 954 |
|
952 | 955 | /* If NMI action is "kdump", then attempt to do it */ |
953 | | - if (uv_nmi_action_is("kdump")) { |
| 956 | + if (uv_nmi_action == nmi_act_kdump) { |
954 | 957 | uv_nmi_kdump(cpu, master, regs); |
955 | 958 |
|
956 | 959 | /* Unexpected return, revert action to "dump" */ |
957 | 960 | if (master) |
958 | | - strscpy(uv_nmi_action, "dump", sizeof(uv_nmi_action)); |
| 961 | + uv_nmi_action = nmi_act_dump; |
959 | 962 | } |
960 | 963 |
|
961 | 964 | /* Pause as all CPU's enter the NMI handler */ |
962 | 965 | uv_nmi_wait(master); |
963 | 966 |
|
964 | 967 | /* Process actions other than "kdump": */ |
965 | | - if (uv_nmi_action_is("health")) { |
| 968 | + switch (uv_nmi_action) { |
| 969 | + case nmi_act_health: |
966 | 970 | uv_nmi_action_health(cpu, regs, master); |
967 | | - } else if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump")) { |
| 971 | + break; |
| 972 | + case nmi_act_ips: |
| 973 | + case nmi_act_dump: |
968 | 974 | uv_nmi_dump_state(cpu, regs, master); |
969 | | - } else if (uv_nmi_action_is("kdb") || uv_nmi_action_is("kgdb")) { |
| 975 | + break; |
| 976 | + case nmi_act_kdb: |
| 977 | + case nmi_act_kgdb: |
970 | 978 | uv_call_kgdb_kdb(cpu, regs, master); |
971 | | - } else { |
| 979 | + break; |
| 980 | + default: |
972 | 981 | if (master) |
973 | | - pr_alert("UV: unknown NMI action: %s\n", uv_nmi_action); |
| 982 | + pr_alert("UV: unknown NMI action: %d\n", uv_nmi_action); |
974 | 983 | uv_nmi_sync_exit(master); |
| 984 | + break; |
975 | 985 | } |
976 | 986 |
|
977 | 987 | /* Clear per_cpu "in_nmi" flag */ |
|
0 commit comments