linux/drivers/tee/optee/core.c
Linus Torvalds bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00

280 lines
6.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, Linaro Limited
* Copyright (c) 2016, EPAM Systems
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/crash_dump.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/rpmb.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tee_core.h>
#include <linux/types.h>
#include "optee_private.h"
struct blocking_notifier_head optee_rpmb_intf_added =
BLOCKING_NOTIFIER_INIT(optee_rpmb_intf_added);
static int rpmb_add_dev(struct device *dev)
{
blocking_notifier_call_chain(&optee_rpmb_intf_added, 0,
to_rpmb_dev(dev));
return 0;
}
static struct class_interface rpmb_class_intf = {
.add_dev = rpmb_add_dev,
};
void optee_bus_scan_rpmb(struct work_struct *work)
{
struct optee *optee = container_of(work, struct optee,
rpmb_scan_bus_work);
int ret;
if (!optee->rpmb_scan_bus_done) {
ret = optee_enumerate_devices(PTA_CMD_GET_DEVICES_RPMB);
optee->rpmb_scan_bus_done = !ret;
if (ret && ret != -ENODEV)
pr_info("Scanning for RPMB device: ret %d\n", ret);
}
}
int optee_rpmb_intf_rdev(struct notifier_block *intf, unsigned long action,
void *data)
{
struct optee *optee = container_of(intf, struct optee, rpmb_intf);
schedule_work(&optee->rpmb_scan_bus_work);
return 0;
}
int optee_set_dma_mask(struct optee *optee, u_int pa_width)
{
u64 mask = DMA_BIT_MASK(min(64, pa_width));
return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
}
int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
{
struct optee *optee = tee_get_drvdata(teedev);
u64 build_id;
if (!optee)
return -ENODEV;
if (!buf || !len)
return -EINVAL;
build_id = optee->revision.os_build_id;
if (build_id)
scnprintf(buf, len, "%u.%u (%016llx)",
optee->revision.os_major,
optee->revision.os_minor,
(unsigned long long)build_id);
else
scnprintf(buf, len, "%u.%u", optee->revision.os_major,
optee->revision.os_minor);
return 0;
}
static void optee_bus_scan(struct work_struct *work)
{
WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
}
static ssize_t rpmb_routing_model_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct optee *optee = dev_get_drvdata(dev);
const char *s;
if (optee->in_kernel_rpmb_routing)
s = "kernel";
else
s = "user";
return sysfs_emit(buf, "%s\n", s);
}
static DEVICE_ATTR_RO(rpmb_routing_model);
static struct attribute *optee_dev_attrs[] = {
&dev_attr_rpmb_routing_model.attr,
NULL
};
ATTRIBUTE_GROUPS(optee_dev);
void optee_set_dev_group(struct optee *optee)
{
tee_device_set_dev_groups(optee->teedev, optee_dev_groups);
tee_device_set_dev_groups(optee->supp_teedev, optee_dev_groups);
}
int optee_open(struct tee_context *ctx, bool cap_memref_null)
{
struct optee_context_data *ctxdata;
struct tee_device *teedev = ctx->teedev;
struct optee *optee = tee_get_drvdata(teedev);
ctxdata = kzalloc_obj(*ctxdata);
if (!ctxdata)
return -ENOMEM;
if (teedev == optee->supp_teedev) {
bool busy = true;
mutex_lock(&optee->supp.mutex);
if (!optee->supp.ctx) {
busy = false;
optee->supp.ctx = ctx;
}
mutex_unlock(&optee->supp.mutex);
if (busy) {
kfree(ctxdata);
return -EBUSY;
}
if (!optee->scan_bus_done) {
INIT_WORK(&optee->scan_bus_work, optee_bus_scan);
schedule_work(&optee->scan_bus_work);
optee->scan_bus_done = true;
}
}
mutex_init(&ctxdata->mutex);
INIT_LIST_HEAD(&ctxdata->sess_list);
ctx->cap_memref_null = cap_memref_null;
ctx->data = ctxdata;
return 0;
}
static void optee_release_helper(struct tee_context *ctx,
int (*close_session)(struct tee_context *ctx,
u32 session,
bool system_thread))
{
struct optee_context_data *ctxdata = ctx->data;
struct optee_session *sess;
struct optee_session *sess_tmp;
if (!ctxdata)
return;
list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
list_node) {
list_del(&sess->list_node);
close_session(ctx, sess->session_id, sess->use_sys_thread);
kfree(sess);
}
kfree(ctxdata);
ctx->data = NULL;
}
void optee_release(struct tee_context *ctx)
{
optee_release_helper(ctx, optee_close_session_helper);
}
void optee_release_supp(struct tee_context *ctx)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
optee_release_helper(ctx, optee_close_session_helper);
optee_supp_release(&optee->supp);
}
void optee_remove_common(struct optee *optee)
{
blocking_notifier_chain_unregister(&optee_rpmb_intf_added,
&optee->rpmb_intf);
cancel_work_sync(&optee->rpmb_scan_bus_work);
/* Unregister OP-TEE specific client devices on TEE bus */
optee_unregister_devices();
optee_notif_uninit(optee);
optee_shm_arg_cache_uninit(optee);
teedev_close_context(optee->ctx);
/*
* The two devices have to be unregistered before we can free the
* other resources.
*/
tee_device_unregister(optee->supp_teedev);
tee_device_unregister(optee->teedev);
tee_shm_pool_free(optee->pool);
optee_supp_uninit(&optee->supp);
mutex_destroy(&optee->call_queue.mutex);
rpmb_dev_put(optee->rpmb_dev);
mutex_destroy(&optee->rpmb_dev_mutex);
}
static int smc_abi_rc;
static int ffa_abi_rc;
static bool intf_is_regged;
static int __init optee_core_init(void)
{
int rc;
/*
* The kernel may have crashed at the same time that all available
* secure world threads were suspended and we cannot reschedule the
* suspended threads without access to the crashed kernel's wait_queue.
* Therefore, we cannot reliably initialize the OP-TEE driver in the
* kdump kernel.
*/
if (is_kdump_kernel())
return -ENODEV;
if (IS_REACHABLE(CONFIG_RPMB)) {
rc = rpmb_interface_register(&rpmb_class_intf);
if (rc)
return rc;
intf_is_regged = true;
}
smc_abi_rc = optee_smc_abi_register();
ffa_abi_rc = optee_ffa_abi_register();
/* If both failed there's no point with this module */
if (smc_abi_rc && ffa_abi_rc) {
if (IS_REACHABLE(CONFIG_RPMB)) {
rpmb_interface_unregister(&rpmb_class_intf);
intf_is_regged = false;
}
return smc_abi_rc;
}
return 0;
}
module_init(optee_core_init);
static void __exit optee_core_exit(void)
{
if (IS_REACHABLE(CONFIG_RPMB) && intf_is_regged) {
rpmb_interface_unregister(&rpmb_class_intf);
intf_is_regged = false;
}
if (!smc_abi_rc)
optee_smc_abi_unregister();
if (!ffa_abi_rc)
optee_ffa_abi_unregister();
}
module_exit(optee_core_exit);
MODULE_AUTHOR("Linaro");
MODULE_DESCRIPTION("OP-TEE driver");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:optee");