V4L/DVB (10694): [PATCH] software IRQ watchdog for Flexcop B2C2 DVB PCI cards
authorPatrick Boettcher <pb@linuxtv.org>
Mon, 23 Feb 2009 09:27:16 +0000 (06:27 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 27 Feb 2009 01:29:18 +0000 (22:29 -0300)
With (some) Technisat cards you cannot run multiple DVB applications
in parallel and switch the channel at the same time.

There seems to be a problem on the interfaces or even inside the flexcop-device
that can't handle interruption on the streaming interface.

This patch adds a watchdog to check whether data is supposed to come in
(streaming PIDs are requested) and if no data is seen within 400ms (default) it
resets the streaming/pid-filtering hardware.

This patch is urgently needed to support the rev 2.8 of the hardware and solves
problem occassionally seen on older hardware.

Signed-off-by: Uwe Bugla <uwe.bugla@gmx.de>
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/b2c2/flexcop-hw-filter.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/b2c2/flexcop.c

index b386cc66c6b31e3b89a2b982e5ad8efede9fdead..451974ba32f37adb656356291146716c8358d819 100644 (file)
@@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
 
        return 0;
 }
+EXPORT_SYMBOL(flexcop_pid_feed_control);
 
 void flexcop_hw_filter_init(struct flexcop_device *fc)
 {
index 5b30dfc7846b2fbbe870efb38901e311c3bc2375..76e37fd96bb6a3995e1ec301b36d166f507e54d3 100644 (file)
@@ -13,9 +13,9 @@ static int enable_pid_filtering = 1;
 module_param(enable_pid_filtering, int, 0444);
 MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
 
-static int irq_chk_intv;
+static int irq_chk_intv = 100;
 module_param(irq_chk_intv, int, 0644);
-MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
 
 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
 #define dprintk(level,args...) \
@@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus
 
 static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug,
+       "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
+        DEBSTATUS);
 
 #define DRIVER_VERSION "0.1"
 #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
@@ -58,6 +60,8 @@ struct flexcop_pci {
        int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
        u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
        int count;
+       int count_prev;
+       int stream_problem;
 
        spinlock_t irq_lock;
 
@@ -103,18 +107,32 @@ static void flexcop_pci_irq_check_work(struct work_struct *work)
                container_of(work, struct flexcop_pci, irq_check_work.work);
        struct flexcop_device *fc = fc_pci->fc_dev;
 
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
-
-       flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
-
-       if (v.sram_dest_reg_714.net_ovflow_error)
-               deb_chk("sram net_ovflow_error\n");
-       if (v.sram_dest_reg_714.media_ovflow_error)
-               deb_chk("sram media_ovflow_error\n");
-       if (v.sram_dest_reg_714.cai_ovflow_error)
-               deb_chk("sram cai_ovflow_error\n");
-       if (v.sram_dest_reg_714.cai_ovflow_error)
-               deb_chk("sram cai_ovflow_error\n");
+       if (fc->feedcount) {
+
+               if (fc_pci->count == fc_pci->count_prev) {
+                       deb_chk("no IRQ since the last check\n");
+                       if (fc_pci->stream_problem++ == 3) {
+                               struct dvb_demux_feed *feed;
+
+                               spin_lock_irq(&fc->demux.lock);
+                               list_for_each_entry(feed, &fc->demux.feed_list,
+                                       list_head) {
+                                       flexcop_pid_feed_control(fc, feed, 0);
+                               }
+
+                               list_for_each_entry(feed, &fc->demux.feed_list,
+                                       list_head) {
+                                       flexcop_pid_feed_control(fc, feed, 1);
+                               }
+                               spin_unlock_irq(&fc->demux.lock);
+
+                               fc_pci->stream_problem = 0;
+                       }
+               } else {
+                       fc_pci->stream_problem = 0;
+                       fc_pci->count_prev = fc_pci->count;
+               }
+       }
 
        schedule_delayed_work(&fc_pci->irq_check_work,
                        msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
@@ -216,16 +234,12 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
                flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
                deb_irq("IRQ enabled\n");
 
+               fc_pci->count_prev = fc_pci->count;
+
 //             fc_pci->active_dma1_addr = 0;
 //             flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
 
-               if (irq_chk_intv > 0)
-                       schedule_delayed_work(&fc_pci->irq_check_work,
-                                       msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
        } else {
-               if (irq_chk_intv > 0)
-                       cancel_delayed_work(&fc_pci->irq_check_work);
-
                flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
                deb_irq("IRQ disabled\n");
 
@@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
                                        IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
                goto err_pci_iounmap;
 
-
-
        fc_pci->init_state |= FC_PCI_INIT;
        return ret;
 
@@ -375,6 +387,10 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
 
+               if (irq_chk_intv > 0)
+                       schedule_delayed_work(&fc_pci->irq_check_work,
+               msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+
        return ret;
 
 err_fc_exit:
@@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
 {
        struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
 
+       if (irq_chk_intv > 0)
+               cancel_delayed_work(&fc_pci->irq_check_work);
+
        flexcop_pci_dma_exit(fc_pci);
        flexcop_device_exit(fc_pci->fc_dev);
        flexcop_pci_exit(fc_pci);
index 676413a915b45c3302995dfe82d49d283843c625..91068952b502b753a349467c78927ae75ce8a670 100644 (file)
@@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
        v210.sw_reset_210.Block_reset_enable = 0xb2;
 
        fc->write_ibi_reg(fc,sw_reset_210,v210);
-       msleep(1);
-
+       udelay(1000);
        fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }