xref: /linux/drivers/gpu/drm/i915/i915_mitigations.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1f7452c7cSChris Wilson // SPDX-License-Identifier: MIT
2f7452c7cSChris Wilson /*
3f7452c7cSChris Wilson  * Copyright © 2021 Intel Corporation
4f7452c7cSChris Wilson  */
5f7452c7cSChris Wilson 
6f7452c7cSChris Wilson #include <linux/kernel.h>
7f7452c7cSChris Wilson #include <linux/moduleparam.h>
8f7452c7cSChris Wilson #include <linux/slab.h>
9f7452c7cSChris Wilson #include <linux/string.h>
10f7452c7cSChris Wilson 
11*24524e3fSJani Nikula #include "i915_driver.h"
12f7452c7cSChris Wilson #include "i915_drv.h"
13f7452c7cSChris Wilson #include "i915_mitigations.h"
14f7452c7cSChris Wilson 
15f7452c7cSChris Wilson static unsigned long mitigations __read_mostly = ~0UL;
16f7452c7cSChris Wilson 
17f7452c7cSChris Wilson enum {
18f7452c7cSChris Wilson 	CLEAR_RESIDUALS = 0,
19f7452c7cSChris Wilson };
20f7452c7cSChris Wilson 
21f7452c7cSChris Wilson static const char * const names[] = {
22f7452c7cSChris Wilson 	[CLEAR_RESIDUALS] = "residuals",
23f7452c7cSChris Wilson };
24f7452c7cSChris Wilson 
i915_mitigate_clear_residuals(void)25f7452c7cSChris Wilson bool i915_mitigate_clear_residuals(void)
26f7452c7cSChris Wilson {
27f7452c7cSChris Wilson 	return READ_ONCE(mitigations) & BIT(CLEAR_RESIDUALS);
28f7452c7cSChris Wilson }
29f7452c7cSChris Wilson 
mitigations_set(const char * val,const struct kernel_param * kp)30f7452c7cSChris Wilson static int mitigations_set(const char *val, const struct kernel_param *kp)
31f7452c7cSChris Wilson {
32f7452c7cSChris Wilson 	unsigned long new = ~0UL;
33f7452c7cSChris Wilson 	char *str, *sep, *tok;
34f7452c7cSChris Wilson 	bool first = true;
35f7452c7cSChris Wilson 	int err = 0;
36f7452c7cSChris Wilson 
37f7452c7cSChris Wilson 	BUILD_BUG_ON(ARRAY_SIZE(names) >= BITS_PER_TYPE(mitigations));
38f7452c7cSChris Wilson 
39f7452c7cSChris Wilson 	str = kstrdup(val, GFP_KERNEL);
40f7452c7cSChris Wilson 	if (!str)
41f7452c7cSChris Wilson 		return -ENOMEM;
42f7452c7cSChris Wilson 
43f7452c7cSChris Wilson 	for (sep = str; (tok = strsep(&sep, ","));) {
44f7452c7cSChris Wilson 		bool enable = true;
45f7452c7cSChris Wilson 		int i;
46f7452c7cSChris Wilson 
47f7452c7cSChris Wilson 		/* Be tolerant of leading/trailing whitespace */
48f7452c7cSChris Wilson 		tok = strim(tok);
49f7452c7cSChris Wilson 
50f7452c7cSChris Wilson 		if (first) {
51f7452c7cSChris Wilson 			first = false;
52f7452c7cSChris Wilson 
53f7452c7cSChris Wilson 			if (!strcmp(tok, "auto"))
54f7452c7cSChris Wilson 				continue;
55f7452c7cSChris Wilson 
56f7452c7cSChris Wilson 			new = 0;
57f7452c7cSChris Wilson 			if (!strcmp(tok, "off"))
58f7452c7cSChris Wilson 				continue;
59f7452c7cSChris Wilson 		}
60f7452c7cSChris Wilson 
61f7452c7cSChris Wilson 		if (*tok == '!') {
62f7452c7cSChris Wilson 			enable = !enable;
63f7452c7cSChris Wilson 			tok++;
64f7452c7cSChris Wilson 		}
65f7452c7cSChris Wilson 
66f7452c7cSChris Wilson 		if (!strncmp(tok, "no", 2)) {
67f7452c7cSChris Wilson 			enable = !enable;
68f7452c7cSChris Wilson 			tok += 2;
69f7452c7cSChris Wilson 		}
70f7452c7cSChris Wilson 
71f7452c7cSChris Wilson 		if (*tok == '\0')
72f7452c7cSChris Wilson 			continue;
73f7452c7cSChris Wilson 
74f7452c7cSChris Wilson 		for (i = 0; i < ARRAY_SIZE(names); i++) {
75f7452c7cSChris Wilson 			if (!strcmp(tok, names[i])) {
76f7452c7cSChris Wilson 				if (enable)
77f7452c7cSChris Wilson 					new |= BIT(i);
78f7452c7cSChris Wilson 				else
79f7452c7cSChris Wilson 					new &= ~BIT(i);
80f7452c7cSChris Wilson 				break;
81f7452c7cSChris Wilson 			}
82f7452c7cSChris Wilson 		}
83f7452c7cSChris Wilson 		if (i == ARRAY_SIZE(names)) {
84f7452c7cSChris Wilson 			pr_err("Bad \"%s.mitigations=%s\", '%s' is unknown\n",
85f7452c7cSChris Wilson 			       DRIVER_NAME, val, tok);
86f7452c7cSChris Wilson 			err = -EINVAL;
87f7452c7cSChris Wilson 			break;
88f7452c7cSChris Wilson 		}
89f7452c7cSChris Wilson 	}
90f7452c7cSChris Wilson 	kfree(str);
91f7452c7cSChris Wilson 	if (err)
92f7452c7cSChris Wilson 		return err;
93f7452c7cSChris Wilson 
94f7452c7cSChris Wilson 	WRITE_ONCE(mitigations, new);
95f7452c7cSChris Wilson 	return 0;
96f7452c7cSChris Wilson }
97f7452c7cSChris Wilson 
mitigations_get(char * buffer,const struct kernel_param * kp)98f7452c7cSChris Wilson static int mitigations_get(char *buffer, const struct kernel_param *kp)
99f7452c7cSChris Wilson {
100f7452c7cSChris Wilson 	unsigned long local = READ_ONCE(mitigations);
101f7452c7cSChris Wilson 	int count, i;
102f7452c7cSChris Wilson 	bool enable;
103f7452c7cSChris Wilson 
104f7452c7cSChris Wilson 	if (!local)
105f7452c7cSChris Wilson 		return scnprintf(buffer, PAGE_SIZE, "%s\n", "off");
106f7452c7cSChris Wilson 
107f7452c7cSChris Wilson 	if (local & BIT(BITS_PER_LONG - 1)) {
108f7452c7cSChris Wilson 		count = scnprintf(buffer, PAGE_SIZE, "%s,", "auto");
109f7452c7cSChris Wilson 		enable = false;
110f7452c7cSChris Wilson 	} else {
111f7452c7cSChris Wilson 		enable = true;
112f7452c7cSChris Wilson 		count = 0;
113f7452c7cSChris Wilson 	}
114f7452c7cSChris Wilson 
115f7452c7cSChris Wilson 	for (i = 0; i < ARRAY_SIZE(names); i++) {
116f7452c7cSChris Wilson 		if ((local & BIT(i)) != enable)
117f7452c7cSChris Wilson 			continue;
118f7452c7cSChris Wilson 
119f7452c7cSChris Wilson 		count += scnprintf(buffer + count, PAGE_SIZE - count,
120f7452c7cSChris Wilson 				   "%s%s,", enable ? "" : "!", names[i]);
121f7452c7cSChris Wilson 	}
122f7452c7cSChris Wilson 
123f7452c7cSChris Wilson 	buffer[count - 1] = '\n';
124f7452c7cSChris Wilson 	return count;
125f7452c7cSChris Wilson }
126f7452c7cSChris Wilson 
127f7452c7cSChris Wilson static const struct kernel_param_ops ops = {
128f7452c7cSChris Wilson 	.set = mitigations_set,
129f7452c7cSChris Wilson 	.get = mitigations_get,
130f7452c7cSChris Wilson };
131f7452c7cSChris Wilson 
132f7452c7cSChris Wilson module_param_cb_unsafe(mitigations, &ops, NULL, 0600);
133f7452c7cSChris Wilson MODULE_PARM_DESC(mitigations,
134f7452c7cSChris Wilson "Selectively enable security mitigations for all Intel® GPUs in the system.\n"
135f7452c7cSChris Wilson "\n"
136f7452c7cSChris Wilson "  auto -- enables all mitigations required for the platform [default]\n"
137f7452c7cSChris Wilson "  off  -- disables all mitigations\n"
138f7452c7cSChris Wilson "\n"
139f7452c7cSChris Wilson "Individual mitigations can be enabled by passing a comma-separated string,\n"
140f7452c7cSChris Wilson "e.g. mitigations=residuals to enable only clearing residuals or\n"
141f7452c7cSChris Wilson "mitigations=auto,noresiduals to disable only the clear residual mitigation.\n"
142f7452c7cSChris Wilson "Either '!' or 'no' may be used to switch from enabling the mitigation to\n"
143f7452c7cSChris Wilson "disabling it.\n"
144f7452c7cSChris Wilson "\n"
145f7452c7cSChris Wilson "Active mitigations for Ivybridge, Baytrail, Haswell:\n"
146f7452c7cSChris Wilson "  residuals -- clear all thread-local registers between contexts"
147f7452c7cSChris Wilson );
148