diff options
author | Andy Walls <awalls@radix.net> | 2008-11-04 22:49:14 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-11-11 05:11:33 -0500 |
commit | 1d6782bda5c1fb2bca44af50647b45427d8ef4ec (patch) | |
tree | 11cc68f4410ca4850ff3d874900f628ed9326064 /drivers/media/video | |
parent | c9ff1b689a5d605640f098afc37d6102ecef9876 (diff) |
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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 12 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 18 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.c | 23 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.h | 1 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-irq.c | 29 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-irq.h | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 14 |
7 files changed, 75 insertions, 26 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 2befa3819cdb..7874d9790a51 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -449,6 +449,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
449 | 449 | ||
450 | spin_lock_init(&cx->lock); | 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 | /* start counting open_id at 1 */ | 460 | /* start counting open_id at 1 */ |
453 | cx->open_id = 1; | 461 | cx->open_id = 1; |
454 | 462 | ||
@@ -831,6 +839,7 @@ free_map: | |||
831 | free_mem: | 839 | free_mem: |
832 | release_mem_region(cx->base_addr, CX18_MEM_SIZE); | 840 | release_mem_region(cx->base_addr, CX18_MEM_SIZE); |
833 | free_workqueue: | 841 | free_workqueue: |
842 | destroy_workqueue(cx->work_queue); | ||
834 | err: | 843 | err: |
835 | if (retval == 0) | 844 | if (retval == 0) |
836 | retval = -ENODEV; | 845 | retval = -ENODEV; |
@@ -931,6 +940,9 @@ static void cx18_remove(struct pci_dev *pci_dev) | |||
931 | 940 | ||
932 | cx18_halt_firmware(cx); | 941 | cx18_halt_firmware(cx); |
933 | 942 | ||
943 | flush_workqueue(cx->work_queue); | ||
944 | destroy_workqueue(cx->work_queue); | ||
945 | |||
934 | cx18_streams_cleanup(cx, 1); | 946 | cx18_streams_cleanup(cx, 1); |
935 | 947 | ||
936 | exit_cx18_i2c(cx); | 948 | exit_cx18_i2c(cx); |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index e721c01d2178..bbdd5f25041d 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -199,12 +199,15 @@ struct cx18_options { | |||
199 | #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ | 199 | #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ |
200 | 200 | ||
201 | /* per-cx18, i_flags */ | 201 | /* per-cx18, i_flags */ |
202 | #define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ | 202 | #define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ |
203 | #define CX18_F_I_EOS 4 /* End of encoder stream reached */ | 203 | #define CX18_F_I_EOS 4 /* End of encoder stream */ |
204 | #define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ | 204 | #define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ |
205 | #define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ | 205 | #define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ |
206 | #define CX18_F_I_INITED 21 /* set after first open */ | 206 | #define CX18_F_I_HAVE_WORK 15 /* there is work to be done */ |
207 | #define CX18_F_I_FAILED 22 /* set if first open failed */ | 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 | /* These are the VBI types as they appear in the embedded VBI private packets. */ | 212 | /* These are the VBI types as they appear in the embedded VBI private packets. */ |
210 | #define CX18_SLICED_TYPE_TELETEXT_B (1) | 213 | #define CX18_SLICED_TYPE_TELETEXT_B (1) |
@@ -431,6 +434,9 @@ struct cx18 { | |||
431 | /* when the current DMA is finished this queue is woken up */ | 434 | /* when the current DMA is finished this queue is woken up */ |
432 | wait_queue_head_t dma_waitq; | 435 | wait_queue_head_t dma_waitq; |
433 | 436 | ||
437 | struct workqueue_struct *work_queue; | ||
438 | struct work_struct work; | ||
439 | |||
434 | /* i2c */ | 440 | /* i2c */ |
435 | struct i2c_adapter i2c_adap[2]; | 441 | struct i2c_adapter i2c_adap[2]; |
436 | struct i2c_algo_bit_data i2c_algo[2]; | 442 | struct i2c_algo_bit_data i2c_algo[2]; |
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index afc694e7bdb2..4542e2e5e3d7 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "cx18-dvb.h" | 23 | #include "cx18-dvb.h" |
24 | #include "cx18-io.h" | 24 | #include "cx18-io.h" |
25 | #include "cx18-streams.h" | 25 | #include "cx18-streams.h" |
26 | #include "cx18-queue.h" | ||
27 | #include "cx18-scb.h" | ||
26 | #include "cx18-cards.h" | 28 | #include "cx18-cards.h" |
27 | #include "s5h1409.h" | 29 | #include "s5h1409.h" |
28 | #include "mxl5005s.h" | 30 | #include "mxl5005s.h" |
@@ -300,3 +302,24 @@ static int dvb_register(struct cx18_stream *stream) | |||
300 | 302 | ||
301 | return ret; | 303 | return ret; |
302 | } | 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 | } | ||
325 | } | ||
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h index bf8d8f6f5455..bbdcefc87f28 100644 --- a/drivers/media/video/cx18/cx18-dvb.h +++ b/drivers/media/video/cx18/cx18-dvb.h | |||
@@ -23,3 +23,4 @@ | |||
23 | 23 | ||
24 | int cx18_dvb_register(struct cx18_stream *stream); | 24 | int cx18_dvb_register(struct cx18_stream *stream); |
25 | void cx18_dvb_unregister(struct cx18_stream *stream); | 25 | void cx18_dvb_unregister(struct cx18_stream *stream); |
26 | void cx18_dvb_work_handler(struct cx18 *cx); | ||
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index c306e142c1c3..5fbfbd0f1493 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c | |||
@@ -29,6 +29,20 @@ | |||
29 | #include "cx18-mailbox.h" | 29 | #include "cx18-mailbox.h" |
30 | #include "cx18-vbi.h" | 30 | #include "cx18-vbi.h" |
31 | #include "cx18-scb.h" | 31 | #include "cx18-scb.h" |
32 | #include "cx18-dvb.h" | ||
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 | } | ||
32 | 46 | ||
33 | static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) | 47 | static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) |
34 | { | 48 | { |
@@ -65,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) | |||
65 | if (buf) { | 79 | if (buf) { |
66 | cx18_buf_sync_for_cpu(s, buf); | 80 | cx18_buf_sync_for_cpu(s, buf); |
67 | if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { | 81 | if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { |
68 | /* process the buffer here */ | 82 | CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", |
69 | CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", | ||
70 | buf->bytesused); | 83 | buf->bytesused); |
71 | 84 | ||
72 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, | 85 | set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags); |
73 | buf->bytesused); | 86 | set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags); |
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); | ||
79 | } else | 87 | } else |
80 | set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); | 88 | set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); |
81 | } else { | 89 | } else { |
@@ -185,5 +193,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) | |||
185 | if (sw1) | 193 | if (sw1) |
186 | epu_cmd(cx, sw1); | 194 | epu_cmd(cx, sw1); |
187 | 195 | ||
196 | if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags)) | ||
197 | queue_work(cx->work_queue, &cx->work); | ||
198 | |||
188 | return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; | 199 | return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; |
189 | } | 200 | } |
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h index 379f704f5cba..6173ca3bc9e4 100644 --- a/drivers/media/video/cx18/cx18-irq.h +++ b/drivers/media/video/cx18/cx18-irq.h | |||
@@ -32,6 +32,4 @@ | |||
32 | 32 | ||
33 | irqreturn_t cx18_irq_handler(int irq, void *dev_id); | 33 | irqreturn_t cx18_irq_handler(int irq, void *dev_id); |
34 | 34 | ||
35 | void cx18_irq_work_handler(struct work_struct *work); | 35 | void cx18_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); | ||
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index a33ba04a2686..174682c2582f 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, | |||
88 | 88 | ||
89 | if (buf->id != id) | 89 | if (buf->id != id) |
90 | continue; | 90 | continue; |
91 | |||
91 | buf->bytesused = bytesused; | 92 | buf->bytesused = bytesused; |
92 | /* the transport buffers are handled differently, | 93 | atomic_dec(&s->q_free.buffers); |
93 | they are not moved to the full queue */ | 94 | atomic_inc(&s->q_full.buffers); |
94 | if (s->type != CX18_ENC_STREAM_TYPE_TS) { | 95 | s->q_full.bytesused += buf->bytesused; |
95 | atomic_dec(&s->q_free.buffers); | 96 | list_move_tail(&buf->list, &s->q_full.list); |
96 | atomic_inc(&s->q_full.buffers); | 97 | |
97 | s->q_full.bytesused += buf->bytesused; | ||
98 | list_move_tail(&buf->list, &s->q_full.list); | ||
99 | } | ||
100 | spin_unlock(&s->qlock); | 98 | spin_unlock(&s->qlock); |
101 | return buf; | 99 | return buf; |
102 | } | 100 | } |