Skip to content

Commit

Permalink
[PATCH] dvb: flexcop: woraround irq stop problem
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick Boettcher authored and Linus Torvalds committed Jul 8, 2005
1 parent 2819639 commit 64221be
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 96 deletions.
6 changes: 5 additions & 1 deletion drivers/media/dvb/b2c2/flexcop-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,17 @@ void flexcop_device_kfree(struct flexcop_device*);
int flexcop_device_initialize(struct flexcop_device*);
void flexcop_device_exit(struct flexcop_device *fc);

void flexcop_reset_block_300(struct flexcop_device *fc);

/* from flexcop-dma.c */
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
void flexcop_dma_free(struct flexcop_dma *dma);

int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);

Expand Down Expand Up @@ -151,6 +154,7 @@ int flexcop_sram_init(struct flexcop_device *fc);
/* from flexcop-misc.c */
void flexcop_determine_revision(struct flexcop_device *fc);
void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);

/* from flexcop-hw-filter.c */
int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
Expand Down
165 changes: 111 additions & 54 deletions drivers/media/dvb/b2c2/flexcop-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma)
}
EXPORT_SYMBOL(flexcop_dma_free);

int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
int flexcop_dma_config(struct flexcop_device *fc,
struct flexcop_dma *dma,
flexcop_dma_index_t dma_idx)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
flexcop_ibi_value v0x0,v0x4,v0xc;
v0x0.raw = v0x4.raw = v0xc.raw = 0;

if (no & FC_DMA_1)
v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;

if (no & FC_DMA_2)
v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
if ((dma_idx & FC_DMA_1) == dma_idx) {
fc->write_ibi_reg(fc,dma1_000,v0x0);
fc->write_ibi_reg(fc,dma1_004,v0x4);
fc->write_ibi_reg(fc,dma1_00c,v0xc);
} else if ((dma_idx & FC_DMA_2) == dma_idx) {
fc->write_ibi_reg(fc,dma2_010,v0x0);
fc->write_ibi_reg(fc,dma2_014,v0x4);
fc->write_ibi_reg(fc,dma2_01c,v0xc);
} else {
err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
return -EINVAL;
}

fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
EXPORT_SYMBOL(flexcop_dma_config);

/* start the DMA transfers, but not the DMA IRQs */
int flexcop_dma_xfer_control(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx,
flexcop_dma_addr_index_t index,
int onoff)
{
flexcop_ibi_value v0x0,v0xc;
flexcop_ibi_register r0x0,r0xc;

if ((dma_idx & FC_DMA_1) == dma_idx) {
r0x0 = dma1_000;
r0xc = dma1_00c;
} else if ((dma_idx & FC_DMA_2) == dma_idx) {
r0x0 = dma2_010;
r0xc = dma2_01c;
} else {
err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
return -EINVAL;
}

v0x0 = fc->read_ibi_reg(fc,r0x0);
v0xc = fc->read_ibi_reg(fc,r0xc);

deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);

if (index & FC_DMA_SUBADDR_0)
v0x0.dma_0x0.dma_0start = onoff;

if (index & FC_DMA_SUBADDR_1)
v0xc.dma_0xc.dma_1start = onoff;

fc->write_ibi_reg(fc,r0x0,v0x0);
fc->write_ibi_reg(fc,r0xc,v0xc);

deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
return 0;
}
EXPORT_SYMBOL(flexcop_dma_xfer_control);

static int flexcop_dma_remap(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx,
int onoff)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
deb_info("%s\n",__FUNCTION__);
v.dma_0xc.remap_enable = onoff;
fc->write_ibi_reg(fc,r,v);
return 0;
}

int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
int flexcop_dma_control_size_irq(struct flexcop_device *fc,
flexcop_dma_index_t no,
int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);

Expand All @@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t
}
EXPORT_SYMBOL(flexcop_dma_control_size_irq);

int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
flexcop_dma_index_t no,
int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);

if (no & FC_DMA_1)
v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
v.ctrl_208.DMA1_Timer_Enable_sig = onoff;

if (no & FC_DMA_2)
v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
v.ctrl_208.DMA2_Timer_Enable_sig = onoff;

fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
EXPORT_SYMBOL(flexcop_dma_control_timer_irq);

int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
/* 1 cycles = 1.97 msec */
int flexcop_dma_config_timer(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx,
u8 cycles)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);

flexcop_ibi_value v0x0,v0x4,v0xc;
v0x0.raw = v0x4.raw = v0xc.raw = 0;

v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;

if (index & FC_DMA_SUBADDR_0)
v0x0.dma_0x0.dma_0start = 1;

if (index & FC_DMA_SUBADDR_1)
v0xc.dma_0xc.dma_1start = 1;

if (dma_idx & FC_DMA_1) {
fc->write_ibi_reg(fc,dma1_000,v0x0);
fc->write_ibi_reg(fc,dma1_004,v0x4);
fc->write_ibi_reg(fc,dma1_00c,v0xc);
} else { /* (dma_idx & FC_DMA_2) */
fc->write_ibi_reg(fc,dma2_010,v0x0);
fc->write_ibi_reg(fc,dma2_014,v0x4);
fc->write_ibi_reg(fc,dma2_01c,v0xc);
}

return 0;
}
EXPORT_SYMBOL(flexcop_dma_config);
flexcop_dma_remap(fc,dma_idx,0);

static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
v.dma_0xc.remap_enable = onoff;
deb_info("%s\n",__FUNCTION__);
v.dma_0x4_write.dmatimer = cycles;
fc->write_ibi_reg(fc,r,v);
return 0;
}
EXPORT_SYMBOL(flexcop_dma_config_timer);

/* 1 cycles = 1.97 msec */
int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */
int flexcop_dma_control_packet_irq(struct flexcop_device *fc,
flexcop_dma_index_t no,
int onoff)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);

flexcop_dma_remap(fc,dma_idx,0);
deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
if (no & FC_DMA_1)
v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;

if (no & FC_DMA_2)
v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;

fc->write_ibi_reg(fc,ctrl_208,v);
deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);

v.dma_0x4_write.dmatimer = cycles >> 1;
fc->write_ibi_reg(fc,r,v);
return 0;
}
EXPORT_SYMBOL(flexcop_dma_config_timer);
EXPORT_SYMBOL(flexcop_dma_control_packet_irq);

int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
int flexcop_dma_config_packet_count(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx,
u8 packets)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
Expand Down
12 changes: 10 additions & 2 deletions drivers/media/dvb/b2c2/flexcop-hw-filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);

deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
}

void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
Expand Down Expand Up @@ -151,7 +153,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
{
int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;

fc->feedcount += onoff ? 1 : -1;
fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
if (dvbdmxfeed->index >= max_pid_filter)
fc->extra_feedcount += onoff ? 1 : -1;

Expand All @@ -178,8 +180,14 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
/* if it was the first or last feed request change the stream-status */
if (fc->feedcount == onoff) {
flexcop_rcv_data_ctrl(fc,onoff);
if (fc->stream_control)
if (fc->stream_control) /* device specific stream control */
fc->stream_control(fc,onoff);

/* feeding stopped -> reset the flexcop filter*/
if (onoff == 0) {
flexcop_reset_block_300(fc);
flexcop_hw_filter_init(fc);
}
}

return 0;
Expand Down
12 changes: 12 additions & 0 deletions drivers/media/dvb/b2c2/flexcop-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,15 @@ void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
flexcop_revision_names[fc->rev],suffix);
}

void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
{
flexcop_ibi_value v;
int i;
for (i = 0; i < num; i++) {
v = fc->read_ibi_reg(fc,reg+4*i);
deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
}
deb_rdump("\n");
}
EXPORT_SYMBOL(flexcop_dump_reg);
Loading

0 comments on commit 64221be

Please sign in to comment.