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

Commit 3c1652e1 authored by Jeyaprakash Soundrapandian's avatar Jeyaprakash Soundrapandian Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: sync:Cleanup sync object link properly" into dev/msm-4.9-camx

parents f6fad951 cf0278c1
Loading
Loading
Loading
Loading
+2 −16
Original line number Diff line number Diff line
@@ -230,6 +230,8 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status)
				spin_unlock_bh(
					&sync_dev->row_spinlocks[
						parent_info->sync_id]);
				spin_unlock_bh(
					&sync_dev->row_spinlocks[sync_obj]);
				return rc;
			}
		}
@@ -344,24 +346,8 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj)

int cam_sync_destroy(int32_t sync_obj)
{
	struct sync_table_row *row = NULL;

	if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
		return -EINVAL;

	spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
	row = sync_dev->sync_table + sync_obj;
	if (row->state == CAM_SYNC_STATE_INVALID) {
		CAM_ERR(CAM_SYNC,
			"Error: accessing an uninitialized sync obj: idx = %d",
			sync_obj);
		spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
		return -EINVAL;
	}

	cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
	spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);

	return 0;
}

+12 −0
Original line number Diff line number Diff line
@@ -54,6 +54,18 @@ enum sync_type {
	SYNC_TYPE_GROUP
};

/**
 * enum sync_list_clean_type - Enum to indicate the type of list clean action
 * to be peformed, i.e. specific sync ID or all list sync ids.
 *
 * @SYNC_CLEAN_ID  : Specific object to be cleaned in the list
 * @SYNC_CLEAN_ALL : Clean all objects in the list
 */
enum sync_list_clean_type {
	SYNC_LIST_CLEAN_ID,
	SYNC_LIST_CLEAN_ALL
};

/**
 * struct sync_parent_info - Single node of information about a parent
 * of a sync object, usually part of the parents linked list
+141 −12
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ int cam_sync_init_group_object(struct sync_table_row *table,

		if (!child_info) {
			cam_sync_util_cleanup_children_list(
				&row->children_list);
				&row->children_list, SYNC_LIST_CLEAN_ALL, 0);
			return -ENOMEM;
		}

@@ -160,9 +160,10 @@ int cam_sync_init_group_object(struct sync_table_row *table,
		parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC);
		if (!parent_info) {
			cam_sync_util_cleanup_parents_list(
				&child_row->parents_list);
				&child_row->parents_list,
				SYNC_LIST_CLEAN_ALL, 0);
			cam_sync_util_cleanup_children_list(
				&row->children_list);
				&row->children_list, SYNC_LIST_CLEAN_ALL, 0);
			spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
			return -ENOMEM;
		}
@@ -197,27 +198,131 @@ int cam_sync_init_group_object(struct sync_table_row *table,
int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx)
{
	struct sync_table_row *row = table + idx;
	struct sync_child_info *child_info, *temp_child;
	struct sync_child_info *child_info, *temp_child, *child_copy_info;
	struct sync_callback_info *sync_cb, *temp_cb;
	struct sync_parent_info *parent_info, *temp_parent;
	struct sync_parent_info *parent_info, *temp_parent, *parent_copy_info;
	struct sync_user_payload *upayload_info, *temp_upayload;
	struct sync_table_row   *child_row = NULL, *parent_row = NULL;
	struct list_head child_copy_list, parent_copy_list;

	if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
		return -EINVAL;

	clear_bit(idx, sync_dev->bitmap);
	list_for_each_entry_safe(child_info, temp_child,
				&row->children_list, list) {
	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
	if (row->state == CAM_SYNC_STATE_INVALID) {
		CAM_ERR(CAM_SYNC,
			"Error: accessing an uninitialized sync obj: idx = %d",
			idx);
		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
		return -EINVAL;
	}

	/* Objects child and parent objects will be added into this list */
	INIT_LIST_HEAD(&child_copy_list);
	INIT_LIST_HEAD(&parent_copy_list);

	list_for_each_entry_safe(child_info, temp_child, &row->children_list,
		list) {
		if (child_info->sync_id <= 0)
			continue;

		child_copy_info = kzalloc(sizeof(*child_copy_info), GFP_ATOMIC);
		if (!child_copy_info) {
			/* No free memory, clean up the child_copy_list */
			while (!list_empty(&child_copy_list)) {
				child_info = list_first_entry(&child_copy_list,
					struct sync_child_info, list);
				list_del_init(&child_info->list);
				kfree(child_info);
			}
			spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
			goto deinit;
		}
		child_copy_info->sync_id = child_info->sync_id;
		list_add_tail(&child_copy_info->list, &child_copy_list);
	}

	list_for_each_entry_safe(parent_info, temp_parent, &row->parents_list,
		list) {
		if (parent_info->sync_id <= 0)
			continue;
		parent_copy_info = kzalloc(sizeof(*parent_copy_info),
			GFP_ATOMIC);
		if (!parent_copy_info) {
			/* No free memory, clean up the parent_copy_list */
			while (!list_empty(&parent_copy_list)) {
				parent_info = list_first_entry(
					&parent_copy_list,
					struct sync_parent_info, list);
				list_del_init(&parent_info->list);
				kfree(parent_info);
			}
			/* No free memory, clean up the child_copy_list */
			while (!list_empty(&child_copy_list)) {
				child_info = list_first_entry(&child_copy_list,
					struct sync_child_info, list);
				list_del_init(&child_info->list);
				kfree(child_info);
			}
			spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
			goto deinit;
		}
		parent_copy_info->sync_id = parent_info->sync_id;
		list_add_tail(&parent_copy_info->list, &parent_copy_list);
	}

	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
	/* Cleanup the child to parent link from child list*/
	while (!list_empty(&child_copy_list)) {
		child_info = list_first_entry(&child_copy_list,
			struct sync_child_info, list);
		child_row = sync_dev->sync_table + child_info->sync_id;
		spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
		if (child_row->state == CAM_SYNC_STATE_INVALID) {
			spin_unlock_bh(&sync_dev->row_spinlocks[
				child_info->sync_id]);
			list_del_init(&child_info->list);
			kfree(child_info);
			continue;
		}

		cam_sync_util_cleanup_parents_list(&child_row->parents_list,
			SYNC_LIST_CLEAN_ID, idx);

		spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
		list_del_init(&child_info->list);
		kfree(child_info);
	}

	list_for_each_entry_safe(parent_info, temp_parent,
				&row->parents_list, list) {
	/* Cleanup the parent to child link */
	while (!list_empty(&parent_copy_list)) {
		parent_info = list_first_entry(&parent_copy_list,
			struct sync_parent_info, list);
		parent_row = sync_dev->sync_table + parent_info->sync_id;
		spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
		if (parent_row->state == CAM_SYNC_STATE_INVALID) {
			spin_unlock_bh(&sync_dev->row_spinlocks[
				parent_info->sync_id]);
			list_del_init(&parent_info->list);
			kfree(parent_info);
			continue;
		}

		cam_sync_util_cleanup_children_list(&parent_row->children_list,
			SYNC_LIST_CLEAN_ID, idx);

		spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
		list_del_init(&parent_info->list);
		kfree(parent_info);
	}

deinit:
	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
	cam_sync_util_cleanup_children_list(&row->children_list,
		SYNC_LIST_CLEAN_ALL, 0);
	cam_sync_util_cleanup_parents_list(&row->parents_list,
		SYNC_LIST_CLEAN_ALL, 0);

	list_for_each_entry_safe(upayload_info, temp_upayload,
				&row->user_payload_list, list) {
		list_del_init(&upayload_info->list);
@@ -232,6 +337,8 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx)

	row->state = CAM_SYNC_STATE_INVALID;
	memset(row, 0, sizeof(*row));
	clear_bit(idx, sync_dev->bitmap);
	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);

	return 0;
}
@@ -350,26 +457,48 @@ int cam_sync_util_get_state(int current_state,
	return result;
}

void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean)
void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean,
	uint32_t list_clean_type, uint32_t sync_obj)
{
	struct sync_child_info *child_info = NULL;
	struct sync_child_info *temp_child_info = NULL;
	uint32_t                curr_sync_obj;

	list_for_each_entry_safe(child_info,
			temp_child_info, list_to_clean, list) {
		if ((list_clean_type == SYNC_LIST_CLEAN_ID) &&
			(child_info->sync_id != sync_obj))
			continue;

		curr_sync_obj = child_info->sync_id;
		list_del_init(&child_info->list);
		kfree(child_info);

		if ((list_clean_type == SYNC_LIST_CLEAN_ID) &&
			(curr_sync_obj == sync_obj))
			break;
	}
}

void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean)
void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean,
	uint32_t list_clean_type, uint32_t sync_obj)
{
	struct sync_parent_info *parent_info = NULL;
	struct sync_parent_info *temp_parent_info = NULL;
	uint32_t                 curr_sync_obj;

	list_for_each_entry_safe(parent_info,
			temp_parent_info, list_to_clean, list) {
		if ((list_clean_type == SYNC_LIST_CLEAN_ID) &&
			(parent_info->sync_id != sync_obj))
			continue;

		curr_sync_obj = parent_info->sync_id;
		list_del_init(&parent_info->list);
		kfree(parent_info);

		if ((list_clean_type == SYNC_LIST_CLEAN_ID) &&
			(curr_sync_obj == sync_obj))
			break;
	}
}
+10 −2
Original line number Diff line number Diff line
@@ -141,17 +141,25 @@ int cam_sync_util_get_state(int current_state,
/**
 * @brief: Function to clean up the children of a sync object
 * @param list_to_clean : List to clean up
 * @list_clean_type     : Clean specific object or clean all objects
 * @sync_obj            : Sync object to be clean if list clean type is
 *                         SYNC_LIST_CLEAN_ID
 *
 * @return None
 */
void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean);
void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean,
	uint32_t list_clean_type, uint32_t sync_obj);

/**
 * @brief: Function to clean up the parents of a sync object
 * @param list_to_clean : List to clean up
 * @list_clean_type     : Clean specific object or clean all objects
 * @sync_obj            : Sync object to be clean if list clean type is
 *                         SYNC_LIST_CLEAN_ID
 *
 * @return None
 */
void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean);
void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean,
	uint32_t list_clean_type, uint32_t sync_obj);

#endif /* __CAM_SYNC_UTIL_H__ */