179e29cb8SLiming Sun // SPDX-License-Identifier: GPL-2.0+
279e29cb8SLiming Sun /*
379e29cb8SLiming Sun * Mellanox boot control driver
479e29cb8SLiming Sun *
579e29cb8SLiming Sun * This driver provides a sysfs interface for systems management
679e29cb8SLiming Sun * software to manage reset-time actions.
779e29cb8SLiming Sun *
879e29cb8SLiming Sun * Copyright (C) 2019 Mellanox Technologies
979e29cb8SLiming Sun */
1079e29cb8SLiming Sun
1179e29cb8SLiming Sun #include <linux/acpi.h>
1279e29cb8SLiming Sun #include <linux/arm-smccc.h>
1382c3a0b7SLiming Sun #include <linux/delay.h>
147e38a742SDavid Thompson #include <linux/if_ether.h>
15e9d1b2d0SLiming Sun #include <linux/iopoll.h>
1679e29cb8SLiming Sun #include <linux/module.h>
1779e29cb8SLiming Sun #include <linux/platform_device.h>
1879e29cb8SLiming Sun
1979e29cb8SLiming Sun #include "mlxbf-bootctl.h"
2079e29cb8SLiming Sun
2179e29cb8SLiming Sun #define MLXBF_BOOTCTL_SB_SECURE_MASK 0x03
2279e29cb8SLiming Sun #define MLXBF_BOOTCTL_SB_TEST_MASK 0x0c
23d4eef752SDavid Thompson #define MLXBF_BOOTCTL_SB_DEV_MASK BIT(4)
2479e29cb8SLiming Sun
2579e29cb8SLiming Sun #define MLXBF_SB_KEY_NUM 4
2679e29cb8SLiming Sun
2779e29cb8SLiming Sun /* UUID used to probe ATF service. */
2879e29cb8SLiming Sun static const char *mlxbf_bootctl_svc_uuid_str =
2979e29cb8SLiming Sun "89c036b4-e7d7-11e6-8797-001aca00bfc4";
3079e29cb8SLiming Sun
3179e29cb8SLiming Sun struct mlxbf_bootctl_name {
3279e29cb8SLiming Sun u32 value;
3379e29cb8SLiming Sun const char *name;
3479e29cb8SLiming Sun };
3579e29cb8SLiming Sun
3679e29cb8SLiming Sun static struct mlxbf_bootctl_name boot_names[] = {
3779e29cb8SLiming Sun { MLXBF_BOOTCTL_EXTERNAL, "external" },
3879e29cb8SLiming Sun { MLXBF_BOOTCTL_EMMC, "emmc" },
3979e29cb8SLiming Sun { MLNX_BOOTCTL_SWAP_EMMC, "swap_emmc" },
4079e29cb8SLiming Sun { MLXBF_BOOTCTL_EMMC_LEGACY, "emmc_legacy" },
4179e29cb8SLiming Sun { MLXBF_BOOTCTL_NONE, "none" },
4279e29cb8SLiming Sun };
4379e29cb8SLiming Sun
44d4eef752SDavid Thompson enum {
45d4eef752SDavid Thompson MLXBF_BOOTCTL_SB_LIFECYCLE_PRODUCTION = 0,
46d4eef752SDavid Thompson MLXBF_BOOTCTL_SB_LIFECYCLE_GA_SECURE = 1,
47d4eef752SDavid Thompson MLXBF_BOOTCTL_SB_LIFECYCLE_GA_NON_SECURE = 2,
48d4eef752SDavid Thompson MLXBF_BOOTCTL_SB_LIFECYCLE_RMA = 3
49d4eef752SDavid Thompson };
50d4eef752SDavid Thompson
5179e29cb8SLiming Sun static const char * const mlxbf_bootctl_lifecycle_states[] = {
52d4eef752SDavid Thompson [MLXBF_BOOTCTL_SB_LIFECYCLE_PRODUCTION] = "Production",
53d4eef752SDavid Thompson [MLXBF_BOOTCTL_SB_LIFECYCLE_GA_SECURE] = "GA Secured",
54d4eef752SDavid Thompson [MLXBF_BOOTCTL_SB_LIFECYCLE_GA_NON_SECURE] = "GA Non-Secured",
55d4eef752SDavid Thompson [MLXBF_BOOTCTL_SB_LIFECYCLE_RMA] = "RMA",
5679e29cb8SLiming Sun };
5779e29cb8SLiming Sun
58e9d1b2d0SLiming Sun /* Log header format. */
59e9d1b2d0SLiming Sun #define MLXBF_RSH_LOG_TYPE_MASK GENMASK_ULL(59, 56)
60e9d1b2d0SLiming Sun #define MLXBF_RSH_LOG_LEN_MASK GENMASK_ULL(54, 48)
61e9d1b2d0SLiming Sun #define MLXBF_RSH_LOG_LEVEL_MASK GENMASK_ULL(7, 0)
62e9d1b2d0SLiming Sun
63e9d1b2d0SLiming Sun /* Log module ID and type (only MSG type in Linux driver for now). */
64e9d1b2d0SLiming Sun #define MLXBF_RSH_LOG_TYPE_MSG 0x04ULL
65e9d1b2d0SLiming Sun
66e9d1b2d0SLiming Sun /* Log ctl/data register offset. */
67e9d1b2d0SLiming Sun #define MLXBF_RSH_SCRATCH_BUF_CTL_OFF 0
68e9d1b2d0SLiming Sun #define MLXBF_RSH_SCRATCH_BUF_DATA_OFF 0x10
69e9d1b2d0SLiming Sun
70e9d1b2d0SLiming Sun /* Log message levels. */
71e9d1b2d0SLiming Sun enum {
72e9d1b2d0SLiming Sun MLXBF_RSH_LOG_INFO,
73e9d1b2d0SLiming Sun MLXBF_RSH_LOG_WARN,
74e9d1b2d0SLiming Sun MLXBF_RSH_LOG_ERR,
75e9d1b2d0SLiming Sun MLXBF_RSH_LOG_ASSERT
76e9d1b2d0SLiming Sun };
77e9d1b2d0SLiming Sun
7882c3a0b7SLiming Sun /* Mapped pointer for RSH_BOOT_FIFO_DATA and RSH_BOOT_FIFO_COUNT register. */
7982c3a0b7SLiming Sun static void __iomem *mlxbf_rsh_boot_data;
8082c3a0b7SLiming Sun static void __iomem *mlxbf_rsh_boot_cnt;
8182c3a0b7SLiming Sun
82e9d1b2d0SLiming Sun /* Mapped pointer for rsh log semaphore/ctrl/data register. */
83e9d1b2d0SLiming Sun static void __iomem *mlxbf_rsh_semaphore;
84e9d1b2d0SLiming Sun static void __iomem *mlxbf_rsh_scratch_buf_ctl;
85e9d1b2d0SLiming Sun static void __iomem *mlxbf_rsh_scratch_buf_data;
86e9d1b2d0SLiming Sun
87e9d1b2d0SLiming Sun /* Rsh log levels. */
88e9d1b2d0SLiming Sun static const char * const mlxbf_rsh_log_level[] = {
89e9d1b2d0SLiming Sun "INFO", "WARN", "ERR", "ASSERT"};
90e9d1b2d0SLiming Sun
91b18a97edSAsmaa Mnebhi static DEFINE_MUTEX(icm_ops_lock);
92e3205d41SAsmaa Mnebhi static DEFINE_MUTEX(os_up_lock);
937e38a742SDavid Thompson static DEFINE_MUTEX(mfg_ops_lock);
947e38a742SDavid Thompson
957e38a742SDavid Thompson /*
967e38a742SDavid Thompson * Objects are stored within the MFG partition per type.
977e38a742SDavid Thompson * Type 0 is not supported.
987e38a742SDavid Thompson */
997e38a742SDavid Thompson enum {
1007e38a742SDavid Thompson MLNX_MFG_TYPE_OOB_MAC = 1,
1017e38a742SDavid Thompson MLNX_MFG_TYPE_OPN_0,
1027e38a742SDavid Thompson MLNX_MFG_TYPE_OPN_1,
1037e38a742SDavid Thompson MLNX_MFG_TYPE_OPN_2,
1047e38a742SDavid Thompson MLNX_MFG_TYPE_SKU_0,
1057e38a742SDavid Thompson MLNX_MFG_TYPE_SKU_1,
1067e38a742SDavid Thompson MLNX_MFG_TYPE_SKU_2,
1077e38a742SDavid Thompson MLNX_MFG_TYPE_MODL_0,
1087e38a742SDavid Thompson MLNX_MFG_TYPE_MODL_1,
1097e38a742SDavid Thompson MLNX_MFG_TYPE_MODL_2,
1107e38a742SDavid Thompson MLNX_MFG_TYPE_SN_0,
1117e38a742SDavid Thompson MLNX_MFG_TYPE_SN_1,
1127e38a742SDavid Thompson MLNX_MFG_TYPE_SN_2,
1137e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_0,
1147e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_1,
1157e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_2,
1167e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_3,
1177e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_4,
1187e38a742SDavid Thompson MLNX_MFG_TYPE_REV,
1197e38a742SDavid Thompson };
1207e38a742SDavid Thompson
1217e38a742SDavid Thompson #define MLNX_MFG_OPN_VAL_LEN 24
1227e38a742SDavid Thompson #define MLNX_MFG_SKU_VAL_LEN 24
1237e38a742SDavid Thompson #define MLNX_MFG_MODL_VAL_LEN 24
1247e38a742SDavid Thompson #define MLNX_MFG_SN_VAL_LEN 24
1257e38a742SDavid Thompson #define MLNX_MFG_UUID_VAL_LEN 40
1267e38a742SDavid Thompson #define MLNX_MFG_REV_VAL_LEN 8
1277e38a742SDavid Thompson #define MLNX_MFG_VAL_QWORD_CNT(type) \
1287e38a742SDavid Thompson (MLNX_MFG_##type##_VAL_LEN / sizeof(u64))
1297e38a742SDavid Thompson
1307e38a742SDavid Thompson /*
1317e38a742SDavid Thompson * The MAC address consists of 6 bytes (2 digits each) separated by ':'.
1327e38a742SDavid Thompson * The expected format is: "XX:XX:XX:XX:XX:XX"
1337e38a742SDavid Thompson */
1347e38a742SDavid Thompson #define MLNX_MFG_OOB_MAC_FORMAT_LEN \
1357e38a742SDavid Thompson ((ETH_ALEN * 2) + (ETH_ALEN - 1))
136b18a97edSAsmaa Mnebhi
13779e29cb8SLiming Sun /* ARM SMC call which is atomic and no need for lock. */
mlxbf_bootctl_smc(unsigned int smc_op,int smc_arg)13879e29cb8SLiming Sun static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg)
13979e29cb8SLiming Sun {
14079e29cb8SLiming Sun struct arm_smccc_res res;
14179e29cb8SLiming Sun
14279e29cb8SLiming Sun arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res);
14379e29cb8SLiming Sun
14479e29cb8SLiming Sun return res.a0;
14579e29cb8SLiming Sun }
14679e29cb8SLiming Sun
14779e29cb8SLiming Sun /* Return the action in integer or an error code. */
mlxbf_bootctl_reset_action_to_val(const char * action)14879e29cb8SLiming Sun static int mlxbf_bootctl_reset_action_to_val(const char *action)
14979e29cb8SLiming Sun {
15079e29cb8SLiming Sun int i;
15179e29cb8SLiming Sun
15279e29cb8SLiming Sun for (i = 0; i < ARRAY_SIZE(boot_names); i++)
15379e29cb8SLiming Sun if (sysfs_streq(boot_names[i].name, action))
15479e29cb8SLiming Sun return boot_names[i].value;
15579e29cb8SLiming Sun
15679e29cb8SLiming Sun return -EINVAL;
15779e29cb8SLiming Sun }
15879e29cb8SLiming Sun
15979e29cb8SLiming Sun /* Return the action in string. */
mlxbf_bootctl_action_to_string(int action)16079e29cb8SLiming Sun static const char *mlxbf_bootctl_action_to_string(int action)
16179e29cb8SLiming Sun {
16279e29cb8SLiming Sun int i;
16379e29cb8SLiming Sun
16479e29cb8SLiming Sun for (i = 0; i < ARRAY_SIZE(boot_names); i++)
16579e29cb8SLiming Sun if (boot_names[i].value == action)
16679e29cb8SLiming Sun return boot_names[i].name;
16779e29cb8SLiming Sun
16879e29cb8SLiming Sun return "invalid action";
16979e29cb8SLiming Sun }
17079e29cb8SLiming Sun
post_reset_wdog_show(struct device * dev,struct device_attribute * attr,char * buf)17179e29cb8SLiming Sun static ssize_t post_reset_wdog_show(struct device *dev,
17279e29cb8SLiming Sun struct device_attribute *attr, char *buf)
17379e29cb8SLiming Sun {
17479e29cb8SLiming Sun int ret;
17579e29cb8SLiming Sun
17679e29cb8SLiming Sun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_POST_RESET_WDOG, 0);
17779e29cb8SLiming Sun if (ret < 0)
17879e29cb8SLiming Sun return ret;
17979e29cb8SLiming Sun
18079e29cb8SLiming Sun return sprintf(buf, "%d\n", ret);
18179e29cb8SLiming Sun }
18279e29cb8SLiming Sun
post_reset_wdog_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)18379e29cb8SLiming Sun static ssize_t post_reset_wdog_store(struct device *dev,
18479e29cb8SLiming Sun struct device_attribute *attr,
18579e29cb8SLiming Sun const char *buf, size_t count)
18679e29cb8SLiming Sun {
18779e29cb8SLiming Sun unsigned long value;
18879e29cb8SLiming Sun int ret;
18979e29cb8SLiming Sun
19079e29cb8SLiming Sun ret = kstrtoul(buf, 10, &value);
19179e29cb8SLiming Sun if (ret)
19279e29cb8SLiming Sun return ret;
19379e29cb8SLiming Sun
19479e29cb8SLiming Sun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_POST_RESET_WDOG, value);
19579e29cb8SLiming Sun if (ret < 0)
19679e29cb8SLiming Sun return ret;
19779e29cb8SLiming Sun
19879e29cb8SLiming Sun return count;
19979e29cb8SLiming Sun }
20079e29cb8SLiming Sun
mlxbf_bootctl_show(int smc_op,char * buf)20179e29cb8SLiming Sun static ssize_t mlxbf_bootctl_show(int smc_op, char *buf)
20279e29cb8SLiming Sun {
20379e29cb8SLiming Sun int action;
20479e29cb8SLiming Sun
20579e29cb8SLiming Sun action = mlxbf_bootctl_smc(smc_op, 0);
20679e29cb8SLiming Sun if (action < 0)
20779e29cb8SLiming Sun return action;
20879e29cb8SLiming Sun
20979e29cb8SLiming Sun return sprintf(buf, "%s\n", mlxbf_bootctl_action_to_string(action));
21079e29cb8SLiming Sun }
21179e29cb8SLiming Sun
mlxbf_bootctl_store(int smc_op,const char * buf,size_t count)21279e29cb8SLiming Sun static int mlxbf_bootctl_store(int smc_op, const char *buf, size_t count)
21379e29cb8SLiming Sun {
21479e29cb8SLiming Sun int ret, action;
21579e29cb8SLiming Sun
21679e29cb8SLiming Sun action = mlxbf_bootctl_reset_action_to_val(buf);
21779e29cb8SLiming Sun if (action < 0)
21879e29cb8SLiming Sun return action;
21979e29cb8SLiming Sun
22079e29cb8SLiming Sun ret = mlxbf_bootctl_smc(smc_op, action);
22179e29cb8SLiming Sun if (ret < 0)
22279e29cb8SLiming Sun return ret;
22379e29cb8SLiming Sun
22479e29cb8SLiming Sun return count;
22579e29cb8SLiming Sun }
22679e29cb8SLiming Sun
reset_action_show(struct device * dev,struct device_attribute * attr,char * buf)22779e29cb8SLiming Sun static ssize_t reset_action_show(struct device *dev,
22879e29cb8SLiming Sun struct device_attribute *attr, char *buf)
22979e29cb8SLiming Sun {
23079e29cb8SLiming Sun return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_RESET_ACTION, buf);
23179e29cb8SLiming Sun }
23279e29cb8SLiming Sun
reset_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)23379e29cb8SLiming Sun static ssize_t reset_action_store(struct device *dev,
23479e29cb8SLiming Sun struct device_attribute *attr,
23579e29cb8SLiming Sun const char *buf, size_t count)
23679e29cb8SLiming Sun {
23779e29cb8SLiming Sun return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_RESET_ACTION, buf, count);
23879e29cb8SLiming Sun }
23979e29cb8SLiming Sun
second_reset_action_show(struct device * dev,struct device_attribute * attr,char * buf)24079e29cb8SLiming Sun static ssize_t second_reset_action_show(struct device *dev,
24179e29cb8SLiming Sun struct device_attribute *attr,
24279e29cb8SLiming Sun char *buf)
24379e29cb8SLiming Sun {
24479e29cb8SLiming Sun return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION, buf);
24579e29cb8SLiming Sun }
24679e29cb8SLiming Sun
second_reset_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)24779e29cb8SLiming Sun static ssize_t second_reset_action_store(struct device *dev,
24879e29cb8SLiming Sun struct device_attribute *attr,
24979e29cb8SLiming Sun const char *buf, size_t count)
25079e29cb8SLiming Sun {
25179e29cb8SLiming Sun return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION, buf,
25279e29cb8SLiming Sun count);
25379e29cb8SLiming Sun }
25479e29cb8SLiming Sun
lifecycle_state_show(struct device * dev,struct device_attribute * attr,char * buf)25579e29cb8SLiming Sun static ssize_t lifecycle_state_show(struct device *dev,
25679e29cb8SLiming Sun struct device_attribute *attr, char *buf)
25779e29cb8SLiming Sun {
258d4eef752SDavid Thompson int status_bits;
259d4eef752SDavid Thompson int use_dev_key;
260d4eef752SDavid Thompson int test_state;
26179e29cb8SLiming Sun int lc_state;
26279e29cb8SLiming Sun
263d4eef752SDavid Thompson status_bits = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
26479e29cb8SLiming Sun MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE);
265d4eef752SDavid Thompson if (status_bits < 0)
266d4eef752SDavid Thompson return status_bits;
26779e29cb8SLiming Sun
268d4eef752SDavid Thompson use_dev_key = status_bits & MLXBF_BOOTCTL_SB_DEV_MASK;
269d4eef752SDavid Thompson test_state = status_bits & MLXBF_BOOTCTL_SB_TEST_MASK;
270d4eef752SDavid Thompson lc_state = status_bits & MLXBF_BOOTCTL_SB_SECURE_MASK;
27179e29cb8SLiming Sun
27279e29cb8SLiming Sun /*
27379e29cb8SLiming Sun * If the test bits are set, we specify that the current state may be
27479e29cb8SLiming Sun * due to using the test bits.
27579e29cb8SLiming Sun */
276d4eef752SDavid Thompson if (test_state) {
27779e29cb8SLiming Sun return sprintf(buf, "%s(test)\n",
27879e29cb8SLiming Sun mlxbf_bootctl_lifecycle_states[lc_state]);
279d4eef752SDavid Thompson } else if (use_dev_key &&
280d4eef752SDavid Thompson (lc_state == MLXBF_BOOTCTL_SB_LIFECYCLE_GA_SECURE)) {
281d4eef752SDavid Thompson return sprintf(buf, "Secured (development)\n");
28279e29cb8SLiming Sun }
28379e29cb8SLiming Sun
28479e29cb8SLiming Sun return sprintf(buf, "%s\n", mlxbf_bootctl_lifecycle_states[lc_state]);
28579e29cb8SLiming Sun }
28679e29cb8SLiming Sun
secure_boot_fuse_state_show(struct device * dev,struct device_attribute * attr,char * buf)28779e29cb8SLiming Sun static ssize_t secure_boot_fuse_state_show(struct device *dev,
28879e29cb8SLiming Sun struct device_attribute *attr,
28979e29cb8SLiming Sun char *buf)
29079e29cb8SLiming Sun {
29179e29cb8SLiming Sun int burnt, valid, key, key_state, buf_len = 0, upper_key_used = 0;
29279e29cb8SLiming Sun const char *status;
29379e29cb8SLiming Sun
29479e29cb8SLiming Sun key_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
29579e29cb8SLiming Sun MLXBF_BOOTCTL_FUSE_STATUS_KEYS);
29679e29cb8SLiming Sun if (key_state < 0)
29779e29cb8SLiming Sun return key_state;
29879e29cb8SLiming Sun
29979e29cb8SLiming Sun /*
30079e29cb8SLiming Sun * key_state contains the bits for 4 Key versions, loaded from eFuses
30179e29cb8SLiming Sun * after a hard reset. Lower 4 bits are a thermometer code indicating
30279e29cb8SLiming Sun * key programming has started for key n (0000 = none, 0001 = version 0,
30379e29cb8SLiming Sun * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits
30479e29cb8SLiming Sun * are a thermometer code indicating key programming has completed for
30579e29cb8SLiming Sun * key n (same encodings as the start bits). This allows for detection
30604cdaf6dSBhaskar Chowdhury * of an interruption in the programming process which has left the key
30779e29cb8SLiming Sun * partially programmed (and thus invalid). The process is to burn the
30879e29cb8SLiming Sun * eFuse for the new key start bit, burn the key eFuses, then burn the
30979e29cb8SLiming Sun * eFuse for the new key complete bit.
31079e29cb8SLiming Sun *
31179e29cb8SLiming Sun * For example 0000_0000: no key valid, 0001_0001: key version 0 valid,
31279e29cb8SLiming Sun * 0011_0011: key 1 version valid, 0011_0111: key version 2 started
31379e29cb8SLiming Sun * programming but did not complete, etc. The most recent key for which
31479e29cb8SLiming Sun * both start and complete bit is set is loaded. On soft reset, this
31579e29cb8SLiming Sun * register is not modified.
31679e29cb8SLiming Sun */
31779e29cb8SLiming Sun for (key = MLXBF_SB_KEY_NUM - 1; key >= 0; key--) {
31879e29cb8SLiming Sun burnt = key_state & BIT(key);
31979e29cb8SLiming Sun valid = key_state & BIT(key + MLXBF_SB_KEY_NUM);
32079e29cb8SLiming Sun
32179e29cb8SLiming Sun if (burnt && valid)
32279e29cb8SLiming Sun upper_key_used = 1;
32379e29cb8SLiming Sun
32479e29cb8SLiming Sun if (upper_key_used) {
32579e29cb8SLiming Sun if (burnt)
32679e29cb8SLiming Sun status = valid ? "Used" : "Wasted";
32779e29cb8SLiming Sun else
32879e29cb8SLiming Sun status = valid ? "Invalid" : "Skipped";
32979e29cb8SLiming Sun } else {
33079e29cb8SLiming Sun if (burnt)
33179e29cb8SLiming Sun status = valid ? "InUse" : "Incomplete";
33279e29cb8SLiming Sun else
33379e29cb8SLiming Sun status = valid ? "Invalid" : "Free";
33479e29cb8SLiming Sun }
33579e29cb8SLiming Sun buf_len += sprintf(buf + buf_len, "%d:%s ", key, status);
33679e29cb8SLiming Sun }
33779e29cb8SLiming Sun buf_len += sprintf(buf + buf_len, "\n");
33879e29cb8SLiming Sun
33979e29cb8SLiming Sun return buf_len;
34079e29cb8SLiming Sun }
34179e29cb8SLiming Sun
fw_reset_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3427bef7eeaSKhalil Blaiech static ssize_t fw_reset_store(struct device *dev,
3437bef7eeaSKhalil Blaiech struct device_attribute *attr,
3447bef7eeaSKhalil Blaiech const char *buf, size_t count)
3457bef7eeaSKhalil Blaiech {
3467bef7eeaSKhalil Blaiech unsigned long key;
3477bef7eeaSKhalil Blaiech int err;
3487bef7eeaSKhalil Blaiech
3497bef7eeaSKhalil Blaiech err = kstrtoul(buf, 16, &key);
3507bef7eeaSKhalil Blaiech if (err)
3517bef7eeaSKhalil Blaiech return err;
3527bef7eeaSKhalil Blaiech
3537bef7eeaSKhalil Blaiech if (mlxbf_bootctl_smc(MLXBF_BOOTCTL_FW_RESET, key) < 0)
3547bef7eeaSKhalil Blaiech return -EINVAL;
3557bef7eeaSKhalil Blaiech
3567bef7eeaSKhalil Blaiech return count;
3577bef7eeaSKhalil Blaiech }
3587bef7eeaSKhalil Blaiech
359e9d1b2d0SLiming Sun /* Size(8-byte words) of the log buffer. */
360e9d1b2d0SLiming Sun #define RSH_SCRATCH_BUF_CTL_IDX_MASK 0x7f
361e9d1b2d0SLiming Sun
362e9d1b2d0SLiming Sun /* 100ms timeout */
363e9d1b2d0SLiming Sun #define RSH_SCRATCH_BUF_POLL_TIMEOUT 100000
364e9d1b2d0SLiming Sun
mlxbf_rsh_log_sem_lock(void)365e9d1b2d0SLiming Sun static int mlxbf_rsh_log_sem_lock(void)
366e9d1b2d0SLiming Sun {
367e9d1b2d0SLiming Sun unsigned long reg;
368e9d1b2d0SLiming Sun
369e9d1b2d0SLiming Sun return readq_poll_timeout(mlxbf_rsh_semaphore, reg, !reg, 0,
370e9d1b2d0SLiming Sun RSH_SCRATCH_BUF_POLL_TIMEOUT);
371e9d1b2d0SLiming Sun }
372e9d1b2d0SLiming Sun
mlxbf_rsh_log_sem_unlock(void)373e9d1b2d0SLiming Sun static void mlxbf_rsh_log_sem_unlock(void)
374e9d1b2d0SLiming Sun {
375e9d1b2d0SLiming Sun writeq(0, mlxbf_rsh_semaphore);
376e9d1b2d0SLiming Sun }
377e9d1b2d0SLiming Sun
rsh_log_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)378e9d1b2d0SLiming Sun static ssize_t rsh_log_store(struct device *dev,
379e9d1b2d0SLiming Sun struct device_attribute *attr,
380e9d1b2d0SLiming Sun const char *buf, size_t count)
381e9d1b2d0SLiming Sun {
382e9d1b2d0SLiming Sun int rc, idx, num, len, level = MLXBF_RSH_LOG_INFO;
383e9d1b2d0SLiming Sun size_t size = count;
384e9d1b2d0SLiming Sun u64 data;
385e9d1b2d0SLiming Sun
386e9d1b2d0SLiming Sun if (!size)
387e9d1b2d0SLiming Sun return -EINVAL;
388e9d1b2d0SLiming Sun
389e9d1b2d0SLiming Sun if (!mlxbf_rsh_semaphore || !mlxbf_rsh_scratch_buf_ctl)
390e9d1b2d0SLiming Sun return -EOPNOTSUPP;
391e9d1b2d0SLiming Sun
392e9d1b2d0SLiming Sun /* Ignore line break at the end. */
393e9d1b2d0SLiming Sun if (buf[size - 1] == '\n')
394e9d1b2d0SLiming Sun size--;
395e9d1b2d0SLiming Sun
396e9d1b2d0SLiming Sun /* Check the message prefix. */
397e9d1b2d0SLiming Sun for (idx = 0; idx < ARRAY_SIZE(mlxbf_rsh_log_level); idx++) {
398e9d1b2d0SLiming Sun len = strlen(mlxbf_rsh_log_level[idx]);
399e9d1b2d0SLiming Sun if (len + 1 < size &&
400e9d1b2d0SLiming Sun !strncmp(buf, mlxbf_rsh_log_level[idx], len)) {
401e9d1b2d0SLiming Sun buf += len;
402e9d1b2d0SLiming Sun size -= len;
403e9d1b2d0SLiming Sun level = idx;
404e9d1b2d0SLiming Sun break;
405e9d1b2d0SLiming Sun }
406e9d1b2d0SLiming Sun }
407e9d1b2d0SLiming Sun
408e9d1b2d0SLiming Sun /* Ignore leading spaces. */
409e9d1b2d0SLiming Sun while (size > 0 && buf[0] == ' ') {
410e9d1b2d0SLiming Sun size--;
411e9d1b2d0SLiming Sun buf++;
412e9d1b2d0SLiming Sun }
413e9d1b2d0SLiming Sun
414e9d1b2d0SLiming Sun /* Take the semaphore. */
415e9d1b2d0SLiming Sun rc = mlxbf_rsh_log_sem_lock();
416e9d1b2d0SLiming Sun if (rc)
417e9d1b2d0SLiming Sun return rc;
418e9d1b2d0SLiming Sun
419e9d1b2d0SLiming Sun /* Calculate how many words are available. */
420e9d1b2d0SLiming Sun idx = readq(mlxbf_rsh_scratch_buf_ctl);
421e9d1b2d0SLiming Sun num = min((int)DIV_ROUND_UP(size, sizeof(u64)),
422e9d1b2d0SLiming Sun RSH_SCRATCH_BUF_CTL_IDX_MASK - idx - 1);
423e9d1b2d0SLiming Sun if (num <= 0)
424e9d1b2d0SLiming Sun goto done;
425e9d1b2d0SLiming Sun
426e9d1b2d0SLiming Sun /* Write Header. */
427e9d1b2d0SLiming Sun data = FIELD_PREP(MLXBF_RSH_LOG_TYPE_MASK, MLXBF_RSH_LOG_TYPE_MSG);
428e9d1b2d0SLiming Sun data |= FIELD_PREP(MLXBF_RSH_LOG_LEN_MASK, num);
429e9d1b2d0SLiming Sun data |= FIELD_PREP(MLXBF_RSH_LOG_LEVEL_MASK, level);
430e9d1b2d0SLiming Sun writeq(data, mlxbf_rsh_scratch_buf_data);
431e9d1b2d0SLiming Sun
432e9d1b2d0SLiming Sun /* Write message. */
433e9d1b2d0SLiming Sun for (idx = 0; idx < num && size > 0; idx++) {
434e9d1b2d0SLiming Sun if (size < sizeof(u64)) {
435e9d1b2d0SLiming Sun data = 0;
436e9d1b2d0SLiming Sun memcpy(&data, buf, size);
437e9d1b2d0SLiming Sun size = 0;
438e9d1b2d0SLiming Sun } else {
439e9d1b2d0SLiming Sun memcpy(&data, buf, sizeof(u64));
440e9d1b2d0SLiming Sun size -= sizeof(u64);
441e9d1b2d0SLiming Sun buf += sizeof(u64);
442e9d1b2d0SLiming Sun }
443e9d1b2d0SLiming Sun writeq(data, mlxbf_rsh_scratch_buf_data);
444e9d1b2d0SLiming Sun }
445e9d1b2d0SLiming Sun
446e9d1b2d0SLiming Sun done:
447e9d1b2d0SLiming Sun /* Release the semaphore. */
448e9d1b2d0SLiming Sun mlxbf_rsh_log_sem_unlock();
449e9d1b2d0SLiming Sun
450e9d1b2d0SLiming Sun /* Ignore the rest if no more space. */
451e9d1b2d0SLiming Sun return count;
452e9d1b2d0SLiming Sun }
453e9d1b2d0SLiming Sun
large_icm_show(struct device * dev,struct device_attribute * attr,char * buf)454b18a97edSAsmaa Mnebhi static ssize_t large_icm_show(struct device *dev,
455b18a97edSAsmaa Mnebhi struct device_attribute *attr, char *buf)
456b18a97edSAsmaa Mnebhi {
457b18a97edSAsmaa Mnebhi struct arm_smccc_res res;
458b18a97edSAsmaa Mnebhi
459b18a97edSAsmaa Mnebhi mutex_lock(&icm_ops_lock);
460b18a97edSAsmaa Mnebhi arm_smccc_smc(MLNX_HANDLE_GET_ICM_INFO, 0, 0, 0, 0,
461b18a97edSAsmaa Mnebhi 0, 0, 0, &res);
462b18a97edSAsmaa Mnebhi mutex_unlock(&icm_ops_lock);
463b18a97edSAsmaa Mnebhi if (res.a0)
464b18a97edSAsmaa Mnebhi return -EPERM;
465b18a97edSAsmaa Mnebhi
466*e5afa3d7SLi Zhijian return sysfs_emit(buf, "0x%lx", res.a1);
467b18a97edSAsmaa Mnebhi }
468b18a97edSAsmaa Mnebhi
large_icm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)469b18a97edSAsmaa Mnebhi static ssize_t large_icm_store(struct device *dev,
470b18a97edSAsmaa Mnebhi struct device_attribute *attr,
471b18a97edSAsmaa Mnebhi const char *buf, size_t count)
472b18a97edSAsmaa Mnebhi {
473b18a97edSAsmaa Mnebhi struct arm_smccc_res res;
474b18a97edSAsmaa Mnebhi unsigned long icm_data;
475b18a97edSAsmaa Mnebhi int err;
476b18a97edSAsmaa Mnebhi
477b18a97edSAsmaa Mnebhi err = kstrtoul(buf, MLXBF_LARGE_ICMC_MAX_STRING_SIZE, &icm_data);
478b18a97edSAsmaa Mnebhi if (err)
479b18a97edSAsmaa Mnebhi return err;
480b18a97edSAsmaa Mnebhi
481b18a97edSAsmaa Mnebhi if ((icm_data != 0 && icm_data < MLXBF_LARGE_ICMC_SIZE_MIN) ||
482b18a97edSAsmaa Mnebhi icm_data > MLXBF_LARGE_ICMC_SIZE_MAX || icm_data % MLXBF_LARGE_ICMC_GRANULARITY)
483b18a97edSAsmaa Mnebhi return -EPERM;
484b18a97edSAsmaa Mnebhi
485b18a97edSAsmaa Mnebhi mutex_lock(&icm_ops_lock);
486b18a97edSAsmaa Mnebhi arm_smccc_smc(MLNX_HANDLE_SET_ICM_INFO, icm_data, 0, 0, 0, 0, 0, 0, &res);
487b18a97edSAsmaa Mnebhi mutex_unlock(&icm_ops_lock);
488b18a97edSAsmaa Mnebhi
489b18a97edSAsmaa Mnebhi return res.a0 ? -EPERM : count;
490b18a97edSAsmaa Mnebhi }
491b18a97edSAsmaa Mnebhi
os_up_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)492e3205d41SAsmaa Mnebhi static ssize_t os_up_store(struct device *dev,
493e3205d41SAsmaa Mnebhi struct device_attribute *attr,
494e3205d41SAsmaa Mnebhi const char *buf, size_t count)
495e3205d41SAsmaa Mnebhi {
496e3205d41SAsmaa Mnebhi struct arm_smccc_res res;
497e3205d41SAsmaa Mnebhi unsigned long val;
498e3205d41SAsmaa Mnebhi int err;
499e3205d41SAsmaa Mnebhi
500e3205d41SAsmaa Mnebhi err = kstrtoul(buf, 10, &val);
501e3205d41SAsmaa Mnebhi if (err)
502e3205d41SAsmaa Mnebhi return err;
503e3205d41SAsmaa Mnebhi
504e3205d41SAsmaa Mnebhi if (val != 1)
505e3205d41SAsmaa Mnebhi return -EINVAL;
506e3205d41SAsmaa Mnebhi
507e3205d41SAsmaa Mnebhi mutex_lock(&os_up_lock);
508e3205d41SAsmaa Mnebhi arm_smccc_smc(MLNX_HANDLE_OS_UP, 0, 0, 0, 0, 0, 0, 0, &res);
509e3205d41SAsmaa Mnebhi mutex_unlock(&os_up_lock);
510e3205d41SAsmaa Mnebhi
511e3205d41SAsmaa Mnebhi return count;
512e3205d41SAsmaa Mnebhi }
513e3205d41SAsmaa Mnebhi
oob_mac_show(struct device * dev,struct device_attribute * attr,char * buf)5147e38a742SDavid Thompson static ssize_t oob_mac_show(struct device *dev,
5157e38a742SDavid Thompson struct device_attribute *attr, char *buf)
5167e38a742SDavid Thompson {
5177e38a742SDavid Thompson struct arm_smccc_res res;
5187e38a742SDavid Thompson u8 *mac_byte_ptr;
5197e38a742SDavid Thompson
5207e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
5217e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO, MLNX_MFG_TYPE_OOB_MAC, 0, 0, 0,
5227e38a742SDavid Thompson 0, 0, 0, &res);
5237e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
5247e38a742SDavid Thompson if (res.a0)
5257e38a742SDavid Thompson return -EPERM;
5267e38a742SDavid Thompson
5277e38a742SDavid Thompson mac_byte_ptr = (u8 *)&res.a1;
5287e38a742SDavid Thompson
5297e38a742SDavid Thompson return sysfs_format_mac(buf, mac_byte_ptr, ETH_ALEN);
5307e38a742SDavid Thompson }
5317e38a742SDavid Thompson
oob_mac_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5327e38a742SDavid Thompson static ssize_t oob_mac_store(struct device *dev,
5337e38a742SDavid Thompson struct device_attribute *attr,
5347e38a742SDavid Thompson const char *buf, size_t count)
5357e38a742SDavid Thompson {
5367e38a742SDavid Thompson unsigned int byte[MLNX_MFG_OOB_MAC_FORMAT_LEN] = { 0 };
5377e38a742SDavid Thompson struct arm_smccc_res res;
5387e38a742SDavid Thompson int byte_idx, len;
5397e38a742SDavid Thompson u64 mac_addr = 0;
5407e38a742SDavid Thompson u8 *mac_byte_ptr;
5417e38a742SDavid Thompson
5427e38a742SDavid Thompson if ((count - 1) != MLNX_MFG_OOB_MAC_FORMAT_LEN)
5437e38a742SDavid Thompson return -EINVAL;
5447e38a742SDavid Thompson
5457e38a742SDavid Thompson len = sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
5467e38a742SDavid Thompson &byte[0], &byte[1], &byte[2],
5477e38a742SDavid Thompson &byte[3], &byte[4], &byte[5]);
5487e38a742SDavid Thompson if (len != ETH_ALEN)
5497e38a742SDavid Thompson return -EINVAL;
5507e38a742SDavid Thompson
5517e38a742SDavid Thompson mac_byte_ptr = (u8 *)&mac_addr;
5527e38a742SDavid Thompson
5537e38a742SDavid Thompson for (byte_idx = 0; byte_idx < ETH_ALEN; byte_idx++)
5547e38a742SDavid Thompson mac_byte_ptr[byte_idx] = (u8)byte[byte_idx];
5557e38a742SDavid Thompson
5567e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
5577e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO, MLNX_MFG_TYPE_OOB_MAC,
5587e38a742SDavid Thompson ETH_ALEN, mac_addr, 0, 0, 0, 0, &res);
5597e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
5607e38a742SDavid Thompson
5617e38a742SDavid Thompson return res.a0 ? -EPERM : count;
5627e38a742SDavid Thompson }
5637e38a742SDavid Thompson
opn_show(struct device * dev,struct device_attribute * attr,char * buf)5647e38a742SDavid Thompson static ssize_t opn_show(struct device *dev,
5657e38a742SDavid Thompson struct device_attribute *attr, char *buf)
5667e38a742SDavid Thompson {
5677e38a742SDavid Thompson u64 opn_data[MLNX_MFG_VAL_QWORD_CNT(OPN) + 1] = { 0 };
5687e38a742SDavid Thompson struct arm_smccc_res res;
5697e38a742SDavid Thompson int word;
5707e38a742SDavid Thompson
5717e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
5727e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(OPN); word++) {
5737e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
5747e38a742SDavid Thompson MLNX_MFG_TYPE_OPN_0 + word,
5757e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
5767e38a742SDavid Thompson if (res.a0) {
5777e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
5787e38a742SDavid Thompson return -EPERM;
5797e38a742SDavid Thompson }
5807e38a742SDavid Thompson opn_data[word] = res.a1;
5817e38a742SDavid Thompson }
5827e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
5837e38a742SDavid Thompson
584*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)opn_data);
5857e38a742SDavid Thompson }
5867e38a742SDavid Thompson
opn_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5877e38a742SDavid Thompson static ssize_t opn_store(struct device *dev,
5887e38a742SDavid Thompson struct device_attribute *attr,
5897e38a742SDavid Thompson const char *buf, size_t count)
5907e38a742SDavid Thompson {
5917e38a742SDavid Thompson u64 opn[MLNX_MFG_VAL_QWORD_CNT(OPN)] = { 0 };
5927e38a742SDavid Thompson struct arm_smccc_res res;
5937e38a742SDavid Thompson int word;
5947e38a742SDavid Thompson
5957e38a742SDavid Thompson if (count > MLNX_MFG_OPN_VAL_LEN)
5967e38a742SDavid Thompson return -EINVAL;
5977e38a742SDavid Thompson
5987e38a742SDavid Thompson memcpy(opn, buf, count);
5997e38a742SDavid Thompson
6007e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
6017e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(OPN); word++) {
6027e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
6037e38a742SDavid Thompson MLNX_MFG_TYPE_OPN_0 + word,
6047e38a742SDavid Thompson sizeof(u64), opn[word], 0, 0, 0, 0, &res);
6057e38a742SDavid Thompson if (res.a0) {
6067e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6077e38a742SDavid Thompson return -EPERM;
6087e38a742SDavid Thompson }
6097e38a742SDavid Thompson }
6107e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6117e38a742SDavid Thompson
6127e38a742SDavid Thompson return count;
6137e38a742SDavid Thompson }
6147e38a742SDavid Thompson
sku_show(struct device * dev,struct device_attribute * attr,char * buf)6157e38a742SDavid Thompson static ssize_t sku_show(struct device *dev,
6167e38a742SDavid Thompson struct device_attribute *attr, char *buf)
6177e38a742SDavid Thompson {
6187e38a742SDavid Thompson u64 sku_data[MLNX_MFG_VAL_QWORD_CNT(SKU) + 1] = { 0 };
6197e38a742SDavid Thompson struct arm_smccc_res res;
6207e38a742SDavid Thompson int word;
6217e38a742SDavid Thompson
6227e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
6237e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SKU); word++) {
6247e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
6257e38a742SDavid Thompson MLNX_MFG_TYPE_SKU_0 + word,
6267e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
6277e38a742SDavid Thompson if (res.a0) {
6287e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6297e38a742SDavid Thompson return -EPERM;
6307e38a742SDavid Thompson }
6317e38a742SDavid Thompson sku_data[word] = res.a1;
6327e38a742SDavid Thompson }
6337e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6347e38a742SDavid Thompson
635*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)sku_data);
6367e38a742SDavid Thompson }
6377e38a742SDavid Thompson
sku_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)6387e38a742SDavid Thompson static ssize_t sku_store(struct device *dev,
6397e38a742SDavid Thompson struct device_attribute *attr,
6407e38a742SDavid Thompson const char *buf, size_t count)
6417e38a742SDavid Thompson {
6427e38a742SDavid Thompson u64 sku[MLNX_MFG_VAL_QWORD_CNT(SKU)] = { 0 };
6437e38a742SDavid Thompson struct arm_smccc_res res;
6447e38a742SDavid Thompson int word;
6457e38a742SDavid Thompson
6467e38a742SDavid Thompson if (count > MLNX_MFG_SKU_VAL_LEN)
6477e38a742SDavid Thompson return -EINVAL;
6487e38a742SDavid Thompson
6497e38a742SDavid Thompson memcpy(sku, buf, count);
6507e38a742SDavid Thompson
6517e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
6527e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SKU); word++) {
6537e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
6547e38a742SDavid Thompson MLNX_MFG_TYPE_SKU_0 + word,
6557e38a742SDavid Thompson sizeof(u64), sku[word], 0, 0, 0, 0, &res);
6567e38a742SDavid Thompson if (res.a0) {
6577e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6587e38a742SDavid Thompson return -EPERM;
6597e38a742SDavid Thompson }
6607e38a742SDavid Thompson }
6617e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6627e38a742SDavid Thompson
6637e38a742SDavid Thompson return count;
6647e38a742SDavid Thompson }
6657e38a742SDavid Thompson
modl_show(struct device * dev,struct device_attribute * attr,char * buf)6667e38a742SDavid Thompson static ssize_t modl_show(struct device *dev,
6677e38a742SDavid Thompson struct device_attribute *attr, char *buf)
6687e38a742SDavid Thompson {
6697e38a742SDavid Thompson u64 modl_data[MLNX_MFG_VAL_QWORD_CNT(MODL) + 1] = { 0 };
6707e38a742SDavid Thompson struct arm_smccc_res res;
6717e38a742SDavid Thompson int word;
6727e38a742SDavid Thompson
6737e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
6747e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(MODL); word++) {
6757e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
6767e38a742SDavid Thompson MLNX_MFG_TYPE_MODL_0 + word,
6777e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
6787e38a742SDavid Thompson if (res.a0) {
6797e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6807e38a742SDavid Thompson return -EPERM;
6817e38a742SDavid Thompson }
6827e38a742SDavid Thompson modl_data[word] = res.a1;
6837e38a742SDavid Thompson }
6847e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
6857e38a742SDavid Thompson
686*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)modl_data);
6877e38a742SDavid Thompson }
6887e38a742SDavid Thompson
modl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)6897e38a742SDavid Thompson static ssize_t modl_store(struct device *dev,
6907e38a742SDavid Thompson struct device_attribute *attr,
6917e38a742SDavid Thompson const char *buf, size_t count)
6927e38a742SDavid Thompson {
6937e38a742SDavid Thompson u64 modl[MLNX_MFG_VAL_QWORD_CNT(MODL)] = { 0 };
6947e38a742SDavid Thompson struct arm_smccc_res res;
6957e38a742SDavid Thompson int word;
6967e38a742SDavid Thompson
6977e38a742SDavid Thompson if (count > MLNX_MFG_MODL_VAL_LEN)
6987e38a742SDavid Thompson return -EINVAL;
6997e38a742SDavid Thompson
7007e38a742SDavid Thompson memcpy(modl, buf, count);
7017e38a742SDavid Thompson
7027e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
7037e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(MODL); word++) {
7047e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
7057e38a742SDavid Thompson MLNX_MFG_TYPE_MODL_0 + word,
7067e38a742SDavid Thompson sizeof(u64), modl[word], 0, 0, 0, 0, &res);
7077e38a742SDavid Thompson if (res.a0) {
7087e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7097e38a742SDavid Thompson return -EPERM;
7107e38a742SDavid Thompson }
7117e38a742SDavid Thompson }
7127e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7137e38a742SDavid Thompson
7147e38a742SDavid Thompson return count;
7157e38a742SDavid Thompson }
7167e38a742SDavid Thompson
sn_show(struct device * dev,struct device_attribute * attr,char * buf)7177e38a742SDavid Thompson static ssize_t sn_show(struct device *dev,
7187e38a742SDavid Thompson struct device_attribute *attr, char *buf)
7197e38a742SDavid Thompson {
7207e38a742SDavid Thompson u64 sn_data[MLNX_MFG_VAL_QWORD_CNT(SN) + 1] = { 0 };
7217e38a742SDavid Thompson struct arm_smccc_res res;
7227e38a742SDavid Thompson int word;
7237e38a742SDavid Thompson
7247e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
7257e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SN); word++) {
7267e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
7277e38a742SDavid Thompson MLNX_MFG_TYPE_SN_0 + word,
7287e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
7297e38a742SDavid Thompson if (res.a0) {
7307e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7317e38a742SDavid Thompson return -EPERM;
7327e38a742SDavid Thompson }
7337e38a742SDavid Thompson sn_data[word] = res.a1;
7347e38a742SDavid Thompson }
7357e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7367e38a742SDavid Thompson
737*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)sn_data);
7387e38a742SDavid Thompson }
7397e38a742SDavid Thompson
sn_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7407e38a742SDavid Thompson static ssize_t sn_store(struct device *dev,
7417e38a742SDavid Thompson struct device_attribute *attr,
7427e38a742SDavid Thompson const char *buf, size_t count)
7437e38a742SDavid Thompson {
7447e38a742SDavid Thompson u64 sn[MLNX_MFG_VAL_QWORD_CNT(SN)] = { 0 };
7457e38a742SDavid Thompson struct arm_smccc_res res;
7467e38a742SDavid Thompson int word;
7477e38a742SDavid Thompson
7487e38a742SDavid Thompson if (count > MLNX_MFG_SN_VAL_LEN)
7497e38a742SDavid Thompson return -EINVAL;
7507e38a742SDavid Thompson
7517e38a742SDavid Thompson memcpy(sn, buf, count);
7527e38a742SDavid Thompson
7537e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
7547e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SN); word++) {
7557e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
7567e38a742SDavid Thompson MLNX_MFG_TYPE_SN_0 + word,
7577e38a742SDavid Thompson sizeof(u64), sn[word], 0, 0, 0, 0, &res);
7587e38a742SDavid Thompson if (res.a0) {
7597e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7607e38a742SDavid Thompson return -EPERM;
7617e38a742SDavid Thompson }
7627e38a742SDavid Thompson }
7637e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7647e38a742SDavid Thompson
7657e38a742SDavid Thompson return count;
7667e38a742SDavid Thompson }
7677e38a742SDavid Thompson
uuid_show(struct device * dev,struct device_attribute * attr,char * buf)7687e38a742SDavid Thompson static ssize_t uuid_show(struct device *dev,
7697e38a742SDavid Thompson struct device_attribute *attr, char *buf)
7707e38a742SDavid Thompson {
7717e38a742SDavid Thompson u64 uuid_data[MLNX_MFG_VAL_QWORD_CNT(UUID) + 1] = { 0 };
7727e38a742SDavid Thompson struct arm_smccc_res res;
7737e38a742SDavid Thompson int word;
7747e38a742SDavid Thompson
7757e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
7767e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(UUID); word++) {
7777e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
7787e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_0 + word,
7797e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
7807e38a742SDavid Thompson if (res.a0) {
7817e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7827e38a742SDavid Thompson return -EPERM;
7837e38a742SDavid Thompson }
7847e38a742SDavid Thompson uuid_data[word] = res.a1;
7857e38a742SDavid Thompson }
7867e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
7877e38a742SDavid Thompson
788*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)uuid_data);
7897e38a742SDavid Thompson }
7907e38a742SDavid Thompson
uuid_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7917e38a742SDavid Thompson static ssize_t uuid_store(struct device *dev,
7927e38a742SDavid Thompson struct device_attribute *attr,
7937e38a742SDavid Thompson const char *buf, size_t count)
7947e38a742SDavid Thompson {
7957e38a742SDavid Thompson u64 uuid[MLNX_MFG_VAL_QWORD_CNT(UUID)] = { 0 };
7967e38a742SDavid Thompson struct arm_smccc_res res;
7977e38a742SDavid Thompson int word;
7987e38a742SDavid Thompson
7997e38a742SDavid Thompson if (count > MLNX_MFG_UUID_VAL_LEN)
8007e38a742SDavid Thompson return -EINVAL;
8017e38a742SDavid Thompson
8027e38a742SDavid Thompson memcpy(uuid, buf, count);
8037e38a742SDavid Thompson
8047e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
8057e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(UUID); word++) {
8067e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
8077e38a742SDavid Thompson MLNX_MFG_TYPE_UUID_0 + word,
8087e38a742SDavid Thompson sizeof(u64), uuid[word], 0, 0, 0, 0, &res);
8097e38a742SDavid Thompson if (res.a0) {
8107e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8117e38a742SDavid Thompson return -EPERM;
8127e38a742SDavid Thompson }
8137e38a742SDavid Thompson }
8147e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8157e38a742SDavid Thompson
8167e38a742SDavid Thompson return count;
8177e38a742SDavid Thompson }
8187e38a742SDavid Thompson
rev_show(struct device * dev,struct device_attribute * attr,char * buf)8197e38a742SDavid Thompson static ssize_t rev_show(struct device *dev,
8207e38a742SDavid Thompson struct device_attribute *attr, char *buf)
8217e38a742SDavid Thompson {
8227e38a742SDavid Thompson u64 rev_data[MLNX_MFG_VAL_QWORD_CNT(REV) + 1] = { 0 };
8237e38a742SDavid Thompson struct arm_smccc_res res;
8247e38a742SDavid Thompson int word;
8257e38a742SDavid Thompson
8267e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
8277e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(REV); word++) {
8287e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_GET_MFG_INFO,
8297e38a742SDavid Thompson MLNX_MFG_TYPE_REV + word,
8307e38a742SDavid Thompson 0, 0, 0, 0, 0, 0, &res);
8317e38a742SDavid Thompson if (res.a0) {
8327e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8337e38a742SDavid Thompson return -EPERM;
8347e38a742SDavid Thompson }
8357e38a742SDavid Thompson rev_data[word] = res.a1;
8367e38a742SDavid Thompson }
8377e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8387e38a742SDavid Thompson
839*e5afa3d7SLi Zhijian return sysfs_emit(buf, "%s", (char *)rev_data);
8407e38a742SDavid Thompson }
8417e38a742SDavid Thompson
rev_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)8427e38a742SDavid Thompson static ssize_t rev_store(struct device *dev,
8437e38a742SDavid Thompson struct device_attribute *attr,
8447e38a742SDavid Thompson const char *buf, size_t count)
8457e38a742SDavid Thompson {
8467e38a742SDavid Thompson u64 rev[MLNX_MFG_VAL_QWORD_CNT(REV)] = { 0 };
8477e38a742SDavid Thompson struct arm_smccc_res res;
8487e38a742SDavid Thompson int word;
8497e38a742SDavid Thompson
8507e38a742SDavid Thompson if (count > MLNX_MFG_REV_VAL_LEN)
8517e38a742SDavid Thompson return -EINVAL;
8527e38a742SDavid Thompson
8537e38a742SDavid Thompson memcpy(rev, buf, count);
8547e38a742SDavid Thompson
8557e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
8567e38a742SDavid Thompson for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(REV); word++) {
8577e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_SET_MFG_INFO,
8587e38a742SDavid Thompson MLNX_MFG_TYPE_REV + word,
8597e38a742SDavid Thompson sizeof(u64), rev[word], 0, 0, 0, 0, &res);
8607e38a742SDavid Thompson if (res.a0) {
8617e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8627e38a742SDavid Thompson return -EPERM;
8637e38a742SDavid Thompson }
8647e38a742SDavid Thompson }
8657e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8667e38a742SDavid Thompson
8677e38a742SDavid Thompson return count;
8687e38a742SDavid Thompson }
8697e38a742SDavid Thompson
mfg_lock_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)8707e38a742SDavid Thompson static ssize_t mfg_lock_store(struct device *dev,
8717e38a742SDavid Thompson struct device_attribute *attr,
8727e38a742SDavid Thompson const char *buf, size_t count)
8737e38a742SDavid Thompson {
8747e38a742SDavid Thompson struct arm_smccc_res res;
8757e38a742SDavid Thompson unsigned long val;
8767e38a742SDavid Thompson int err;
8777e38a742SDavid Thompson
8787e38a742SDavid Thompson err = kstrtoul(buf, 10, &val);
8797e38a742SDavid Thompson if (err)
8807e38a742SDavid Thompson return err;
8817e38a742SDavid Thompson
8827e38a742SDavid Thompson if (val != 1)
8837e38a742SDavid Thompson return -EINVAL;
8847e38a742SDavid Thompson
8857e38a742SDavid Thompson mutex_lock(&mfg_ops_lock);
8867e38a742SDavid Thompson arm_smccc_smc(MLXBF_BOOTCTL_LOCK_MFG_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
8877e38a742SDavid Thompson mutex_unlock(&mfg_ops_lock);
8887e38a742SDavid Thompson
8897e38a742SDavid Thompson return count;
8907e38a742SDavid Thompson }
8917e38a742SDavid Thompson
89279e29cb8SLiming Sun static DEVICE_ATTR_RW(post_reset_wdog);
89379e29cb8SLiming Sun static DEVICE_ATTR_RW(reset_action);
89479e29cb8SLiming Sun static DEVICE_ATTR_RW(second_reset_action);
89579e29cb8SLiming Sun static DEVICE_ATTR_RO(lifecycle_state);
89679e29cb8SLiming Sun static DEVICE_ATTR_RO(secure_boot_fuse_state);
8977bef7eeaSKhalil Blaiech static DEVICE_ATTR_WO(fw_reset);
898e9d1b2d0SLiming Sun static DEVICE_ATTR_WO(rsh_log);
899b18a97edSAsmaa Mnebhi static DEVICE_ATTR_RW(large_icm);
900e3205d41SAsmaa Mnebhi static DEVICE_ATTR_WO(os_up);
9017e38a742SDavid Thompson static DEVICE_ATTR_RW(oob_mac);
9027e38a742SDavid Thompson static DEVICE_ATTR_RW(opn);
9037e38a742SDavid Thompson static DEVICE_ATTR_RW(sku);
9047e38a742SDavid Thompson static DEVICE_ATTR_RW(modl);
9057e38a742SDavid Thompson static DEVICE_ATTR_RW(sn);
9067e38a742SDavid Thompson static DEVICE_ATTR_RW(uuid);
9077e38a742SDavid Thompson static DEVICE_ATTR_RW(rev);
9087e38a742SDavid Thompson static DEVICE_ATTR_WO(mfg_lock);
90979e29cb8SLiming Sun
91079e29cb8SLiming Sun static struct attribute *mlxbf_bootctl_attrs[] = {
91179e29cb8SLiming Sun &dev_attr_post_reset_wdog.attr,
91279e29cb8SLiming Sun &dev_attr_reset_action.attr,
91379e29cb8SLiming Sun &dev_attr_second_reset_action.attr,
91479e29cb8SLiming Sun &dev_attr_lifecycle_state.attr,
91579e29cb8SLiming Sun &dev_attr_secure_boot_fuse_state.attr,
9167bef7eeaSKhalil Blaiech &dev_attr_fw_reset.attr,
917e9d1b2d0SLiming Sun &dev_attr_rsh_log.attr,
918b18a97edSAsmaa Mnebhi &dev_attr_large_icm.attr,
919e3205d41SAsmaa Mnebhi &dev_attr_os_up.attr,
9207e38a742SDavid Thompson &dev_attr_oob_mac.attr,
9217e38a742SDavid Thompson &dev_attr_opn.attr,
9227e38a742SDavid Thompson &dev_attr_sku.attr,
9237e38a742SDavid Thompson &dev_attr_modl.attr,
9247e38a742SDavid Thompson &dev_attr_sn.attr,
9257e38a742SDavid Thompson &dev_attr_uuid.attr,
9267e38a742SDavid Thompson &dev_attr_rev.attr,
9277e38a742SDavid Thompson &dev_attr_mfg_lock.attr,
92879e29cb8SLiming Sun NULL
92979e29cb8SLiming Sun };
93079e29cb8SLiming Sun
93179e29cb8SLiming Sun ATTRIBUTE_GROUPS(mlxbf_bootctl);
93279e29cb8SLiming Sun
93379e29cb8SLiming Sun static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = {
93479e29cb8SLiming Sun {"MLNXBF04", 0},
93579e29cb8SLiming Sun {}
93679e29cb8SLiming Sun };
93779e29cb8SLiming Sun
93879e29cb8SLiming Sun MODULE_DEVICE_TABLE(acpi, mlxbf_bootctl_acpi_ids);
93979e29cb8SLiming Sun
mlxbf_bootctl_bootfifo_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)94082c3a0b7SLiming Sun static ssize_t mlxbf_bootctl_bootfifo_read(struct file *filp,
94182c3a0b7SLiming Sun struct kobject *kobj,
94282c3a0b7SLiming Sun struct bin_attribute *bin_attr,
94382c3a0b7SLiming Sun char *buf, loff_t pos,
94482c3a0b7SLiming Sun size_t count)
94582c3a0b7SLiming Sun {
94682c3a0b7SLiming Sun unsigned long timeout = msecs_to_jiffies(500);
94782c3a0b7SLiming Sun unsigned long expire = jiffies + timeout;
94882c3a0b7SLiming Sun u64 data, cnt = 0;
94982c3a0b7SLiming Sun char *p = buf;
95082c3a0b7SLiming Sun
95182c3a0b7SLiming Sun while (count >= sizeof(data)) {
95282c3a0b7SLiming Sun /* Give up reading if no more data within 500ms. */
95382c3a0b7SLiming Sun if (!cnt) {
95482c3a0b7SLiming Sun cnt = readq(mlxbf_rsh_boot_cnt);
95582c3a0b7SLiming Sun if (!cnt) {
95682c3a0b7SLiming Sun if (time_after(jiffies, expire))
95782c3a0b7SLiming Sun break;
95882c3a0b7SLiming Sun usleep_range(10, 50);
95982c3a0b7SLiming Sun continue;
96082c3a0b7SLiming Sun }
96182c3a0b7SLiming Sun }
96282c3a0b7SLiming Sun
96382c3a0b7SLiming Sun data = readq(mlxbf_rsh_boot_data);
96482c3a0b7SLiming Sun memcpy(p, &data, sizeof(data));
96582c3a0b7SLiming Sun count -= sizeof(data);
96682c3a0b7SLiming Sun p += sizeof(data);
96782c3a0b7SLiming Sun cnt--;
96882c3a0b7SLiming Sun expire = jiffies + timeout;
96982c3a0b7SLiming Sun }
97082c3a0b7SLiming Sun
97182c3a0b7SLiming Sun return p - buf;
97282c3a0b7SLiming Sun }
97382c3a0b7SLiming Sun
97482c3a0b7SLiming Sun static struct bin_attribute mlxbf_bootctl_bootfifo_sysfs_attr = {
97582c3a0b7SLiming Sun .attr = { .name = "bootfifo", .mode = 0400 },
97682c3a0b7SLiming Sun .read = mlxbf_bootctl_bootfifo_read,
97782c3a0b7SLiming Sun };
97882c3a0b7SLiming Sun
mlxbf_bootctl_guid_match(const guid_t * guid,const struct arm_smccc_res * res)97979e29cb8SLiming Sun static bool mlxbf_bootctl_guid_match(const guid_t *guid,
98079e29cb8SLiming Sun const struct arm_smccc_res *res)
98179e29cb8SLiming Sun {
98279e29cb8SLiming Sun guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16,
98379e29cb8SLiming Sun res->a2, res->a2 >> 8, res->a2 >> 16,
98479e29cb8SLiming Sun res->a2 >> 24, res->a3, res->a3 >> 8,
98579e29cb8SLiming Sun res->a3 >> 16, res->a3 >> 24);
98679e29cb8SLiming Sun
98779e29cb8SLiming Sun return guid_equal(guid, &id);
98879e29cb8SLiming Sun }
98979e29cb8SLiming Sun
mlxbf_bootctl_probe(struct platform_device * pdev)99079e29cb8SLiming Sun static int mlxbf_bootctl_probe(struct platform_device *pdev)
99179e29cb8SLiming Sun {
99279e29cb8SLiming Sun struct arm_smccc_res res = { 0 };
993e9d1b2d0SLiming Sun void __iomem *reg;
99479e29cb8SLiming Sun guid_t guid;
99579e29cb8SLiming Sun int ret;
99679e29cb8SLiming Sun
997e9d1b2d0SLiming Sun /* Map the resource of the bootfifo data register. */
99882c3a0b7SLiming Sun mlxbf_rsh_boot_data = devm_platform_ioremap_resource(pdev, 0);
99982c3a0b7SLiming Sun if (IS_ERR(mlxbf_rsh_boot_data))
100082c3a0b7SLiming Sun return PTR_ERR(mlxbf_rsh_boot_data);
100182c3a0b7SLiming Sun
1002e9d1b2d0SLiming Sun /* Map the resource of the bootfifo counter register. */
100382c3a0b7SLiming Sun mlxbf_rsh_boot_cnt = devm_platform_ioremap_resource(pdev, 1);
100482c3a0b7SLiming Sun if (IS_ERR(mlxbf_rsh_boot_cnt))
100582c3a0b7SLiming Sun return PTR_ERR(mlxbf_rsh_boot_cnt);
100682c3a0b7SLiming Sun
1007e9d1b2d0SLiming Sun /* Map the resource of the rshim semaphore register. */
1008e9d1b2d0SLiming Sun mlxbf_rsh_semaphore = devm_platform_ioremap_resource(pdev, 2);
1009e9d1b2d0SLiming Sun if (IS_ERR(mlxbf_rsh_semaphore))
1010e9d1b2d0SLiming Sun return PTR_ERR(mlxbf_rsh_semaphore);
1011e9d1b2d0SLiming Sun
1012e9d1b2d0SLiming Sun /* Map the resource of the scratch buffer (log) registers. */
1013e9d1b2d0SLiming Sun reg = devm_platform_ioremap_resource(pdev, 3);
1014e9d1b2d0SLiming Sun if (IS_ERR(reg))
1015e9d1b2d0SLiming Sun return PTR_ERR(reg);
1016e9d1b2d0SLiming Sun mlxbf_rsh_scratch_buf_ctl = reg + MLXBF_RSH_SCRATCH_BUF_CTL_OFF;
1017e9d1b2d0SLiming Sun mlxbf_rsh_scratch_buf_data = reg + MLXBF_RSH_SCRATCH_BUF_DATA_OFF;
1018e9d1b2d0SLiming Sun
101979e29cb8SLiming Sun /* Ensure we have the UUID we expect for this service. */
102079e29cb8SLiming Sun arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
102179e29cb8SLiming Sun guid_parse(mlxbf_bootctl_svc_uuid_str, &guid);
102279e29cb8SLiming Sun if (!mlxbf_bootctl_guid_match(&guid, &res))
102379e29cb8SLiming Sun return -ENODEV;
102479e29cb8SLiming Sun
102579e29cb8SLiming Sun /*
102679e29cb8SLiming Sun * When watchdog is used, it sets boot mode to MLXBF_BOOTCTL_SWAP_EMMC
102779e29cb8SLiming Sun * in case of boot failures. However it doesn't clear the state if there
102879e29cb8SLiming Sun * is no failure. Restore the default boot mode here to avoid any
102979e29cb8SLiming Sun * unnecessary boot partition swapping.
103079e29cb8SLiming Sun */
103179e29cb8SLiming Sun ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_RESET_ACTION,
103279e29cb8SLiming Sun MLXBF_BOOTCTL_EMMC);
103379e29cb8SLiming Sun if (ret < 0)
103479e29cb8SLiming Sun dev_warn(&pdev->dev, "Unable to reset the EMMC boot mode\n");
103579e29cb8SLiming Sun
103682c3a0b7SLiming Sun ret = sysfs_create_bin_file(&pdev->dev.kobj,
103782c3a0b7SLiming Sun &mlxbf_bootctl_bootfifo_sysfs_attr);
103882c3a0b7SLiming Sun if (ret)
103982c3a0b7SLiming Sun pr_err("Unable to create bootfifo sysfs file, error %d\n", ret);
104082c3a0b7SLiming Sun
104182c3a0b7SLiming Sun return ret;
104282c3a0b7SLiming Sun }
104382c3a0b7SLiming Sun
mlxbf_bootctl_remove(struct platform_device * pdev)1044a6cff421SUwe Kleine-König static void mlxbf_bootctl_remove(struct platform_device *pdev)
104582c3a0b7SLiming Sun {
104682c3a0b7SLiming Sun sysfs_remove_bin_file(&pdev->dev.kobj,
104782c3a0b7SLiming Sun &mlxbf_bootctl_bootfifo_sysfs_attr);
104879e29cb8SLiming Sun }
104979e29cb8SLiming Sun
105079e29cb8SLiming Sun static struct platform_driver mlxbf_bootctl_driver = {
105179e29cb8SLiming Sun .probe = mlxbf_bootctl_probe,
1052a6cff421SUwe Kleine-König .remove_new = mlxbf_bootctl_remove,
105379e29cb8SLiming Sun .driver = {
105479e29cb8SLiming Sun .name = "mlxbf-bootctl",
105577dcc95eSLiming Sun .dev_groups = mlxbf_bootctl_groups,
105679e29cb8SLiming Sun .acpi_match_table = mlxbf_bootctl_acpi_ids,
105779e29cb8SLiming Sun }
105879e29cb8SLiming Sun };
105979e29cb8SLiming Sun
106079e29cb8SLiming Sun module_platform_driver(mlxbf_bootctl_driver);
106179e29cb8SLiming Sun
106279e29cb8SLiming Sun MODULE_DESCRIPTION("Mellanox boot control driver");
106379e29cb8SLiming Sun MODULE_LICENSE("GPL v2");
106479e29cb8SLiming Sun MODULE_AUTHOR("Mellanox Technologies");
1065