1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Mellanox boot control driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This driver provides a sysfs interface for systems management
6*4882a593Smuzhiyun * software to manage reset-time actions.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Copyright (C) 2019 Mellanox Technologies
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/acpi.h>
12*4882a593Smuzhiyun #include <linux/arm-smccc.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "mlxbf-bootctl.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define MLXBF_BOOTCTL_SB_SECURE_MASK 0x03
19*4882a593Smuzhiyun #define MLXBF_BOOTCTL_SB_TEST_MASK 0x0c
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define MLXBF_SB_KEY_NUM 4
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /* UUID used to probe ATF service. */
24*4882a593Smuzhiyun static const char *mlxbf_bootctl_svc_uuid_str =
25*4882a593Smuzhiyun "89c036b4-e7d7-11e6-8797-001aca00bfc4";
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct mlxbf_bootctl_name {
28*4882a593Smuzhiyun u32 value;
29*4882a593Smuzhiyun const char *name;
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun static struct mlxbf_bootctl_name boot_names[] = {
33*4882a593Smuzhiyun { MLXBF_BOOTCTL_EXTERNAL, "external" },
34*4882a593Smuzhiyun { MLXBF_BOOTCTL_EMMC, "emmc" },
35*4882a593Smuzhiyun { MLNX_BOOTCTL_SWAP_EMMC, "swap_emmc" },
36*4882a593Smuzhiyun { MLXBF_BOOTCTL_EMMC_LEGACY, "emmc_legacy" },
37*4882a593Smuzhiyun { MLXBF_BOOTCTL_NONE, "none" },
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const char * const mlxbf_bootctl_lifecycle_states[] = {
41*4882a593Smuzhiyun [0] = "Production",
42*4882a593Smuzhiyun [1] = "GA Secured",
43*4882a593Smuzhiyun [2] = "GA Non-Secured",
44*4882a593Smuzhiyun [3] = "RMA",
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* ARM SMC call which is atomic and no need for lock. */
mlxbf_bootctl_smc(unsigned int smc_op,int smc_arg)48*4882a593Smuzhiyun static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun struct arm_smccc_res res;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return res.a0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* Return the action in integer or an error code. */
mlxbf_bootctl_reset_action_to_val(const char * action)58*4882a593Smuzhiyun static int mlxbf_bootctl_reset_action_to_val(const char *action)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun int i;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(boot_names); i++)
63*4882a593Smuzhiyun if (sysfs_streq(boot_names[i].name, action))
64*4882a593Smuzhiyun return boot_names[i].value;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return -EINVAL;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Return the action in string. */
mlxbf_bootctl_action_to_string(int action)70*4882a593Smuzhiyun static const char *mlxbf_bootctl_action_to_string(int action)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun int i;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(boot_names); i++)
75*4882a593Smuzhiyun if (boot_names[i].value == action)
76*4882a593Smuzhiyun return boot_names[i].name;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun return "invalid action";
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
post_reset_wdog_show(struct device * dev,struct device_attribute * attr,char * buf)81*4882a593Smuzhiyun static ssize_t post_reset_wdog_show(struct device *dev,
82*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun int ret;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_POST_RESET_WDOG, 0);
87*4882a593Smuzhiyun if (ret < 0)
88*4882a593Smuzhiyun return ret;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return sprintf(buf, "%d\n", ret);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
post_reset_wdog_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)93*4882a593Smuzhiyun static ssize_t post_reset_wdog_store(struct device *dev,
94*4882a593Smuzhiyun struct device_attribute *attr,
95*4882a593Smuzhiyun const char *buf, size_t count)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun unsigned long value;
98*4882a593Smuzhiyun int ret;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun ret = kstrtoul(buf, 10, &value);
101*4882a593Smuzhiyun if (ret)
102*4882a593Smuzhiyun return ret;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_POST_RESET_WDOG, value);
105*4882a593Smuzhiyun if (ret < 0)
106*4882a593Smuzhiyun return ret;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return count;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
mlxbf_bootctl_show(int smc_op,char * buf)111*4882a593Smuzhiyun static ssize_t mlxbf_bootctl_show(int smc_op, char *buf)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun int action;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun action = mlxbf_bootctl_smc(smc_op, 0);
116*4882a593Smuzhiyun if (action < 0)
117*4882a593Smuzhiyun return action;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun return sprintf(buf, "%s\n", mlxbf_bootctl_action_to_string(action));
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
mlxbf_bootctl_store(int smc_op,const char * buf,size_t count)122*4882a593Smuzhiyun static int mlxbf_bootctl_store(int smc_op, const char *buf, size_t count)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun int ret, action;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun action = mlxbf_bootctl_reset_action_to_val(buf);
127*4882a593Smuzhiyun if (action < 0)
128*4882a593Smuzhiyun return action;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun ret = mlxbf_bootctl_smc(smc_op, action);
131*4882a593Smuzhiyun if (ret < 0)
132*4882a593Smuzhiyun return ret;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return count;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
reset_action_show(struct device * dev,struct device_attribute * attr,char * buf)137*4882a593Smuzhiyun static ssize_t reset_action_show(struct device *dev,
138*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_RESET_ACTION, buf);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
reset_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)143*4882a593Smuzhiyun static ssize_t reset_action_store(struct device *dev,
144*4882a593Smuzhiyun struct device_attribute *attr,
145*4882a593Smuzhiyun const char *buf, size_t count)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_RESET_ACTION, buf, count);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
second_reset_action_show(struct device * dev,struct device_attribute * attr,char * buf)150*4882a593Smuzhiyun static ssize_t second_reset_action_show(struct device *dev,
151*4882a593Smuzhiyun struct device_attribute *attr,
152*4882a593Smuzhiyun char *buf)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION, buf);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
second_reset_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)157*4882a593Smuzhiyun static ssize_t second_reset_action_store(struct device *dev,
158*4882a593Smuzhiyun struct device_attribute *attr,
159*4882a593Smuzhiyun const char *buf, size_t count)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION, buf,
162*4882a593Smuzhiyun count);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
lifecycle_state_show(struct device * dev,struct device_attribute * attr,char * buf)165*4882a593Smuzhiyun static ssize_t lifecycle_state_show(struct device *dev,
166*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun int lc_state;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun lc_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
171*4882a593Smuzhiyun MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE);
172*4882a593Smuzhiyun if (lc_state < 0)
173*4882a593Smuzhiyun return lc_state;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun lc_state &=
176*4882a593Smuzhiyun MLXBF_BOOTCTL_SB_TEST_MASK | MLXBF_BOOTCTL_SB_SECURE_MASK;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * If the test bits are set, we specify that the current state may be
180*4882a593Smuzhiyun * due to using the test bits.
181*4882a593Smuzhiyun */
182*4882a593Smuzhiyun if (lc_state & MLXBF_BOOTCTL_SB_TEST_MASK) {
183*4882a593Smuzhiyun lc_state &= MLXBF_BOOTCTL_SB_SECURE_MASK;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return sprintf(buf, "%s(test)\n",
186*4882a593Smuzhiyun mlxbf_bootctl_lifecycle_states[lc_state]);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return sprintf(buf, "%s\n", mlxbf_bootctl_lifecycle_states[lc_state]);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
secure_boot_fuse_state_show(struct device * dev,struct device_attribute * attr,char * buf)192*4882a593Smuzhiyun static ssize_t secure_boot_fuse_state_show(struct device *dev,
193*4882a593Smuzhiyun struct device_attribute *attr,
194*4882a593Smuzhiyun char *buf)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun int burnt, valid, key, key_state, buf_len = 0, upper_key_used = 0;
197*4882a593Smuzhiyun const char *status;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun key_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
200*4882a593Smuzhiyun MLXBF_BOOTCTL_FUSE_STATUS_KEYS);
201*4882a593Smuzhiyun if (key_state < 0)
202*4882a593Smuzhiyun return key_state;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun * key_state contains the bits for 4 Key versions, loaded from eFuses
206*4882a593Smuzhiyun * after a hard reset. Lower 4 bits are a thermometer code indicating
207*4882a593Smuzhiyun * key programming has started for key n (0000 = none, 0001 = version 0,
208*4882a593Smuzhiyun * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits
209*4882a593Smuzhiyun * are a thermometer code indicating key programming has completed for
210*4882a593Smuzhiyun * key n (same encodings as the start bits). This allows for detection
211*4882a593Smuzhiyun * of an interruption in the progamming process which has left the key
212*4882a593Smuzhiyun * partially programmed (and thus invalid). The process is to burn the
213*4882a593Smuzhiyun * eFuse for the new key start bit, burn the key eFuses, then burn the
214*4882a593Smuzhiyun * eFuse for the new key complete bit.
215*4882a593Smuzhiyun *
216*4882a593Smuzhiyun * For example 0000_0000: no key valid, 0001_0001: key version 0 valid,
217*4882a593Smuzhiyun * 0011_0011: key 1 version valid, 0011_0111: key version 2 started
218*4882a593Smuzhiyun * programming but did not complete, etc. The most recent key for which
219*4882a593Smuzhiyun * both start and complete bit is set is loaded. On soft reset, this
220*4882a593Smuzhiyun * register is not modified.
221*4882a593Smuzhiyun */
222*4882a593Smuzhiyun for (key = MLXBF_SB_KEY_NUM - 1; key >= 0; key--) {
223*4882a593Smuzhiyun burnt = key_state & BIT(key);
224*4882a593Smuzhiyun valid = key_state & BIT(key + MLXBF_SB_KEY_NUM);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (burnt && valid)
227*4882a593Smuzhiyun upper_key_used = 1;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (upper_key_used) {
230*4882a593Smuzhiyun if (burnt)
231*4882a593Smuzhiyun status = valid ? "Used" : "Wasted";
232*4882a593Smuzhiyun else
233*4882a593Smuzhiyun status = valid ? "Invalid" : "Skipped";
234*4882a593Smuzhiyun } else {
235*4882a593Smuzhiyun if (burnt)
236*4882a593Smuzhiyun status = valid ? "InUse" : "Incomplete";
237*4882a593Smuzhiyun else
238*4882a593Smuzhiyun status = valid ? "Invalid" : "Free";
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun buf_len += sprintf(buf + buf_len, "%d:%s ", key, status);
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun buf_len += sprintf(buf + buf_len, "\n");
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun return buf_len;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun static DEVICE_ATTR_RW(post_reset_wdog);
248*4882a593Smuzhiyun static DEVICE_ATTR_RW(reset_action);
249*4882a593Smuzhiyun static DEVICE_ATTR_RW(second_reset_action);
250*4882a593Smuzhiyun static DEVICE_ATTR_RO(lifecycle_state);
251*4882a593Smuzhiyun static DEVICE_ATTR_RO(secure_boot_fuse_state);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun static struct attribute *mlxbf_bootctl_attrs[] = {
254*4882a593Smuzhiyun &dev_attr_post_reset_wdog.attr,
255*4882a593Smuzhiyun &dev_attr_reset_action.attr,
256*4882a593Smuzhiyun &dev_attr_second_reset_action.attr,
257*4882a593Smuzhiyun &dev_attr_lifecycle_state.attr,
258*4882a593Smuzhiyun &dev_attr_secure_boot_fuse_state.attr,
259*4882a593Smuzhiyun NULL
260*4882a593Smuzhiyun };
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun ATTRIBUTE_GROUPS(mlxbf_bootctl);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = {
265*4882a593Smuzhiyun {"MLNXBF04", 0},
266*4882a593Smuzhiyun {}
267*4882a593Smuzhiyun };
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, mlxbf_bootctl_acpi_ids);
270*4882a593Smuzhiyun
mlxbf_bootctl_guid_match(const guid_t * guid,const struct arm_smccc_res * res)271*4882a593Smuzhiyun static bool mlxbf_bootctl_guid_match(const guid_t *guid,
272*4882a593Smuzhiyun const struct arm_smccc_res *res)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16,
275*4882a593Smuzhiyun res->a2, res->a2 >> 8, res->a2 >> 16,
276*4882a593Smuzhiyun res->a2 >> 24, res->a3, res->a3 >> 8,
277*4882a593Smuzhiyun res->a3 >> 16, res->a3 >> 24);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return guid_equal(guid, &id);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
mlxbf_bootctl_probe(struct platform_device * pdev)282*4882a593Smuzhiyun static int mlxbf_bootctl_probe(struct platform_device *pdev)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun struct arm_smccc_res res = { 0 };
285*4882a593Smuzhiyun guid_t guid;
286*4882a593Smuzhiyun int ret;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* Ensure we have the UUID we expect for this service. */
289*4882a593Smuzhiyun arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
290*4882a593Smuzhiyun guid_parse(mlxbf_bootctl_svc_uuid_str, &guid);
291*4882a593Smuzhiyun if (!mlxbf_bootctl_guid_match(&guid, &res))
292*4882a593Smuzhiyun return -ENODEV;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /*
295*4882a593Smuzhiyun * When watchdog is used, it sets boot mode to MLXBF_BOOTCTL_SWAP_EMMC
296*4882a593Smuzhiyun * in case of boot failures. However it doesn't clear the state if there
297*4882a593Smuzhiyun * is no failure. Restore the default boot mode here to avoid any
298*4882a593Smuzhiyun * unnecessary boot partition swapping.
299*4882a593Smuzhiyun */
300*4882a593Smuzhiyun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_RESET_ACTION,
301*4882a593Smuzhiyun MLXBF_BOOTCTL_EMMC);
302*4882a593Smuzhiyun if (ret < 0)
303*4882a593Smuzhiyun dev_warn(&pdev->dev, "Unable to reset the EMMC boot mode\n");
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun static struct platform_driver mlxbf_bootctl_driver = {
309*4882a593Smuzhiyun .probe = mlxbf_bootctl_probe,
310*4882a593Smuzhiyun .driver = {
311*4882a593Smuzhiyun .name = "mlxbf-bootctl",
312*4882a593Smuzhiyun .dev_groups = mlxbf_bootctl_groups,
313*4882a593Smuzhiyun .acpi_match_table = mlxbf_bootctl_acpi_ids,
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun };
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun module_platform_driver(mlxbf_bootctl_driver);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun MODULE_DESCRIPTION("Mellanox boot control driver");
320*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
321*4882a593Smuzhiyun MODULE_AUTHOR("Mellanox Technologies");
322