in optee/smc_abi.c [1362:1513]
static int optee_probe(struct platform_device *pdev)
{
optee_invoke_fn *invoke_fn;
struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
struct optee *optee = NULL;
void *memremaped_shm = NULL;
struct tee_device *teedev;
u32 max_notif_value;
u32 sec_caps;
int rc;
invoke_fn = get_invoke_func(&pdev->dev);
if (IS_ERR(invoke_fn))
return PTR_ERR(invoke_fn);
if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
pr_warn("api uid mismatch\n");
return -EINVAL;
}
optee_msg_get_os_revision(invoke_fn);
if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
pr_warn("api revision mismatch\n");
return -EINVAL;
}
if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps,
&max_notif_value)) {
pr_warn("capabilities mismatch\n");
return -EINVAL;
}
/*
* Try to use dynamic shared memory if possible
*/
if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
pool = optee_config_dyn_shm();
/*
* If dynamic shared memory is not available or failed - try static one
*/
if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
if (IS_ERR(pool))
return PTR_ERR(pool);
optee = kzalloc(sizeof(*optee), GFP_KERNEL);
if (!optee) {
rc = -ENOMEM;
goto err_free_pool;
}
optee->ops = &optee_ops;
optee->smc.invoke_fn = invoke_fn;
optee->smc.sec_caps = sec_caps;
teedev = tee_device_alloc(&optee_clnt_desc, NULL, pool, optee);
if (IS_ERR(teedev)) {
rc = PTR_ERR(teedev);
goto err_free_optee;
}
optee->teedev = teedev;
teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
if (IS_ERR(teedev)) {
rc = PTR_ERR(teedev);
goto err_unreg_teedev;
}
optee->supp_teedev = teedev;
rc = tee_device_register(optee->teedev);
if (rc)
goto err_unreg_supp_teedev;
rc = tee_device_register(optee->supp_teedev);
if (rc)
goto err_unreg_supp_teedev;
mutex_init(&optee->call_queue.mutex);
INIT_LIST_HEAD(&optee->call_queue.waiters);
optee_supp_init(&optee->supp);
optee->smc.memremaped_shm = memremaped_shm;
optee->pool = pool;
platform_set_drvdata(pdev, optee);
rc = optee_notif_init(optee, max_notif_value);
if (rc)
goto err_supp_uninit;
if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
unsigned int irq;
rc = platform_get_irq(pdev, 0);
if (rc < 0) {
pr_err("platform_get_irq: ret %d\n", rc);
goto err_notif_uninit;
}
irq = rc;
rc = optee_smc_notif_init_irq(optee, irq);
if (rc) {
irq_dispose_mapping(irq);
goto err_notif_uninit;
}
enable_async_notif(optee->smc.invoke_fn);
pr_info("Asynchronous notifications enabled\n");
}
/*
* Ensure that there are no pre-existing shm objects before enabling
* the shm cache so that there's no chance of receiving an invalid
* address during shutdown. This could occur, for example, if we're
* kexec booting from an older kernel that did not properly cleanup the
* shm cache.
*/
optee_disable_unmapped_shm_cache(optee);
optee_enable_shm_cache(optee);
if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
pr_info("dynamic shared memory is enabled\n");
rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
if (rc)
goto err_disable_shm_cache;
pr_info("initialized driver\n");
return 0;
err_disable_shm_cache:
optee_disable_shm_cache(optee);
optee_smc_notif_uninit_irq(optee);
optee_unregister_devices();
err_notif_uninit:
optee_notif_uninit(optee);
err_supp_uninit:
optee_supp_uninit(&optee->supp);
mutex_destroy(&optee->call_queue.mutex);
err_unreg_supp_teedev:
tee_device_unregister(optee->supp_teedev);
err_unreg_teedev:
tee_device_unregister(optee->teedev);
err_free_optee:
kfree(optee);
err_free_pool:
tee_shm_pool_free(pool);
if (memremaped_shm)
memunmap(memremaped_shm);
return rc;
}