aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-07-27 03:20:32 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 16:47:46 -0400
commit669b7a0938e759097c150400cd36bd49befaf5bb (patch)
treeb7244699ea1e8bf04c50dde2b9efeaf504f44bc6
parentd843fc6e9dc9bee7061b6833594860ea93ad98e1 (diff)
hsu: add a periodic timer to check dma rx channel
A general problem for uart rx dma channel is you never know when and how much data will be received, so usually preset it a DMA descriptor with a big size, and rely on DMA RX timeout IRQ to know there is some data in rx channel. For a RX data size of multiple of MOTSR, there will be no timeout IRQ issued, thus OS will never be notified about that. This is a work around for that, current timer frequency is 5 times per second, it should vary according to the baud rate When future silicon version fix the problem, this workaround need be removed Signed-off-by: Feng Tang <feng.tang@intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/serial/mfd.c50
1 files changed, 47 insertions, 3 deletions
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
index 300dcb134e07..ed2bf6b14a4a 100644
--- a/drivers/serial/mfd.c
+++ b/drivers/serial/mfd.c
@@ -64,6 +64,8 @@
64#define mfd_readl(obj, offset) readl(obj->reg + offset) 64#define mfd_readl(obj, offset) readl(obj->reg + offset)
65#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) 65#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
66 66
67#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10)
68
67struct hsu_dma_buffer { 69struct hsu_dma_buffer {
68 u8 *buf; 70 u8 *buf;
69 dma_addr_t dma_addr; 71 dma_addr_t dma_addr;
@@ -75,7 +77,8 @@ struct hsu_dma_chan {
75 u32 id; 77 u32 id;
76 u32 dirt; /* to or from device */ 78 u32 dirt; /* to or from device */
77 struct uart_hsu_port *uport; 79 struct uart_hsu_port *uport;
78 void __iomem *reg; 80 void __iomem *reg;
81 struct timer_list rx_timer; /* only needed by RX channel */
79}; 82};
80 83
81struct uart_hsu_port { 84struct uart_hsu_port {
@@ -377,6 +380,8 @@ void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf
377 | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ 380 | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
378 ); 381 );
379 chan_writel(rxc, HSU_CH_CR, 0x3); 382 chan_writel(rxc, HSU_CH_CR, 0x3);
383
384 mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
380} 385}
381 386
382/* Protected by spin_lock_irqsave(port->lock) */ 387/* Protected by spin_lock_irqsave(port->lock) */
@@ -437,8 +442,13 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
437 /* We can use 2 ways to calc the actual transfer len */ 442 /* We can use 2 ways to calc the actual transfer len */
438 count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; 443 count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
439 444
440 if (!count) 445 if (!count) {
446 /* restart the channel before we leave */
447 chan_writel(chan, HSU_CH_CR, 0x3);
441 return; 448 return;
449 }
450
451 del_timer(&chan->rx_timer);
442 452
443 dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, 453 dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
444 dbuf->dma_size, DMA_FROM_DEVICE); 454 dbuf->dma_size, DMA_FROM_DEVICE);
@@ -463,9 +473,12 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
463 | (0x1 << 16) 473 | (0x1 << 16)
464 | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ 474 | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
465 ); 475 );
476 tty_flip_buffer_push(tty);
477
466 chan_writel(chan, HSU_CH_CR, 0x3); 478 chan_writel(chan, HSU_CH_CR, 0x3);
479 chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ;
480 add_timer(&chan->rx_timer);
467 481
468 tty_flip_buffer_push(tty);
469} 482}
470 483
471static void serial_hsu_stop_rx(struct uart_port *port) 484static void serial_hsu_stop_rx(struct uart_port *port)
@@ -893,6 +906,8 @@ static void serial_hsu_shutdown(struct uart_port *port)
893 container_of(port, struct uart_hsu_port, port); 906 container_of(port, struct uart_hsu_port, port);
894 unsigned long flags; 907 unsigned long flags;
895 908
909 del_timer_sync(&up->rxc->rx_timer);
910
896 /* Disable interrupts from this port */ 911 /* Disable interrupts from this port */
897 up->ier = 0; 912 up->ier = 0;
898 serial_out(up, UART_IER, 0); 913 serial_out(up, UART_IER, 0);
@@ -1348,6 +1363,28 @@ err_disable:
1348 return ret; 1363 return ret;
1349} 1364}
1350 1365
1366static void hsu_dma_rx_timeout(unsigned long data)
1367{
1368 struct hsu_dma_chan *chan = (void *)data;
1369 struct uart_hsu_port *up = chan->uport;
1370 struct hsu_dma_buffer *dbuf = &up->rxbuf;
1371 int count = 0;
1372 unsigned long flags;
1373
1374 spin_lock_irqsave(&up->port.lock, flags);
1375
1376 count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
1377
1378 if (!count) {
1379 mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ);
1380 goto exit;
1381 }
1382
1383 hsu_dma_rx(up, 0);
1384exit:
1385 spin_unlock_irqrestore(&up->port.lock, flags);
1386}
1387
1351static void hsu_global_init(void) 1388static void hsu_global_init(void)
1352{ 1389{
1353 struct hsu_port *hsu; 1390 struct hsu_port *hsu;
@@ -1409,6 +1446,13 @@ static void hsu_global_init(void)
1409 dchan->uport = &hsu->port[i/2]; 1446 dchan->uport = &hsu->port[i/2];
1410 dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + 1447 dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
1411 i * HSU_DMA_CHANS_REG_LENGTH; 1448 i * HSU_DMA_CHANS_REG_LENGTH;
1449
1450 /* Work around for RX */
1451 if (dchan->dirt == DMA_FROM_DEVICE) {
1452 init_timer(&dchan->rx_timer);
1453 dchan->rx_timer.function = hsu_dma_rx_timeout;
1454 dchan->rx_timer.data = (unsigned long)dchan;
1455 }
1412 dchan++; 1456 dchan++;
1413 } 1457 }
1414 1458