diff options
author | Johannes Stezenbach <devnull@localhost> | 2004-12-26 02:16:13 +0000 |
---|---|---|
committer | Johannes Stezenbach <devnull@localhost> | 2004-12-26 02:16:13 +0000 |
commit | c23a8b2b1ed73f9e18510b1efe379b73bbcf63d5 (patch) | |
tree | c59703ab95783e65bc4bb5e101c7dc90aeb2d210 /linux/drivers/media/dvb/ttpci/av7110.c | |
parent | cee6d44aa9ebf486690fac0983365f9baeeb3606 (diff) | |
download | mediapointer-dvb-s2-c23a8b2b1ed73f9e18510b1efe379b73bbcf63d5.tar.gz mediapointer-dvb-s2-c23a8b2b1ed73f9e18510b1efe379b73bbcf63d5.tar.bz2 |
- clean up debi irq/tasklet handling to make it work on SMP
- misc. changes to av7110_send_fw_cmd() error handling done
along the way
Diffstat (limited to 'linux/drivers/media/dvb/ttpci/av7110.c')
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.c | 176 |
1 files changed, 96 insertions, 80 deletions
diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 524d18a8a..c459b57b7 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -350,27 +350,42 @@ static inline void print_time(char *s) #endif } +#define DEBI_READ 0 +#define DEBI_WRITE 1 +static inline void start_debi_dma(struct av7110 *av7110, int dir, + unsigned long addr, unsigned int len) +{ + dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__); + return; + } + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ + SAA7146_IER_ENABLE(av7110->dev, MASK_19); + if (len < 5) + len = 5; /* we want a real DEBI DMA */ + if (dir == DEBI_WRITE) + iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); + else + irdebi(av7110, DEBISWAB, addr, 0, len); +} + static void debiirq(unsigned long data) { struct av7110 *av7110 = (struct av7110 *) data; int type = av7110->debitype; int handle = (type >> 8) & 0x1f; - -// dprintk(4, "%p\n",av7110); + unsigned int xfer = 0; print_time("debi"); - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); + dprintk(4, "type 0x%04x\n", type); if (type == -1) { printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies, saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR)); - spin_lock(&av7110->debilock); - ARM_ClearMailBox(av7110); - ARM_ClearIrq(av7110); - spin_unlock(&av7110->debilock); - return; + goto debi_done; } av7110->debitype = -1; @@ -380,22 +395,16 @@ static void debiirq(unsigned long data) dvb_dmx_swfilter_packets(&av7110->demux, (const u8 *) av7110->debi_virt, av7110->debilen / 188); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_PES_RECORD: if (av7110->demux.recording) av7110_record_cb(&av7110->p2t[handle], (u8 *) av7110->debi_virt, av7110->debilen); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_IPMPE: case DATA_FSECTION: @@ -405,11 +414,8 @@ static void debiirq(unsigned long data) av7110->debilen, NULL, 0, av7110->handle2filter[handle], DMX_OK, av7110); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_CI_GET: { @@ -426,11 +432,8 @@ static void debiirq(unsigned long data) ci_get_data(&av7110->ci_rbuffer, av7110->debi_virt, av7110->debilen); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; } case DATA_COMMON_INTERFACE: @@ -450,37 +453,35 @@ static void debiirq(unsigned long data) printk("\n"); } #endif - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_DEBUG_MESSAGE: ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; printk("%s\n", (s8 *) av7110->debi_virt); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_CI_PUT: + dprintk(4, "debi DATA_CI_PUT\n"); case DATA_MPEG_PLAY: + dprintk(4, "debi DATA_MPEG_PLAY\n"); case DATA_BMP_LOAD: - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + dprintk(4, "debi DATA_BMP_LOAD\n"); + xfer = TX_BUFF; + break; default: break; } +debi_done: spin_lock(&av7110->debilock); + if (xfer) + iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); ARM_ClearMailBox(av7110); spin_unlock(&av7110->debilock); } +/* irq from av7110 firmware writing the mailbox register in the DPRAM */ static void gpioirq(unsigned long data) { struct av7110 *av7110 = (struct av7110 *) data; @@ -488,27 +489,29 @@ static void gpioirq(unsigned long data) int len; if (av7110->debitype != -1) + /* we shouldn't get any irq while a debi xfer is running */ printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies, saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR)); - spin_lock(&av7110->debilock); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__); + BUG(); /* maybe we should try resetting the debi? */ + } + spin_lock(&av7110->debilock); ARM_ClearIrq(av7110); - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); - + /* see what the av7110 wants */ av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); len = (av7110->debilen + 3) & ~3; -// dprintk(8, "GPIO0 irq %d %d\n", av7110->debitype, av7110->debilen); print_time("gpio"); + dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); -// dprintk(8, "GPIO0 irq %02x\n", av7110->debitype&0xff); switch (av7110->debitype & 0xff) { case DATA_TS_PLAY: @@ -580,16 +583,12 @@ static void gpioirq(unsigned long data) dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0); - wake_up(&cibuf->queue); iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - saa7146_wait_for_debi_done(av7110->dev, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - iwdebi(av7110, DEBISWAB, DPRAM_BASE + txbuf, 0, (len + 3) & ~3); + dprintk(8, "DMA: CI\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); spin_unlock(&av7110->debilock); + wake_up(&cibuf->queue); return; } @@ -621,22 +620,21 @@ static void gpioirq(unsigned long data) dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - saa7146_wait_for_debi_done(av7110->dev, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - - iwdebi(av7110, DEBISWAB, DPRAM_BASE + txbuf, 0, (len + 3) & ~3); + dprintk(8, "DMA: MPEG_PLAY\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); spin_unlock(&av7110->debilock); return; case DATA_BMP_LOAD: len = av7110->debilen; + dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); if (!len) { av7110->bmp_state = BMP_LOADED; iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); wake_up(&av7110->bmpq); + dprintk(8, "gpio DATA_BMP_LOAD done\n"); break; } if (len > av7110->bmplen) @@ -648,12 +646,8 @@ static void gpioirq(unsigned long data) memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); av7110->bmpp += len; av7110->bmplen -= len; - saa7146_wait_for_debi_done(av7110->dev, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len + 3) & ~3); + dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); spin_unlock(&av7110->debilock); return; @@ -670,22 +664,17 @@ static void gpioirq(unsigned long data) case DATA_TS_RECORD: case DATA_PES_RECORD: - saa7146_wait_for_debi_done(av7110->dev, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len); + dprintk(8, "DMA: TS_REC etc.\n"); + start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); spin_unlock(&av7110->debilock); return; case DATA_DEBUG_MESSAGE: - saa7146_wait_for_debi_done(av7110->dev, 0); if (!len || len > 0xff) { iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; } - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - irdebi(av7110, DEBISWAB, Reserved, 0, len); + start_debi_dma(av7110, DEBI_READ, Reserved, len); spin_unlock(&av7110->debilock); return; @@ -700,8 +689,8 @@ static void gpioirq(unsigned long data) av7110->debitype, av7110->debilen); break; } - ARM_ClearMailBox(av7110); av7110->debitype = -1; + ARM_ClearMailBox(av7110); spin_unlock(&av7110->debilock); } @@ -2156,11 +2145,38 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr) { struct av7110 *av7110 = dev->ext_priv; - if (*isr & MASK_19) + //print_time("av7110_irq"); + + /* Note: Don't try to handle the DEBI error irq (MASK_18), in + * intel mode the timeout is asserted all the time... + */ + + if (*isr & MASK_19) { + //printk("av7110_irq: DEBI\n"); + /* Note 1: The DEBI irq is level triggered: We must enable it + * only after we started a DMA xfer, and disable it here + * immediately, or it will be signalled all the time while + * DEBI is idle. + * Note 2: You would think that an irq which is masked is + * not signalled by the hardware. Not so for the SAA7146: + * An irq is signalled as long as the corresponding bit + * in the ISR is set, and disabling irqs just prevents the + * hardware from setting the ISR bit. This means a) that we + * must clear the ISR *after* disabling the irq (which is why + * we must do it here even though saa7146_core did it already), + * and b) that if we were to disable an edge triggered irq + * (like the gpio irqs sadly are) temporarily we would likely + * loose some. This sucks :-( + */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); tasklet_schedule(&av7110->debi_tasklet); + } - if (*isr & MASK_03) + if (*isr & MASK_03) { + //printk("av7110_irq: GPIO\n"); tasklet_schedule(&av7110->gpio_tasklet); + } } @@ -2211,7 +2227,7 @@ static struct saa7146_extension av7110_extension = { .attach = av7110_attach, .detach = av7110_detach, - .irq_mask = MASK_19|MASK_03, + .irq_mask = MASK_19 | MASK_03, .irq_func = av7110_irq, }; |