[PATCH] tty: n_gsm: Don't block input queue by waiting MSC

Seppo Takalo posted 1 patch 1 month, 1 week ago
There is a newer version of this series
drivers/tty/n_gsm.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
[PATCH] tty: n_gsm: Don't block input queue by waiting MSC
Posted by Seppo Takalo 1 month, 1 week ago
Add parameter "wait" for gsm_modem_update() to indicate if we
should wait for the response.

Currently gsm_queue() processes incoming frames and when opening
a DLC channel it calls gsm_dlci_open() which calls gsm_modem_update().
If basic mode is used it calls gsm_modem_upd_via_msc() and it
cannot block the input queue by waiting the response to come
into the same input queue.

Instead allow sending Modem Status Command without waiting for remote
end to respond.

Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
---
 drivers/tty/n_gsm.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 8dd3f23af3d2..8e8475d9fbeb 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -454,7 +454,7 @@ static const u8 gsm_fcs8[256] = {
 
 static void gsm_dlci_close(struct gsm_dlci *dlci);
 static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
-static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
+static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk, bool wait);
 static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
 								u8 ctrl);
 static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
@@ -2174,7 +2174,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
 		pr_debug("DLCI %d goes open.\n", dlci->addr);
 	/* Send current modem state */
 	if (dlci->addr) {
-		gsm_modem_update(dlci, 0);
+		gsm_modem_update(dlci, 0, false);
 	} else {
 		/* Start keep-alive control */
 		gsm->ka_num = 0;
@@ -4138,7 +4138,7 @@ static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
  *	@brk: break signal
  */
 
-static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
+static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk, bool wait)
 {
 	u8 modembits[3];
 	struct gsm_control *ctrl;
@@ -4155,10 +4155,15 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
 		modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */
 		len++;
 	}
-	ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len);
-	if (ctrl == NULL)
-		return -ENOMEM;
-	return gsm_control_wait(dlci->gsm, ctrl);
+	if (wait) {
+		ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len);
+		if (!ctrl)
+			return -ENOMEM;
+		return gsm_control_wait(dlci->gsm, ctrl);
+	} else {
+		return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits,
+				  len);
+	}
 }
 
 /**
@@ -4167,7 +4172,7 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
  *	@brk: break signal
  */
 
-static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
+static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk, bool wait)
 {
 	if (dlci->gsm->dead)
 		return -EL2HLT;
@@ -4177,7 +4182,7 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
 		return 0;
 	} else if (dlci->gsm->encoding == GSM_BASIC_OPT) {
 		/* Send as MSC control message. */
-		return gsm_modem_upd_via_msc(dlci, brk);
+		return gsm_modem_upd_via_msc(dlci, brk, wait);
 	}
 
 	/* Modem status lines are not supported. */
@@ -4243,7 +4248,7 @@ static void gsm_dtr_rts(struct tty_port *port, bool active)
 		modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
 	if (modem_tx != dlci->modem_tx) {
 		dlci->modem_tx = modem_tx;
-		gsm_modem_update(dlci, 0);
+		gsm_modem_update(dlci, 0, true);
 	}
 }
 
@@ -4449,7 +4454,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
 
 	if (modem_tx != dlci->modem_tx) {
 		dlci->modem_tx = modem_tx;
-		return gsm_modem_update(dlci, 0);
+		return gsm_modem_update(dlci, 0, true);
 	}
 	return 0;
 }
@@ -4531,7 +4536,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
 		dlci->modem_tx &= ~TIOCM_RTS;
 	dlci->throttled = true;
 	/* Send an MSC with RTS cleared */
-	gsm_modem_update(dlci, 0);
+	gsm_modem_update(dlci, 0, true);
 }
 
 static void gsmtty_unthrottle(struct tty_struct *tty)
@@ -4543,7 +4548,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
 		dlci->modem_tx |= TIOCM_RTS;
 	dlci->throttled = false;
 	/* Send an MSC with RTS set */
-	gsm_modem_update(dlci, 0);
+	gsm_modem_update(dlci, 0, true);
 }
 
 static int gsmtty_break_ctl(struct tty_struct *tty, int state)
@@ -4561,7 +4566,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
 		if (encode > 0x0F)
 			encode = 0x0F;	/* Best effort */
 	}
-	return gsm_modem_update(dlci, encode);
+	return gsm_modem_update(dlci, encode, true);
 }
 
 static void gsmtty_cleanup(struct tty_struct *tty)
-- 
2.43.0
Re: [PATCH] tty: n_gsm: Don't block input queue by waiting MSC
Posted by Greg Kroah-Hartman 1 month, 1 week ago
On Mon, Aug 25, 2025 at 04:55:00PM +0300, Seppo Takalo wrote:
> Add parameter "wait" for gsm_modem_update() to indicate if we
> should wait for the response.
> 
> Currently gsm_queue() processes incoming frames and when opening
> a DLC channel it calls gsm_dlci_open() which calls gsm_modem_update().
> If basic mode is used it calls gsm_modem_upd_via_msc() and it
> cannot block the input queue by waiting the response to come
> into the same input queue.
> 
> Instead allow sending Modem Status Command without waiting for remote
> end to respond.
> 
> Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>

What commit id does this fix?

> ---
>  drivers/tty/n_gsm.c | 33 +++++++++++++++++++--------------
>  1 file changed, 19 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
> index 8dd3f23af3d2..8e8475d9fbeb 100644
> --- a/drivers/tty/n_gsm.c
> +++ b/drivers/tty/n_gsm.c
> @@ -454,7 +454,7 @@ static const u8 gsm_fcs8[256] = {
>  
>  static void gsm_dlci_close(struct gsm_dlci *dlci);
>  static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
> -static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
> +static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk, bool wait);

Adding a random boolean to a function is almost never a good idea.  Now
every time you call this function, you have to go and look up what that
boolean means.

Please never do that, instead make a "wrapper" function that will then
call this "core" function with the boolean set properly.  That way you
can name the wrapper functions in a way that describes what it does.

>  static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
>  								u8 ctrl);
>  static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
> @@ -2174,7 +2174,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
>  		pr_debug("DLCI %d goes open.\n", dlci->addr);
>  	/* Send current modem state */
>  	if (dlci->addr) {
> -		gsm_modem_update(dlci, 0);
> +		gsm_modem_update(dlci, 0, false);

See, what does false mean?  No clue :(

Why not call gsm_modem_update_and_wait() instead?

thanks,

greg k-h
[PATCH v2] tty: n_gsm: Don't block input queue by waiting MSC
Posted by Seppo Takalo 1 month, 1 week ago
Currently gsm_queue() processes incoming frames and when opening
a DLC channel it calls gsm_dlci_open() which calls gsm_modem_update().
If basic mode is used it calls gsm_modem_upd_via_msc() and it
cannot block the input queue by waiting the response to come
into the same input queue.

Instead allow sending Modem Status Command without waiting for remote
end to respond. Define a new function gsm_modem_send_initial_msc()
for this purpose. As MSC is only valid for basic encoding, it does
not do anything for advanced or when convergence layer type 2 is used.

Fixes: 48473802506d ("tty: n_gsm: fix missing update of modem controls after DLCI open")
Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
---
v1 --> v2
- Removed the proposed "bool wait" parameter from gsm_modem_update().
- Defined a new function gsm_modem_send_initial_msc()

 drivers/tty/n_gsm.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 8dd3f23af3d2..532027370dff 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -461,6 +461,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
 static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr);
 static void gsmld_write_trigger(struct gsm_mux *gsm);
 static void gsmld_write_task(struct work_struct *work);
+static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci);
 
 /**
  *	gsm_fcs_add	-	update FCS
@@ -2174,7 +2175,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
 		pr_debug("DLCI %d goes open.\n", dlci->addr);
 	/* Send current modem state */
 	if (dlci->addr) {
-		gsm_modem_update(dlci, 0);
+		gsm_modem_send_initial_msc(dlci);
 	} else {
 		/* Start keep-alive control */
 		gsm->ka_num = 0;
@@ -4161,6 +4162,28 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
 	return gsm_control_wait(dlci->gsm, ctrl);
 }
 
+/**
+ * gsm_modem_send_initial_msc - Send initial modem status message
+ *
+ * @dlci channel
+ *
+ * Send an initial MSC message after DLCI open to set the initial
+ * modem status lines. This is only done for basic mode.
+ * Does not wait for a response as we cannot block the input queue
+ * processing.
+ */
+static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci)
+{
+	u8 modembits[2];
+
+	if (dlci->adaption != 1 || dlci->gsm->encoding != GSM_BASIC_OPT)
+		return 0;
+
+	modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
+	modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+	return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits, 2);
+}
+
 /**
  *	gsm_modem_update	-	send modem status line state
  *	@dlci: channel
-- 
2.43.0