18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2021 Intel Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "i915_drv.h" 128c2ecf20Sopenharmony_ci#include "i915_mitigations.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic unsigned long mitigations __read_mostly = ~0UL; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cienum { 178c2ecf20Sopenharmony_ci CLEAR_RESIDUALS = 0, 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic const char * const names[] = { 218c2ecf20Sopenharmony_ci [CLEAR_RESIDUALS] = "residuals", 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cibool i915_mitigate_clear_residuals(void) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci return READ_ONCE(mitigations) & BIT(CLEAR_RESIDUALS); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int mitigations_set(const char *val, const struct kernel_param *kp) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci unsigned long new = ~0UL; 328c2ecf20Sopenharmony_ci char *str, *sep, *tok; 338c2ecf20Sopenharmony_ci bool first = true; 348c2ecf20Sopenharmony_ci int err = 0; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(names) >= BITS_PER_TYPE(mitigations)); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci str = kstrdup(val, GFP_KERNEL); 398c2ecf20Sopenharmony_ci if (!str) 408c2ecf20Sopenharmony_ci return -ENOMEM; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci for (sep = str; (tok = strsep(&sep, ","));) { 438c2ecf20Sopenharmony_ci bool enable = true; 448c2ecf20Sopenharmony_ci int i; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Be tolerant of leading/trailing whitespace */ 478c2ecf20Sopenharmony_ci tok = strim(tok); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (first) { 508c2ecf20Sopenharmony_ci first = false; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!strcmp(tok, "auto")) 538c2ecf20Sopenharmony_ci continue; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci new = 0; 568c2ecf20Sopenharmony_ci if (!strcmp(tok, "off")) 578c2ecf20Sopenharmony_ci continue; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (*tok == '!') { 618c2ecf20Sopenharmony_ci enable = !enable; 628c2ecf20Sopenharmony_ci tok++; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!strncmp(tok, "no", 2)) { 668c2ecf20Sopenharmony_ci enable = !enable; 678c2ecf20Sopenharmony_ci tok += 2; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (*tok == '\0') 718c2ecf20Sopenharmony_ci continue; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(names); i++) { 748c2ecf20Sopenharmony_ci if (!strcmp(tok, names[i])) { 758c2ecf20Sopenharmony_ci if (enable) 768c2ecf20Sopenharmony_ci new |= BIT(i); 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci new &= ~BIT(i); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(names)) { 838c2ecf20Sopenharmony_ci pr_err("Bad \"%s.mitigations=%s\", '%s' is unknown\n", 848c2ecf20Sopenharmony_ci DRIVER_NAME, val, tok); 858c2ecf20Sopenharmony_ci err = -EINVAL; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci kfree(str); 908c2ecf20Sopenharmony_ci if (err) 918c2ecf20Sopenharmony_ci return err; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci WRITE_ONCE(mitigations, new); 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int mitigations_get(char *buffer, const struct kernel_param *kp) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci unsigned long local = READ_ONCE(mitigations); 1008c2ecf20Sopenharmony_ci int count, i; 1018c2ecf20Sopenharmony_ci bool enable; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (!local) 1048c2ecf20Sopenharmony_ci return scnprintf(buffer, PAGE_SIZE, "%s\n", "off"); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (local & BIT(BITS_PER_LONG - 1)) { 1078c2ecf20Sopenharmony_ci count = scnprintf(buffer, PAGE_SIZE, "%s,", "auto"); 1088c2ecf20Sopenharmony_ci enable = false; 1098c2ecf20Sopenharmony_ci } else { 1108c2ecf20Sopenharmony_ci enable = true; 1118c2ecf20Sopenharmony_ci count = 0; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(names); i++) { 1158c2ecf20Sopenharmony_ci if ((local & BIT(i)) != enable) 1168c2ecf20Sopenharmony_ci continue; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci count += scnprintf(buffer + count, PAGE_SIZE - count, 1198c2ecf20Sopenharmony_ci "%s%s,", enable ? "" : "!", names[i]); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci buffer[count - 1] = '\n'; 1238c2ecf20Sopenharmony_ci return count; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic const struct kernel_param_ops ops = { 1278c2ecf20Sopenharmony_ci .set = mitigations_set, 1288c2ecf20Sopenharmony_ci .get = mitigations_get, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cimodule_param_cb_unsafe(mitigations, &ops, NULL, 0600); 1328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mitigations, 1338c2ecf20Sopenharmony_ci"Selectively enable security mitigations for all Intel® GPUs in the system.\n" 1348c2ecf20Sopenharmony_ci"\n" 1358c2ecf20Sopenharmony_ci" auto -- enables all mitigations required for the platform [default]\n" 1368c2ecf20Sopenharmony_ci" off -- disables all mitigations\n" 1378c2ecf20Sopenharmony_ci"\n" 1388c2ecf20Sopenharmony_ci"Individual mitigations can be enabled by passing a comma-separated string,\n" 1398c2ecf20Sopenharmony_ci"e.g. mitigations=residuals to enable only clearing residuals or\n" 1408c2ecf20Sopenharmony_ci"mitigations=auto,noresiduals to disable only the clear residual mitigation.\n" 1418c2ecf20Sopenharmony_ci"Either '!' or 'no' may be used to switch from enabling the mitigation to\n" 1428c2ecf20Sopenharmony_ci"disabling it.\n" 1438c2ecf20Sopenharmony_ci"\n" 1448c2ecf20Sopenharmony_ci"Active mitigations for Ivybridge, Baytrail, Haswell:\n" 1458c2ecf20Sopenharmony_ci" residuals -- clear all thread-local registers between contexts" 1468c2ecf20Sopenharmony_ci); 147