[linux-dvb] RFC - Flexcop Streaming watchdog (VDSB)

Patrick Boettcher patrick.boettcher at desy.de
Fri Jan 16 16:03:10 CET 2009


Hi lists,

For years there has been the Video Data Stream Borken-error with VDR and
Technisat cards: The error occured randomly and unfrequently. A 
work-around for that problem was to restart VDR and let the driver reset 
the pid-filtering and streaming interface.

In fact it turned out, that the problem is worse with setups not based on 
VDR and the "VDSB-error" could be really easily reproduced (I'm not sure 
if this applies to all generations on SkyStar2-card). I'm skipping the 
description of the problem here...

Attached you'll find a patch which works around the hardware bug which is 
causing VDSB-error without needing to reload the driver.

There a struct-work-watchdog looking at the number of irq-received while 
having PIDs active in the PID-filter. If no IRQs are received, the 
pid-filter-system is reset.

It seems to fix the problem and so far I've not seen any false positives 
(like resetting the pid-filter even though streaming is working fine).

Before asking to pull the patch I'd like to discuss an issue: my 
work-around is iterating over the pid-filter-list in the dvb_demux. I'm 
doing this in the struct-work-callback. In dvb_demux.c I see that this 
list is protected with a spinlock. When I now try to take the spinlock in 
the work-function I'll get a nice message saying, that I cannot do take a 
spinlock in a work-function.

What can I do? What is the proper way to protect access to this list? Is 
it needed at all?

thanks for you input in advance,
Patrick.

--
   Mail: patrick.boettcher at desy.de
   WWW:  http://www.wi-bw.tfh-wildau.de/~pboettch/
-------------- next part --------------
diff -r 7981bdd4e25a linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c
--- a/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c	Mon Jan 12 00:18:04 2009 +0000
+++ b/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c	Fri Jan 16 15:46:32 2009 +0100
@@ -179,7 +179,7 @@
 
 	/* if it was the first or last feed request change the stream-status */
 	if (fc->feedcount == onoff) {
-		flexcop_rcv_data_ctrl(fc,onoff);
+		flexcop_rcv_data_ctrl(fc, onoff);
 		if (fc->stream_control) /* device specific stream control */
 			fc->stream_control(fc,onoff);
 
@@ -192,6 +192,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(flexcop_pid_feed_control);
 
 void flexcop_hw_filter_init(struct flexcop_device *fc)
 {
diff -r 7981bdd4e25a linux/drivers/media/dvb/b2c2/flexcop-pci.c
--- a/linux/drivers/media/dvb/b2c2/flexcop-pci.c	Mon Jan 12 00:18:04 2009 +0000
+++ b/linux/drivers/media/dvb/b2c2/flexcop-pci.c	Fri Jan 16 15:46:32 2009 +0100
@@ -13,9 +13,9 @@
 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,7 @@
 
 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 +58,8 @@
 	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;
 
@@ -115,18 +117,47 @@
 #endif
 	struct flexcop_device *fc = fc_pci->fc_dev;
 
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+	if (fc->feedcount) {
+		flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
 
-	flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
+		//	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 0
+		deb_chk("net_ovflow_error: %d, media_ovflow_error: %d, cai_ovflow_error: %d, cao_ovflow_error: %d, sram_dma: %d, maximumfill: %d\n",
+				v.sram_dest_reg_714.net_ovflow_error,
+				v.sram_dest_reg_714.media_ovflow_error,
+				v.sram_dest_reg_714.cai_ovflow_error,
+				v.sram_dest_reg_714.cao_ovflow_error,
+				v.sram_dest_reg_714.ctrl_sramdma,
+				v.sram_dest_reg_714.ctrl_maximumfill);
+#endif
+
+		if (fc_pci->count == fc_pci->count_prev) {
+			deb_chk("no IRQ since the last time\n");
+			if (fc_pci->stream_problem++ == 3) {
+				struct dvb_demux_feed *feed;
+				int t = 0;
+
+				/* work-queue is atomic -> cannot
+				 * take the demux.lock here, but is it needed? XXX
+				 * spin_lock_irq(&fc->demux.lock); */
+				list_for_each_entry(feed, &fc->demux.feed_list, list_head) {
+					flexcop_pid_feed_control(fc, feed, 0);
+					t++;
+				}
+
+				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));
@@ -232,16 +263,12 @@
 		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");
 
@@ -315,8 +342,6 @@
 					IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
 		goto err_pci_iounmap;
 
-
-
 	fc_pci->init_state |= FC_PCI_INIT;
 	return ret;
 
@@ -395,6 +420,10 @@
 	INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
 #endif
 
+	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:
@@ -412,6 +441,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);


More information about the linux-dvb mailing list