We have a periodic timer polling DMA RX data due to a silicon bug
in A0 stepping, which has been fixed in B0. So add a runtime check
to make sure the timer only be used for A0 stepping

This patch and the timer should both be removed after A0 platforms
phase out.

Signed-off-by: Feng Tang <[email protected]>
---
 drivers/serial/mfd.c |   33 ++++++++++++++++++++++++++-------
 1 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
index 5dff45c..9f6e477 100644
--- a/drivers/serial/mfd.c
+++ b/drivers/serial/mfd.c
@@ -41,6 +41,8 @@
 #include <linux/io.h>
 #include <linux/debugfs.h>
 
+#include <asm/processor.h>
+
 #define  MFD_HSU_A0_STEPPING   1
 
 #define HSU_DMA_BUF_SIZE       2048
@@ -100,6 +102,15 @@ struct hsu_port {
        struct dentry *debugfs;
 };
 
+/*
+ * The runtime check is used to check whether the current chip
+ * stepping is A0, if yes, enable the DMA RX timeout timer
+ */
+static inline int dmarx_need_timer(void)
+{
+       return (boot_cpu_data.x86_mask == 0);
+}
+
 static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
 {
        unsigned int val;
@@ -348,7 +359,8 @@ void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct 
hsu_dma_buffer *dbuf
                                         );
        chan_writel(rxc, HSU_CH_CR, 0x3);
 
-       mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
+       if (dmarx_need_timer())
+               mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
 }
 
 /* Protected by spin_lock_irqsave(port->lock) */
@@ -412,7 +424,9 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
                chan_writel(chan, HSU_CH_CR, 0x3);
                return;
        }
-       del_timer(&chan->rx_timer);
+
+       if (dmarx_need_timer())
+               del_timer(&chan->rx_timer);
 
        dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
                        dbuf->dma_size, DMA_FROM_DEVICE);
@@ -440,9 +454,11 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
        tty_flip_buffer_push(tty);
 
        chan_writel(chan, HSU_CH_CR, 0x3);
-       chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
-       add_timer(&chan->rx_timer);
 
+       if (dmarx_need_timer()) {
+               chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
+               add_timer(&chan->rx_timer);
+       }
 }
 
 static void serial_hsu_stop_rx(struct uart_port *port)
@@ -862,7 +878,8 @@ static void serial_hsu_shutdown(struct uart_port *port)
                container_of(port, struct uart_hsu_port, port);
        unsigned long flags;
 
-       del_timer_sync(&up->rxc->rx_timer);
+       if (dmarx_need_timer())
+               del_timer_sync(&up->rxc->rx_timer);
 
        /* Disable interrupts from this port */
        up->ier = 0;
@@ -1343,7 +1360,9 @@ static void hsu_dma_rx_timeout(unsigned long data)
        count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
 
        if (!count) {
-               mod_timer(&chan->rx_timer, jiffies + 
HSU_DMA_TIMEOUT_CHECK_FREQ);
+               if (dmarx_need_timer())
+                       mod_timer(&chan->rx_timer,
+                               jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
                goto exit;
        }
 
@@ -1415,7 +1434,7 @@ static void hsu_global_init(void)
                                i * HSU_DMA_CHANS_REG_LENGTH;
 
                /* Work around for RX */
-               if (dchan->dirt == DMA_FROM_DEVICE) {
+               if (dmarx_need_timer() && dchan->dirt == DMA_FROM_DEVICE) {
                        init_timer(&dchan->rx_timer);
                        dchan->rx_timer.function = hsu_dma_rx_timeout;
                        dchan->rx_timer.data = (unsigned long)dchan;
-- 
1.7.0.4

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to