From: Andrew Morton <akpm@linux-foundation.org>
To: Paul Fulghum <paulkf@microgate.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] synclink_gt fix transmit race and timeout
Date: Mon, 22 Jun 2009 23:19:37 -0700 [thread overview]
Message-ID: <20090622231937.2d32898e.akpm@linux-foundation.org> (raw)
In-Reply-To: <1245181451.3727.5.camel@x2.microgate.com>
On Tue, 16 Jun 2009 14:44:11 -0500 Paul Fulghum <paulkf@microgate.com> wrote:
> Fix race condition when adding transmit data to active DMA buffer ring
> that can cause transmit stall.
> Update transmit timeout when adding data to active DMA buffer ring.
> Base transmit timeout on amount of buffered data instead of
> using fixed value.
>
It's not a terribly good changelog, sorry.
It fails to describe the race condition?
It fails to explain the user-visible effects of the bug which was
fixed. Those who need to make should-we-backport-this-to-stable
decisions need to know this. Often we are told, often we can guess.
Sometimes neither.
>
> --- a/drivers/char/synclink_gt.c 2009-06-09 22:05:27.000000000 -0500
> +++ b/drivers/char/synclink_gt.c 2009-06-16 13:58:14.000000000 -0500
> @@ -463,7 +463,6 @@ static unsigned int free_tbuf_count(stru
> static unsigned int tbuf_bytes(struct slgt_info *info);
> static void reset_tbufs(struct slgt_info *info);
> static void tdma_reset(struct slgt_info *info);
> -static void tdma_start(struct slgt_info *info);
> static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
>
> static void get_signals(struct slgt_info *info);
> @@ -791,6 +790,18 @@ static void set_termios(struct tty_struc
> }
> }
>
> +static void update_tx_timer(struct slgt_info *info)
> +{
> + /*
> + * use worst case speed of 1200bps to calculate transmit timeout
> + * based on data in buffers (tbuf_bytes) and FIFO (128 bytes)
> + */
> + if (info->params.mode == MGSL_MODE_HDLC) {
> + int timeout = (tbuf_bytes(info) * 7) + 1000;
> + mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout));
> + }
> +}
Where did the "7" come from?
> static int write(struct tty_struct *tty,
> const unsigned char *buf, int count)
> {
> @@ -834,8 +845,18 @@ start:
> spin_lock_irqsave(&info->lock,flags);
> if (!info->tx_active)
> tx_start(info);
> - else
> - tdma_start(info);
> + else if (!(rd_reg32(info, TDCSR) & BIT0)) {
> + /* transmit still active but transmit DMA stopped */
> + unsigned int i = info->tbuf_current;
> + if (!i)
> + i = info->tbuf_count;
> + i--;
> + /* if DMA buf unsent must try later after tx idle */
> + if (desc_count(info->tbufs[i]))
> + ret = 0;
> + }
> + if (ret > 0)
> + update_tx_timer(info);
> spin_unlock_irqrestore(&info->lock,flags);
> }
>
> @@ -1498,10 +1519,9 @@ static int hdlcdev_xmit(struct sk_buff *
> /* save start time for transmit timeout detection */
> dev->trans_start = jiffies;
>
> - /* start hardware transmitter if necessary */
> spin_lock_irqsave(&info->lock,flags);
> - if (!info->tx_active)
> - tx_start(info);
> + tx_start(info);
> + update_tx_timer(info);
> spin_unlock_irqrestore(&info->lock,flags);
>
> return 0;
> @@ -3886,50 +3906,19 @@ static void tx_start(struct slgt_info *i
> slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
> /* clear tx idle and underrun status bits */
> wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
> - if (info->params.mode == MGSL_MODE_HDLC)
> - mod_timer(&info->tx_timer, jiffies +
> - msecs_to_jiffies(5000));
> } else {
> slgt_irq_off(info, IRQ_TXDATA);
> slgt_irq_on(info, IRQ_TXIDLE);
> /* clear tx idle status bit */
> wr_reg16(info, SSR, IRQ_TXIDLE);
> }
> - tdma_start(info);
> + /* set 1st descriptor address and start DMA */
> + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
> + wr_reg32(info, TDCSR, BIT2 + BIT0);
> info->tx_active = true;
> }
> }
>
> ...
>
> @@ -4942,8 +4931,7 @@ static void tx_timeout(unsigned long con
> info->icount.txtimeout++;
> }
> spin_lock_irqsave(&info->lock,flags);
> - info->tx_active = false;
> - info->tx_count = 0;
> + tx_stop(info);
I have a suspicion that tx_stop() should use del_timer_sync(), not
del_timer(). What happens if the timer handler is concurrently
running?
next prev parent reply other threads:[~2009-06-23 6:20 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-16 19:44 [PATCH] synclink_gt fix transmit race and timeout Paul Fulghum
2009-06-23 6:19 ` Andrew Morton [this message]
2009-06-23 15:16 ` Paul Fulghum
2009-06-23 16:27 ` Andrew Morton
2009-06-23 17:55 ` Paul Fulghum
2009-06-23 17:02 ` Andrew Morton
2009-06-23 18:29 ` Paul Fulghum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090622231937.2d32898e.akpm@linux-foundation.org \
--to=akpm@linux-foundation.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=paulkf@microgate.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.