Linux Serial subsystem development
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] serial: 8250_omap: Drop check for of_node
From: Sebastian Reichel @ 2019-01-10 12:07 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Vignesh R, Greg Kroah-Hartman, Rob Herring, Jiri Slaby,
	Lokesh Vutla, linux-serial, linux-omap, devicetree, linux-kernel
In-Reply-To: <20190109214403.GW5544@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 1093 bytes --]

Hi,

On Wed, Jan 09, 2019 at 01:44:03PM -0800, Tony Lindgren wrote:
> * Vignesh R <vigneshr@ti.com> [190109 09:11]:
> > 8250_omap is DT only driver so dev->of_node always exists. Drop check
> > for existence of valid dev->of_node to simplify omap8250_probe().
> 
> That part seems safe to me now.
> 
> > --- a/drivers/tty/serial/8250/8250_omap.c
> > +++ b/drivers/tty/serial/8250/8250_omap.c
> ...
> > -		const struct of_device_id *id;
> > -
> > -		ret = of_alias_get_id(pdev->dev.of_node, "serial");
> > -
> > -		of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> > -				     &up.port.uartclk);
> > -		priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
> > -
> > -		id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
> > -		if (id && id->data)
> > -			priv->habit |= *(u8 *)id->data;
> 
> But this part it seems we still need to keep around
> as we still have lots of clock-frequency references
> in the *.dtsi files. Or am I missing something?

It's re-added a couple of lines later. Only the indent was removed.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH 1/3] serial: 8250_omap: Drop check for of_node
From: Vignesh R @ 2019-01-10 13:24 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren
  Cc: Greg Kroah-Hartman, Rob Herring, Jiri Slaby, Lokesh Vutla,
	linux-serial, linux-omap, devicetree, linux-kernel
In-Reply-To: <20190110120758.bz63neey5ztepw4m@earth.universe>


On 10-Jan-19 5:37 PM, Sebastian Reichel wrote:
> Hi,
> 
> On Wed, Jan 09, 2019 at 01:44:03PM -0800, Tony Lindgren wrote:
>> * Vignesh R <vigneshr@ti.com> [190109 09:11]:
>>> 8250_omap is DT only driver so dev->of_node always exists. Drop check
>>> for existence of valid dev->of_node to simplify omap8250_probe().
>>
>> That part seems safe to me now.
>>
>>> --- a/drivers/tty/serial/8250/8250_omap.c
>>> +++ b/drivers/tty/serial/8250/8250_omap.c
>> ...
>>> -		const struct of_device_id *id;
>>> -
>>> -		ret = of_alias_get_id(pdev->dev.of_node, "serial");
>>> -
>>> -		of_property_read_u32(pdev->dev.of_node, "clock-frequency",
>>> -				     &up.port.uartclk);
>>> -		priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
>>> -
>>> -		id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
>>> -		if (id && id->data)
>>> -			priv->habit |= *(u8 *)id->data;
>>
>> But this part it seems we still need to keep around
>> as we still have lots of clock-frequency references
>> in the *.dtsi files. Or am I missing something?
> 
> It's re-added a couple of lines later. Only the indent was removed.
> 

That's right. You beat me to it. Thanks :)

Regards
Vignesh

^ permalink raw reply

* [PATCH] tty/serial: emit CR before NL in RISC-V SBL console
From: Andreas Schwab @ 2019-01-10 14:07 UTC (permalink / raw)
  To: Anup Patel
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel, linux-serial
In-Reply-To: <20181204135507.3706-2-anup@brainfault.org>

Signed-off-by: Andreas Schwab <schwab@suse.de>
---
 drivers/tty/serial/earlycon-riscv-sbi.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c
index e1a551aae3..9c51b945b5 100644
--- a/drivers/tty/serial/earlycon-riscv-sbi.c
+++ b/drivers/tty/serial/earlycon-riscv-sbi.c
@@ -15,8 +15,11 @@ static void sbi_console_write(struct console *con,
 {
 	int i;
 
-	for (i = 0; i < n; ++i)
+	for (i = 0; i < n; ++i) {
+		if (s[i] == '\n')
+			sbi_console_putchar('\r');
 		sbi_console_putchar(s[i]);
+	}
 }
 
 static int __init early_sbi_setup(struct earlycon_device *device,
-- 
2.20.1

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply related

* Re: [PATCH] tty/serial: emit CR before NL in RISC-V SBL console
From: Anup Patel @ 2019-01-10 15:16 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel@vger.kernel.org List, linux-serial
In-Reply-To: <mvmbm4oehd5.fsf_-_@suse.de>

On Thu, Jan 10, 2019 at 7:37 PM Andreas Schwab <schwab@suse.de> wrote:
>
> Signed-off-by: Andreas Schwab <schwab@suse.de>
> ---
>  drivers/tty/serial/earlycon-riscv-sbi.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c
> index e1a551aae3..9c51b945b5 100644
> --- a/drivers/tty/serial/earlycon-riscv-sbi.c
> +++ b/drivers/tty/serial/earlycon-riscv-sbi.c
> @@ -15,8 +15,11 @@ static void sbi_console_write(struct console *con,
>  {
>         int i;
>
> -       for (i = 0; i < n; ++i)
> +       for (i = 0; i < n; ++i) {
> +               if (s[i] == '\n')
> +                       sbi_console_putchar('\r');

Instead of doing '\n' handling here, we should do it in BBL or
OpenSBI (i.e. SBI runtime firmware) otherwise all users of
SBI_CONSOLE_PUTCHAR (namely, Linux, FreeBSD,
FreeRTOS, U-Boot S-mode, etc) will endup having '\n'
handling.

Currently, the BBL does not handle it but we have already
handled this in upcoming OpenSBI.

The SBI_CONSOLE_PUTCHAR is comparable to ARM
semihosting early prints (refer, tty/serial/earlycon-arm-semihost.c).
Even in ARM semihosting early prints the '\n' is not explicitly
handled.

Regards,
Anup

^ permalink raw reply

* Re: [PATCH] tty/serial: emit CR before NL in RISC-V SBL console
From: Andreas Schwab @ 2019-01-10 15:26 UTC (permalink / raw)
  To: Anup Patel
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel@vger.kernel.org List, linux-serial
In-Reply-To: <CAAhSdy3-SaP7RBbgx7kZgkkxeN2W-Ue8QDFXkOgFG5GiAg52-g@mail.gmail.com>

On Jan 10 2019, Anup Patel <anup@brainfault.org> wrote:

> Instead of doing '\n' handling here, we should do it in BBL or
> OpenSBI (i.e. SBI runtime firmware) otherwise all users of
> SBI_CONSOLE_PUTCHAR (namely, Linux, FreeBSD,
> FreeRTOS, U-Boot S-mode, etc) will endup having '\n'
> handling.

I don't think the serial driver should do NLCR handling on its own,
without being instructed by the tty layer.  Since the earlycon does not
have a tty layer, it needs to handle it explicitly.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply

* Re: [PATCH 1/3] serial: 8250_omap: Drop check for of_node
From: Tony Lindgren @ 2019-01-10 15:27 UTC (permalink / raw)
  To: Vignesh R
  Cc: Sebastian Reichel, Greg Kroah-Hartman, Rob Herring, Jiri Slaby,
	Lokesh Vutla, linux-serial, linux-omap, devicetree, linux-kernel
In-Reply-To: <dbc00a69-2144-6e30-e9b1-4f8ee272ab8a@ti.com>

* Vignesh R <vigneshr@ti.com> [190110 13:24]:
> 
> On 10-Jan-19 5:37 PM, Sebastian Reichel wrote:
> > Hi,
> > 
> > On Wed, Jan 09, 2019 at 01:44:03PM -0800, Tony Lindgren wrote:
> >> * Vignesh R <vigneshr@ti.com> [190109 09:11]:
> >>> 8250_omap is DT only driver so dev->of_node always exists. Drop check
> >>> for existence of valid dev->of_node to simplify omap8250_probe().
> >>
> >> That part seems safe to me now.
> >>
> >>> --- a/drivers/tty/serial/8250/8250_omap.c
> >>> +++ b/drivers/tty/serial/8250/8250_omap.c
> >> ...
> >>> -		const struct of_device_id *id;
> >>> -
> >>> -		ret = of_alias_get_id(pdev->dev.of_node, "serial");
> >>> -
> >>> -		of_property_read_u32(pdev->dev.of_node, "clock-frequency",
> >>> -				     &up.port.uartclk);
> >>> -		priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
> >>> -
> >>> -		id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
> >>> -		if (id && id->data)
> >>> -			priv->habit |= *(u8 *)id->data;
> >>
> >> But this part it seems we still need to keep around
> >> as we still have lots of clock-frequency references
> >> in the *.dtsi files. Or am I missing something?
> > 
> > It's re-added a couple of lines later. Only the indent was removed.
> > 
> 
> That's right. You beat me to it. Thanks :)

Oh right, sorry I missed that :)

Regards,

Tony

^ permalink raw reply

* Re: [PATCH] tty/serial: emit CR before NL in RISC-V SBL console
From: Anup Patel @ 2019-01-10 16:17 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel@vger.kernel.org List, linux-serial
In-Reply-To: <mvm7efcedop.fsf@suse.de>

On Thu, Jan 10, 2019 at 8:56 PM Andreas Schwab <schwab@suse.de> wrote:
>
> On Jan 10 2019, Anup Patel <anup@brainfault.org> wrote:
>
> > Instead of doing '\n' handling here, we should do it in BBL or
> > OpenSBI (i.e. SBI runtime firmware) otherwise all users of
> > SBI_CONSOLE_PUTCHAR (namely, Linux, FreeBSD,
> > FreeRTOS, U-Boot S-mode, etc) will endup having '\n'
> > handling.
>
> I don't think the serial driver should do NLCR handling on its own,
> without being instructed by the tty layer.  Since the earlycon does not
> have a tty layer, it needs to handle it explicitly.

I tried to investigate more. What you suggest is correct
but we should use uart_console_write() API.

Instead of explicitly doing NLCR here, we should do
something as follows:

static void sbi_putc(struct uart_port *port, int c)
{
    sbi_console_putchar(c);
}

static void sbi_console_write(struct console *con,
                                               const char *s, unsigned n)
{
    struct earlycon_device *dev = con->data;
    uart_console_write(&dev->port, s, n, sbi_putc);
}

The uart_console_write() does the NLCR handling.

Regards,
Anup

^ permalink raw reply

* [PATCH] tty/serial: use uart_console_write in the RISC-V SBL early console
From: Andreas Schwab @ 2019-01-10 17:11 UTC (permalink / raw)
  To: Anup Patel
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel@vger.kernel.org List, linux-serial
In-Reply-To: <CAAhSdy0suSgKpdz+NUrXzS9Ozp75hMC6ovW4yLf5s0KYJwwocw@mail.gmail.com>

This enables proper NLCR processing.

Suggested-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Andreas Schwab <schwab@suse.de>
---
 drivers/tty/serial/earlycon-riscv-sbi.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c
index e1a551aae3..ce81523c31 100644
--- a/drivers/tty/serial/earlycon-riscv-sbi.c
+++ b/drivers/tty/serial/earlycon-riscv-sbi.c
@@ -10,13 +10,16 @@
 #include <linux/serial_core.h>
 #include <asm/sbi.h>
 
-static void sbi_console_write(struct console *con,
-			      const char *s, unsigned int n)
+static void sbi_putc(struct uart_port *port, int c)
 {
-	int i;
+	sbi_console_putchar(c);
+}
 
-	for (i = 0; i < n; ++i)
-		sbi_console_putchar(s[i]);
+static void sbi_console_write(struct console *con,
+			      const char *s, unsigned n)
+{
+	struct earlycon_device *dev = con->data;
+	uart_console_write(&dev->port, s, n, sbi_putc);
 }
 
 static int __init early_sbi_setup(struct earlycon_device *device,
-- 
2.20.1

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply related

* Re: [PATCH] tty/serial: emit CR before NL in RISC-V SBL console
From: Palmer Dabbelt @ 2019-01-10 20:54 UTC (permalink / raw)
  To: schwab, anup
  Cc: Greg KH, jslaby, aou, atish.patra, Christoph Hellwig, robh,
	linux-riscv, linux-kernel, linux-serial
In-Reply-To: <CAAhSdy0suSgKpdz+NUrXzS9Ozp75hMC6ovW4yLf5s0KYJwwocw@mail.gmail.com>

On Thu, 10 Jan 2019 07:26:46 PST (-0800), schwab@suse.de wrote:
> On Jan 10 2019, Anup Patel <anup@brainfault.org> wrote:
>
>> Instead of doing '\n' handling here, we should do it in BBL or
>> OpenSBI (i.e. SBI runtime firmware) otherwise all users of
>> SBI_CONSOLE_PUTCHAR (namely, Linux, FreeBSD,
>> FreeRTOS, U-Boot S-mode, etc) will endup having '\n'
>> handling.
>
> I don't think the serial driver should do NLCR handling on its own,
> without being instructed by the tty layer.  Since the earlycon does not
> have a tty layer, it needs to handle it explicitly.

I think it's best if we have the SBI interfaces be defined to be bit-exact.  It
does mean that everyone who uses the interfaces needs to do this handling, but
I think that's actually a feature because it'll be subtly different everywhere.

This also has the advantage of being compatible with what we currently do in
BBL and what we current expect in Linux everywhere but this earlycon driver
(and will do assuming we merge this patch).

On Thu, 10 Jan 2019 08:17:07 PST (-0800), anup@brainfault.org wrote:
> On Thu, Jan 10, 2019 at 8:56 PM Andreas Schwab <schwab@suse.de> wrote:
>>
>> On Jan 10 2019, Anup Patel <anup@brainfault.org> wrote:
>>
>> > Instead of doing '\n' handling here, we should do it in BBL or
>> > OpenSBI (i.e. SBI runtime firmware) otherwise all users of
>> > SBI_CONSOLE_PUTCHAR (namely, Linux, FreeBSD,
>> > FreeRTOS, U-Boot S-mode, etc) will endup having '\n'
>> > handling.
>>
>> I don't think the serial driver should do NLCR handling on its own,
>> without being instructed by the tty layer.  Since the earlycon does not
>> have a tty layer, it needs to handle it explicitly.
>
> I tried to investigate more. What you suggest is correct
> but we should use uart_console_write() API.
>
> Instead of explicitly doing NLCR here, we should do
> something as follows:
>
> static void sbi_putc(struct uart_port *port, int c)
> {
>     sbi_console_putchar(c);
> }
>
> static void sbi_console_write(struct console *con,
>                                                const char *s, unsigned n)
> {
>     struct earlycon_device *dev = con->data;
>     uart_console_write(&dev->port, s, n, sbi_putc);
> }
>
> The uart_console_write() does the NLCR handling.

That does look cleaner.  I'll expect a v2 :)

^ permalink raw reply

* [PATCH] dt-bindings: serial: Convert arm,pl011 to json-schema
From: Rob Herring @ 2019-01-10 22:19 UTC (permalink / raw)
  To: devicetree; +Cc: linux-kernel, Greg Kroah-Hartman, linux-serial

Convert the arm,pl011 binding to DT schema using json-schema.

The zte,zx296702-uart binding appears to be broken as the dts files are
missing 'arm,primecell'. That's included in the schema here to throw a
warning.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/serial/pl011.txt      |  51 -------
 .../devicetree/bindings/serial/pl011.yaml     | 126 ++++++++++++++++++
 2 files changed, 126 insertions(+), 51 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/serial/pl011.txt
 create mode 100644 Documentation/devicetree/bindings/serial/pl011.yaml

diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt
deleted file mode 100644
index 77863aefe9ef..000000000000
--- a/Documentation/devicetree/bindings/serial/pl011.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-* ARM AMBA Primecell PL011 serial UART
-
-Required properties:
-- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart"
-- reg: exactly one register range with length 0x1000
-- interrupts: exactly one interrupt specifier
-
-Optional properties:
-- pinctrl:
-	   When present, must have one state named "default",
-	   and may contain a second name named "sleep". The former
-	   state sets up pins for ordinary operation whereas
-	   the latter state will put the associated pins to sleep
-	   when the UART is unused
-- clocks:
-	   When present, the first clock listed must correspond to
-	   the clock named UARTCLK on the IP block, i.e. the clock
-	   to the external serial line, whereas the second clock
-	   must correspond to the PCLK clocking the internal logic
-	   of the block. Just listing one clock (the first one) is
-	   deprecated.
-- clock-names:
-	   When present, the first clock listed must be named
-	   "uartclk" and the second clock listed must be named
-	   "apb_pclk"
-- dmas:	
-	   When present, may have one or two dma channels.
-	   The first one must be named "rx", the second one
-	   must be named "tx".
-- auto-poll:
-	   Enables polling when using RX DMA.
-- poll-rate-ms:
-	   Rate at which poll occurs when auto-poll is set,
-	   default 100ms.
-- poll-timeout-ms:
-	   Poll timeout when auto-poll is set, default
-	   3000ms.
-
-See also bindings/arm/primecell.txt
-
-Example:
-
-uart@80120000 {
-	compatible = "arm,pl011", "arm,primecell";
-	reg = <0x80120000 0x1000>;
-	interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
-	dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>;
-	dma-names = "rx", "tx";
-	clocks = <&foo_clk>, <&bar_clk>;
-	clock-names = "uartclk", "apb_pclk";
-};
diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml
new file mode 100644
index 000000000000..1a64d59152aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/pl011.yaml
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/pl011.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM AMBA Primecell PL011 serial UART
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+allOf:
+  - $ref: /schemas/serial.yaml#
+
+# Need a custom select here or 'arm,primecell' will match on lots of nodes
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - arm,pl011
+          - zte,zx296702-uart
+  required:
+    - compatible
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - const: arm,pl011
+          - const: arm,primecell
+      - items:
+          - const: zte,zx296702-uart
+          - const: arm,primecell
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  pinctrl-0: true
+  pinctrl-1: true
+
+  pinctrl-names:
+    description:
+      When present, must have one state named "default",
+      and may contain a second name named "sleep". The former
+      state sets up pins for ordinary operation whereas
+      the latter state will put the associated pins to sleep
+      when the UART is unused
+    minItems: 1
+    items:
+      - const: default
+      - const: sleep
+
+  clocks:
+    description:
+      When present, the first clock listed must correspond to
+      the clock named UARTCLK on the IP block, i.e. the clock
+      to the external serial line, whereas the second clock
+      must correspond to the PCLK clocking the internal logic
+      of the block. Just listing one clock (the first one) is
+      deprecated.
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: uartclk
+      - const: apb_pclk
+
+  dmas:
+    minItems: 1
+    maxItems: 2
+
+  dma-names:
+    minItems: 1
+    items:
+      - const: rx
+      - const: tx
+
+  auto-poll:
+    description:
+      Enables polling when using RX DMA.
+    type: boolean
+
+  poll-rate-ms:
+    description:
+      Rate at which poll occurs when auto-poll is set.
+      default 100ms.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - default: 100
+
+  poll-timeout-ms:
+    description:
+      Poll timeout when auto-poll is set, default
+      3000ms.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - default: 3000
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+dependencies:
+  poll-rate-ms: [ auto-poll ]
+  poll-timeout-ms: [ auto-poll ]
+
+additionalProperties: false
+
+examples:
+  - |
+    serial@80120000 {
+      compatible = "arm,pl011", "arm,primecell";
+      reg = <0x80120000 0x1000>;
+      interrupts = <0 11 4>;
+      dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>;
+      dma-names = "rx", "tx";
+      clocks = <&foo_clk>, <&bar_clk>;
+      clock-names = "uartclk", "apb_pclk";
+    };
+
+...
-- 
2.19.1

^ permalink raw reply related

* [PATCH 1/2] dt-bindings: serial: Convert snps,dw-apb-uart to json-schema
From: Rob Herring @ 2019-01-10 22:20 UTC (permalink / raw)
  To: devicetree; +Cc: linux-kernel, Greg Kroah-Hartman, linux-serial

Convert the snps,dw-apb-uart binding to DT schema using json-schema.

The Rockchip and Broadcom compatible strings were not documented,
so add them here.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
 .../bindings/serial/snps-dw-apb-uart.txt      |  76 ----------
 .../bindings/serial/snps-dw-apb-uart.yaml     | 140 ++++++++++++++++++
 2 files changed, 140 insertions(+), 76 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
 create mode 100644 Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
deleted file mode 100644
index 12bbe9f22560..000000000000
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-* Synopsys DesignWare ABP UART
-
-Required properties:
-- compatible : "snps,dw-apb-uart"
-- reg : offset and length of the register set for the device.
-- interrupts : should contain uart interrupt.
-
-Clock handling:
-The clock rate of the input clock needs to be supplied by one of
-- clock-frequency : the input clock frequency for the UART.
-- clocks : phandle to the input clock
-
-The supplying peripheral clock can also be handled, needing a second property
-- clock-names: tuple listing input clock names.
-	Required elements: "baudclk", "apb_pclk"
-
-Optional properties:
-- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE
-  configuration parameter. Define this if your UART does not implement the busy
-  functionality.
-- resets : phandle to the parent reset controller.
-- reg-shift : quantity to shift the register offsets by.  If this property is
-  not present then the register offsets are not shifted.
-- reg-io-width : the size (in bytes) of the IO accesses that should be
-  performed on the device.  If this property is not present then single byte
-  accesses are used.
-- dcd-override : Override the DCD modem status signal. This signal will always
-  be reported as active instead of being obtained from the modem status
-  register. Define this if your serial port does not use this pin.
-- dsr-override : Override the DTS modem status signal. This signal will always
-  be reported as active instead of being obtained from the modem status
-  register. Define this if your serial port does not use this pin.
-- cts-override : Override the CTS modem status signal. This signal will always
-  be reported as active instead of being obtained from the modem status
-  register. Define this if your serial port does not use this pin.
-- ri-override : Override the RI modem status signal. This signal will always be
-  reported as inactive instead of being obtained from the modem status register.
-  Define this if your serial port does not use this pin.
-
-Example:
-
-	uart@80230000 {
-		compatible = "snps,dw-apb-uart";
-		reg = <0x80230000 0x100>;
-		clock-frequency = <3686400>;
-		interrupts = <10>;
-		reg-shift = <2>;
-		reg-io-width = <4>;
-		dcd-override;
-		dsr-override;
-		cts-override;
-		ri-override;
-	};
-
-Example with one clock:
-
-	uart@80230000 {
-		compatible = "snps,dw-apb-uart";
-		reg = <0x80230000 0x100>;
-		clocks = <&baudclk>;
-		interrupts = <10>;
-		reg-shift = <2>;
-		reg-io-width = <4>;
-	};
-
-Example with two clocks:
-
-	uart@80230000 {
-		compatible = "snps,dw-apb-uart";
-		reg = <0x80230000 0x100>;
-		clocks = <&baudclk>, <&apb_pclk>;
-		clock-names = "baudclk", "apb_pclk";
-		interrupts = <10>;
-		reg-shift = <2>;
-		reg-io-width = <4>;
-	};
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
new file mode 100644
index 000000000000..b42002542690
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/snps-dw-apb-uart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare ABP UART
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+allOf:
+  - $ref: /schemas/serial.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - renesas,r9a06g032-uart
+              - renesas,r9a06g033-uart
+          - const: renesas,rzn1-uart
+      - items:
+          - enum:
+              - rockchip,px30-uart
+              - rockchip,rk3036-uart
+              - rockchip,rk3066-uart
+              - rockchip,rk3188-uart
+              - rockchip,rk3288-uart
+              - rockchip,rk3328-uart
+              - rockchip,rk3368-uart
+              - rockchip,rk3399-uart
+              - rockchip,rv1108-uart
+          - const: snps,dw-apb-uart
+      - items:
+          - enum:
+              - brcm,bcm11351-dw-apb-uart
+              - brcm,bcm21664-dw-apb-uart
+          - const: snps,dw-apb-uart
+      - const: snps,dw-apb-uart
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clock-frequency: true
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: baudclk
+      - const: apb_pclk
+
+  snps,uart-16550-compatible:
+    description: reflects the value of UART_16550_COMPATIBLE configuration
+      parameter. Define this if your UART does not implement the busy functionality.
+    type: boolean
+
+  resets:
+    maxItems: 1
+
+  reg-shift: true
+
+  reg-io-width: true
+
+  dcd-override:
+    description: Override the DCD modem status signal. This signal will
+      always be reported as active instead of being obtained from the modem
+      status register. Define this if your serial port does not use this
+      pin.
+    type: boolean
+
+  dsr-override:
+    description: Override the DTS modem status signal. This signal will
+      always be reported as active instead of being obtained from the modem
+      status register. Define this if your serial port does not use this
+      pin.
+    type: boolean
+
+  cts-override:
+    description: Override the CTS modem status signal. This signal will
+      always be reported as active instead of being obtained from the modem
+      status register. Define this if your serial port does not use this
+      pin.
+    type: boolean
+
+  ri-override:
+    description: Override the RI modem status signal. This signal will always
+      be reported as inactive instead of being obtained from the modem status
+      register. Define this if your serial port does not use this pin.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    serial@80230000 {
+      compatible = "snps,dw-apb-uart";
+      reg = <0x80230000 0x100>;
+      clock-frequency = <3686400>;
+      interrupts = <10>;
+      reg-shift = <2>;
+      reg-io-width = <4>;
+      dcd-override;
+      dsr-override;
+      cts-override;
+      ri-override;
+    };
+
+  - |
+    // Example with one clock:
+    serial@80230000 {
+      compatible = "snps,dw-apb-uart";
+      reg = <0x80230000 0x100>;
+      clocks = <&baudclk>;
+      interrupts = <10>;
+      reg-shift = <2>;
+      reg-io-width = <4>;
+    };
+
+  - |
+    // Example with two clocks:
+    serial@80230000 {
+      compatible = "snps,dw-apb-uart";
+      reg = <0x80230000 0x100>;
+      clocks = <&baudclk>, <&apb_pclk>;
+      clock-names = "baudclk", "apb_pclk";
+      interrupts = <10>;
+      reg-shift = <2>;
+      reg-io-width = <4>;
+    };
+...
-- 
2.19.1

^ permalink raw reply related

* [PATCH 2/2] dt-bindings: serial: Move renesas,rzn1-uart into the snps-dw-apb-uart binding
From: Rob Herring @ 2019-01-10 22:20 UTC (permalink / raw)
  To: devicetree
  Cc: linux-kernel, Phil Edworthy, Simon Horman, Greg Kroah-Hartman,
	linux-serial
In-Reply-To: <20190110222017.6390-1-robh@kernel.org>

The renesas,rzn1-uart binding only differs in compatible string from the
snps-dw-apb-uart binding. Move it there, converting it to json-schema in
the process.

Cc: Phil Edworthy <phil.edworthy@renesas.com>
Cc: Simon Horman <horms+renesas@verge.net.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/serial/renesas,rzn1-uart.txt   | 10 ----------
 1 file changed, 10 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt b/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt
deleted file mode 100644
index 8b9e0d4dc2e4..000000000000
--- a/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Renesas RZ/N1 UART
-
-This controller is based on the Synopsys DesignWare ABP UART and inherits all
-properties defined in snps-dw-apb-uart.txt except for the compatible property.
-
-Required properties:
-- compatible : The device specific string followed by the generic RZ/N1 string.
-   Therefore it must be one of:
-   "renesas,r9a06g032-uart", "renesas,rzn1-uart"
-   "renesas,r9a06g033-uart", "renesas,rzn1-uart"
-- 
2.19.1

^ permalink raw reply related

* Re: [PATCH v9 1/2] dmaengine: 8250_mtk_dma: add MediaTek uart DMA support
From: Long Cheng @ 2019-01-11  1:18 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee, Sean Wang,
	Nicolas Boichat, Matthias Brugger, Dan Williams,
	Greg Kroah-Hartman, Jiri Slaby, Sean Wang, dmaengine, devicetree,
	linux-arm-kernel, linux-mediatek, linux-kernel, linux-serial,
	srv_heupstream, Yingjoe Chen, YT Shen,
	Zhenbao Liu <zhenbao.li>
In-Reply-To: <1547116431.3831.43.camel@mhfsdcap03>

On Thu, 2019-01-10 at 18:33 +0800, Long Cheng wrote:
fix spell error

> On Fri, 2019-01-04 at 22:49 +0530, Vinod Koul wrote:
> > On 02-01-19, 10:12, Long Cheng wrote:
> > > In DMA engine framework, add 8250 uart dma to support MediaTek uart.
> > > If MediaTek uart enabled(SERIAL_8250_MT6577), and want to improve
> > > the performance, can enable the function.
> > 
> > Is the DMA controller UART specific, can it work with other controllers
> > as well, if so you should get rid of uart name in patch
> > 
> 
> I don't know that it can work or not on other controller. but it's for
> MediaTek SOC
> 
> > > +#define MTK_UART_APDMA_CHANNELS		(CONFIG_SERIAL_8250_NR_UARTS * 2)
> > 
> > Why are the channels not coming from DT?
> > 
> 
> i will using dma-requests install of it.
> 
i will using 'dma-requests' instead of it.

> > > +
> > > +#define VFF_EN_B		BIT(0)
> > > +#define VFF_STOP_B		BIT(0)
> > > +#define VFF_FLUSH_B		BIT(0)
> > > +#define VFF_4G_SUPPORT_B	BIT(0)
> > > +#define VFF_RX_INT_EN0_B	BIT(0)	/*rx valid size >=  vff thre*/
> > > +#define VFF_RX_INT_EN1_B	BIT(1)
> > > +#define VFF_TX_INT_EN_B		BIT(0)	/*tx left size >= vff thre*/
> > 
> > space around /* space */ also run checkpatch to check for style errors
> > 
> 
> ok.
> 
> > > +static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
> > > +{
> > > +	unsigned int len, send, left, wpt, d_wpt, tmp;
> > > +	int ret;
> > > +
> > > +	left = mtk_uart_apdma_read(c, VFF_LEFT_SIZE);
> > > +	if (!left) {
> > > +		mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
> > > +		return;
> > > +	}
> > > +
> > > +	/* Wait 1sec for flush,  can't sleep*/
> > > +	ret = readx_poll_timeout(readl, c->base + VFF_FLUSH, tmp,
> > > +			tmp != VFF_FLUSH_B, 0, 1000000);
> > > +	if (ret)
> > > +		dev_warn(c->vc.chan.device->dev, "tx: fail, debug=0x%x\n",
> > > +			mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
> > > +
> > > +	send = min_t(unsigned int, left, c->desc->avail_len);
> > > +	wpt = mtk_uart_apdma_read(c, VFF_WPT);
> > > +	len = mtk_uart_apdma_read(c, VFF_LEN);
> > > +
> > > +	d_wpt = wpt + send;
> > > +	if ((d_wpt & VFF_RING_SIZE) >= len) {
> > > +		d_wpt = d_wpt - len;
> > > +		d_wpt = d_wpt ^ VFF_RING_WRAP;
> > > +	}
> > > +	mtk_uart_apdma_write(c, VFF_WPT, d_wpt);
> > > +
> > > +	c->desc->avail_len -= send;
> > > +
> > > +	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
> > > +	if (mtk_uart_apdma_read(c, VFF_FLUSH) == 0U)
> > > +		mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
> > > +}
> > > +
> > > +static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
> > > +{
> > > +	struct mtk_uart_apdma_desc *d = c->desc;
> > > +	unsigned int len, wg, rg, cnt;
> > > +
> > > +	if ((mtk_uart_apdma_read(c, VFF_VALID_SIZE) == 0U) ||
> > > +		!d || !vchan_next_desc(&c->vc))
> > > +		return;
> > > +
> > > +	len = mtk_uart_apdma_read(c, VFF_LEN);
> > > +	rg = mtk_uart_apdma_read(c, VFF_RPT);
> > > +	wg = mtk_uart_apdma_read(c, VFF_WPT);
> > > +	if ((rg ^ wg) & VFF_RING_WRAP)
> > > +		cnt = (wg & VFF_RING_SIZE) + len - (rg & VFF_RING_SIZE);
> > > +	else
> > > +		cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
> > > +
> > > +	c->rx_status = cnt;
> > > +	mtk_uart_apdma_write(c, VFF_RPT, wg);
> > > +
> > > +	list_del(&d->vd.node);
> > > +	vchan_cookie_complete(&d->vd);
> > > +}
> > 
> > this looks odd, why do you have different rx and tx start routines?
> > 
> 
> Would you like explain it in more detail? thanks.
> In tx function, will wait the last data flush done. and the count the
> size that send.
> In Rx function, will count the size that receive.
> Any way, in rx / tx, need andle WPT or RPT.
> 
Any way, in rx / tx, need handle WPT or RPT.

> > > +static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
> > > +{
> > > +	struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
> > > +	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > > +	u32 tmp;
> > > +	int ret;
> > > +
> > > +	pm_runtime_get_sync(mtkd->ddev.dev);
> > > +
> > > +	mtk_uart_apdma_write(c, VFF_ADDR, 0);
> > > +	mtk_uart_apdma_write(c, VFF_THRE, 0);
> > > +	mtk_uart_apdma_write(c, VFF_LEN, 0);
> > > +	mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);
> > > +
> > > +	ret = readx_poll_timeout(readl, c->base + VFF_EN, tmp,
> > > +			tmp == 0, 10, 100);
> > > +	if (ret) {
> > > +		dev_err(chan->device->dev, "dma reset: fail, timeout\n");
> > > +		return ret;
> > > +	}
> > 
> > register read does reset?
> > 
> 
> 'mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);' is reset. resd just
> poll reset done.
> 
> > > +
> > > +	if (!c->requested) {
> > > +		c->requested = true;
> > > +		ret = request_irq(mtkd->dma_irq[chan->chan_id],
> > > +				  mtk_uart_apdma_irq_handler, IRQF_TRIGGER_NONE,
> > > +				  KBUILD_MODNAME, chan);
> > 
> > why is the irq not requested in driver probe?
> > 
> 
> I have explained in below,
> http://lists.infradead.org/pipermail/linux-mediatek/2018-December/016418.html
> 
> > > +static enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
> > > +					 dma_cookie_t cookie,
> > > +					 struct dma_tx_state *txstate)
> > > +{
> > > +	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > > +	enum dma_status ret;
> > > +	unsigned long flags;
> > > +
> > > +	if (!txstate)
> > > +		return DMA_ERROR;
> > > +
> > > +	ret = dma_cookie_status(chan, cookie, txstate);
> > > +	spin_lock_irqsave(&c->vc.lock, flags);
> > > +	if (ret == DMA_IN_PROGRESS) {
> > > +		c->rx_status = mtk_uart_apdma_read(c, VFF_RPT) & VFF_RING_SIZE;
> > > +		dma_set_residue(txstate, c->rx_status);
> > > +	} else if (ret == DMA_COMPLETE && c->cfg.direction == DMA_DEV_TO_MEM) {
> > 
> > why set reside when it is complete? also reside can be null, that should
> > be checked as well
> > 
> In different status, set different reside.
> 
> > > +static struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
> > > +	(struct dma_chan *chan, struct scatterlist *sgl,
> > > +	unsigned int sglen, enum dma_transfer_direction dir,
> > > +	unsigned long tx_flags, void *context)
> > > +{
> > > +	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > > +	struct mtk_uart_apdma_desc *d;
> > > +
> > > +	if ((dir != DMA_DEV_TO_MEM) &&
> > > +		(dir != DMA_MEM_TO_DEV)) {
> > > +		dev_err(chan->device->dev, "bad direction\n");
> > > +		return NULL;
> > > +	}
> > 
> > we have a macro for this
> 
> Thanks for your suggestion. i will modify it.
> > 
> > > +
> > > +	/* Now allocate and setup the descriptor */
> > > +	d = kzalloc(sizeof(*d), GFP_ATOMIC);
> > > +	if (!d)
> > > +		return NULL;
> > > +
> > > +	/* sglen is 1 */
> > 
> > ?
> > 
> > > +static int mtk_uart_apdma_slave_config(struct dma_chan *chan,
> > > +				struct dma_slave_config *cfg)
> > > +{
> > > +	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > > +	struct mtk_uart_apdmadev *mtkd =
> > > +				to_mtk_uart_apdma_dev(c->vc.chan.device);
> > > +
> > > +	c->cfg = *cfg;
> > > +
> > > +	if (cfg->direction == DMA_DEV_TO_MEM) {
> > 
> > fg->direction is deprecated, in fact I have removed all users recently,
> > please do not use this
> 
> You will remove 'direction' in 'struct dma_slave_config'? if remove, how
> do confirm direction?
> 
> > 
> > > +		unsigned int rx_len = cfg->src_addr_width * 1024;
> > > +
> > > +		mtk_uart_apdma_write(c, VFF_ADDR, cfg->src_addr);
> > > +		mtk_uart_apdma_write(c, VFF_LEN, rx_len);
> > > +		mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(rx_len));
> > > +		mtk_uart_apdma_write(c, VFF_INT_EN,
> > > +				VFF_RX_INT_EN0_B | VFF_RX_INT_EN1_B);
> > > +		mtk_uart_apdma_write(c, VFF_RPT, 0);
> > > +		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_FLAG_CLR_B);
> > > +		mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
> > 
> > why are we writing this here, we are supposed to do that when txn
> > starts!
> > 
> 
> also you can review the link
> http://lists.infradead.org/pipermail/linux-mediatek/2018-December/016418.html
> 
> > > +static int mtk_uart_apdma_device_resume(struct dma_chan *chan)
> > > +{
> > > +	/* just for check caps pass */
> > > +	return 0;
> > > +}
> > 
> > if you do not support this please remove this!
> > 
> > > +static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
> > > +{
> > > +	while (list_empty(&mtkd->ddev.channels) == 0) {
> > > +		struct mtk_chan *c = list_first_entry(&mtkd->ddev.channels,
> > > +			struct mtk_chan, vc.chan.device_node);
> > > +
> > > +		list_del(&c->vc.chan.device_node);
> > > +		tasklet_kill(&c->vc.task);
> > > +	}
> > > +}
> > > +
> > > +static const struct of_device_id mtk_uart_apdma_match[] = {
> > > +	{ .compatible = "mediatek,mt6577-uart-dma", },
> > 
> > where is the binding document for ediatek,mt6577-uart-dma ??
> > 
> 
> http://lists.infradead.org/pipermail/linux-mediatek/2018-December/016154.html
> 

^ permalink raw reply

* [PATCH][V2][resend] tty: fix race between flush_to_ldisc and tty_open
From: Li RongQing @ 2019-01-11  3:03 UTC (permalink / raw)
  To: linux-serial, linux-kernel, jslaby, gregkh, gkohli, alan, robh,
	lirongqing

There still is a race window after the commit b027e2298bd588
("tty: fix data race between tty_init_dev and flush of buf"),
if receive_buf call comes before tty initialization completes
in n_tty_open and tty->driver_data may be NULL.

CPU0                                    CPU1
----                                    ----
                                 n_tty_open
                                   tty_init_dev
                                     tty_ldisc_unlock
                                       schedule
flush_to_ldisc
  n_tty_receive_buf
    uart_flush_chars
      uart_start
      /*tty->driver_data is NULL*/
                                   tty->ops->open
                                   /*init tty->driver_data*/

Extending ldisc semaphore lock in tty_init_dev to driver_data
initialized completely after tty->ops->open().

Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
 drivers/staging/speakup/spk_ttyio.c |  1 +
 drivers/tty/pty.c                   |  2 ++
 drivers/tty/serdev/serdev-ttyport.c |  2 ++
 drivers/tty/tty_io.c                | 14 +++++++++++---
 drivers/tty/tty_ldisc.c             |  1 +
 5 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c
index 979e3ae249c1..c31f08c98383 100644
--- a/drivers/staging/speakup/spk_ttyio.c
+++ b/drivers/staging/speakup/spk_ttyio.c
@@ -155,6 +155,7 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
 	else
 		ret = -ENODEV;
 
+	tty_ldisc_unlock(tty);
 	if (ret) {
 		tty_unlock(tty);
 		return ret;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 00099a8439d2..1b9684d4f718 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -873,9 +873,11 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
+	tty_ldisc_unlock(tty);
 	tty_unlock(tty);
 	return 0;
 err_release:
+	tty_ldisc_unlock(tty);
 	tty_unlock(tty);
 	// This will also put-ref the fsi
 	tty_release(inode, filp);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index fa1672993b4c..ce16cb303e28 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -123,6 +123,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
 	if (ret)
 		goto err_close;
 
+	tty_ldisc_unlock(tty);
 	tty_unlock(serport->tty);
 
 	/* Bring the UART into a known 8 bits no parity hw fc state */
@@ -145,6 +146,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
 err_close:
 	tty->ops->close(tty, NULL);
 err_unlock:
+	tty_ldisc_unlock(tty);
 	tty_unlock(tty);
 	tty_release_struct(tty, serport->tty_idx);
 
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 687250ec8032..199f45e2e1b1 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1351,7 +1351,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 		goto err_release_tty;
-	tty_ldisc_unlock(tty);
 	/* Return the tty locked so that it cannot vanish under the caller */
 	return tty;
 
@@ -1926,7 +1925,7 @@ EXPORT_SYMBOL_GPL(tty_kopen);
  *	  - concurrent tty removal from driver table
  */
 static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
-					     struct file *filp)
+					     struct file *filp, bool *unlock)
 {
 	struct tty_struct *tty;
 	struct tty_driver *driver = NULL;
@@ -1970,6 +1969,7 @@ static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
 		}
 	} else { /* Returns with the tty_lock held for now */
 		tty = tty_init_dev(driver, index);
+		*unlock = true;
 		mutex_unlock(&tty_mutex);
 	}
 out:
@@ -2007,6 +2007,7 @@ static int tty_open(struct inode *inode, struct file *filp)
 	int noctty, retval;
 	dev_t device = inode->i_rdev;
 	unsigned saved_flags = filp->f_flags;
+	bool unlock = false;
 
 	nonseekable_open(inode, filp);
 
@@ -2017,7 +2018,7 @@ static int tty_open(struct inode *inode, struct file *filp)
 
 	tty = tty_open_current_tty(device, filp);
 	if (!tty)
-		tty = tty_open_by_driver(device, inode, filp);
+		tty = tty_open_by_driver(device, inode, filp, &unlock);
 
 	if (IS_ERR(tty)) {
 		tty_free_file(filp);
@@ -2042,6 +2043,10 @@ static int tty_open(struct inode *inode, struct file *filp)
 	if (retval) {
 		tty_debug_hangup(tty, "open error %d, releasing\n", retval);
 
+		if (unlock) {
+			unlock = false;
+			tty_ldisc_unlock(tty);
+		}
 		tty_unlock(tty); /* need to call tty_release without BTM */
 		tty_release(inode, filp);
 		if (retval != -ERESTARTSYS)
@@ -2067,6 +2072,9 @@ static int tty_open(struct inode *inode, struct file *filp)
 		  tty->driver->subtype == PTY_TYPE_MASTER);
 	if (!noctty)
 		tty_open_proc_set_tty(filp, tty);
+
+	if (unlock)
+		tty_ldisc_unlock(tty);
 	tty_unlock(tty);
 	return 0;
 }
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index fc4c97cae01e..dd9b41f66c18 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -339,6 +339,7 @@ void tty_ldisc_unlock(struct tty_struct *tty)
 	clear_bit(TTY_LDISC_HALTED, &tty->flags);
 	__tty_ldisc_unlock(tty);
 }
+EXPORT_SYMBOL_GPL(tty_ldisc_unlock);
 
 static int
 tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
-- 
2.16.2

^ permalink raw reply related

* Re:[PATCH] 8250_pci.c: Only check for communication class in serial_pci_guess_board
From: Guan Yung Tseng @ 2019-01-11  6:18 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Guan Yung Tseng

On Thu, Jan 10, 2019 at 04:12:12PM +0800, Guan Yung Tseng wrote:
> Some multiport serial cards, such as the NI PXI-8430/2, NI PXI-8430/8,
> and NI PXI-8432/4 use PCI_CLASS_COMMUNICATION_OTHER and this fail the
> serial_pci_is_class_communication test added in the commit 7d8905d06405
> ("serial: 8250_pci: Enable device after we check black list").
> 
> Since these devices are correctly listed in serial_pci_tbl, we
> shouldn't need to check the PCI class IDs. This change relocates the
> class checking solely into "serial_pci_guess_board" where it had been
> before so that the class-check doesn't hinder initialization.
> 
> Signed-off-by: Guan Yung Tseng <guan.yung.tseng@ni.com>
> ---
>  drivers/tty/serial/8250/8250_pci.c | 28 +++++++++-------------------
>  1 file changed, 9 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
> index 4986b4a..e33a869 100644
> --- a/drivers/tty/serial/8250/8250_pci.c
> +++ b/drivers/tty/serial/8250/8250_pci.c
> @@ -3382,21 +3382,6 @@ static const struct pci_device_id blacklist[] = {
>  	{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
>  };
>  
> -static int serial_pci_is_class_communication(struct pci_dev *dev)
> -{
> -	/*
> -	 * If it is not a communications device or the programming
> -	 * interface is greater than 6, give up.
> -	 */
> -	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
> -	     ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MULTISERIAL) &&
> -	     ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
> -	    (dev->class & 0xff) > 6)
> -		return -ENODEV;
> -
> -	return 0;
> -}

>
> Noted.
>

Please leave this as a function, no need to move it inside another
function at this point in time.


>  static int serial_pci_is_blacklisted(struct pci_dev *dev)
>  {
>  	const struct pci_device_id *bldev;
> @@ -3427,6 +3412,15 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
>  	int num_iomem, num_port, first_port = -1, i;
>  
>  	/*
> +	 * If it is not a communications device or the programming
> +	 * interface is greater than 6, give up.
> +	 *
> +	 */
> +	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
> +	     ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
> +	    (dev->class & 0xff) > 6)
> +		return -ENODEV;
> +	/*

>
> It was my mistake. I should not remove it.
> I will fix them and submit another patch.
>

what happened to the multiserial check?

You should just call the function here.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v2] 8250_pci.c: Only check for communication class in serial_pci_guess_board
From: Guan Yung Tseng @ 2019-01-11  8:41 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Guan Yung Tseng

Some multiport serial cards, such as the NI PXI-8430/2, NI PXI-8430/8,
and NI PXI-8432/4 use PCI_CLASS_COMMUNICATION_OTHER and this fail the
serial_pci_is_class_communication test added in the commit 7d8905d06405
("serial: 8250_pci: Enable device after we check black list").

Since these devices are correctly listed in serial_pci_tbl, we
shouldn't need to check the PCI class IDs. This change relocates the
class checking solely into "serial_pci_guess_board" where it had been
before so that the class-check doesn't hinder initialization.

Signed-off-by: Guan Yung Tseng <guan.yung.tseng@ni.com>
---
Changes in v2:
  - Remain the serial_pci_is_class_communication
  - Call the serial_pci_is_class_communication in serial_pci_guess_board
    function.

 drivers/tty/serial/8250/8250_pci.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 4986b4a..2ca0694 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -3424,8 +3424,11 @@ static int serial_pci_is_blacklisted(struct pci_dev *dev)
 static int
 serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 {
-	int num_iomem, num_port, first_port = -1, i;
+	int num_iomem, num_port, first_port = -1, i, rc;
 
+	rc = serial_pci_is_class_communication(dev);
+	if (rc)
+		return rc;
 	/*
 	 * Should we try to make guesses for multiport serial devices later?
 	 */
@@ -3652,10 +3655,6 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
 
 	board = &pci_boards[ent->driver_data];
 
-	rc = serial_pci_is_class_communication(dev);
-	if (rc)
-		return rc;
-
 	rc = serial_pci_is_blacklisted(dev);
 	if (rc)
 		return rc;
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] tty/serial: use uart_console_write in the RISC-V SBL early console
From: Anup Patel @ 2019-01-11 11:13 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Greg Kroah-Hartman, Jiri Slaby, Palmer Dabbelt, Albert Ou,
	Atish Patra, Christoph Hellwig, Rob Herring, linux-riscv,
	linux-kernel@vger.kernel.org List, linux-serial
In-Reply-To: <mvmsgy0cu9g.fsf_-_@suse.de>

On Thu, Jan 10, 2019 at 10:41 PM Andreas Schwab <schwab@suse.de> wrote:
>
> This enables proper NLCR processing.
>
> Suggested-by: Anup Patel <anup@brainfault.org>
> Signed-off-by: Andreas Schwab <schwab@suse.de>
> ---
>  drivers/tty/serial/earlycon-riscv-sbi.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c
> index e1a551aae3..ce81523c31 100644
> --- a/drivers/tty/serial/earlycon-riscv-sbi.c
> +++ b/drivers/tty/serial/earlycon-riscv-sbi.c
> @@ -10,13 +10,16 @@
>  #include <linux/serial_core.h>
>  #include <asm/sbi.h>
>
> -static void sbi_console_write(struct console *con,
> -                             const char *s, unsigned int n)
> +static void sbi_putc(struct uart_port *port, int c)
>  {
> -       int i;
> +       sbi_console_putchar(c);
> +}
>
> -       for (i = 0; i < n; ++i)
> -               sbi_console_putchar(s[i]);
> +static void sbi_console_write(struct console *con,
> +                             const char *s, unsigned n)
> +{
> +       struct earlycon_device *dev = con->data;
> +       uart_console_write(&dev->port, s, n, sbi_putc);
>  }
>
>  static int __init early_sbi_setup(struct earlycon_device *device,
> --
> 2.20.1
>
> --
> Andreas Schwab, SUSE Labs, schwab@suse.de
> GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
> "And now for something completely different."

Looks good to me.

Reviewed-by: Anup Patel <anup@brainfault.org>

Regards,
Anup

^ permalink raw reply

* [GIT PULL] TTY/Serial fixes for 5.0-rc2
From: Greg KH @ 2019-01-13 10:23 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Jiri Slaby, Stephen Rothwell, Andrew Morton, linux-kernel,
	linux-serial

The following changes since commit bfeffd155283772bbe78c6a05dec7c0128ee500c:

  Linux 5.0-rc1 (2019-01-06 17:08:20 -0800)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-5.0-rc2

for you to fetch changes up to d3736d82e8169768218ee0ef68718875918091a0:

  tty: Don't hold ldisc lock in tty_reopen() if ldisc present (2019-01-11 17:03:42 +0100)

----------------------------------------------------------------
tty/serial fixes for 5.0-rc2

Here are 2 tty and serial fixes for 5.0-rc2 that resolve some reported
issues.

The first is a simple serial driver fix for a regression that showed up
in 5.0-rc1.  The second one resolves a number of reported issues with
the recent tty locking fixes that went into 5.0-rc1.  Lots of people
have tested the second one and say it resolves their issues.

Both have been in linux-next with no reported issues.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

----------------------------------------------------------------
Dmitry Safonov (1):
      tty: Don't hold ldisc lock in tty_reopen() if ldisc present

Hauke Mehrtens (1):
      serial: lantiq: Do not swap register read/writes

 drivers/tty/serial/lantiq.c | 36 +++++++++++++++++++-----------------
 drivers/tty/tty_io.c        | 20 +++++++++++++-------
 2 files changed, 32 insertions(+), 24 deletions(-)

^ permalink raw reply

* Re: [GIT PULL] TTY/Serial fixes for 5.0-rc2
From: pr-tracker-bot @ 2019-01-13 18:05 UTC (permalink / raw)
  To: Greg KH
  Cc: Linus Torvalds, Jiri Slaby, Stephen Rothwell, Andrew Morton,
	linux-kernel, linux-serial
In-Reply-To: <20190113102316.GA17169@kroah.com>

The pull request you sent on Sun, 13 Jan 2019 11:23:16 +0100:

> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-5.0-rc2

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/437e878a6c48028273e4b06be7e09d235b189e62

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.wiki.kernel.org/userdoc/prtracker

^ permalink raw reply

* Re: Hilscher NetX mach-netx refactorings
From: Linus Walleij @ 2019-01-13 22:39 UTC (permalink / raw)
  To: Ladislav Michl
  Cc: linux-serial, Arnd Bergmann, Robert Schwebel,
	Pengutronix Kernel Team, Olof Johansson, github, Linux ARM
In-Reply-To: <20190113155047.GA12829@lenoch>

On Sun, Jan 13, 2019 at 4:50 PM Ladislav Michl <ladis@linux-mips.org> wrote:
> On Sun, Jan 13, 2019 at 01:14:36PM +0100, Linus Walleij wrote:

> > > On a related note, there does appear to be active work on
> > > newer netx machines that were never upstreamed, see
> > > https://github.com/Hilscher/netx4000-linux/commits/v4.9-netx4000-stable
> >
> > That RS485 addition to PL011 using GPIOs is a bit hacky but
> > looks like very useful for industrial applications.
> > Ladislav, have you been in contact with Hilscher?
>
> I guess I appeared on Cc list because of commit 797537a45450 ("amba-pl011:
> Add RS485 support (ioctl and devicetree)") from above github repo which
> is based on my hack originaly done for rPi3 as I got tired of all those
> experts implementing 'drive enable' in userspace. That's broken by design
> and works only by accident.

I suppose it is one of those GPIO hacks in userspace. Yeah that makes
the GPIO maintainer very unhappy I can tell you that :/

> But as I'm also considering every single
> device running from SD card broken by design - it was perfect match ;-)

Ha ha ;)

> But seriously, it is indeed needed for industrial applications and
> should be done a bit better - I mean regarding those delays in interrupt
> context.

I suppose this thing is a bit of an oddity since the PL011
does have an RTS signal, but in this case (for reasons such
as hardware doesn't do the right thing, or the hardware engineer
didn't care do make it possible to get the RTS line out of the
chip, or the board engineer didn't think of it) a GPIO is used
for RTS instead. So what the patch does is add that as an
option.

There are DT bindings for RTS (etc):
Documentation/devicetree/bindings/serial/serial.txt

I think that GPIO support code could be implemented using
the library in:
drivers/tty/serial/serial_mctrl_gpio.c

This makes it possible to handle any extra "modem control"
pins using GPIO. I think it is fine to just look for RTS if that is all
that's needed. Possibly those extra delay settings could be
added in mctrl and added as generic DT bindings as well.
(I'm not smart enough to tell if that is possible.)

Sorry for the sidetrack.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH 0/3] serdev support for n_gsm
From: Tony Lindgren @ 2019-01-14  1:25 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, Alan Cox, Jiri Slaby, Johan Hovold, Pavel Machek,
	Peter Hurley, Rob Herring, Sebastian Reichel, linux-serial

Hi all,

Here's a series of patches to add initial serdev support to n_gsm
TS 27.010 line discipline.

This allows handling vendor specific protocols on top of TS 27.010 and
allows creating simple serdev drivers where it makes sense. So far I've
tested it with droid 4 for it's modem to provide char devices for AT
ports, modem PM support, and serdev drivers for GNSS and Alsa ASoC.

I'll be posting the related MFD, GNSS and Alsa ASoC drivers separately.
For reference, the MFD driver is at [0], the GNSS driver at [1], and
the Alsa ASoC driver at [2] below.

Regards,

Tony


[0] https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git/tree/drivers/mfd/motorola-mdm.c?h=droid4-pending-mdm-v4.20
[1] https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git/tree/drivers/gnss/motmdm.c?h=droid4-pending-mdm-v4.20
[2] https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git/tree/sound/soc/codecs/motmdm.c?h=droid4-pending-mdm-v4.20


Tony Lindgren (3):
  tty: n_gsm: Add copy_config() and gsm_config() to prepare for serdev
  n_gsm: Constify u8 and unsigned char usage
  tty: n_gsm: Add support for serdev drivers

 drivers/tty/n_gsm.c        | 548 +++++++++++++++++++++++++++++--------
 include/linux/serdev-gsm.h | 227 +++++++++++++++
 2 files changed, 663 insertions(+), 112 deletions(-)
 create mode 100644 include/linux/serdev-gsm.h

-- 
2.20.1

^ permalink raw reply

* [PATCH 1/3] tty: n_gsm: Add copy_config() and gsm_config() to prepare for serdev
From: Tony Lindgren @ 2019-01-14  1:25 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, linux-serial, Alan Cox, Jiri Slaby, Johan Hovold,
	Pavel Machek, Peter Hurley, Rob Herring, Sebastian Reichel
In-Reply-To: <20190114012528.2367-1-tony@atomide.com>

For supporting serdev drivers, we need to be able to configure n_gsm
from drivers. Let's prepare for that by adding copy_config() and
gsm_config() helper functions by moving the code around a bit.

Let's also unify the comments to keep checkpatch happy while at it.

Cc: linux-serial@vger.kernel.org
Cc: Alan Cox <alan@llwyncelyn.cymru>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Johan Hovold <johan@kernel.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/tty/n_gsm.c | 207 +++++++++++++++++++++++---------------------
 1 file changed, 107 insertions(+), 100 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2214,6 +2214,111 @@ static struct gsm_mux *gsm_alloc_mux(void)
 	return gsm;
 }
 
+static void gsm_copy_config_values(struct gsm_mux *gsm,
+				   struct gsm_config *c)
+{
+	memset(c, 0, sizeof(*c));
+	c->adaption = gsm->adaption;
+	c->encapsulation = gsm->encoding;
+	c->initiator = gsm->initiator;
+	c->t1 = gsm->t1;
+	c->t2 = gsm->t2;
+	c->t3 = 0;	/* Not supported */
+	c->n2 = gsm->n2;
+	if (gsm->ftype == UIH)
+		c->i = 1;
+	else
+		c->i = 2;
+	pr_debug("Ftype %d i %d\n", gsm->ftype, c->i);
+	c->mru = gsm->mru;
+	c->mtu = gsm->mtu;
+	c->k = 0;
+}
+
+static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
+{
+	int need_close = 0;
+	int need_restart = 0;
+
+	/* Stuff we don't support yet - UI or I frame transport, windowing */
+	if ((c->adaption != 1 && c->adaption != 2) || c->k)
+		return -EOPNOTSUPP;
+	/* Check the MRU/MTU range looks sane */
+	if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+		return -EINVAL;
+	if (c->n2 < 3)
+		return -EINVAL;
+	if (c->encapsulation > 1)	/* Basic, advanced, no I */
+		return -EINVAL;
+	if (c->initiator > 1)
+		return -EINVAL;
+	if (c->i == 0 || c->i > 2)	/* UIH and UI only */
+		return -EINVAL;
+	/*
+	 * See what is needed for reconfiguration
+	 */
+
+	/* Timing fields */
+	if (c->t1 != 0 && c->t1 != gsm->t1)
+		need_restart = 1;
+	if (c->t2 != 0 && c->t2 != gsm->t2)
+		need_restart = 1;
+	if (c->encapsulation != gsm->encoding)
+		need_restart = 1;
+	if (c->adaption != gsm->adaption)
+		need_restart = 1;
+	/* Requires care */
+	if (c->initiator != gsm->initiator)
+		need_close = 1;
+	if (c->mru != gsm->mru)
+		need_restart = 1;
+	if (c->mtu != gsm->mtu)
+		need_restart = 1;
+
+	/*
+	 * Close down what is needed, restart and initiate the new
+	 * configuration
+	 */
+
+	if (need_close || need_restart) {
+		int ret;
+
+		ret = gsm_disconnect(gsm);
+
+		if (ret)
+			return ret;
+	}
+	if (need_restart)
+		gsm_cleanup_mux(gsm);
+
+	gsm->initiator = c->initiator;
+	gsm->mru = c->mru;
+	gsm->mtu = c->mtu;
+	gsm->encoding = c->encapsulation;
+	gsm->adaption = c->adaption;
+	gsm->n2 = c->n2;
+
+	if (c->i == 1)
+		gsm->ftype = UIH;
+	else if (c->i == 2)
+		gsm->ftype = UI;
+
+	if (c->t1)
+		gsm->t1 = c->t1;
+	if (c->t2)
+		gsm->t2 = c->t2;
+
+	/*
+	 * FIXME: We need to separate activation/deactivation from adding
+	 * and removing from the mux array
+	 */
+	if (need_restart)
+		gsm_activate_mux(gsm);
+	if (gsm->initiator && need_close)
+		gsm_dlci_begin_open(gsm->dlci[0]);
+	return 0;
+}
+
 /**
  *	gsmld_output		-	write to link
  *	@gsm: our mux
@@ -2495,89 +2600,6 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file,
 	return mask;
 }
 
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
-							struct gsm_config *c)
-{
-	int need_close = 0;
-	int need_restart = 0;
-
-	/* Stuff we don't support yet - UI or I frame transport, windowing */
-	if ((c->adaption != 1 && c->adaption != 2) || c->k)
-		return -EOPNOTSUPP;
-	/* Check the MRU/MTU range looks sane */
-	if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
-		return -EINVAL;
-	if (c->n2 < 3)
-		return -EINVAL;
-	if (c->encapsulation > 1)	/* Basic, advanced, no I */
-		return -EINVAL;
-	if (c->initiator > 1)
-		return -EINVAL;
-	if (c->i == 0 || c->i > 2)	/* UIH and UI only */
-		return -EINVAL;
-	/*
-	 *	See what is needed for reconfiguration
-	 */
-
-	/* Timing fields */
-	if (c->t1 != 0 && c->t1 != gsm->t1)
-		need_restart = 1;
-	if (c->t2 != 0 && c->t2 != gsm->t2)
-		need_restart = 1;
-	if (c->encapsulation != gsm->encoding)
-		need_restart = 1;
-	if (c->adaption != gsm->adaption)
-		need_restart = 1;
-	/* Requires care */
-	if (c->initiator != gsm->initiator)
-		need_close = 1;
-	if (c->mru != gsm->mru)
-		need_restart = 1;
-	if (c->mtu != gsm->mtu)
-		need_restart = 1;
-
-	/*
-	 *	Close down what is needed, restart and initiate the new
-	 *	configuration
-	 */
-
-	if (need_close || need_restart) {
-		int ret;
-
-		ret = gsm_disconnect(gsm);
-
-		if (ret)
-			return ret;
-	}
-	if (need_restart)
-		gsm_cleanup_mux(gsm);
-
-	gsm->initiator = c->initiator;
-	gsm->mru = c->mru;
-	gsm->mtu = c->mtu;
-	gsm->encoding = c->encapsulation;
-	gsm->adaption = c->adaption;
-	gsm->n2 = c->n2;
-
-	if (c->i == 1)
-		gsm->ftype = UIH;
-	else if (c->i == 2)
-		gsm->ftype = UI;
-
-	if (c->t1)
-		gsm->t1 = c->t1;
-	if (c->t2)
-		gsm->t2 = c->t2;
-
-	/* FIXME: We need to separate activation/deactivation from adding
-	   and removing from the mux array */
-	if (need_restart)
-		gsm_activate_mux(gsm);
-	if (gsm->initiator && need_close)
-		gsm_dlci_begin_open(gsm->dlci[0]);
-	return 0;
-}
-
 static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
@@ -2586,29 +2608,14 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
 
 	switch (cmd) {
 	case GSMIOC_GETCONF:
-		memset(&c, 0, sizeof(c));
-		c.adaption = gsm->adaption;
-		c.encapsulation = gsm->encoding;
-		c.initiator = gsm->initiator;
-		c.t1 = gsm->t1;
-		c.t2 = gsm->t2;
-		c.t3 = 0;	/* Not supported */
-		c.n2 = gsm->n2;
-		if (gsm->ftype == UIH)
-			c.i = 1;
-		else
-			c.i = 2;
-		pr_debug("Ftype %d i %d\n", gsm->ftype, c.i);
-		c.mru = gsm->mru;
-		c.mtu = gsm->mtu;
-		c.k = 0;
+		gsm_copy_config_values(gsm, &c);
 		if (copy_to_user((void *)arg, &c, sizeof(c)))
 			return -EFAULT;
 		return 0;
 	case GSMIOC_SETCONF:
 		if (copy_from_user(&c, (void *)arg, sizeof(c)))
 			return -EFAULT;
-		return gsmld_config(tty, gsm, &c);
+		return gsm_config(gsm, &c);
 	default:
 		return n_tty_ioctl_helper(tty, file, cmd, arg);
 	}
-- 
2.20.1

^ permalink raw reply

* [PATCH 2/3] n_gsm: Constify u8 and unsigned char usage
From: Tony Lindgren @ 2019-01-14  1:25 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, linux-serial, Alan Cox, Jiri Slaby, Johan Hovold,
	Pavel Machek, Peter Hurley, Rob Herring, Sebastian Reichel
In-Reply-To: <20190114012528.2367-1-tony@atomide.com>

In order to prepare for adding serdev driver support, let's constify
the use of u8 and unsigned char for n_gsm.

Note that gsm_control_modem() gsm_control_rls() read the data for tty
control characters and then call gsm_control_reply() that allocates a
new reply and copies the data.

Cc: linux-serial@vger.kernel.org
Cc: Alan Cox <alan@llwyncelyn.cymru>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Johan Hovold <johan@kernel.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/tty/n_gsm.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -143,8 +143,8 @@ struct gsm_dlci {
 	struct sk_buff *skb;	/* Frame being sent */
 	struct sk_buff_head skb_list;	/* Queued frames */
 	/* Data handling callback */
-	void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
-	void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len);
+	void (*data)(struct gsm_dlci *dlci, const u8 *data, int len);
+	void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len);
 	struct net_device *net; /* network interface, if created */
 };
 
@@ -988,7 +988,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
  *	Encode up and queue a UI/UIH frame containing our response.
  */
 
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
+static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
 					int dlen)
 {
 	struct gsm_msg *msg;
@@ -1073,14 +1073,14 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
  *	and if need be stuff a break message down the tty.
  */
 
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
+static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
 {
 	unsigned int addr = 0;
 	unsigned int modem = 0;
 	unsigned int brk = 0;
 	struct gsm_dlci *dlci;
 	int len = clen;
-	u8 *dp = data;
+	const u8 *dp = data;
 	struct tty_struct *tty;
 
 	while (gsm_read_ea(&addr, *dp++) == 0) {
@@ -1134,13 +1134,13 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
  *	this into the uplink tty if present
  */
 
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
+static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
 {
 	struct tty_port *port;
 	unsigned int addr = 0;
 	u8 bits;
 	int len = clen;
-	u8 *dp = data;
+	const u8 *dp = data;
 
 	while (gsm_read_ea(&addr, *dp++) == 0) {
 		len--;
@@ -1189,7 +1189,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
  */
 
 static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
-							u8 *data, int clen)
+						const u8 *data, int clen)
 {
 	u8 buf[1];
 	unsigned long flags;
@@ -1261,7 +1261,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
  */
 
 static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
-							u8 *data, int clen)
+						const u8 *data, int clen)
 {
 	struct gsm_control *ctrl;
 	unsigned long flags;
@@ -1553,7 +1553,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
  *	open we shovel the bits down it, if not we drop them.
  */
 
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
+static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
 {
 	/* krefs .. */
 	struct tty_port *port = &dlci->port;
@@ -1603,7 +1603,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
  *	and we divide up the work accordingly.
  */
 
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
+static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
 {
 	/* See what command is involved */
 	unsigned int command = 0;
@@ -2702,7 +2702,7 @@ static void gsm_mux_net_tx_timeout(struct net_device *net)
 }
 
 static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
-				   unsigned char *in_buf, int size)
+				const unsigned char *in_buf, int size)
 {
 	struct net_device *net = dlci->net;
 	struct sk_buff *skb;
-- 
2.20.1

^ permalink raw reply

* [PATCH 3/3] tty: n_gsm: Add support for serdev drivers
From: Tony Lindgren @ 2019-01-14  1:25 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, linux-serial, Alan Cox, Jiri Slaby, Johan Hovold,
	Pavel Machek, Peter Hurley, Rob Herring, Sebastian Reichel
In-Reply-To: <20190114012528.2367-1-tony@atomide.com>

We can make use of serdev drivers to do simple device drivers for
TS 27.010 chanels, and we can handle vendor specific protocols on top
of TS 27.010 with serdev drivers.

Serdev device drivers can be done for channel specific features, such
as GNSS framework and Alsa ASoC voice call audio mixer found on some
modems. And serdev drivers can be used to provide character devices
for things like AT modems on TS 27.010 channels.

So far this has been tested with Motorola droid4 where there is a custom
packet numbering protocol on top of TS 27.010 for the MDM6600 modem. I'll
be posting the motorola-mdm MFD driver separately followed by channel
specific drivers for Alsa ASoC and GNSS frameworks.

I initially though about adding the serdev support into a separate file,
but that will take some refactoring of n_gsm.c. And I'd like to have
things working first. Then later on we might want to consider splitting
n_gsm.c into three pieces for core, tty and serdev parts.

Cc: linux-serial@vger.kernel.org
Cc: Alan Cox <alan@llwyncelyn.cymru>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Johan Hovold <johan@kernel.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/tty/n_gsm.c        | 317 +++++++++++++++++++++++++++++++++++++
 include/linux/serdev-gsm.h | 227 ++++++++++++++++++++++++++
 2 files changed, 544 insertions(+)
 create mode 100644 include/linux/serdev-gsm.h

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -39,6 +39,7 @@
 #include <linux/file.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
+#include <linux/serdev.h>
 #include <linux/timer.h>
 #include <linux/tty_flip.h>
 #include <linux/tty_driver.h>
@@ -50,6 +51,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/gsmmux.h>
+#include <linux/serdev-gsm.h>
 
 static int debug;
 module_param(debug, int, 0600);
@@ -145,6 +147,7 @@ struct gsm_dlci {
 	/* Data handling callback */
 	void (*data)(struct gsm_dlci *dlci, const u8 *data, int len);
 	void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len);
+	struct gsm_serdev_dlci *ops; /* serdev dlci ops, if used */
 	struct net_device *net; /* network interface, if created */
 };
 
@@ -179,6 +182,7 @@ struct gsm_control {
  */
 
 struct gsm_mux {
+	struct gsm_serdev *gsd;		/* Serial device bus data */
 	struct tty_struct *tty;		/* The tty our ldisc is bound to */
 	spinlock_t lock;
 	struct mutex mutex;
@@ -2319,6 +2323,319 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
 	return 0;
 }
 
+#ifdef CONFIG_SERIAL_DEV_BUS
+static int gsd_get_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	struct gsm_mux *gsm;
+
+	if (!gsd || !gsd->gsm)
+		return -ENODEV;
+
+	gsm = gsd->gsm;
+
+	if (!c)
+		return -EINVAL;
+
+	gsm_copy_config_values(gsm, c);
+
+	return 0;
+}
+
+static int gsd_set_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	struct gsm_mux *gsm;
+
+	if (!gsd || !gsd->serdev || !gsd->gsm)
+		return -ENODEV;
+
+	gsm = gsd->gsm;
+
+	if (!c)
+		return -EINVAL;
+
+	return gsm_config(gsm, c);
+}
+
+static struct gsm_dlci *gsd_dlci_get(struct gsm_serdev *gsd, int line,
+				     bool allocate)
+{
+	struct gsm_mux *gsm;
+	struct gsm_dlci *dlci;
+
+	if (!gsd || !gsd->gsm)
+		return ERR_PTR(-ENODEV);
+
+	gsm = gsd->gsm;
+
+	if (line < 1 || line >= 63)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&gsm->mutex);
+
+	if (gsm->dlci[line]) {
+		dlci = gsm->dlci[line];
+		goto unlock;
+	} else if (!allocate) {
+		dlci = ERR_PTR(-ENODEV);
+		goto unlock;
+	}
+
+	dlci = gsm_dlci_alloc(gsm, line);
+	if (!dlci) {
+		gsm = ERR_PTR(-ENOMEM);
+		goto unlock;
+	}
+
+	gsm->dlci[line] = dlci;
+
+unlock:
+	mutex_unlock(&gsm->mutex);
+
+	return dlci;
+}
+
+static void gsd_dlci_data(struct gsm_dlci *dlci, const u8 *buf, int len)
+{
+	struct gsm_mux *gsm = dlci->gsm;
+	struct gsm_serdev *gsd = gsm->gsd;
+
+	if (!gsd || !dlci->ops)
+		return;
+
+	switch (dlci->adaption) {
+	case 0:
+	case 1:
+		if (dlci->ops->receive_buf)
+			dlci->ops->receive_buf(dlci->ops, buf, len);
+		break;
+	default:
+		pr_warn("dlci%i adaption %i not yet implemented\n",
+			dlci->addr, dlci->adaption);
+		break;
+	}
+}
+
+static int gsd_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *sd,
+		     const u8 *buf, int len)
+{
+	struct gsm_mux *gsm;
+	struct gsm_dlci *dlci;
+	struct gsm_msg *msg;
+	int h, size, total_size = 0;
+	u8 *dp;
+
+	if (!gsd || !gsd->gsm)
+		return -ENODEV;
+
+	gsm = gsd->gsm;
+
+	dlci = gsd_dlci_get(gsd, sd->line, false);
+	if (IS_ERR(dlci))
+		return PTR_ERR(dlci);
+
+	h = dlci->adaption - 1;
+
+	if (len > gsm->mtu)
+		len = gsm->mtu;
+
+	size = len + h;
+
+	msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+	if (!msg)
+		return -ENOMEM;
+
+	dp = msg->data;
+	switch (dlci->adaption) {
+	case 1:
+		break;
+	case 2:
+		*dp++ = gsm_encode_modem(dlci);
+		break;
+	}
+	memcpy(dp, buf, len);
+	__gsm_data_queue(dlci, msg);
+	total_size += size;
+
+	return total_size;
+}
+
+static void gsd_data_kick(struct gsm_serdev *gsd)
+{
+	struct gsm_mux *gsm;
+	unsigned long flags;
+
+	if (!gsd || !gsd->gsm)
+		return;
+
+	gsm = gsd->gsm;
+
+	spin_lock_irqsave(&gsm->tx_lock, flags);
+	gsm_data_kick(gsm);
+	spin_unlock_irqrestore(&gsm->tx_lock, flags);
+}
+
+static int gsd_register_dlci(struct gsm_serdev *gsd,
+			     struct gsm_serdev_dlci *ops)
+{
+	struct gsm_dlci *dlci;
+	struct gsm_mux *gsm;
+
+	if (!gsd || !gsd->gsm || !gsd->serdev)
+		return -ENODEV;
+
+	gsm = gsd->gsm;
+
+	if (!ops || !ops->line || !ops->receive_buf)
+		return -EINVAL;
+
+	dlci = gsd_dlci_get(gsd, ops->line, true);
+	if (IS_ERR(dlci))
+		return PTR_ERR(dlci);
+
+	if (dlci->state == DLCI_OPENING || dlci->state == DLCI_OPEN ||
+	    dlci->state == DLCI_CLOSING)
+		return -EBUSY;
+
+	mutex_lock(&dlci->mutex);
+	dlci->ops = ops;
+	dlci->modem_rx = 0;
+	dlci->prev_data = dlci->data;
+	dlci->data = gsd_dlci_data;
+	mutex_unlock(&dlci->mutex);
+
+	gsm_dlci_begin_open(dlci);
+
+	return 0;
+}
+
+static void gsd_unregister_dlci(struct gsm_serdev *gsd,
+				struct gsm_serdev_dlci *ops)
+{
+	struct gsm_mux *gsm;
+	struct gsm_dlci *dlci;
+
+	if (!gsd || !gsd->gsm || !gsd->serdev || !gsd->unregister_dlci)
+		return;
+
+	gsm = gsd->gsm;
+
+	if (!ops || !ops->line)
+		return;
+
+	dlci = gsd_dlci_get(gsd, ops->line, false);
+	if (IS_ERR(dlci))
+		return;
+
+	mutex_lock(&dlci->mutex);
+	gsm_destroy_network(dlci);
+	dlci->data = dlci->prev_data;
+	dlci->ops = NULL;
+	mutex_unlock(&dlci->mutex);
+
+	gsm_dlci_begin_close(dlci);
+}
+
+static int gsm_serdev_output(struct gsm_mux *gsm, u8 *data, int len)
+{
+	struct gsm_serdev *gsd = gsm->gsd;
+	struct serdev_device *serdev = gsm->gsd->serdev;
+	bool asleep;
+
+	asleep = atomic_read(&gsd->asleep);
+	if (asleep)
+		return -ENOSPC;
+
+	if (gsm->gsd->output)
+		return gsm->gsd->output(gsm->gsd, data, len);
+	else
+		return serdev_device_write_buf(serdev, data, len);
+}
+
+static int gsd_receive_buf(struct serdev_device *serdev, const u8 *data,
+			   size_t count)
+{
+	struct gsm_serdev *gsd = serdev_device_get_drvdata(serdev);
+	struct gsm_mux *gsm;
+	const unsigned char *dp;
+	int i;
+
+	if (WARN_ON(!gsd))
+		return 0;
+
+	gsm = gsd->gsm;
+
+	if (debug & 4)
+		print_hex_dump_bytes("gsd_receive_buf: ",
+				     DUMP_PREFIX_OFFSET,
+				     data, count);
+
+	for (i = count, dp = data; i; i--, dp++)
+		gsm->receive(gsm, *dp);
+
+	return count;
+}
+
+static void gsd_write_wakeup(struct serdev_device *serdev)
+{
+	serdev_device_write_wakeup(serdev);
+}
+
+static struct serdev_device_ops gsd_client_ops = {
+	.receive_buf = gsd_receive_buf,
+	.write_wakeup = gsd_write_wakeup,
+};
+
+int gsm_serdev_register_device(struct gsm_serdev *gsd)
+{
+	struct gsm_mux *gsm;
+	int error;
+
+	if (WARN(!gsd || !gsd->serdev || !gsd->output,
+		 "serdev and output must be initialized\n"))
+		return -EINVAL;
+
+	serdev_device_set_client_ops(gsd->serdev, &gsd_client_ops);
+
+	gsm = gsm_alloc_mux();
+	if (!gsm)
+		return -ENOMEM;
+
+	gsm->encoding = 1;
+	gsm->tty = NULL;
+	gsm->gsd = gsd;
+	atomic_set(&gsd->asleep, 0);
+	gsd->gsm = gsm;
+	gsd->get_config = gsd_get_config;
+	gsd->set_config = gsd_set_config;
+	gsd->register_dlci = gsd_register_dlci;
+	gsd->unregister_dlci = gsd_unregister_dlci;
+	gsm->output = gsm_serdev_output;
+	gsd->write = gsd_write;
+	gsd->kick = gsd_data_kick;
+	mux_get(gsd->gsm);
+
+	error = gsm_activate_mux(gsd->gsm);
+	if (error) {
+		gsm_cleanup_mux(gsd->gsm);
+		mux_put(gsd->gsm);
+
+		return error;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gsm_serdev_register_device);
+
+void gsm_serdev_unregister_device(struct gsm_serdev *gsd)
+{
+	gsm_cleanup_mux(gsd->gsm);
+	mux_put(gsd->gsm);
+	gsd->gsm = NULL;
+}
+EXPORT_SYMBOL_GPL(gsm_serdev_unregister_device);
+
+#endif	/* CONFIG_SERIAL_DEV_BUS */
+
 /**
  *	gsmld_output		-	write to link
  *	@gsm: our mux
diff --git a/include/linux/serdev-gsm.h b/include/linux/serdev-gsm.h
new file mode 100644
--- /dev/null
+++ b/include/linux/serdev-gsm.h
@@ -0,0 +1,227 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+struct serdev_device;
+struct gsm_mux;
+struct gsm_config;
+struct gsm_dlci;
+struct gsm_serdev_dlci;
+
+/**
+ * struct gsm_serdev - serdev-gsm instance
+ * @serdev:		serdev instance
+ * @gsm:		ts 27.010 n_gsm instance
+ * @asleep:		device is in idle state
+ * @drvdata:		serdev-gsm consumer driver data
+ * @get_config:		get ts 27.010 config
+ * @set_config:		set ts 27.010 config
+ * @register_dlci:	register ts 27.010 channel
+ * @unregister_dlci:	unregister ts 27.010 channel
+ * @output:		read data from ts 27.010 channel
+ * @write:		write data to a ts 27.010 channel
+ * @kick:		indicate more data is ready
+ *
+ * Currently only serdev and output must be initialized, the rest are
+ * are initialized by gsm_serdev_register_dlci().
+ */
+struct gsm_serdev {
+	struct serdev_device *serdev;
+	struct gsm_mux *gsm;
+	atomic_t asleep;
+	void *drvdata;
+	int (*get_config)(struct gsm_serdev *gsd, struct gsm_config *c);
+	int (*set_config)(struct gsm_serdev *gsd, struct gsm_config *c);
+	int (*register_dlci)(struct gsm_serdev *gsd,
+			     struct gsm_serdev_dlci *ops);
+	void (*unregister_dlci)(struct gsm_serdev *gsd,
+				struct gsm_serdev_dlci *ops);
+	int (*output)(struct gsm_serdev *gsd, u8 *data, int len);
+	int (*write)(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+		     const u8 *buf, int len);
+	void (*kick)(struct gsm_serdev *gsd);
+};
+
+/**
+ * struct gsm_serdev_dlci - serdev-gsm ts 27.010 channel data
+ * @line:		ts 27.010 channel, control channel 0 is not available
+ * @receive_buf:	function to handle data received for the channel
+ */
+struct gsm_serdev_dlci {
+	int line;
+	int (*receive_buf)(struct gsm_serdev_dlci *ops,
+			   const unsigned char *buf,
+			   size_t len);
+};
+
+#ifdef CONFIG_SERIAL_DEV_BUS
+
+int gsm_serdev_register_device(struct gsm_serdev *gsd);
+void gsm_serdev_unregister_device(struct gsm_serdev *gsd);
+
+static inline void *gsm_serdev_get_drvdata(struct device *dev)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+	struct gsm_serdev *gsd = serdev_device_get_drvdata(serdev);
+
+	if (gsd)
+		return gsd->drvdata;
+
+	return NULL;
+}
+
+static inline void gsm_serdev_set_drvdata(struct device *dev, void *drvdata)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+	struct gsm_serdev *gsd = serdev_device_get_drvdata(serdev);
+
+	if (gsd)
+		gsd->drvdata = drvdata;
+}
+
+/**
+ * gsm_serdev_get_config - read ts 27.010 config
+ * @gsd:	serdev-gsm instance
+ * @c:		ts 27.010 config data
+ *
+ * See gsm_copy_config_values() for more information.
+ */
+static inline
+int gsm_serdev_get_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	return gsd->get_config(gsd, c);
+}
+
+/**
+ * gsm_serdev_set_config - set ts 27.010 config
+ * @gsd:	serdev-gsm instance
+ * @c:		ts 27.010 config data
+ *
+ * See gsm_config() for more information.
+ */
+static inline
+int gsm_serdev_set_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	if (gsd && gsd->set_config)
+		return gsd->set_config(gsd, c);
+
+	return -ENODEV;
+}
+
+/**
+ * gsm_serdev_register_dlci - register a ts 27.010 channel
+ * @gsd:	serdev-gsm instance
+ * @ops:	channel ops
+ */
+static inline
+int gsm_serdev_register_dlci(struct gsm_serdev *gsd,
+			     struct gsm_serdev_dlci *ops)
+{
+	if (gsd && gsd->register_dlci)
+		return gsd->register_dlci(gsd, ops);
+
+	return -ENODEV;
+}
+
+/**
+ * gsm_serdev_unregister_dlci - unregister a ts 27.010 channel
+ * @gsd:	serdev-gsm instance
+ * @ops:	channel ops
+ */
+static inline
+void gsm_serdev_unregister_dlci(struct gsm_serdev *gsd,
+				struct gsm_serdev_dlci *ops)
+{
+	if (gsd && gsd->unregister_dlci)
+		gsd->unregister_dlci(gsd, ops);
+}
+
+/**
+ * gsm_serdev_write - write data to a ts 27.010 channel
+ * @gsd:	serdev-gsm instance
+ * @ops:	channel ops
+ * @buf:	write buffer
+ * @len:	buffer length
+ */
+static inline
+int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+		     const u8 *buf, int len)
+{
+	if (gsd && gsd->write)
+		return gsd->write(gsd, ops, buf, len);
+
+	return -ENODEV;
+}
+
+/**
+ * gsm_serdev_data_kick - indicate more data can be trasmitted
+ * @gsd:	serdev-gsm instance
+ *
+ * See gsm_data_kick() for more information.
+ */
+static inline
+void gsm_serdev_data_kick(struct gsm_serdev *gsd)
+{
+	if (gsd && gsd->kick)
+		gsd->kick(gsd);
+}
+
+#else	/* CONFIG_SERIAL_DEV_BUS */
+
+static inline
+int gsm_serdev_register_device(struct gsm_serdev *gsd)
+{
+	return -ENODEV;
+}
+
+static inline
+void gsm_serdev_unregister_device(struct gsm_serdev *gsd)
+{
+}
+
+static inline void *gsm_serdev_get_drvdata(struct device *dev)
+{
+	return NULL;
+}
+
+static inline
+void gsm_serdev_set_drvdata(struct device *dev, void *drvdata)
+{
+}
+
+static inline
+int gsm_serdev_get_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	return -ENODEV;
+}
+
+static inline
+int gsm_serdev_set_config(struct gsm_serdev *gsd, struct gsm_config *c)
+{
+	return -ENODEV;
+}
+
+static inline
+int gsm_serdev_register_dlci(struct gsm_serdev *gsd,
+			     struct gsm_serdev_dlci *ops)
+{
+	return -ENODEV;
+}
+
+static inline
+void gsm_serdev_unregister_dlci(struct gsm_serdev *gsd,
+				struct gsm_serdev_dlci *ops)
+{
+}
+
+static inline
+int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+		     const u8 *buf, int len)
+{
+	return -ENODEV;
+}
+
+static inline
+void gsm_serdev_data_kick(struct gsm_serdev *gsd)
+{
+}
+
+#endif	/* CONFIG_SERIAL_DEV_BUS */
-- 
2.20.1

^ permalink raw reply

* [PATCH] tty: not call tty close in fallback
From: yes @ 2019-01-14  6:56 UTC (permalink / raw)
  To: robh, gregkh, jslaby, linux-serial, linux-kernel

From: Li RongQing <lirongqing@baidu.com>

when fail to open tty, tty is not in open status and not need
to call close

Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
 drivers/tty/serdev/serdev-ttyport.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index fa1672993b4c..bcc1e27d00de 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -121,7 +121,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
 
 	ret = tty->ops->open(serport->tty, NULL);
 	if (ret)
-		goto err_close;
+		goto err_unlock;
 
 	tty_unlock(serport->tty);
 
@@ -142,8 +142,6 @@ static int ttyport_open(struct serdev_controller *ctrl)
 
 	return 0;
 
-err_close:
-	tty->ops->close(tty, NULL);
 err_unlock:
 	tty_unlock(tty);
 	tty_release_struct(tty, serport->tty_idx);
-- 
2.16.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox