aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2007-07-31 03:37:35 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-31 18:39:37 -0400
commitbb029c67e430e9ae96476ce7233468c11627c1db (patch)
treed792805dcca0b6da7b3f0a7e0a7ac93ab236b97a /drivers/char
parentddb437b7f74de775ff50ef51a8b2970564d56f86 (diff)
synclink_gt: fix transmit DMA stall
Fix transmit DMA stall when write() called in window after previous transmit DMA completes but before previous serial transmission completes. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/synclink_gt.c75
1 files changed, 46 insertions, 29 deletions
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 372a37e25620..bbb7f1292665 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $ 2 * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $
3 * 3 *
4 * Device driver for Microgate SyncLink GT serial adapters. 4 * Device driver for Microgate SyncLink GT serial adapters.
5 * 5 *
@@ -93,7 +93,7 @@
93 * module identification 93 * module identification
94 */ 94 */
95static char *driver_name = "SyncLink GT"; 95static char *driver_name = "SyncLink GT";
96static char *driver_version = "$Revision: 4.36 $"; 96static char *driver_version = "$Revision: 4.50 $";
97static char *tty_driver_name = "synclink_gt"; 97static char *tty_driver_name = "synclink_gt";
98static char *tty_dev_prefix = "ttySLG"; 98static char *tty_dev_prefix = "ttySLG";
99MODULE_LICENSE("GPL"); 99MODULE_LICENSE("GPL");
@@ -477,6 +477,7 @@ static void tx_set_idle(struct slgt_info *info);
477static unsigned int free_tbuf_count(struct slgt_info *info); 477static unsigned int free_tbuf_count(struct slgt_info *info);
478static void reset_tbufs(struct slgt_info *info); 478static void reset_tbufs(struct slgt_info *info);
479static void tdma_reset(struct slgt_info *info); 479static void tdma_reset(struct slgt_info *info);
480static void tdma_start(struct slgt_info *info);
480static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); 481static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
481 482
482static void get_signals(struct slgt_info *info); 483static void get_signals(struct slgt_info *info);
@@ -904,6 +905,8 @@ start:
904 spin_lock_irqsave(&info->lock,flags); 905 spin_lock_irqsave(&info->lock,flags);
905 if (!info->tx_active) 906 if (!info->tx_active)
906 tx_start(info); 907 tx_start(info);
908 else
909 tdma_start(info);
907 spin_unlock_irqrestore(&info->lock,flags); 910 spin_unlock_irqrestore(&info->lock,flags);
908 } 911 }
909 912
@@ -3871,44 +3874,58 @@ static void tx_start(struct slgt_info *info)
3871 slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); 3874 slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
3872 /* clear tx idle and underrun status bits */ 3875 /* clear tx idle and underrun status bits */
3873 wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); 3876 wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
3874
3875 if (!(rd_reg32(info, TDCSR) & BIT0)) {
3876 /* tx DMA stopped, restart tx DMA */
3877 tdma_reset(info);
3878 /* set 1st descriptor address */
3879 wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
3880 switch(info->params.mode) {
3881 case MGSL_MODE_RAW:
3882 case MGSL_MODE_MONOSYNC:
3883 case MGSL_MODE_BISYNC:
3884 wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
3885 break;
3886 default:
3887 wr_reg32(info, TDCSR, BIT0); /* DMA enable */
3888 }
3889 }
3890
3891 if (info->params.mode == MGSL_MODE_HDLC) 3877 if (info->params.mode == MGSL_MODE_HDLC)
3892 mod_timer(&info->tx_timer, jiffies + 3878 mod_timer(&info->tx_timer, jiffies +
3893 msecs_to_jiffies(5000)); 3879 msecs_to_jiffies(5000));
3894 } else { 3880 } else {
3895 tdma_reset(info);
3896 /* set 1st descriptor address */
3897 wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
3898
3899 slgt_irq_off(info, IRQ_TXDATA); 3881 slgt_irq_off(info, IRQ_TXDATA);
3900 slgt_irq_on(info, IRQ_TXIDLE); 3882 slgt_irq_on(info, IRQ_TXIDLE);
3901 /* clear tx idle status bit */ 3883 /* clear tx idle status bit */
3902 wr_reg16(info, SSR, IRQ_TXIDLE); 3884 wr_reg16(info, SSR, IRQ_TXIDLE);
3903
3904 /* enable tx DMA */
3905 wr_reg32(info, TDCSR, BIT0);
3906 } 3885 }
3907 3886 tdma_start(info);
3908 info->tx_active = 1; 3887 info->tx_active = 1;
3909 } 3888 }
3910} 3889}
3911 3890
3891/*
3892 * start transmit DMA if inactive and there are unsent buffers
3893 */
3894static void tdma_start(struct slgt_info *info)
3895{
3896 unsigned int i;
3897
3898 if (rd_reg32(info, TDCSR) & BIT0)
3899 return;
3900
3901 /* transmit DMA inactive, check for unsent buffers */
3902 i = info->tbuf_start;
3903 while (!desc_count(info->tbufs[i])) {
3904 if (++i == info->tbuf_count)
3905 i = 0;
3906 if (i == info->tbuf_current)
3907 return;
3908 }
3909 info->tbuf_start = i;
3910
3911 /* there are unsent buffers, start transmit DMA */
3912
3913 /* reset needed if previous error condition */
3914 tdma_reset(info);
3915
3916 /* set 1st descriptor address */
3917 wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
3918 switch(info->params.mode) {
3919 case MGSL_MODE_RAW:
3920 case MGSL_MODE_MONOSYNC:
3921 case MGSL_MODE_BISYNC:
3922 wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
3923 break;
3924 default:
3925 wr_reg32(info, TDCSR, BIT0); /* DMA enable */
3926 }
3927}
3928
3912static void tx_stop(struct slgt_info *info) 3929static void tx_stop(struct slgt_info *info)
3913{ 3930{
3914 unsigned short val; 3931 unsigned short val;
@@ -4642,8 +4659,8 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
4642 i=0; 4659 i=0;
4643 } while (i != info->tbuf_current); 4660 } while (i != info->tbuf_current);
4644 4661
4645 /* last buffer with zero count may be in use, assume it is */ 4662 /* if tx DMA active, last zero count buffer is in use */
4646 if (count) 4663 if (count && (rd_reg32(info, TDCSR) & BIT0))
4647 --count; 4664 --count;
4648 4665
4649 return count; 4666 return count;