summaryrefslogtreecommitdiff
path: root/drivers/media/platform/allegro-dvt/allegro-core.c
diff options
context:
space:
mode:
authorMatthias Fend <matthias.fend@emfend.at>2025-09-01 17:13:37 +0200
committerHans Verkuil <hverkuil+cisco@kernel.org>2025-10-20 09:23:17 +0200
commit62190e91b070cf5987f85dddafe82dbfb193999f (patch)
tree9d1e7d4939b763f765e13594b11e9db71d630103 /drivers/media/platform/allegro-dvt/allegro-core.c
parent277f507fb1ece3c2050b75594d64b050590cc82b (diff)
media: allegro: process all pending status mbox messages
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> Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Diffstat (limited to 'drivers/media/platform/allegro-dvt/allegro-core.c')
-rw-r--r--drivers/media/platform/allegro-dvt/allegro-core.c42
1 files 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 be56ef682845..3d531dce8086 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -831,6 +831,20 @@ out:
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)
{
@@ -839,11 +853,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;
@@ -857,6 +875,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
@@ -916,26 +936,27 @@ out:
* 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);
@@ -947,6 +968,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,
@@ -2329,7 +2352,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;
}