From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Ong Hock Yu Date: Mon, 3 Dec 2018 01:02:05 +0000 Subject: [PATCH] media: intel-ipu4: [ICI] Fix putbuf list and getbuf list out of sync issue. As both the list used indenpedent lock, this caused them get out of sync when transferring buffer between the list. Change-Id: Id66e877cbbd47e2d46653d008f06d9dfe75e5df9 Tracked-On: OAM-64123 Tracked-On: OAM-64294 Tracked-On: OAM-64937 Tracked-On: OLINUX-2973 Tracked-On: OLINUX-3042 Signed-off-by: Ong Hock Yu --- .../media/pci/intel/ici/ici-isys-frame-buf.c | 48 ++++++++++++------- .../pci/intel/virtio/intel-ipu4-virtio-be.c | 12 +++-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/media/pci/intel/ici/ici-isys-frame-buf.c b/drivers/media/pci/intel/ici/ici-isys-frame-buf.c index 2ef0c6d86d9b..e38ba99392aa 100644 --- a/drivers/media/pci/intel/ici/ici-isys-frame-buf.c +++ b/drivers/media/pci/intel/ici/ici-isys-frame-buf.c @@ -31,7 +31,9 @@ static struct ici_frame_buf_wrapper struct ici_frame_buf_wrapper *buf; int i; int mem_type = user_frame_info->mem_type; + unsigned long flags = 0; + spin_lock_irqsave(&buf_list->lock, flags); list_for_each_entry(buf, &buf_list->getbuf_list, node) { for (i = 0; i < user_frame_info->num_planes; i++) { struct ici_frame_plane *new_plane = @@ -46,19 +48,24 @@ static struct ici_frame_buf_wrapper switch (mem_type) { case ICI_MEM_USERPTR: if (new_plane->mem.userptr == - cur_plane->mem.userptr) + cur_plane->mem.userptr) { + spin_unlock_irqrestore(&buf_list->lock, flags); return buf; + } break; case ICI_MEM_DMABUF: if (new_plane->mem.dmafd == - cur_plane->mem.dmafd) + cur_plane->mem.dmafd) { + spin_unlock_irqrestore(&buf_list->lock, flags); return buf; + } break; } //TODO: add multiplaner checks } } + spin_unlock_irqrestore(&buf_list->lock, flags); return NULL; } @@ -421,6 +428,7 @@ int ici_isys_get_buf(struct ici_isys_stream *as, int res; unsigned i; struct ici_frame_buf_wrapper *buf; + unsigned long flags = 0; struct ici_kframe_plane *kframe_plane; struct ici_isys_frame_buf_list *buf_list = &as->buf_list; @@ -489,10 +497,10 @@ int ici_isys_get_buf(struct ici_isys_stream *as, break; } - mutex_lock(&buf_list->mutex); + spin_lock_irqsave(&buf_list->lock, flags); buf->state = ICI_BUF_PREPARED; list_add_tail(&buf->node, &buf_list->getbuf_list); - mutex_unlock(&buf_list->mutex); + spin_unlock_irqrestore(&buf_list->lock, flags); return 0; err_exit: @@ -506,6 +514,7 @@ int ici_isys_get_buf_virt(struct ici_isys_stream *as, { int res; unsigned i; + unsigned long flags = 0; struct ici_frame_buf_wrapper *buf; struct ici_kframe_plane *kframe_plane; @@ -562,10 +571,10 @@ int ici_isys_get_buf_virt(struct ici_isys_stream *as, break; } - mutex_lock(&buf_list->mutex); + spin_lock_irqsave(&buf_list->lock, flags); buf->state = ICI_BUF_PREPARED; list_add_tail(&buf->node, &buf_list->getbuf_list); - mutex_unlock(&buf_list->mutex); + spin_unlock_irqrestore(&buf_list->lock, flags); return 0; } @@ -600,13 +609,11 @@ int ici_isys_put_buf(struct ici_isys_stream *as, buf = list_entry(buf_list->putbuf_list.next, struct ici_frame_buf_wrapper, node); list_del(&buf->node); - spin_unlock_irqrestore(&buf_list->lock, flags); - mutex_lock(&buf_list->mutex); buf->state = ICI_BUF_DONE; list_add_tail(&buf->node, &buf_list->getbuf_list); - mutex_unlock(&buf_list->mutex); + spin_unlock_irqrestore(&buf_list->lock, flags); memcpy(frame_info, &buf->frame_info, sizeof(buf->frame_info)); return 0; @@ -734,30 +741,35 @@ void ici_isys_frame_buf_stream_cancel(struct struct ici_isys_frame_buf_list *buf_list = &as->buf_list; struct ici_frame_buf_wrapper *buf; struct ici_frame_buf_wrapper *next_buf; - - mutex_lock(&buf_list->mutex); + unsigned long flags = 0; list_for_each_entry_safe(buf, next_buf, &buf_list->getbuf_list, node) { + spin_lock_irqsave(&buf_list->lock, flags); list_del(&buf->node); + spin_unlock_irqrestore(&buf_list->lock, flags); if (as->strm_dev.virt_dev_id < 0) unmap_buf(buf); else unmap_buf_virt(buf); } + list_for_each_entry_safe(buf, next_buf, &buf_list->putbuf_list, node) { + spin_lock_irqsave(&buf_list->lock, flags); list_del(&buf->node); + spin_unlock_irqrestore(&buf_list->lock, flags); if (as->strm_dev.virt_dev_id < 0) unmap_buf(buf); else unmap_buf_virt(buf); } + list_for_each_entry_safe(buf, next_buf, &buf_list->interlacebuf_list, node) { + spin_lock_irqsave(&buf_list->short_packet_queue_lock, flags); list_del(&buf->node); + spin_unlock_irqrestore(&buf_list->short_packet_queue_lock, flags); unmap_buf(buf); } - - mutex_unlock(&buf_list->mutex); } int ici_isys_frame_buf_add_next( @@ -769,7 +781,7 @@ int ici_isys_frame_buf_add_next( unsigned long flags = 0; bool found = false; - mutex_lock(&buf_list->mutex); + spin_lock_irqsave(&buf_list->lock, flags); list_for_each_entry(buf, &buf_list->getbuf_list, node) { if (buf->state == ICI_BUF_PREPARED){ @@ -780,12 +792,12 @@ int ici_isys_frame_buf_add_next( if (!found) { /* No more buffers available */ - goto cleanup_mutex; + goto cleanup_spinlock; } buf->state = ICI_BUF_ACTIVE; - mutex_unlock(&buf_list->mutex); + spin_unlock_irqrestore(&buf_list->lock, flags); pr_debug("%s: add buf to FW! %lu", __func__, buf->frame_info.frame_planes[0].mem.userptr); @@ -829,8 +841,8 @@ int ici_isys_frame_buf_add_next( } return 0; -cleanup_mutex: - mutex_unlock(&buf_list->mutex); +cleanup_spinlock: + spin_unlock_irqrestore(&buf_list->lock, flags); return -ENODATA; } diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c index b2c0f32d35fc..b0adf273bf0b 100644 --- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c +++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c @@ -221,14 +221,12 @@ static void handle_vq_kick(int client_id, int vq_idx) static int handle_kick(int client_id, long unsigned *ioreqs_map) { - int val[IPU_VIRTIO_QUEUE_MAX], i, count; + int *val, i, count; struct ipu4_virtio_be_priv *priv; if (unlikely(bitmap_empty(ioreqs_map, VHM_REQUEST_MAX))) return -EINVAL; - pr_debug("%s: IPU VBK handle kick!\n", __func__); - priv = ipu_vbk_hash_find(client_id); if (priv == NULL) { pr_err("%s: client %d not found!\n", @@ -236,7 +234,11 @@ static int handle_kick(int client_id, long unsigned *ioreqs_map) return -EINVAL; } - count = virtio_vqs_index_get(&priv->dev, ioreqs_map, val, IPU_VIRTIO_QUEUE_MAX); + val = kzalloc(priv->dev._ctx.max_vcpu * sizeof(int), + GFP_KERNEL); + + count = virtio_vqs_index_get(&priv->dev, ioreqs_map, val, + priv->dev._ctx.max_vcpu); for (i = 0; i < count; i++) { if (val[i] >= 0) { @@ -244,6 +246,8 @@ static int handle_kick(int client_id, long unsigned *ioreqs_map) } } + kfree(val); + return 0; } -- https://clearlinux.org