clear-pkgs-linux-iot-lts2018/0855-media-intel-ipu4-ICI-W...

323 lines
11 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Yang, Zhonghua" <zhonghuax.yang@intel.com>
Date: Thu, 27 Dec 2018 16:14:42 +0800
Subject: [PATCH] media: intel-ipu4: [ICI] Workaround to force compare buffer
index at ici dqbuf
The disorder of FW buffer index would causes first element of pubuf_list
to not match with HAL after memcpy.
HAL pending buffers may link to same user_ptr, then crash or hung.
Change-Id: I01c1ecf5ce68faa67c5f031e7a7b64b6506b431b
Tracked-On: OAM-73683
Tracked-On: OAM-73444
Tracked-On: OAM-73726
Signed-off-by: Yin.ZhiyeX <zhiyeyix@intel.com>
---
.../media/pci/intel/ici/ici-isys-frame-buf.c | 93 ++++++++++---------
drivers/media/pci/intel/ici/ici-isys-stream.c | 16 +++-
2 files changed, 60 insertions(+), 49 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 6c2b608..5d3c876 100644
--- a/drivers/media/pci/intel/ici/ici-isys-frame-buf.c
+++ b/drivers/media/pci/intel/ici/ici-isys-frame-buf.c
@@ -77,9 +77,9 @@ static void ici_put_userpages(struct device *dev,
struct scatterlist *sgl;
unsigned int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- DEFINE_DMA_ATTRS(attrs);
+ DEFINE_DMA_ATTRS(attrs);
#else
- unsigned long attrs;
+ unsigned long attrs;
#endif
struct mm_struct* mm = current->active_mm;
@@ -95,7 +95,7 @@ static void ici_put_userpages(struct device *dev,
dma_unmap_sg_attrs(kframe_plane->dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- attrs = DMA_ATTR_SKIP_CPU_SYNC;
+ attrs = DMA_ATTR_SKIP_CPU_SYNC;
dma_unmap_sg_attrs(kframe_plane->dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, attrs);
#endif
@@ -125,9 +125,9 @@ static void ici_put_userpages_virt(struct device *dev,
{
struct sg_table *sgt = kframe_plane->sgt;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- DEFINE_DMA_ATTRS(attrs);
+ DEFINE_DMA_ATTRS(attrs);
#else
- unsigned long attrs;
+ unsigned long attrs;
#endif
struct mm_struct* mm = current->active_mm;
@@ -143,7 +143,7 @@ static void ici_put_userpages_virt(struct device *dev,
dma_unmap_sg_attrs(kframe_plane->dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- attrs = DMA_ATTR_SKIP_CPU_SYNC;
+ attrs = DMA_ATTR_SKIP_CPU_SYNC;
dma_unmap_sg_attrs(kframe_plane->dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, attrs);
#endif
@@ -255,9 +255,9 @@ static int ici_get_userpages(struct device *dev,
struct sg_table *sgt;
unsigned int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- DEFINE_DMA_ATTRS(attrs);
+ DEFINE_DMA_ATTRS(attrs);
#else
- unsigned long attrs;
+ unsigned long attrs;
#endif
addr = (unsigned long)frame_plane->mem.userptr;
@@ -289,12 +289,12 @@ static int ici_get_userpages(struct device *dev,
current, current->mm,
start, npages, 1, 0, pages, NULL);
#else
- nr = get_user_pages(start, npages, FOLL_WRITE, pages, NULL);
+ nr = get_user_pages(start, npages, FOLL_WRITE, pages, NULL);
#endif
if (nr < npages)
goto error_free_pages;
- ret = sg_alloc_table_from_pages(sgt, pages, npages,
+ ret = sg_alloc_table_from_pages(sgt, pages, npages,
addr & ~PAGE_MASK, frame_plane->length,
GFP_KERNEL);
if (ret) {
@@ -305,13 +305,13 @@ static int ici_get_userpages(struct device *dev,
kframe_plane->dev = dev;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- attrs = DMA_ATTR_SKIP_CPU_SYNC;
- sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
- DMA_FROM_DEVICE, attrs);
+ attrs = DMA_ATTR_SKIP_CPU_SYNC;
+ sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ DMA_FROM_DEVICE, attrs);
#endif
if (sgt->nents <= 0) {
@@ -334,10 +334,10 @@ static int ici_get_userpages(struct device *dev,
error_dma_map:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, attrs);
#endif
@@ -362,9 +362,9 @@ static int ici_get_userpages_virt(struct device *dev,
int ret = 0;
struct sg_table *sgt;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- DEFINE_DMA_ATTRS(attrs);
+ DEFINE_DMA_ATTRS(attrs);
#else
- unsigned long attrs;
+ unsigned long attrs;
#endif
addr = (unsigned long)frame_plane->mem.userptr;
@@ -377,7 +377,7 @@ static int ici_get_userpages_virt(struct device *dev,
if (!sgt)
return -ENOMEM;
- ret = sg_alloc_table_from_pages(sgt, pages, npages,
+ ret = sg_alloc_table_from_pages(sgt, pages, npages,
addr & ~PAGE_MASK, frame_plane->length,
GFP_KERNEL);
if (ret) {
@@ -388,12 +388,12 @@ static int ici_get_userpages_virt(struct device *dev,
kframe_plane->dev = dev;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- attrs = DMA_ATTR_SKIP_CPU_SYNC;
- sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ attrs = DMA_ATTR_SKIP_CPU_SYNC;
+ sgt->nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, attrs);
#endif
@@ -410,10 +410,10 @@ static int ici_get_userpages_virt(struct device *dev,
error_dma_map:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, &attrs);
#else
- dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->orig_nents,
DMA_FROM_DEVICE, attrs);
#endif
@@ -595,9 +595,9 @@ int ici_isys_put_buf(struct ici_isys_stream *as,
rval = wait_event_interruptible(buf_list->wait,
!list_empty(&buf_list->
putbuf_list));
- spin_lock_irqsave(&buf_list->lock, flags);
if (rval == -ERESTARTSYS)
return rval;
+ spin_lock_irqsave(&buf_list->lock, flags);
}
}
@@ -606,16 +606,21 @@ int ici_isys_put_buf(struct ici_isys_stream *as,
return -ENODATA;
}
- buf = list_entry(buf_list->putbuf_list.next,
- struct ici_frame_buf_wrapper, node);
- list_del(&buf->node);
-
- buf->state = ICI_BUF_DONE;
- list_add_tail(&buf->node,
- &buf_list->getbuf_list);
+ // FIXME: This is different from ICG V4L2 implementation which uses time stamp
+ // to sort frames
+ list_for_each_entry(buf, &buf_list->putbuf_list, node) {
+ if (buf->state == ICI_BUF_READY && buf->frame_info.frame_buf_id ==
+ frame_info->frame_buf_id) {
+ list_del(&buf->node);
+ memcpy(frame_info, &buf->frame_info, sizeof(buf->frame_info));
+ buf->state = ICI_BUF_DONE;
+ list_add_tail(&buf->node,
+ &buf_list->getbuf_list);
+ break;
+ }
+ }
spin_unlock_irqrestore(&buf_list->lock, flags);
- memcpy(frame_info, &buf->frame_info, sizeof(buf->frame_info));
return 0;
}
@@ -639,7 +644,7 @@ void ici_isys_frame_buf_ready(struct ici_isys_pipeline
{
struct ici_frame_buf_wrapper *buf;
struct ici_isys_stream *as =
- ici_pipeline_to_stream(ip);
+ ici_pipeline_to_stream(ip);
struct ici_isys_frame_buf_list *buf_list = &as->buf_list;
struct ici_isys *isys = as->isys;
unsigned long flags = 0;
@@ -809,7 +814,7 @@ int ici_isys_frame_buf_add_next(
css_buf->send_irq_sof = 1;
css_buf->output_pins[buf_list->fw_output].addr =
(uint32_t)buf->kframe_info.planes[0].dma_addr;
- css_buf->output_pins[buf_list->fw_output].out_buf_id =
+ css_buf->output_pins[buf_list->fw_output].out_buf_id =
buf->buf_id + 1;
if (buf_list->short_packet_bufs) {
@@ -925,16 +930,16 @@ void ici_isys_frame_buf_short_packet_destroy(
{
struct ici_isys_frame_buf_list *buf_list =
&as->buf_list;
- unsigned int i;
+ unsigned int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- struct dma_attrs attrs;
+ struct dma_attrs attrs;
init_dma_attrs(&attrs);
dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
#else
- unsigned long attrs;
- attrs = DMA_ATTR_NON_CONSISTENT;
+ unsigned long attrs;
+ attrs = DMA_ATTR_NON_CONSISTENT;
#endif
- if (!buf_list->short_packet_bufs)
+ if (!buf_list->short_packet_bufs)
return;
for (i = 0 ; i < ICI_ISYS_SHORT_PACKET_BUFFER_NUM ;
@@ -963,9 +968,9 @@ int ici_isys_frame_buf_short_packet_setup(
struct ici_isys_frame_buf_list *buf_list =
&as->buf_list;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
- struct dma_attrs attrs;
+ struct dma_attrs attrs;
#else
- unsigned long attrs;
+ unsigned long attrs;
#endif
unsigned int i;
size_t buf_size;
@@ -982,10 +987,10 @@ int ici_isys_frame_buf_short_packet_setup(
init_dma_attrs(&attrs);
dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
#else
- attrs = DMA_ATTR_NON_CONSISTENT;
+ attrs = DMA_ATTR_NON_CONSISTENT;
#endif
- as->ip.cur_field = ICI_FIELD_TOP;
+ as->ip.cur_field = ICI_FIELD_TOP;
buf_list->short_packet_bufs = kzalloc(
sizeof(struct ici_frame_short_buf) *
diff --git a/drivers/media/pci/intel/ici/ici-isys-stream.c b/drivers/media/pci/intel/ici/ici-isys-stream.c
index dc17cfb..33fec29 100644
--- a/drivers/media/pci/intel/ici/ici-isys-stream.c
+++ b/drivers/media/pci/intel/ici/ici-isys-stream.c
@@ -139,6 +139,7 @@ static int pipeline_set_power(struct ici_isys_stream *as,
static int intel_ipu4_isys_library_close(struct ici_isys *isys)
{
struct device *dev = &isys->adev->dev;
+ int timeout = IPU_ISYS_TURNOFF_TIMEOUT;
int rval;
unsigned long flags;
/*
@@ -146,16 +147,21 @@ static int intel_ipu4_isys_library_close(struct ici_isys *isys)
* some time as the FW must stop its actions including code fetch
* to SP icache.
*/
+ mutex_lock(&(isys)->lib_mutex);
spin_lock_irqsave(&isys->power_lock, flags);
- rval = ipu_lib_call(device_close, isys);
+ rval = ipu_lib_call_notrace_unlocked(device_close, isys);
spin_unlock_irqrestore(&isys->power_lock, flags);
+ mutex_unlock(&(isys)->lib_mutex);
if (rval)
dev_err(dev, "Device close failure: %d\n", rval);
- //sleep for 0.5s to 1s
- usleep_range(500 * IPU_ISYS_TURNOFF_DELAY_US,
- 1000 * IPU_ISYS_TURNOFF_DELAY_US);
- rval = ipu_lib_call_notrace(device_release, isys, 0);
+ /* release probably fails if the close failed. Let's try still */
+ do {
+ usleep_range(IPU_ISYS_TURNOFF_DELAY_US,
+ 2 * IPU_ISYS_TURNOFF_DELAY_US);
+ rval = ipu_lib_call_notrace(device_release, isys, 0);
+ timeout--;
+ } while (rval != 0 && timeout);
spin_lock_irqsave(&isys->power_lock, flags);
if (!rval)
--
https://clearlinux.org