| From e9ec22547986dd32c5c70da78107ce35dbff1344 Mon Sep 17 00:00:00 2001 |
| From: Tony Lindgren <tony@atomide.com> |
| Date: Sat, 7 Apr 2018 10:19:50 -0700 |
| Subject: tty: n_gsm: Fix long delays with control frame timeouts in ADM mode |
| |
| From: Tony Lindgren <tony@atomide.com> |
| |
| commit e9ec22547986dd32c5c70da78107ce35dbff1344 upstream. |
| |
| Commit ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for |
| control dlci") added support for DLCI to stay in Asynchronous Disconnected |
| Mode (ADM). But we still get long delays waiting for commands to other |
| DLCI to complete: |
| |
| --> 5) C: SABM(P) |
| Q> 0) C: UIH(F) |
| Q> 0) C: UIH(F) |
| Q> 0) C: UIH(F) |
| ... |
| |
| This happens because gsm_control_send() sets cretries timer to T2 that is |
| by default set to 34. This will cause resend for T2 times for the control |
| frame. In ADM mode, we will never get a response so the control frame, so |
| retries are just delaying all the commands. |
| |
| Let's fix the issue by setting DLCI_MODE_ADM flag after detecting the ADM |
| mode for the control DLCI. Then we can use that in gsm_control_send() to |
| set retries to 1. This means the control frame will be sent once allowing |
| the other end at an opportunity to switch from ADM to ABM mode. |
| |
| Note that retries will be decremented in gsm_control_retransmit() so |
| we don't want to set it to 0 here. |
| |
| Fixes: ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") |
| Cc: linux-serial@vger.kernel.org |
| Cc: Alan Cox <alan@llwyncelyn.cymru> |
| Cc: Dan Williams <dcbw@redhat.com> |
| Cc: Jiri Prchal <jiri.prchal@aksignal.cz> |
| Cc: Jiri Slaby <jslaby@suse.cz> |
| Cc: Marcel Partap <mpartap@gmx.net> |
| Cc: Merlijn Wajer <merlijn@wizzup.org> |
| Cc: Michael Nazzareno Trimarchi <michael@amarulasolutions.com> |
| Cc: Michael Scott <michael.scott@linaro.org> |
| Cc: Pavel Machek <pavel@ucw.cz> |
| Cc: Peter Hurley <peter@hurleysoftware.com> |
| Cc: Russ Gorby <russ.gorby@intel.com> |
| Cc: Sascha Hauer <s.hauer@pengutronix.de> |
| Cc: Sebastian Reichel <sre@kernel.org> |
| Signed-off-by: Tony Lindgren <tony@atomide.com> |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/n_gsm.c | 12 +++++++++++- |
| 1 file changed, 11 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/tty/n_gsm.c |
| +++ b/drivers/tty/n_gsm.c |
| @@ -121,6 +121,9 @@ struct gsm_dlci { |
| struct mutex mutex; |
| |
| /* Link layer */ |
| + int mode; |
| +#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ |
| +#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ |
| spinlock_t lock; /* Protects the internal state */ |
| struct timer_list t1; /* Retransmit timer for SABM and UA */ |
| int retries; |
| @@ -1364,7 +1367,13 @@ retry: |
| ctrl->data = data; |
| ctrl->len = clen; |
| gsm->pending_cmd = ctrl; |
| - gsm->cretries = gsm->n2; |
| + |
| + /* If DLCI0 is in ADM mode skip retries, it won't respond */ |
| + if (gsm->dlci[0]->mode == DLCI_MODE_ADM) |
| + gsm->cretries = 1; |
| + else |
| + gsm->cretries = gsm->n2; |
| + |
| mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); |
| gsm_control_transmit(gsm, ctrl); |
| spin_unlock_irqrestore(&gsm->control_lock, flags); |
| @@ -1472,6 +1481,7 @@ static void gsm_dlci_t1(struct timer_lis |
| if (debug & 8) |
| pr_info("DLCI %d opening in ADM mode.\n", |
| dlci->addr); |
| + dlci->mode = DLCI_MODE_ADM; |
| gsm_dlci_open(dlci); |
| } else { |
| gsm_dlci_close(dlci); |