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
