linux/drivers/firmware/broadcom/tee_bnxt_fw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2019 Broadcom.
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/sizes.h>
   9#include <linux/slab.h>
  10#include <linux/tee_drv.h>
  11#include <linux/uuid.h>
  12
  13#include <linux/firmware/broadcom/tee_bnxt_fw.h>
  14
  15#define MAX_SHM_MEM_SZ  SZ_4M
  16
  17#define MAX_TEE_PARAM_ARRY_MEMB         4
  18
  19enum ta_cmd {
  20        /*
  21         * TA_CMD_BNXT_FASTBOOT - boot bnxt device by copying f/w into sram
  22         *
  23         *      param[0] unused
  24         *      param[1] unused
  25         *      param[2] unused
  26         *      param[3] unused
  27         *
  28         * Result:
  29         *      TEE_SUCCESS - Invoke command success
  30         *      TEE_ERROR_ITEM_NOT_FOUND - Corrupt f/w image found on memory
  31         */
  32        TA_CMD_BNXT_FASTBOOT = 0,
  33
  34        /*
  35         * TA_CMD_BNXT_COPY_COREDUMP - copy the core dump into shm
  36         *
  37         *      param[0] (inout memref) - Coredump buffer memory reference
  38         *      param[1] (in value) - value.a: offset, data to be copied from
  39         *                            value.b: size of data to be copied
  40         *      param[2] unused
  41         *      param[3] unused
  42         *
  43         * Result:
  44         *      TEE_SUCCESS - Invoke command success
  45         *      TEE_ERROR_BAD_PARAMETERS - Incorrect input param
  46         *      TEE_ERROR_ITEM_NOT_FOUND - Corrupt core dump
  47         */
  48        TA_CMD_BNXT_COPY_COREDUMP = 3,
  49};
  50
  51/**
  52 * struct tee_bnxt_fw_private - OP-TEE bnxt private data
  53 * @dev:                OP-TEE based bnxt device.
  54 * @ctx:                OP-TEE context handler.
  55 * @session_id:         TA session identifier.
  56 */
  57struct tee_bnxt_fw_private {
  58        struct device *dev;
  59        struct tee_context *ctx;
  60        u32 session_id;
  61        struct tee_shm *fw_shm_pool;
  62};
  63
  64static struct tee_bnxt_fw_private pvt_data;
  65
  66static void prepare_args(int cmd,
  67                         struct tee_ioctl_invoke_arg *arg,
  68                         struct tee_param *param)
  69{
  70        memset(arg, 0, sizeof(*arg));
  71        memset(param, 0, MAX_TEE_PARAM_ARRY_MEMB * sizeof(*param));
  72
  73        arg->func = cmd;
  74        arg->session = pvt_data.session_id;
  75        arg->num_params = MAX_TEE_PARAM_ARRY_MEMB;
  76
  77        /* Fill invoke cmd params */
  78        switch (cmd) {
  79        case TA_CMD_BNXT_COPY_COREDUMP:
  80                param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
  81                param[0].u.memref.shm = pvt_data.fw_shm_pool;
  82                param[0].u.memref.size = MAX_SHM_MEM_SZ;
  83                param[0].u.memref.shm_offs = 0;
  84                param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
  85                break;
  86        case TA_CMD_BNXT_FASTBOOT:
  87        default:
  88                /* Nothing to do */
  89                break;
  90        }
  91}
  92
  93/**
  94 * tee_bnxt_fw_load() - Load the bnxt firmware
  95 *                  Uses an OP-TEE call to start a secure
  96 *                  boot process.
  97 * Returns 0 on success, negative errno otherwise.
  98 */
  99int tee_bnxt_fw_load(void)
 100{
 101        int ret = 0;
 102        struct tee_ioctl_invoke_arg arg;
 103        struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
 104
 105        if (!pvt_data.ctx)
 106                return -ENODEV;
 107
 108        prepare_args(TA_CMD_BNXT_FASTBOOT, &arg, param);
 109
 110        ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
 111        if (ret < 0 || arg.ret != 0) {
 112                dev_err(pvt_data.dev,
 113                        "TA_CMD_BNXT_FASTBOOT invoke failed TEE err: %x, ret:%x\n",
 114                        arg.ret, ret);
 115                return -EINVAL;
 116        }
 117
 118        return 0;
 119}
 120EXPORT_SYMBOL(tee_bnxt_fw_load);
 121
 122/**
 123 * tee_bnxt_copy_coredump() - Copy coredump from the allocated memory
 124 *                          Uses an OP-TEE call to copy coredump
 125 * @buf:        destination buffer where core dump is copied into
 126 * @offset:     offset from the base address of core dump area
 127 * @size:       size of the dump
 128 *
 129 * Returns 0 on success, negative errno otherwise.
 130 */
 131int tee_bnxt_copy_coredump(void *buf, u32 offset, u32 size)
 132{
 133        struct tee_ioctl_invoke_arg arg;
 134        struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
 135        void *core_data;
 136        u32 rbytes = size;
 137        u32 nbytes = 0;
 138        int ret = 0;
 139
 140        if (!pvt_data.ctx)
 141                return -ENODEV;
 142
 143        prepare_args(TA_CMD_BNXT_COPY_COREDUMP, &arg, param);
 144
 145        while (rbytes)  {
 146                nbytes = rbytes;
 147
 148                nbytes = min_t(u32, rbytes, param[0].u.memref.size);
 149
 150                /* Fill additional invoke cmd params */
 151                param[1].u.value.a = offset;
 152                param[1].u.value.b = nbytes;
 153
 154                ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
 155                if (ret < 0 || arg.ret != 0) {
 156                        dev_err(pvt_data.dev,
 157                                "TA_CMD_BNXT_COPY_COREDUMP invoke failed TEE err: %x, ret:%x\n",
 158                                arg.ret, ret);
 159                        return -EINVAL;
 160                }
 161
 162                core_data = tee_shm_get_va(pvt_data.fw_shm_pool, 0);
 163                if (IS_ERR(core_data)) {
 164                        dev_err(pvt_data.dev, "tee_shm_get_va failed\n");
 165                        return PTR_ERR(core_data);
 166                }
 167
 168                memcpy(buf, core_data, nbytes);
 169
 170                rbytes -= nbytes;
 171                buf += nbytes;
 172                offset += nbytes;
 173        }
 174
 175        return 0;
 176}
 177EXPORT_SYMBOL(tee_bnxt_copy_coredump);
 178
 179static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
 180{
 181        return (ver->impl_id == TEE_IMPL_ID_OPTEE);
 182}
 183
 184static int tee_bnxt_fw_probe(struct device *dev)
 185{
 186        struct tee_client_device *bnxt_device = to_tee_client_device(dev);
 187        int ret, err = -ENODEV;
 188        struct tee_ioctl_open_session_arg sess_arg;
 189        struct tee_shm *fw_shm_pool;
 190
 191        memset(&sess_arg, 0, sizeof(sess_arg));
 192
 193        /* Open context with TEE driver */
 194        pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
 195                                               NULL);
 196        if (IS_ERR(pvt_data.ctx))
 197                return -ENODEV;
 198
 199        /* Open session with Bnxt load Trusted App */
 200        memcpy(sess_arg.uuid, bnxt_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
 201        sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
 202        sess_arg.num_params = 0;
 203
 204        ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
 205        if (ret < 0 || sess_arg.ret != 0) {
 206                dev_err(dev, "tee_client_open_session failed, err: %x\n",
 207                        sess_arg.ret);
 208                err = -EINVAL;
 209                goto out_ctx;
 210        }
 211        pvt_data.session_id = sess_arg.session;
 212
 213        pvt_data.dev = dev;
 214
 215        fw_shm_pool = tee_shm_alloc_kernel_buf(pvt_data.ctx, MAX_SHM_MEM_SZ);
 216        if (IS_ERR(fw_shm_pool)) {
 217                dev_err(pvt_data.dev, "tee_shm_alloc_kernel_buf failed\n");
 218                err = PTR_ERR(fw_shm_pool);
 219                goto out_sess;
 220        }
 221
 222        pvt_data.fw_shm_pool = fw_shm_pool;
 223
 224        return 0;
 225
 226out_sess:
 227        tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
 228out_ctx:
 229        tee_client_close_context(pvt_data.ctx);
 230
 231        return err;
 232}
 233
 234static int tee_bnxt_fw_remove(struct device *dev)
 235{
 236        tee_shm_free(pvt_data.fw_shm_pool);
 237        tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
 238        tee_client_close_context(pvt_data.ctx);
 239        pvt_data.ctx = NULL;
 240
 241        return 0;
 242}
 243
 244static void tee_bnxt_fw_shutdown(struct device *dev)
 245{
 246        tee_shm_free(pvt_data.fw_shm_pool);
 247        tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
 248        tee_client_close_context(pvt_data.ctx);
 249        pvt_data.ctx = NULL;
 250}
 251
 252static const struct tee_client_device_id tee_bnxt_fw_id_table[] = {
 253        {UUID_INIT(0x6272636D, 0x2019, 0x0716,
 254                    0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49)},
 255        {}
 256};
 257
 258MODULE_DEVICE_TABLE(tee, tee_bnxt_fw_id_table);
 259
 260static struct tee_client_driver tee_bnxt_fw_driver = {
 261        .id_table       = tee_bnxt_fw_id_table,
 262        .driver         = {
 263                .name           = KBUILD_MODNAME,
 264                .bus            = &tee_bus_type,
 265                .probe          = tee_bnxt_fw_probe,
 266                .remove         = tee_bnxt_fw_remove,
 267                .shutdown       = tee_bnxt_fw_shutdown,
 268        },
 269};
 270
 271static int __init tee_bnxt_fw_mod_init(void)
 272{
 273        return driver_register(&tee_bnxt_fw_driver.driver);
 274}
 275
 276static void __exit tee_bnxt_fw_mod_exit(void)
 277{
 278        driver_unregister(&tee_bnxt_fw_driver.driver);
 279}
 280
 281module_init(tee_bnxt_fw_mod_init);
 282module_exit(tee_bnxt_fw_mod_exit);
 283
 284MODULE_AUTHOR("Vikas Gupta <vikas.gupta@broadcom.com>");
 285MODULE_DESCRIPTION("Broadcom bnxt firmware manager");
 286MODULE_LICENSE("GPL v2");
 287