Skip to content

Commit ca95c84

Browse files
naushirJacopo Mondi
authored and
Jacopo Mondi
committed
media: bcm2835-unicam: Fix for possible dummy buffer overrun
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 <[email protected]>
1 parent 737b505 commit ca95c84

File tree

1 file changed

+12
-7
lines changed

1 file changed

+12
-7
lines changed

Diff for: drivers/media/platform/broadcom/bcm2835-unicam.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -641,9 +641,9 @@ static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
641641
}
642642

643643
static void unicam_wr_dma_addr(struct unicam_node *node,
644-
struct unicam_buffer *buf)
644+
struct unicam_buffer *buf, unsigned int size)
645645
{
646-
dma_addr_t endaddr = buf->dma_addr + buf->size;
646+
dma_addr_t endaddr = buf->dma_addr + size;
647647

648648
if (node->id == UNICAM_IMAGE_NODE) {
649649
unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);
@@ -676,16 +676,21 @@ static void unicam_schedule_next_buffer(struct unicam_node *node)
676676
node->next_frm = buf;
677677
list_del(&buf->list);
678678

679-
unicam_wr_dma_addr(node, buf);
679+
unicam_wr_dma_addr(node, buf, buf->size);
680680
}
681681

682682
static void unicam_schedule_dummy_buffer(struct unicam_node *node)
683683
{
684684
int node_id = is_image_node(node) ? UNICAM_IMAGE_NODE : UNICAM_METADATA_NODE;
685685

686686
dev_dbg(node->dev->dev, "Scheduling dummy buffer for node %d\n", node_id);
687-
688-
unicam_wr_dma_addr(node, &node->dummy_buf);
687+
/*
688+
* Due to a HW bug causing buffer overruns in circular buffer mode under
689+
* certain (not yet fully known) conditions, the dummy buffer allocation
690+
* is set to a a single page size, but the hardware gets programmed with
691+
* a buffer size of 0.
692+
*/
693+
unicam_wr_dma_addr(node, &node->dummy_buf, 0);
689694

690695
node->next_frm = NULL;
691696
}
@@ -1096,7 +1101,7 @@ static void unicam_start_rx(struct unicam_device *unicam,
10961101

10971102
unicam_reg_write(unicam, UNICAM_IBLS,
10981103
node->fmt.fmt.pix.bytesperline);
1099-
unicam_wr_dma_addr(node, node->cur_frm);
1104+
unicam_wr_dma_addr(node, node->cur_frm, node->cur_frm->size);
11001105
unicam_set_packing_config(unicam, fmtinfo);
11011106

11021107
ret = unicam_get_image_vc_dt(unicam, state, &vc, &dt);
@@ -1134,7 +1139,7 @@ static void unicam_start_metadata(struct unicam_device *unicam)
11341139
struct unicam_node *node = &unicam->node[UNICAM_METADATA_NODE];
11351140

11361141
unicam_enable_ed(unicam);
1137-
unicam_wr_dma_addr(node, node->cur_frm);
1142+
unicam_wr_dma_addr(node, node->cur_frm, node->cur_frm->size);
11381143
unicam_reg_write_field(unicam, UNICAM_DCS, 1, UNICAM_LDP);
11391144
}
11401145

0 commit comments

Comments
 (0)