Commit 4cad3ef9 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Detect and fix erroneous HW pointer in updateIRQJPEG_wp

It looks like compessor is reporting erroneous HW pointer when last
frame ends precisely at the end of buffer and 32 zero bytes start from
the beginning of the buffer. HW pointer in this case should be 0x20, but
it is 0x00 in fact. This situation is detected and fixed in updateIRQJPEG_wp.
parent f3ef9f81
...@@ -111,7 +111,7 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev) ...@@ -111,7 +111,7 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
} }
// set circular buffer size in bytes // set circular buffer size in bytes
set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE); // set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE);
for (i = 0; i < IMAGE_CHN_NUM; i++) { for (i = 0; i < IMAGE_CHN_NUM; i++) {
circbuf_priv[i].buf_ptr = ccam_dma_buf_ptr + BYTE2DW(CIRCBUF_START_OFFSET + i * CCAM_DMA_SIZE); circbuf_priv[i].buf_ptr = ccam_dma_buf_ptr + BYTE2DW(CIRCBUF_START_OFFSET + i * CCAM_DMA_SIZE);
...@@ -290,6 +290,8 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun ...@@ -290,6 +290,8 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH); offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH);
len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)]; len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)];
dev_dbg(g_dev_ptr, "[chn %d] byte_offset = 0x%x, calculated offset = 0x%x, len32 = 0x%lx\n", chn, byte_offset, offset, len32);
if ((len32 & MARKER_FF) != MARKER_FF) { if ((len32 & MARKER_FF) != MARKER_FF) {
dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at offset 0x%x\n", chn, offset); dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at offset 0x%x\n", chn, offset);
// byte_offset = X393_BUFFSUB(byte_offset, CHUNK_SIZE); // byte_offset = X393_BUFFSUB(byte_offset, CHUNK_SIZE);
...@@ -321,7 +323,7 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun ...@@ -321,7 +323,7 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
* -1 if there is no frame at this index, -2 if the pointer is not 32-bytes aligned * -1 if there is no frame at this index, -2 if the pointer is not 32-bytes aligned
* sets *fpp to the frame header, including signature and length * sets *fpp to the frame header, including signature and length
*/ */
int circbuf_valid_ptr(int *rp_offset, struct interframe_params_t **fpp, unsigned int chn) int circbuf_valid_ptr(loff_t *rp_offset, struct interframe_params_t **fpp, unsigned int chn)
{ {
int rp = *rp_offset; int rp = *rp_offset;
int last_image_chunk; int last_image_chunk;
...@@ -478,7 +480,6 @@ void dump_state(unsigned int chn) ...@@ -478,7 +480,6 @@ void dump_state(unsigned int chn)
loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
{ {
unsigned int len32 = 0; unsigned int len32 = 0;
int inserted_bytes;
int last_image_chunk; int last_image_chunk;
int img_start, next_img, padded_frame; int img_start, next_img, padded_frame;
unsigned int minor = MINOR(file->f_inode->i_rdev); unsigned int minor = MINOR(file->f_inode->i_rdev);
...@@ -486,7 +487,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -486,7 +487,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
struct interframe_params_t * fp; struct interframe_params_t * fp;
int fvld = -1; int fvld = -1;
int rp, bp; int rp, bp;
dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x\n",(int) offset, (int) orig); dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x, file->f_pos = 0x%llx\n",(int) offset, (int) orig, file->f_pos);
switch (orig) { switch (orig) {
case SEEK_SET: case SEEK_SET:
...@@ -642,14 +643,14 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -642,14 +643,14 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
break; break;
case LSEEK_CIRC_VALID: case LSEEK_CIRC_VALID:
// no actions to be done here, the pointer was checked on previous step // no actions to be done here, the pointer was checked on previous step
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_VALID: no action required\n", chn); dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_VALID: no action required, fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
break; break;
case LSEEK_CIRC_READY: case LSEEK_CIRC_READY:
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_READY: checking fvld, fvld = %d\n", chn, fvld); dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_READY: checking fvld, fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
if (fvld <= 0) return -EINVAL; // no frame is available better code? if (fvld <= 0) return -EINVAL; // no frame is available better code?
break; break;
case LSEEK_CIRC_WAIT: case LSEEK_CIRC_WAIT:
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_WAIT\n", chn); dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_WAIT: fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
while (((fvld=circbuf_valid_ptr(&file->f_pos, &fp, chn)))==0) { // only while not ready, ready or BAD - return while (((fvld=circbuf_valid_ptr(&file->f_pos, &fp, chn)))==0) { // only while not ready, ready or BAD - return
wait_event_interruptible(circbuf_wait_queue, (camseq_get_jpeg_wp(chn) << 2) != file->f_pos); wait_event_interruptible(circbuf_wait_queue, (camseq_get_jpeg_wp(chn) << 2) != file->f_pos);
} }
...@@ -660,6 +661,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig) ...@@ -660,6 +661,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f))); wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
} }
} }
dev_dbg(g_dev_ptr, "[chn %u] finish SEEK_END processing; return file->f_pos = %lld\n", chn, file->f_pos);
return ( file->f_pos ); // file position >= 0 return ( file->f_pos ); // file position >= 0
} }
break; break;
...@@ -727,8 +729,8 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t * ...@@ -727,8 +729,8 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *
long long res; long long res;
for (i = 0; i < IMAGE_CHN_NUM; i++) { for (i = 0; i < IMAGE_CHN_NUM; i++) {
cntr = get_zero_counter(i); cntr = get_zero_counter(i);
printk(KERN_DEBUG "channel = %d, hw pointer = 0x%x, zero_counter = %d, frame_counter = %lld\n", i, printk(KERN_DEBUG "channel = %d, hw pointer = 0x%x, zero_counter = %d, corrected_offset = %d, frame_counter = %lld\n",
DW2BYTE(camseq_get_jpeg_wp(i)), cntr, get_frame_counter(i)); i, DW2BYTE(camseq_get_jpeg_wp(i)), cntr, get_corrected_offset(i), get_frame_counter(i));
if (cntr != 0) { if (cntr != 0) {
for (j = 0; j < cntr; j++) { for (j = 0; j < cntr; j++) {
res = get_frame_pos(i, j); res = get_frame_pos(i, j);
......
...@@ -683,7 +683,7 @@ void jpeg_htable_fpga_pgm(unsigned int chn) ...@@ -683,7 +683,7 @@ void jpeg_htable_fpga_pgm(unsigned int chn)
table_addr.type = 3; table_addr.type = 3;
local_irq_save(flags); local_irq_save(flags);
x393_cmprs_tables_address(table_addr, chn); x393_cmprs_tables_address(table_addr, chn);
for (i = 0; i < sizeof(huff_tables->fpga_huffman_table); i++) { for (i = 0; i < sizeof(huff_tables->fpga_huffman_table) / sizeof(huff_tables->fpga_huffman_table[0]); i++) {
x393_cmprs_tables_data((u32)huff_tables->fpga_huffman_table[i], chn); x393_cmprs_tables_data((u32)huff_tables->fpga_huffman_table[i], chn);
} }
local_irq_restore(flags); local_irq_restore(flags);
......
...@@ -117,15 +117,18 @@ struct image_acq_pd_t { ...@@ -117,15 +117,18 @@ struct image_acq_pd_t {
struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM]; struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM];
}; };
/* debug code follows */ /* debug code follows */
// jpeg_hw_wp is equal to hardware pointer, jpeg_wp will lag from jpeg_hw_wp by one frame
static volatile int jpeg_hw_wp[IMAGE_CHN_NUM];
long long zero_counter[IMAGE_CHN_NUM] = {0}; long long zero_counter[IMAGE_CHN_NUM] = {0};
long long corrected_offset[IMAGE_CHN_NUM] = {0};
long long frame_counter[IMAGE_CHN_NUM] = {0}; long long frame_counter[IMAGE_CHN_NUM] = {0};
long long frame_pos[IMAGE_CHN_NUM][1000] = {0}; long long frame_pos[IMAGE_CHN_NUM][1000] = {0};
int get_zero_counter(unsigned int chn) long long get_zero_counter(unsigned int chn)
{ {
return zero_counter[chn]; return zero_counter[chn];
} }
long long get_corrected_offset(unsigned int chn)
{
return corrected_offset[chn];
}
long long get_frame_counter(unsigned int chn) long long get_frame_counter(unsigned int chn)
{ {
return frame_counter[chn]; return frame_counter[chn];
...@@ -256,11 +259,22 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr) ...@@ -256,11 +259,22 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
frame_counter[jptr->chn_num] += 1; frame_counter[jptr->chn_num] += 1;
if (jptr->jpeg_wp == 0) { if (jptr->jpeg_wp == 0) {
zero_counter[jptr->chn_num] += 1; zero_counter[jptr->chn_num] += 1;
if (zero_counter < 1000) if (zero_counter[jptr->chn_num] < 1000)
frame_pos[jptr->chn_num][zero_counter[jptr->chn_num]] = frame_counter[jptr->chn_num]; frame_pos[jptr->chn_num][zero_counter[jptr->chn_num] - 1] = frame_counter[jptr->chn_num];
} }
/* end of debug code */ /* end of debug code */
/* Looks like compressor is reporting HW pointer with offset when last frame ends precisely at the
* end of buffer and 32 zero bytes start from the beginning of the buffer. HW pointer in this case should
* be 0x20, but it is 0x00 in fact. Try to detect this situation and correct the offset.
*/
if (jptr->jpeg_wp == 0 &&
circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] == 0x00 &&
(circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp - 1] & MARKER_FF) == MARKER_FF) {
jptr->jpeg_wp += INTERFRAME_PARAMS_SZ;
corrected_offset[jptr->chn_num] += 1;
}
// invalidate CPU L1 and L2 caches // invalidate CPU L1 and L2 caches
// the code below was used to find cache coherence issues // the code below was used to find cache coherence issues
phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE; phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE;
...@@ -314,8 +328,8 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr) ...@@ -314,8 +328,8 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
dma_addr_t phys_addr; dma_addr_t phys_addr;
void *virt_addr; void *virt_addr;
struct interframe_params_t *interframe = NULL; struct interframe_params_t *interframe = NULL;
int len_offset = X393_BUFFSUB(jptr->jpeg_wp, INTERFRAME_PARAMS_SZ + 1); int len_offset = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp), CHUNK_SIZE + 4);
int jpeg_len = circbuf_priv_ptr[jptr->chn_num].buf_ptr[len_offset] & FRAME_LENGTH_MASK; int jpeg_len = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(len_offset)] & FRAME_LENGTH_MASK;
int jpeg_start = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE - INSERTED_BYTES(jpeg_len) - CCAM_MMAP_META, jpeg_len); int jpeg_start = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE - INSERTED_BYTES(jpeg_len) - CCAM_MMAP_META, jpeg_len);
// frame_params_offset points to interframe_params_t area before current frame (this parameters belong to the frame below in memory, not the previous) // frame_params_offset points to interframe_params_t area before current frame (this parameters belong to the frame below in memory, not the previous)
int frame_params_offset = BYTE2DW(X393_BUFFSUB(jpeg_start, CHUNK_SIZE)); int frame_params_offset = BYTE2DW(X393_BUFFSUB(jpeg_start, CHUNK_SIZE));
...@@ -339,7 +353,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr) ...@@ -339,7 +353,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
set_default_interframe(interframe); set_default_interframe(interframe);
/* end of debug code */ /* end of debug code */
set_globalParam(G_FRAME_SIZE, jpeg_len); // set_globalParam(G_FRAME_SIZE, jpeg_len);
// invalidate CPU L1 and L2 caches (in this order) // invalidate CPU L1 and L2 caches (in this order)
phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(frame_params_offset); phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(frame_params_offset);
...@@ -542,11 +556,6 @@ void tasklet_fpga_function(unsigned long arg) { ...@@ -542,11 +556,6 @@ void tasklet_fpga_function(unsigned long arg) {
unsigned long * hash32p=&(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]); unsigned long * hash32p=&(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]);
unsigned long * framep= &(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]); unsigned long * framep= &(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
int i, j;
int last_image_chunk;
int len32;
#ifdef TEST_DISABLE_CODE #ifdef TEST_DISABLE_CODE
/// Time is out? /// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
...@@ -652,7 +661,6 @@ GLOBALPARS(0x1044)=thisFrameNumber; ...@@ -652,7 +661,6 @@ GLOBALPARS(0x1044)=thisFrameNumber;
*/ */
void reset_compressor(unsigned int chn) void reset_compressor(unsigned int chn)
{ {
int i;
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
...@@ -666,9 +674,6 @@ void reset_compressor(unsigned int chn) ...@@ -666,9 +674,6 @@ void reset_compressor(unsigned int chn)
image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0; image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0;
image_acq_priv.jpeg_ptr[chn].fpga_cntr_prev = 0; image_acq_priv.jpeg_ptr[chn].fpga_cntr_prev = 0;
image_acq_priv.jpeg_ptr[chn].flags = 0; image_acq_priv.jpeg_ptr[chn].flags = 0;
/* debug code follows */
jpeg_hw_wp[chn] = 0;
/* debug code end */
//update_irq_circbuf(jptr); //update_irq_circbuf(jptr);
local_irq_restore(flags); local_irq_restore(flags);
} }
......
...@@ -57,7 +57,8 @@ int image_acq_init(struct platform_device *pdev); ...@@ -57,7 +57,8 @@ int image_acq_init(struct platform_device *pdev);
#define OFFSET_X40 0x40 #define OFFSET_X40 0x40
/* debug code follows */ /* debug code follows */
int get_zero_counter(unsigned int chn); long long get_zero_counter(unsigned int chn);
long long get_corrected_offset(unsigned int chn);
long long get_frame_counter(unsigned int chn); long long get_frame_counter(unsigned int chn);
long long get_frame_pos(unsigned int chn, unsigned int pos); long long get_frame_pos(unsigned int chn, unsigned int pos);
/* end of debug code */ /* end of debug code */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment