0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/sizes.h>
0009 #include <linux/slab.h>
0010 #include <linux/tee_drv.h>
0011 #include <linux/uuid.h>
0012
0013 #include <linux/firmware/broadcom/tee_bnxt_fw.h>
0014
0015 #define MAX_SHM_MEM_SZ SZ_4M
0016
0017 #define MAX_TEE_PARAM_ARRY_MEMB 4
0018
0019 enum ta_cmd {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 TA_CMD_BNXT_FASTBOOT = 0,
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 TA_CMD_BNXT_COPY_COREDUMP = 3,
0049 };
0050
0051
0052
0053
0054
0055
0056
0057 struct tee_bnxt_fw_private {
0058 struct device *dev;
0059 struct tee_context *ctx;
0060 u32 session_id;
0061 struct tee_shm *fw_shm_pool;
0062 };
0063
0064 static struct tee_bnxt_fw_private pvt_data;
0065
0066 static void prepare_args(int cmd,
0067 struct tee_ioctl_invoke_arg *arg,
0068 struct tee_param *param)
0069 {
0070 memset(arg, 0, sizeof(*arg));
0071 memset(param, 0, MAX_TEE_PARAM_ARRY_MEMB * sizeof(*param));
0072
0073 arg->func = cmd;
0074 arg->session = pvt_data.session_id;
0075 arg->num_params = MAX_TEE_PARAM_ARRY_MEMB;
0076
0077
0078 switch (cmd) {
0079 case TA_CMD_BNXT_COPY_COREDUMP:
0080 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
0081 param[0].u.memref.shm = pvt_data.fw_shm_pool;
0082 param[0].u.memref.size = MAX_SHM_MEM_SZ;
0083 param[0].u.memref.shm_offs = 0;
0084 param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
0085 break;
0086 case TA_CMD_BNXT_FASTBOOT:
0087 default:
0088
0089 break;
0090 }
0091 }
0092
0093
0094
0095
0096
0097
0098
0099 int tee_bnxt_fw_load(void)
0100 {
0101 int ret = 0;
0102 struct tee_ioctl_invoke_arg arg;
0103 struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
0104
0105 if (!pvt_data.ctx)
0106 return -ENODEV;
0107
0108 prepare_args(TA_CMD_BNXT_FASTBOOT, &arg, param);
0109
0110 ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
0111 if (ret < 0 || arg.ret != 0) {
0112 dev_err(pvt_data.dev,
0113 "TA_CMD_BNXT_FASTBOOT invoke failed TEE err: %x, ret:%x\n",
0114 arg.ret, ret);
0115 return -EINVAL;
0116 }
0117
0118 return 0;
0119 }
0120 EXPORT_SYMBOL(tee_bnxt_fw_load);
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 int tee_bnxt_copy_coredump(void *buf, u32 offset, u32 size)
0132 {
0133 struct tee_ioctl_invoke_arg arg;
0134 struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB];
0135 void *core_data;
0136 u32 rbytes = size;
0137 u32 nbytes = 0;
0138 int ret = 0;
0139
0140 if (!pvt_data.ctx)
0141 return -ENODEV;
0142
0143 prepare_args(TA_CMD_BNXT_COPY_COREDUMP, &arg, param);
0144
0145 while (rbytes) {
0146 nbytes = rbytes;
0147
0148 nbytes = min_t(u32, rbytes, param[0].u.memref.size);
0149
0150
0151 param[1].u.value.a = offset;
0152 param[1].u.value.b = nbytes;
0153
0154 ret = tee_client_invoke_func(pvt_data.ctx, &arg, param);
0155 if (ret < 0 || arg.ret != 0) {
0156 dev_err(pvt_data.dev,
0157 "TA_CMD_BNXT_COPY_COREDUMP invoke failed TEE err: %x, ret:%x\n",
0158 arg.ret, ret);
0159 return -EINVAL;
0160 }
0161
0162 core_data = tee_shm_get_va(pvt_data.fw_shm_pool, 0);
0163 if (IS_ERR(core_data)) {
0164 dev_err(pvt_data.dev, "tee_shm_get_va failed\n");
0165 return PTR_ERR(core_data);
0166 }
0167
0168 memcpy(buf, core_data, nbytes);
0169
0170 rbytes -= nbytes;
0171 buf += nbytes;
0172 offset += nbytes;
0173 }
0174
0175 return 0;
0176 }
0177 EXPORT_SYMBOL(tee_bnxt_copy_coredump);
0178
0179 static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
0180 {
0181 return (ver->impl_id == TEE_IMPL_ID_OPTEE);
0182 }
0183
0184 static int tee_bnxt_fw_probe(struct device *dev)
0185 {
0186 struct tee_client_device *bnxt_device = to_tee_client_device(dev);
0187 int ret, err = -ENODEV;
0188 struct tee_ioctl_open_session_arg sess_arg;
0189 struct tee_shm *fw_shm_pool;
0190
0191 memset(&sess_arg, 0, sizeof(sess_arg));
0192
0193
0194 pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
0195 NULL);
0196 if (IS_ERR(pvt_data.ctx))
0197 return -ENODEV;
0198
0199
0200 export_uuid(sess_arg.uuid, &bnxt_device->id.uuid);
0201 sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
0202 sess_arg.num_params = 0;
0203
0204 ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
0205 if (ret < 0 || sess_arg.ret != 0) {
0206 dev_err(dev, "tee_client_open_session failed, err: %x\n",
0207 sess_arg.ret);
0208 err = -EINVAL;
0209 goto out_ctx;
0210 }
0211 pvt_data.session_id = sess_arg.session;
0212
0213 pvt_data.dev = dev;
0214
0215 fw_shm_pool = tee_shm_alloc_kernel_buf(pvt_data.ctx, MAX_SHM_MEM_SZ);
0216 if (IS_ERR(fw_shm_pool)) {
0217 dev_err(pvt_data.dev, "tee_shm_alloc_kernel_buf failed\n");
0218 err = PTR_ERR(fw_shm_pool);
0219 goto out_sess;
0220 }
0221
0222 pvt_data.fw_shm_pool = fw_shm_pool;
0223
0224 return 0;
0225
0226 out_sess:
0227 tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
0228 out_ctx:
0229 tee_client_close_context(pvt_data.ctx);
0230
0231 return err;
0232 }
0233
0234 static int tee_bnxt_fw_remove(struct device *dev)
0235 {
0236 tee_shm_free(pvt_data.fw_shm_pool);
0237 tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
0238 tee_client_close_context(pvt_data.ctx);
0239 pvt_data.ctx = NULL;
0240
0241 return 0;
0242 }
0243
0244 static void tee_bnxt_fw_shutdown(struct device *dev)
0245 {
0246 tee_shm_free(pvt_data.fw_shm_pool);
0247 tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
0248 tee_client_close_context(pvt_data.ctx);
0249 pvt_data.ctx = NULL;
0250 }
0251
0252 static const struct tee_client_device_id tee_bnxt_fw_id_table[] = {
0253 {UUID_INIT(0x6272636D, 0x2019, 0x0716,
0254 0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49)},
0255 {}
0256 };
0257
0258 MODULE_DEVICE_TABLE(tee, tee_bnxt_fw_id_table);
0259
0260 static struct tee_client_driver tee_bnxt_fw_driver = {
0261 .id_table = tee_bnxt_fw_id_table,
0262 .driver = {
0263 .name = KBUILD_MODNAME,
0264 .bus = &tee_bus_type,
0265 .probe = tee_bnxt_fw_probe,
0266 .remove = tee_bnxt_fw_remove,
0267 .shutdown = tee_bnxt_fw_shutdown,
0268 },
0269 };
0270
0271 static int __init tee_bnxt_fw_mod_init(void)
0272 {
0273 return driver_register(&tee_bnxt_fw_driver.driver);
0274 }
0275
0276 static void __exit tee_bnxt_fw_mod_exit(void)
0277 {
0278 driver_unregister(&tee_bnxt_fw_driver.driver);
0279 }
0280
0281 module_init(tee_bnxt_fw_mod_init);
0282 module_exit(tee_bnxt_fw_mod_exit);
0283
0284 MODULE_AUTHOR("Vikas Gupta <vikas.gupta@broadcom.com>");
0285 MODULE_DESCRIPTION("Broadcom bnxt firmware manager");
0286 MODULE_LICENSE("GPL v2");