Linux Serial subsystem development
 help / color / mirror / Atom feed
* [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

* Re: [PATCH] tty: not call tty close in fallback
From: Jiri Slaby @ 2019-01-14  7:20 UTC (permalink / raw)
  To: yes, robh, gregkh, linux-kernel, linux-serial
In-Reply-To: <1547448961-9588-1-git-send-email-yes>

On 14. 01. 19, 7:56, yes@hpe.com wrote:
> From: Li RongQing <lirongqing@baidu.com>
> 
> when fail to open tty, tty is not in open status and not need
> to call close

But tty drivers are special and expect close even on failed open, right?
See tty_open.

> 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);
> 

thanks,
-- 
js
suse labs

^ permalink raw reply

* Re: [PATCH] tty: not call tty close in fallback
From: Jiri Slaby @ 2019-01-14  7:51 UTC (permalink / raw)
  To: lirongqing, robh, gregkh, linux-kernel, linux-serial
In-Reply-To: <1547448961-9588-1-git-send-email-yes>

yes@hpe.com:

550 5.1.1 User Unknown

You are sending e-mails/patches from a non-existant address?

On 14. 01. 19, 7:56, yes@hpe.com wrote:
> From: Li RongQing <lirongqing@baidu.com>
> 
> when fail to open tty, tty is not in open status and not need
> to call close

But tty drivers are special and expect close even on failed open, right?
See tty_open.

> 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);
> 

thanks,
-- 
js
suse labs

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: serial: Convert snps,dw-apb-uart to json-schema
From: Simon Horman @ 2019-01-14  9:30 UTC (permalink / raw)
  To: Rob Herring; +Cc: devicetree, linux-kernel, Greg Kroah-Hartman, linux-serial
In-Reply-To: <20190110222017.6390-1-robh@kernel.org>

On Thu, Jan 10, 2019 at 04:20:16PM -0600, Rob Herring wrote:
> 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.

I believe the documentation of the Renesas compatible strings is also new
in this file. Perhaps it would be worth mentioning that too.

In any case

Reviewed-by: 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>
> ---
>  .../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>;
> +    };
> +...

^ permalink raw reply

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

On Thu, Jan 10, 2019 at 04:20:17PM -0600, Rob Herring wrote:
> 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.

This confused me slightly as this patch removes renesas,rzn1-uart.txt
but doesn't add the renesas bindings elsewhere. I now see that is done
in patch 1/2, which is fine. But it might be worth rewording the changelog.

That notwithstanding:

Reviewed-by: Simon Horman <horms+renesas@verge.net.au>


> 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

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

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

On Sun 2019-01-13 17:25:25, Tony Lindgren wrote:
> 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.

For the series:

Acked-by: Pavel Machek <pavel@ucw.cz>

Thanks for doing this!
								Pavel
								
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* [PATCH] 8250_pci.c: Update NI specific devices class to multi serial
From: Guan Yung Tseng @ 2019-01-14 14:10 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Guan Yung Tseng

Modified NI devices class to PCI_CLASS_COMMUNICATION_MULTISERIAL.
The reason of doing this is because all NI multi port serial cards
use PCI_CLASS_COMMUNICATION_OTHER class and thus fail the
serial_pci_is_class_communication test added in the commit 7d8905d06405
("serial: 8250_pci: Enable device after we check black list").

Signed-off-by: Guan Yung Tseng <guan.yung.tseng@ni.com>
---
 drivers/tty/serial/8250/8250_pci.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 4986b4a..0949db1 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -663,6 +663,13 @@ static int pci_xircom_init(struct pci_dev *dev)
 	return 0;
 }
 
+static int pci_ni_probe(struct pci_dev *dev)
+{
+	dev->class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8 |
+			(dev->class & 0xff);
+	return 0;
+}
+
 static int pci_ni8420_init(struct pci_dev *dev)
 {
 	void __iomem *p;
@@ -1850,6 +1857,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI23216,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1859,6 +1867,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2328,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1868,6 +1877,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1877,6 +1887,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1886,6 +1897,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2324I,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1895,6 +1907,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2322I,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1904,6 +1917,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_23216,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1913,6 +1927,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2328,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1922,6 +1937,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1931,6 +1947,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1940,6 +1957,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8422_2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1949,6 +1967,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8422_2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1958,6 +1977,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_ANY_ID,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8430_init,
 		.setup		= pci_ni8430_setup,
 		.exit		= pci_ni8430_exit,
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH 1/2] dt-bindings: serial: Convert snps,dw-apb-uart to json-schema
From: Rob Herring @ 2019-01-14 16:23 UTC (permalink / raw)
  To: Simon Horman
  Cc: devicetree, linux-kernel@vger.kernel.org, Greg Kroah-Hartman,
	open list:SERIAL DRIVERS
In-Reply-To: <20190114093022.hjouckoss2zemefg@verge.net.au>

On Mon, Jan 14, 2019 at 3:30 AM Simon Horman <horms@verge.net.au> wrote:
>
> On Thu, Jan 10, 2019 at 04:20:16PM -0600, Rob Herring wrote:
> > 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.
>
> I believe the documentation of the Renesas compatible strings is also new
> in this file. Perhaps it would be worth mentioning that too.

Ah, that should be in patch 2. Will respin.

> In any case
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
>

^ permalink raw reply

* [PATCH] tty: serial: meson: if no alias specified use an available id
From: Loys Ollivier @ 2019-01-14 16:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Kevin Hilman
  Cc: Loys Ollivier, linux-serial, linux-arm-kernel, linux-amlogic,
	linux-kernel

At probe, the uart driver tries to get an id from a device tree alias.
When no alias was specified, the driver would return an error and probing
would fail.

Providing an alias for registering a serial device should not be mandatory.
If the device tree does not specify an alias, provide an id from a reserved
range so that the probing can continue.

Signed-off-by: Loys Ollivier <lollivier@baylibre.com>
---
 drivers/tty/serial/meson_uart.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 8a842591b37c..fbc5bc022a39 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -72,7 +72,8 @@
 #define AML_UART_BAUD_USE		BIT(23)
 #define AML_UART_BAUD_XTAL		BIT(24)
 
-#define AML_UART_PORT_NUM		6
+#define AML_UART_PORT_NUM		12
+#define AML_UART_PORT_OFFSET		6
 #define AML_UART_DEV_NAME		"ttyAML"
 
 
@@ -654,10 +655,20 @@ static int meson_uart_probe(struct platform_device *pdev)
 	struct resource *res_mem, *res_irq;
 	struct uart_port *port;
 	int ret = 0;
+	int id = -1;
 
 	if (pdev->dev.of_node)
 		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
 
+	if (pdev->id < 0) {
+		for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
+			if (!meson_ports[id]) {
+				pdev->id = id;
+				break;
+			}
+		}
+	}
+
 	if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
 		return -EINVAL;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/2] dt-bindings: serial: Convert snps,dw-apb-uart to json-schema
From: Rob Herring @ 2019-01-14 17:29 UTC (permalink / raw)
  To: devicetree; +Cc: linux-kernel, Simon Horman, 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
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Signed-off-by: Rob Herring <robh@kernel.org>
---
v2:
- Move Renesas compatible strings to patch 2

 .../bindings/serial/snps-dw-apb-uart.txt      |  76 ----------
 .../bindings/serial/snps-dw-apb-uart.yaml     | 135 ++++++++++++++++++
 2 files changed, 135 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..3e90c790d720
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -0,0 +1,135 @@
+# 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:
+              - 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 v2 2/2] dt-bindings: serial: Move renesas,rzn1-uart into the snps-dw-apb-uart binding
From: Rob Herring @ 2019-01-14 17:29 UTC (permalink / raw)
  To: devicetree
  Cc: linux-kernel, Simon Horman, Phil Edworthy, Greg Kroah-Hartman,
	linux-serial
In-Reply-To: <20190114172930.7508-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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Signed-off-by: Rob Herring <robh@kernel.org>
---
v2:
- Move Renesas compatible strings to this patch

 .../devicetree/bindings/serial/renesas,rzn1-uart.txt   | 10 ----------
 .../devicetree/bindings/serial/snps-dw-apb-uart.yaml   |  5 +++++
 2 files changed, 5 insertions(+), 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"
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 3e90c790d720..b42002542690 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -15,6 +15,11 @@ allOf:
 properties:
   compatible:
     oneOf:
+      - items:
+          - enum:
+              - renesas,r9a06g032-uart
+              - renesas,r9a06g033-uart
+          - const: renesas,rzn1-uart
       - items:
           - enum:
               - rockchip,px30-uart
-- 
2.19.1

^ permalink raw reply related

* Re: [PATCH 1/2] dt-bindings: serial: Convert snps,dw-apb-uart to json-schema
From: Simon Horman @ 2019-01-15  8:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, linux-kernel@vger.kernel.org, Greg Kroah-Hartman,
	open list:SERIAL DRIVERS
In-Reply-To: <CAL_JsqJd_kHi+XU7_oe0upg1iJT2rjjEup3YpyrDQA-OhkgKTw@mail.gmail.com>

On Mon, Jan 14, 2019 at 10:23:15AM -0600, Rob Herring wrote:
> On Mon, Jan 14, 2019 at 3:30 AM Simon Horman <horms@verge.net.au> wrote:
> >
> > On Thu, Jan 10, 2019 at 04:20:16PM -0600, Rob Herring wrote:
> > > 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.
> >
> > I believe the documentation of the Renesas compatible strings is also new
> > in this file. Perhaps it would be worth mentioning that too.
> 
> Ah, that should be in patch 2. Will respin.

Thanks!

> 
> > In any case
> >
> > Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
> >
> 

^ permalink raw reply

* Re: [PATCH] tty: serial: meson: if no alias specified use an available id
From: Neil Armstrong @ 2019-01-15  9:35 UTC (permalink / raw)
  To: Loys Ollivier, Greg Kroah-Hartman, Jiri Slaby, Kevin Hilman
  Cc: linux-amlogic, linux-arm-kernel, linux-serial, linux-kernel
In-Reply-To: <1547484866-3600-1-git-send-email-lollivier@baylibre.com>

On 14/01/2019 17:54, Loys Ollivier wrote:
> At probe, the uart driver tries to get an id from a device tree alias.
> When no alias was specified, the driver would return an error and probing
> would fail.
> 
> Providing an alias for registering a serial device should not be mandatory.
> If the device tree does not specify an alias, provide an id from a reserved
> range so that the probing can continue.
> 
> Signed-off-by: Loys Ollivier <lollivier@baylibre.com>
> ---
>  drivers/tty/serial/meson_uart.c | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
> index 8a842591b37c..fbc5bc022a39 100644
> --- a/drivers/tty/serial/meson_uart.c
> +++ b/drivers/tty/serial/meson_uart.c
> @@ -72,7 +72,8 @@
>  #define AML_UART_BAUD_USE		BIT(23)
>  #define AML_UART_BAUD_XTAL		BIT(24)
>  
> -#define AML_UART_PORT_NUM		6
> +#define AML_UART_PORT_NUM		12
> +#define AML_UART_PORT_OFFSET		6
>  #define AML_UART_DEV_NAME		"ttyAML"
>  
>  
> @@ -654,10 +655,20 @@ static int meson_uart_probe(struct platform_device *pdev)
>  	struct resource *res_mem, *res_irq;
>  	struct uart_port *port;
>  	int ret = 0;
> +	int id = -1;
>  
>  	if (pdev->dev.of_node)
>  		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
>  
> +	if (pdev->id < 0) {
> +		for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
> +			if (!meson_ports[id]) {
> +				pdev->id = id;
> +				break;
> +			}
> +		}
> +	}
> +
>  	if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
>  		return -EINVAL;
>  
> 

This is welcome !

You could also add:
Suggested-by: Rob Herring <robh@kernel.org>

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

Neil

^ permalink raw reply

* [PATCH v2] 8250_pci.c: Update NI specific devices class to multi serial
From: Guan Yung Tseng @ 2019-01-15 10:10 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Guan Yung Tseng

Modified NI devices class to PCI_CLASS_COMMUNICATION_MULTISERIAL.
The reason of doing this is because all NI multi port serial cards
use PCI_CLASS_COMMUNICATION_OTHER class and thus fail the
serial_pci_is_class_communication test added in the commit 7d8905d06405
("serial: 8250_pci: Enable device after we check black list").

Signed-off-by: Guan Yung Tseng <guan.yung.tseng@ni.com>
---
Changes in v2:
-  added comment to pci_ni_probe function

 drivers/tty/serial/8250/8250_pci.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 4986b4a..1f91858 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -663,6 +663,18 @@ static int pci_xircom_init(struct pci_dev *dev)
 	return 0;
 }
 
+/*
+ * NI Serial devices incorrectly identify themselves
+ * PCI_CLASS_COMMUNICATION_OTHER, instead of what
+ * they really are: PCI_CLASS_COMMUNICATION_MULTISERIAL
+ */
+static int pci_ni_probe(struct pci_dev *dev)
+{
+	dev->class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8 |
+			(dev->class & 0xff);
+	return 0;
+}
+
 static int pci_ni8420_init(struct pci_dev *dev)
 {
 	void __iomem *p;
@@ -1850,6 +1862,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI23216,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1859,6 +1872,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2328,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1868,6 +1882,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1877,6 +1892,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1886,6 +1902,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2324I,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1895,6 +1912,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PCI2322I,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1904,6 +1922,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_23216,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1913,6 +1932,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2328,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1922,6 +1942,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1931,6 +1952,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8420_2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1940,6 +1962,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8422_2324,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1949,6 +1972,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_DEVICE_ID_NI_PXI8422_2322,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
 		.exit		= pci_ni8420_exit,
@@ -1958,6 +1982,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.device		= PCI_ANY_ID,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
+		.probe		= pci_ni_probe,
 		.init		= pci_ni8430_init,
 		.setup		= pci_ni8430_setup,
 		.exit		= pci_ni8430_exit,
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v2] 8250_pci.c: Update NI specific devices class to multi serial
From: Christoph Hellwig @ 2019-01-15 13:31 UTC (permalink / raw)
  To: Guan Yung Tseng; +Cc: gregkh, linux-serial, linux-kernel
In-Reply-To: <1547547005-2149-1-git-send-email-guan.yung.tseng@ni.com>

On Tue, Jan 15, 2019 at 06:10:05PM +0800, Guan Yung Tseng wrote:
> +/*
> + * NI Serial devices incorrectly identify themselves
> + * PCI_CLASS_COMMUNICATION_OTHER, instead of what
> + * they really are: PCI_CLASS_COMMUNICATION_MULTISERIAL
> + */
> +static int pci_ni_probe(struct pci_dev *dev)
> +{
> +	dev->class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8 |
> +			(dev->class & 0xff);
> +	return 0;
> +}

This looks odd.  dev->class should just contain the class code read from
config space.  I think you need to work around this in the places that
check the classcode instead and add a quirk for these devices.

^ permalink raw reply

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

On Thu, Jan 10, 2019 at 06:11:39PM +0100, Andreas Schwab wrote:
> This enables proper NLCR processing.
> 
> Suggested-by: Anup Patel <anup@brainfault.org>
> Signed-off-by: Andreas Schwab <schwab@suse.de>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply

* [PATCH] tty: serial: lpc32xx_hs: fix missing console boot messages
From: Alexandre Belloni @ 2019-01-15 17:18 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Vladimir Zapolskiy
  Cc: Sylvain Lemieux, Roland Stigge, Jiri Slaby, linux-serial,
	linux-arm-kernel, linux-kernel, Alexandre Belloni

When probing the HSUART, it is put in loopback mode in order to prevent a
potential issue that may happen on RX (Errata HSUART.1).

serial_lpc32xx_startup() moves it out of loopback mode but this is too late
to get the kernel boot messages before userspace opens the device.

Also get out of loopback mode in lpc32xx_hsuart_console_setup().

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
---
 drivers/tty/serial/lpc32xx_hs.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index d1d73261575b..f4e27d0ad947 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -151,6 +151,8 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
 	local_irq_restore(flags);
 }
 
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state);
+
 static int __init lpc32xx_hsuart_console_setup(struct console *co,
 					       char *options)
 {
@@ -170,6 +172,8 @@ static int __init lpc32xx_hsuart_console_setup(struct console *co,
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 
+	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
-- 
2.20.1

^ permalink raw reply related

* [PATCH] uart: Fix crash in uart_write and uart_put_char
From: samir @ 2019-01-16 18:28 UTC (permalink / raw)
  To: gregkh, jslaby; +Cc: linux-serial, linux-kernel, Samir Virmani, Tycho Andersen

From: Samir Virmani <samir@embedur.com>

We were experiencing a crash similar to the one reported as part of
commit:a5ba1d95e46e ("uart: fix race between uart_put_char() and
uart_shutdown()") in our testbed as well. We continue to observe the same
crash after integrating the commit a5ba1d95e46e ("uart: fix race between
uart_put_char() and uart_shutdown()")

On reviewing the change, the port lock should be taken prior to checking for
if (!circ->buf) in fn. __uart_put_char and other fns. that update the buffer
uart_state->xmit.

Traceback:

[11/27/2018 06:24:32.4870] Unable to handle kernel NULL pointer dereference
                           at virtual address 0000003b

[11/27/2018 06:24:32.4950] PC is at memcpy+0x48/0x180
[11/27/2018 06:24:32.4950] LR is at uart_write+0x74/0x120
[11/27/2018 06:24:32.4950] pc : [<ffffffc0002e6808>]
                           lr : [<ffffffc0003747cc>] pstate: 000001c5
[11/27/2018 06:24:32.4950] sp : ffffffc076433d30
[11/27/2018 06:24:32.4950] x29: ffffffc076433d30 x28: 0000000000000140
[11/27/2018 06:24:32.4950] x27: ffffffc0009b9d5e x26: ffffffc07ce36580
[11/27/2018 06:24:32.4950] x25: 0000000000000000 x24: 0000000000000140
[11/27/2018 06:24:32.4950] x23: ffffffc000891200 x22: ffffffc01fc34000
[11/27/2018 06:24:32.4950] x21: 0000000000000fff x20: 0000000000000076
[11/27/2018 06:24:32.4950] x19: 0000000000000076 x18: 0000000000000000
[11/27/2018 06:24:32.4950] x17: 000000000047cf08 x16: ffffffc000099e68
[11/27/2018 06:24:32.4950] x15: 0000000000000018 x14: 776d726966205948
[11/27/2018 06:24:32.4950] x13: 50203a6c6974755f x12: 74647075205d3333
[11/27/2018 06:24:32.4950] x11: 3a35323a36203831 x10: 30322f37322f3131
[11/27/2018 06:24:32.4950] x9 : 5b205d303638342e x8 : 746164206f742070
[11/27/2018 06:24:32.4950] x7 : 7520736920657261 x6 : 000000000000003b
[11/27/2018 06:24:32.4950] x5 : 000000000000817a x4 : 0000000000000008
[11/27/2018 06:24:32.4950] x3 : 2f37322f31312a5b x2 : 000000000000006e
[11/27/2018 06:24:32.4950] x1 : ffffffc0009b9cf0 x0 : 000000000000003b

[11/27/2018 06:24:32.4950] CPU2: stopping
[11/27/2018 06:24:32.4950] CPU: 2 PID: 0 Comm: swapper/2 Tainted: P      D    O    4.1.51 #3
[11/27/2018 06:24:32.4950] Hardware name: Broadcom-v8A (DT)
[11/27/2018 06:24:32.4950] Call trace:
[11/27/2018 06:24:32.4950] [<ffffffc0000883b8>] dump_backtrace+0x0/0x150
[11/27/2018 06:24:32.4950] [<ffffffc00008851c>] show_stack+0x14/0x20
[11/27/2018 06:24:32.4950] [<ffffffc0005ee810>] dump_stack+0x90/0xb0
[11/27/2018 06:24:32.4950] [<ffffffc00008e844>] handle_IPI+0x18c/0x1a0
[11/27/2018 06:24:32.4950] [<ffffffc000080c68>] gic_handle_irq+0x88/0x90

Fixes: a5ba1d95e46e ("uart: fix race between uart_put_char() and
                      uart_shutdown()")
Signed-off-by: Samir Virmani <samir@embedur.com>
Cc: Tycho Andersen <tycho@tycho.ws>
---
 drivers/tty/serial/serial_core.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index c439a5a..bb55db2 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -540,10 +540,12 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c)
 	int ret = 0;
 
 	circ = &state->xmit;
-	if (!circ->buf)
+	port = uart_port_lock(state, flags);
+	if (!circ->buf) {
+		uart_port_unlock(port, flags);
 		return 0;
+	}
 
-	port = uart_port_lock(state, flags);
 	if (port && uart_circ_chars_free(circ) != 0) {
 		circ->buf[circ->head] = c;
 		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
@@ -576,11 +578,13 @@ static int uart_write(struct tty_struct *tty,
 		return -EL3HLT;
 	}
 
+	port = uart_port_lock(state, flags);
 	circ = &state->xmit;
-	if (!circ->buf)
+	if (!circ->buf) {
+		uart_port_unlock(port, flags);
 		return 0;
+	}
 
-	port = uart_port_lock(state, flags);
 	while (port) {
 		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
 		if (count < c)
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] uart: Fix crash in uart_write and uart_put_char
From: Tycho Andersen @ 2019-01-16 18:40 UTC (permalink / raw)
  To: samir; +Cc: gregkh, jslaby, linux-serial, linux-kernel
In-Reply-To: <1547663287-4890-1-git-send-email-samir@embedur.com>

On Wed, Jan 16, 2019 at 10:28:07AM -0800, samir@embedur.com wrote:
> From: Samir Virmani <samir@embedur.com>
> 
> We were experiencing a crash similar to the one reported as part of
> commit:a5ba1d95e46e ("uart: fix race between uart_put_char() and
> uart_shutdown()") in our testbed as well. We continue to observe the same
> crash after integrating the commit a5ba1d95e46e ("uart: fix race between
> uart_put_char() and uart_shutdown()")
> 
> On reviewing the change, the port lock should be taken prior to checking for
> if (!circ->buf) in fn. __uart_put_char and other fns. that update the buffer
> uart_state->xmit.
> 
> Traceback:
> 
> [11/27/2018 06:24:32.4870] Unable to handle kernel NULL pointer dereference
>                            at virtual address 0000003b
> 
> [11/27/2018 06:24:32.4950] PC is at memcpy+0x48/0x180
> [11/27/2018 06:24:32.4950] LR is at uart_write+0x74/0x120
> [11/27/2018 06:24:32.4950] pc : [<ffffffc0002e6808>]
>                            lr : [<ffffffc0003747cc>] pstate: 000001c5
> [11/27/2018 06:24:32.4950] sp : ffffffc076433d30
> [11/27/2018 06:24:32.4950] x29: ffffffc076433d30 x28: 0000000000000140
> [11/27/2018 06:24:32.4950] x27: ffffffc0009b9d5e x26: ffffffc07ce36580
> [11/27/2018 06:24:32.4950] x25: 0000000000000000 x24: 0000000000000140
> [11/27/2018 06:24:32.4950] x23: ffffffc000891200 x22: ffffffc01fc34000
> [11/27/2018 06:24:32.4950] x21: 0000000000000fff x20: 0000000000000076
> [11/27/2018 06:24:32.4950] x19: 0000000000000076 x18: 0000000000000000
> [11/27/2018 06:24:32.4950] x17: 000000000047cf08 x16: ffffffc000099e68
> [11/27/2018 06:24:32.4950] x15: 0000000000000018 x14: 776d726966205948
> [11/27/2018 06:24:32.4950] x13: 50203a6c6974755f x12: 74647075205d3333
> [11/27/2018 06:24:32.4950] x11: 3a35323a36203831 x10: 30322f37322f3131
> [11/27/2018 06:24:32.4950] x9 : 5b205d303638342e x8 : 746164206f742070
> [11/27/2018 06:24:32.4950] x7 : 7520736920657261 x6 : 000000000000003b
> [11/27/2018 06:24:32.4950] x5 : 000000000000817a x4 : 0000000000000008
> [11/27/2018 06:24:32.4950] x3 : 2f37322f31312a5b x2 : 000000000000006e
> [11/27/2018 06:24:32.4950] x1 : ffffffc0009b9cf0 x0 : 000000000000003b
> 
> [11/27/2018 06:24:32.4950] CPU2: stopping
> [11/27/2018 06:24:32.4950] CPU: 2 PID: 0 Comm: swapper/2 Tainted: P      D    O    4.1.51 #3
> [11/27/2018 06:24:32.4950] Hardware name: Broadcom-v8A (DT)
> [11/27/2018 06:24:32.4950] Call trace:
> [11/27/2018 06:24:32.4950] [<ffffffc0000883b8>] dump_backtrace+0x0/0x150
> [11/27/2018 06:24:32.4950] [<ffffffc00008851c>] show_stack+0x14/0x20
> [11/27/2018 06:24:32.4950] [<ffffffc0005ee810>] dump_stack+0x90/0xb0
> [11/27/2018 06:24:32.4950] [<ffffffc00008e844>] handle_IPI+0x18c/0x1a0
> [11/27/2018 06:24:32.4950] [<ffffffc000080c68>] gic_handle_irq+0x88/0x90
> 
> Fixes: a5ba1d95e46e ("uart: fix race between uart_put_char() and
>                       uart_shutdown()")
> Signed-off-by: Samir Virmani <samir@embedur.com>
> Cc: Tycho Andersen <tycho@tycho.ws>

Acked-by: Tycho Andersen <tycho@tycho.ws>

Thanks,

Tycho

^ permalink raw reply

* [PATCH] serial: 8250: Fix serial8250 initialization crash
From: zhe.he @ 2019-01-17  9:00 UTC (permalink / raw)
  To: gregkh, jslaby, andriy.shevchenko, bigeasy, Jisheng.Zhang,
	darwin.dingel, linux-serial, linux-kernel, zhe.he

From: He Zhe <zhe.he@windriver.com>

The initialization code of interrupt backoff work might reference NULL
pointer and cause the following crash, if no port was found.

[   10.017727] CPU 0 Unable to handle kernel paging request at virtual address 000001b0, epc == 807088e0, ra == 8070863c
---- snip ----
[   11.704470] [<807088e0>] serial8250_register_8250_port+0x318/0x4ac
[   11.747251] [<80708d74>] serial8250_probe+0x148/0x1c0
[   11.789301] [<80728450>] platform_drv_probe+0x40/0x94
[   11.830515] [<807264f8>] really_probe+0xf8/0x318
[   11.870876] [<80726b7c>] __driver_attach+0x110/0x12c
[   11.910960] [<80724374>] bus_for_each_dev+0x78/0xcc
[   11.951134] [<80725958>] bus_add_driver+0x200/0x234
[   11.989756] [<807273d8>] driver_register+0x84/0x148
[   12.029832] [<80d72f84>] serial8250_init+0x138/0x198
[   12.070447] [<80100e6c>] do_one_initcall+0x5c/0x2a0
[   12.110104] [<80d3a208>] kernel_init_freeable+0x370/0x484
[   12.150722] [<80a49420>] kernel_init+0x10/0xf8
[   12.191517] [<8010756c>] ret_from_kernel_thread+0x14/0x1c

This patch makes sure the initialization code can be reached only if a port
is found.

Fixes: commit 6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during input overruns")
Signed-off-by: He Zhe <zhe.he@windriver.com>
---
 drivers/tty/serial/8250/8250_core.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 189ab12..e441221 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1070,15 +1070,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 
 			ret = 0;
 		}
-	}
 
-	/* Initialise interrupt backoff work if required */
-	if (up->overrun_backoff_time_ms > 0) {
-		uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms;
-		INIT_DELAYED_WORK(&uart->overrun_backoff,
-				  serial_8250_overrun_backoff_work);
-	} else {
-		uart->overrun_backoff_time_ms = 0;
+		/* Initialise interrupt backoff work if required */
+		if (up->overrun_backoff_time_ms > 0) {
+			uart->overrun_backoff_time_ms =
+				up->overrun_backoff_time_ms;
+			INIT_DELAYED_WORK(&uart->overrun_backoff,
+					serial_8250_overrun_backoff_work);
+		} else {
+			uart->overrun_backoff_time_ms = 0;
+		}
 	}
 
 	mutex_unlock(&serial_mutex);
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] serial: 8250: Fix serial8250 initialization crash
From: Darwin Dingel @ 2019-01-17 19:49 UTC (permalink / raw)
  To: zhe.he@windriver.com, gregkh@linuxfoundation.org, jslaby@suse.com,
	andriy.shevchenko@linux.intel.com, bigeasy@linutronix.de,
	Jisheng.Zhang@synaptics.com, linux-serial@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1547715619-181299-1-git-send-email-zhe.he@windriver.com>

On 17/01/19 10:00 PM, zhe.he@windriver.com wrote:
> From: He Zhe <zhe.he@windriver.com>
> 
> The initialization code of interrupt backoff work might reference NULL
> pointer and cause the following crash, if no port was found.
> 
> [   10.017727] CPU 0 Unable to handle kernel paging request at virtual address 000001b0, epc == 807088e0, ra == 8070863c
> ---- snip ----
> [   11.704470] [<807088e0>] serial8250_register_8250_port+0x318/0x4ac
> [   11.747251] [<80708d74>] serial8250_probe+0x148/0x1c0
> [   11.789301] [<80728450>] platform_drv_probe+0x40/0x94
> [   11.830515] [<807264f8>] really_probe+0xf8/0x318
> [   11.870876] [<80726b7c>] __driver_attach+0x110/0x12c
> [   11.910960] [<80724374>] bus_for_each_dev+0x78/0xcc
> [   11.951134] [<80725958>] bus_add_driver+0x200/0x234
> [   11.989756] [<807273d8>] driver_register+0x84/0x148
> [   12.029832] [<80d72f84>] serial8250_init+0x138/0x198
> [   12.070447] [<80100e6c>] do_one_initcall+0x5c/0x2a0
> [   12.110104] [<80d3a208>] kernel_init_freeable+0x370/0x484
> [   12.150722] [<80a49420>] kernel_init+0x10/0xf8
> [   12.191517] [<8010756c>] ret_from_kernel_thread+0x14/0x1c
> 
> This patch makes sure the initialization code can be reached only if a port
> is found.
> 
> Fixes: commit 6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during input overruns")
> Signed-off-by: He Zhe <zhe.he@windriver.com>
> ---
>   drivers/tty/serial/8250/8250_core.c | 17 +++++++++--------
>   1 file changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index 189ab12..e441221 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -1070,15 +1070,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
>   
>   			ret = 0;
>   		}
> -	}
>   
> -	/* Initialise interrupt backoff work if required */
> -	if (up->overrun_backoff_time_ms > 0) {
> -		uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms;
> -		INIT_DELAYED_WORK(&uart->overrun_backoff,
> -				  serial_8250_overrun_backoff_work);
> -	} else {
> -		uart->overrun_backoff_time_ms = 0;
> +		/* Initialise interrupt backoff work if required */
> +		if (up->overrun_backoff_time_ms > 0) {
> +			uart->overrun_backoff_time_ms =
> +				up->overrun_backoff_time_ms;
> +			INIT_DELAYED_WORK(&uart->overrun_backoff,
> +					serial_8250_overrun_backoff_work);
> +		} else {
> +			uart->overrun_backoff_time_ms = 0;
> +		}
>   	}
>   
>   	mutex_unlock(&serial_mutex);
> 

Reviewed-by: Darwin Dingel <darwin.dingel@alliedtelesis.co.nz>

I presume this is the same issue reported here:

https://www.spinics.net/lists/linux-serial/msg33114.html
https://lkml.org/lkml/2018/12/22/171



Thanks!
Regards,

Darwin

^ permalink raw reply

* Re: [PATCH] serial: 8250: Fix serial8250 initialization crash
From: Darwin Dingel @ 2019-01-17 20:06 UTC (permalink / raw)
  To: zhe.he@windriver.com, gregkh@linuxfoundation.org, jslaby@suse.com,
	andriy.shevchenko@linux.intel.com, bigeasy@linutronix.de,
	Jisheng.Zhang@synaptics.com, linux-serial@vger.kernel.org,
	linux-kernel@vger.kernel.org, colin.king@canonical.com,
	dan.carpenter@oracle.com
In-Reply-To: <41c574bfdce7490597079dae8f328661@svr-chch-ex1.atlnz.lc>

On 18/01/19 8:49 AM, Darwin Dingel wrote:
> On 17/01/19 10:00 PM, zhe.he@windriver.com wrote:
>> From: He Zhe <zhe.he@windriver.com>
>>
>> The initialization code of interrupt backoff work might reference NULL
>> pointer and cause the following crash, if no port was found.
>>
>> [   10.017727] CPU 0 Unable to handle kernel paging request at virtual address 000001b0, epc == 807088e0, ra == 8070863c
>> ---- snip ----
>> [   11.704470] [<807088e0>] serial8250_register_8250_port+0x318/0x4ac
>> [   11.747251] [<80708d74>] serial8250_probe+0x148/0x1c0
>> [   11.789301] [<80728450>] platform_drv_probe+0x40/0x94
>> [   11.830515] [<807264f8>] really_probe+0xf8/0x318
>> [   11.870876] [<80726b7c>] __driver_attach+0x110/0x12c
>> [   11.910960] [<80724374>] bus_for_each_dev+0x78/0xcc
>> [   11.951134] [<80725958>] bus_add_driver+0x200/0x234
>> [   11.989756] [<807273d8>] driver_register+0x84/0x148
>> [   12.029832] [<80d72f84>] serial8250_init+0x138/0x198
>> [   12.070447] [<80100e6c>] do_one_initcall+0x5c/0x2a0
>> [   12.110104] [<80d3a208>] kernel_init_freeable+0x370/0x484
>> [   12.150722] [<80a49420>] kernel_init+0x10/0xf8
>> [   12.191517] [<8010756c>] ret_from_kernel_thread+0x14/0x1c
>>
>> This patch makes sure the initialization code can be reached only if a port
>> is found.
>>
>> Fixes: commit 6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during input overruns")
>> Signed-off-by: He Zhe <zhe.he@windriver.com>
>> ---
>>    drivers/tty/serial/8250/8250_core.c | 17 +++++++++--------
>>    1 file changed, 9 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
>> index 189ab12..e441221 100644
>> --- a/drivers/tty/serial/8250/8250_core.c
>> +++ b/drivers/tty/serial/8250/8250_core.c
>> @@ -1070,15 +1070,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
>>    
>>    			ret = 0;
>>    		}
>> -	}
>>    
>> -	/* Initialise interrupt backoff work if required */
>> -	if (up->overrun_backoff_time_ms > 0) {
>> -		uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms;
>> -		INIT_DELAYED_WORK(&uart->overrun_backoff,
>> -				  serial_8250_overrun_backoff_work);
>> -	} else {
>> -		uart->overrun_backoff_time_ms = 0;
>> +		/* Initialise interrupt backoff work if required */
>> +		if (up->overrun_backoff_time_ms > 0) {
>> +			uart->overrun_backoff_time_ms =
>> +				up->overrun_backoff_time_ms;
>> +			INIT_DELAYED_WORK(&uart->overrun_backoff,
>> +					serial_8250_overrun_backoff_work);
>> +		} else {
>> +			uart->overrun_backoff_time_ms = 0;
>> +		}
>>    	}
>>    
>>    	mutex_unlock(&serial_mutex);
>>
> 
> Reviewed-by: Darwin Dingel <darwin.dingel@alliedtelesis.co.nz>
> 
> I presume this is the same issue reported here:
> 
> https://www.spinics.net/lists/linux-serial/msg33114.html
> https://lkml.org/lkml/2018/12/22/171
> 
> 
> 
> Thanks!
> Regards,
> 
> Darwin
> 

Adding Colin and Dan.

Regards,
Darwin

^ permalink raw reply

* [PATCH v10 0/3] add uart DMA function
From: Long Cheng @ 2019-01-18  3:10 UTC (permalink / raw)
  To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
	Sean Wang, Nicolas Boichat
  Cc: Zhenbao Liu, devicetree, YT Shen, srv_heupstream,
	Greg Kroah-Hartman, Sean Wang, linux-kernel, dmaengine,
	Long Cheng, linux-mediatek, linux-serial, Jiri Slaby,
	Matthias Brugger, Yingjoe Chen, Dan Williams, linux-arm-kernel

In Mediatek SOCs, the uart can support DMA function.
Base on DMA engine formwork, we add the DMA code to support uart. And put the code under drivers/dma/mediatek.

This series contains document bindings, Kconfig to control the function enable or not,
device tree including interrupt and dma device node, the code of UART DMA

Changes compared to v9
-rename dt-bindings file
-remove direction from device_config
-simplified code
Changes compared to v8
-revise missing items
Changes compared to v7:
-modify apdma uart tx
Changes compared to v6:
-Correct spelling
Changes compared to v5:
-move 'requst irqs' to alloc channel
-remove tasklet.
Changes compared to v4:
-modify Kconfig depends on.
Changes compared to v3:
-fix CONFIG_PM, will cause build fail
Changes compared to v2:
-remove unimportant parameters
-instead of cookie, use APIs of virtual channel.
-use of_dma_xlate_by_chan_id.
Changes compared to v1:
-mian revised file, 8250_mtk_dma.c
--parameters renamed for standard
--remove atomic operation

Long Cheng (3):
  dmaengine: 8250_mtk_dma: add MediaTek uart DMA support
  arm: dts: mt2712: add uart APDMA to device tree
  dt-bindings: dma: uart: rename binding

 .../devicetree/bindings/dma/8250_mtk_dma.txt       |   33 -
 .../devicetree/bindings/dma/mtk-uart-apdma.txt     |   33 +
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi          |   51 ++
 drivers/dma/mediatek/Kconfig                       |   11 +
 drivers/dma/mediatek/Makefile                      |    1 +
 drivers/dma/mediatek/mtk-uart-apdma.c              |  669 ++++++++++++++++++++
 6 files changed, 765 insertions(+), 33 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
 create mode 100644 Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
 create mode 100644 drivers/dma/mediatek/mtk-uart-apdma.c

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v10 1/3] dmaengine: 8250_mtk_dma: add MediaTek uart DMA support
From: Long Cheng @ 2019-01-18  3:10 UTC (permalink / raw)
  To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
	Sean Wang, Nicolas Boichat
  Cc: 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, Long Cheng
In-Reply-To: <1547781016-890-1-git-send-email-long.cheng@mediatek.com>

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.

Signed-off-by: Long Cheng <long.cheng@mediatek.com>
---
 drivers/dma/mediatek/Kconfig          |   11 +
 drivers/dma/mediatek/Makefile         |    1 +
 drivers/dma/mediatek/mtk-uart-apdma.c |  669 +++++++++++++++++++++++++++++++++
 3 files changed, 681 insertions(+)
 create mode 100644 drivers/dma/mediatek/mtk-uart-apdma.c

diff --git a/drivers/dma/mediatek/Kconfig b/drivers/dma/mediatek/Kconfig
index 680fc05..ac49eb6 100644
--- a/drivers/dma/mediatek/Kconfig
+++ b/drivers/dma/mediatek/Kconfig
@@ -24,3 +24,14 @@ config MTK_CQDMA
 
 	  This controller provides the channels which is dedicated to
 	  memory-to-memory transfer to offload from CPU.
+
+config MTK_UART_APDMA
+	tristate "MediaTek SoCs APDMA support for UART"
+	depends on OF && SERIAL_8250_MT6577
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Support for the UART DMA engine found on MediaTek MTK SoCs.
+	  When SERIAL_8250_MT6577 is enabled, and if you want to use DMA,
+	  you can enable the config. The DMA engine can only be used
+	  with MediaTek SoCs.
diff --git a/drivers/dma/mediatek/Makefile b/drivers/dma/mediatek/Makefile
index 41bb381..61a6d29 100644
--- a/drivers/dma/mediatek/Makefile
+++ b/drivers/dma/mediatek/Makefile
@@ -1,2 +1,3 @@
+obj-$(CONFIG_MTK_UART_APDMA) += mtk-uart-apdma.o
 obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o
 obj-$(CONFIG_MTK_CQDMA) += mtk-cqdma.o
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
new file mode 100644
index 0000000..427db69
--- /dev/null
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek Uart APDMA driver.
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Long Cheng <long.cheng@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../virt-dma.h"
+
+/* The default number of virtual channel */
+#define MTK_UART_APDMA_NR_VCHANS	8
+
+#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 */
+#define VFF_WARM_RST_B		BIT(0)
+#define VFF_RX_INT_CLR_B	(BIT(0) | BIT(1))
+#define VFF_TX_INT_CLR_B	0
+#define VFF_STOP_CLR_B		0
+#define VFF_INT_EN_CLR_B	0
+#define VFF_4G_SUPPORT_CLR_B	0
+
+/* interrupt trigger level for tx */
+#define VFF_TX_THRE(n)		((n) * 7 / 8)
+/* interrupt trigger level for rx */
+#define VFF_RX_THRE(n)		((n) * 3 / 4)
+
+#define VFF_RING_SIZE	0xffffU
+/* invert this bit when wrap ring head again */
+#define VFF_RING_WRAP	0x10000U
+
+#define VFF_INT_FLAG		0x00
+#define VFF_INT_EN		0x04
+#define VFF_EN			0x08
+#define VFF_RST			0x0c
+#define VFF_STOP		0x10
+#define VFF_FLUSH		0x14
+#define VFF_ADDR		0x1c
+#define VFF_LEN			0x24
+#define VFF_THRE		0x28
+#define VFF_WPT			0x2c
+#define VFF_RPT			0x30
+/* TX: the buffer size HW can read. RX: the buffer size SW can read. */
+#define VFF_VALID_SIZE		0x3c
+/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
+#define VFF_LEFT_SIZE		0x40
+#define VFF_DEBUG_STATUS	0x50
+#define VFF_4G_SUPPORT		0x54
+
+struct mtk_uart_apdmadev {
+	struct dma_device ddev;
+	struct clk *clk;
+	bool support_33bits;
+	unsigned int dma_requests;
+	unsigned int *dma_irq;
+};
+
+struct mtk_uart_apdma_desc {
+	struct virt_dma_desc vd;
+
+	unsigned int avail_len;
+};
+
+struct mtk_chan {
+	struct virt_dma_chan vc;
+	struct dma_slave_config	cfg;
+	void __iomem *base;
+	struct mtk_uart_apdma_desc *desc;
+
+	enum dma_transfer_direction dir;
+
+	bool requested;
+
+	unsigned int rx_status;
+};
+
+static inline struct mtk_uart_apdmadev *
+to_mtk_uart_apdma_dev(struct dma_device *d)
+{
+	return container_of(d, struct mtk_uart_apdmadev, ddev);
+}
+
+static inline struct mtk_chan *to_mtk_uart_apdma_chan(struct dma_chan *c)
+{
+	return container_of(c, struct mtk_chan, vc.chan);
+}
+
+static inline struct mtk_uart_apdma_desc *to_mtk_uart_apdma_desc
+	(struct dma_async_tx_descriptor *t)
+{
+	return container_of(t, struct mtk_uart_apdma_desc, vd.tx);
+}
+
+static void mtk_uart_apdma_write(struct mtk_chan *c,
+			       unsigned int reg, unsigned int val)
+{
+	writel(val, c->base + reg);
+}
+
+static unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
+{
+	return readl(c->base + reg);
+}
+
+static void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
+{
+	struct dma_chan *chan = vd->tx.chan;
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+	kfree(c->desc);
+}
+
+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;
+	int 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);
+	cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
+	/*
+	 * The buffer is ring buffer. If wrap bit different,
+	 * represents the start of the next cycle for WPT
+	 */
+	if ((rg ^ wg) & VFF_RING_WRAP)
+		cnt += len;
+
+	c->rx_status = cnt;
+	mtk_uart_apdma_write(c, VFF_RPT, wg);
+
+	list_del(&d->vd.node);
+	vchan_cookie_complete(&d->vd);
+}
+
+static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
+{
+	struct dma_chan *chan = (struct dma_chan *)dev_id;
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+	struct mtk_uart_apdma_desc *d;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->vc.lock, flags);
+	if (c->dir == DMA_DEV_TO_MEM) {
+		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+		mtk_uart_apdma_start_rx(c);
+	} else if (c->dir == DMA_MEM_TO_DEV) {
+		d = c->desc;
+
+		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+		if (d->avail_len != 0U) {
+			mtk_uart_apdma_start_tx(c);
+		} else {
+			list_del(&d->vd.node);
+			vchan_cookie_complete(&d->vd);
+		}
+	}
+	spin_unlock_irqrestore(&c->vc.lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+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);
+	unsigned int 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, 10, 100);
+	if (ret) {
+		dev_err(chan->device->dev, "dma reset: fail, timeout\n");
+		return ret;
+	}
+
+	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);
+		if (ret < 0) {
+			dev_err(chan->device->dev, "Can't request dma IRQ\n");
+			return -EINVAL;
+		}
+	}
+
+	if (mtkd->support_33bits)
+		mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
+
+	return ret;
+}
+
+static void mtk_uart_apdma_free_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);
+
+	if (c->requested) {
+		c->requested = false;
+		free_irq(mtkd->dma_irq[chan->chan_id], chan);
+	}
+
+	tasklet_kill(&c->vc.task);
+
+	vchan_free_chan_resources(&c->vc);
+
+	pm_runtime_put_sync(mtkd->ddev.dev);
+}
+
+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->dir == DMA_DEV_TO_MEM) {
+		dma_set_residue(txstate, c->rx_status);
+	} else {
+		dma_set_residue(txstate, 0);
+	}
+	spin_unlock_irqrestore(&c->vc.lock, flags);
+
+	return ret;
+}
+
+static void mtk_uart_apdma_config_write(struct dma_chan *chan,
+			       struct dma_slave_config *cfg,
+			       enum dma_transfer_direction dir)
+{
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+	struct mtk_uart_apdmadev *mtkd =
+				to_mtk_uart_apdma_dev(c->vc.chan.device);
+	unsigned int tmp;
+
+	if (mtk_uart_apdma_read(c, VFF_EN) == VFF_EN_B)
+		return;
+
+	c->dir = dir;
+
+	if (dir == DMA_DEV_TO_MEM) {
+		tmp = cfg->src_addr_width * 1024;
+
+		mtk_uart_apdma_write(c, VFF_ADDR, cfg->src_addr);
+		mtk_uart_apdma_write(c, VFF_LEN, tmp);
+		mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(tmp));
+		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_CLR_B);
+	} else if (dir == DMA_MEM_TO_DEV)	{
+		tmp = cfg->dst_addr_width * 1024;
+
+		mtk_uart_apdma_write(c, VFF_ADDR, cfg->dst_addr);
+		mtk_uart_apdma_write(c, VFF_LEN, tmp);
+		mtk_uart_apdma_write(c, VFF_THRE, VFF_TX_THRE(tmp));
+		mtk_uart_apdma_write(c, VFF_WPT, 0);
+		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+	}
+
+	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+
+	if (mtkd->support_33bits)
+		mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_B);
+
+	if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+		dev_err(chan->device->dev, "dir[%d] fail\n", dir);
+}
+
+/*
+ * dmaengine_prep_slave_single will call the function. and sglen is 1.
+ * 8250 uart using one ring buffer, and deal with one sg.
+ */
+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 (!is_slave_direction(dir))
+		return NULL;
+
+	mtk_uart_apdma_config_write(chan, &c->cfg, dir);
+
+	/* Now allocate and setup the descriptor */
+	d = kzalloc(sizeof(*d), GFP_ATOMIC);
+	if (!d)
+		return NULL;
+
+	/* sglen is 1 */
+	d->avail_len = sg_dma_len(sgl);
+
+	return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
+}
+
+static void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
+{
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+	struct virt_dma_desc *vd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->vc.lock, flags);
+	if (vchan_issue_pending(&c->vc)) {
+		vd = vchan_next_desc(&c->vc);
+		c->desc = to_mtk_uart_apdma_desc(&vd->tx);
+	}
+
+	if (c->dir == DMA_DEV_TO_MEM)
+		mtk_uart_apdma_start_rx(c);
+	else if (c->dir == DMA_MEM_TO_DEV)
+		mtk_uart_apdma_start_tx(c);
+
+	spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static int mtk_uart_apdma_slave_config(struct dma_chan *chan,
+				   struct dma_slave_config *config)
+{
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+	memcpy(&c->cfg, config, sizeof(*config));
+
+	return 0;
+}
+
+static int mtk_uart_apdma_terminate_all(struct dma_chan *chan)
+{
+	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+	unsigned long flags;
+	unsigned int tmp;
+	int ret;
+
+	spin_lock_irqsave(&c->vc.lock, flags);
+
+	mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+	/* 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_err(c->vc.chan.device->dev, "flush: fail, debug=0x%x\n",
+			mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+	/* set stop as 1 -> wait until en is 0 -> set stop as 0 */
+	mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_B);
+	ret = readx_poll_timeout(readl, c->base + VFF_EN, tmp, !tmp, 10, 100);
+	if (ret)
+		dev_err(c->vc.chan.device->dev, "stop: fail, debug=0x%x\n",
+			mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+	mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_CLR_B);
+	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+	if (c->dir == DMA_DEV_TO_MEM)
+		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+	else if (c->dir == DMA_MEM_TO_DEV)
+		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+	spin_unlock_irqrestore(&c->vc.lock, flags);
+
+	return 0;
+}
+
+static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
+{
+	/* just for check caps pass */
+	return 0;
+}
+
+static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
+{
+	while (!list_empty(&mtkd->ddev.channels)) {
+		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", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_uart_apdma_match);
+
+static int mtk_uart_apdma_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct mtk_uart_apdmadev *mtkd;
+	struct resource *res;
+	struct mtk_chan *c;
+	int bit_mask = 32, rc;
+	unsigned int i;
+
+	mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
+	if (!mtkd)
+		return -ENOMEM;
+
+	mtkd->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(mtkd->clk)) {
+		dev_err(&pdev->dev, "No clock specified\n");
+		rc = PTR_ERR(mtkd->clk);
+		return rc;
+	}
+
+	if (of_property_read_bool(np, "dma-33bits"))
+		mtkd->support_33bits = true;
+
+	if (mtkd->support_33bits)
+		bit_mask = 33;
+
+	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
+	if (rc)
+		return rc;
+
+	dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
+	mtkd->ddev.device_alloc_chan_resources =
+				mtk_uart_apdma_alloc_chan_resources;
+	mtkd->ddev.device_free_chan_resources =
+				mtk_uart_apdma_free_chan_resources;
+	mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
+	mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
+	mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
+	mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
+	mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
+	mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
+	mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+	mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+	mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+	mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+	mtkd->ddev.dev = &pdev->dev;
+	INIT_LIST_HEAD(&mtkd->ddev.channels);
+
+	mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
+	if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
+		dev_info(&pdev->dev,
+			 "Using %u as missing dma-requests property\n",
+			 MTK_UART_APDMA_NR_VCHANS);
+	}
+
+	mtkd->dma_irq = devm_kcalloc(&pdev->dev, mtkd->dma_requests,
+				 sizeof(*mtkd->dma_irq), GFP_KERNEL);
+	if (!mtkd->dma_irq)
+		return -ENOMEM;
+
+	for (i = 0; i < mtkd->dma_requests; i++) {
+		c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
+		if (!c) {
+			rc = -ENODEV;
+			goto err_no_dma;
+		}
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			rc = -ENODEV;
+			goto err_no_dma;
+		}
+
+		c->base = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(c->base)) {
+			rc = PTR_ERR(c->base);
+			goto err_no_dma;
+		}
+		c->requested = false;
+		c->vc.desc_free = mtk_uart_apdma_desc_free;
+		vchan_init(&c->vc, &mtkd->ddev);
+
+		mtkd->dma_irq[i] = platform_get_irq(pdev, i);
+		if ((int)mtkd->dma_irq[i] < 0) {
+			dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i);
+			rc = -EINVAL;
+			goto err_no_dma;
+		}
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+
+	rc = dma_async_device_register(&mtkd->ddev);
+	if (rc)
+		goto rpm_disable;
+
+	platform_set_drvdata(pdev, mtkd);
+
+	/* Device-tree DMA controller registration */
+	rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
+	if (rc)
+		goto dma_remove;
+
+	return rc;
+
+dma_remove:
+	dma_async_device_unregister(&mtkd->ddev);
+rpm_disable:
+	pm_runtime_disable(&pdev->dev);
+err_no_dma:
+	mtk_uart_apdma_free(mtkd);
+	return rc;
+}
+
+static int mtk_uart_apdma_remove(struct platform_device *pdev)
+{
+	struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
+
+	if (pdev->dev.of_node)
+		of_dma_controller_free(pdev->dev.of_node);
+
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
+
+	dma_async_device_unregister(&mtkd->ddev);
+	mtk_uart_apdma_free(mtkd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_uart_apdma_suspend(struct device *dev)
+{
+	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+	if (!pm_runtime_suspended(dev))
+		clk_disable_unprepare(mtkd->clk);
+
+	return 0;
+}
+
+static int mtk_uart_apdma_resume(struct device *dev)
+{
+	int ret;
+	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+	if (!pm_runtime_suspended(dev)) {
+		ret = clk_prepare_enable(mtkd->clk);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_uart_apdma_runtime_suspend(struct device *dev)
+{
+	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(mtkd->clk);
+
+	return 0;
+}
+
+static int mtk_uart_apdma_runtime_resume(struct device *dev)
+{
+	int ret;
+	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+	ret = clk_prepare_enable(mtkd->clk);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
+	SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
+			   mtk_uart_apdma_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_uart_apdma_driver = {
+	.probe	= mtk_uart_apdma_probe,
+	.remove	= mtk_uart_apdma_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.pm		= &mtk_uart_apdma_pm_ops,
+		.of_match_table = of_match_ptr(mtk_uart_apdma_match),
+	},
+};
+
+module_platform_driver(mtk_uart_apdma_driver);
+
+MODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
+MODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v10 2/3] arm: dts: mt2712: add uart APDMA to device tree
From: Long Cheng @ 2019-01-18  3:10 UTC (permalink / raw)
  To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
	Sean Wang, Nicolas Boichat
  Cc: 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, Long Cheng
In-Reply-To: <1547781016-890-1-git-send-email-long.cheng@mediatek.com>

1. add uart APDMA controller device node
2. add uart 0/1/2/3/4/5 DMA function

Signed-off-by: Long Cheng <long.cheng@mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi |   51 +++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
index ee627a7..3469a6c 100644
--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
@@ -298,6 +298,9 @@
 		interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 10
+			&apdma 11>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
@@ -346,6 +349,39 @@
 			 (GIC_CPU_MASK_RAW(0x13) | IRQ_TYPE_LEVEL_HIGH)>;
 	};
 
+	apdma: dma-controller@11000400 {
+		compatible = "mediatek,mt2712-uart-dma",
+			     "mediatek,mt6577-uart-dma";
+		reg = <0 0x11000400 0 0x80>,
+		      <0 0x11000480 0 0x80>,
+		      <0 0x11000500 0 0x80>,
+		      <0 0x11000580 0 0x80>,
+		      <0 0x11000600 0 0x80>,
+		      <0 0x11000680 0 0x80>,
+		      <0 0x11000700 0 0x80>,
+		      <0 0x11000780 0 0x80>,
+		      <0 0x11000800 0 0x80>,
+		      <0 0x11000880 0 0x80>,
+		      <0 0x11000900 0 0x80>,
+		      <0 0x11000980 0 0x80>;
+		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+		dma-requests = <12>;
+		clocks = <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "apdma";
+		#dma-cells = <1>;
+	};
+
 	auxadc: adc@11001000 {
 		compatible = "mediatek,mt2712-auxadc";
 		reg = <0 0x11001000 0 0x1000>;
@@ -362,6 +398,9 @@
 		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 0
+			&apdma 1>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
@@ -372,6 +411,9 @@
 		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 2
+			&apdma 3>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
@@ -382,6 +424,9 @@
 		interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 4
+			&apdma 5>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
@@ -392,6 +437,9 @@
 		interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 6
+			&apdma 7>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
@@ -402,6 +450,9 @@
 		interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&baud_clk>, <&sys_clk>;
 		clock-names = "baud", "bus";
+		dmas = <&apdma 8
+			&apdma 9>;
+		dma-names = "tx", "rx";
 		status = "disabled";
 	};
 
-- 
1.7.9.5

^ 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