diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_ipp.c')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_ipp.c | 265 | 
1 files changed, 134 insertions, 131 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 824e0705c8d..a1888e128f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -16,7 +16,6 @@  #include <linux/types.h>  #include <linux/clk.h>  #include <linux/pm_runtime.h> -#include <plat/map-base.h>  #include <drm/drmP.h>  #include <drm/exynos_drm.h> @@ -168,6 +167,13 @@ static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj,  	return 0;  } +static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) +{ +	mutex_lock(lock); +	idr_remove(id_idr, id); +	mutex_unlock(lock); +} +  static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id)  {  	void *obj; @@ -277,24 +283,22 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)  	DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); -	if (list_empty(&exynos_drm_ippdrv_list)) { -		DRM_DEBUG_KMS("ippdrv_list is empty.\n"); -		return ERR_PTR(-ENODEV); -	} -  	/*  	 * This case is search ipp driver by prop_id handle.  	 * sometimes, ipp subsystem find driver by prop_id. -	 * e.g PAUSE state, queue buf, command contro. +	 * e.g PAUSE state, queue buf, command control.  	 */  	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {  		DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv); -		if (!list_empty(&ippdrv->cmd_list)) { -			list_for_each_entry(c_node, &ippdrv->cmd_list, list) -				if (c_node->property.prop_id == prop_id) -					return ippdrv; +		mutex_lock(&ippdrv->cmd_lock); +		list_for_each_entry(c_node, &ippdrv->cmd_list, list) { +			if (c_node->property.prop_id == prop_id) { +				mutex_unlock(&ippdrv->cmd_lock); +				return ippdrv; +			}  		} +		mutex_unlock(&ippdrv->cmd_lock);  	}  	return ERR_PTR(-ENODEV); @@ -326,6 +330,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,  	if (!prop_list->ipp_id) {  		list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list)  			count++; +  		/*  		 * Supports ippdrv list count for user application.  		 * First step user application getting ippdrv count. @@ -335,7 +340,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,  	} else {  		/*  		 * Getting ippdrv capability by ipp_id. -		 * some deivce not supported wb, output interface. +		 * some device not supported wb, output interface.  		 * so, user application detect correct ipp driver  		 * using this ioctl.  		 */ @@ -347,7 +352,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,  			return PTR_ERR(ippdrv);  		} -		prop_list = ippdrv->prop_list; +		*prop_list = ippdrv->prop_list;  	}  	return 0; @@ -387,9 +392,11 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)  	 * when we find this command no using prop_id.  	 * return property information set in this command node.  	 */ +	mutex_lock(&ippdrv->cmd_lock);  	list_for_each_entry(c_node, &ippdrv->cmd_list, list) {  		if ((c_node->property.prop_id == prop_id) &&  		    (c_node->state == IPP_STATE_STOP)) { +			mutex_unlock(&ippdrv->cmd_lock);  			DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n",  				property->cmd, (int)ippdrv); @@ -397,6 +404,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)  			return 0;  		}  	} +	mutex_unlock(&ippdrv->cmd_lock);  	DRM_ERROR("failed to search property.\n"); @@ -500,7 +508,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,  	c_node->start_work = ipp_create_cmd_work();  	if (IS_ERR(c_node->start_work)) {  		DRM_ERROR("failed to create start work.\n"); -		goto err_clear; +		goto err_remove_id;  	}  	c_node->stop_work = ipp_create_cmd_work(); @@ -515,7 +523,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,  		goto err_free_stop;  	} -	mutex_init(&c_node->cmd_lock); +	mutex_init(&c_node->lock);  	mutex_init(&c_node->mem_lock);  	mutex_init(&c_node->event_lock); @@ -527,7 +535,9 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,  	INIT_LIST_HEAD(&c_node->event_list);  	list_splice_init(&priv->event_list, &c_node->event_list); +	mutex_lock(&ippdrv->cmd_lock);  	list_add_tail(&c_node->list, &ippdrv->cmd_list); +	mutex_unlock(&ippdrv->cmd_lock);  	/* make dedicated state without m2m */  	if (!ipp_is_m2m_cmd(property->cmd)) @@ -539,18 +549,24 @@ err_free_stop:  	kfree(c_node->stop_work);  err_free_start:  	kfree(c_node->start_work); +err_remove_id: +	ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id);  err_clear:  	kfree(c_node);  	return ret;  } -static void ipp_clean_cmd_node(struct drm_exynos_ipp_cmd_node *c_node) +static void ipp_clean_cmd_node(struct ipp_context *ctx, +				struct drm_exynos_ipp_cmd_node *c_node)  {  	/* delete list */  	list_del(&c_node->list); +	ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, +			c_node->property.prop_id); +  	/* destroy mutex */ -	mutex_destroy(&c_node->cmd_lock); +	mutex_destroy(&c_node->lock);  	mutex_destroy(&c_node->mem_lock);  	mutex_destroy(&c_node->event_lock); @@ -568,17 +584,10 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)  	struct list_head *head;  	int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, }; -	mutex_lock(&c_node->mem_lock); -  	for_each_ipp_ops(i) {  		/* source/destination memory list */  		head = &c_node->mem_list[i]; -		if (list_empty(head)) { -			DRM_DEBUG_KMS("%s memory empty.\n", i ? "dst" : "src"); -			continue; -		} -  		/* find memory node entry */  		list_for_each_entry(m_node, head, list) {  			DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n", @@ -603,8 +612,6 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)  		ret = max(count[EXYNOS_DRM_OPS_SRC],  			count[EXYNOS_DRM_OPS_DST]); -	mutex_unlock(&c_node->mem_lock); -  	return ret;  } @@ -647,16 +654,13 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,  		return -EFAULT;  	} -	mutex_lock(&c_node->mem_lock); -  	DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);  	/* get operations callback */  	ops = ippdrv->ops[m_node->ops_id];  	if (!ops) {  		DRM_ERROR("not support ops.\n"); -		ret = -EFAULT; -		goto err_unlock; +		return -EFAULT;  	}  	/* set address and enable irq */ @@ -665,12 +669,10 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,  			m_node->buf_id, IPP_BUF_ENQUEUE);  		if (ret) {  			DRM_ERROR("failed to set addr.\n"); -			goto err_unlock; +			return ret;  		}  	} -err_unlock: -	mutex_unlock(&c_node->mem_lock);  	return ret;  } @@ -685,11 +687,9 @@ static struct drm_exynos_ipp_mem_node  	void *addr;  	int i; -	mutex_lock(&c_node->mem_lock); -  	m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);  	if (!m_node) -		goto err_unlock; +		return ERR_PTR(-ENOMEM);  	/* clear base address for error handling */  	memset(&buf_info, 0x0, sizeof(buf_info)); @@ -723,15 +723,14 @@ static struct drm_exynos_ipp_mem_node  	m_node->filp = file;  	m_node->buf_info = buf_info; +	mutex_lock(&c_node->mem_lock);  	list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); -  	mutex_unlock(&c_node->mem_lock); +  	return m_node;  err_clear:  	kfree(m_node); -err_unlock: -	mutex_unlock(&c_node->mem_lock);  	return ERR_PTR(-EFAULT);  } @@ -748,13 +747,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,  		return -EFAULT;  	} -	if (list_empty(&m_node->list)) { -		DRM_ERROR("empty memory node.\n"); -		return -ENOMEM; -	} - -	mutex_lock(&c_node->mem_lock); -  	DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);  	/* put gem buffer */ @@ -769,8 +761,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,  	list_del(&m_node->list);  	kfree(m_node); -	mutex_unlock(&c_node->mem_lock); -  	return 0;  } @@ -806,7 +796,9 @@ static int ipp_get_event(struct drm_device *drm_dev,  	e->base.event = &e->event.base;  	e->base.file_priv = file;  	e->base.destroy = ipp_free_event; +	mutex_lock(&c_node->event_lock);  	list_add_tail(&e->base.link, &c_node->event_list); +	mutex_unlock(&c_node->event_lock);  	return 0;  } @@ -817,16 +809,12 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,  	struct drm_exynos_ipp_send_event *e, *te;  	int count = 0; -	if (list_empty(&c_node->event_list)) { -		DRM_DEBUG_KMS("event_list is empty.\n"); -		return; -	} - +	mutex_lock(&c_node->event_lock);  	list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {  		DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);  		/* -		 * quf == NULL condition means all event deletion. +		 * qbuf == NULL condition means all event deletion.  		 * stop operations want to delete all event list.  		 * another case delete only same buf id.  		 */ @@ -842,9 +830,13 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,  			/* delete list */  			list_del(&e->base.link);  			kfree(e); -			return; +			goto out_unlock;  		}  	} + +out_unlock: +	mutex_unlock(&c_node->event_lock); +	return;  }  static void ipp_handle_cmd_work(struct device *dev, @@ -888,7 +880,9 @@ static int ipp_queue_buf_with_run(struct device *dev,  		return 0;  	} +	mutex_lock(&c_node->mem_lock);  	if (!ipp_check_mem_list(c_node)) { +		mutex_unlock(&c_node->mem_lock);  		DRM_DEBUG_KMS("empty memory.\n");  		return 0;  	} @@ -905,10 +899,12 @@ static int ipp_queue_buf_with_run(struct device *dev,  	} else {  		ret = ipp_set_mem_node(ippdrv, c_node, m_node);  		if (ret) { +			mutex_unlock(&c_node->mem_lock);  			DRM_ERROR("failed to set m node.\n");  			return ret;  		}  	} +	mutex_unlock(&c_node->mem_lock);  	return 0;  } @@ -919,15 +915,15 @@ static void ipp_clean_queue_buf(struct drm_device *drm_dev,  {  	struct drm_exynos_ipp_mem_node *m_node, *tm_node; -	if (!list_empty(&c_node->mem_list[qbuf->ops_id])) { -		/* delete list */ -		list_for_each_entry_safe(m_node, tm_node, -			&c_node->mem_list[qbuf->ops_id], list) { -			if (m_node->buf_id == qbuf->buf_id && -			    m_node->ops_id == qbuf->ops_id) -				ipp_put_mem_node(drm_dev, c_node, m_node); -		} +	/* delete list */ +	mutex_lock(&c_node->mem_lock); +	list_for_each_entry_safe(m_node, tm_node, +		&c_node->mem_list[qbuf->ops_id], list) { +		if (m_node->buf_id == qbuf->buf_id && +		    m_node->ops_id == qbuf->ops_id) +			ipp_put_mem_node(drm_dev, c_node, m_node);  	} +	mutex_unlock(&c_node->mem_lock);  }  int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, @@ -999,7 +995,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,  		}  		break;  	case IPP_BUF_DEQUEUE: -		mutex_lock(&c_node->cmd_lock); +		mutex_lock(&c_node->lock);  		/* put event for destination buffer */  		if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) @@ -1007,7 +1003,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,  		ipp_clean_queue_buf(drm_dev, c_node, qbuf); -		mutex_unlock(&c_node->cmd_lock); +		mutex_unlock(&c_node->lock);  		break;  	default:  		DRM_ERROR("invalid buffer control.\n"); @@ -1110,12 +1106,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,  	case IPP_CTRL_PLAY:  		if (pm_runtime_suspended(ippdrv->dev))  			pm_runtime_get_sync(ippdrv->dev); +  		c_node->state = IPP_STATE_START;  		cmd_work = c_node->start_work;  		cmd_work->ctrl = cmd_ctrl->ctrl;  		ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); -		c_node->state = IPP_STATE_START;  		break;  	case IPP_CTRL_STOP:  		cmd_work = c_node->stop_work; @@ -1130,10 +1126,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,  		c_node->state = IPP_STATE_STOP;  		ippdrv->dedicated = false; -		ipp_clean_cmd_node(c_node); +		mutex_lock(&ippdrv->cmd_lock); +		ipp_clean_cmd_node(ctx, c_node);  		if (list_empty(&ippdrv->cmd_list))  			pm_runtime_put_sync(ippdrv->dev); +		mutex_unlock(&ippdrv->cmd_lock);  		break;  	case IPP_CTRL_PAUSE:  		cmd_work = c_node->stop_work; @@ -1261,9 +1259,11 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  	/* store command info in ippdrv */  	ippdrv->c_node = c_node; +	mutex_lock(&c_node->mem_lock);  	if (!ipp_check_mem_list(c_node)) {  		DRM_DEBUG_KMS("empty memory.\n"); -		return -ENOMEM; +		ret = -ENOMEM; +		goto err_unlock;  	}  	/* set current property in ippdrv */ @@ -1271,7 +1271,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  	if (ret) {  		DRM_ERROR("failed to set property.\n");  		ippdrv->c_node = NULL; -		return ret; +		goto err_unlock;  	}  	/* check command */ @@ -1286,7 +1286,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  			if (!m_node) {  				DRM_ERROR("failed to get node.\n");  				ret = -EFAULT; -				return ret; +				goto err_unlock;  			}  			DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); @@ -1294,7 +1294,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  			ret = ipp_set_mem_node(ippdrv, c_node, m_node);  			if (ret) {  				DRM_ERROR("failed to set m node.\n"); -				return ret; +				goto err_unlock;  			}  		}  		break; @@ -1306,7 +1306,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  			ret = ipp_set_mem_node(ippdrv, c_node, m_node);  			if (ret) {  				DRM_ERROR("failed to set m node.\n"); -				return ret; +				goto err_unlock;  			}  		}  		break; @@ -1318,14 +1318,16 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  			ret = ipp_set_mem_node(ippdrv, c_node, m_node);  			if (ret) {  				DRM_ERROR("failed to set m node.\n"); -				return ret; +				goto err_unlock;  			}  		}  		break;  	default:  		DRM_ERROR("invalid operations.\n"); -		return -EINVAL; +		ret = -EINVAL; +		goto err_unlock;  	} +	mutex_unlock(&c_node->mem_lock);  	DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); @@ -1334,11 +1336,17 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,  		ret = ippdrv->start(ippdrv->dev, property->cmd);  		if (ret) {  			DRM_ERROR("failed to start ops.\n"); +			ippdrv->c_node = NULL;  			return ret;  		}  	}  	return 0; + +err_unlock: +	mutex_unlock(&c_node->mem_lock); +	ippdrv->c_node = NULL; +	return ret;  }  static int ipp_stop_property(struct drm_device *drm_dev, @@ -1355,6 +1363,8 @@ static int ipp_stop_property(struct drm_device *drm_dev,  	/* put event */  	ipp_put_event(c_node, NULL); +	mutex_lock(&c_node->mem_lock); +  	/* check command */  	switch (property->cmd) {  	case IPP_CMD_M2M: @@ -1362,11 +1372,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,  			/* source/destination memory list */  			head = &c_node->mem_list[i]; -			if (list_empty(head)) { -				DRM_DEBUG_KMS("mem_list is empty.\n"); -				break; -			} -  			list_for_each_entry_safe(m_node, tm_node,  				head, list) {  				ret = ipp_put_mem_node(drm_dev, c_node, @@ -1382,11 +1387,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,  		/* destination memory list */  		head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; -		if (list_empty(head)) { -			DRM_DEBUG_KMS("mem_list is empty.\n"); -			break; -		} -  		list_for_each_entry_safe(m_node, tm_node, head, list) {  			ret = ipp_put_mem_node(drm_dev, c_node, m_node);  			if (ret) { @@ -1399,11 +1399,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,  		/* source memory list */  		head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; -		if (list_empty(head)) { -			DRM_DEBUG_KMS("mem_list is empty.\n"); -			break; -		} -  		list_for_each_entry_safe(m_node, tm_node, head, list) {  			ret = ipp_put_mem_node(drm_dev, c_node, m_node);  			if (ret) { @@ -1419,6 +1414,8 @@ static int ipp_stop_property(struct drm_device *drm_dev,  	}  err_clear: +	mutex_unlock(&c_node->mem_lock); +  	/* stop operations */  	if (ippdrv->stop)  		ippdrv->stop(ippdrv->dev, property->cmd); @@ -1447,7 +1444,7 @@ void ipp_sched_cmd(struct work_struct *work)  		return;  	} -	mutex_lock(&c_node->cmd_lock); +	mutex_lock(&c_node->lock);  	property = &c_node->property; @@ -1495,7 +1492,7 @@ void ipp_sched_cmd(struct work_struct *work)  	DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl);  err_unlock: -	mutex_unlock(&c_node->cmd_lock); +	mutex_unlock(&c_node->lock);  }  static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, @@ -1525,14 +1522,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  		return -EINVAL;  	} +	mutex_lock(&c_node->event_lock);  	if (list_empty(&c_node->event_list)) {  		DRM_DEBUG_KMS("event list is empty.\n"); -		return 0; +		ret = 0; +		goto err_event_unlock;  	} +	mutex_lock(&c_node->mem_lock);  	if (!ipp_check_mem_list(c_node)) {  		DRM_DEBUG_KMS("empty memory.\n"); -		return 0; +		ret = 0; +		goto err_mem_unlock;  	}  	/* check command */ @@ -1546,7 +1547,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  				struct drm_exynos_ipp_mem_node, list);  			if (!m_node) {  				DRM_ERROR("empty memory node.\n"); -				return -ENOMEM; +				ret = -ENOMEM; +				goto err_mem_unlock;  			}  			tbuf_id[i] = m_node->buf_id; @@ -1568,7 +1570,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  		m_node = ipp_find_mem_node(c_node, &qbuf);  		if (!m_node) {  			DRM_ERROR("empty memory node.\n"); -			return -ENOMEM; +			ret = -ENOMEM; +			goto err_mem_unlock;  		}  		tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; @@ -1585,7 +1588,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  			struct drm_exynos_ipp_mem_node, list);  		if (!m_node) {  			DRM_ERROR("empty memory node.\n"); -			return -ENOMEM; +			ret = -ENOMEM; +			goto err_mem_unlock;  		}  		tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; @@ -1596,8 +1600,10 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  		break;  	default:  		DRM_ERROR("invalid operations.\n"); -		return -EINVAL; +		ret = -EINVAL; +		goto err_mem_unlock;  	} +	mutex_unlock(&c_node->mem_lock);  	if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST])  		DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", @@ -1612,11 +1618,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  	e = list_first_entry(&c_node->event_list,  		struct drm_exynos_ipp_send_event, base.link); -	if (!e) { -		DRM_ERROR("empty event.\n"); -		return -EINVAL; -	} -  	do_gettimeofday(&now);  	DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec);  	e->event.tv_sec = now.tv_sec; @@ -1631,11 +1632,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,  	list_move_tail(&e->base.link, &e->base.file_priv->event_list);  	wake_up_interruptible(&e->base.file_priv->event_wait);  	spin_unlock_irqrestore(&drm_dev->event_lock, flags); +	mutex_unlock(&c_node->event_lock);  	DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n",  		property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]);  	return 0; + +err_mem_unlock: +	mutex_unlock(&c_node->mem_lock); +err_event_unlock: +	mutex_unlock(&c_node->event_lock); +	return ret;  }  void ipp_sched_event(struct work_struct *work) @@ -1677,8 +1685,6 @@ void ipp_sched_event(struct work_struct *work)  		goto err_completion;  	} -	mutex_lock(&c_node->event_lock); -  	ret = ipp_send_event(ippdrv, c_node, event_work->buf_id);  	if (ret) {  		DRM_ERROR("failed to send event.\n"); @@ -1688,8 +1694,6 @@ void ipp_sched_event(struct work_struct *work)  err_completion:  	if (ipp_is_m2m_cmd(c_node->property.cmd))  		complete(&c_node->start_complete); - -	mutex_unlock(&c_node->event_lock);  }  static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) @@ -1700,23 +1704,21 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)  	/* get ipp driver entry */  	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { +		u32 ipp_id; +  		ippdrv->drm_dev = drm_dev;  		ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv, -			&ippdrv->ipp_id); -		if (ret) { +				    &ipp_id); +		if (ret || ipp_id == 0) {  			DRM_ERROR("failed to create id.\n"); -			goto err_idr; +			goto err;  		}  		DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", -			count++, (int)ippdrv, ippdrv->ipp_id); +			count++, (int)ippdrv, ipp_id); -		if (ippdrv->ipp_id == 0) { -			DRM_ERROR("failed to get ipp_id[%d]\n", -				ippdrv->ipp_id); -			goto err_idr; -		} +		ippdrv->prop_list.ipp_id = ipp_id;  		/* store parent device for node */  		ippdrv->parent_dev = dev; @@ -1725,39 +1727,46 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)  		ippdrv->event_workq = ctx->event_workq;  		ippdrv->sched_event = ipp_sched_event;  		INIT_LIST_HEAD(&ippdrv->cmd_list); +		mutex_init(&ippdrv->cmd_lock);  		if (is_drm_iommu_supported(drm_dev)) {  			ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);  			if (ret) {  				DRM_ERROR("failed to activate iommu\n"); -				goto err_iommu; +				goto err;  			}  		}  	}  	return 0; -err_iommu: +err:  	/* get ipp driver entry */ -	list_for_each_entry_reverse(ippdrv, &exynos_drm_ippdrv_list, drv_list) +	list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, +						drv_list) {  		if (is_drm_iommu_supported(drm_dev))  			drm_iommu_detach_device(drm_dev, ippdrv->dev); -err_idr: -	idr_destroy(&ctx->ipp_idr); -	idr_destroy(&ctx->prop_idr); +		ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, +				ippdrv->prop_list.ipp_id); +	} +  	return ret;  }  static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)  {  	struct exynos_drm_ippdrv *ippdrv; +	struct ipp_context *ctx = get_ipp_context(dev);  	/* get ipp driver entry */  	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {  		if (is_drm_iommu_supported(drm_dev))  			drm_iommu_detach_device(drm_dev, ippdrv->dev); +		ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, +				ippdrv->prop_list.ipp_id); +  		ippdrv->drm_dev = NULL;  		exynos_drm_ippdrv_unregister(ippdrv);  	} @@ -1788,20 +1797,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,  	struct drm_exynos_file_private *file_priv = file->driver_priv;  	struct exynos_drm_ipp_private *priv = file_priv->ipp_priv;  	struct exynos_drm_ippdrv *ippdrv = NULL; +	struct ipp_context *ctx = get_ipp_context(dev);  	struct drm_exynos_ipp_cmd_node *c_node, *tc_node;  	int count = 0;  	DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv); -	if (list_empty(&exynos_drm_ippdrv_list)) { -		DRM_DEBUG_KMS("ippdrv_list is empty.\n"); -		goto err_clear; -	} -  	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { -		if (list_empty(&ippdrv->cmd_list)) -			continue; - +		mutex_lock(&ippdrv->cmd_lock);  		list_for_each_entry_safe(c_node, tc_node,  			&ippdrv->cmd_list, list) {  			DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", @@ -1821,14 +1824,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,  				}  				ippdrv->dedicated = false; -				ipp_clean_cmd_node(c_node); +				ipp_clean_cmd_node(ctx, c_node);  				if (list_empty(&ippdrv->cmd_list))  					pm_runtime_put_sync(ippdrv->dev);  			}  		} +		mutex_unlock(&ippdrv->cmd_lock);  	} -err_clear:  	kfree(priv);  	return;  }  | 
