Commit bcbf0531 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'tee-optee-pldrv-for-5.6' of...

Merge tag 'tee-optee-pldrv-for-5.6' of git://git.linaro.org:/people/jens.wiklander/linux-tee into arm/drivers

Model OP-TEE as a platform device/driver

* tag 'tee-optee-pldrv-for-5.6' of git://git.linaro.org:/people/jens.wiklander/linux-tee:
  optee: model OP-TEE as a platform device/driver

Link: https://lore.kernel.org/r/20200103090025.GA11243@jax


Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 965af1cf f349710e
Loading
Loading
Loading
Loading
+64 −89
Original line number Diff line number Diff line
@@ -534,13 +534,13 @@ static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
}

static optee_invoke_fn *get_invoke_func(struct device_node *np)
static optee_invoke_fn *get_invoke_func(struct device *dev)
{
	const char *method;

	pr_info("probing for conduit method from DT.\n");
	pr_info("probing for conduit method.\n");

	if (of_property_read_string(np, "method", &method)) {
	if (device_property_read_string(dev, "method", &method)) {
		pr_warn("missing \"method\" property\n");
		return ERR_PTR(-ENXIO);
	}
@@ -554,7 +554,37 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np)
	return ERR_PTR(-EINVAL);
}

static struct optee *optee_probe(struct device_node *np)
static int optee_remove(struct platform_device *pdev)
{
	struct optee *optee = platform_get_drvdata(pdev);

	/*
	 * Ask OP-TEE to free all cached shared memory objects to decrease
	 * reference counters and also avoid wild pointers in secure world
	 * into the old shared memory range.
	 */
	optee_disable_shm_cache(optee);

	/*
	 * 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);
	if (optee->memremaped_shm)
		memunmap(optee->memremaped_shm);
	optee_wait_queue_exit(&optee->wait_queue);
	optee_supp_uninit(&optee->supp);
	mutex_destroy(&optee->call_queue.mutex);

	kfree(optee);

	return 0;
}

static int optee_probe(struct platform_device *pdev)
{
	optee_invoke_fn *invoke_fn;
	struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
@@ -564,25 +594,25 @@ static struct optee *optee_probe(struct device_node *np)
	u32 sec_caps;
	int rc;

	invoke_fn = get_invoke_func(np);
	invoke_fn = get_invoke_func(&pdev->dev);
	if (IS_ERR(invoke_fn))
		return (void *)invoke_fn;
		return PTR_ERR(invoke_fn);

	if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
		pr_warn("api uid mismatch\n");
		return ERR_PTR(-EINVAL);
		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 ERR_PTR(-EINVAL);
		return -EINVAL;
	}

	if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) {
		pr_warn("capabilities mismatch\n");
		return ERR_PTR(-EINVAL);
		return -EINVAL;
	}

	/*
@@ -598,7 +628,7 @@ static struct optee *optee_probe(struct device_node *np)
		pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);

	if (IS_ERR(pool))
		return (void *)pool;
		return PTR_ERR(pool);

	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
	if (!optee) {
@@ -643,7 +673,16 @@ static struct optee *optee_probe(struct device_node *np)
	if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
		pr_info("dynamic shared memory is enabled\n");

	return optee;
	platform_set_drvdata(pdev, optee);

	rc = optee_enumerate_devices();
	if (rc) {
		optee_remove(pdev);
		return rc;
	}

	pr_info("initialized driver\n");
	return 0;
err:
	if (optee) {
		/*
@@ -659,92 +698,28 @@ static struct optee *optee_probe(struct device_node *np)
		tee_shm_pool_free(pool);
	if (memremaped_shm)
		memunmap(memremaped_shm);
	return ERR_PTR(rc);
}

static void optee_remove(struct optee *optee)
{
	/*
	 * Ask OP-TEE to free all cached shared memory objects to decrease
	 * reference counters and also avoid wild pointers in secure world
	 * into the old shared memory range.
	 */
	optee_disable_shm_cache(optee);

	/*
	 * The two devices has 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);
	if (optee->memremaped_shm)
		memunmap(optee->memremaped_shm);
	optee_wait_queue_exit(&optee->wait_queue);
	optee_supp_uninit(&optee->supp);
	mutex_destroy(&optee->call_queue.mutex);

	kfree(optee);
	return rc;
}

static const struct of_device_id optee_match[] = {
static const struct of_device_id optee_dt_match[] = {
	{ .compatible = "linaro,optee-tz" },
	{},
};

static struct optee *optee_svc;

static int __init optee_driver_init(void)
{
	struct device_node *fw_np = NULL;
	struct device_node *np = NULL;
	struct optee *optee = NULL;
	int rc = 0;

	/* Node is supposed to be below /firmware */
	fw_np = of_find_node_by_name(NULL, "firmware");
	if (!fw_np)
		return -ENODEV;

	np = of_find_matching_node(fw_np, optee_match);
	if (!np || !of_device_is_available(np)) {
		of_node_put(np);
		return -ENODEV;
	}

	optee = optee_probe(np);
	of_node_put(np);

	if (IS_ERR(optee))
		return PTR_ERR(optee);

	rc = optee_enumerate_devices();
	if (rc) {
		optee_remove(optee);
		return rc;
	}

	pr_info("initialized driver\n");

	optee_svc = optee;

	return 0;
}
module_init(optee_driver_init);

static void __exit optee_driver_exit(void)
{
	struct optee *optee = optee_svc;

	optee_svc = NULL;
	if (optee)
		optee_remove(optee);
}
module_exit(optee_driver_exit);
MODULE_DEVICE_TABLE(of, optee_dt_match);

static struct platform_driver optee_driver = {
	.probe  = optee_probe,
	.remove = optee_remove,
	.driver = {
		.name = "optee",
		.of_match_table = optee_dt_match,
	},
};
module_platform_driver(optee_driver);

MODULE_AUTHOR("Linaro");
MODULE_DESCRIPTION("OP-TEE driver");
MODULE_SUPPORTED_DEVICE("");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:optee");