summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/ttpci/av7110.c
diff options
context:
space:
mode:
authorJohannes Stezenbach <devnull@localhost>2004-12-26 02:16:13 +0000
committerJohannes Stezenbach <devnull@localhost>2004-12-26 02:16:13 +0000
commitc23a8b2b1ed73f9e18510b1efe379b73bbcf63d5 (patch)
treec59703ab95783e65bc4bb5e101c7dc90aeb2d210 /linux/drivers/media/dvb/ttpci/av7110.c
parentcee6d44aa9ebf486690fac0983365f9baeeb3606 (diff)
downloadmediapointer-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.c176
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,
};