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 | |
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
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.c | 176 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.h | 2 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110_hw.c | 38 |
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; } |