Message ID | c1f7f7ce16eec0fe36aea395f279edc7270218f6.1623666674.git.shravankr@nvidia.com |
---|---|
State | New |
Headers | show |
Series | UBUNTU: SAUCE: mlx-bootctl: Support VPD info in EEPROM MFG | expand |
There are at least 3 unrelated changes in this single patch. 1) sprintf --> snprintf fixes 2) VPD in EEPROM support 3) version and license updates I think you should split out each functional change. rtg On 6/14/21 4:50 AM, Shravan Kumar Ramani wrote: > BugLink: https://bugs.launchpad.net/bugs/1931843 > > The MFG partition of the EEPROM now also holds the VPD fields. > With this change, the mlx-bootctl driver exposes sysfs entries > for each of the newly added fields: sn, uuid, sku and modl. > Also, the "opn_str" sysfs has been renamed to "opn". > > Signed-off-by: Shravan Kumar Ramani <shravankr@nvidia.com> > > --- > drivers/platform/mellanox/mlx-bootctl.c | 353 ++++++++++++++++++------ > 1 file changed, 270 insertions(+), 83 deletions(-) > > diff --git a/drivers/platform/mellanox/mlx-bootctl.c b/drivers/platform/mellanox/mlx-bootctl.c > index 6eff360551d9..2f12dc5a1234 100644 > --- a/drivers/platform/mellanox/mlx-bootctl.c > +++ b/drivers/platform/mellanox/mlx-bootctl.c > @@ -1,4 +1,4 @@ > -// SPDX-License-Identifier: GPL-2.0 > +// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause > /* > * Mellanox boot control driver > * This driver provides a sysfs interface for systems management > @@ -25,7 +25,7 @@ > #include "mlx-bootctl.h" > > #define DRIVER_NAME "mlx-bootctl" > -#define DRIVER_VERSION "1.3" > +#define DRIVER_VERSION "1.4" > #define DRIVER_DESCRIPTION "Mellanox boot control driver" > > #define SB_MODE_SECURE_MASK 0x03 > @@ -76,21 +76,39 @@ enum { > MLNX_MFG_TYPE_OOB_MAC = 1, > MLNX_MFG_TYPE_OPN_0, > MLNX_MFG_TYPE_OPN_1, > + MLNX_MFG_TYPE_OPN_2, > + MLNX_MFG_TYPE_SKU_0, > + MLNX_MFG_TYPE_SKU_1, > + MLNX_MFG_TYPE_SKU_2, > + MLNX_MFG_TYPE_MODL_0, > + MLNX_MFG_TYPE_MODL_1, > + MLNX_MFG_TYPE_MODL_2, > + MLNX_MFG_TYPE_SN_0, > + MLNX_MFG_TYPE_SN_1, > + MLNX_MFG_TYPE_SN_2, > + MLNX_MFG_TYPE_UUID_0, > + MLNX_MFG_TYPE_UUID_1, > + MLNX_MFG_TYPE_UUID_2, > + MLNX_MFG_TYPE_UUID_3, > + MLNX_MFG_TYPE_UUID_4, > }; > > /* This mutex is used to serialize MFG write and lock operations. */ > static DEFINE_MUTEX(mfg_ops_lock); > > -#define MLNX_MFG_OPN_VAL_LEN 16 > -#define MLNX_MFG_OPN_VAL_WORD_CNT (MLNX_MFG_OPN_VAL_LEN / 8) > - > -#define MLNX_MFG_OOB_MAC_LEN ETH_ALEN > +#define MLNX_MFG_OOB_MAC_LEN ETH_ALEN > +#define MLNX_MFG_OPN_VAL_LEN 24 > +#define MLNX_MFG_SKU_VAL_LEN 24 > +#define MLNX_MFG_MODL_VAL_LEN 24 > +#define MLNX_MFG_SN_VAL_LEN 24 > +#define MLNX_MFG_UUID_VAL_LEN 40 > +#define MLNX_MFG_VAL_WORD_CNT(type) (MLNX_MFG_##type##_VAL_LEN / 8) > /* > * The MAC address consists of 6 bytes (2 digits each) separated by ':'. > * The expected format is: "XX:XX:XX:XX:XX:XX" > */ > #define MLNX_MFG_OOB_MAC_FORMAT_LEN \ > - ((MLNX_MFG_OOB_MAC_LEN * 2) + (MLNX_MFG_OOB_MAC_LEN - 1)) > + ((MLNX_MFG_OOB_MAC_LEN * 2) + (MLNX_MFG_OOB_MAC_LEN - 1)) > > /* The SMC calls in question are atomic, so we don't have to lock here. */ > static int smc_call1(unsigned int smc_op, int smc_arg) > @@ -156,8 +174,8 @@ static ssize_t post_reset_wdog_store(struct device_driver *drv, > static ssize_t reset_action_show(struct device_driver *drv, > char *buf) > { > - return sprintf(buf, "%s\n", reset_action_to_string( > - smc_call0(MLNX_GET_RESET_ACTION))); > + return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( > + smc_call0(MLNX_GET_RESET_ACTION))); > } > > static ssize_t reset_action_store(struct device_driver *drv, > @@ -177,8 +195,8 @@ static ssize_t reset_action_store(struct device_driver *drv, > static ssize_t second_reset_action_show(struct device_driver *drv, > char *buf) > { > - return sprintf(buf, "%s\n", reset_action_to_string( > - smc_call0(MLNX_GET_SECOND_RESET_ACTION))); > + return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( > + smc_call0(MLNX_GET_SECOND_RESET_ACTION))); > } > > static ssize_t second_reset_action_store(struct device_driver *drv, > @@ -213,10 +231,11 @@ static ssize_t lifecycle_state_show(struct device_driver *drv, > > lc_state &= SB_MODE_SECURE_MASK; > > - return sprintf(buf, "%s(test)\n", lifecycle_states[lc_state]); > + return snprintf(buf, PAGE_SIZE, "%s(test)\n", > + lifecycle_states[lc_state]); > } > > - return sprintf(buf, "%s\n", lifecycle_states[lc_state]); > + return snprintf(buf, PAGE_SIZE, "%s\n", lifecycle_states[lc_state]); > } > > static ssize_t secure_boot_fuse_state_show(struct device_driver *drv, > @@ -309,7 +328,7 @@ static ssize_t oob_mac_show(struct device_driver *drv, char *buf) > mac_byte_ptr[0], mac_byte_ptr[1], mac_byte_ptr[2], > mac_byte_ptr[3], mac_byte_ptr[4], mac_byte_ptr[5]); > > - return sprintf(buf, "%s\n", mac_str); > + return snprintf(buf, sizeof(mac_str), "%s", mac_str); > } > > static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, > @@ -343,87 +362,239 @@ static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, > return res.a0 ? -EPERM : count; > } > > -static u8 get_opn_type(u8 word) > +static ssize_t opn_show(struct device_driver *drv, char *buf) > { > - switch (word) { > - case 0: > - return MLNX_MFG_TYPE_OPN_0; > - case 1: > - return MLNX_MFG_TYPE_OPN_1; > + u64 opn_data[MLNX_MFG_VAL_WORD_CNT(OPN)] = { 0 }; > + char opn[MLNX_MFG_OPN_VAL_LEN + 1] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(OPN); word++) { > + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, > + MLNX_MFG_TYPE_OPN_0 + word, > + 0, 0, 0, 0, 0, 0, &res); > + if (res.a0) > + return -EPERM; > + opn_data[word] = res.a1; > } > > - return 0; > + memcpy(opn, opn_data, MLNX_MFG_OPN_VAL_LEN); > + > + return snprintf(buf, sizeof(opn), "%s", opn); > } > > -static int get_opn_data(u64 *data, u8 word) > +static ssize_t opn_store(struct device_driver *drv, const char *buf, > + size_t count) > { > + u64 opn[MLNX_MFG_VAL_WORD_CNT(OPN)] = { 0 }; > struct arm_smccc_res res; > - u8 type; > + int word; > > - type = get_opn_type(word); > - if (!type || !data) > + if (count > MLNX_MFG_OPN_VAL_LEN) > return -EINVAL; > > - arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, type, 0, 0, 0, 0, 0, 0, &res); > - if (res.a0) > - return -EPERM; > + memcpy(opn, buf, count); > > - *data = res.a1; > + mutex_lock(&mfg_ops_lock); > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(OPN); word++) { > + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, > + MLNX_MFG_TYPE_OPN_0 + word, > + sizeof(u64), opn[word], 0, 0, 0, 0, &res); > + if (res.a0) { > + mutex_unlock(&mfg_ops_lock); > + return -EPERM; > + } > + } > + mutex_unlock(&mfg_ops_lock); > > - return 0; > + return count; > +} > + > +static ssize_t sku_show(struct device_driver *drv, char *buf) > +{ > + u64 sku_data[MLNX_MFG_VAL_WORD_CNT(SKU)] = { 0 }; > + char sku[MLNX_MFG_SKU_VAL_LEN + 1] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SKU); word++) { > + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, > + MLNX_MFG_TYPE_SKU_0 + word, > + 0, 0, 0, 0, 0, 0, &res); > + if (res.a0) > + return -EPERM; > + sku_data[word] = res.a1; > + } > + > + memcpy(sku, sku_data, MLNX_MFG_SKU_VAL_LEN); > + > + return snprintf(buf, sizeof(sku), "%s", sku); > } > > -static int set_opn_data(u64 data, u8 word) > +static ssize_t sku_store(struct device_driver *drv, const char *buf, > + size_t count) > { > + u64 sku[MLNX_MFG_VAL_WORD_CNT(SKU)] = { 0 }; > struct arm_smccc_res res; > - u8 type; > + int word; > > - type = get_opn_type(word); > - if (!type) > + if (count > MLNX_MFG_SKU_VAL_LEN) > return -EINVAL; > > - arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, type, sizeof(u64), data, 0, 0, > - 0, 0, &res); > - if (res.a0) > - return -EPERM; > + memcpy(sku, buf, count); > > - return 0; > + mutex_lock(&mfg_ops_lock); > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SKU); word++) { > + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, > + MLNX_MFG_TYPE_SKU_0 + word, > + sizeof(u64), sku[word], 0, 0, 0, 0, &res); > + if (res.a0) { > + mutex_unlock(&mfg_ops_lock); > + return -EPERM; > + } > + } > + mutex_unlock(&mfg_ops_lock); > + > + return count; > } > > -static ssize_t opn_str_show(struct device_driver *drv, char *buf) > +static ssize_t modl_show(struct device_driver *drv, char *buf) > { > - u64 opn_data[MLNX_MFG_OPN_VAL_WORD_CNT] = { 0 }; > - char opn_str[MLNX_MFG_OPN_VAL_LEN] = { 0 }; > - int word, err; > - > - for (word = 0; word < MLNX_MFG_OPN_VAL_WORD_CNT; word++) { > - err = get_opn_data(&opn_data[word], word); > - if (err) > - return err; > + u64 modl_data[MLNX_MFG_VAL_WORD_CNT(MODL)] = { 0 }; > + char modl[MLNX_MFG_MODL_VAL_LEN + 1] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(MODL); word++) { > + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, > + MLNX_MFG_TYPE_MODL_0 + word, > + 0, 0, 0, 0, 0, 0, &res); > + if (res.a0) > + return -EPERM; > + modl_data[word] = res.a1; > } > > - memcpy(opn_str, opn_data, MLNX_MFG_OPN_VAL_LEN); > + memcpy(modl, modl_data, MLNX_MFG_MODL_VAL_LEN); > > - return sprintf(buf, "%s", opn_str); > + return snprintf(buf, sizeof(modl), "%s", modl); > } > > -static ssize_t opn_str_store(struct device_driver *drv, const char *buf, > - size_t count) > +static ssize_t modl_store(struct device_driver *drv, const char *buf, > + size_t count) > { > - u64 opn[MLNX_MFG_OPN_VAL_WORD_CNT] = { 0 }; > - int word, err; > + u64 modl[MLNX_MFG_VAL_WORD_CNT(MODL)] = { 0 }; > + struct arm_smccc_res res; > + int word; > > - if (count > MLNX_MFG_OPN_VAL_LEN) > + if (count > MLNX_MFG_MODL_VAL_LEN) > return -EINVAL; > > - memcpy(opn, buf, strlen(buf)); > + memcpy(modl, buf, count); > > mutex_lock(&mfg_ops_lock); > - for (word = 0; word < MLNX_MFG_OPN_VAL_WORD_CNT; word++) { > - err = set_opn_data(opn[word], word); > - if (err) { > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(MODL); word++) { > + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, > + MLNX_MFG_TYPE_MODL_0 + word, > + sizeof(u64), modl[word], 0, 0, 0, 0, &res); > + if (res.a0) { > mutex_unlock(&mfg_ops_lock); > - return err; > + return -EPERM; > + } > + } > + mutex_unlock(&mfg_ops_lock); > + > + return count; > +} > + > +static ssize_t sn_show(struct device_driver *drv, char *buf) > +{ > + u64 sn_data[MLNX_MFG_VAL_WORD_CNT(SN)] = { 0 }; > + char sn[MLNX_MFG_SN_VAL_LEN + 1] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SN); word++) { > + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, > + MLNX_MFG_TYPE_SN_0 + word, > + 0, 0, 0, 0, 0, 0, &res); > + if (res.a0) > + return -EPERM; > + sn_data[word] = res.a1; > + } > + > + memcpy(sn, sn_data, MLNX_MFG_SN_VAL_LEN); > + > + return snprintf(buf, sizeof(sn), "%s", sn); > +} > + > +static ssize_t sn_store(struct device_driver *drv, const char *buf, > + size_t count) > +{ > + u64 sn[MLNX_MFG_VAL_WORD_CNT(SN)] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + if (count > MLNX_MFG_SN_VAL_LEN) > + return -EINVAL; > + > + memcpy(sn, buf, count); > + > + mutex_lock(&mfg_ops_lock); > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SN); word++) { > + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, > + MLNX_MFG_TYPE_SN_0 + word, > + sizeof(u64), sn[word], 0, 0, 0, 0, &res); > + if (res.a0) { > + mutex_unlock(&mfg_ops_lock); > + return -EPERM; > + } > + } > + mutex_unlock(&mfg_ops_lock); > + > + return count; > +} > + > +static ssize_t uuid_show(struct device_driver *drv, char *buf) > +{ > + u64 uuid_data[MLNX_MFG_VAL_WORD_CNT(UUID)] = { 0 }; > + char uuid[MLNX_MFG_UUID_VAL_LEN + 1] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(UUID); word++) { > + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, > + MLNX_MFG_TYPE_UUID_0 + word, > + 0, 0, 0, 0, 0, 0, &res); > + if (res.a0) > + return -EPERM; > + uuid_data[word] = res.a1; > + } > + > + memcpy(uuid, uuid_data, MLNX_MFG_UUID_VAL_LEN); > + > + return snprintf(buf, sizeof(uuid), "%s", uuid); > +} > + > +static ssize_t uuid_store(struct device_driver *drv, const char *buf, > + size_t count) > +{ > + u64 uuid[MLNX_MFG_VAL_WORD_CNT(UUID)] = { 0 }; > + struct arm_smccc_res res; > + int word; > + > + if (count > MLNX_MFG_UUID_VAL_LEN) > + return -EINVAL; > + > + memcpy(uuid, buf, count); > + > + mutex_lock(&mfg_ops_lock); > + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(UUID); word++) { > + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, > + MLNX_MFG_TYPE_UUID_0 + word, > + sizeof(u64), uuid[word], 0, 0, 0, 0, &res); > + if (res.a0) { > + mutex_unlock(&mfg_ops_lock); > + return -EPERM; > } > } > mutex_unlock(&mfg_ops_lock); > @@ -727,7 +898,7 @@ static char *rsh_log_get_reg_name(u64 opcode) > return "unknown"; > } > > -static int rsh_log_show_crash(u64 hdr, char *buf) > +static int rsh_log_show_crash(u64 hdr, char *buf, int size) > { > int i, module, type, len, n = 0; > u32 pc, syndrome, ec; > @@ -743,17 +914,20 @@ static int rsh_log_show_crash(u64 hdr, char *buf) > if (type == BF_RSH_LOG_TYPE_EXCEPTION) { > syndrome = BF_RSH_LOG_HEADER_GET(SYNDROME, hdr); > ec = syndrome >> AARCH64_ESR_ELX_EXCEPTION_CLASS_SHIFT; > - n = sprintf(p, " Exception(%s): syndrome = 0x%x%s\n", > + n = snprintf(p, size, " Exception(%s): syndrome = 0x%x%s\n", > rsh_log_mod[module], syndrome, > (ec == 0x24 || ec == 0x25) ? "(Data Abort)" : > (ec == 0x2f) ? "(SError)" : ""); > } else if (type == BF_RSH_LOG_TYPE_PANIC) { > pc = BF_RSH_LOG_HEADER_GET(PC, hdr); > - n = sprintf(p, " PANIC(%s): PC = 0x%x\n", rsh_log_mod[module], > - pc); > + n = snprintf(p, size, > + " PANIC(%s): PC = 0x%x\n", rsh_log_mod[module], > + pc); > } > - if (n > 0) > + if (n > 0) { > p += n; > + size -= n; > + } > > /* > * Read the registers in a loop. 'len' is the total number of words in > @@ -765,28 +939,31 @@ static int rsh_log_show_crash(u64 hdr, char *buf) > > opcode = (opcode >> AARCH64_MRS_REG_SHIFT) & > AARCH64_MRS_REG_MASK; > - n = sprintf(p, " %-16s0x%llx\n", rsh_log_get_reg_name(opcode), > - (unsigned long long)data); > - if (n > 0) > + n = snprintf(p, size, > + " %-16s0x%llx\n", rsh_log_get_reg_name(opcode), > + (unsigned long long)data); > + if (n > 0) { > p += n; > + size -= n; > + } > } > > return p - buf; > } > > -static int rsh_log_format_msg(char *buf, const char *msg, ...) > +static int rsh_log_format_msg(char *buf, int size, const char *msg, ...) > { > va_list args; > int len; > > va_start(args, msg); > - len = vsprintf(buf, msg, args); > + len = vsnprintf(buf, size, msg, args); > va_end(args); > > return len; > } > > -static int rsh_log_show_msg(u64 hdr, char *buf) > +static int rsh_log_show_msg(u64 hdr, char *buf, int size) > { > int has_arg = BF_RSH_LOG_HEADER_GET(HAS_ARG, hdr); > int level = BF_RSH_LOG_HEADER_GET(LEVEL, hdr); > @@ -817,13 +994,13 @@ static int rsh_log_show_msg(u64 hdr, char *buf) > } > *p = '\0'; > if (!has_arg) { > - len = sprintf(buf, " %s[%s]: %s\n", rsh_log_level[level], > - rsh_log_mod[module], msg); > + len = snprintf(buf, size, " %s[%s]: %s\n", rsh_log_level[level], > + rsh_log_mod[module], msg); > } else { > - len = sprintf(buf, " %s[%s]: ", rsh_log_level[level], > - rsh_log_mod[module]); > - len += rsh_log_format_msg(buf + len, msg, arg); > - len += sprintf(buf + len, "\n"); > + len = snprintf(buf, size, " %s[%s]: ", rsh_log_level[level], > + rsh_log_mod[module]); > + len += rsh_log_format_msg(buf + len, size - len, msg, arg); > + len += snprintf(buf + len, size - len, "\n"); > } > > kfree(msg); > @@ -834,7 +1011,7 @@ static ssize_t rsh_log_show(struct device_driver *drv, char *buf) > { > u64 hdr; > char *p = buf; > - int i, n, rc, idx, type, len; > + int i, n, rc, idx, type, len, size = PAGE_SIZE; > > if (!rsh_semaphore || !rsh_scratch_buf_ctl) > return -EOPNOTSUPP; > @@ -862,12 +1039,14 @@ static ssize_t rsh_log_show(struct device_driver *drv, char *buf) > switch (type) { > case BF_RSH_LOG_TYPE_PANIC: > case BF_RSH_LOG_TYPE_EXCEPTION: > - n = rsh_log_show_crash(hdr, p); > + n = rsh_log_show_crash(hdr, p, size); > p += n; > + size -= n; > break; > case BF_RSH_LOG_TYPE_MSG: > - n = rsh_log_show_msg(hdr, p); > + n = rsh_log_show_msg(hdr, p, size); > p += n; > + size -= n; > break; > default: > /* Drain this message. */ > @@ -896,7 +1075,11 @@ static DRIVER_ATTR_RO(lifecycle_state); > static DRIVER_ATTR_RO(secure_boot_fuse_state); > static DRIVER_ATTR_WO(fw_reset); > static DRIVER_ATTR_RW(oob_mac); > -static DRIVER_ATTR_RW(opn_str); > +static DRIVER_ATTR_RW(opn); > +static DRIVER_ATTR_RW(sku); > +static DRIVER_ATTR_RW(modl); > +static DRIVER_ATTR_RW(sn); > +static DRIVER_ATTR_RW(uuid); > static DRIVER_ATTR_WO(mfg_lock); > static DRIVER_ATTR_RW(rsh_log); > > @@ -908,7 +1091,11 @@ static struct attribute *mbc_dev_attrs[] = { > &driver_attr_secure_boot_fuse_state.attr, > &driver_attr_fw_reset.attr, > &driver_attr_oob_mac.attr, > - &driver_attr_opn_str.attr, > + &driver_attr_opn.attr, > + &driver_attr_sku.attr, > + &driver_attr_modl.attr, > + &driver_attr_sn.attr, > + &driver_attr_uuid.attr, > &driver_attr_mfg_lock.attr, > &driver_attr_rsh_log.attr, > NULL > @@ -1064,4 +1251,4 @@ module_platform_driver(mbc_driver); > MODULE_DESCRIPTION(DRIVER_DESCRIPTION); > MODULE_VERSION(DRIVER_VERSION); > MODULE_AUTHOR("Mellanox Technologies"); > -MODULE_LICENSE("GPL"); > +MODULE_LICENSE("Dual BSD/GPL"); >
diff --git a/drivers/platform/mellanox/mlx-bootctl.c b/drivers/platform/mellanox/mlx-bootctl.c index 6eff360551d9..2f12dc5a1234 100644 --- a/drivers/platform/mellanox/mlx-bootctl.c +++ b/drivers/platform/mellanox/mlx-bootctl.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause /* * Mellanox boot control driver * This driver provides a sysfs interface for systems management @@ -25,7 +25,7 @@ #include "mlx-bootctl.h" #define DRIVER_NAME "mlx-bootctl" -#define DRIVER_VERSION "1.3" +#define DRIVER_VERSION "1.4" #define DRIVER_DESCRIPTION "Mellanox boot control driver" #define SB_MODE_SECURE_MASK 0x03 @@ -76,21 +76,39 @@ enum { MLNX_MFG_TYPE_OOB_MAC = 1, MLNX_MFG_TYPE_OPN_0, MLNX_MFG_TYPE_OPN_1, + MLNX_MFG_TYPE_OPN_2, + MLNX_MFG_TYPE_SKU_0, + MLNX_MFG_TYPE_SKU_1, + MLNX_MFG_TYPE_SKU_2, + MLNX_MFG_TYPE_MODL_0, + MLNX_MFG_TYPE_MODL_1, + MLNX_MFG_TYPE_MODL_2, + MLNX_MFG_TYPE_SN_0, + MLNX_MFG_TYPE_SN_1, + MLNX_MFG_TYPE_SN_2, + MLNX_MFG_TYPE_UUID_0, + MLNX_MFG_TYPE_UUID_1, + MLNX_MFG_TYPE_UUID_2, + MLNX_MFG_TYPE_UUID_3, + MLNX_MFG_TYPE_UUID_4, }; /* This mutex is used to serialize MFG write and lock operations. */ static DEFINE_MUTEX(mfg_ops_lock); -#define MLNX_MFG_OPN_VAL_LEN 16 -#define MLNX_MFG_OPN_VAL_WORD_CNT (MLNX_MFG_OPN_VAL_LEN / 8) - -#define MLNX_MFG_OOB_MAC_LEN ETH_ALEN +#define MLNX_MFG_OOB_MAC_LEN ETH_ALEN +#define MLNX_MFG_OPN_VAL_LEN 24 +#define MLNX_MFG_SKU_VAL_LEN 24 +#define MLNX_MFG_MODL_VAL_LEN 24 +#define MLNX_MFG_SN_VAL_LEN 24 +#define MLNX_MFG_UUID_VAL_LEN 40 +#define MLNX_MFG_VAL_WORD_CNT(type) (MLNX_MFG_##type##_VAL_LEN / 8) /* * The MAC address consists of 6 bytes (2 digits each) separated by ':'. * The expected format is: "XX:XX:XX:XX:XX:XX" */ #define MLNX_MFG_OOB_MAC_FORMAT_LEN \ - ((MLNX_MFG_OOB_MAC_LEN * 2) + (MLNX_MFG_OOB_MAC_LEN - 1)) + ((MLNX_MFG_OOB_MAC_LEN * 2) + (MLNX_MFG_OOB_MAC_LEN - 1)) /* The SMC calls in question are atomic, so we don't have to lock here. */ static int smc_call1(unsigned int smc_op, int smc_arg) @@ -156,8 +174,8 @@ static ssize_t post_reset_wdog_store(struct device_driver *drv, static ssize_t reset_action_show(struct device_driver *drv, char *buf) { - return sprintf(buf, "%s\n", reset_action_to_string( - smc_call0(MLNX_GET_RESET_ACTION))); + return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( + smc_call0(MLNX_GET_RESET_ACTION))); } static ssize_t reset_action_store(struct device_driver *drv, @@ -177,8 +195,8 @@ static ssize_t reset_action_store(struct device_driver *drv, static ssize_t second_reset_action_show(struct device_driver *drv, char *buf) { - return sprintf(buf, "%s\n", reset_action_to_string( - smc_call0(MLNX_GET_SECOND_RESET_ACTION))); + return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( + smc_call0(MLNX_GET_SECOND_RESET_ACTION))); } static ssize_t second_reset_action_store(struct device_driver *drv, @@ -213,10 +231,11 @@ static ssize_t lifecycle_state_show(struct device_driver *drv, lc_state &= SB_MODE_SECURE_MASK; - return sprintf(buf, "%s(test)\n", lifecycle_states[lc_state]); + return snprintf(buf, PAGE_SIZE, "%s(test)\n", + lifecycle_states[lc_state]); } - return sprintf(buf, "%s\n", lifecycle_states[lc_state]); + return snprintf(buf, PAGE_SIZE, "%s\n", lifecycle_states[lc_state]); } static ssize_t secure_boot_fuse_state_show(struct device_driver *drv, @@ -309,7 +328,7 @@ static ssize_t oob_mac_show(struct device_driver *drv, char *buf) mac_byte_ptr[0], mac_byte_ptr[1], mac_byte_ptr[2], mac_byte_ptr[3], mac_byte_ptr[4], mac_byte_ptr[5]); - return sprintf(buf, "%s\n", mac_str); + return snprintf(buf, sizeof(mac_str), "%s", mac_str); } static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, @@ -343,87 +362,239 @@ static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, return res.a0 ? -EPERM : count; } -static u8 get_opn_type(u8 word) +static ssize_t opn_show(struct device_driver *drv, char *buf) { - switch (word) { - case 0: - return MLNX_MFG_TYPE_OPN_0; - case 1: - return MLNX_MFG_TYPE_OPN_1; + u64 opn_data[MLNX_MFG_VAL_WORD_CNT(OPN)] = { 0 }; + char opn[MLNX_MFG_OPN_VAL_LEN + 1] = { 0 }; + struct arm_smccc_res res; + int word; + + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(OPN); word++) { + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, + MLNX_MFG_TYPE_OPN_0 + word, + 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EPERM; + opn_data[word] = res.a1; } - return 0; + memcpy(opn, opn_data, MLNX_MFG_OPN_VAL_LEN); + + return snprintf(buf, sizeof(opn), "%s", opn); } -static int get_opn_data(u64 *data, u8 word) +static ssize_t opn_store(struct device_driver *drv, const char *buf, + size_t count) { + u64 opn[MLNX_MFG_VAL_WORD_CNT(OPN)] = { 0 }; struct arm_smccc_res res; - u8 type; + int word; - type = get_opn_type(word); - if (!type || !data) + if (count > MLNX_MFG_OPN_VAL_LEN) return -EINVAL; - arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, type, 0, 0, 0, 0, 0, 0, &res); - if (res.a0) - return -EPERM; + memcpy(opn, buf, count); - *data = res.a1; + mutex_lock(&mfg_ops_lock); + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(OPN); word++) { + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, + MLNX_MFG_TYPE_OPN_0 + word, + sizeof(u64), opn[word], 0, 0, 0, 0, &res); + if (res.a0) { + mutex_unlock(&mfg_ops_lock); + return -EPERM; + } + } + mutex_unlock(&mfg_ops_lock); - return 0; + return count; +} + +static ssize_t sku_show(struct device_driver *drv, char *buf) +{ + u64 sku_data[MLNX_MFG_VAL_WORD_CNT(SKU)] = { 0 }; + char sku[MLNX_MFG_SKU_VAL_LEN + 1] = { 0 }; + struct arm_smccc_res res; + int word; + + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SKU); word++) { + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, + MLNX_MFG_TYPE_SKU_0 + word, + 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EPERM; + sku_data[word] = res.a1; + } + + memcpy(sku, sku_data, MLNX_MFG_SKU_VAL_LEN); + + return snprintf(buf, sizeof(sku), "%s", sku); } -static int set_opn_data(u64 data, u8 word) +static ssize_t sku_store(struct device_driver *drv, const char *buf, + size_t count) { + u64 sku[MLNX_MFG_VAL_WORD_CNT(SKU)] = { 0 }; struct arm_smccc_res res; - u8 type; + int word; - type = get_opn_type(word); - if (!type) + if (count > MLNX_MFG_SKU_VAL_LEN) return -EINVAL; - arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, type, sizeof(u64), data, 0, 0, - 0, 0, &res); - if (res.a0) - return -EPERM; + memcpy(sku, buf, count); - return 0; + mutex_lock(&mfg_ops_lock); + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SKU); word++) { + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, + MLNX_MFG_TYPE_SKU_0 + word, + sizeof(u64), sku[word], 0, 0, 0, 0, &res); + if (res.a0) { + mutex_unlock(&mfg_ops_lock); + return -EPERM; + } + } + mutex_unlock(&mfg_ops_lock); + + return count; } -static ssize_t opn_str_show(struct device_driver *drv, char *buf) +static ssize_t modl_show(struct device_driver *drv, char *buf) { - u64 opn_data[MLNX_MFG_OPN_VAL_WORD_CNT] = { 0 }; - char opn_str[MLNX_MFG_OPN_VAL_LEN] = { 0 }; - int word, err; - - for (word = 0; word < MLNX_MFG_OPN_VAL_WORD_CNT; word++) { - err = get_opn_data(&opn_data[word], word); - if (err) - return err; + u64 modl_data[MLNX_MFG_VAL_WORD_CNT(MODL)] = { 0 }; + char modl[MLNX_MFG_MODL_VAL_LEN + 1] = { 0 }; + struct arm_smccc_res res; + int word; + + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(MODL); word++) { + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, + MLNX_MFG_TYPE_MODL_0 + word, + 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EPERM; + modl_data[word] = res.a1; } - memcpy(opn_str, opn_data, MLNX_MFG_OPN_VAL_LEN); + memcpy(modl, modl_data, MLNX_MFG_MODL_VAL_LEN); - return sprintf(buf, "%s", opn_str); + return snprintf(buf, sizeof(modl), "%s", modl); } -static ssize_t opn_str_store(struct device_driver *drv, const char *buf, - size_t count) +static ssize_t modl_store(struct device_driver *drv, const char *buf, + size_t count) { - u64 opn[MLNX_MFG_OPN_VAL_WORD_CNT] = { 0 }; - int word, err; + u64 modl[MLNX_MFG_VAL_WORD_CNT(MODL)] = { 0 }; + struct arm_smccc_res res; + int word; - if (count > MLNX_MFG_OPN_VAL_LEN) + if (count > MLNX_MFG_MODL_VAL_LEN) return -EINVAL; - memcpy(opn, buf, strlen(buf)); + memcpy(modl, buf, count); mutex_lock(&mfg_ops_lock); - for (word = 0; word < MLNX_MFG_OPN_VAL_WORD_CNT; word++) { - err = set_opn_data(opn[word], word); - if (err) { + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(MODL); word++) { + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, + MLNX_MFG_TYPE_MODL_0 + word, + sizeof(u64), modl[word], 0, 0, 0, 0, &res); + if (res.a0) { mutex_unlock(&mfg_ops_lock); - return err; + return -EPERM; + } + } + mutex_unlock(&mfg_ops_lock); + + return count; +} + +static ssize_t sn_show(struct device_driver *drv, char *buf) +{ + u64 sn_data[MLNX_MFG_VAL_WORD_CNT(SN)] = { 0 }; + char sn[MLNX_MFG_SN_VAL_LEN + 1] = { 0 }; + struct arm_smccc_res res; + int word; + + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SN); word++) { + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, + MLNX_MFG_TYPE_SN_0 + word, + 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EPERM; + sn_data[word] = res.a1; + } + + memcpy(sn, sn_data, MLNX_MFG_SN_VAL_LEN); + + return snprintf(buf, sizeof(sn), "%s", sn); +} + +static ssize_t sn_store(struct device_driver *drv, const char *buf, + size_t count) +{ + u64 sn[MLNX_MFG_VAL_WORD_CNT(SN)] = { 0 }; + struct arm_smccc_res res; + int word; + + if (count > MLNX_MFG_SN_VAL_LEN) + return -EINVAL; + + memcpy(sn, buf, count); + + mutex_lock(&mfg_ops_lock); + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(SN); word++) { + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, + MLNX_MFG_TYPE_SN_0 + word, + sizeof(u64), sn[word], 0, 0, 0, 0, &res); + if (res.a0) { + mutex_unlock(&mfg_ops_lock); + return -EPERM; + } + } + mutex_unlock(&mfg_ops_lock); + + return count; +} + +static ssize_t uuid_show(struct device_driver *drv, char *buf) +{ + u64 uuid_data[MLNX_MFG_VAL_WORD_CNT(UUID)] = { 0 }; + char uuid[MLNX_MFG_UUID_VAL_LEN + 1] = { 0 }; + struct arm_smccc_res res; + int word; + + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(UUID); word++) { + arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, + MLNX_MFG_TYPE_UUID_0 + word, + 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EPERM; + uuid_data[word] = res.a1; + } + + memcpy(uuid, uuid_data, MLNX_MFG_UUID_VAL_LEN); + + return snprintf(buf, sizeof(uuid), "%s", uuid); +} + +static ssize_t uuid_store(struct device_driver *drv, const char *buf, + size_t count) +{ + u64 uuid[MLNX_MFG_VAL_WORD_CNT(UUID)] = { 0 }; + struct arm_smccc_res res; + int word; + + if (count > MLNX_MFG_UUID_VAL_LEN) + return -EINVAL; + + memcpy(uuid, buf, count); + + mutex_lock(&mfg_ops_lock); + for (word = 0; word < MLNX_MFG_VAL_WORD_CNT(UUID); word++) { + arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, + MLNX_MFG_TYPE_UUID_0 + word, + sizeof(u64), uuid[word], 0, 0, 0, 0, &res); + if (res.a0) { + mutex_unlock(&mfg_ops_lock); + return -EPERM; } } mutex_unlock(&mfg_ops_lock); @@ -727,7 +898,7 @@ static char *rsh_log_get_reg_name(u64 opcode) return "unknown"; } -static int rsh_log_show_crash(u64 hdr, char *buf) +static int rsh_log_show_crash(u64 hdr, char *buf, int size) { int i, module, type, len, n = 0; u32 pc, syndrome, ec; @@ -743,17 +914,20 @@ static int rsh_log_show_crash(u64 hdr, char *buf) if (type == BF_RSH_LOG_TYPE_EXCEPTION) { syndrome = BF_RSH_LOG_HEADER_GET(SYNDROME, hdr); ec = syndrome >> AARCH64_ESR_ELX_EXCEPTION_CLASS_SHIFT; - n = sprintf(p, " Exception(%s): syndrome = 0x%x%s\n", + n = snprintf(p, size, " Exception(%s): syndrome = 0x%x%s\n", rsh_log_mod[module], syndrome, (ec == 0x24 || ec == 0x25) ? "(Data Abort)" : (ec == 0x2f) ? "(SError)" : ""); } else if (type == BF_RSH_LOG_TYPE_PANIC) { pc = BF_RSH_LOG_HEADER_GET(PC, hdr); - n = sprintf(p, " PANIC(%s): PC = 0x%x\n", rsh_log_mod[module], - pc); + n = snprintf(p, size, + " PANIC(%s): PC = 0x%x\n", rsh_log_mod[module], + pc); } - if (n > 0) + if (n > 0) { p += n; + size -= n; + } /* * Read the registers in a loop. 'len' is the total number of words in @@ -765,28 +939,31 @@ static int rsh_log_show_crash(u64 hdr, char *buf) opcode = (opcode >> AARCH64_MRS_REG_SHIFT) & AARCH64_MRS_REG_MASK; - n = sprintf(p, " %-16s0x%llx\n", rsh_log_get_reg_name(opcode), - (unsigned long long)data); - if (n > 0) + n = snprintf(p, size, + " %-16s0x%llx\n", rsh_log_get_reg_name(opcode), + (unsigned long long)data); + if (n > 0) { p += n; + size -= n; + } } return p - buf; } -static int rsh_log_format_msg(char *buf, const char *msg, ...) +static int rsh_log_format_msg(char *buf, int size, const char *msg, ...) { va_list args; int len; va_start(args, msg); - len = vsprintf(buf, msg, args); + len = vsnprintf(buf, size, msg, args); va_end(args); return len; } -static int rsh_log_show_msg(u64 hdr, char *buf) +static int rsh_log_show_msg(u64 hdr, char *buf, int size) { int has_arg = BF_RSH_LOG_HEADER_GET(HAS_ARG, hdr); int level = BF_RSH_LOG_HEADER_GET(LEVEL, hdr); @@ -817,13 +994,13 @@ static int rsh_log_show_msg(u64 hdr, char *buf) } *p = '\0'; if (!has_arg) { - len = sprintf(buf, " %s[%s]: %s\n", rsh_log_level[level], - rsh_log_mod[module], msg); + len = snprintf(buf, size, " %s[%s]: %s\n", rsh_log_level[level], + rsh_log_mod[module], msg); } else { - len = sprintf(buf, " %s[%s]: ", rsh_log_level[level], - rsh_log_mod[module]); - len += rsh_log_format_msg(buf + len, msg, arg); - len += sprintf(buf + len, "\n"); + len = snprintf(buf, size, " %s[%s]: ", rsh_log_level[level], + rsh_log_mod[module]); + len += rsh_log_format_msg(buf + len, size - len, msg, arg); + len += snprintf(buf + len, size - len, "\n"); } kfree(msg); @@ -834,7 +1011,7 @@ static ssize_t rsh_log_show(struct device_driver *drv, char *buf) { u64 hdr; char *p = buf; - int i, n, rc, idx, type, len; + int i, n, rc, idx, type, len, size = PAGE_SIZE; if (!rsh_semaphore || !rsh_scratch_buf_ctl) return -EOPNOTSUPP; @@ -862,12 +1039,14 @@ static ssize_t rsh_log_show(struct device_driver *drv, char *buf) switch (type) { case BF_RSH_LOG_TYPE_PANIC: case BF_RSH_LOG_TYPE_EXCEPTION: - n = rsh_log_show_crash(hdr, p); + n = rsh_log_show_crash(hdr, p, size); p += n; + size -= n; break; case BF_RSH_LOG_TYPE_MSG: - n = rsh_log_show_msg(hdr, p); + n = rsh_log_show_msg(hdr, p, size); p += n; + size -= n; break; default: /* Drain this message. */ @@ -896,7 +1075,11 @@ static DRIVER_ATTR_RO(lifecycle_state); static DRIVER_ATTR_RO(secure_boot_fuse_state); static DRIVER_ATTR_WO(fw_reset); static DRIVER_ATTR_RW(oob_mac); -static DRIVER_ATTR_RW(opn_str); +static DRIVER_ATTR_RW(opn); +static DRIVER_ATTR_RW(sku); +static DRIVER_ATTR_RW(modl); +static DRIVER_ATTR_RW(sn); +static DRIVER_ATTR_RW(uuid); static DRIVER_ATTR_WO(mfg_lock); static DRIVER_ATTR_RW(rsh_log); @@ -908,7 +1091,11 @@ static struct attribute *mbc_dev_attrs[] = { &driver_attr_secure_boot_fuse_state.attr, &driver_attr_fw_reset.attr, &driver_attr_oob_mac.attr, - &driver_attr_opn_str.attr, + &driver_attr_opn.attr, + &driver_attr_sku.attr, + &driver_attr_modl.attr, + &driver_attr_sn.attr, + &driver_attr_uuid.attr, &driver_attr_mfg_lock.attr, &driver_attr_rsh_log.attr, NULL @@ -1064,4 +1251,4 @@ module_platform_driver(mbc_driver); MODULE_DESCRIPTION(DRIVER_DESCRIPTION); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR("Mellanox Technologies"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual BSD/GPL");
BugLink: https://bugs.launchpad.net/bugs/1931843 The MFG partition of the EEPROM now also holds the VPD fields. With this change, the mlx-bootctl driver exposes sysfs entries for each of the newly added fields: sn, uuid, sku and modl. Also, the "opn_str" sysfs has been renamed to "opn". Signed-off-by: Shravan Kumar Ramani <shravankr@nvidia.com> --- drivers/platform/mellanox/mlx-bootctl.c | 353 ++++++++++++++++++------ 1 file changed, 270 insertions(+), 83 deletions(-)