diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_ipp.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_ipp.c | 259 |
1 files changed, 70 insertions, 189 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index a1888e128f1d..c411399070d6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -129,9 +129,6 @@ void exynos_platform_device_ipp_unregister(void) int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) { - if (!ippdrv) - return -EINVAL; - mutex_lock(&exynos_drm_ippdrv_lock); list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); mutex_unlock(&exynos_drm_ippdrv_lock); @@ -141,9 +138,6 @@ int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) { - if (!ippdrv) - return -EINVAL; - mutex_lock(&exynos_drm_ippdrv_lock); list_del(&ippdrv->drv_list); mutex_unlock(&exynos_drm_ippdrv_lock); @@ -151,20 +145,15 @@ int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) return 0; } -static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj, - u32 *idp) +static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj) { int ret; - /* do the allocation under our mutexlock */ mutex_lock(lock); ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); mutex_unlock(lock); - if (ret < 0) - return ret; - *idp = ret; - return 0; + return ret; } static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) @@ -178,35 +167,25 @@ static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) { void *obj; - DRM_DEBUG_KMS("id[%d]\n", id); - mutex_lock(lock); - - /* find object using handle */ obj = idr_find(id_idr, id); - if (!obj) { - DRM_ERROR("failed to find object.\n"); - mutex_unlock(lock); - return ERR_PTR(-ENODEV); - } - mutex_unlock(lock); return obj; } -static inline bool ipp_check_dedicated(struct exynos_drm_ippdrv *ippdrv, - enum drm_exynos_ipp_cmd cmd) +static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv, + struct drm_exynos_ipp_property *property) { - /* - * check dedicated flag and WB, OUTPUT operation with - * power on state. - */ - if (ippdrv->dedicated || (!ipp_is_m2m_cmd(cmd) && - !pm_runtime_suspended(ippdrv->dev))) - return true; + if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) && + !pm_runtime_suspended(ippdrv->dev))) + return -EBUSY; - return false; + if (ippdrv->check_property && + ippdrv->check_property(ippdrv->dev, property)) + return -EINVAL; + + return 0; } static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, @@ -214,62 +193,30 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, { struct exynos_drm_ippdrv *ippdrv; u32 ipp_id = property->ipp_id; - - DRM_DEBUG_KMS("ipp_id[%d]\n", ipp_id); + int ret; if (ipp_id) { - /* find ipp driver using idr */ - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, - ipp_id); - if (IS_ERR(ippdrv)) { - DRM_ERROR("not found ipp%d driver.\n", ipp_id); - return ippdrv; + ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); + if (!ippdrv) { + DRM_DEBUG("ipp%d driver not found\n", ipp_id); + return ERR_PTR(-ENODEV); } - /* - * WB, OUTPUT opertion not supported multi-operation. - * so, make dedicated state at set property ioctl. - * when ipp driver finished operations, clear dedicated flags. - */ - if (ipp_check_dedicated(ippdrv, property->cmd)) { - DRM_ERROR("already used choose device.\n"); - return ERR_PTR(-EBUSY); - } - - /* - * This is necessary to find correct device in ipp drivers. - * ipp drivers have different abilities, - * so need to check property. - */ - if (ippdrv->check_property && - ippdrv->check_property(ippdrv->dev, property)) { - DRM_ERROR("not support property.\n"); - return ERR_PTR(-EINVAL); + ret = ipp_check_driver(ippdrv, property); + if (ret < 0) { + DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret); + return ERR_PTR(ret); } return ippdrv; } else { - /* - * This case is search all ipp driver for finding. - * user application don't set ipp_id in this case, - * so ipp subsystem search correct driver in driver list. - */ list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - if (ipp_check_dedicated(ippdrv, property->cmd)) { - DRM_DEBUG_KMS("used device.\n"); - continue; - } - - if (ippdrv->check_property && - ippdrv->check_property(ippdrv->dev, property)) { - DRM_DEBUG_KMS("not support property.\n"); - continue; - } - - return ippdrv; + ret = ipp_check_driver(ippdrv, property); + if (ret == 0) + return ippdrv; } - DRM_ERROR("not support ipp driver operations.\n"); + DRM_DEBUG("cannot find driver suitable for given property.\n"); } return ERR_PTR(-ENODEV); @@ -308,8 +255,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; - struct device *dev = priv->dev; + struct device *dev = file_priv->ipp_dev; struct ipp_context *ctx = get_ipp_context(dev); struct drm_exynos_ipp_prop_list *prop_list = data; struct exynos_drm_ippdrv *ippdrv; @@ -346,10 +292,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, */ ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, prop_list->ipp_id); - if (IS_ERR(ippdrv)) { + if (!ippdrv) { DRM_ERROR("not found ipp%d driver.\n", prop_list->ipp_id); - return PTR_ERR(ippdrv); + return -ENODEV; } *prop_list = ippdrv->prop_list; @@ -432,7 +378,7 @@ static struct drm_exynos_ipp_event_work *ipp_create_event_work(void) if (!event_work) return ERR_PTR(-ENOMEM); - INIT_WORK((struct work_struct *)event_work, ipp_sched_event); + INIT_WORK(&event_work->work, ipp_sched_event); return event_work; } @@ -441,8 +387,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; - struct device *dev = priv->dev; + struct device *dev = file_priv->ipp_dev; struct ipp_context *ctx = get_ipp_context(dev); struct drm_exynos_ipp_property *property = data; struct exynos_drm_ippdrv *ippdrv; @@ -489,19 +434,18 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, if (!c_node) return -ENOMEM; - /* create property id */ - ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node, - &property->prop_id); - if (ret) { + ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node); + if (ret < 0) { DRM_ERROR("failed to create id.\n"); goto err_clear; } + property->prop_id = ret; DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n", property->prop_id, property->cmd, (int)ippdrv); /* stored property information and ippdrv in private data */ - c_node->priv = priv; + c_node->dev = dev; c_node->property = *property; c_node->state = IPP_STATE_IDLE; @@ -534,7 +478,6 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, INIT_LIST_HEAD(&c_node->mem_list[i]); 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); @@ -577,42 +520,18 @@ static void ipp_clean_cmd_node(struct ipp_context *ctx, kfree(c_node); } -static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) +static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) { - struct drm_exynos_ipp_property *property = &c_node->property; - struct drm_exynos_ipp_mem_node *m_node; - struct list_head *head; - int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, }; - - for_each_ipp_ops(i) { - /* source/destination memory list */ - head = &c_node->mem_list[i]; - - /* find memory node entry */ - list_for_each_entry(m_node, head, list) { - DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n", - i ? "dst" : "src", count[i], (int)m_node); - count[i]++; - } + switch (c_node->property.cmd) { + case IPP_CMD_WB: + return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); + case IPP_CMD_OUTPUT: + return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]); + case IPP_CMD_M2M: + default: + return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) && + !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); } - - DRM_DEBUG_KMS("min[%d]max[%d]\n", - min(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]), - max(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST])); - - /* - * M2M operations should be need paired memory address. - * so, need to check minimum count about src, dst. - * other case not use paired memory, so use maximum count - */ - if (ipp_is_m2m_cmd(property->cmd)) - ret = min(count[EXYNOS_DRM_OPS_SRC], - count[EXYNOS_DRM_OPS_DST]); - else - ret = max(count[EXYNOS_DRM_OPS_SRC], - count[EXYNOS_DRM_OPS_DST]); - - return ret; } static struct drm_exynos_ipp_mem_node @@ -683,16 +602,14 @@ static struct drm_exynos_ipp_mem_node struct drm_exynos_ipp_queue_buf *qbuf) { struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_buf_info buf_info; - void *addr; + struct drm_exynos_ipp_buf_info *buf_info; int i; m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); if (!m_node) return ERR_PTR(-ENOMEM); - /* clear base address for error handling */ - memset(&buf_info, 0x0, sizeof(buf_info)); + buf_info = &m_node->buf_info; /* operations, buffer id */ m_node->ops_id = qbuf->ops_id; @@ -707,6 +624,8 @@ static struct drm_exynos_ipp_mem_node /* get dma address by handle */ if (qbuf->handle[i]) { + dma_addr_t *addr; + addr = exynos_drm_gem_get_dma_addr(drm_dev, qbuf->handle[i], file); if (IS_ERR(addr)) { @@ -714,15 +633,14 @@ static struct drm_exynos_ipp_mem_node goto err_clear; } - buf_info.handles[i] = qbuf->handle[i]; - buf_info.base[i] = *(dma_addr_t *) addr; - DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%x]\n", - i, buf_info.base[i], (int)buf_info.handles[i]); + buf_info->handles[i] = qbuf->handle[i]; + buf_info->base[i] = *addr; + DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%lx]\n", i, + buf_info->base[i], buf_info->handles[i]); } } 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); @@ -930,8 +848,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ipp_private *priv = file_priv->ipp_priv; - struct device *dev = priv->dev; + struct device *dev = file_priv->ipp_dev; struct ipp_context *ctx = get_ipp_context(dev); struct drm_exynos_ipp_queue_buf *qbuf = data; struct drm_exynos_ipp_cmd_node *c_node; @@ -955,9 +872,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, /* find command node */ c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, qbuf->prop_id); - if (IS_ERR(c_node)) { + if (!c_node) { DRM_ERROR("failed to get command node.\n"); - return PTR_ERR(c_node); + return -ENODEV; } /* buffer control */ @@ -1062,9 +979,8 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, struct drm_file *file) { 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 device *dev = priv->dev; + struct device *dev = file_priv->ipp_dev; struct ipp_context *ctx = get_ipp_context(dev); struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; struct drm_exynos_ipp_cmd_work *cmd_work; @@ -1091,9 +1007,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, cmd_ctrl->prop_id); - if (IS_ERR(c_node)) { + if (!c_node) { DRM_ERROR("invalid command node list.\n"); - return PTR_ERR(c_node); + return -ENODEV; } if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, @@ -1198,7 +1114,6 @@ static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, /* reset h/w block */ if (ippdrv->reset && ippdrv->reset(ippdrv->dev)) { - DRM_ERROR("failed to reset.\n"); return -EINVAL; } @@ -1216,30 +1131,24 @@ static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, /* set format */ if (ops->set_fmt) { ret = ops->set_fmt(ippdrv->dev, config->fmt); - if (ret) { - DRM_ERROR("not support format.\n"); + if (ret) return ret; - } } /* set transform for rotation, flip */ if (ops->set_transf) { ret = ops->set_transf(ippdrv->dev, config->degree, config->flip, &swap); - if (ret) { - DRM_ERROR("not support tranf.\n"); - return -EINVAL; - } + if (ret) + return ret; } /* set size */ if (ops->set_size) { ret = ops->set_size(ippdrv->dev, swap, &config->pos, &config->sz); - if (ret) { - DRM_ERROR("not support size.\n"); + if (ret) return ret; - } } } @@ -1283,11 +1192,6 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, m_node = list_first_entry(head, struct drm_exynos_ipp_mem_node, list); - if (!m_node) { - DRM_ERROR("failed to get node.\n"); - ret = -EFAULT; - goto err_unlock; - } DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node); @@ -1545,11 +1449,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, m_node = list_first_entry(head, struct drm_exynos_ipp_mem_node, list); - if (!m_node) { - DRM_ERROR("empty memory node.\n"); - ret = -ENOMEM; - goto err_mem_unlock; - } tbuf_id[i] = m_node->buf_id; DRM_DEBUG_KMS("%s buf_id[%d]\n", @@ -1586,11 +1485,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, m_node = list_first_entry(head, struct drm_exynos_ipp_mem_node, list); - if (!m_node) { - DRM_ERROR("empty memory node.\n"); - ret = -ENOMEM; - goto err_mem_unlock; - } tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; @@ -1704,21 +1598,17 @@ 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, - &ipp_id); - if (ret || ipp_id == 0) { + ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv); + if (ret < 0) { DRM_ERROR("failed to create id.\n"); goto err; } + ippdrv->prop_list.ipp_id = ret; DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n", - count++, (int)ippdrv, ipp_id); - - ippdrv->prop_list.ipp_id = ipp_id; + count++, (int)ippdrv, ret); /* store parent device for node */ ippdrv->parent_dev = dev; @@ -1776,17 +1666,10 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ipp_private *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - priv->dev = dev; - file_priv->ipp_priv = priv; - INIT_LIST_HEAD(&priv->event_list); + file_priv->ipp_dev = dev; - DRM_DEBUG_KMS("done priv[0x%x]\n", (int)priv); + DRM_DEBUG_KMS("done priv[0x%x]\n", (int)dev); return 0; } @@ -1795,13 +1678,12 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, struct drm_file *file) { 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); + DRM_DEBUG_KMS("for priv[0x%x]\n", (int)file_priv->ipp_dev); list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { mutex_lock(&ippdrv->cmd_lock); @@ -1810,7 +1692,7 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv); - if (c_node->priv == priv) { + if (c_node->dev == file_priv->ipp_dev) { /* * userland goto unnormal state. process killed. * and close the file. @@ -1832,7 +1714,6 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, mutex_unlock(&ippdrv->cmd_lock); } - kfree(priv); return; } |