Commit 9de93068 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Fix pointer convertion error in jpeghead

WIP: hw pointer offset error is still there
parent 2fd99c36
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -184,8 +184,8 @@ loff_t circbuf_all_lseek(struct file *file, loff_t offset, int orig)
		return  circbuf_lseek(file, offset, orig);
		return  circbuf_lseek(file, offset, orig);
	case JPEGHEAD_MINOR:
	case JPEGHEAD_MINOR:
		if (orig == SEEK_END && offset > 0) {
		if (orig == SEEK_END && offset > 0) {
			rp = BYTE2DW(offset) & (~7); // convert to index to long, align to 32-bytes
			rp = BYTE2DW(X393_BUFFSUB(offset, CHUNK_SIZE)) & (~7); // convert to index to long, align to 32-bytes
			fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[X393_BUFFSUB(rp, 8)];
			fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[rp];
		}
		}
		return  jpeghead_lseek(file, offset, orig, fp);
		return  jpeghead_lseek(file, offset, orig, fp);
	case HUFFMAN_MINOR:
	case HUFFMAN_MINOR:
+39 −0
Original line number Original line Diff line number Diff line
@@ -310,6 +310,38 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute


    return count;
    return count;
}
}
static ssize_t flush_cpu_cache(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	const int buff_size = 0x1000000;
	const int buff_start_offset = 0x100000;
	unsigned int chn;
	int start_offset, end_offset;
	int num_items;
	dma_addr_t phys_addr_start, phys_addr_end;

	num_items = sscanf(buf, "%u:%d:%d", &chn, &start_offset, &end_offset);
	if (num_items == 3) {
		// invalidate L2 caches
		if (end_offset > start_offset) {
			// handle single buffer case
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);
		} else {
			// handle split buffer case when pointer rolls over the end
			// first, process the peace at the end of the buffer
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + ++chn * buff_size - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);

			// second, process the peace at the start of the buffer
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);
		}
	}
	return count;
}


static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
{
@@ -335,6 +367,11 @@ static ssize_t get_sync_for_cpu_bidir(struct device *dev, struct device_attribut
{
{
	return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n");
	return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n");
}
}
static ssize_t get_flush_cpu_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "Write command and address into this file to flush CPU caches. Format 'chn:start_offset:end_offset' where "
			"'chn' is sensor channel, 'start_offset' and 'end_offset' are start and end data offsets in circbuf\n");
}


static DEVICE_ATTR(buffer_address,        SYSFS_PERMISSIONS & SYSFS_READONLY,     get_paddr,                 NULL);
static DEVICE_ATTR(buffer_address,        SYSFS_PERMISSIONS & SYSFS_READONLY,     get_paddr,                 NULL);
static DEVICE_ATTR(buffer_pages,          SYSFS_PERMISSIONS & SYSFS_READONLY,     get_size,                  NULL);
static DEVICE_ATTR(buffer_pages,          SYSFS_PERMISSIONS & SYSFS_READONLY,     get_size,                  NULL);
@@ -351,6 +388,7 @@ static DEVICE_ATTR(sync_for_cpu_d2h, SYSFS_PERMISSIONS,
static DEVICE_ATTR(sync_for_device_d2h,   SYSFS_PERMISSIONS,                      get_sync_for_device_d2h,   sync_for_device_d2h);
static DEVICE_ATTR(sync_for_device_d2h,   SYSFS_PERMISSIONS,                      get_sync_for_device_d2h,   sync_for_device_d2h);
static DEVICE_ATTR(sync_for_cpu_bidir,    SYSFS_PERMISSIONS,                      get_sync_for_cpu_bidir,    sync_for_cpu_bidir);
static DEVICE_ATTR(sync_for_cpu_bidir,    SYSFS_PERMISSIONS,                      get_sync_for_cpu_bidir,    sync_for_cpu_bidir);
static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS,                      get_sync_for_device_bidir, sync_for_device_bidir);
static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS,                      get_sync_for_device_bidir, sync_for_device_bidir);
static DEVICE_ATTR(flush_cpu_cache,       SYSFS_PERMISSIONS,                      get_flush_cpu_cache,       flush_cpu_cache);


static struct attribute *root_dev_attrs[] = {
static struct attribute *root_dev_attrs[] = {
		&dev_attr_buffer_address.attr,
		&dev_attr_buffer_address.attr,
@@ -368,6 +406,7 @@ static struct attribute *root_dev_attrs[] = {
		&dev_attr_sync_for_device_d2h.attr,
		&dev_attr_sync_for_device_d2h.attr,
		&dev_attr_sync_for_cpu_bidir.attr,
		&dev_attr_sync_for_cpu_bidir.attr,
		&dev_attr_sync_for_device_bidir.attr,
		&dev_attr_sync_for_device_bidir.attr,
		&dev_attr_flush_cpu_cache.attr,
		NULL
		NULL
};
};


+26 −5
Original line number Original line Diff line number Diff line
@@ -244,6 +244,7 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
{
{
	phys_addr_t phys_addr;
	phys_addr_t phys_addr;
	void *virt_addr;
	void *virt_addr;
	int prev_dword;
	int xferred;                                           /// number of 32-byte chunks transferred since compressor was reset
	int xferred;                                           /// number of 32-byte chunks transferred since compressor was reset
	x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);
	x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);


@@ -268,12 +269,32 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
	 * end of buffer and 32 zero bytes start from the beginning of the buffer. HW pointer in this case should
	 * 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.
	 * be 0x20, but it is 0x00 in fact. Try to detect this situation and correct the offset.
	 */
	 */
	if (jptr->jpeg_wp == 0 &&
	if (jptr->jpeg_wp == 0) {
		circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] == 0x00 &&
		// if pointer is set incorrectly, then we need two invalidate two cache lines in order to
		(circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp - 1] & MARKER_FF) == MARKER_FF) {
		// estimate the situation correctly: one line after the pointer, which should be the line of
		// 32 zeros, and one line before the pointer, which should be the last line of the frame. If this is not done
		// then the data read from memory can be incorrect and error detection will give false result. Barrier is set to
		// prevent compiler from reordering operations.
		phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr;
		virt_addr = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
		dev_dbg(NULL, "from updateIRQJPEG_wp: phys_addr = 0x%x, virt_addr = 0x%p\n", phys_addr, virt_addr);
		outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
		__cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
		phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + CCAM_DMA_SIZE - CHUNK_SIZE;
		virt_addr = circbuf_priv_ptr[jptr->chn_num].buf_ptr + BYTE2DW(CCAM_DMA_SIZE - CHUNK_SIZE);
		outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
		__cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
		dev_dbg(NULL, "from updateIRQJPEG_wp: phys_addr = 0x%x, virt_addr = 0x%p\n", phys_addr, virt_addr);
		barrier();
		prev_dword = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp), 4);
		dev_dbg(NULL, "circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] = 0x%x\n", circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp]);
		dev_dbg(NULL, "circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)] = 0x%x\n", circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)]);
		if (circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] == 0x00 &&
		(circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)] & MARKER_FF) == MARKER_FF) {
			jptr->jpeg_wp += INTERFRAME_PARAMS_SZ;
			jptr->jpeg_wp += INTERFRAME_PARAMS_SZ;
			corrected_offset[jptr->chn_num] += 1;
			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