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

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

Merge "msm: synx: fix merged synx sharing across processes"

parents bbac8b4a 9e0b6978
Loading
Loading
Loading
Loading
+25 −40
Original line number Diff line number Diff line
@@ -633,74 +633,57 @@ int synx_addrefcount(s32 synx_obj, s32 count)
	return 0;
}

int synx_import(s32 synx_obj, u32 secure_key, s32 *new_synx_obj)
int synx_import(s32 synx_obj, u32 import_key, s32 *new_synx_obj)
{
	bool bit;
	s32 id;
	long idx = 0;
	struct dma_fence *fence;
	struct synx_table_row *row = NULL;
	struct synx_table_row *new_row = NULL;

	pr_debug("Enter %s\n", __func__);

	if (!new_synx_obj)
		return -EINVAL;

	row = synx_from_key(synx_obj, secure_key);
	row = synx_from_import_key(synx_obj, import_key);
	if (!row)
		return -EINVAL;

	/*
	 * Reason for separate metadata (for merged synx) being
	 * dma fence array has separate release func registed with
	 * dma fence ops, which doesn't invoke release func registered
	 * by the framework to clear metadata when all refs are released.
	 * Hence we need to clear the metadata for merged synx obj
	 * upon synx_release itself. But this creates a problem if
	 * the synx obj is exported. Thus we need separate metadata
	 * structures even though they represent same synx obj.
	 * Note, only the metadata is released, and the fence reference
	 * count is decremented still.
	 */
	if (is_merged_synx(row)) {
		do {
			idx = find_first_zero_bit(synx_dev->bitmap,
					SYNX_MAX_OBJS);
			if (idx >= SYNX_MAX_OBJS)
				return -ENOMEM;
			bit = test_and_set_bit(idx, synx_dev->bitmap);
		} while (bit);

		new_row = synx_dev->synx_table + idx;
	/* new global synx id */
		id = synx_create_handle(new_row);

		/* both metadata points to same dma fence */
		new_row->fence = row->fence;
		new_row->index = idx;
		new_row->synx_obj = id;
	} else {
		/* new global synx id. Imported synx points to same metadata */
	id = synx_create_handle(row);
	if (id < 0) {
		fence = row->fence;
		if (is_merged_synx(row)) {
			clear_bit(row->index, synx_dev->bitmap);
			memset(row, 0, sizeof(*row));
		}
		/* release the reference obtained during export */
		dma_fence_put(fence);
		return -EINVAL;
	}

	row->synx_obj = id;
	*new_synx_obj = id;
	pr_debug("Exit %s\n", __func__);

	return 0;
}

int synx_export(s32 synx_obj, u32 *key)
int synx_export(s32 synx_obj, u32 *import_key)
{
	int rc;
	struct synx_table_row *row = NULL;

	pr_debug("Enter %s\n", __func__);

	row = synx_from_handle(synx_obj);
	if (!row)
		return -EINVAL;

	spin_lock_bh(&synx_dev->row_spinlocks[row->index]);
	*key = synx_generate_secure_key(row);
	rc = synx_generate_import_key(row, import_key);
	if (rc < 0)
		return rc;

	spin_lock_bh(&synx_dev->row_spinlocks[row->index]);
	/*
	 * to make sure the synx is not lost if the process dies or
	 * synx is released before any other process gets a chance to
@@ -710,6 +693,7 @@ int synx_export(s32 synx_obj, u32 *key)
	 */
	dma_fence_get(row->fence);
	spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);
	pr_debug("Exit %s\n", __func__);

	return 0;
}
@@ -1489,6 +1473,7 @@ static int __init synx_init(void)
	}

	INIT_LIST_HEAD(&synx_dev->client_list);
	INIT_LIST_HEAD(&synx_dev->import_list);
	synx_dev->dma_context = dma_fence_context_alloc(1);

	synx_dev->debugfs_root = init_synx_debug_dir(synx_dev);
+18 −0
Original line number Diff line number Diff line
@@ -155,6 +155,22 @@ struct synx_registered_ops {
	u32 type;
};

/**
 * struct synx_import_data - Import metadata for sharing synx handles
 * with processes
 *
 * @key      : Import key for sharing synx handle
 * @synx_obj : Synx handle being exported
 * @row      : Pointer to synx object
 * @list     : List member used to append the node to import list
 */
struct synx_import_data {
	u32 key;
	s32 synx_obj;
	struct synx_table_row *row;
	struct list_head list;
};

/**
 * struct synx_device - Internal struct to book keep synx driver details
 *
@@ -175,6 +191,7 @@ struct synx_registered_ops {
 * debugfs_root   : Root directory for debugfs
 * synx_node_head : list head for synx nodes
 * synx_node_list_lock : Spinlock for synx nodes
 * import_list    : List to validate synx import requests
 */
struct synx_device {
	struct cdev cdev;
@@ -194,6 +211,7 @@ struct synx_device {
	struct dentry *debugfs_root;
	struct list_head synx_debug_head;
	spinlock_t synx_node_list_lock;
	struct list_head import_list;
};

/**
+92 −0
Original line number Diff line number Diff line
@@ -579,6 +579,98 @@ struct synx_table_row *synx_from_fence(struct dma_fence *fence)
	return row;
}

struct synx_table_row *synx_from_import_key(s32 synx_obj, u32 key)
{
	struct synx_import_data *data, *tmp_data;
	struct synx_table_row *row = NULL;

	mutex_lock(&synx_dev->table_lock);
	list_for_each_entry_safe(data, tmp_data,
		&synx_dev->import_list, list) {
		if (data->key == key && data->synx_obj == synx_obj) {
			pr_debug("found synx handle, importing 0x%x\n",
				synx_obj);
			row = data->row;
			list_del_init(&data->list);
			kfree(data);
			break;
		}
	}
	mutex_unlock(&synx_dev->table_lock);

	return row;
}

int synx_generate_import_key(struct synx_table_row *row,
	u32 *key)
{
	bool bit;
	long idx = 0;
	struct synx_import_data *data;
	struct synx_table_row *new_row;

	if (!row)
		return -EINVAL;

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

	mutex_lock(&synx_dev->table_lock);
	do {
		/* obtain a random non-zero key */
		get_random_bytes(key, sizeof(*key));
	} while (!*key);

	data->key = *key;
	data->synx_obj = row->synx_obj;
	/*
	 * Reason for separate metadata (for merged synx)
	 * being dma fence array has separate release func
	 * registed with dma fence ops, which doesn't invoke
	 * release func registered by the framework to clear
	 * metadata when all refs are released.
	 * Hence we need to clear the metadata for merged synx
	 * obj upon synx_release itself. But this creates a
	 * problem if synx obj is exported. Thus need separate
	 * metadata structures even though they represent same
	 * synx obj.
	 * Note, only the metadata is released, and the fence
	 * reference count is decremented still.
	 */
	if (is_merged_synx(row)) {
		do {
			idx = find_first_zero_bit(
					synx_dev->bitmap,
					SYNX_MAX_OBJS);
			if (idx >= SYNX_MAX_OBJS) {
				kfree(data);
				mutex_unlock(
					&synx_dev->table_lock);
				return -ENOMEM;
			}
			bit = test_and_set_bit(idx,
					synx_dev->bitmap);
		} while (bit);

		new_row = synx_dev->synx_table + idx;
		/* both metadata points to same dma fence */
		new_row->fence = row->fence;
		new_row->index = idx;
		INIT_LIST_HEAD(&new_row->callback_list);
		INIT_LIST_HEAD(&new_row->user_payload_list);
		data->row = new_row;
	} else {
		data->row = row;
	}
	list_add(&data->list, &synx_dev->import_list);
	pr_debug("allocated import key for 0x%x\n",
		row->synx_obj);
	mutex_unlock(&synx_dev->table_lock);

	return 0;
}

void *synx_from_key(s32 id, u32 secure_key)
{
	struct synx_table_row *row = NULL;
+25 −0
Original line number Diff line number Diff line
@@ -228,6 +228,31 @@ struct bind_operations *synx_get_bind_ops(u32 type);
 */
int synx_generate_secure_key(struct synx_table_row *row);

/**
 * @brief: Function to generate a key for authenticating requests
 *         Generated key for synx object being exported is
 *         verified during import.
 *
 * @param row : Pointer to the synx object row
 * @param key : Pointer to key (filled by the function)
 *
 * @return Status of operation. Negative in case of error. Zero otherwise.
 */
int synx_generate_import_key(struct synx_table_row *row,
	u32 *key);

/**
 * @brief: Function to authenticate requests for importing synx handle
 *         Used to verify the requests generated on synx object
 *         being imported.
 *
 * @param synx_obj : Synx handle being imported
 * @param key      : Key to authenticate import request
 *
 * @return Pointer to the synx object row for valid request. NULL otherwise.
 */
struct synx_table_row *synx_from_import_key(s32 synx_obj, u32 key);

/**
 * @brief: Function to handle adding an error
 *         code to a synx