linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] media: allegro: fixes and improvements
@ 2025-09-01 15:13 Matthias Fend
  2025-09-01 15:13 ` [PATCH 1/3] media: allegro: print warning if channel creation timeout occurs Matthias Fend
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Matthias Fend @ 2025-09-01 15:13 UTC (permalink / raw)
  To: Michael Tretter, Pengutronix Kernel Team, Mauro Carvalho Chehab
  Cc: linux-media, linux-kernel, Matthias Fend

Several fixes and improvements for the Allegro DVT video IP encoder.
These relate to race conditions that occur when multiple streams are used
simultaneously.
The problems could be reproduced on a ZCU-104 eval board with VCU firmware
version 2019.2 on various kernel versions (6.4, 6.12 and 6.16).
It is highly likely that these problems can also occur with other firmware
versions.

Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
---
Matthias Fend (3):
      media: allegro: print warning if channel creation timeout occurs
      media: allegro: process all pending status mbox messages
      media: allegro: fix race conditions in channel handling

 drivers/media/platform/allegro-dvt/allegro-core.c | 114 +++++++++++++++++-----
 1 file changed, 91 insertions(+), 23 deletions(-)
---
base-commit: b320789d6883cc00ac78ce83bccbfe7ed58afcf0
change-id: 20250901-allegro-dvt-fixes-932f2c97063e

Best regards,
-- 
Matthias Fend <matthias.fend@emfend.at>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] media: allegro: print warning if channel creation timeout occurs
  2025-09-01 15:13 [PATCH 0/3] media: allegro: fixes and improvements Matthias Fend
@ 2025-09-01 15:13 ` Matthias Fend
  2025-09-01 15:13 ` [PATCH 2/3] media: allegro: process all pending status mbox messages Matthias Fend
  2025-09-01 15:13 ` [PATCH 3/3] media: allegro: fix race conditions in channel handling Matthias Fend
  2 siblings, 0 replies; 4+ messages in thread
From: Matthias Fend @ 2025-09-01 15:13 UTC (permalink / raw)
  To: Michael Tretter, Pengutronix Kernel Team, Mauro Carvalho Chehab
  Cc: linux-media, linux-kernel, Matthias Fend

This message can be helpful for troubleshooting and there is already a
corresponding message in case of a channel destroy timeout.
Add a similar message for channel creation.

Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
---
 drivers/media/platform/allegro-dvt/allegro-core.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
index eb03df0d8652745ef533b9b7aa6c105a140ad022..4c5c2a7fe5426aa81ba341aba046ef166c51f664 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -2599,8 +2599,14 @@ static int allegro_create_channel(struct allegro_channel *channel)
 	allegro_mcu_send_create_channel(dev, channel);
 	time_left = wait_for_completion_timeout(&channel->completion,
 						msecs_to_jiffies(5000));
-	if (time_left == 0)
+	if (time_left == 0) {
+		v4l2_warn(&dev->v4l2_dev,
+			  "user %d: timeout while creating channel\n",
+			  channel->user_id);
+
 		channel->error = -ETIMEDOUT;
+	}
+
 	if (channel->error)
 		goto err;
 

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] media: allegro: process all pending status mbox messages
  2025-09-01 15:13 [PATCH 0/3] media: allegro: fixes and improvements Matthias Fend
  2025-09-01 15:13 ` [PATCH 1/3] media: allegro: print warning if channel creation timeout occurs Matthias Fend
@ 2025-09-01 15:13 ` Matthias Fend
  2025-09-01 15:13 ` [PATCH 3/3] media: allegro: fix race conditions in channel handling Matthias Fend
  2 siblings, 0 replies; 4+ messages in thread
From: Matthias Fend @ 2025-09-01 15:13 UTC (permalink / raw)
  To: Michael Tretter, Pengutronix Kernel Team, Mauro Carvalho Chehab
  Cc: linux-media, linux-kernel, Matthias Fend

Under certain circumstances, not every message written by the MCU to the
status mailbox may trigger a corresponding interrupt. This is likely when
multiple messages are generated in a very short period of time. Since the
current implementation only processes one message per interrupt, even if
multiple messages are already available in the mailbox, expected messages
are either not received or are processed late. This leads to various
subsequent problems and causes the driver to no longer function properly.

The behavior has been adjusted so that after an interrupt, all messages
available in the mailbox are processed.

Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
---
 drivers/media/platform/allegro-dvt/allegro-core.c | 42 ++++++++++++++++++-----
 1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
index 4c5c2a7fe5426aa81ba341aba046ef166c51f664..d3aea46b7d1d9854307d61d2f1647eaa340d504d 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -828,6 +828,20 @@ static int allegro_mbox_write(struct allegro_mbox *mbox,
 	return err;
 }
 
+static unsigned int allegro_mbox_get_available(struct allegro_mbox *mbox)
+{
+	struct regmap *sram = mbox->dev->sram;
+	unsigned int head, tail;
+
+	regmap_read(sram, mbox->head, &head);
+	regmap_read(sram, mbox->tail, &tail);
+
+	if (tail >= head)
+		return tail - head;
+	else
+		return mbox->size - (head - tail);
+}
+
 static ssize_t allegro_mbox_read(struct allegro_mbox *mbox,
 				 u32 *dst, size_t nbyte)
 {
@@ -836,11 +850,15 @@ static ssize_t allegro_mbox_read(struct allegro_mbox *mbox,
 		u16 type;
 	} __attribute__ ((__packed__)) *header;
 	struct regmap *sram = mbox->dev->sram;
-	unsigned int head;
+	unsigned int available, head;
 	ssize_t size;
 	size_t body_no_wrap;
 	int stride = regmap_get_reg_stride(sram);
 
+	available = allegro_mbox_get_available(mbox);
+	if (available < sizeof(*header))
+		return -EAGAIN;
+
 	regmap_read(sram, mbox->head, &head);
 	if (head > mbox->size)
 		return -EIO;
@@ -854,6 +872,8 @@ static ssize_t allegro_mbox_read(struct allegro_mbox *mbox,
 		return -EIO;
 	if (size > nbyte)
 		return -EINVAL;
+	if (size > available)
+		return -EAGAIN;
 
 	/*
 	 * The message might wrap within the mailbox. If the message does not
@@ -913,26 +933,27 @@ static int allegro_mbox_send(struct allegro_mbox *mbox, void *msg)
  * allegro_mbox_notify() - Notify the mailbox about a new message
  * @mbox: The allegro_mbox to notify
  */
-static void allegro_mbox_notify(struct allegro_mbox *mbox)
+static int allegro_mbox_notify(struct allegro_mbox *mbox)
 {
 	struct allegro_dev *dev = mbox->dev;
 	union mcu_msg_response *msg;
-	ssize_t size;
 	u32 *tmp;
 	int err;
 
 	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
 	if (!msg)
-		return;
+		return -ENOMEM;
 
 	msg->header.version = dev->fw_info->mailbox_version;
 
 	tmp = kmalloc(mbox->size, GFP_KERNEL);
-	if (!tmp)
+	if (!tmp) {
+		err = -ENOMEM;
 		goto out;
+	}
 
-	size = allegro_mbox_read(mbox, tmp, mbox->size);
-	if (size < 0)
+	err = allegro_mbox_read(mbox, tmp, mbox->size);
+	if (err < 0)
 		goto out;
 
 	err = allegro_decode_mail(msg, tmp);
@@ -944,6 +965,8 @@ static void allegro_mbox_notify(struct allegro_mbox *mbox)
 out:
 	kfree(tmp);
 	kfree(msg);
+
+	return err;
 }
 
 static int allegro_encoder_buffer_init(struct allegro_dev *dev,
@@ -2326,7 +2349,10 @@ static irqreturn_t allegro_irq_thread(int irq, void *data)
 	if (!dev->mbox_status)
 		return IRQ_NONE;
 
-	allegro_mbox_notify(dev->mbox_status);
+	while (allegro_mbox_get_available(dev->mbox_status) > 0) {
+		if (allegro_mbox_notify(dev->mbox_status))
+			break;
+	}
 
 	return IRQ_HANDLED;
 }

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] media: allegro: fix race conditions in channel handling
  2025-09-01 15:13 [PATCH 0/3] media: allegro: fixes and improvements Matthias Fend
  2025-09-01 15:13 ` [PATCH 1/3] media: allegro: print warning if channel creation timeout occurs Matthias Fend
  2025-09-01 15:13 ` [PATCH 2/3] media: allegro: process all pending status mbox messages Matthias Fend
@ 2025-09-01 15:13 ` Matthias Fend
  2 siblings, 0 replies; 4+ messages in thread
From: Matthias Fend @ 2025-09-01 15:13 UTC (permalink / raw)
  To: Michael Tretter, Pengutronix Kernel Team, Mauro Carvalho Chehab
  Cc: linux-media, linux-kernel, Matthias Fend

Since the channel list is used in different contexts, it must be ensured
that it is always consistent. Also, the channels contained in the list may
only be released when they are no longer needed in any context.

Add a lock to protect the list and reference handling for the channels.

Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
---
 drivers/media/platform/allegro-dvt/allegro-core.c | 64 ++++++++++++++++++-----
 1 file changed, 50 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
index d3aea46b7d1d9854307d61d2f1647eaa340d504d..adcaa4f877df1c58807d62ddf3eb21848fb08520 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -177,6 +177,7 @@ struct allegro_dev {
 	 */
 	unsigned long channel_user_ids;
 	struct list_head channels;
+	struct mutex channels_lock;
 };
 
 static const struct regmap_config allegro_regmap_config = {
@@ -200,6 +201,7 @@ static const struct regmap_config allegro_sram_config = {
 #define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh)
 
 struct allegro_channel {
+	struct kref ref;
 	struct allegro_dev *dev;
 	struct v4l2_fh fh;
 	struct v4l2_ctrl_handler ctrl_handler;
@@ -427,33 +429,55 @@ static unsigned long allegro_next_user_id(struct allegro_dev *dev)
 }
 
 static struct allegro_channel *
-allegro_find_channel_by_user_id(struct allegro_dev *dev,
-				unsigned int user_id)
+allegro_ref_get_channel_by_user_id(struct allegro_dev *dev,
+				   unsigned int user_id)
 {
 	struct allegro_channel *channel;
 
+	guard(mutex)(&dev->channels_lock);
+
 	list_for_each_entry(channel, &dev->channels, list) {
-		if (channel->user_id == user_id)
-			return channel;
+		if (channel->user_id == user_id) {
+			if (kref_get_unless_zero(&channel->ref))
+				return channel;
+			break;
+		}
 	}
 
 	return ERR_PTR(-EINVAL);
 }
 
 static struct allegro_channel *
-allegro_find_channel_by_channel_id(struct allegro_dev *dev,
-				   unsigned int channel_id)
+allegro_ref_get_channel_by_channel_id(struct allegro_dev *dev,
+				      unsigned int channel_id)
 {
 	struct allegro_channel *channel;
 
+	guard(mutex)(&dev->channels_lock);
+
 	list_for_each_entry(channel, &dev->channels, list) {
-		if (channel->mcu_channel_id == channel_id)
-			return channel;
+		if (channel->mcu_channel_id == channel_id) {
+			if (kref_get_unless_zero(&channel->ref))
+				return channel;
+			break;
+		}
 	}
 
 	return ERR_PTR(-EINVAL);
 }
 
+static void allegro_free_channel(struct kref *ref)
+{
+	struct allegro_channel *channel = container_of(ref, struct allegro_channel, ref);
+
+	kfree(channel);
+}
+
+static int allegro_ref_put_channel(struct allegro_channel *channel)
+{
+	return kref_put(&channel->ref, allegro_free_channel);
+}
+
 static inline bool channel_exists(struct allegro_channel *channel)
 {
 	return channel->mcu_channel_id != -1;
@@ -2183,7 +2207,7 @@ allegro_handle_create_channel(struct allegro_dev *dev,
 	int err = 0;
 	struct create_channel_param param;
 
-	channel = allegro_find_channel_by_user_id(dev, msg->user_id);
+	channel = allegro_ref_get_channel_by_user_id(dev, msg->user_id);
 	if (IS_ERR(channel)) {
 		v4l2_warn(&dev->v4l2_dev,
 			  "received %s for unknown user %d\n",
@@ -2250,6 +2274,7 @@ allegro_handle_create_channel(struct allegro_dev *dev,
 out:
 	channel->error = err;
 	complete(&channel->completion);
+	allegro_ref_put_channel(channel);
 
 	/* Handled successfully, error is passed via channel->error */
 	return 0;
@@ -2261,7 +2286,7 @@ allegro_handle_destroy_channel(struct allegro_dev *dev,
 {
 	struct allegro_channel *channel;
 
-	channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+	channel = allegro_ref_get_channel_by_channel_id(dev, msg->channel_id);
 	if (IS_ERR(channel)) {
 		v4l2_err(&dev->v4l2_dev,
 			 "received %s for unknown channel %d\n",
@@ -2274,6 +2299,7 @@ allegro_handle_destroy_channel(struct allegro_dev *dev,
 		 "user %d: vcu destroyed channel %d\n",
 		 channel->user_id, channel->mcu_channel_id);
 	complete(&channel->completion);
+	allegro_ref_put_channel(channel);
 
 	return 0;
 }
@@ -2284,7 +2310,7 @@ allegro_handle_encode_frame(struct allegro_dev *dev,
 {
 	struct allegro_channel *channel;
 
-	channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+	channel = allegro_ref_get_channel_by_channel_id(dev, msg->channel_id);
 	if (IS_ERR(channel)) {
 		v4l2_err(&dev->v4l2_dev,
 			 "received %s for unknown channel %d\n",
@@ -2294,6 +2320,7 @@ allegro_handle_encode_frame(struct allegro_dev *dev,
 	}
 
 	allegro_channel_finish_frame(channel, msg);
+	allegro_ref_put_channel(channel);
 
 	return 0;
 }
@@ -3079,6 +3106,8 @@ static int allegro_open(struct file *file)
 	if (!channel)
 		return -ENOMEM;
 
+	kref_init(&channel->ref);
+
 	v4l2_fh_init(&channel->fh, vdev);
 
 	init_completion(&channel->completion);
@@ -3245,7 +3274,10 @@ static int allegro_open(struct file *file)
 		goto error;
 	}
 
-	list_add(&channel->list, &dev->channels);
+	scoped_guard(mutex, &dev->channels_lock) {
+		list_add(&channel->list, &dev->channels);
+	}
+
 	file->private_data = &channel->fh;
 	v4l2_fh_add(&channel->fh);
 
@@ -3262,17 +3294,20 @@ static int allegro_open(struct file *file)
 static int allegro_release(struct file *file)
 {
 	struct allegro_channel *channel = fh_to_channel(file->private_data);
+	struct allegro_dev *dev = channel->dev;
 
 	v4l2_m2m_ctx_release(channel->fh.m2m_ctx);
 
-	list_del(&channel->list);
+	scoped_guard(mutex, &dev->channels_lock) {
+		list_del(&channel->list);
+	}
 
 	v4l2_ctrl_handler_free(&channel->ctrl_handler);
 
 	v4l2_fh_del(&channel->fh);
 	v4l2_fh_exit(&channel->fh);
 
-	kfree(channel);
+	allegro_ref_put_channel(channel);
 
 	return 0;
 }
@@ -3867,6 +3902,7 @@ static int allegro_probe(struct platform_device *pdev)
 	dev->plat_dev = pdev;
 	init_completion(&dev->init_complete);
 	INIT_LIST_HEAD(&dev->channels);
+	mutex_init(&dev->channels_lock);
 
 	mutex_init(&dev->lock);
 

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-09-01 15:43 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-01 15:13 [PATCH 0/3] media: allegro: fixes and improvements Matthias Fend
2025-09-01 15:13 ` [PATCH 1/3] media: allegro: print warning if channel creation timeout occurs Matthias Fend
2025-09-01 15:13 ` [PATCH 2/3] media: allegro: process all pending status mbox messages Matthias Fend
2025-09-01 15:13 ` [PATCH 3/3] media: allegro: fix race conditions in channel handling Matthias Fend

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).