static int optee_ffa_probe()

in optee/ffa_abi.c [792:886]


static int optee_ffa_probe(struct ffa_device *ffa_dev)
{
	const struct ffa_dev_ops *ffa_ops;
	unsigned int rpc_arg_count;
	struct tee_device *teedev;
	struct optee *optee;
	int rc;

	ffa_ops = ffa_dev_ops_get(ffa_dev);
	if (!ffa_ops) {
		pr_warn("failed \"method\" init: ffa\n");
		return -ENOENT;
	}

	if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops))
		return -EINVAL;

	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &rpc_arg_count))
		return -EINVAL;

	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
	if (!optee)
		return -ENOMEM;

	optee->pool = optee_ffa_config_dyn_shm();
	if (IS_ERR(optee->pool)) {
		rc = PTR_ERR(optee->pool);
		optee->pool = NULL;
		goto err;
	}

	optee->ops = &optee_ffa_ops;
	optee->ffa.ffa_dev = ffa_dev;
	optee->ffa.ffa_ops = ffa_ops;
	optee->rpc_arg_count = rpc_arg_count;

	teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,
				  optee);
	if (IS_ERR(teedev)) {
		rc = PTR_ERR(teedev);
		goto err;
	}
	optee->teedev = teedev;

	teedev = tee_device_alloc(&optee_ffa_supp_desc, NULL, optee->pool,
				  optee);
	if (IS_ERR(teedev)) {
		rc = PTR_ERR(teedev);
		goto err;
	}
	optee->supp_teedev = teedev;

	rc = tee_device_register(optee->teedev);
	if (rc)
		goto err;

	rc = tee_device_register(optee->supp_teedev);
	if (rc)
		goto err;

	rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
	if (rc)
		goto err;
	mutex_init(&optee->ffa.mutex);
	mutex_init(&optee->call_queue.mutex);
	INIT_LIST_HEAD(&optee->call_queue.waiters);
	optee_supp_init(&optee->supp);
	ffa_dev_set_drvdata(ffa_dev, optee);
	rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
	if (rc) {
		optee_ffa_remove(ffa_dev);
		return rc;
	}

	rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
	if (rc) {
		optee_ffa_remove(ffa_dev);
		return rc;
	}

	pr_info("initialized driver\n");
	return 0;
err:
	/*
	 * tee_device_unregister() is safe to call even if the
	 * devices hasn't been registered with
	 * tee_device_register() yet.
	 */
	tee_device_unregister(optee->supp_teedev);
	tee_device_unregister(optee->teedev);
	if (optee->pool)
		tee_shm_pool_free(optee->pool);
	kfree(optee);
	return rc;
}