Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/media/pci/intel/ipu7/abi/ipu7_fw_isys_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/pci/intel/ipu7/ipu7-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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) |
Expand Down
6 changes: 6 additions & 0 deletions drivers/media/pci/intel/ipu7/ipu7-bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 6 additions & 3 deletions drivers/media/pci/intel/ipu7/ipu7-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down
17 changes: 7 additions & 10 deletions drivers/media/pci/intel/ipu7/ipu7-fw-isys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions drivers/media/pci/intel/ipu7/ipu7-isys-queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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];
Expand All @@ -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];
Expand Down Expand Up @@ -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);
Expand Down
26 changes: 6 additions & 20 deletions drivers/media/pci/intel/ipu7/ipu7-isys-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
81 changes: 71 additions & 10 deletions drivers/media/pci/intel/ipu7/ipu7-isys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -997,25 +1037,30 @@ 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;
}
}
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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading
Loading