diff mbox series

[v1,4/5] drivers: media: bcm2835-unicam: Fix for possible dummy buffer overrun

Message ID 20241122084152.1841419-5-naush@raspberrypi.com (mailing list archive)
State New
Headers show
Series media: bcm2835-unicam: Upstreaming various improvements | expand

Commit Message

Naushir Patuck Nov. 22, 2024, 8:41 a.m. UTC
The Unicam hardware has been observed to cause a buffer overrun when
using the dummy buffer as a circular buffer. The conditions that cause
the overrun are not fully known, but it seems to occur when the memory
bus is heavily loaded.

To avoid the overrun, program the hardware with a buffer size of 0 when
using the dummy buffer. This will cause overrun into the allocated dummy
buffer, but avoid out of bounds writes.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 drivers/media/platform/broadcom/bcm2835-unicam.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Comments

Jacopo Mondi Nov. 22, 2024, 11:20 a.m. UTC | #1
Hi Naush

On Fri, Nov 22, 2024 at 08:41:51AM +0000, Naushir Patuck wrote:
> The Unicam hardware has been observed to cause a buffer overrun when
> using the dummy buffer as a circular buffer. The conditions that cause
> the overrun are not fully known, but it seems to occur when the memory
> bus is heavily loaded.
>
> To avoid the overrun, program the hardware with a buffer size of 0 when
> using the dummy buffer. This will cause overrun into the allocated dummy
> buffer, but avoid out of bounds writes.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> ---
>  drivers/media/platform/broadcom/bcm2835-unicam.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> index 550eb1b064f1..f10064107d54 100644
> --- a/drivers/media/platform/broadcom/bcm2835-unicam.c
> +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> @@ -640,7 +640,14 @@ static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
>  static void unicam_wr_dma_addr(struct unicam_node *node,
>  			       struct unicam_buffer *buf)
>  {
> -	dma_addr_t endaddr = buf->dma_addr + buf->size;
> +	/*
> +	 * Due to a HW bug causing buffer overruns in circular buffer mode under
> +	 * certain (not yet fully known) conditions, the dummy buffer allocation
> +	 * is set to a a single page size, but the hardware gets programmed with
> +	 * a buffer size of 0.
> +	 */
> +	dma_addr_t endaddr = buf->dma_addr +
> +			     (buf != &node->dummy_buf ? buf->size : 0);

So the DMA engine doesn't actually write any data to dummy_buf
anymore ?

Does it still need to be allocated at all ? Or can we simply set the
dma transfer size to 0 ?

>
>  	if (node->id == UNICAM_IMAGE_NODE) {
>  		unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);
> --
> 2.34.1
>
>
Naushir Patuck Nov. 22, 2024, 11:35 a.m. UTC | #2
Hi Jacopo,

On Fri, 22 Nov 2024 at 11:20, Jacopo Mondi
<jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Naush
>
> On Fri, Nov 22, 2024 at 08:41:51AM +0000, Naushir Patuck wrote:
> > The Unicam hardware has been observed to cause a buffer overrun when
> > using the dummy buffer as a circular buffer. The conditions that cause
> > the overrun are not fully known, but it seems to occur when the memory
> > bus is heavily loaded.
> >
> > To avoid the overrun, program the hardware with a buffer size of 0 when
> > using the dummy buffer. This will cause overrun into the allocated dummy
> > buffer, but avoid out of bounds writes.
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > ---
> >  drivers/media/platform/broadcom/bcm2835-unicam.c | 9 ++++++++-
> >  1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > index 550eb1b064f1..f10064107d54 100644
> > --- a/drivers/media/platform/broadcom/bcm2835-unicam.c
> > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > @@ -640,7 +640,14 @@ static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
> >  static void unicam_wr_dma_addr(struct unicam_node *node,
> >                              struct unicam_buffer *buf)
> >  {
> > -     dma_addr_t endaddr = buf->dma_addr + buf->size;
> > +     /*
> > +      * Due to a HW bug causing buffer overruns in circular buffer mode under
> > +      * certain (not yet fully known) conditions, the dummy buffer allocation
> > +      * is set to a a single page size, but the hardware gets programmed with
> > +      * a buffer size of 0.
> > +      */
> > +     dma_addr_t endaddr = buf->dma_addr +
> > +                          (buf != &node->dummy_buf ? buf->size : 0);
>
> So the DMA engine doesn't actually write any data to dummy_buf
> anymore ?
>
>
> Does it still need to be allocated at all ? Or can we simply set the
> dma transfer size to 0 ?

The DMA engine does still write to the buffer, so the allocation needs
to occur. The zero size programmed into the register is a quirk of the
HW itself, and is used to ensure the write wrap correctly in the
buffer.

Naush

>
> >
> >       if (node->id == UNICAM_IMAGE_NODE) {
> >               unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);
> > --
> > 2.34.1
> >
> >
Jacopo Mondi Nov. 22, 2024, 2:42 p.m. UTC | #3
Hi Naush

On Fri, Nov 22, 2024 at 11:35:59AM +0000, Naushir Patuck wrote:
> Hi Jacopo,

Thanks for the explanation

>
> On Fri, 22 Nov 2024 at 11:20, Jacopo Mondi
> <jacopo.mondi@ideasonboard.com> wrote:
> >
> > Hi Naush
> >
> > On Fri, Nov 22, 2024 at 08:41:51AM +0000, Naushir Patuck wrote:
> > > The Unicam hardware has been observed to cause a buffer overrun when
> > > using the dummy buffer as a circular buffer. The conditions that cause
> > > the overrun are not fully known, but it seems to occur when the memory
> > > bus is heavily loaded.
> > >
> > > To avoid the overrun, program the hardware with a buffer size of 0 when
> > > using the dummy buffer. This will cause overrun into the allocated dummy
> > > buffer, but avoid out of bounds writes.
> > >
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Thanks
  j

> > > ---
> > >  drivers/media/platform/broadcom/bcm2835-unicam.c | 9 ++++++++-
> > >  1 file changed, 8 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > index 550eb1b064f1..f10064107d54 100644
> > > --- a/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > @@ -640,7 +640,14 @@ static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
> > >  static void unicam_wr_dma_addr(struct unicam_node *node,
> > >                              struct unicam_buffer *buf)
> > >  {
> > > -     dma_addr_t endaddr = buf->dma_addr + buf->size;
> > > +     /*
> > > +      * Due to a HW bug causing buffer overruns in circular buffer mode under
> > > +      * certain (not yet fully known) conditions, the dummy buffer allocation
> > > +      * is set to a a single page size, but the hardware gets programmed with
> > > +      * a buffer size of 0.
> > > +      */
> > > +     dma_addr_t endaddr = buf->dma_addr +
> > > +                          (buf != &node->dummy_buf ? buf->size : 0);
> >
> > So the DMA engine doesn't actually write any data to dummy_buf
> > anymore ?
> >
> >
> > Does it still need to be allocated at all ? Or can we simply set the
> > dma transfer size to 0 ?
>
> The DMA engine does still write to the buffer, so the allocation needs
> to occur. The zero size programmed into the register is a quirk of the
> HW itself, and is used to ensure the write wrap correctly in the
> buffer.
>
> Naush
>
> >
> > >
> > >       if (node->id == UNICAM_IMAGE_NODE) {
> > >               unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);
> > > --
> > > 2.34.1
> > >
> > >
>
diff mbox series

Patch

diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
index 550eb1b064f1..f10064107d54 100644
--- a/drivers/media/platform/broadcom/bcm2835-unicam.c
+++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
@@ -640,7 +640,14 @@  static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
 static void unicam_wr_dma_addr(struct unicam_node *node,
 			       struct unicam_buffer *buf)
 {
-	dma_addr_t endaddr = buf->dma_addr + buf->size;
+	/*
+	 * Due to a HW bug causing buffer overruns in circular buffer mode under
+	 * certain (not yet fully known) conditions, the dummy buffer allocation
+	 * is set to a a single page size, but the hardware gets programmed with
+	 * a buffer size of 0.
+	 */
+	dma_addr_t endaddr = buf->dma_addr +
+			     (buf != &node->dummy_buf ? buf->size : 0);
 
 	if (node->id == UNICAM_IMAGE_NODE) {
 		unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);