diff options
author | Paul Fulghum <paulkf@microgate.com> | 2007-07-31 03:37:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 18:39:37 -0400 |
commit | bb029c67e430e9ae96476ce7233468c11627c1db (patch) | |
tree | d792805dcca0b6da7b3f0a7e0a7ac93ab236b97a /drivers/char | |
parent | ddb437b7f74de775ff50ef51a8b2970564d56f86 (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.c | 75 |
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 | */ |
95 | static char *driver_name = "SyncLink GT"; | 95 | static char *driver_name = "SyncLink GT"; |
96 | static char *driver_version = "$Revision: 4.36 $"; | 96 | static char *driver_version = "$Revision: 4.50 $"; |
97 | static char *tty_driver_name = "synclink_gt"; | 97 | static char *tty_driver_name = "synclink_gt"; |
98 | static char *tty_dev_prefix = "ttySLG"; | 98 | static char *tty_dev_prefix = "ttySLG"; |
99 | MODULE_LICENSE("GPL"); | 99 | MODULE_LICENSE("GPL"); |
@@ -477,6 +477,7 @@ static void tx_set_idle(struct slgt_info *info); | |||
477 | static unsigned int free_tbuf_count(struct slgt_info *info); | 477 | static unsigned int free_tbuf_count(struct slgt_info *info); |
478 | static void reset_tbufs(struct slgt_info *info); | 478 | static void reset_tbufs(struct slgt_info *info); |
479 | static void tdma_reset(struct slgt_info *info); | 479 | static void tdma_reset(struct slgt_info *info); |
480 | static void tdma_start(struct slgt_info *info); | ||
480 | static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); | 481 | static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); |
481 | 482 | ||
482 | static void get_signals(struct slgt_info *info); | 483 | static 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 | */ | ||
3894 | static 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 | |||
3912 | static void tx_stop(struct slgt_info *info) | 3929 | static 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; |