mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
drivers: media: platform: rockchip: cif: fix panic when stream on
log: [ 79.156494] Unable to handle kernel NULL pointer dereference at virtual address 00000200 [ 79.168633] pgd = df940b55 [ 79.171344] [00000200] *pgd=00000000 [ 79.174933] Internal error: Oops: 5 [#1] PREEMPT SMP ARM [ 79.180249] Modules linked in: [ 79.183321] CPU: 1 PID: 1574 Comm: ImguThread Not tainted 4.19.111 #155 [ 79.189933] Hardware name: Generic DT based system [ 79.194734] PC is at __list_add_valid+0x24/0x84 [ 79.199272] LR is at rkcif_buf_queue+0x78/0x164 [ 79.203805] pc : [<c04ae6b0>] lr : [<c07896b0>] psr: 60000093 [ 79.210073] sp : c6127d80 ip : ca0bc7e4 fp : c13e5ee4 [ 79.215295] r10: 60000013 r9 : ca0bc800 r8 : cb5e5b58 [ 79.220525] r7 : 00000200 r6 : cb5e5a00 r5 : ca0bc7e4 r4 : ca0bc320 [ 79.227048] r3 : ca0bc800 r2 : 00000200 r1 : 00000200 r0 : cb5e5b58 [ 79.233573] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none [ 79.240797] Control: 10c5387d Table: 66f4c06a DAC: 00000051 Signed-off-by: Allon Huang <allon.huang@rock-chips.com> Change-Id: Ifb3f307971faa9d80dc5a996a41327d11fac4d1b
This commit is contained in:
@@ -514,51 +514,69 @@ static void rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 frm_addr_y, frm_addr_uv;
|
||||
|
||||
/* Set up an empty buffer for the next frame */
|
||||
spin_lock(&stream->vbq_lock);
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY ||
|
||||
stat == RKCIF_YUV_ADDR_STATE_INIT) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
buffer = stream->curr_buf;
|
||||
}
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY ||
|
||||
stat == RKCIF_YUV_ADDR_STATE_INIT) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
buffer = stream->next_buf;
|
||||
}
|
||||
} else {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY)
|
||||
stream->curr_buf = NULL;
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY)
|
||||
stream->next_buf = NULL;
|
||||
buffer = NULL;
|
||||
}
|
||||
spin_unlock(&stream->vbq_lock);
|
||||
|
||||
if (stat == RKCIF_YUV_ADDR_STATE_INIT) {
|
||||
if (stream->curr_buf && stream->next_buf) {
|
||||
if (!stream->curr_buf) {
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer,
|
||||
queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->curr_buf) {
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_Y,
|
||||
stream->curr_buf->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_UV,
|
||||
stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_Y,
|
||||
dummy_buf->dma_addr);
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_UV,
|
||||
dummy_buf->dma_addr);
|
||||
}
|
||||
|
||||
if (!stream->next_buf) {
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->next_buf) {
|
||||
write_cif_reg(base, CIF_FRM1_ADDR_Y,
|
||||
stream->next_buf->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, CIF_FRM1_ADDR_UV,
|
||||
stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "Drop to dummy buf\n");
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_Y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, CIF_FRM0_ADDR_UV, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, CIF_FRM1_ADDR_Y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, CIF_FRM1_ADDR_UV, dummy_buf->dma_addr);
|
||||
}
|
||||
} else if (stat == RKCIF_YUV_ADDR_STATE_UPDATE) {
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
buffer = stream->curr_buf;
|
||||
}
|
||||
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY ) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
buffer = stream->next_buf;
|
||||
}
|
||||
} else {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY)
|
||||
stream->curr_buf = NULL;
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY)
|
||||
stream->next_buf = NULL;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
|
||||
frm_addr_y = CIF_FRM0_ADDR_Y;
|
||||
frm_addr_uv = CIF_FRM0_ADDR_UV;
|
||||
@@ -581,6 +599,7 @@ static void rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
|
||||
"frame Drop to dummy buf\n");
|
||||
}
|
||||
}
|
||||
spin_unlock(&stream->vbq_lock);
|
||||
}
|
||||
|
||||
static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
|
||||
@@ -592,31 +611,6 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 frm_addr_y, frm_addr_uv;
|
||||
|
||||
/* Set up an empty buffer for the next frame */
|
||||
spin_lock(&stream->vbq_lock);
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY || init) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
buffer = stream->curr_buf;
|
||||
}
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY || init) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
buffer = stream->next_buf;
|
||||
}
|
||||
} else {
|
||||
if (stream->frame_phase & CIF_CSI_FRAME0_READY)
|
||||
stream->curr_buf = NULL;
|
||||
if (stream->frame_phase & CIF_CSI_FRAME1_READY)
|
||||
stream->next_buf = NULL;
|
||||
|
||||
buffer = NULL;
|
||||
}
|
||||
spin_unlock(&stream->vbq_lock);
|
||||
|
||||
if (init) {
|
||||
u32 frm0_addr_y, frm0_addr_uv;
|
||||
u32 frm1_addr_y, frm1_addr_uv;
|
||||
@@ -633,49 +627,94 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
|
||||
frm1_addr_uv = CIF_FRM1_ADDR_UV;
|
||||
}
|
||||
|
||||
if (stream->curr_buf && stream->next_buf) {
|
||||
spin_lock(&stream->vbq_lock);
|
||||
if (!stream->curr_buf) {
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer,
|
||||
queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->curr_buf) {
|
||||
write_cif_reg(base, frm0_addr_y,
|
||||
stream->curr_buf->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, frm0_addr_uv,
|
||||
stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
write_cif_reg(base, frm0_addr_y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm0_addr_uv, dummy_buf->dma_addr);
|
||||
}
|
||||
|
||||
if (!stream->next_buf) {
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->next_buf) {
|
||||
write_cif_reg(base, frm1_addr_y,
|
||||
stream->next_buf->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, frm1_addr_uv,
|
||||
stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "Drop to dummy buf\n");
|
||||
write_cif_reg(base, frm0_addr_y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm0_addr_uv, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm1_addr_y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm1_addr_uv, dummy_buf->dma_addr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
(CIF_CSI_FRM1_ADDR_Y_ID0 + 0x20 * csi_ch) :
|
||||
(CIF_CSI_FRM0_ADDR_Y_ID0 + 0x20 * csi_ch);
|
||||
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
(CIF_CSI_FRM1_ADDR_UV_ID0 + 0x20 * csi_ch) :
|
||||
(CIF_CSI_FRM0_ADDR_UV_ID0 + 0x20 * csi_ch);
|
||||
spin_unlock(&stream->vbq_lock);
|
||||
} else {
|
||||
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
CIF_FRM1_ADDR_Y : CIF_FRM0_ADDR_Y;
|
||||
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
CIF_FRM1_ADDR_UV : CIF_FRM0_ADDR_UV;
|
||||
}
|
||||
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
(CIF_CSI_FRM1_ADDR_Y_ID0 + 0x20 * csi_ch) :
|
||||
(CIF_CSI_FRM0_ADDR_Y_ID0 + 0x20 * csi_ch);
|
||||
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
(CIF_CSI_FRM1_ADDR_UV_ID0 + 0x20 * csi_ch) :
|
||||
(CIF_CSI_FRM0_ADDR_UV_ID0 + 0x20 * csi_ch);
|
||||
} else {
|
||||
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
CIF_FRM1_ADDR_Y : CIF_FRM0_ADDR_Y;
|
||||
frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ?
|
||||
CIF_FRM1_ADDR_UV : CIF_FRM0_ADDR_UV;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
write_cif_reg(base, frm_addr_y,
|
||||
buffer->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, frm_addr_uv,
|
||||
buffer->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "Drop to dummy buf\n");
|
||||
write_cif_reg(base, frm_addr_y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm_addr_uv, dummy_buf->dma_addr);
|
||||
spin_lock(&stream->vbq_lock);
|
||||
if (!list_empty(&stream->buf_head)) {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY) {
|
||||
stream->curr_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
buffer = stream->curr_buf;
|
||||
}
|
||||
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY) {
|
||||
stream->next_buf = list_first_entry(&stream->buf_head,
|
||||
struct rkcif_buffer, queue);
|
||||
list_del(&stream->next_buf->queue);
|
||||
buffer = stream->next_buf;
|
||||
}
|
||||
} else {
|
||||
if (stream->frame_phase == CIF_CSI_FRAME0_READY)
|
||||
stream->curr_buf = NULL;
|
||||
if (stream->frame_phase == CIF_CSI_FRAME1_READY)
|
||||
stream->next_buf = NULL;
|
||||
buffer = NULL;
|
||||
}
|
||||
spin_unlock(&stream->vbq_lock);
|
||||
|
||||
if (buffer) {
|
||||
write_cif_reg(base, frm_addr_y,
|
||||
buffer->buff_addr[RKCIF_PLANE_Y]);
|
||||
write_cif_reg(base, frm_addr_uv,
|
||||
buffer->buff_addr[RKCIF_PLANE_CBCR]);
|
||||
} else {
|
||||
write_cif_reg(base, frm_addr_y, dummy_buf->dma_addr);
|
||||
write_cif_reg(base, frm_addr_uv, dummy_buf->dma_addr);
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
|
||||
"frame Drop to dummy buf\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1389,9 +1428,9 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
|
||||
} else {
|
||||
ret = rkcif_stream_start(stream);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto runtime_put;
|
||||
|
||||
/* start sub-devices */
|
||||
ret = dev->pipe.set_stream(&dev->pipe, true);
|
||||
if (ret < 0)
|
||||
@@ -1605,6 +1644,7 @@ static int rkcif_fh_open(struct file *filp)
|
||||
} else {
|
||||
rkcif_soft_reset(cifdev, true);
|
||||
}
|
||||
|
||||
return v4l2_fh_open(filp);
|
||||
}
|
||||
|
||||
@@ -1617,6 +1657,7 @@ static int rkcif_fh_release(struct file *filp)
|
||||
int ret = 0;
|
||||
|
||||
ret = vb2_fop_release(filp);
|
||||
|
||||
mutex_lock(&cifdev->stream_lock);
|
||||
if (!atomic_dec_return(&cifdev->fh_cnt))
|
||||
rkcif_soft_reset(cifdev, true);
|
||||
|
||||
Reference in New Issue
Block a user