Commit f7f5be40 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Use separate wait queue for each port in circbuf

Now each channel has its own instance of wait queue to prevent race
conditions when one channel wakes up the queue while the other channel
is processing interrupt and moved its write pointer, but has not
finished all other functions yet (i.e. filling interframe parameters).
parent 65b5b0e1
...@@ -50,8 +50,11 @@ ...@@ -50,8 +50,11 @@
/** @brief Driver name displayed in system logs */ /** @brief Driver name displayed in system logs */
//#define CIRCBUF_DRIVER_NAME "circbuf driver" //#define CIRCBUF_DRIVER_NAME "circbuf driver"
/** @brief Wait queue for the processes waiting for a new frame to appear in the circular buffer */ /** @brief Wait queue for the processes waiting for a new frame to appear in the circular buffer. Each channel has
wait_queue_head_t circbuf_wait_queue; * its own instance of wait queue to prevent race conditions when one channel wakes up the queue while the other
* channel is processing interrupt and moved its write pointer, but has not finished all other functions yet.
*/
wait_queue_head_t circbuf_wait_queue[SENSOR_PORTS];
struct circbuf_priv_t circbuf_priv[SENSOR_PORTS]; struct circbuf_priv_t circbuf_priv[SENSOR_PORTS];
struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv; struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv;
/** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */ /** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */
...@@ -690,13 +693,13 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) { ...@@ -690,13 +693,13 @@ loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
break; break;
case LSEEK_CIRC_WAIT: case LSEEK_CIRC_WAIT:
while (((fvld=circbufValidPointer(file->f_pos, &fp, chn)))==0) { //! only while not ready, ready or BAD - return while (((fvld=circbufValidPointer(file->f_pos, &fp, chn)))==0) { //! only while not ready, ready or BAD - return
wait_event_interruptible (circbuf_wait_queue,(camSeqGetJPEG_wp(chn)<<2)!=file->f_pos); wait_event_interruptible (circbuf_wait_queue[chn],(camSeqGetJPEG_wp(chn)<<2)!=file->f_pos);
} }
if (fvld < 0) return -ESPIPE; //!invalid seek - have better code? if (fvld < 0) return -ESPIPE; //!invalid seek - have better code?
return file->f_pos ; //! data already available, return file pointer return file->f_pos ; //! data already available, return file pointer
default: default:
if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) { if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
wait_event_interruptible (circbuf_wait_queue, get_imageParamsFrame(chn, P_DAEMON_EN, camSeqGetJPEG_frame(chn)) & (1<<(offset & 0x1f))); wait_event_interruptible (circbuf_wait_queue[chn], get_imageParamsFrame(chn, P_DAEMON_EN, camSeqGetJPEG_frame(chn)) & (1<<(offset & 0x1f)));
} }
} }
dev_dbg(g_dev_ptr, "return SEEK_END file->f_pos =0x%08llx\n",file->f_pos); dev_dbg(g_dev_ptr, "return SEEK_END file->f_pos =0x%08llx\n",file->f_pos);
...@@ -835,7 +838,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait) ...@@ -835,7 +838,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait)
return POLLIN | POLLRDNORM; // there was frame already available return POLLIN | POLLRDNORM; // there was frame already available
} else { } else {
// pointer valid, no frame yet // pointer valid, no frame yet
poll_wait(file, &circbuf_wait_queue, wait); poll_wait(file, &circbuf_wait_queue[chn], wait);
// Frame might become available during call to poll_wait so nobody will wake us up, // Frame might become available during call to poll_wait so nobody will wake us up,
// let's see if there is still no frame. // let's see if there is still no frame.
w_ptr = camseq_get_jpeg_wp(chn) << 2; w_ptr = camseq_get_jpeg_wp(chn) << 2;
...@@ -863,7 +866,7 @@ static struct file_operations circbuf_fops = { ...@@ -863,7 +866,7 @@ static struct file_operations circbuf_fops = {
*/ */
static int circbuf_all_init(struct platform_device *pdev) static int circbuf_all_init(struct platform_device *pdev)
{ {
int res; int res, i;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct of_device_id *match; const struct of_device_id *match;
...@@ -897,7 +900,8 @@ static int circbuf_all_init(struct platform_device *pdev) ...@@ -897,7 +900,8 @@ static int circbuf_all_init(struct platform_device *pdev)
} }
dev_dbg(dev, "initialize circbuf wait queue\n"); dev_dbg(dev, "initialize circbuf wait queue\n");
init_waitqueue_head(&circbuf_wait_queue); for (i = 0; i < SENSOR_PORTS; i++)
init_waitqueue_head(&circbuf_wait_queue[i]);
dev_dbg(dev, "initialize Huffman tables with default data\n"); dev_dbg(dev, "initialize Huffman tables with default data\n");
g_dev_ptr = dev; g_dev_ptr = dev;
......
...@@ -40,7 +40,7 @@ struct circbuf_priv_t { ...@@ -40,7 +40,7 @@ struct circbuf_priv_t {
}; };
struct circbuf_priv_t *get_circbuf(int chn); // alternative to use of extern struct circbuf_priv_ptr; struct circbuf_priv_t *get_circbuf(int chn); // alternative to use of extern struct circbuf_priv_ptr;
extern struct circbuf_priv_t *circbuf_priv_ptr; extern struct circbuf_priv_t *circbuf_priv_ptr;
extern wait_queue_head_t circbuf_wait_queue; extern wait_queue_head_t circbuf_wait_queue[SENSOR_PORTS];
int circbuf_all_open (struct inode *inode, struct file *filp); // set file size int circbuf_all_open (struct inode *inode, struct file *filp); // set file size
int circbuf_all_release(struct inode *inode, struct file *filp); int circbuf_all_release(struct inode *inode, struct file *filp);
......
...@@ -694,7 +694,7 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id) ...@@ -694,7 +694,7 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
* @brief Tasklet - software interrupt * @brief Tasklet - software interrupt
* lower priority tasks * lower priority tasks
* try to implement some balancing - if job is not finished - reduce FPS for it (alternate jobs)? * try to implement some balancing - if job is not finished - reduce FPS for it (alternate jobs)?
* @param arg not used * @param arg sensor port number
*/ */
void tasklet_compressor_function(unsigned long arg) void tasklet_compressor_function(unsigned long arg)
...@@ -724,7 +724,7 @@ void tasklet_compressor_function(unsigned long arg) ...@@ -724,7 +724,7 @@ void tasklet_compressor_function(unsigned long arg)
outer_inv_range(phys_addr_start, phys_addr_end); outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, sz - ccam_dma_size); __cpuc_flush_dcache_area(virt_addr_start, sz - ccam_dma_size);
} }
wake_up_interruptible(&circbuf_wait_queue); // should be done in here (after cache invalidation), not in ISR wake_up_interruptible(&circbuf_wait_queue[arg]); // should be done in here (after cache invalidation), not in ISR
} }
/*!TODO: /*!TODO:
......
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