aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/b2c2/flexcop-pci.c
diff options
context:
space:
mode:
authorPatrick Boettcher <pb@linuxtv.org>2005-07-07 20:57:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:56 -0400
commit64221be7b9006338e4a45228f013e467ee4bf045 (patch)
treeacf137799c31c966f6d8083aee39c27f331905ab /drivers/media/dvb/b2c2/flexcop-pci.c
parent2819639b5630cd26d399ee0481be9a752280cf4d (diff)
[PATCH] dvb: flexcop: woraround irq stop problem
The flexcop chip often stops generating interrupts after some hours of operation. Apparently this can be fixed by resetting register block 0x300 at each channel change (this is not detailed in the flexcop data books). This patch also restructures DMA handling and adds a bit of debug code for the irq problem in case it still happens for someone. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb/b2c2/flexcop-pci.c')
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c122
1 files changed, 87 insertions, 35 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index ed717c0073d5..a436d5584ea6 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -13,6 +13,10 @@ static int enable_pid_filtering = 1;
13module_param(enable_pid_filtering, int, 0444); 13module_param(enable_pid_filtering, int, 0444);
14MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); 14MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
15 15
16static int irq_chk_intv;
17module_param(irq_chk_intv, int, 0644);
18MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
19
16#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG 20#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
17#define dprintk(level,args...) \ 21#define dprintk(level,args...) \
18 do { if ((debug & level)) printk(args); } while (0) 22 do { if ((debug & level)) printk(args); } while (0)
@@ -26,6 +30,7 @@ MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported
26#define deb_reg(args...) dprintk(0x02,args) 30#define deb_reg(args...) dprintk(0x02,args)
27#define deb_ts(args...) dprintk(0x04,args) 31#define deb_ts(args...) dprintk(0x04,args)
28#define deb_irq(args...) dprintk(0x08,args) 32#define deb_irq(args...) dprintk(0x08,args)
33#define deb_chk(args...) dprintk(0x10,args)
29 34
30static int debug = 0; 35static int debug = 0;
31module_param(debug, int, 0644); 36module_param(debug, int, 0644);
@@ -56,6 +61,10 @@ struct flexcop_pci {
56 61
57 spinlock_t irq_lock; 62 spinlock_t irq_lock;
58 63
64 unsigned long last_irq;
65
66 struct work_struct irq_check_work;
67
59 struct flexcop_device *fc_dev; 68 struct flexcop_device *fc_dev;
60}; 69};
61 70
@@ -88,18 +97,55 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi
88 return 0; 97 return 0;
89} 98}
90 99
100static void flexcop_pci_irq_check_work(void *data)
101{
102 struct flexcop_pci *fc_pci = data;
103 struct flexcop_device *fc = fc_pci->fc_dev;
104
105 flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
106
107 flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
108
109 if (v.sram_dest_reg_714.net_ovflow_error)
110 deb_chk("sram net_ovflow_error\n");
111 if (v.sram_dest_reg_714.media_ovflow_error)
112 deb_chk("sram media_ovflow_error\n");
113 if (v.sram_dest_reg_714.cai_ovflow_error)
114 deb_chk("sram cai_ovflow_error\n");
115 if (v.sram_dest_reg_714.cai_ovflow_error)
116 deb_chk("sram cai_ovflow_error\n");
117
118 schedule_delayed_work(&fc_pci->irq_check_work,
119 msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
120}
121
91/* When PID filtering is turned on, we use the timer IRQ, because small amounts 122/* When PID filtering is turned on, we use the timer IRQ, because small amounts
92 * of data need to be passed to the user space instantly as well. When PID 123 * of data need to be passed to the user space instantly as well. When PID
93 * filtering is turned off, we use the page-change-IRQ */ 124 * filtering is turned off, we use the page-change-IRQ */
94static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) 125static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs)
95{ 126{
96 struct flexcop_pci *fc_pci = dev_id; 127 struct flexcop_pci *fc_pci = dev_id;
97 struct flexcop_device *fc = fc_pci->fc_dev; 128 struct flexcop_device *fc = fc_pci->fc_dev;
98 flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); 129 flexcop_ibi_value v;
99 irqreturn_t ret = IRQ_HANDLED; 130 irqreturn_t ret = IRQ_HANDLED;
100 131
101 spin_lock_irq(&fc_pci->irq_lock); 132 spin_lock_irq(&fc_pci->irq_lock);
102 133
134 v = fc->read_ibi_reg(fc,irq_20c);
135
136 /* errors */
137 if (v.irq_20c.Data_receiver_error)
138 deb_chk("data receiver error\n");
139 if (v.irq_20c.Continuity_error_flag)
140 deb_chk("Contunuity error flag is set\n");
141 if (v.irq_20c.LLC_SNAP_FLAG_set)
142 deb_chk("LLC_SNAP_FLAG_set is set\n");
143 if (v.irq_20c.Transport_Error)
144 deb_chk("Transport error\n");
145
146 if ((fc_pci->count % 1000) == 0)
147 deb_chk("%d valid irq took place so far\n",fc_pci->count);
148
103 if (v.irq_20c.DMA1_IRQ_Status == 1) { 149 if (v.irq_20c.DMA1_IRQ_Status == 1) {
104 if (fc_pci->active_dma1_addr == 0) 150 if (fc_pci->active_dma1_addr == 0)
105 flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); 151 flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
@@ -115,8 +161,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
115 fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; 161 fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
116 u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; 162 u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
117 163
118 deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", 164 deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
119 v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); 165 jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
166 fc_pci->last_irq = jiffies;
120 167
121 /* buffer end was reached, restarted from the beginning 168 /* buffer end was reached, restarted from the beginning
122 * pass the data from last_cur_pos to the buffer end to the demux 169 * pass the data from last_cur_pos to the buffer end to the demux
@@ -127,7 +174,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
127 fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, 174 fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
128 (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos); 175 (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
129 fc_pci->last_dma1_cur_pos = 0; 176 fc_pci->last_dma1_cur_pos = 0;
130 fc_pci->count = 0;
131 } 177 }
132 178
133 if (cur_pos > fc_pci->last_dma1_cur_pos) { 179 if (cur_pos > fc_pci->last_dma1_cur_pos) {
@@ -139,16 +185,14 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
139 deb_irq("\n"); 185 deb_irq("\n");
140 186
141 fc_pci->last_dma1_cur_pos = cur_pos; 187 fc_pci->last_dma1_cur_pos = cur_pos;
142 } else 188 fc_pci->count++;
189 } else {
190 deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
143 ret = IRQ_NONE; 191 ret = IRQ_NONE;
192 }
144 193
145 spin_unlock_irq(&fc_pci->irq_lock); 194 spin_unlock_irq(&fc_pci->irq_lock);
146 195
147/* packet count would be ideal for hw filtering, but it isn't working. Either
148 * the data book is wrong, or I'm unable to read it correctly */
149
150/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
151
152 return ret; 196 return ret;
153} 197}
154 198
@@ -156,30 +200,35 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
156{ 200{
157 struct flexcop_pci *fc_pci = fc->bus_specific; 201 struct flexcop_pci *fc_pci = fc->bus_specific;
158 if (onoff) { 202 if (onoff) {
159 flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); 203 flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
160 flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); 204 flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
161 flexcop_dma_config_timer(fc,FC_DMA_1,1);
162 205
163 if (fc_pci->fc_dev->pid_filtering) { 206 flexcop_dma_config_timer(fc,FC_DMA_1,0);
164 fc_pci->last_dma1_cur_pos = 0;
165 flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
166 } else {
167 fc_pci->active_dma1_addr = 0;
168 flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
169 }
170 207
171/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0); 208 flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
172 flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */ 209 deb_irq("DMA xfer enabled\n");
173 210
174 deb_irq("irqs enabled\n"); 211 fc_pci->last_dma1_cur_pos = 0;
212 flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
213 deb_irq("IRQ enabled\n");
214
215// fc_pci->active_dma1_addr = 0;
216// flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
217
218 if (irq_chk_intv > 0)
219 schedule_delayed_work(&fc_pci->irq_check_work,
220 msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
175 } else { 221 } else {
176 if (fc_pci->fc_dev->pid_filtering) 222 if (irq_chk_intv > 0)
177 flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); 223 cancel_delayed_work(&fc_pci->irq_check_work);
178 else 224
179 flexcop_dma_control_size_irq(fc,FC_DMA_1,0); 225 flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
226 deb_irq("IRQ disabled\n");
180 227
181// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0); 228// flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
182 deb_irq("irqs disabled\n"); 229
230 flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
231 deb_irq("DMA xfer disabled\n");
183 } 232 }
184 233
185 return 0; 234 return 0;
@@ -198,6 +247,7 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
198 flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); 247 flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
199 248
200 fc_pci->init_state |= FC_PCI_DMA_INIT; 249 fc_pci->init_state |= FC_PCI_DMA_INIT;
250
201 goto success; 251 goto success;
202dma1_free: 252dma1_free:
203 flexcop_dma_free(&fc_pci->dma[0]); 253 flexcop_dma_free(&fc_pci->dma[0]);
@@ -244,7 +294,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
244 294
245 pci_set_drvdata(fc_pci->pdev, fc_pci); 295 pci_set_drvdata(fc_pci->pdev, fc_pci);
246 296
247 if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq, 297 if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
248 SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) 298 SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
249 goto err_pci_iounmap; 299 goto err_pci_iounmap;
250 300
@@ -324,6 +374,8 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
324 if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) 374 if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
325 goto err_fc_exit; 375 goto err_fc_exit;
326 376
377 INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
378
327 goto success; 379 goto success;
328err_fc_exit: 380err_fc_exit:
329 flexcop_device_exit(fc); 381 flexcop_device_exit(fc);
@@ -350,17 +402,17 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
350 402
351static struct pci_device_id flexcop_pci_tbl[] = { 403static struct pci_device_id flexcop_pci_tbl[] = {
352 { PCI_DEVICE(0x13d0, 0x2103) }, 404 { PCI_DEVICE(0x13d0, 0x2103) },
353/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */ 405/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */
354 { }, 406 { },
355}; 407};
356 408
357MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); 409MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
358 410
359static struct pci_driver flexcop_pci_driver = { 411static struct pci_driver flexcop_pci_driver = {
360 .name = "Technisat/B2C2 FlexCop II/IIb/III PCI", 412 .name = "Technisat/B2C2 FlexCop II/IIb PCI",
361 .id_table = flexcop_pci_tbl, 413 .id_table = flexcop_pci_tbl,
362 .probe = flexcop_pci_probe, 414 .probe = flexcop_pci_probe,
363 .remove = flexcop_pci_remove, 415 .remove = flexcop_pci_remove,
364}; 416};
365 417
366static int __init flexcop_pci_module_init(void) 418static int __init flexcop_pci_module_init(void)