summaryrefslogtreecommitdiff
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
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
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.c176
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.h2
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110_hw.c38
3 files changed, 118 insertions, 98 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,
};
diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h
index 60ddf1281..019998055 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.h
+++ b/linux/drivers/media/dvb/ttpci/av7110.h
@@ -115,7 +115,7 @@ struct av7110 {
int bmpp;
int bmplen;
- int bmp_state;
+ volatile int bmp_state;
#define BMP_NONE 0
#define BMP_LOADING 1
#define BMP_LOADINGS 2
diff --git a/linux/drivers/media/dvb/ttpci/av7110_hw.c b/linux/drivers/media/dvb/ttpci/av7110_hw.c
index f5e753851..67a95df63 100644
--- a/linux/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/linux/drivers/media/dvb/ttpci/av7110_hw.c
@@ -336,7 +336,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (!av7110->arm_ready) {
dprintk(1, "arm not ready.\n");
- return -1;
+ return -ENXIO;
}
start = jiffies;
@@ -344,7 +344,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
msleep(1);
if (time_after(jiffies, start + ARM_WAIT_FREE)) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
- return -1;
+ return -ETIMEDOUT;
}
}
@@ -356,7 +356,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
msleep(1);
if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
- return -1;
+ return -ETIMEDOUT;
}
}
#endif
@@ -426,18 +426,18 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (time_after(jiffies, start + ARM_WAIT_FREE)) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
__FUNCTION__);
- return -1;
+ return -ETIMEDOUT;
}
}
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & GPMQOver) {
printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
- return -1;
+ return -ENOSPC;
}
else if (stat & OSDQOver) {
printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
- return -1;
+ return -ENOSPC;
}
#endif
@@ -460,7 +460,8 @@ int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
ret = __av7110_send_fw_cmd(av7110, buf, length);
up(&av7110->dcomlock);
if (ret)
- printk("dvb-ttpci: %s(): av7110_send_fw_cmd error\n", __FUNCTION__);
+ printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
+ __FUNCTION__, ret);
return ret;
}
@@ -484,7 +485,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
ret = av7110_send_fw_cmd(av7110, buf, num + 2);
if (ret)
- printk("dvb-ttpci: av7110_fw_cmd error\n");
+ printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
return ret;
}
@@ -506,7 +507,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
ret = av7110_send_fw_cmd(av7110, cmd, 18);
if (ret)
- printk("dvb-ttpci: av7110_send_ci_cmd error\n");
+ printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
return ret;
}
@@ -532,7 +533,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
up(&av7110->dcomlock);
- printk("dvb-ttpci: av7110_fw_request error\n");
+ printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
return err;
}
@@ -586,7 +587,7 @@ int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
int ret;
ret = av7110_fw_request(av7110, &tag, 0, buf, length);
if (ret)
- printk("dvb-ttpci: av7110_fw_query error\n");
+ printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
return ret;
}
@@ -633,7 +634,7 @@ int av7110_firmversion(struct av7110 *av7110)
int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
{
- int i;
+ int i, ret;
u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -653,8 +654,8 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
for (i = 0; i < len; i++)
buf[i + 4] = msg[i];
- if (av7110_send_fw_cmd(av7110, buf, 18))
- printk("dvb-ttpci: av7110_diseqc_send error\n");
+ if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
+ printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
return 0;
}
@@ -763,7 +764,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
up(&av7110->dcomlock);
if (ret)
- printk("dvb-ttpci: WriteText error\n");
+ printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
return ret;
}
@@ -830,7 +831,8 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__);
+ printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+ ret, av7110->bmp_state);
av7110->bmp_state = BMP_NONE;
return -1;
}
@@ -872,6 +874,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
}
}
av7110->bmplen += 1024;
+ dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
}
@@ -886,7 +889,8 @@ static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
ret = wait_event_interruptible_timeout(av7110->bmpq,
av7110->bmp_state != BMP_LOADING, 10*HZ);
if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__);
+ printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
+ ret, av7110->bmp_state);
av7110->bmp_state = BMP_NONE;
return (ret == 0) ? -ETIMEDOUT : ret;
}