diff --git a/drivers/media/pci/intel/ipu7/abi/ipu7_fw_isys_abi.h b/drivers/media/pci/intel/ipu7/abi/ipu7_fw_isys_abi.h index db1bcfd..5d1e23a 100644 --- a/drivers/media/pci/intel/ipu7/abi/ipu7_fw_isys_abi.h +++ b/drivers/media/pci/intel/ipu7/abi/ipu7_fw_isys_abi.h @@ -399,13 +399,13 @@ struct ipu7_insys_resp { struct ipu7_insys_capture_output_pin_payload pin; struct ia_gofo_msg_err error_info; u32 timestamp[2]; - u16 mipi_fn; u8 type; u8 msg_link_streaming_mode; u8 stream_id; u8 pin_id; u8 frame_id; u8 skip_frame; + u16 mipi_fn; }; struct ipu7_insys_resp_queue_token { diff --git a/drivers/media/pci/intel/ipu7/ipu7-bus.c b/drivers/media/pci/intel/ipu7/ipu7-bus.c index 7da44fd..cd06417 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-bus.c +++ b/drivers/media/pci/intel/ipu7/ipu7-bus.c @@ -75,6 +75,7 @@ static void ipu7_bus_release(struct device *dev) { struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + mutex_destroy(&adev->acquire_fw_task_buffer_lock); kfree(adev->pdata); kfree(adev); } @@ -96,6 +97,7 @@ ipu7_bus_initialize_device(struct pci_dev *pdev, struct device *parent, adev->isp = isp; adev->ctrl = ctrl; adev->pdata = pdata; + mutex_init(&adev->acquire_fw_task_buffer_lock); auxdev = &adev->auxdev; auxdev->name = name; auxdev->id = (pci_domain_nr(pdev->bus) << 16) | diff --git a/drivers/media/pci/intel/ipu7/ipu7-bus.h b/drivers/media/pci/intel/ipu7/ipu7-bus.h index 45157df..eb9d0c9 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-bus.h +++ b/drivers/media/pci/intel/ipu7/ipu7-bus.h @@ -46,6 +46,12 @@ struct ipu7_bus_device { struct ia_gofo_boot_config *boot_config; dma_addr_t boot_config_dma_addr; u32 boot_config_size; + + /* Serialize FW message buffer or task queue acquisition against + * TLB invalidation. + */ + struct mutex acquire_fw_task_buffer_lock; + unsigned int (*get_running_fw_task_count)(struct ipu7_bus_device *adev); }; struct ipu7_auxdrv_data { diff --git a/drivers/media/pci/intel/ipu7/ipu7-dma.c b/drivers/media/pci/intel/ipu7/ipu7-dma.c index 48fdf70..e3c6208 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-dma.c +++ b/drivers/media/pci/intel/ipu7/ipu7-dma.c @@ -219,7 +219,8 @@ void *ipu7_dma_alloc(struct ipu7_bus_device *sys, size_t size, } } - mmu->tlb_invalidate(mmu); + if (mmu->mmid == ISYS_MMID) + mmu->tlb_invalidate(mmu, IPU_IS_MMU_FW_RD); info->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL); if (!info->vaddr) @@ -309,7 +310,7 @@ void ipu7_dma_free(struct ipu7_bus_device *sys, size_t size, void *vaddr, __free_buffer(pages, size, attrs); - mmu->tlb_invalidate(mmu); + mmu->tlb_invalidate(mmu, -1); __free_iova(&mmu->dmap->iovad, iova); @@ -396,7 +397,9 @@ void ipu7_dma_unmap_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), PFN_PHYS(iova_size(iova))); - mmu->tlb_invalidate(mmu); + mutex_lock(&sys->acquire_fw_task_buffer_lock); + mmu->tlb_invalidate(mmu, -1); + mutex_unlock(&sys->acquire_fw_task_buffer_lock); __free_iova(&mmu->dmap->iovad, iova); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) diff --git a/drivers/media/pci/intel/ipu7/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu7/ipu7-fw-isys.c index c594dbd..ca2dbf0 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-fw-isys.c +++ b/drivers/media/pci/intel/ipu7/ipu7-fw-isys.c @@ -119,7 +119,7 @@ static size_t isys_prepare_fw_payload(void *cpu_mapped_buf, } } -static void isys_decode_resp_v1(struct ipu7_insys_resp *dst, const void *token) +static __maybe_unused void isys_decode_resp_v1(struct ipu7_insys_resp *dst, const void *token) { const struct ipu7_insys_resp_v1 *src = token; @@ -212,17 +212,14 @@ int ipu7_fw_isys_init(struct ipu7_isys *isys) if (!syscom) return -ENOMEM; - if (is_ipu8(adev->isp->hw_ver)) { + if (is_ipu8(adev->isp->hw_ver)) isys->abi_ops.prepare_payload = isys_prepare_fw_payload; - isys->abi_ops.decode_resp = isys_decode_resp; - isys->abi_ops.resp_queue_token_size = - sizeof(struct ipu7_insys_resp); - } else { + else isys->abi_ops.prepare_payload = isys_prepare_fw_payload_v1; - isys->abi_ops.decode_resp = isys_decode_resp_v1; - isys->abi_ops.resp_queue_token_size = - sizeof(struct ipu7_insys_resp_v1); - } + + isys->abi_ops.decode_resp = isys_decode_resp; + isys->abi_ops.resp_queue_token_size = + sizeof(struct ipu7_insys_resp); adev->syscom = syscom; syscom->num_input_queues = IPU_INSYS_MAX_INPUT_QUEUES; diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys-queue.c b/drivers/media/pci/intel/ipu7/ipu7-isys-queue.c index 06d280e..f6dc20c 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys-queue.c +++ b/drivers/media/pci/intel/ipu7/ipu7-isys-queue.c @@ -337,6 +337,8 @@ static int ipu7_isys_stream_start(struct ipu7_isys_video *av, if (!msg) return -ENOMEM; + msg->stream_id = stream->stream_handle; + buf = &msg->fw_msg.frame; ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl); @@ -437,6 +439,7 @@ static void buf_queue(struct vb2_buffer *vb) ret = -ENOMEM; goto out; } + msg->stream_id = stream->stream_handle; buf = &msg->fw_msg.frame; @@ -655,11 +658,13 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) static void reset_stop_streaming(struct ipu7_isys_video *av) { struct ipu7_isys_queue *aq = &av->aq; + struct device *dev = &av->isys->adev->auxdev.dev; struct ipu7_isys_stream *stream = av->stream; struct ipu7_isys_buffer *ib; struct vb2_buffer *vb; unsigned long flags; + dev_dbg(dev, "reset stop streams: %s\n", av->vdev.name); mutex_lock(&av->isys->stream_mutex); if (stream->nr_streaming == stream->nr_queues && stream->streaming) ipu7_isys_video_set_streaming(av, 0, NULL); @@ -830,7 +835,6 @@ static int ipu_isys_reset(struct ipu7_isys_video *self_av, mutex_unlock(&isys->reset_mutex); - dev_dbg(dev, "reset stop streams\n"); for (i = 0; i < csi2_pdata->nports; i++) { for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) { av = &isys->csi2[i].av[j]; @@ -855,8 +859,6 @@ static int ipu_isys_reset(struct ipu7_isys_video *self_av, ipu7_cleanup_fw_msg_bufs(isys); - dev_dbg(dev, "reset start streams\n"); - for (j = 0; j < csi2_pdata->nports; j++) { for (i = 0; i < IPU7_NR_OF_CSI2_SRC_PADS; i++) { av = &isys->csi2[j].av[i]; @@ -947,7 +949,7 @@ static void stop_streaming(struct vb2_queue *q) mutex_unlock(&av->isys->reset_mutex); if (need_reset) { - if (!stream->nr_streaming) { + if (av->isys->stream_opened > 0) { ipu_isys_reset(av, stream); } else { mutex_lock(&av->isys->reset_mutex); diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys-video.c b/drivers/media/pci/intel/ipu7/ipu7-isys-video.c index 3078cf2..94d6a3f 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys-video.c +++ b/drivers/media/pci/intel/ipu7/ipu7-isys-video.c @@ -91,25 +91,6 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { IPU_INSYS_FRAME_FORMAT_RGBA888}, }; -static int video_open(struct file *file) -{ -#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET - struct ipu7_isys_video *av = video_drvdata(file); - struct ipu7_isys *isys = av->isys; - struct ipu7_bus_device *adev = isys->adev; - - mutex_lock(&isys->reset_mutex); - if (isys->need_reset) { - mutex_unlock(&isys->reset_mutex); - dev_warn(&adev->auxdev.dev, "isys power cycle required\n"); - return -EIO; - } - mutex_unlock(&isys->reset_mutex); - -#endif - return v4l2_fh_open(file); -} - #ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET static int video_release(struct file *file) { @@ -507,6 +488,8 @@ static int start_stream_firmware(struct ipu7_isys_video *av, if (!msg) return -ENOMEM; + msg->stream_id = stream->stream_handle; + stream_cfg = &msg->fw_msg.stream; stream_cfg->port_id = stream->stream_source; stream_cfg->vc = stream->vc; @@ -563,6 +546,7 @@ static int start_stream_firmware(struct ipu7_isys_video *av, ret = -ENOMEM; goto out_put_stream_opened; } + msg->stream_id = stream->stream_handle; buf = &msg->fw_msg.frame; ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl); @@ -862,6 +846,7 @@ int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state, struct media_pad *r_pad; struct v4l2_subdev *sd; u32 r_stream = 0; + u16 stream_id = stream->stream_handle; int ret = 0; dev_dbg(dev, "set stream: %d\n", state); @@ -886,6 +871,7 @@ int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state, } close_streaming_firmware(av); + ipu7_cleanup_fw_msg_bufs_by_stream_id(av->isys, stream_id); } else { ret = start_stream_firmware(av, bl); if (ret) { @@ -942,7 +928,7 @@ static const struct v4l2_file_operations isys_fops = { .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, - .open = video_open, + .open = v4l2_fh_open, #ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET .release = video_release, #else diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys.c b/drivers/media/pci/intel/ipu7/ipu7-isys.c index bf4dfe1..8b0f0c3 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys.c +++ b/drivers/media/pci/intel/ipu7/ipu7-isys.c @@ -505,6 +505,8 @@ static void isys_v4l2_notify(struct v4l2_subdev *sd, unsigned int notification, container_of(sd->v4l2_dev, struct ipu7_isys, v4l2_dev); struct device *dev = &isys->adev->auxdev.dev; struct v4l2_event *ev = arg; + struct ipu7_isys_csi2_config *csi2_cfg; + unsigned int i; unsigned long flags; spin_lock_irqsave(&isys->power_lock, flags); @@ -517,14 +519,31 @@ static void isys_v4l2_notify(struct v4l2_subdev *sd, unsigned int notification, spin_unlock_irqrestore(&isys->power_lock, flags); if (notification == V4L2_DEVICE_NOTIFY_EVENT) { - if ((ev->type == V4L2_EVENT_SOURCE_CHANGE || - ev->type == V4L2_EVENT_EOS) && - isys->stream_opened > 1) { - dev_dbg(dev, "%s: isys need reset due to notify %u, stream opened %d\n", - sd->name, ev->type, isys->stream_opened); - mutex_lock(&isys->reset_mutex); - isys->need_reset = true; - mutex_unlock(&isys->reset_mutex); + if (ev->type == V4L2_EVENT_SOURCE_CHANGE || + ev->type == V4L2_EVENT_EOS) { + csi2_cfg = v4l2_get_subdev_hostdata(sd); + if (!csi2_cfg) { + dev_warn(dev, "%s: missing csi2 cfg for notify %u\n", + sd->name, ev->type); + return; + } + + for (i = 0; i < IPU7_NR_OF_CSI2_SRC_PADS; i++) { + struct ipu7_isys_video *av = + &isys->csi2[csi2_cfg->port].av[i]; + + if (READ_ONCE(av->start_streaming)) { + dev_info(dev, + "%s: isys need reset due to notify %u on port %u\n", + sd->name, ev->type, csi2_cfg->port); + mutex_lock(&isys->reset_mutex); + isys->need_reset = true; + mutex_unlock(&isys->reset_mutex); + return; + } + } + dev_dbg(dev, "%s: notify %u ignored, no AV starting on this port\n", + sd->name, notification); } } else { dev_warn(dev, "%s: unknown notification %u\n", @@ -817,6 +836,8 @@ static void isys_remove(struct auxiliary_device *auxdev) struct isys_fw_msgs *fwmsg, *safe; struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); + adev->get_running_fw_task_count = NULL; + #ifdef CONFIG_DEBUG_FS if (adev->isp->ipu7_dir) debugfs_remove_recursive(isys->debugfsdir); @@ -852,6 +873,8 @@ static void isys_remove(struct auxiliary_device *auxdev) struct isys_fw_msgs *fwmsg, *safe; struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); + adev->get_running_fw_task_count = NULL; + #ifdef CONFIG_DEBUG_FS if (adev->isp->ipu7_dir) debugfs_remove_recursive(isys->debugfsdir); @@ -989,6 +1012,23 @@ static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) return -ENOMEM; } +static unsigned int ipu7_isys_get_running_fw_task_count( + struct ipu7_bus_device *adev) +{ + struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); + unsigned long flags; + unsigned int count; + + if (!isys) + return 0; + + spin_lock_irqsave(&isys->listlock, flags); + count = list_count_nodes(&isys->framebuflist_fw); + spin_unlock_irqrestore(&isys->listlock, flags); + + return count; +} + struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) { struct device *dev = &stream->isys->adev->auxdev.dev; @@ -997,18 +1037,22 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) unsigned long flags; int ret; + mutex_lock(&isys->adev->acquire_fw_task_buffer_lock); spin_lock_irqsave(&isys->listlock, flags); if (list_empty(&isys->framebuflist)) { spin_unlock_irqrestore(&isys->listlock, flags); dev_dbg(dev, "Frame buffer list empty\n"); - ret = alloc_fw_msg_bufs(isys, 5); - if (ret < 0) + ret = alloc_fw_msg_bufs(isys, 10); + if (ret < 0) { + mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); return NULL; + } spin_lock_irqsave(&isys->listlock, flags); if (list_empty(&isys->framebuflist)) { spin_unlock_irqrestore(&isys->listlock, flags); + mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); dev_err(dev, "Frame list empty\n"); return NULL; } @@ -1016,6 +1060,7 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head); list_move(&msg->head, &isys->framebuflist_fw); spin_unlock_irqrestore(&isys->listlock, flags); + mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); memset(&msg->fw_msg, 0, sizeof(msg->fw_msg)); return msg; @@ -1032,6 +1077,20 @@ void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys) spin_unlock_irqrestore(&isys->listlock, flags); } +void ipu7_cleanup_fw_msg_bufs_by_stream_id(struct ipu7_isys *isys, + u16 stream_id) +{ + struct isys_fw_msgs *fwmsg, *fwmsg0; + unsigned long flags; + + spin_lock_irqsave(&isys->listlock, flags); + list_for_each_entry_safe(fwmsg, fwmsg0, &isys->framebuflist_fw, head) { + if (fwmsg->stream_id == stream_id) + list_move(&fwmsg->head, &isys->framebuflist); + } + spin_unlock_irqrestore(&isys->listlock, flags); +} + void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data) { struct isys_fw_msgs *msg; @@ -1103,6 +1162,8 @@ static int isys_probe(struct auxiliary_device *auxdev, INIT_LIST_HEAD(&isys->framebuflist_fw); dev_set_drvdata(&auxdev->dev, isys); + adev->get_running_fw_task_count = + ipu7_isys_get_running_fw_task_count; isys->icache_prefetch = 0; isys->phy_rext_cal = 0; diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys.h b/drivers/media/pci/intel/ipu7/ipu7-isys.h index c950f24..0343b2e 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys.h +++ b/drivers/media/pci/intel/ipu7/ipu7-isys.h @@ -151,6 +151,7 @@ struct isys_fw_msgs { } fw_msg; struct list_head head; dma_addr_t dma_addr; + u16 stream_id; }; struct ipu7_isys_csi2_config { @@ -182,6 +183,8 @@ struct sensor_async_sd { struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream); void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data); void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys); +void ipu7_cleanup_fw_msg_bufs_by_stream_id(struct ipu7_isys *isys, + u16 stream_id); int isys_isr_one(struct ipu7_bus_device *adev); void ipu7_isys_setup_hw(struct ipu7_isys *isys); #endif /* IPU7_ISYS_H */ diff --git a/drivers/media/pci/intel/ipu7/ipu7-mmu.c b/drivers/media/pci/intel/ipu7/ipu7-mmu.c index 8ea5692..3f94bd2 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-mmu.c +++ b/drivers/media/pci/intel/ipu7/ipu7-mmu.c @@ -28,6 +28,7 @@ #include #include "ipu7.h" +#include "ipu7-bus.h" #include "ipu7-dma.h" #include "ipu7-mmu.h" #include "ipu7-platform-regs.h" @@ -53,6 +54,8 @@ #define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT) #define MMU_TLB_INVALIDATE_TIMEOUT 2000 +#define WAIT_FW_MSG_BUFS_CLEAR_TIME_MS 17 +#define WAIT_FW_MSG_BUFS_CLEAR_TIMES 5 static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) { @@ -67,12 +70,40 @@ static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) } } -static void tlb_invalidate(struct ipu7_mmu *mmu) +static void tlb_invalidate(struct ipu7_mmu *mmu, int mmu_id) { unsigned long flags; + unsigned int start, end; unsigned int i; int ret; u32 val; + unsigned int prev_task_cnt = UINT_MAX; + unsigned int curr_task_cnt; + unsigned int not_decreasing_count = 0; + struct ipu7_bus_device *adev = to_ipu7_bus_device(mmu->dev); + + if (adev->get_running_fw_task_count) { + while (1) { + curr_task_cnt = adev->get_running_fw_task_count(adev); + if (curr_task_cnt == 0) + break; + + if (curr_task_cnt >= prev_task_cnt) + not_decreasing_count++; + else + not_decreasing_count = 0; + prev_task_cnt = curr_task_cnt; + + if (not_decreasing_count > + WAIT_FW_MSG_BUFS_CLEAR_TIMES) { + dev_warn(mmu->dev, + "wait running fw tasks clear timeout\n"); + break; + } + + msleep(WAIT_FW_MSG_BUFS_CLEAR_TIME_MS); + } + } spin_lock_irqsave(&mmu->ready_lock, flags); if (!mmu->ready) { @@ -80,7 +111,23 @@ static void tlb_invalidate(struct ipu7_mmu *mmu) return; } - for (i = 0; i < mmu->nr_mmus; i++) { + /* mmu_id < 0: all MMUs, otherwise one MMU. */ + if (mmu_id < 0) { + start = 0; + end = mmu->nr_mmus; + } else if (mmu_id >= mmu->nr_mmus) { + dev_warn(mmu->dev, "invalid mmu_id %d, nr_mmus %u\n", + mmu_id, mmu->nr_mmus); + spin_unlock_irqrestore(&mmu->ready_lock, flags); + return; + } + + if (mmu_id >= 0) { + start = mmu_id; + end = mmu_id + 1; + } + + for (i = start; i < end; i++) { writel(0xffffffffU, mmu->mmu_hw[i].base + MMU_REG_INVALIDATE_0); diff --git a/drivers/media/pci/intel/ipu7/ipu7-mmu.h b/drivers/media/pci/intel/ipu7/ipu7-mmu.h index d85bb8f..e4bc485 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-mmu.h +++ b/drivers/media/pci/intel/ipu7/ipu7-mmu.h @@ -20,6 +20,12 @@ struct ipu7_mmu_info; #define ISYS_MMID 0x1 #define PSYS_MMID 0x0 +#define IPU_IS_MMU_FW_RD 0 +#define IPU_IS_MMU_FW_WR 1 +#define IPU_IS_MMU_M0 2 +#define IPU_IS_MMU_M1 3 +#define IPU_IS_MMU_UPIPE 4 + /* IPU7 for LNL */ /* IS MMU Cmd RD */ #define IPU7_IS_MMU_FW_RD_OFFSET 0x274000 @@ -396,7 +402,7 @@ struct ipu7_mmu { bool ready; spinlock_t ready_lock; /* Serialize access to bool ready */ - void (*tlb_invalidate)(struct ipu7_mmu *mmu); + void (*tlb_invalidate)(struct ipu7_mmu *mmu, int mmu_id); }; struct ipu7_mmu *ipu7_mmu_init(struct device *dev, diff --git a/drivers/media/pci/intel/ipu7/psys/ipu-psys.c b/drivers/media/pci/intel/ipu7/psys/ipu-psys.c index d89e8b6..a409a69 100644 --- a/drivers/media/pci/intel/ipu7/psys/ipu-psys.c +++ b/drivers/media/pci/intel/ipu7/psys/ipu-psys.c @@ -886,6 +886,20 @@ static long ipu_psys_graph_open(struct ipu_psys_graph_info *graph, return 0; } +static void ipu_psys_cleanup_running_task_queue(struct ipu7_psys_fh *fh) +{ + struct ipu7_psys_stream *ip = fh->ip; + struct ipu_psys_task_queue *tq; + struct ipu_psys_task_queue *tmp; + + mutex_lock(&ip->task_mutex); + list_for_each_entry_safe(tq, tmp, &ip->tq_running_list, list) { + tq->task_state = IPU_MSG_TASK_STATE_DONE; + list_move_tail(&tq->list, &ip->tq_list); + } + mutex_unlock(&ip->task_mutex); +} + static long ipu_psys_graph_close(int graph_id, struct ipu7_psys_fh *fh) { struct ipu7_psys *psys = fh->psys; @@ -922,6 +936,8 @@ static long ipu_psys_graph_close(int graph_id, struct ipu7_psys_fh *fh) return -EINVAL; } + ipu_psys_cleanup_running_task_queue(fh); + return 0; } @@ -989,6 +1005,27 @@ ipu7_psys_get_task_queue(struct ipu7_psys_stream *ip, return NULL; } +static unsigned int ipu7_psys_get_running_fw_task_count( + struct ipu7_bus_device *adev) +{ + struct ipu7_psys *psys = ipu7_bus_get_drvdata(adev); + struct ipu7_psys_fh *fh; + unsigned int count = 0; + + if (!psys) + return 0; + + mutex_lock(&psys->mutex); + list_for_each_entry(fh, &psys->fhs, list) { + mutex_lock(&fh->ip->task_mutex); + count += list_count_nodes(&fh->ip->tq_running_list); + mutex_unlock(&fh->ip->task_mutex); + } + mutex_unlock(&psys->mutex); + + return count; +} + static long ipu_psys_task_request(struct ipu_psys_task_request *task, struct ipu7_psys_fh *fh) { @@ -1001,7 +1038,9 @@ static long ipu_psys_task_request(struct ipu_psys_task_request *task, return -EINVAL; } + mutex_lock(&psys->adev->acquire_fw_task_buffer_lock); tq = ipu7_psys_get_task_queue(fh->ip, task); + mutex_unlock(&psys->adev->acquire_fw_task_buffer_lock); if (!tq) { dev_err(&psys->dev, "Failed to get task queue\n"); return -EINVAL; @@ -1424,6 +1463,8 @@ static int ipu7_psys_probe(struct auxiliary_device *auxdev, } dev_set_drvdata(dev, psys); + adev->get_running_fw_task_count = + ipu7_psys_get_running_fw_task_count; mutex_unlock(&ipu7_psys_mutex); #ifdef CONFIG_DEBUG_FS psys_fw_log_init(psys); @@ -1458,6 +1499,8 @@ static void ipu7_psys_remove(struct auxiliary_device *auxdev) { struct ipu7_psys *psys = dev_get_drvdata(&auxdev->dev); struct device *dev = &auxdev->dev; + + psys->adev->get_running_fw_task_count = NULL; #ifdef CONFIG_DEBUG_FS struct ipu7_device *isp = psys->adev->isp; diff --git a/patch/v7.0.0_iot/0001-ipu7-Wait-ipu-fw-requests-to-clear.patch b/patch/v7.0.0_iot/0001-ipu7-Wait-ipu-fw-requests-to-clear.patch new file mode 100644 index 0000000..2731c48 --- /dev/null +++ b/patch/v7.0.0_iot/0001-ipu7-Wait-ipu-fw-requests-to-clear.patch @@ -0,0 +1,294 @@ +From f7907df8dcf5c1bb736e3ad4de1db3f010c4ea84 Mon Sep 17 00:00:00 2001 +From: hepengpx +Date: Wed, 17 Jun 2026 10:13:25 +0800 +Subject: [PATCH 01/23] ipu7: Wait ipu fw requests to clear + +IPU ISYS MMUs run in parallel, and runtime TLB invalidation may +overlap with ongoing data movement. For fw msg buf expansion, +invalidating ISYS MMU0 is sufficient. + +The goal of acquire_fw_task_buffer_lock is to block subsequent +getting fw message buffer or task queue while waiting for +framebuflist_fw to drain. + +With "glimagesink sync=false", gstreamer will launch each stream one +by one. So, when isys message buffer is not enough, just allocating +max buffer count(10) is enough. + +Signed-off-by: hepengpx +--- + drivers/staging/media/ipu7/ipu7-bus.c | 2 + + drivers/staging/media/ipu7/ipu7-bus.h | 6 +++ + drivers/staging/media/ipu7/ipu7-dma.c | 8 +++- + drivers/staging/media/ipu7/ipu7-isys.c | 30 ++++++++++++++- + drivers/staging/media/ipu7/ipu7-mmu.c | 52 +++++++++++++++++++++++++- + drivers/staging/media/ipu7/ipu7-mmu.h | 8 +++- + 6 files changed, 99 insertions(+), 7 deletions(-) + +diff --git a/drivers/staging/media/ipu7/ipu7-bus.c b/drivers/staging/media/ipu7/ipu7-bus.c +index 7a1b0744b236..397fcab0a7ee 100644 +--- a/drivers/staging/media/ipu7/ipu7-bus.c ++++ b/drivers/staging/media/ipu7/ipu7-bus.c +@@ -75,6 +75,7 @@ static void ipu7_bus_release(struct device *dev) + { + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + ++ mutex_destroy(&adev->acquire_fw_task_buffer_lock); + kfree(adev->pdata); + kfree(adev); + } +@@ -96,6 +97,7 @@ ipu7_bus_initialize_device(struct pci_dev *pdev, struct device *parent, + adev->isp = isp; + adev->ctrl = ctrl; + adev->pdata = pdata; ++ mutex_init(&adev->acquire_fw_task_buffer_lock); + auxdev = &adev->auxdev; + auxdev->name = name; + auxdev->id = (pci_domain_nr(pdev->bus) << 16) | +diff --git a/drivers/staging/media/ipu7/ipu7-bus.h b/drivers/staging/media/ipu7/ipu7-bus.h +index 45157df16e90..eb9d0c907ddc 100644 +--- a/drivers/staging/media/ipu7/ipu7-bus.h ++++ b/drivers/staging/media/ipu7/ipu7-bus.h +@@ -46,6 +46,12 @@ struct ipu7_bus_device { + struct ia_gofo_boot_config *boot_config; + dma_addr_t boot_config_dma_addr; + u32 boot_config_size; ++ ++ /* Serialize FW message buffer or task queue acquisition against ++ * TLB invalidation. ++ */ ++ struct mutex acquire_fw_task_buffer_lock; ++ unsigned int (*get_running_fw_task_count)(struct ipu7_bus_device *adev); + }; + + struct ipu7_auxdrv_data { +diff --git a/drivers/staging/media/ipu7/ipu7-dma.c b/drivers/staging/media/ipu7/ipu7-dma.c +index 9a356ae3b95a..6b076de8c8fe 100644 +--- a/drivers/staging/media/ipu7/ipu7-dma.c ++++ b/drivers/staging/media/ipu7/ipu7-dma.c +@@ -206,6 +206,8 @@ void *ipu7_dma_alloc(struct ipu7_bus_device *sys, size_t size, + } + } + ++ if (mmu->mmid == ISYS_MMID) ++ mmu->tlb_invalidate(mmu, IPU_IS_MMU_FW_RD); + info->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL); + if (!info->vaddr) + goto out_unmap; +@@ -286,7 +288,7 @@ void ipu7_dma_free(struct ipu7_bus_device *sys, size_t size, void *vaddr, + + __free_buffer(pages, size, attrs); + +- mmu->tlb_invalidate(mmu); ++ mmu->tlb_invalidate(mmu, -1); + + __free_iova(&mmu->dmap->iovad, iova); + +@@ -366,7 +368,9 @@ void ipu7_dma_unmap_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), + PFN_PHYS(iova_size(iova))); + +- mmu->tlb_invalidate(mmu); ++ mutex_lock(&sys->acquire_fw_task_buffer_lock); ++ mmu->tlb_invalidate(mmu, -1); ++ mutex_unlock(&sys->acquire_fw_task_buffer_lock); + __free_iova(&mmu->dmap->iovad, iova); + } + EXPORT_SYMBOL_NS_GPL(ipu7_dma_unmap_sg, "INTEL_IPU7"); +diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c +index cb2f49f3e0fa..1d1d6f515813 100644 +--- a/drivers/staging/media/ipu7/ipu7-isys.c ++++ b/drivers/staging/media/ipu7/ipu7-isys.c +@@ -576,6 +576,8 @@ static void isys_remove(struct auxiliary_device *auxdev) + struct isys_fw_msgs *fwmsg, *safe; + struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); + ++ adev->get_running_fw_task_count = NULL; ++ + for (int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) + mutex_destroy(&isys->streams[i].mutex); + +@@ -634,6 +636,23 @@ static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) + return -ENOMEM; + } + ++static unsigned int ipu7_isys_get_running_fw_task_count( ++ struct ipu7_bus_device *adev) ++{ ++ struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); ++ unsigned long flags; ++ unsigned int count; ++ ++ if (!isys) ++ return 0; ++ ++ spin_lock_irqsave(&isys->listlock, flags); ++ count = list_count_nodes(&isys->framebuflist_fw); ++ spin_unlock_irqrestore(&isys->listlock, flags); ++ ++ return count; ++} ++ + struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) + { + struct device *dev = &stream->isys->adev->auxdev.dev; +@@ -642,18 +661,22 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) + unsigned long flags; + int ret; + ++ mutex_lock(&isys->adev->acquire_fw_task_buffer_lock); + spin_lock_irqsave(&isys->listlock, flags); + if (list_empty(&isys->framebuflist)) { + spin_unlock_irqrestore(&isys->listlock, flags); + dev_dbg(dev, "Frame buffer list empty\n"); + +- ret = alloc_fw_msg_bufs(isys, 5); +- if (ret < 0) ++ ret = alloc_fw_msg_bufs(isys, 10); ++ if (ret < 0) { ++ mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); + return NULL; ++ } + + spin_lock_irqsave(&isys->listlock, flags); + if (list_empty(&isys->framebuflist)) { + spin_unlock_irqrestore(&isys->listlock, flags); ++ mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); + dev_err(dev, "Frame list empty\n"); + return NULL; + } +@@ -661,6 +684,7 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) + msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head); + list_move(&msg->head, &isys->framebuflist_fw); + spin_unlock_irqrestore(&isys->listlock, flags); ++ mutex_unlock(&isys->adev->acquire_fw_task_buffer_lock); + memset(&msg->fw_msg, 0, sizeof(msg->fw_msg)); + + return msg; +@@ -744,6 +768,8 @@ static int isys_probe(struct auxiliary_device *auxdev, + INIT_LIST_HEAD(&isys->framebuflist_fw); + + dev_set_drvdata(&auxdev->dev, isys); ++ adev->get_running_fw_task_count = ++ ipu7_isys_get_running_fw_task_count; + + isys->icache_prefetch = 0; + isys->phy_rext_cal = 0; +diff --git a/drivers/staging/media/ipu7/ipu7-mmu.c b/drivers/staging/media/ipu7/ipu7-mmu.c +index 6ded07ccd780..07ac61ee999c 100644 +--- a/drivers/staging/media/ipu7/ipu7-mmu.c ++++ b/drivers/staging/media/ipu7/ipu7-mmu.c +@@ -27,6 +27,7 @@ + #include + + #include "ipu7.h" ++#include "ipu7-bus.h" + #include "ipu7-dma.h" + #include "ipu7-mmu.h" + #include "ipu7-platform-regs.h" +@@ -52,6 +53,8 @@ + #define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT) + + #define MMU_TLB_INVALIDATE_TIMEOUT 2000 ++#define WAIT_FW_MSG_BUFS_CLEAR_TIME_MS 17 ++#define WAIT_FW_MSG_BUFS_CLEAR_TIMES 5 + + static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) + { +@@ -66,12 +69,41 @@ static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) + } + } + +-static void tlb_invalidate(struct ipu7_mmu *mmu) ++static void tlb_invalidate(struct ipu7_mmu *mmu, int mmu_id) + { + unsigned long flags; ++ unsigned int start, end; + unsigned int i; + int ret; + u32 val; ++ unsigned int prev_task_cnt = UINT_MAX; ++ unsigned int curr_task_cnt; ++ unsigned int not_decreasing_count = 0; ++ struct ipu7_bus_device *adev = to_ipu7_bus_device(mmu->dev); ++ ++ if (adev->get_running_fw_task_count) { ++ while (1) { ++ curr_task_cnt = ++ adev->get_running_fw_task_count(adev); ++ if (curr_task_cnt == 0) ++ break; ++ ++ if (curr_task_cnt >= prev_task_cnt) ++ not_decreasing_count++; ++ else ++ not_decreasing_count = 0; ++ prev_task_cnt = curr_task_cnt; ++ ++ if (not_decreasing_count > ++ WAIT_FW_MSG_BUFS_CLEAR_TIMES) { ++ dev_warn(mmu->dev, ++ "wait running fw tasks clear timeout\n"); ++ break; ++ } ++ ++ msleep(WAIT_FW_MSG_BUFS_CLEAR_TIME_MS); ++ } ++ } + + spin_lock_irqsave(&mmu->ready_lock, flags); + if (!mmu->ready) { +@@ -79,7 +111,23 @@ static void tlb_invalidate(struct ipu7_mmu *mmu) + return; + } + +- for (i = 0; i < mmu->nr_mmus; i++) { ++ /* mmu_id < 0: all MMUs, otherwise one MMU. */ ++ if (mmu_id < 0) { ++ start = 0; ++ end = mmu->nr_mmus; ++ } else if (mmu_id >= mmu->nr_mmus) { ++ dev_warn(mmu->dev, "invalid mmu_id %d, nr_mmus %u\n", ++ mmu_id, mmu->nr_mmus); ++ spin_unlock_irqrestore(&mmu->ready_lock, flags); ++ return; ++ } ++ ++ if (mmu_id >= 0) { ++ start = mmu_id; ++ end = mmu_id + 1; ++ } ++ ++ for (i = start; i < end; i++) { + writel(0xffffffffU, mmu->mmu_hw[i].base + + MMU_REG_INVALIDATE_0); + +diff --git a/drivers/staging/media/ipu7/ipu7-mmu.h b/drivers/staging/media/ipu7/ipu7-mmu.h +index d85bb8ffc711..e4bc485496f4 100644 +--- a/drivers/staging/media/ipu7/ipu7-mmu.h ++++ b/drivers/staging/media/ipu7/ipu7-mmu.h +@@ -20,6 +20,12 @@ struct ipu7_mmu_info; + #define ISYS_MMID 0x1 + #define PSYS_MMID 0x0 + ++#define IPU_IS_MMU_FW_RD 0 ++#define IPU_IS_MMU_FW_WR 1 ++#define IPU_IS_MMU_M0 2 ++#define IPU_IS_MMU_M1 3 ++#define IPU_IS_MMU_UPIPE 4 ++ + /* IPU7 for LNL */ + /* IS MMU Cmd RD */ + #define IPU7_IS_MMU_FW_RD_OFFSET 0x274000 +@@ -396,7 +402,7 @@ struct ipu7_mmu { + bool ready; + spinlock_t ready_lock; /* Serialize access to bool ready */ + +- void (*tlb_invalidate)(struct ipu7_mmu *mmu); ++ void (*tlb_invalidate)(struct ipu7_mmu *mmu, int mmu_id); + }; + + struct ipu7_mmu *ipu7_mmu_init(struct device *dev, +-- +2.43.0 + diff --git a/patch/v7.0.0_iot/0001-staging-ipu7-Wait-back-firmware-message-buffers-when.patch b/patch/v7.0.0_iot/0001-staging-ipu7-Wait-back-firmware-message-buffers-when.patch deleted file mode 100644 index 3d65e39..0000000 --- a/patch/v7.0.0_iot/0001-staging-ipu7-Wait-back-firmware-message-buffers-when.patch +++ /dev/null @@ -1,284 +0,0 @@ -From 582759ec17edaa8fd0cf8d32616033a6fd39c3de Mon Sep 17 00:00:00 2001 -From: hepengpx -Date: Fri, 5 Jun 2026 10:50:21 +0800 -Subject: [PATCH 01/23] staging: ipu7: Wait back firmware message buffers when - tlb_invalidate - -IPU MMUs run in parallel, and runtime TLB invalidation may overlap with -ongoing data movement. For fw msg buf expansion, invalidating MMU0 is -sufficient. - -The goal of acquire_fw_msgbuf_lock is to block subsequent fw msg buf -allocations while waiting for framebuflist_fw to drain. It is not meant -to serialize all TLB invalidation callers. - -If TLB invalidation is triggered outside the fw msg buf allocation path, -the first caller takes acquire_fw_msgbuf_lock (when unlocked), establishes -the protection window. Later callers may proceed without taking the lock -again, which is acceptable for this design goal. - -Test results show fw msg buf count may stay unchanged for at most one poll. -To reduce latency, use half-frame wait time for each polling interval. - -Signed-off-by: hepengpx ---- - drivers/staging/media/ipu7/ipu7-dma.c | 7 ++- - drivers/staging/media/ipu7/ipu7-isys.c | 10 +++- - drivers/staging/media/ipu7/ipu7-isys.h | 2 + - drivers/staging/media/ipu7/ipu7-mmu.c | 75 +++++++++++++++++++++++++- - drivers/staging/media/ipu7/ipu7-mmu.h | 8 ++- - 5 files changed, 96 insertions(+), 6 deletions(-) - -diff --git a/drivers/staging/media/ipu7/ipu7-dma.c b/drivers/staging/media/ipu7/ipu7-dma.c -index 9a356ae3b95a..39b9d12f2c68 100644 ---- a/drivers/staging/media/ipu7/ipu7-dma.c -+++ b/drivers/staging/media/ipu7/ipu7-dma.c -@@ -206,6 +206,9 @@ void *ipu7_dma_alloc(struct ipu7_bus_device *sys, size_t size, - } - } - -+ if (mmu->mmid == ISYS_MMID) -+ mmu->tlb_invalidate(mmu, IPU_IS_MMU_FW_RD); -+ - info->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL); - if (!info->vaddr) - goto out_unmap; -@@ -286,7 +289,7 @@ void ipu7_dma_free(struct ipu7_bus_device *sys, size_t size, void *vaddr, - - __free_buffer(pages, size, attrs); - -- mmu->tlb_invalidate(mmu); -+ mmu->tlb_invalidate(mmu, -1); - - __free_iova(&mmu->dmap->iovad, iova); - -@@ -366,7 +369,7 @@ void ipu7_dma_unmap_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, - ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), - PFN_PHYS(iova_size(iova))); - -- mmu->tlb_invalidate(mmu); -+ mmu->tlb_invalidate(mmu, -1); - __free_iova(&mmu->dmap->iovad, iova); - } - EXPORT_SYMBOL_NS_GPL(ipu7_dma_unmap_sg, "INTEL_IPU7"); -diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c -index cb2f49f3e0fa..6c89eab60023 100644 ---- a/drivers/staging/media/ipu7/ipu7-isys.c -+++ b/drivers/staging/media/ipu7/ipu7-isys.c -@@ -594,6 +594,7 @@ static void isys_remove(struct auxiliary_device *auxdev) - - mutex_destroy(&isys->stream_mutex); - mutex_destroy(&isys->mutex); -+ mutex_destroy(&isys->acquire_fw_msgbuf_lock); - } - - static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) -@@ -642,18 +643,22 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) - unsigned long flags; - int ret; - -+ mutex_lock(&isys->acquire_fw_msgbuf_lock); - spin_lock_irqsave(&isys->listlock, flags); - if (list_empty(&isys->framebuflist)) { - spin_unlock_irqrestore(&isys->listlock, flags); - dev_dbg(dev, "Frame buffer list empty\n"); - - ret = alloc_fw_msg_bufs(isys, 5); -- if (ret < 0) -+ if (ret < 0) { -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); - return NULL; -+ } - - spin_lock_irqsave(&isys->listlock, flags); - if (list_empty(&isys->framebuflist)) { - spin_unlock_irqrestore(&isys->listlock, flags); -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); - dev_err(dev, "Frame list empty\n"); - return NULL; - } -@@ -661,6 +666,7 @@ struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) - msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head); - list_move(&msg->head, &isys->framebuflist_fw); - spin_unlock_irqrestore(&isys->listlock, flags); -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); - memset(&msg->fw_msg, 0, sizeof(msg->fw_msg)); - - return msg; -@@ -738,6 +744,7 @@ static int isys_probe(struct auxiliary_device *auxdev, - - mutex_init(&isys->mutex); - mutex_init(&isys->stream_mutex); -+ mutex_init(&isys->acquire_fw_msgbuf_lock); - - spin_lock_init(&isys->listlock); - INIT_LIST_HEAD(&isys->framebuflist); -@@ -777,6 +784,7 @@ static int isys_probe(struct auxiliary_device *auxdev, - out_cleanup_fw: - ipu7_fw_isys_release(isys); - out_cleanup_isys: -+ mutex_destroy(&isys->acquire_fw_msgbuf_lock); - cpu_latency_qos_remove_request(&isys->pm_qos); - - for (unsigned int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) -diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h -index ef1ab1b42f6c..29abb9a2d375 100644 ---- a/drivers/staging/media/ipu7/ipu7-isys.h -+++ b/drivers/staging/media/ipu7/ipu7-isys.h -@@ -109,6 +109,8 @@ struct ipu7_isys { - - struct ipu7_insys_config *subsys_config; - dma_addr_t subsys_config_dma_addr; -+ /* Protect framebuflist when getting fw msg buf. */ -+ struct mutex acquire_fw_msgbuf_lock; - }; - - struct isys_fw_msgs { -diff --git a/drivers/staging/media/ipu7/ipu7-mmu.c b/drivers/staging/media/ipu7/ipu7-mmu.c -index 6ded07ccd780..58bd0db39103 100644 ---- a/drivers/staging/media/ipu7/ipu7-mmu.c -+++ b/drivers/staging/media/ipu7/ipu7-mmu.c -@@ -30,6 +30,7 @@ - #include "ipu7-dma.h" - #include "ipu7-mmu.h" - #include "ipu7-platform-regs.h" -+#include "ipu7-isys.h" - - #define ISP_PAGE_SHIFT 12 - #define ISP_PAGE_SIZE BIT(ISP_PAGE_SHIFT) -@@ -52,6 +53,8 @@ - #define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT) - - #define MMU_TLB_INVALIDATE_TIMEOUT 2000 -+#define WAIT_FW_MSG_BUFS_CLEAR_TIME_MS 17 -+#define WAIT_FW_MSG_BUFS_CLEAR_TIMES 5 - - static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) - { -@@ -66,20 +69,86 @@ static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) - } - } - --static void tlb_invalidate(struct ipu7_mmu *mmu) -+static void tlb_invalidate(struct ipu7_mmu *mmu, int mmu_id) - { - unsigned long flags; -+ unsigned int start, end; - unsigned int i; - int ret; - u32 val; -+ bool locked_get_fw = false; -+ struct ipu7_isys *isys = NULL; -+ unsigned int prev_fw_cnt = UINT_MAX; -+ unsigned int curr_fw_cnt = UINT_MAX; -+ unsigned int not_decreasing_count = 0; -+ -+ if (mmu->mmid == ISYS_MMID) { -+ isys = dev_get_drvdata(mmu->dev); -+ if (!isys) { -+ dev_warn(mmu->dev, "isys drvdata is NULL, skip tlb invalidate wait\n"); -+ return; -+ } -+ -+ if (!mutex_is_locked(&isys->acquire_fw_msgbuf_lock)) { -+ mutex_lock(&isys->acquire_fw_msgbuf_lock); -+ locked_get_fw = true; -+ } -+ -+ while (1) { -+ spin_lock_irqsave(&isys->listlock, flags); -+ curr_fw_cnt = list_count_nodes(&isys->framebuflist_fw); -+ spin_unlock_irqrestore(&isys->listlock, flags); -+ if (curr_fw_cnt == 0) -+ break; -+ -+ if (curr_fw_cnt >= prev_fw_cnt) -+ not_decreasing_count++; -+ else -+ not_decreasing_count = 0; -+ prev_fw_cnt = curr_fw_cnt; -+ -+ /* -+ * Timeout after consecutive non-decreasing counts. -+ * Continue invalidate to avoid indefinite stall. -+ */ -+ if (not_decreasing_count > -+ WAIT_FW_MSG_BUFS_CLEAR_TIMES) { -+ dev_warn(&isys->adev->auxdev.dev, -+ "wait framebuflist_fw empty timeout"); -+ break; -+ } -+ -+ msleep(WAIT_FW_MSG_BUFS_CLEAR_TIME_MS); -+ } -+ } - - spin_lock_irqsave(&mmu->ready_lock, flags); - if (!mmu->ready) { - spin_unlock_irqrestore(&mmu->ready_lock, flags); -+ if (locked_get_fw) -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); - return; - } - -- for (i = 0; i < mmu->nr_mmus; i++) { -+ /* mmu_id < 0: all MMUs, otherwise one MMU. */ -+ if (mmu_id < 0) { -+ start = 0; -+ end = mmu->nr_mmus; -+ } else if (mmu_id >= mmu->nr_mmus) { -+ dev_warn(mmu->dev, "invalid mmu_id %d, nr_mmus %u\n", -+ mmu_id, mmu->nr_mmus); -+ spin_unlock_irqrestore(&mmu->ready_lock, flags); -+ if (locked_get_fw) -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); -+ return; -+ } -+ -+ if (mmu_id >= 0) { -+ start = mmu_id; -+ end = mmu_id + 1; -+ } -+ -+ for (i = start; i < end; i++) { - writel(0xffffffffU, mmu->mmu_hw[i].base + - MMU_REG_INVALIDATE_0); - -@@ -106,6 +175,8 @@ static void tlb_invalidate(struct ipu7_mmu *mmu) - } - - spin_unlock_irqrestore(&mmu->ready_lock, flags); -+ if (locked_get_fw) -+ mutex_unlock(&isys->acquire_fw_msgbuf_lock); - } - - static dma_addr_t map_single(struct ipu7_mmu_info *mmu_info, void *ptr) -diff --git a/drivers/staging/media/ipu7/ipu7-mmu.h b/drivers/staging/media/ipu7/ipu7-mmu.h -index d85bb8ffc711..e4bc485496f4 100644 ---- a/drivers/staging/media/ipu7/ipu7-mmu.h -+++ b/drivers/staging/media/ipu7/ipu7-mmu.h -@@ -20,6 +20,12 @@ struct ipu7_mmu_info; - #define ISYS_MMID 0x1 - #define PSYS_MMID 0x0 - -+#define IPU_IS_MMU_FW_RD 0 -+#define IPU_IS_MMU_FW_WR 1 -+#define IPU_IS_MMU_M0 2 -+#define IPU_IS_MMU_M1 3 -+#define IPU_IS_MMU_UPIPE 4 -+ - /* IPU7 for LNL */ - /* IS MMU Cmd RD */ - #define IPU7_IS_MMU_FW_RD_OFFSET 0x274000 -@@ -396,7 +402,7 @@ struct ipu7_mmu { - bool ready; - spinlock_t ready_lock; /* Serialize access to bool ready */ - -- void (*tlb_invalidate)(struct ipu7_mmu *mmu); -+ void (*tlb_invalidate)(struct ipu7_mmu *mmu, int mmu_id); - }; - - struct ipu7_mmu *ipu7_mmu_init(struct device *dev, --- -2.43.0 - diff --git a/patch/v7.0.0_iot/0004-patch-staging-add-ipu7-isys-reset-code-for-v7.0.patch b/patch/v7.0.0_iot/0004_staging_ipu7_add_isys_reset_feature.patch similarity index 87% rename from patch/v7.0.0_iot/0004-patch-staging-add-ipu7-isys-reset-code-for-v7.0.patch rename to patch/v7.0.0_iot/0004_staging_ipu7_add_isys_reset_feature.patch index ed93f66..941c616 100644 --- a/patch/v7.0.0_iot/0004-patch-staging-add-ipu7-isys-reset-code-for-v7.0.patch +++ b/patch/v7.0.0_iot/0004_staging_ipu7_add_isys_reset_feature.patch @@ -1,18 +1,18 @@ -From 63d5147bceab8c35d14f867f234f5e5dcd6f2dbe Mon Sep 17 00:00:00 2001 -From: linya14x -Date: Tue, 21 Apr 2026 14:30:26 +0800 -Subject: [PATCH 04/23] patch: staging add ipu7 isys reset code for v7.0 +From 011de55cd83d79d418e49bb9b7df9589d4a83638 Mon Sep 17 00:00:00 2001 +From: Lin Yang +Date: Tue, 9 Jun 2026 17:47:39 +0800 +Subject: [PATCH 04/23] staging: ipu7: add isys reset feature Signed-off-by: linya14x --- drivers/staging/media/ipu7/Kconfig | 10 + - drivers/staging/media/ipu7/ipu7-isys-queue.c | 354 ++++++++++++++++++- + drivers/staging/media/ipu7/ipu7-isys-queue.c | 353 ++++++++++++++++++- drivers/staging/media/ipu7/ipu7-isys-queue.h | 3 + - drivers/staging/media/ipu7/ipu7-isys-video.c | 98 +++++ + drivers/staging/media/ipu7/ipu7-isys-video.c | 81 +++++ drivers/staging/media/ipu7/ipu7-isys-video.h | 8 + - drivers/staging/media/ipu7/ipu7-isys.c | 55 +++ + drivers/staging/media/ipu7/ipu7-isys.c | 74 ++++ drivers/staging/media/ipu7/ipu7-isys.h | 16 + - 7 files changed, 543 insertions(+), 1 deletion(-) + 7 files changed, 544 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/ipu7/Kconfig b/drivers/staging/media/ipu7/Kconfig index 7d831ba7501d..c4eee7c3e6d7 100644 @@ -33,7 +33,7 @@ index 7d831ba7501d..c4eee7c3e6d7 100644 + + If doubt, say N here. diff --git a/drivers/staging/media/ipu7/ipu7-isys-queue.c b/drivers/staging/media/ipu7/ipu7-isys-queue.c -index 537542ff5ad4..c7cd9b3e66f0 100644 +index 537542ff5ad4..27d8b1b3310d 100644 --- a/drivers/staging/media/ipu7/ipu7-isys-queue.c +++ b/drivers/staging/media/ipu7/ipu7-isys-queue.c @@ -11,6 +11,9 @@ @@ -102,7 +102,7 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 return 0; -@@ -620,17 +651,282 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) +@@ -620,17 +651,281 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) return ret; } @@ -110,11 +110,13 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 +static void reset_stop_streaming(struct ipu7_isys_video *av) +{ + struct ipu7_isys_queue *aq = &av->aq; ++ struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + struct ipu7_isys_buffer *ib; + struct vb2_buffer *vb; + unsigned long flags; + ++ dev_dbg(dev, "reset stop streams: %s\n", av->vdev.name); + mutex_lock(&av->isys->stream_mutex); + if (stream->nr_streaming == stream->nr_queues && stream->streaming) + ipu7_isys_video_set_streaming(av, 0, NULL); @@ -285,7 +287,6 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 + + mutex_unlock(&isys->reset_mutex); + -+ dev_dbg(dev, "reset stop streams\n"); + for (i = 0; i < csi2_pdata->nports; i++) { + for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) { + av = &isys->csi2[i].av[j]; @@ -310,8 +311,6 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 + + ipu7_cleanup_fw_msg_bufs(isys); + -+ dev_dbg(dev, "reset start streams\n"); -+ + for (j = 0; j < csi2_pdata->nports; j++) { + for (i = 0; i < IPU7_NR_OF_CSI2_SRC_PADS; i++) { + av = &isys->csi2[j].av[i]; @@ -386,7 +385,7 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 stream->nr_streaming--; list_del(&aq->node); -@@ -643,7 +939,58 @@ static void stop_streaming(struct vb2_queue *q) +@@ -643,7 +938,58 @@ static void stop_streaming(struct vb2_queue *q) return_buffers(aq, VB2_BUF_STATE_ERROR); ipu7_isys_fw_close(av->isys); @@ -398,7 +397,7 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 + mutex_unlock(&av->isys->reset_mutex); + + if (need_reset) { -+ if (!stream->nr_streaming) { ++ if (av->isys->stream_opened > 0) { + ipu_isys_reset(av, stream); + } else { + mutex_lock(&av->isys->reset_mutex); @@ -445,7 +444,7 @@ index 537542ff5ad4..c7cd9b3e66f0 100644 static unsigned int get_sof_sequence_by_timestamp(struct ipu7_isys_stream *stream, u64 time) -@@ -725,6 +1072,11 @@ static void ipu7_isys_queue_buf_done(struct ipu7_isys_buffer *ib) +@@ -725,6 +1071,11 @@ static void ipu7_isys_queue_buf_done(struct ipu7_isys_buffer *ib) * to the userspace when it is de-queued */ atomic_set(&ib->str2mmio_flag, 0); @@ -472,7 +471,7 @@ index 0cb08a38f756..5a909c3a78d2 100644 struct ipu7_isys_video_buffer { diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.c b/drivers/staging/media/ipu7/ipu7-isys-video.c -index 9953d4aa3a38..6e6c627b957e 100644 +index 9953d4aa3a38..b3792dd534db 100644 --- a/drivers/staging/media/ipu7/ipu7-isys-video.c +++ b/drivers/staging/media/ipu7/ipu7-isys-video.c @@ -18,6 +18,9 @@ @@ -485,27 +484,11 @@ index 9953d4aa3a38..6e6c627b957e 100644 #include #include -@@ -88,6 +91,42 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { +@@ -88,6 +91,26 @@ const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { IPU_INSYS_FRAME_FORMAT_RGBA888}, }; +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET -+static int video_open(struct file *file) -+ { -+ struct ipu7_isys_video *av = video_drvdata(file); -+ struct ipu7_isys *isys = av->isys; -+ struct ipu7_bus_device *adev = isys->adev; -+ -+ mutex_lock(&isys->reset_mutex); -+ if (isys->need_reset) { -+ mutex_unlock(&isys->reset_mutex); -+ dev_warn(&adev->auxdev.dev, "isys power cycle required\n"); -+ return -EIO; -+ } -+ mutex_unlock(&isys->reset_mutex); -+ return v4l2_fh_open(file); -+ } -+ +static int video_release(struct file *file) +{ + struct ipu7_isys_video *av = video_drvdata(file); @@ -528,7 +511,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat) { unsigned int i; -@@ -584,7 +623,11 @@ static void stop_streaming_firmware(struct ipu7_isys_video *av) +@@ -584,7 +607,11 @@ static void stop_streaming_firmware(struct ipu7_isys_video *av) } tout = wait_for_completion_timeout(&stream->stream_stop_completion, @@ -540,7 +523,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 if (!tout) dev_warn(dev, "stream stop time out\n"); else if (stream->error) -@@ -609,7 +652,11 @@ static void close_streaming_firmware(struct ipu7_isys_video *av) +@@ -609,7 +636,11 @@ static void close_streaming_firmware(struct ipu7_isys_video *av) } tout = wait_for_completion_timeout(&stream->stream_close_completion, @@ -552,7 +535,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 if (!tout) dev_warn(dev, "stream close time out\n"); else if (stream->error) -@@ -617,6 +664,12 @@ static void close_streaming_firmware(struct ipu7_isys_video *av) +@@ -617,6 +648,12 @@ static void close_streaming_firmware(struct ipu7_isys_video *av) else dev_dbg(dev, "close stream: complete\n"); @@ -565,7 +548,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 put_stream_opened(av); } -@@ -631,7 +684,18 @@ int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av, +@@ -631,7 +668,18 @@ int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av, return -EINVAL; stream->nr_queues = nr_queues; @@ -584,21 +567,19 @@ index 9953d4aa3a38..6e6c627b957e 100644 atomic_set(&stream->buf_id, 0); stream->seq_index = 0; -@@ -866,8 +930,13 @@ static const struct v4l2_file_operations isys_fops = { - .poll = vb2_fop_poll, +@@ -867,7 +915,11 @@ static const struct v4l2_file_operations isys_fops = { .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, + .open = v4l2_fh_open, +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET -+ .open = video_open, + .release = video_release, +#else - .open = v4l2_fh_open, .release = vb2_fop_release, +#endif }; int ipu7_isys_fw_open(struct ipu7_isys *isys) -@@ -906,6 +975,28 @@ int ipu7_isys_fw_open(struct ipu7_isys *isys) +@@ -906,6 +958,28 @@ int ipu7_isys_fw_open(struct ipu7_isys *isys) return ret; } @@ -627,7 +608,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 void ipu7_isys_fw_close(struct ipu7_isys *isys) { mutex_lock(&isys->mutex); -@@ -918,6 +1009,7 @@ void ipu7_isys_fw_close(struct ipu7_isys *isys) +@@ -918,6 +992,7 @@ void ipu7_isys_fw_close(struct ipu7_isys *isys) mutex_unlock(&isys->mutex); pm_runtime_put(&isys->adev->auxdev.dev); } @@ -635,7 +616,7 @@ index 9953d4aa3a38..6e6c627b957e 100644 int ipu7_isys_setup_video(struct ipu7_isys_video *av, struct media_entity **source_entity, int *nr_queues) -@@ -1053,6 +1145,12 @@ int ipu7_isys_video_init(struct ipu7_isys_video *av) +@@ -1053,6 +1128,12 @@ int ipu7_isys_video_init(struct ipu7_isys_video *av) __ipu_isys_vidioc_try_fmt_vid_cap(av, &format); av->pix_fmt = format.fmt.pix; @@ -675,10 +656,10 @@ index 1ac1787fabef..e6d1da2b7b47 100644 #define ipu7_isys_queue_to_video(__aq) \ diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c -index e2e6e6f6b092..b59cf28a9f17 100644 +index acdcad5f2614..e7169da2e5e5 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.c +++ b/drivers/staging/media/ipu7/ipu7-isys.c -@@ -371,6 +371,42 @@ static int isys_csi2_create_media_links(struct ipu7_isys *isys) +@@ -371,6 +371,61 @@ static int isys_csi2_create_media_links(struct ipu7_isys *isys) return 0; } @@ -690,6 +671,8 @@ index e2e6e6f6b092..b59cf28a9f17 100644 + container_of(sd->v4l2_dev, struct ipu7_isys, v4l2_dev); + struct device *dev = &isys->adev->auxdev.dev; + struct v4l2_event *ev = arg; ++ struct ipu7_isys_csi2_config *csi2_cfg; ++ unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&isys->power_lock, flags); @@ -702,14 +685,31 @@ index e2e6e6f6b092..b59cf28a9f17 100644 + spin_unlock_irqrestore(&isys->power_lock, flags); + + if (notification == V4L2_DEVICE_NOTIFY_EVENT) { -+ if ((ev->type == V4L2_EVENT_SOURCE_CHANGE || -+ ev->type == V4L2_EVENT_EOS) && -+ isys->stream_opened > 1) { -+ dev_dbg(dev, "%s: isys need reset due to notify %u, stream opened %d\n", -+ sd->name, ev->type, isys->stream_opened); -+ mutex_lock(&isys->reset_mutex); -+ isys->need_reset = true; -+ mutex_unlock(&isys->reset_mutex); ++ if (ev->type == V4L2_EVENT_SOURCE_CHANGE || ++ ev->type == V4L2_EVENT_EOS) { ++ csi2_cfg = v4l2_get_subdev_hostdata(sd); ++ if (!csi2_cfg) { ++ dev_warn(dev, "%s: missing csi2 cfg for notify %u\n", ++ sd->name, ev->type); ++ return; ++ } ++ ++ for (i = 0; i < IPU7_NR_OF_CSI2_SRC_PADS; i++) { ++ struct ipu7_isys_video *av = ++ &isys->csi2[csi2_cfg->port].av[i]; ++ ++ if (READ_ONCE(av->start_streaming)) { ++ dev_info(dev, ++ "%s: isys need reset due to notify %u on port %u\n", ++ sd->name, ev->type, csi2_cfg->port); ++ mutex_lock(&isys->reset_mutex); ++ isys->need_reset = true; ++ mutex_unlock(&isys->reset_mutex); ++ return; ++ } ++ } ++ dev_dbg(dev, "%s: notify %u ignored, no AV starting on this port\n", ++ sd->name, notification); + } + } else { + dev_warn(dev, "%s: unknown notification %u\n", @@ -721,7 +721,7 @@ index e2e6e6f6b092..b59cf28a9f17 100644 static int isys_register_devices(struct ipu7_isys *isys) { struct device *dev = &isys->adev->auxdev.dev; -@@ -390,6 +426,9 @@ static int isys_register_devices(struct ipu7_isys *isys) +@@ -390,6 +445,9 @@ static int isys_register_devices(struct ipu7_isys *isys) isys->v4l2_dev.mdev = &isys->media_dev; isys->v4l2_dev.ctrl_handler = NULL; @@ -731,7 +731,7 @@ index e2e6e6f6b092..b59cf28a9f17 100644 ret = v4l2_device_register(dev, &isys->v4l2_dev); if (ret < 0) goto out_media_device_unregister; -@@ -540,6 +579,12 @@ static int isys_runtime_pm_suspend(struct device *dev) +@@ -540,6 +598,12 @@ static int isys_runtime_pm_suspend(struct device *dev) isys->power = 0; spin_unlock_irqrestore(&isys->power_lock, flags); @@ -744,20 +744,20 @@ index e2e6e6f6b092..b59cf28a9f17 100644 cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE); ipu7_mmu_hw_cleanup(adev->mmu); -@@ -594,6 +639,9 @@ static void isys_remove(struct auxiliary_device *auxdev) +@@ -594,6 +658,9 @@ static void isys_remove(struct auxiliary_device *auxdev) mutex_destroy(&isys->stream_mutex); mutex_destroy(&isys->mutex); +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET + mutex_destroy(&isys->reset_mutex); +#endif - mutex_destroy(&isys->acquire_fw_msgbuf_lock); } -@@ -759,6 +807,10 @@ static int isys_probe(struct auxiliary_device *auxdev, + static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) +@@ -757,6 +824,10 @@ static int isys_probe(struct auxiliary_device *auxdev, + mutex_init(&isys->mutex); mutex_init(&isys->stream_mutex); - mutex_init(&isys->acquire_fw_msgbuf_lock); +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET + mutex_init(&isys->reset_mutex); + isys->state = 0; @@ -765,18 +765,18 @@ index e2e6e6f6b092..b59cf28a9f17 100644 spin_lock_init(&isys->listlock); INIT_LIST_HEAD(&isys->framebuflist); -@@ -798,6 +850,9 @@ static int isys_probe(struct auxiliary_device *auxdev, +@@ -796,6 +867,9 @@ static int isys_probe(struct auxiliary_device *auxdev, out_cleanup_fw: ipu7_fw_isys_release(isys); out_cleanup_isys: +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET + mutex_destroy(&isys->reset_mutex); +#endif - mutex_destroy(&isys->acquire_fw_msgbuf_lock); cpu_latency_qos_remove_request(&isys->pm_qos); + for (unsigned int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h -index c6a3d4f22a25..18f54c17d4b7 100644 +index d7f6b7bc5484..48d207f0952f 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.h +++ b/drivers/staging/media/ipu7/ipu7-isys.h @@ -44,8 +44,16 @@ @@ -806,10 +806,10 @@ index c6a3d4f22a25..18f54c17d4b7 100644 * @ref_count: total number of callers fw open * @mutex: serialise access isys video open/release related operations * @stream_mutex: serialise stream start and stop, queueing requests -@@ -111,6 +122,11 @@ struct ipu7_isys { +@@ -109,6 +120,11 @@ struct ipu7_isys { + + struct ipu7_insys_config *subsys_config; dma_addr_t subsys_config_dma_addr; - /* Protect framebuflist when getting fw msg buf. */ - struct mutex acquire_fw_msgbuf_lock; +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET + struct mutex reset_mutex; + bool need_reset; diff --git a/patch/v7.0.0_iot/0005-patch-staging-add-enable-CONFIG_DEBUG_FS.patch b/patch/v7.0.0_iot/0005-patch-staging-add-enable-CONFIG_DEBUG_FS.patch index 8c62c77..021e71f 100644 --- a/patch/v7.0.0_iot/0005-patch-staging-add-enable-CONFIG_DEBUG_FS.patch +++ b/patch/v7.0.0_iot/0005-patch-staging-add-enable-CONFIG_DEBUG_FS.patch @@ -1,4 +1,4 @@ -From a32ce6c2c845555cac99a923f4fac515f8d88805 Mon Sep 17 00:00:00 2001 +From 7795ec9aa909e1f8ecec9a5db0db0421785d6036 Mon Sep 17 00:00:00 2001 From: linya14x Date: Mon, 20 Oct 2025 12:36:12 +0800 Subject: [PATCH 05/23] patch: staging add enable CONFIG_DEBUG_FS @@ -12,7 +12,7 @@ Signed-off-by: linya14x 4 files changed, 154 insertions(+) diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c -index b59cf28a9f17..1da071fa5241 100644 +index 2e9fc608d9bc..78d1c562d88d 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.c +++ b/drivers/staging/media/ipu7/ipu7-isys.c @@ -9,6 +9,9 @@ @@ -25,9 +25,9 @@ index b59cf28a9f17..1da071fa5241 100644 #include #include #include -@@ -621,6 +624,10 @@ static void isys_remove(struct auxiliary_device *auxdev) - struct isys_fw_msgs *fwmsg, *safe; - struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); +@@ -642,6 +645,10 @@ static void isys_remove(struct auxiliary_device *auxdev) + + adev->get_running_fw_task_count = NULL; +#ifdef CONFIG_DEBUG_FS + if (adev->isp->ipu7_dir) @@ -36,8 +36,8 @@ index b59cf28a9f17..1da071fa5241 100644 for (int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) mutex_destroy(&isys->streams[i].mutex); -@@ -645,6 +652,78 @@ static void isys_remove(struct auxiliary_device *auxdev) - mutex_destroy(&isys->acquire_fw_msgbuf_lock); +@@ -665,6 +672,78 @@ static void isys_remove(struct auxiliary_device *auxdev) + #endif } +#ifdef CONFIG_DEBUG_FS @@ -115,7 +115,7 @@ index b59cf28a9f17..1da071fa5241 100644 static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) { struct ipu7_bus_device *adev = isys->adev; -@@ -823,6 +902,11 @@ static int isys_probe(struct auxiliary_device *auxdev, +@@ -861,6 +940,11 @@ static int isys_probe(struct auxiliary_device *auxdev, isys_stream_init(isys); @@ -128,7 +128,7 @@ index b59cf28a9f17..1da071fa5241 100644 ret = alloc_fw_msg_bufs(isys, 20); if (ret < 0) diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h -index 18f54c17d4b7..a2a7d75696c5 100644 +index 48d207f0952f..60520834fdc6 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.h +++ b/drivers/staging/media/ipu7/ipu7-isys.h @@ -25,6 +25,10 @@ diff --git a/patch/v7.0.0_iot/0006-patch-staging-add-enable-CONFIG_INTEL_IPU_ACPI.patch b/patch/v7.0.0_iot/0006-patch-staging-add-enable-CONFIG_INTEL_IPU_ACPI.patch index 90be4f1..b7cd536 100644 --- a/patch/v7.0.0_iot/0006-patch-staging-add-enable-CONFIG_INTEL_IPU_ACPI.patch +++ b/patch/v7.0.0_iot/0006-patch-staging-add-enable-CONFIG_INTEL_IPU_ACPI.patch @@ -1,4 +1,4 @@ -From 3dbefe49f48fddc9d8945d87a5f89d87170be810 Mon Sep 17 00:00:00 2001 +From f2f7b903f896af3dc37ad8ff49ef41d5ccc99cd6 Mon Sep 17 00:00:00 2001 From: linya14x Date: Fri, 30 Jan 2026 12:16:30 +0800 Subject: [PATCH 06/23] patch: staging add enable CONFIG_INTEL_IPU_ACPI @@ -12,7 +12,7 @@ Signed-off-by: linya14x 4 files changed, 258 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c -index 1da071fa5241..71cd9a779e83 100644 +index 43e764b9120b..5320330f7987 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.c +++ b/drivers/staging/media/ipu7/ipu7-isys.c @@ -96,6 +96,126 @@ isys_complete_ext_device_registration(struct ipu7_isys *isys, @@ -158,7 +158,7 @@ index 1da071fa5241..71cd9a779e83 100644 static void isys_unregister_video_devices(struct ipu7_isys *isys) { -@@ -410,6 +532,7 @@ static void isys_v4l2_notify(struct v4l2_subdev *sd, unsigned int notification, +@@ -429,6 +551,7 @@ static void isys_v4l2_notify(struct v4l2_subdev *sd, unsigned int notification, } #endif @@ -166,7 +166,7 @@ index 1da071fa5241..71cd9a779e83 100644 static int isys_register_devices(struct ipu7_isys *isys) { struct device *dev = &isys->adev->auxdev.dev; -@@ -448,7 +571,74 @@ static int isys_register_devices(struct ipu7_isys *isys) +@@ -467,7 +590,74 @@ static int isys_register_devices(struct ipu7_isys *isys) if (ret) goto out_csi2_unregister_subdevices; @@ -242,7 +242,7 @@ index 1da071fa5241..71cd9a779e83 100644 if (ret) goto out_csi2_unregister_subdevices; -@@ -471,6 +661,7 @@ static int isys_register_devices(struct ipu7_isys *isys) +@@ -490,6 +680,7 @@ static int isys_register_devices(struct ipu7_isys *isys) return ret; } @@ -250,7 +250,7 @@ index 1da071fa5241..71cd9a779e83 100644 static void isys_unregister_devices(struct ipu7_isys *isys) { -@@ -618,6 +809,7 @@ static const struct dev_pm_ops isys_pm_ops = { +@@ -637,6 +828,7 @@ static const struct dev_pm_ops isys_pm_ops = { .resume = isys_resume, }; @@ -258,7 +258,7 @@ index 1da071fa5241..71cd9a779e83 100644 static void isys_remove(struct auxiliary_device *auxdev) { struct ipu7_isys *isys = dev_get_drvdata(&auxdev->dev); -@@ -639,7 +831,9 @@ static void isys_remove(struct auxiliary_device *auxdev) +@@ -658,7 +850,9 @@ static void isys_remove(struct auxiliary_device *auxdev) ipu7_dma_free(adev, sizeof(struct isys_fw_msgs), fwmsg, fwmsg->dma_addr, 0); @@ -269,9 +269,9 @@ index 1da071fa5241..71cd9a779e83 100644 isys_unregister_devices(isys); cpu_latency_qos_remove_request(&isys->pm_qos); -@@ -651,6 +845,40 @@ static void isys_remove(struct auxiliary_device *auxdev) +@@ -669,6 +863,40 @@ static void isys_remove(struct auxiliary_device *auxdev) + mutex_destroy(&isys->reset_mutex); #endif - mutex_destroy(&isys->acquire_fw_msgbuf_lock); } +#else +static void isys_remove(struct auxiliary_device *auxdev) @@ -299,22 +299,22 @@ index 1da071fa5241..71cd9a779e83 100644 + + cpu_latency_qos_remove_request(&isys->pm_qos); + ++ mutex_destroy(&isys->acquire_fw_msgbuf_lock); + mutex_destroy(&isys->stream_mutex); + mutex_destroy(&isys->mutex); +#ifdef CONFIG_VIDEO_INTEL_IPU7_ISYS_RESET + mutex_destroy(&isys->reset_mutex); +#endif -+ mutex_destroy(&isys->acquire_fw_msgbuf_lock); +} +#endif #ifdef CONFIG_DEBUG_FS static ssize_t fwlog_read(struct file *file, char __user *userbuf, size_t size, diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h -index a2a7d75696c5..7351fa82888f 100644 +index 60520834fdc6..af18182229d7 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.h +++ b/drivers/staging/media/ipu7/ipu7-isys.h -@@ -153,6 +153,21 @@ struct ipu7_isys_csi2_config { +@@ -151,6 +151,21 @@ struct ipu7_isys_csi2_config { enum v4l2_mbus_type bus_type; }; diff --git a/patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.12.patch b/patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.14.patch similarity index 89% rename from patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.12.patch rename to patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.14.patch index 47fd55c..e34f0ce 100644 --- a/patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.12.patch +++ b/patch/v7.0.0_iot/0019-staging-ipu7-Add-IPU8-ABI-version-1.0.14.patch @@ -1,19 +1,19 @@ -From fab7263816856190f3859cd839a5fe48d7ad6af0 Mon Sep 17 00:00:00 2001 -From: Hao Yao -Date: Fri, 24 Oct 2025 12:09:58 +0800 -Subject: [PATCH 19/23] staging: ipu7: Add IPU8 ABI version 1.0.12 +From 50a189347a602c63000fa80ba80db5eb75a392b9 Mon Sep 17 00:00:00 2001 +From: Shunyong Yang +Date: Tue, 16 Jun 2026 10:35:28 +0800 +Subject: [PATCH] staging: ipu7: Add IPU8 ABI version 1.0.14 -Signed-off-by: Hao Yao +Signed-off-by: Shunyong Yang --- - .../staging/media/ipu7/abi/ipu7_fw_isys_abi.h | 93 +++++++++- - drivers/staging/media/ipu7/ipu7-fw-isys.c | 170 +++++++++++++++++- + .../staging/media/ipu7/abi/ipu7_fw_isys_abi.h | 91 +++++++++- + drivers/staging/media/ipu7/ipu7-fw-isys.c | 167 +++++++++++++++++- drivers/staging/media/ipu7/ipu7-isys-queue.c | 5 +- drivers/staging/media/ipu7/ipu7-isys-video.c | 13 ++ drivers/staging/media/ipu7/ipu7-isys.h | 9 + - 5 files changed, 276 insertions(+), 14 deletions(-) + 5 files changed, 272 insertions(+), 13 deletions(-) diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h -index 7f622bfe9af6..9a4c63b68044 100644 +index 7f622bfe9af6..ca9e35872eb9 100644 --- a/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h @@ -251,9 +251,16 @@ struct ipu7_insys_output_link { @@ -119,11 +119,10 @@ index 7f622bfe9af6..9a4c63b68044 100644 struct ipu7_insys_capture_output_pin_payload output_pins[4]; u8 capture_msg_map; u8 frame_id; -@@ -304,7 +363,15 @@ struct ipu7_insys_buffset { +@@ -304,6 +363,28 @@ struct ipu7_insys_buffset { u8 pad[5]; }; --struct ipu7_insys_resp { +struct ipu7_insys_buffset { + struct ipu7_insys_capture_output_pin_cfg output_pins[4]; + u8 capture_msg_map; @@ -133,30 +132,22 @@ index 7f622bfe9af6..9a4c63b68044 100644 +}; + +struct ipu7_insys_resp_v1 { - u64 buf_id; - struct ipu7_insys_capture_output_pin_payload pin; - struct ia_gofo_msg_err error_info; -@@ -318,6 +385,20 @@ struct ipu7_insys_resp { - u16 mipi_fn; - }; - -+struct ipu7_insys_resp { + u64 buf_id; + struct ipu7_insys_capture_output_pin_payload pin; + struct ia_gofo_msg_err error_info; + u32 timestamp[2]; -+ u16 mipi_fn; + u8 type; + u8 msg_link_streaming_mode; + u8 stream_id; + u8 pin_id; + u8 frame_id; + u8 skip_frame; ++ u16 mipi_fn; +}; + - struct ipu7_insys_resp_queue_token { - struct ipu7_insys_resp resp_info; - }; + struct ipu7_insys_resp { + u64 buf_id; + struct ipu7_insys_capture_output_pin_payload pin; @@ -372,6 +453,12 @@ enum insys_msg_err_stream { INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES_OUTPUT = 36, INSYS_MSG_ERR_STREAM_WIDTH_OUTPUT_SIZE = 37, @@ -171,7 +162,7 @@ index 7f622bfe9af6..9a4c63b68044 100644 }; diff --git a/drivers/staging/media/ipu7/ipu7-fw-isys.c b/drivers/staging/media/ipu7/ipu7-fw-isys.c -index 1ece286c2934..c594dbdbf3cc 100644 +index 1ece286c2934..ca2dbf0d325d 100644 --- a/drivers/staging/media/ipu7/ipu7-fw-isys.c +++ b/drivers/staging/media/ipu7/ipu7-fw-isys.c @@ -31,6 +31,118 @@ static const char * const send_msg_types[N_IPU_INSYS_SEND_TYPE] = { @@ -266,7 +257,7 @@ index 1ece286c2934..c594dbdbf3cc 100644 + } +} + -+static void isys_decode_resp_v1(struct ipu7_insys_resp *dst, const void *token) ++static __maybe_unused void isys_decode_resp_v1(struct ipu7_insys_resp *dst, const void *token) +{ + const struct ipu7_insys_resp_v1 *src = token; + @@ -306,26 +297,23 @@ index 1ece286c2934..c594dbdbf3cc 100644 token = ipu7_syscom_get_token(ctx, stream_handle + IPU_INSYS_INPUT_MSG_QUEUE); -@@ -97,6 +212,18 @@ int ipu7_fw_isys_init(struct ipu7_isys *isys) +@@ -97,6 +212,15 @@ int ipu7_fw_isys_init(struct ipu7_isys *isys) if (!syscom) return -ENOMEM; -+ if (is_ipu8(adev->isp->hw_ver)) { ++ if (is_ipu8(adev->isp->hw_ver)) + isys->abi_ops.prepare_payload = isys_prepare_fw_payload; -+ isys->abi_ops.decode_resp = isys_decode_resp; -+ isys->abi_ops.resp_queue_token_size = -+ sizeof(struct ipu7_insys_resp); -+ } else { ++ else + isys->abi_ops.prepare_payload = isys_prepare_fw_payload_v1; -+ isys->abi_ops.decode_resp = isys_decode_resp_v1; -+ isys->abi_ops.resp_queue_token_size = -+ sizeof(struct ipu7_insys_resp_v1); -+ } ++ ++ isys->abi_ops.decode_resp = isys_decode_resp; ++ isys->abi_ops.resp_queue_token_size = ++ sizeof(struct ipu7_insys_resp); + adev->syscom = syscom; syscom->num_input_queues = IPU_INSYS_MAX_INPUT_QUEUES; syscom->num_output_queues = IPU_INSYS_MAX_OUTPUT_QUEUES; -@@ -111,11 +238,11 @@ int ipu7_fw_isys_init(struct ipu7_isys *isys) +@@ -111,11 +235,11 @@ int ipu7_fw_isys_init(struct ipu7_isys *isys) queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].max_capacity = IPU_ISYS_SIZE_RECV_QUEUE; queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes = @@ -339,7 +327,7 @@ index 1ece286c2934..c594dbdbf3cc 100644 queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0; queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0; -@@ -195,9 +322,15 @@ int ipu7_fw_isys_close(struct ipu7_isys *isys) +@@ -195,9 +319,15 @@ int ipu7_fw_isys_close(struct ipu7_isys *isys) struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys) { @@ -358,7 +346,7 @@ index 1ece286c2934..c594dbdbf3cc 100644 } void ipu7_fw_isys_put_resp(struct ipu7_isys *isys) -@@ -327,6 +460,10 @@ void ipu7_fw_isys_dump_stream_cfg(struct device *dev, +@@ -327,6 +457,10 @@ void ipu7_fw_isys_dump_stream_cfg(struct device *dev, cfg->output_pins[i].crop.line_top); dev_dbg(dev, "\t.crop.line_bottom = %d\n", cfg->output_pins[i].crop.line_bottom); @@ -369,7 +357,7 @@ index 1ece286c2934..c594dbdbf3cc 100644 dev_dbg(dev, "\t.dpcm_enable = %d\n", cfg->output_pins[i].dpcm.enable); -@@ -334,6 +471,18 @@ void ipu7_fw_isys_dump_stream_cfg(struct device *dev, +@@ -334,6 +468,18 @@ void ipu7_fw_isys_dump_stream_cfg(struct device *dev, cfg->output_pins[i].dpcm.type); dev_dbg(dev, "\t.dpcm.predictor = %d\n", cfg->output_pins[i].dpcm.predictor); @@ -388,7 +376,7 @@ index 1ece286c2934..c594dbdbf3cc 100644 } dev_dbg(dev, "---------------------------\n"); } -@@ -352,9 +501,12 @@ void ipu7_fw_isys_dump_frame_buff_set(struct device *dev, +@@ -352,9 +498,12 @@ void ipu7_fw_isys_dump_frame_buff_set(struct device *dev, for (i = 0; i < outputs; i++) { dev_dbg(dev, ".output_pin[%d]:\n", i); @@ -476,5 +464,5 @@ index 7351fa82888f..87d30afbd872 100644 struct ipu7_insys_config *subsys_config; dma_addr_t subsys_config_dma_addr; -- -2.43.0 +2.34.1