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