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