Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b7ea909 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "shmbridge: some improvements for shmbridge driver"

parents c413877b 4f0b20ff
Loading
Loading
Loading
Loading
+122 −34
Original line number Diff line number Diff line
@@ -93,10 +93,22 @@ struct bridge_info {
	int min_alloc_order;
	struct gen_pool *genpool;
};

struct bridge_list {
	struct list_head head;
	struct mutex lock;
};

struct bridge_list_entry {
	struct list_head list;
	phys_addr_t paddr;
	uint64_t handle;
};

static struct bridge_info default_bridge;
static struct bridge_list bridge_list_head;
static bool qtee_shmbridge_enabled;


/* enable shared memory bridge mechanism in HYP */
static int32_t qtee_shmbridge_enable(bool enable)
{
@@ -114,7 +126,7 @@ static int32_t qtee_shmbridge_enable(bool enable)
	if (ret) {
		pr_err("Failed to enable shmbridge, rsp = %lld, ret = %d\n",
			desc.ret[0], ret);
		return -EINVAL;
		return ret;
	}
	qtee_shmbridge_enabled = true;
	pr_warn("shmbridge is enabled\n");
@@ -128,6 +140,56 @@ bool qtee_shmbridge_is_enabled(void)
}
EXPORT_SYMBOL(qtee_shmbridge_is_enabled);

int32_t qtee_shmbridge_list_add_nolock(phys_addr_t paddr, uint64_t handle)
{
	struct bridge_list_entry *entry;

	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;
	entry->handle = handle;
	entry->paddr = paddr;
	list_add_tail(&entry->list, &bridge_list_head.head);
	return 0;
}

void qtee_shmbridge_list_del_nolock(uint64_t handle)
{
	struct bridge_list_entry *entry;

	list_for_each_entry(entry, &bridge_list_head.head, list) {
		if (entry->handle == handle) {
			list_del(&entry->list);
			kfree(entry);
			break;
		}
	}
}

int32_t qtee_shmbridge_query_nolock(phys_addr_t paddr)
{
	struct bridge_list_entry *entry;

	list_for_each_entry(entry, &bridge_list_head.head, list)
		if (entry->paddr == paddr) {
			pr_debug("A bridge on %llx exists\n", (uint64_t)paddr);
			return -EEXIST;
		}
	return 0;
}

/* Check whether a bridge starting from paddr exists */
int32_t qtee_shmbridge_query(phys_addr_t paddr)
{
	int32_t ret = 0;

	mutex_lock(&bridge_list_head.lock);
	ret = qtee_shmbridge_query_nolock(paddr);
	mutex_unlock(&bridge_list_head.lock);
	return ret;
}
EXPORT_SYMBOL(qtee_shmbridge_query);

/* Register paddr & size as a bridge, return bridge handle */
int32_t qtee_shmbridge_register(
		phys_addr_t paddr,
@@ -145,12 +207,20 @@ int32_t qtee_shmbridge_register(
	struct scm_desc desc = {0};
	int i = 0;

	if (!qtee_shmbridge_enabled)
		return 0;

	if (!handle || !ns_vmid_list || !ns_vm_perm_list ||
				ns_vmid_num > MAXSHMVMS) {
		pr_err("invalid input parameters\n");
		return -EINVAL;
	}

	mutex_lock(&bridge_list_head.lock);
	ret = qtee_shmbridge_query_nolock(paddr);
	if (ret)
		goto exit;

	for (i = 0; i < ns_vmid_num; i++) {
		ns_perms = UPDATE_NS_PERMS(ns_perms, ns_vm_perm_list[i]);
		ns_vmids = UPDATE_NS_VMIDS(ns_vmids, ns_vmid_list[i]);
@@ -169,10 +239,15 @@ int32_t qtee_shmbridge_register(
	if (ret || desc.ret[0]) {
		pr_err("create shmbridge failed, ret = %d, status = %llx\n",
				ret, desc.ret[0]);
		return -EINVAL;
		ret = -EINVAL;
		goto exit;
	}
	*handle = desc.ret[1];
	return 0;

	ret = qtee_shmbridge_list_add_nolock(paddr, *handle);
exit:
	mutex_unlock(&bridge_list_head.lock);
	return ret;
}
EXPORT_SYMBOL(qtee_shmbridge_register);

@@ -182,14 +257,22 @@ int32_t qtee_shmbridge_deregister(uint64_t handle)
	int32_t ret = 0;
	struct scm_desc desc = {0};

	if (!qtee_shmbridge_enabled)
		return 0;

	mutex_lock(&bridge_list_head.lock);
	desc.arginfo = TZ_SHM_BRIDGE_DELETE_PARAM_ID;
	desc.args[0] = handle;
	ret = scm_call2(TZ_SHM_BRIDGE_DELETE, &desc);
	if (ret) {
		pr_err("scm_call to delete shmbridge failed, ret = %d\n", ret);
		return ret;
		pr_err("Failed to del bridge %lld, ret = %d\n", handle, ret);
		goto exit;
	}
	return 0;
	qtee_shmbridge_list_del_nolock(handle);

exit:
	mutex_unlock(&bridge_list_head.lock);
	return ret;
}
EXPORT_SYMBOL(qtee_shmbridge_deregister);

@@ -238,7 +321,7 @@ EXPORT_SYMBOL(qtee_shmbridge_allocate_shm);
/* Free buffer that is sub-allocated from default kernel bridge */
void qtee_shmbridge_free_shm(struct qtee_shm *shm)
{
	if (IS_ERR_OR_NULL(shm))
	if (IS_ERR_OR_NULL(shm) || !shm->vaddr)
		return;
	gen_pool_free(default_bridge.genpool, (unsigned long)shm->vaddr,
		      shm->size);
@@ -257,34 +340,16 @@ static int __init qtee_shmbridge_init(void)

	if (default_bridge.vaddr) {
		pr_warn("qtee shmbridge is already initialized\n");
		goto exit;
		return 0;
	}

	/* do not enable shm bridge mechanism for now*/
	ret = qtee_shmbridge_enable(false);
	if (ret)
		goto exit;

	/* allocate a contiguous buffer */
	default_bridge.size = DEFAULT_BRIDGE_SIZE;
	default_bridge.vaddr = kzalloc(default_bridge.size, GFP_KERNEL);
	if (!default_bridge.vaddr) {
		ret = -ENOMEM;
		goto exit;
	}
	if (!default_bridge.vaddr)
		return -ENOMEM;
	default_bridge.paddr = virt_to_phys(default_bridge.vaddr);

	/*register default bridge*/
	ret = qtee_shmbridge_register(default_bridge.paddr,
			default_bridge.size, ns_vm_ids,
			ns_vm_perms, 1, VM_PERM_R|VM_PERM_W,
			&default_bridge.handle);
	if (ret) {
		pr_err("Failed to register default bridge, size %zu\n",
			default_bridge.size);
		goto exit_freebuf;
	}

	/* create a general mem pool */
	default_bridge.min_alloc_order = 3; /* 8 byte aligned */
	default_bridge.genpool = gen_pool_create(
@@ -292,7 +357,7 @@ static int __init qtee_shmbridge_init(void)
	if (!default_bridge.genpool) {
		pr_err("gen_pool_add_virt() failed\n");
		ret = -ENOMEM;
		goto exit_dereg;
		goto exit_freebuf;
	}

	gen_pool_set_algo(default_bridge.genpool, gen_pool_best_fit, NULL);
@@ -300,19 +365,42 @@ static int __init qtee_shmbridge_init(void)
			(uintptr_t)default_bridge.vaddr,
				default_bridge.paddr, default_bridge.size, -1);
	if (ret) {
		pr_err("gen_pool_add_virt() failed\n");
		pr_err("gen_pool_add_virt() failed, ret = %d\n", ret);
		goto exit_destroy_pool;
	}

	pr_warn("qtee shmbridge registered default bridge with size %d bytes\n",
	mutex_init(&bridge_list_head.lock);
	INIT_LIST_HEAD(&bridge_list_head.head);

	/* do not enable shm bridge mechanism for now*/
	ret = qtee_shmbridge_enable(false);
	if (ret) {
		if (ret == -EIO) {
			/* keep the mem pool even shmbridge isn't supported */
			pr_warn("shmbridge feature is not supported\n");
			ret = 0;
		}
		goto exit;
	}

	/*register default bridge*/
	ret = qtee_shmbridge_register(default_bridge.paddr,
			default_bridge.size, ns_vm_ids,
			ns_vm_perms, 1, VM_PERM_R|VM_PERM_W,
			&default_bridge.handle);
	if (ret) {
		pr_err("Failed to register default bridge, size %zu\n",
			default_bridge.size);
		goto exit;
	}

	pr_debug("qtee shmbridge registered default bridge with size %d bytes\n",
			DEFAULT_BRIDGE_SIZE);

	return 0;

exit_destroy_pool:
	gen_pool_destroy(default_bridge.genpool);
exit_dereg:
	qtee_shmbridge_deregister(default_bridge.handle);
exit_freebuf:
	kfree(default_bridge.vaddr);
exit:
+10 −1
Original line number Diff line number Diff line
@@ -28,10 +28,19 @@ struct qtee_shm {
 */
bool qtee_shmbridge_is_enabled(void);

/**
 * Check whether a bridge starting from paddr exists
 *
 * @ [IN] paddr: physical addr of the buffer
 *
 * return 0 or -EEXIST
 */
int32_t qtee_shmbridge_query(phys_addr_t paddr);

/**
 * Register paddr & size as a bridge, get bridge handle
 *
 * @ [IN] addr: paddr of buffer to be turned into bridge
 * @ [IN] paddr: physical addr of the buffer to be turned into bridge
 * @ [IN] size: size of the bridge
 * @ [IN] ns_vmid_list: non-secure vmids array
 * @ [IN] ns_vm_perm_list: NS VM permission array