Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (10694): [PATCH] software IRQ watchdog for Flexcop B2C2 DVB PCI cards

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>

authored by

Patrick Boettcher and committed by
Mauro Carvalho Chehab
382c5546 0ad675eb

+42 -23
+1
drivers/media/dvb/b2c2/flexcop-hw-filter.c
··· 192 192 193 193 return 0; 194 194 } 195 + EXPORT_SYMBOL(flexcop_pid_feed_control); 195 196 196 197 void flexcop_hw_filter_init(struct flexcop_device *fc) 197 198 {
+40 -21
drivers/media/dvb/b2c2/flexcop-pci.c
··· 13 13 module_param(enable_pid_filtering, int, 0444); 14 14 MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); 15 15 16 - static int irq_chk_intv; 16 + static int irq_chk_intv = 100; 17 17 module_param(irq_chk_intv, int, 0644); 18 - MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging)."); 18 + MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); 19 19 20 20 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG 21 21 #define dprintk(level,args...) \ ··· 34 34 35 35 static int debug; 36 36 module_param(debug, int, 0644); 37 - MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS); 37 + MODULE_PARM_DESC(debug, 38 + "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." 39 + DEBSTATUS); 38 40 39 41 #define DRIVER_VERSION "0.1" 40 42 #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" ··· 60 58 int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ 61 59 u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ 62 60 int count; 61 + int count_prev; 62 + int stream_problem; 63 63 64 64 spinlock_t irq_lock; 65 65 ··· 107 103 container_of(work, struct flexcop_pci, irq_check_work.work); 108 104 struct flexcop_device *fc = fc_pci->fc_dev; 109 105 110 - flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); 106 + if (fc->feedcount) { 111 107 112 - flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4); 108 + if (fc_pci->count == fc_pci->count_prev) { 109 + deb_chk("no IRQ since the last check\n"); 110 + if (fc_pci->stream_problem++ == 3) { 111 + struct dvb_demux_feed *feed; 113 112 114 - if (v.sram_dest_reg_714.net_ovflow_error) 115 - deb_chk("sram net_ovflow_error\n"); 116 - if (v.sram_dest_reg_714.media_ovflow_error) 117 - deb_chk("sram media_ovflow_error\n"); 118 - if (v.sram_dest_reg_714.cai_ovflow_error) 119 - deb_chk("sram cai_ovflow_error\n"); 120 - if (v.sram_dest_reg_714.cai_ovflow_error) 121 - deb_chk("sram cai_ovflow_error\n"); 113 + spin_lock_irq(&fc->demux.lock); 114 + list_for_each_entry(feed, &fc->demux.feed_list, 115 + list_head) { 116 + flexcop_pid_feed_control(fc, feed, 0); 117 + } 118 + 119 + list_for_each_entry(feed, &fc->demux.feed_list, 120 + list_head) { 121 + flexcop_pid_feed_control(fc, feed, 1); 122 + } 123 + spin_unlock_irq(&fc->demux.lock); 124 + 125 + fc_pci->stream_problem = 0; 126 + } 127 + } else { 128 + fc_pci->stream_problem = 0; 129 + fc_pci->count_prev = fc_pci->count; 130 + } 131 + } 122 132 123 133 schedule_delayed_work(&fc_pci->irq_check_work, 124 134 msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); ··· 234 216 flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); 235 217 deb_irq("IRQ enabled\n"); 236 218 219 + fc_pci->count_prev = fc_pci->count; 220 + 237 221 // fc_pci->active_dma1_addr = 0; 238 222 // flexcop_dma_control_size_irq(fc,FC_DMA_1,1); 239 223 240 - if (irq_chk_intv > 0) 241 - schedule_delayed_work(&fc_pci->irq_check_work, 242 - msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); 243 224 } else { 244 - if (irq_chk_intv > 0) 245 - cancel_delayed_work(&fc_pci->irq_check_work); 246 - 247 225 flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); 248 226 deb_irq("IRQ disabled\n"); 249 227 ··· 312 298 if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, 313 299 IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) 314 300 goto err_pci_iounmap; 315 - 316 - 317 301 318 302 fc_pci->init_state |= FC_PCI_INIT; 319 303 return ret; ··· 387 375 388 376 INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); 389 377 378 + if (irq_chk_intv > 0) 379 + schedule_delayed_work(&fc_pci->irq_check_work, 380 + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); 381 + 390 382 return ret; 391 383 392 384 err_fc_exit: ··· 408 392 static void flexcop_pci_remove(struct pci_dev *pdev) 409 393 { 410 394 struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); 395 + 396 + if (irq_chk_intv > 0) 397 + cancel_delayed_work(&fc_pci->irq_check_work); 411 398 412 399 flexcop_pci_dma_exit(fc_pci); 413 400 flexcop_device_exit(fc_pci->fc_dev);
+1 -2
drivers/media/dvb/b2c2/flexcop.c
··· 212 212 v210.sw_reset_210.Block_reset_enable = 0xb2; 213 213 214 214 fc->write_ibi_reg(fc,sw_reset_210,v210); 215 - msleep(1); 216 - 215 + udelay(1000); 217 216 fc->write_ibi_reg(fc,ctrl_208,v208_save); 218 217 } 219 218