|
10 | 10 | #include <linux/thread_info.h>
|
11 | 11 | #include <linux/init.h>
|
12 | 12 | #include <linux/uaccess.h>
|
| 13 | +#include <linux/delay.h> |
13 | 14 |
|
14 | 15 | #include <asm/cpufeature.h>
|
15 | 16 | #include <asm/msr.h>
|
@@ -41,6 +42,7 @@ enum split_lock_detect_state {
|
41 | 42 | sld_off = 0,
|
42 | 43 | sld_warn,
|
43 | 44 | sld_fatal,
|
| 45 | + sld_ratelimit, |
44 | 46 | };
|
45 | 47 |
|
46 | 48 | /*
|
@@ -997,13 +999,30 @@ static const struct {
|
997 | 999 | { "off", sld_off },
|
998 | 1000 | { "warn", sld_warn },
|
999 | 1001 | { "fatal", sld_fatal },
|
| 1002 | + { "ratelimit:", sld_ratelimit }, |
1000 | 1003 | };
|
1001 | 1004 |
|
| 1005 | +static struct ratelimit_state bld_ratelimit; |
| 1006 | + |
1002 | 1007 | static inline bool match_option(const char *arg, int arglen, const char *opt)
|
1003 | 1008 | {
|
1004 |
| - int len = strlen(opt); |
| 1009 | + int len = strlen(opt), ratelimit; |
| 1010 | + |
| 1011 | + if (strncmp(arg, opt, len)) |
| 1012 | + return false; |
| 1013 | + |
| 1014 | + /* |
| 1015 | + * Min ratelimit is 1 bus lock/sec. |
| 1016 | + * Max ratelimit is 1000 bus locks/sec. |
| 1017 | + */ |
| 1018 | + if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 && |
| 1019 | + ratelimit > 0 && ratelimit <= 1000) { |
| 1020 | + ratelimit_state_init(&bld_ratelimit, HZ, ratelimit); |
| 1021 | + ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE); |
| 1022 | + return true; |
| 1023 | + } |
1005 | 1024 |
|
1006 |
| - return len == arglen && !strncmp(arg, opt, len); |
| 1025 | + return len == arglen; |
1007 | 1026 | }
|
1008 | 1027 |
|
1009 | 1028 | static bool split_lock_verify_msr(bool on)
|
@@ -1082,6 +1101,15 @@ static void sld_update_msr(bool on)
|
1082 | 1101 |
|
1083 | 1102 | static void split_lock_init(void)
|
1084 | 1103 | {
|
| 1104 | + /* |
| 1105 | + * #DB for bus lock handles ratelimit and #AC for split lock is |
| 1106 | + * disabled. |
| 1107 | + */ |
| 1108 | + if (sld_state == sld_ratelimit) { |
| 1109 | + split_lock_verify_msr(false); |
| 1110 | + return; |
| 1111 | + } |
| 1112 | + |
1085 | 1113 | if (cpu_model_supports_sld)
|
1086 | 1114 | split_lock_verify_msr(sld_state != sld_off);
|
1087 | 1115 | }
|
@@ -1154,6 +1182,12 @@ void handle_bus_lock(struct pt_regs *regs)
|
1154 | 1182 | switch (sld_state) {
|
1155 | 1183 | case sld_off:
|
1156 | 1184 | break;
|
| 1185 | + case sld_ratelimit: |
| 1186 | + /* Enforce no more than bld_ratelimit bus locks/sec. */ |
| 1187 | + while (!__ratelimit(&bld_ratelimit)) |
| 1188 | + msleep(20); |
| 1189 | + /* Warn on the bus lock. */ |
| 1190 | + fallthrough; |
1157 | 1191 | case sld_warn:
|
1158 | 1192 | pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n",
|
1159 | 1193 | current->comm, current->pid, regs->ip);
|
@@ -1259,6 +1293,10 @@ static void sld_state_show(void)
|
1259 | 1293 | " from non-WB" : "");
|
1260 | 1294 | }
|
1261 | 1295 | break;
|
| 1296 | + case sld_ratelimit: |
| 1297 | + if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) |
| 1298 | + pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst); |
| 1299 | + break; |
1262 | 1300 | }
|
1263 | 1301 | }
|
1264 | 1302 |
|
|
0 commit comments