Skip to content

Commit

Permalink
ivtv: use kthread_worker instead of workqueue
Browse files Browse the repository at this point in the history
Upcoming workqueue updates will no longer guarantee fixed workqueue to
worker kthread association, so giving RT priority to the irq worker
won't work.  Use kthread_worker which guarantees specific kthread
association instead.  This also makes setting the priority cleaner.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Andy Walls <awalls@md.metrocast.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: ivtv-devel@ivtvdriver.org
Cc: linux-media@vger.kernel.org
  • Loading branch information
htejun committed Jun 29, 2010
1 parent b56c0d8 commit 7bc4656
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 27 deletions.
26 changes: 16 additions & 10 deletions drivers/media/video/ivtv/ivtv-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ static void ivtv_process_options(struct ivtv *itv)
*/
static int __devinit ivtv_init_struct1(struct ivtv *itv)
{
struct sched_param param = { .sched_priority = 99 };

itv->base_addr = pci_resource_start(itv->pdev, 0);
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
Expand All @@ -706,13 +708,17 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);

itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name);
if (itv->irq_work_queues == NULL) {
IVTV_ERR("Could not create ivtv workqueue\n");
init_kthread_worker(&itv->irq_worker);
itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
itv->v4l2_dev.name);
if (IS_ERR(itv->irq_worker_task)) {
IVTV_ERR("Could not create ivtv task\n");
return -1;
}
/* must use the FIFO scheduler as it is realtime sensitive */
sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, &param);

INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler);
init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);

/* start counting open_id at 1 */
itv->open_id = 1;
Expand Down Expand Up @@ -996,7 +1002,7 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
/* PCI Device Setup */
retval = ivtv_setup_pci(itv, pdev, pci_id);
if (retval == -EIO)
goto free_workqueue;
goto free_worker;
if (retval == -ENXIO)
goto free_mem;

Expand Down Expand Up @@ -1208,8 +1214,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
free_workqueue:
destroy_workqueue(itv->irq_work_queues);
free_worker:
kthread_stop(itv->irq_worker_task);
err:
if (retval == 0)
retval = -ENODEV;
Expand Down Expand Up @@ -1353,9 +1359,9 @@ static void ivtv_remove(struct pci_dev *pdev)
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);

/* Stop all Work Queues */
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
/* Kill irq worker */
flush_kthread_worker(&itv->irq_worker);
kthread_stop(itv->irq_worker_task);

ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
Expand Down
8 changes: 4 additions & 4 deletions drivers/media/video/ivtv/ivtv-driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
#include <linux/unistd.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
Expand Down Expand Up @@ -257,7 +257,6 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
#define IVTV_F_I_INITED 21 /* set after first open */
#define IVTV_F_I_FAILED 22 /* set if first open failed */
#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */

/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
Expand Down Expand Up @@ -663,8 +662,9 @@ struct ivtv {
/* Interrupts & DMA */
u32 irqmask; /* active interrupts */
u32 irq_rr_idx; /* round-robin stream index */
struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */
struct work_struct irq_work_queue; /* work entry */
struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */
struct task_struct *irq_worker_task; /* task for irq_worker */
struct kthread_work irq_work; /* kthread work entry */
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */
int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */
Expand Down
15 changes: 3 additions & 12 deletions drivers/media/video/ivtv/ivtv-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,10 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}

void ivtv_irq_work_handler(struct work_struct *work)
void ivtv_irq_work_handler(struct kthread_work *work)
{
struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue);
struct ivtv *itv = container_of(work, struct ivtv, irq_work);

DEFINE_WAIT(wait);

if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
struct sched_param param = { .sched_priority = 99 };

/* This thread must use the FIFO scheduler as it
is realtime sensitive. */
sched_setscheduler(current, SCHED_FIFO, &param);
}
if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
ivtv_pio_work_handler(itv);

Expand Down Expand Up @@ -975,7 +966,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}

if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
queue_work(itv->irq_work_queues, &itv->irq_work_queue);
queue_kthread_work(&itv->irq_worker, &itv->irq_work);
}

spin_unlock(&itv->dma_reg_lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/media/video/ivtv/ivtv-irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

irqreturn_t ivtv_irq_handler(int irq, void *dev_id);

void ivtv_irq_work_handler(struct work_struct *work);
void ivtv_irq_work_handler(struct kthread_work *work);
void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
void ivtv_unfinished_dma(unsigned long arg);

Expand Down

0 comments on commit 7bc4656

Please sign in to comment.