Commit 1d6782bd authored by Andy Walls's avatar Andy Walls Committed by Mauro Carvalho Chehab

V4L/DVB (9516): cx18: Move DVB buffer transfer handling from irq handler to work_queue

cx18: Move DVB buffer transfer handling from irq handler to work_queue thread.
In order to properly lock the epu2cpu mailbox for driver to CX23418 commands,
the DVB/TS buffer handling needs to be moved from the IRQ handler and IRQ
context to a work queue.  This work_queue implmentation is strikingly similar
to the ivtv implementation - for better or worse.
Signed-off-by: default avatarAndy Walls <awalls@radix.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c9ff1b68
...@@ -449,6 +449,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) ...@@ -449,6 +449,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
spin_lock_init(&cx->lock); spin_lock_init(&cx->lock);
cx->work_queue = create_singlethread_workqueue(cx->name);
if (cx->work_queue == NULL) {
CX18_ERR("Could not create work queue\n");
return -1;
}
INIT_WORK(&cx->work, cx18_work_handler);
/* start counting open_id at 1 */ /* start counting open_id at 1 */
cx->open_id = 1; cx->open_id = 1;
...@@ -831,6 +839,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, ...@@ -831,6 +839,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
free_mem: free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE); release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueue: free_workqueue:
destroy_workqueue(cx->work_queue);
err: err:
if (retval == 0) if (retval == 0)
retval = -ENODEV; retval = -ENODEV;
...@@ -931,6 +940,9 @@ static void cx18_remove(struct pci_dev *pci_dev) ...@@ -931,6 +940,9 @@ static void cx18_remove(struct pci_dev *pci_dev)
cx18_halt_firmware(cx); cx18_halt_firmware(cx);
flush_workqueue(cx->work_queue);
destroy_workqueue(cx->work_queue);
cx18_streams_cleanup(cx, 1); cx18_streams_cleanup(cx, 1);
exit_cx18_i2c(cx); exit_cx18_i2c(cx);
......
...@@ -199,12 +199,15 @@ struct cx18_options { ...@@ -199,12 +199,15 @@ struct cx18_options {
#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
/* per-cx18, i_flags */ /* per-cx18, i_flags */
#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ #define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */
#define CX18_F_I_EOS 4 /* End of encoder stream reached */ #define CX18_F_I_EOS 4 /* End of encoder stream */
#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ #define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */
#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ #define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
#define CX18_F_I_INITED 21 /* set after first open */ #define CX18_F_I_HAVE_WORK 15 /* there is work to be done */
#define CX18_F_I_FAILED 22 /* set if first open failed */ #define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */
#define CX18_F_I_INITED 21 /* set after first open */
#define CX18_F_I_FAILED 22 /* set if first open failed */
#define CX18_F_I_WORK_INITED 23 /* worker thread initialized */
/* These are the VBI types as they appear in the embedded VBI private packets. */ /* These are the VBI types as they appear in the embedded VBI private packets. */
#define CX18_SLICED_TYPE_TELETEXT_B (1) #define CX18_SLICED_TYPE_TELETEXT_B (1)
...@@ -431,6 +434,9 @@ struct cx18 { ...@@ -431,6 +434,9 @@ struct cx18 {
/* when the current DMA is finished this queue is woken up */ /* when the current DMA is finished this queue is woken up */
wait_queue_head_t dma_waitq; wait_queue_head_t dma_waitq;
struct workqueue_struct *work_queue;
struct work_struct work;
/* i2c */ /* i2c */
struct i2c_adapter i2c_adap[2]; struct i2c_adapter i2c_adap[2];
struct i2c_algo_bit_data i2c_algo[2]; struct i2c_algo_bit_data i2c_algo[2];
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "cx18-dvb.h" #include "cx18-dvb.h"
#include "cx18-io.h" #include "cx18-io.h"
#include "cx18-streams.h" #include "cx18-streams.h"
#include "cx18-queue.h"
#include "cx18-scb.h"
#include "cx18-cards.h" #include "cx18-cards.h"
#include "s5h1409.h" #include "s5h1409.h"
#include "mxl5005s.h" #include "mxl5005s.h"
...@@ -300,3 +302,24 @@ static int dvb_register(struct cx18_stream *stream) ...@@ -300,3 +302,24 @@ static int dvb_register(struct cx18_stream *stream)
return ret; return ret;
} }
void cx18_dvb_work_handler(struct cx18 *cx)
{
struct cx18_buffer *buf;
struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS];
while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) {
if (s->dvb.enabled)
dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
buf->bytesused);
cx18_enqueue(s, buf, &s->q_free);
cx18_buf_sync_for_device(s, buf);
if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */
continue;
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
(void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
1, buf->id, s->buf_size);
}
}
...@@ -23,3 +23,4 @@ ...@@ -23,3 +23,4 @@
int cx18_dvb_register(struct cx18_stream *stream); int cx18_dvb_register(struct cx18_stream *stream);
void cx18_dvb_unregister(struct cx18_stream *stream); void cx18_dvb_unregister(struct cx18_stream *stream);
void cx18_dvb_work_handler(struct cx18 *cx);
...@@ -29,6 +29,20 @@ ...@@ -29,6 +29,20 @@
#include "cx18-mailbox.h" #include "cx18-mailbox.h"
#include "cx18-vbi.h" #include "cx18-vbi.h"
#include "cx18-scb.h" #include "cx18-scb.h"
#include "cx18-dvb.h"
void cx18_work_handler(struct work_struct *work)
{
struct cx18 *cx = container_of(work, struct cx18, work);
if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) {
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
/* This thread must use the FIFO scheduler as it
* is realtime sensitive. */
sched_setscheduler(current, SCHED_FIFO, &param);
}
if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags))
cx18_dvb_work_handler(cx);
}
static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
{ {
...@@ -65,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) ...@@ -65,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
if (buf) { if (buf) {
cx18_buf_sync_for_cpu(s, buf); cx18_buf_sync_for_cpu(s, buf);
if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
/* process the buffer here */ CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
buf->bytesused); buf->bytesused);
dvb_dmx_swfilter(&s->dvb.demux, buf->buf, set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags);
buf->bytesused); set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags);
cx18_buf_sync_for_device(s, buf);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
(void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
1, buf->id, s->buf_size);
} else } else
set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
} else { } else {
...@@ -185,5 +193,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) ...@@ -185,5 +193,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
if (sw1) if (sw1)
epu_cmd(cx, sw1); epu_cmd(cx, sw1);
if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags))
queue_work(cx->work_queue, &cx->work);
return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE;
} }
...@@ -32,6 +32,4 @@ ...@@ -32,6 +32,4 @@
irqreturn_t cx18_irq_handler(int irq, void *dev_id); irqreturn_t cx18_irq_handler(int irq, void *dev_id);
void cx18_irq_work_handler(struct work_struct *work); void cx18_work_handler(struct work_struct *work);
void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
void cx18_unfinished_dma(unsigned long arg);
...@@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, ...@@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
if (buf->id != id) if (buf->id != id)
continue; continue;
buf->bytesused = bytesused; buf->bytesused = bytesused;
/* the transport buffers are handled differently, atomic_dec(&s->q_free.buffers);
they are not moved to the full queue */ atomic_inc(&s->q_full.buffers);
if (s->type != CX18_ENC_STREAM_TYPE_TS) { s->q_full.bytesused += buf->bytesused;
atomic_dec(&s->q_free.buffers); list_move_tail(&buf->list, &s->q_full.list);
atomic_inc(&s->q_full.buffers);
s->q_full.bytesused += buf->bytesused;
list_move_tail(&buf->list, &s->q_full.list);
}
spin_unlock(&s->qlock); spin_unlock(&s->qlock);
return buf; return buf;
} }
......
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