Commit 382c5546 authored by Patrick Boettcher's avatar Patrick Boettcher Committed by Mauro Carvalho Chehab

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: default avatarUwe Bugla <uwe.bugla@gmx.de>
Signed-off-by: default avatarPatrick Boettcher <pb@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0ad675eb
...@@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d ...@@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
return 0; return 0;
} }
EXPORT_SYMBOL(flexcop_pid_feed_control);
void flexcop_hw_filter_init(struct flexcop_device *fc) void flexcop_hw_filter_init(struct flexcop_device *fc)
{ {
......
...@@ -13,9 +13,9 @@ static int enable_pid_filtering = 1; ...@@ -13,9 +13,9 @@ static int enable_pid_filtering = 1;
module_param(enable_pid_filtering, int, 0444); module_param(enable_pid_filtering, int, 0444);
MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); 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_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 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define dprintk(level,args...) \ #define dprintk(level,args...) \
...@@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus ...@@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus
static int debug; static int debug;
module_param(debug, int, 0644); 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_VERSION "0.1"
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
...@@ -58,6 +60,8 @@ struct flexcop_pci { ...@@ -58,6 +60,8 @@ struct flexcop_pci {
int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ 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 */ u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
int count; int count;
int count_prev;
int stream_problem;
spinlock_t irq_lock; spinlock_t irq_lock;
...@@ -103,18 +107,32 @@ static void flexcop_pci_irq_check_work(struct work_struct *work) ...@@ -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); container_of(work, struct flexcop_pci, irq_check_work.work);
struct flexcop_device *fc = fc_pci->fc_dev; 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_dump_reg(fc_pci->fc_dev,dma1_000,4); if (fc_pci->count == fc_pci->count_prev) {
deb_chk("no IRQ since the last check\n");
if (v.sram_dest_reg_714.net_ovflow_error) if (fc_pci->stream_problem++ == 3) {
deb_chk("sram net_ovflow_error\n"); struct dvb_demux_feed *feed;
if (v.sram_dest_reg_714.media_ovflow_error)
deb_chk("sram media_ovflow_error\n"); spin_lock_irq(&fc->demux.lock);
if (v.sram_dest_reg_714.cai_ovflow_error) list_for_each_entry(feed, &fc->demux.feed_list,
deb_chk("sram cai_ovflow_error\n"); list_head) {
if (v.sram_dest_reg_714.cai_ovflow_error) flexcop_pid_feed_control(fc, feed, 0);
deb_chk("sram cai_ovflow_error\n"); }
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, schedule_delayed_work(&fc_pci->irq_check_work,
msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); 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) ...@@ -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); flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
deb_irq("IRQ enabled\n"); deb_irq("IRQ enabled\n");
fc_pci->count_prev = fc_pci->count;
// fc_pci->active_dma1_addr = 0; // fc_pci->active_dma1_addr = 0;
// flexcop_dma_control_size_irq(fc,FC_DMA_1,1); // 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 { } else {
if (irq_chk_intv > 0)
cancel_delayed_work(&fc_pci->irq_check_work);
flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
deb_irq("IRQ disabled\n"); deb_irq("IRQ disabled\n");
...@@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) ...@@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
goto err_pci_iounmap; goto err_pci_iounmap;
fc_pci->init_state |= FC_PCI_INIT; fc_pci->init_state |= FC_PCI_INIT;
return ret; return ret;
...@@ -375,6 +387,10 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e ...@@ -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); 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; return ret;
err_fc_exit: err_fc_exit:
...@@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev) ...@@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
{ {
struct flexcop_pci *fc_pci = pci_get_drvdata(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_pci_dma_exit(fc_pci);
flexcop_device_exit(fc_pci->fc_dev); flexcop_device_exit(fc_pci->fc_dev);
flexcop_pci_exit(fc_pci); flexcop_pci_exit(fc_pci);
......
...@@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc) ...@@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
v210.sw_reset_210.Block_reset_enable = 0xb2; v210.sw_reset_210.Block_reset_enable = 0xb2;
fc->write_ibi_reg(fc,sw_reset_210,v210); fc->write_ibi_reg(fc,sw_reset_210,v210);
msleep(1); udelay(1000);
fc->write_ibi_reg(fc,ctrl_208,v208_save); fc->write_ibi_reg(fc,ctrl_208,v208_save);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment