V4L/DVB (9721): cx18: Change to singlethreaded global work queue thread for deferable...
authorAndy Walls <awalls@radix.net>
Sun, 16 Nov 2008 20:15:01 +0000 (17:15 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:38:08 +0000 (09:38 -0200)
Change to singlethreaded global work queue thread for deferable work,
instead of the kernel default multithreaded work queue.  This ensures
execution of deferable work is always in the proper order, so caputred buffers
don't get reordered.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-mailbox.c

index 434cc7fdee3673f7bcf94f0fbfd3dce2d52bcb09..752ca908ccb13761c2dadc0b15be2593518d555e 100644 (file)
@@ -56,6 +56,9 @@ struct cx18 *cx18_cards[CX18_MAX_CARDS];
 /* Protects cx18_cards_active */
 DEFINE_SPINLOCK(cx18_cards_lock);
 
+/* Queue for deferrable IRQ handling work for all cx18 cards in system */
+struct workqueue_struct *cx18_work_queue;
+
 /* add your revision and whatnot here */
 static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -920,6 +923,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
        return 0;
 }
 
+static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
+               cancel_work_sync(&cx->epu_work_order[i].work);
+}
+
 static void cx18_remove(struct pci_dev *pci_dev)
 {
        struct cx18 *cx = pci_get_drvdata(pci_dev);
@@ -937,7 +947,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        cx18_halt_firmware(cx);
 
-       flush_scheduled_work();
+       cx18_cancel_epu_work_orders(cx);
 
        cx18_streams_cleanup(cx, 1);
 
@@ -981,8 +991,17 @@ static int module_start(void)
                printk(KERN_INFO "cx18:   Debug value must be >= 0 and <= 511!\n");
        }
 
+       cx18_work_queue = create_singlethread_workqueue("cx18");
+       if (cx18_work_queue == NULL) {
+               printk(KERN_ERR
+                      "cx18:   Unable to create work hander thread\n");
+               return -ENOMEM;
+       }
+
        if (pci_register_driver(&cx18_pci_driver)) {
                printk(KERN_ERR "cx18:   Error detecting PCI card\n");
+               destroy_workqueue(cx18_work_queue);
+               cx18_work_queue = NULL;
                return -ENODEV;
        }
        printk(KERN_INFO "cx18:  End initialization\n");
@@ -995,11 +1014,15 @@ static void module_cleanup(void)
 
        pci_unregister_driver(&cx18_pci_driver);
 
+       destroy_workqueue(cx18_work_queue);
+       cx18_work_queue = NULL;
+
        for (i = 0; i < cx18_cards_active; i++) {
                if (cx18_cards[i] == NULL)
                        continue;
                kfree(cx18_cards[i]);
        }
+
 }
 
 module_init(module_start);
index 5ebf84b78ca808bd12924b66bfa55df53e0d9390..f8929eb72ad0345a756d158e40f68fe24e0266fc 100644 (file)
@@ -486,6 +486,7 @@ extern struct cx18 *cx18_cards[];
 extern int cx18_cards_active;
 extern int cx18_first_minor;
 extern spinlock_t cx18_cards_lock;
+extern struct workqueue_struct *cx18_work_queue;
 
 /*==============Prototypes==================*/
 
index 3d210d2ffdad540210f943def8ad5e509c2cfdc9..d49c7c27c18fefdaac69373070e34af962c6de63 100644 (file)
@@ -409,7 +409,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
         */
        submit = epu_cmd_irq(cx, order, stale);
        if (submit > 0) {
-               schedule_work(&order->work);
+               queue_work(cx18_work_queue, &order->work);
        }
 }