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 | |
| 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>
| -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 | } |
