Commit 1d6782bda5c1fb2bca44af50647b45427d8ef4ec

Authored by Andy Walls
Committed by Mauro Carvalho Chehab
1 parent c9ff1b689a

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: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

Showing 7 changed files with 75 additions and 26 deletions Side-by-side Diff

drivers/media/video/cx18/cx18-driver.c
... ... @@ -449,6 +449,14 @@
449 449  
450 450 spin_lock_init(&cx->lock);
451 451  
  452 + cx->work_queue = create_singlethread_workqueue(cx->name);
  453 + if (cx->work_queue == NULL) {
  454 + CX18_ERR("Could not create work queue\n");
  455 + return -1;
  456 + }
  457 +
  458 + INIT_WORK(&cx->work, cx18_work_handler);
  459 +
452 460 /* start counting open_id at 1 */
453 461 cx->open_id = 1;
454 462  
... ... @@ -831,6 +839,7 @@
831 839 free_mem:
832 840 release_mem_region(cx->base_addr, CX18_MEM_SIZE);
833 841 free_workqueue:
  842 + destroy_workqueue(cx->work_queue);
834 843 err:
835 844 if (retval == 0)
836 845 retval = -ENODEV;
... ... @@ -930,6 +939,9 @@
930 939 cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
931 940  
932 941 cx18_halt_firmware(cx);
  942 +
  943 + flush_workqueue(cx->work_queue);
  944 + destroy_workqueue(cx->work_queue);
933 945  
934 946 cx18_streams_cleanup(cx, 1);
935 947  
drivers/media/video/cx18/cx18-driver.h
... ... @@ -199,12 +199,15 @@
199 199 #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
200 200  
201 201 /* per-cx18, i_flags */
202   -#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */
203   -#define CX18_F_I_EOS 4 /* End of encoder stream reached */
204   -#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */
205   -#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
206   -#define CX18_F_I_INITED 21 /* set after first open */
207   -#define CX18_F_I_FAILED 22 /* set if first open failed */
  202 +#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */
  203 +#define CX18_F_I_EOS 4 /* End of encoder stream */
  204 +#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */
  205 +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
  206 +#define CX18_F_I_HAVE_WORK 15 /* there is work to be done */
  207 +#define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */
  208 +#define CX18_F_I_INITED 21 /* set after first open */
  209 +#define CX18_F_I_FAILED 22 /* set if first open failed */
  210 +#define CX18_F_I_WORK_INITED 23 /* worker thread initialized */
208 211  
209 212 /* These are the VBI types as they appear in the embedded VBI private packets. */
210 213 #define CX18_SLICED_TYPE_TELETEXT_B (1)
... ... @@ -430,6 +433,9 @@
430 433 wait_queue_head_t cap_w;
431 434 /* when the current DMA is finished this queue is woken up */
432 435 wait_queue_head_t dma_waitq;
  436 +
  437 + struct workqueue_struct *work_queue;
  438 + struct work_struct work;
433 439  
434 440 /* i2c */
435 441 struct i2c_adapter i2c_adap[2];
drivers/media/video/cx18/cx18-dvb.c
... ... @@ -23,6 +23,8 @@
23 23 #include "cx18-dvb.h"
24 24 #include "cx18-io.h"
25 25 #include "cx18-streams.h"
  26 +#include "cx18-queue.h"
  27 +#include "cx18-scb.h"
26 28 #include "cx18-cards.h"
27 29 #include "s5h1409.h"
28 30 #include "mxl5005s.h"
... ... @@ -299,5 +301,26 @@
299 301 }
300 302  
301 303 return ret;
  304 +}
  305 +
  306 +void cx18_dvb_work_handler(struct cx18 *cx)
  307 +{
  308 + struct cx18_buffer *buf;
  309 + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS];
  310 +
  311 + while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) {
  312 + if (s->dvb.enabled)
  313 + dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
  314 + buf->bytesused);
  315 +
  316 + cx18_enqueue(s, buf, &s->q_free);
  317 + cx18_buf_sync_for_device(s, buf);
  318 + if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */
  319 + continue;
  320 +
  321 + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
  322 + (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
  323 + 1, buf->id, s->buf_size);
  324 + }
302 325 }
drivers/media/video/cx18/cx18-dvb.h
... ... @@ -23,4 +23,5 @@
23 23  
24 24 int cx18_dvb_register(struct cx18_stream *stream);
25 25 void cx18_dvb_unregister(struct cx18_stream *stream);
  26 +void cx18_dvb_work_handler(struct cx18 *cx);
drivers/media/video/cx18/cx18-irq.c
... ... @@ -29,7 +29,21 @@
29 29 #include "cx18-mailbox.h"
30 30 #include "cx18-vbi.h"
31 31 #include "cx18-scb.h"
  32 +#include "cx18-dvb.h"
32 33  
  34 +void cx18_work_handler(struct work_struct *work)
  35 +{
  36 + struct cx18 *cx = container_of(work, struct cx18, work);
  37 + if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) {
  38 + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
  39 + /* This thread must use the FIFO scheduler as it
  40 + * is realtime sensitive. */
  41 + sched_setscheduler(current, SCHED_FIFO, &param);
  42 + }
  43 + if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags))
  44 + cx18_dvb_work_handler(cx);
  45 +}
  46 +
33 47 static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
34 48 {
35 49 u32 handle = mb->args[0];
36 50  
... ... @@ -65,17 +79,11 @@
65 79 if (buf) {
66 80 cx18_buf_sync_for_cpu(s, buf);
67 81 if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
68   - /* process the buffer here */
69   - CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
  82 + CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
70 83 buf->bytesused);
71 84  
72   - dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
73   - buf->bytesused);
74   -
75   - cx18_buf_sync_for_device(s, buf);
76   - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
77   - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
78   - 1, buf->id, s->buf_size);
  85 + set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags);
  86 + set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags);
79 87 } else
80 88 set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
81 89 } else {
... ... @@ -184,6 +192,9 @@
184 192  
185 193 if (sw1)
186 194 epu_cmd(cx, sw1);
  195 +
  196 + if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags))
  197 + queue_work(cx->work_queue, &cx->work);
187 198  
188 199 return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE;
189 200 }
drivers/media/video/cx18/cx18-irq.h
... ... @@ -32,7 +32,5 @@
32 32  
33 33 irqreturn_t cx18_irq_handler(int irq, void *dev_id);
34 34  
35   -void cx18_irq_work_handler(struct work_struct *work);
36   -void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
37   -void cx18_unfinished_dma(unsigned long arg);
  35 +void cx18_work_handler(struct work_struct *work);
drivers/media/video/cx18/cx18-queue.c
... ... @@ -88,15 +88,13 @@
88 88  
89 89 if (buf->id != id)
90 90 continue;
  91 +
91 92 buf->bytesused = bytesused;
92   - /* the transport buffers are handled differently,
93   - they are not moved to the full queue */
94   - if (s->type != CX18_ENC_STREAM_TYPE_TS) {
95   - atomic_dec(&s->q_free.buffers);
96   - atomic_inc(&s->q_full.buffers);
97   - s->q_full.bytesused += buf->bytesused;
98   - list_move_tail(&buf->list, &s->q_full.list);
99   - }
  93 + atomic_dec(&s->q_free.buffers);
  94 + atomic_inc(&s->q_full.buffers);
  95 + s->q_full.bytesused += buf->bytesused;
  96 + list_move_tail(&buf->list, &s->q_full.list);
  97 +
100 98 spin_unlock(&s->qlock);
101 99 return buf;
102 100 }