Commit 1d6782bda5c1fb2bca44af50647b45427d8ef4ec
Committed by
Mauro Carvalho Chehab
1 parent
c9ff1b689a
Exists in
master
and in
39 other branches
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
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, ¶m); | |
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 | } |