* [PATCH v4 1/3] serial: 8250: introduce get_divisor() and set_divisor() hook
From: Jisheng Zhang @ 2018-07-10 3:12 UTC (permalink / raw)
To: Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710110942.5b0a016e@xhacker.debian>
Add these two hooks so that they can be overridden with driver specific
implementations.
Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/tty/serial/8250/8250_core.c | 4 ++++
drivers/tty/serial/8250/8250_port.c | 27 +++++++++++++++++++++++----
include/linux/serial_core.h | 7 +++++++
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 9342fc2ee7df..a0bb77290747 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1023,6 +1023,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.get_mctrl = up->port.get_mctrl;
if (up->port.set_mctrl)
uart->port.set_mctrl = up->port.set_mctrl;
+ if (up->port.get_divisor)
+ uart->port.get_divisor = up->port.get_divisor;
+ if (up->port.set_divisor)
+ uart->port.set_divisor = up->port.set_divisor;
if (up->port.startup)
uart->port.startup = up->port.startup;
if (up->port.shutdown)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 709fe6b4265c..ce0dc17f18ee 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2498,9 +2498,9 @@ static unsigned int npcm_get_divisor(struct uart_8250_port *up,
return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
}
-static unsigned int serial8250_get_divisor(struct uart_port *port,
- unsigned int baud,
- unsigned int *frac)
+static unsigned int serial8250_do_get_divisor(struct uart_port *port,
+ unsigned int baud,
+ unsigned int *frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int quot;
@@ -2532,6 +2532,16 @@ static unsigned int serial8250_get_divisor(struct uart_port *port,
return quot;
}
+static unsigned int serial8250_get_divisor(struct uart_port *port,
+ unsigned int baud,
+ unsigned int *frac)
+{
+ if (port->get_divisor)
+ return port->get_divisor(port, baud, frac);
+
+ return serial8250_do_get_divisor(port, baud, frac);
+}
+
static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
tcflag_t c_cflag)
{
@@ -2570,7 +2580,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
return cval;
}
-static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
+static void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2603,6 +2613,15 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
}
}
+static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ if (port->set_divisor)
+ port->set_divisor(port, baud, quot, quot_frac);
+ else
+ serial8250_do_set_divisor(port, baud, quot, quot_frac);
+}
+
static unsigned int serial8250_get_baud_rate(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 06ea4eeb09ab..406edae44ca3 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -127,6 +127,13 @@ struct uart_port {
struct ktermios *);
unsigned int (*get_mctrl)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int);
+ unsigned int (*get_divisor)(struct uart_port *,
+ unsigned int baud,
+ unsigned int *frac);
+ void (*set_divisor)(struct uart_port *,
+ unsigned int baud,
+ unsigned int quot,
+ unsigned int quot_frac);
int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port);
void (*throttle)(struct uart_port *port);
--
2.18.0
^ permalink raw reply related
* [PATCH v4 2/3] serial: 8250: export serial8250_do_set_divisor()
From: Jisheng Zhang @ 2018-07-10 3:13 UTC (permalink / raw)
To: Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710110942.5b0a016e@xhacker.debian>
Some drivers could call serial8250_do_set_divisor() to complete its
own set_divisor routine. Export this symbol for code reusing.
Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
---
drivers/tty/serial/8250/8250_port.c | 5 +++--
include/linux/serial_8250.h | 3 +++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index ce0dc17f18ee..945f8dc2d50f 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2580,8 +2580,8 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
return cval;
}
-static void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
- unsigned int quot, unsigned int quot_frac)
+void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2612,6 +2612,7 @@ static void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac);
}
}
+EXPORT_SYMBOL_GPL(serial8250_do_set_divisor);
static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 76b9db71e489..18e21427bce4 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -160,6 +160,9 @@ extern void serial8250_do_shutdown(struct uart_port *port);
extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate);
extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
+extern void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot,
+ unsigned int quot_frac);
extern int fsl8250_handle_irq(struct uart_port *port);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
--
2.18.0
^ permalink raw reply related
* [PATCH v4 3/3] serial: 8250_dw: add fractional divisor support
From: Jisheng Zhang @ 2018-07-10 3:15 UTC (permalink / raw)
To: Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710110942.5b0a016e@xhacker.debian>
For Synopsys DesignWare 8250 uart which version >= 4.00a, there's a
valid divisor latch fraction register. The fractional divisor width is
4bits ~ 6bits.
Now the preparation is done, it's easy to add the feature support.
This patch firstly tries to get the fractional divisor width during
probe, then setups dw specific get_divisor() and set_divisor() hook.
Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
---
drivers/tty/serial/8250/8250_dw.c | 45 +++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index fa8a00e8c9c6..ad08d7a3b93b 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -31,6 +31,7 @@
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
+#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */
@@ -55,6 +56,7 @@
struct dw8250_data {
u8 usr_reg;
+ u8 dlf_size;
int line;
int msr_mask_on;
int msr_mask_off;
@@ -366,6 +368,37 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev->parent;
}
+/*
+ * divisor = div(I) + div(F)
+ * "I" means integer, "F" means fractional
+ * quot = div(I) = clk / (16 * baud)
+ * frac = div(F) * 2^dlf_size
+ *
+ * let rem = clk % (16 * baud)
+ * we have: div(F) * (16 * baud) = rem
+ * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud)
+ */
+static unsigned int dw8250_get_divisor(struct uart_port *p,
+ unsigned int baud,
+ unsigned int *frac)
+{
+ unsigned int quot, rem;
+ struct dw8250_data *d = p->private_data;
+
+ quot = p->uartclk / (16 * baud);
+ rem = p->uartclk % (16 * baud);
+ *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, 16 * baud);
+
+ return quot;
+}
+
+static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
+ serial8250_do_set_divisor(p, baud, quot, quot_frac);
+}
+
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
if (p->dev->of_node) {
@@ -426,6 +459,18 @@ static void dw8250_setup_port(struct uart_port *p)
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+ dw8250_writel_ext(p, DW_UART_DLF, ~0U);
+ reg = dw8250_readl_ext(p, DW_UART_DLF);
+ dw8250_writel_ext(p, DW_UART_DLF, 0);
+
+ if (reg) {
+ struct dw8250_data *d = p->private_data;
+
+ d->dlf_size = fls(reg);
+ p->get_divisor = dw8250_get_divisor;
+ p->set_divisor = dw8250_set_divisor;
+ }
+
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg)
return;
--
2.18.0
^ permalink raw reply related
* Re: [PATCH v4 1/1] arm64: dts: mediatek: add mt6765 support
From: Matthias Brugger @ 2018-07-10 10:52 UTC (permalink / raw)
To: Mars Cheng, Marc Zyngier
Cc: Rob Herring, CC Hwang, Loda Chou, linux-kernel, linux-mediatek,
devicetree, wsd_upstream, linux-serial, linux-arm-kernel
In-Reply-To: <1531177443.7777.18.camel@mtkswgap22>
On 10/07/18 01:04, Mars Cheng wrote:
> Hi Matthias/Marc
>
> On Mon, 2018-07-09 at 17:43 +0100, Marc Zyngier wrote:
>> On 09/07/18 11:20, Matthias Brugger wrote:
>>>
>>>
>>> On 09/07/18 08:05, Mars Cheng wrote:
>>>> This adds basic chip support for MT6765 SoC.
>>>>
>>>> Signed-off-by: Mars Cheng <mars.cheng@mediatek.com>
>>>> ---
>>>> arch/arm64/boot/dts/mediatek/Makefile | 1 +
>>>> arch/arm64/boot/dts/mediatek/mt6765-evb.dts | 33 ++++++
>>>> arch/arm64/boot/dts/mediatek/mt6765.dtsi | 156 +++++++++++++++++++++++++++
>>>> 3 files changed, 190 insertions(+)
>>>> create mode 100644 arch/arm64/boot/dts/mediatek/mt6765-evb.dts
>>>> create mode 100644 arch/arm64/boot/dts/mediatek/mt6765.dtsi
>>>>
>>>> diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
>>>> index ac17f60..7506b0d 100644
>>>> --- a/arch/arm64/boot/dts/mediatek/Makefile
>>>> +++ b/arch/arm64/boot/dts/mediatek/Makefile
>>>> @@ -1,6 +1,7 @@
>>>> # SPDX-License-Identifier: GPL-2.0
>>>> dtb-$(CONFIG_ARCH_MEDIATEK) += mt2712-evb.dtb
>>>> dtb-$(CONFIG_ARCH_MEDIATEK) += mt6755-evb.dtb
>>>> +dtb-$(CONFIG_ARCH_MEDIATEK) += mt6765-evb.dtb
>>>> dtb-$(CONFIG_ARCH_MEDIATEK) += mt6795-evb.dtb
>>>> dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-evb.dtb
>>>> dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
>>>
>>> As you can see, we have a long list of SoCs which are poorly supported.
>>> I'm not very keen to just add another SoC which supports booting into a ramdisk
>>> using the serial console. Do you have a roadmap adding mainline support for this
>>> SoC?
>>
>> Yes, that's a valid concern.
>>
>> mt6755 and mt6795 are in a similar state, the latter after three years.
>> I'm all for supporting new SoCs, but this feels looks a box-ticking
>> exercise ("hey, look, our SoC is supported in mainline") which doesn't
>> help anyone.
>>
>> My Ack still stands, but I'd definitely like to see some more complete
>> support before this patch goes in.
>>
>> Thanks,
>>
>> M.
>
> Yes, we do arrange more resources to do upstream task for mt6765,
> clk/pinctrl drivers are almost ready to submit. systimer is under
> reviewing (v9).
> http://lists.infradead.org/pipermail/linux-mediatek/2018-July/013989.html
>
> other drivers including
> pmic/pwrap/i2c/rtc/kpd/spi/wdt/cqdma/auxadc/pwm/cmdq/disp. We have
> dedicated owners to handle them and will cowork tightly with members to
> make sure things happen in the following weeks.
>
Ok, so let's wait until pinctrl driver is submitted. I'd prefer if you could add
the clk driver to this series. This way we can get rid of the dummy clocks in
the device tree.
> For previous chips, we did have no enough support after shell. It is due
> to fast pace of smartphone SoC and other resource issues. We also know
> that is no excuse so that we already confirmed owners and their
> schedules for mt6765.
>
> If there is any suggestion, please let us know.
>
I know that smartphone SoC is a fast paced business. Never the less I'm
convinced that the basic building blocks won't change much from one version to
another. And that mainline support for the previous version of your SoC will
help you to get your new drivers faster upstream.
For me the best example is the mt7622 which got to a reasonable upstream support
quite fast, thanks to a good foundation of mt7623 in mainline. I'd love to see
that happen on the smartphone SoCs as well.
Not to mention that upstream support will help you internally when you have to
rebase your BSP code-base to a new kernel version.
That said I think it is good news that you have already defined owner for the
different devices and hope to see submissions for them in the near future :)
As a suggestion I would say that upstream submission takes time and effort and
it will help your engineers if they can allocate some time to do so. But that's
most probably a management decision and all engineers know that management bases
it's decision on some hard-to-understandable abbreviations like EBITDA etc. ;)
Best regards,
Matthias
^ permalink raw reply
* Re: [PATCH v4 2/3] serial: 8250: export serial8250_do_set_divisor()
From: Andy Shevchenko @ 2018-07-10 13:56 UTC (permalink / raw)
To: Jisheng Zhang, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710111327.072584c0@xhacker.debian>
On Tue, 2018-07-10 at 11:13 +0800, Jisheng Zhang wrote:
> Some drivers could call serial8250_do_set_divisor() to complete its
> own set_divisor routine. Export this symbol for code reusing.
>
I dunno Greg's preferences here, but it could be merged with patch 1.
In any case,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
for this part.
> Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
> ---
> drivers/tty/serial/8250/8250_port.c | 5 +++--
> include/linux/serial_8250.h | 3 +++
> 2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_port.c
> b/drivers/tty/serial/8250/8250_port.c
> index ce0dc17f18ee..945f8dc2d50f 100644
> --- a/drivers/tty/serial/8250/8250_port.c
> +++ b/drivers/tty/serial/8250/8250_port.c
> @@ -2580,8 +2580,8 @@ static unsigned char
> serial8250_compute_lcr(struct uart_8250_port *up,
> return cval;
> }
>
> -static void serial8250_do_set_divisor(struct uart_port *port,
> unsigned int baud,
> - unsigned int quot, unsigned int
> quot_frac)
> +void serial8250_do_set_divisor(struct uart_port *port, unsigned int
> baud,
> + unsigned int quot, unsigned int
> quot_frac)
> {
> struct uart_8250_port *up = up_to_u8250p(port);
>
> @@ -2612,6 +2612,7 @@ static void serial8250_do_set_divisor(struct
> uart_port *port, unsigned int baud,
> serial_port_out(port, 0x2, quot_frac);
> }
> }
> +EXPORT_SYMBOL_GPL(serial8250_do_set_divisor);
>
> static void serial8250_set_divisor(struct uart_port *port, unsigned
> int baud,
> unsigned int quot, unsigned int
> quot_frac)
> diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
> index 76b9db71e489..18e21427bce4 100644
> --- a/include/linux/serial_8250.h
> +++ b/include/linux/serial_8250.h
> @@ -160,6 +160,9 @@ extern void serial8250_do_shutdown(struct
> uart_port *port);
> extern void serial8250_do_pm(struct uart_port *port, unsigned int
> state,
> unsigned int oldstate);
> extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned
> int mctrl);
> +extern void serial8250_do_set_divisor(struct uart_port *port,
> unsigned int baud,
> + unsigned int quot,
> + unsigned int quot_frac);
> extern int fsl8250_handle_irq(struct uart_port *port);
> int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
> unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned
> char lsr);
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* Re: [PATCH v3 3/8] mailbox: Add transmit done by blocking option
From: Thierry Reding @ 2018-07-10 15:49 UTC (permalink / raw)
To: Jassi Brar
Cc: devicetree, gregkh, linux-kernel, jonathanh, linux-serial,
linux-tegra, Mikko Perttunen, linux-arm-kernel
In-Reply-To: <20180702114033.15654-4-mperttunen@nvidia.com>
[-- Attachment #1.1: Type: text/plain, Size: 1066 bytes --]
On Mon, Jul 02, 2018 at 02:40:28PM +0300, Mikko Perttunen wrote:
> Add a new TXDONE option, TXDONE_BY_BLOCK. With this option, the
> send_data function of the mailbox driver is expected to block until
> the message has been sent. The new option is used with the Tegra
> Combined UART driver to minimize unnecessary overhead when transmitting
> data.
>
> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> ---
> drivers/mailbox/mailbox.c | 30 +++++++++++++++++++++---------
> drivers/mailbox/mailbox.h | 1 +
> 2 files changed, 22 insertions(+), 9 deletions(-)
Jassi,
any comments on this patch and 4/8 and 5/8? Greg's already said that
he'd be fine if I take the serial driver (patch 6/8) through the Tegra
tree to resolve the dependencies. If you're okay with the three mailbox
patches I can pick them up as well with your Acked-by.
Otherwise, if you'd prefer to take these through the mailbox tree, let
me know and I'll wait until sometime after v4.19-rc1 before I send out
pull requests for the DT changes.
Thanks,
Thierry
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 3/3] serial: 8250_dw: add fractional divisor support
From: Andy Shevchenko @ 2018-07-10 16:19 UTC (permalink / raw)
To: Jisheng Zhang, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710111516.13b8c570@xhacker.debian>
On Tue, 2018-07-10 at 11:15 +0800, Jisheng Zhang wrote:
> For Synopsys DesignWare 8250 uart which version >= 4.00a, there's a
> valid divisor latch fraction register. The fractional divisor width is
> 4bits ~ 6bits.
>
> Now the preparation is done, it's easy to add the feature support.
> This patch firstly tries to get the fractional divisor width during
> probe, then setups dw specific get_divisor() and set_divisor() hook.
Thanks for an update, my comments below.
> +/*
> + * divisor = div(I) + div(F)
> + * "I" means integer, "F" means fractional
> + * quot = div(I) = clk / (16 * baud)
> + * frac = div(F) * 2^dlf_size
> + *
> + * let rem = clk % (16 * baud)
> + * we have: div(F) * (16 * baud) = rem
> + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16
> * baud)
> + */
> +static unsigned int dw8250_get_divisor(struct uart_port *p,
> + unsigned int baud,
> + unsigned int *frac)
> +{
unsigned int base_baud = baud * 16;
> + unsigned int quot, rem;
> + struct dw8250_data *d = p->private_data;
> +
> + quot = p->uartclk / (16 * baud);
> + rem = p->uartclk % (16 * baud);
> + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, 16 * baud);
> +
While it looks indeed better, I would rather like to have a confirmation
it's working as designed.
For example, when I did some calculus, I cooked a preliminary check in
Python (easy and fast to prototype), for example:
https://gist.github.com/andy-shev/06b084488b3629898121 in Python, or
commit 9df461eca18f ("spi: pxa2xx: replace ugly table by approximation")
in the kernel.
Or another one here https://gist.github.com/andy-shev/8b2a73aeca2874f4cc
89 and commits c1a67b48f6a5 ("serial: 8250_pci: replace switch-case by
formula for Intel MID"), 21947ba654a6 ("serial: 8250_pci: replace
switch-case by formula")
P.S. The code itself looks good to me, thanks!
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* Re: [PATCH v10 5/6] spi: at91-usart: add driver for at91-usart as spi
From: Mark Brown @ 2018-07-10 18:15 UTC (permalink / raw)
To: Radu Pirea
Cc: mark.rutland, devicetree, alexandre.belloni, linux-kernel,
richard.genoud, gregkh, linux-spi, robh+dt, linux-serial,
lee.jones, linux-arm-kernel
In-Reply-To: <20180625172230.29686-6-radu.pirea@microchip.com>
[-- Attachment #1.1: Type: text/plain, Size: 752 bytes --]
On Mon, Jun 25, 2018 at 08:22:29PM +0300, Radu Pirea wrote:
This is mostly good, just a couple of small things:
> +config SPI_AT91_USART
> + tristate "Atmel USART Controller SPI driver"
> + depends on HAS_DMA
> + depends on (ARCH_AT91 || COMPILE_TEST)
> + select MFD_AT91_USART
Why is this selecting rather than depending on the MFD like we normally
do?
> @@ -0,0 +1,432 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for AT91 USART Controllers as SPI
> + *
> + * Copyright (C) 2018 Microchip Technology Inc.
> + * Author: Radu Pirea <radu.pirea@microchip.com>
> + */
Please use C++ comments for the whole block so it looks a bit more
intentional.
Otherwise
Reviwed-by: Mark Brown <broonie@kernel.org>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 3/3] serial: 8250_dw: add fractional divisor support
From: Jisheng Zhang @ 2018-07-11 6:41 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-kernel, linux-arm-kernel,
linux-serial
In-Reply-To: <8c5b6bbbde12b0836e1f833c86b805a817596654.camel@linux.intel.com>
Hi Andy,
On Tue, 10 Jul 2018 19:19:21 +0300 Andy Shevchenko wrote:
> On Tue, 2018-07-10 at 11:15 +0800, Jisheng Zhang wrote:
> > For Synopsys DesignWare 8250 uart which version >= 4.00a, there's a
> > valid divisor latch fraction register. The fractional divisor width is
> > 4bits ~ 6bits.
> >
> > Now the preparation is done, it's easy to add the feature support.
> > This patch firstly tries to get the fractional divisor width during
> > probe, then setups dw specific get_divisor() and set_divisor() hook.
>
> Thanks for an update, my comments below.
>
> > +/*
> > + * divisor = div(I) + div(F)
> > + * "I" means integer, "F" means fractional
> > + * quot = div(I) = clk / (16 * baud)
> > + * frac = div(F) * 2^dlf_size
> > + *
> > + * let rem = clk % (16 * baud)
> > + * we have: div(F) * (16 * baud) = rem
> > + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16
> > * baud)
> > + */
> > +static unsigned int dw8250_get_divisor(struct uart_port *p,
> > + unsigned int baud,
> > + unsigned int *frac)
> > +{
>
> unsigned int base_baud = baud * 16;
Good point. will send a new version.
>
> > + unsigned int quot, rem;
> > + struct dw8250_data *d = p->private_data;
> > +
> > + quot = p->uartclk / (16 * baud);
> > + rem = p->uartclk % (16 * baud);
> > + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, 16 * baud);
> > +
>
> While it looks indeed better, I would rather like to have a confirmation
> it's working as designed.
>
> For example, when I did some calculus, I cooked a preliminary check in
> Python (easy and fast to prototype), for example:
> https://gist.github.com/andy-shev/06b084488b3629898121 in Python, or
> commit 9df461eca18f ("spi: pxa2xx: replace ugly table by approximation")
> in the kernel.
>
> Or another one here https://gist.github.com/andy-shev/8b2a73aeca2874f4cc
> 89 and commits c1a67b48f6a5 ("serial: 8250_pci: replace switch-case by
> formula for Intel MID"), 21947ba654a6 ("serial: 8250_pci: replace
> switch-case by formula")
My python coding skill is limited. So I wrote a simple c program to
do the check for common clks and baudrate combination. All passed. I
paste the code here:
#include <stdio.h>
#include <assert.h>
#include <math.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define DIV_ROUND_CLOSEST(x, divisor)( \
{ \
typeof(x) __x = x; \
typeof(divisor) __d = divisor; \
(((typeof(x))-1) > 0 || \
((typeof(divisor))-1) > 0 || \
(((__x) > 0) == ((__d) > 0))) ? \
(((__x) + ((__d) / 2)) / (__d)) : \
(((__x) - ((__d) / 2)) / (__d)); \
} \
)
static unsigned int baud[] = {9600, 19200, 38400, 57600, 115200, 230400,
460800, 921600, 1843200, 3250000, 4454400,
576000, 1152000, 500000, 1000000, 1500000,
2000000, 2500000, 3000000, 3500000, 4000000};
static unsigned int clk[] = {25000000, 50000000, 100000000, 133000000, 200000000};
static void check(int baud, int clk, int dlf_size)
{
unsigned int rem, frac, quot;
unsigned int base_baud = baud * 16;
float div, divf;
quot = clk / base_baud;
rem = clk % base_baud;
frac = DIV_ROUND_CLOSEST(rem << dlf_size, base_baud);
div = (float)clk / base_baud;
divf = div - (int)div;
divf *= (1 << dlf_size);
assert(quot == (int)div);
assert(frac == (int)round(divf));
printf("checked %d %d %d %d %d\n", baud, clk, dlf_size, quot, frac);
}
int main()
{
int i, j, k;
for (i = 0; i < ARRAY_SIZE(baud); i++) {
for (j = 0; j < ARRAY_SIZE(clk); j++) {
for (k = 4; k <= 6; k++) {
check(baud[i], clk[j], k);
}
}
}
return 0;
}
^ permalink raw reply
* [PATCH v5 3/3] serial: 8250_dw: add fractional divisor support
From: Jisheng Zhang @ 2018-07-11 7:11 UTC (permalink / raw)
To: Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180710111516.13b8c570@xhacker.debian>
For Synopsys DesignWare 8250 uart which version >= 4.00a, there's a
valid divisor latch fraction register. The fractional divisor width is
4bits ~ 6bits.
Now the preparation is done, it's easy to add the feature support.
This patch firstly tries to get the fractional divisor width during
probe, then setups dw specific get_divisor() and set_divisor() hook.
Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
---
drivers/tty/serial/8250/8250_dw.c | 45 +++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index fa8a00e8c9c6..5a60c4814d62 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -31,6 +31,7 @@
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
+#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */
@@ -55,6 +56,7 @@
struct dw8250_data {
u8 usr_reg;
+ u8 dlf_size;
int line;
int msr_mask_on;
int msr_mask_off;
@@ -366,6 +368,37 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev->parent;
}
+/*
+ * divisor = div(I) + div(F)
+ * "I" means integer, "F" means fractional
+ * quot = div(I) = clk / (16 * baud)
+ * frac = div(F) * 2^dlf_size
+ *
+ * let rem = clk % (16 * baud)
+ * we have: div(F) * (16 * baud) = rem
+ * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud)
+ */
+static unsigned int dw8250_get_divisor(struct uart_port *p,
+ unsigned int baud,
+ unsigned int *frac)
+{
+ unsigned int quot, rem, base_baud = baud * 16;
+ struct dw8250_data *d = p->private_data;
+
+ quot = p->uartclk / base_baud;
+ rem = p->uartclk % base_baud;
+ *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud);
+
+ return quot;
+}
+
+static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
+ serial8250_do_set_divisor(p, baud, quot, quot_frac);
+}
+
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
if (p->dev->of_node) {
@@ -426,6 +459,18 @@ static void dw8250_setup_port(struct uart_port *p)
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+ dw8250_writel_ext(p, DW_UART_DLF, ~0U);
+ reg = dw8250_readl_ext(p, DW_UART_DLF);
+ dw8250_writel_ext(p, DW_UART_DLF, 0);
+
+ if (reg) {
+ struct dw8250_data *d = p->private_data;
+
+ d->dlf_size = fls(reg);
+ p->get_divisor = dw8250_get_divisor;
+ p->set_divisor = dw8250_set_divisor;
+ }
+
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg)
return;
--
2.18.0
^ permalink raw reply related
* Re: [PATCH v10 0/6] Driver for at91 usart in spi mode
From: Nicolas Ferre @ 2018-07-11 8:26 UTC (permalink / raw)
To: Radu Pirea, lee.jones
Cc: broonie, alexandre.belloni, richard.genoud, robh+dt, mark.rutland,
gregkh, linux-spi, linux-arm-kernel, linux-kernel, devicetree,
linux-serial
In-Reply-To: <20180625172230.29686-1-radu.pirea@microchip.com>
On 25/06/2018 at 19:22, Radu Pirea wrote:
> Hello,
>
> This is the second version of driver. I added a mfd driver which by
> default probes atmel_serial driver and if in dt is specified to probe
> the spi driver, then the spi-at91-usart driver will be probed. The
> compatible for atmel_serial is now the compatible for at91-usart mfd
> driver and compatilbe for atmel_serial driver was changed in order to
> keep the bindings for serial as they are.
>
> Changes in v10:
> -fixed kbuild test robot warning
>
> Changes in v9:
> - minor changes
> - rebased on top of broonie/for-4.19
>
> Changes in v8:
> - fixed passing an empty mfd cell if "atmel,usart-mode" value is invalid
>
> Changes in v7:
> - synced up SPDIX license with module license
> - numbering of usart modes starts from 0 insteand of 1
>
> Changes in v6:
> - removed unused compatible strings from serial and spi drivers
>
> Changes in v5:
> - fixed usage of stdout-path property with atmel_serial driver
>
> Changes in v4:
> - modified the spi driver to use cs gpio support form spi subsystem
> - fixed dma transfers for serial driver
> - squashed binding for spi and serial and moved them to mfd/atmel-usart.txt
>
> Changes in v3:
> - fixed spi slaves probing
>
> Changes in v2:
> - added at91-usart mfd driver
> - modified spi-at91-usart driver to work as mfd driver child
> - modified atmel_serial driver to work as mfd driver child
>
> Changes in v1:
> - added spi-at91-usart driver
>
>
> Radu Pirea (6):
> MAINTAINERS: add at91 usart mfd driver
> dt-bindings: add binding for atmel-usart in SPI mode
> mfd: at91-usart: added mfd driver for usart
> MAINTAINERS: add at91 usart spi driver
> spi: at91-usart: add driver for at91-usart as spi
> tty/serial: atmel: change the driver to work under at91-usart mfd
For the record or if needed by the MAINTAINERS changes, you can add my:
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
for the whole series.
Once the remarks by Mark are addressed, you can certainly re-send the
series with all tags collected for Lee to take it, if he is okay with
this process, of course...
Thanks, best regards,
Nicolas
> .../bindings/{serial => mfd}/atmel-usart.txt | 25 +-
> MAINTAINERS | 16 +
> drivers/mfd/Kconfig | 9 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/at91-usart.c | 71 +++
> drivers/spi/Kconfig | 9 +
> drivers/spi/Makefile | 1 +
> drivers/spi/spi-at91-usart.c | 432 ++++++++++++++++++
> drivers/tty/serial/Kconfig | 1 +
> drivers/tty/serial/atmel_serial.c | 42 +-
> include/dt-bindings/mfd/at91-usart.h | 17 +
> 11 files changed, 607 insertions(+), 17 deletions(-)
> rename Documentation/devicetree/bindings/{serial => mfd}/atmel-usart.txt (76%)
> create mode 100644 drivers/mfd/at91-usart.c
> create mode 100644 drivers/spi/spi-at91-usart.c
> create mode 100644 include/dt-bindings/mfd/at91-usart.h
>
--
Nicolas Ferre
^ permalink raw reply
* Re: [PATCH v5 3/3] serial: 8250_dw: add fractional divisor support
From: Andy Shevchenko @ 2018-07-11 11:31 UTC (permalink / raw)
To: Jisheng Zhang, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-arm-kernel, linux-kernel, linux-serial
In-Reply-To: <20180711151111.6f417020@xhacker.debian>
On Wed, 2018-07-11 at 15:11 +0800, Jisheng Zhang wrote:
> For Synopsys DesignWare 8250 uart which version >= 4.00a, there's a
> valid divisor latch fraction register. The fractional divisor width is
> 4bits ~ 6bits.
>
> Now the preparation is done, it's easy to add the feature support.
> This patch firstly tries to get the fractional divisor width during
> probe, then setups dw specific get_divisor() and set_divisor() hook.
>
You would need to resend entire series as v6.
Don't forget to add given tags.
But, wait a bit, I would like to check the algo (thanks for C program!).
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 0/3] add ISO7816 support
From: Ludovic Desroches @ 2018-07-11 13:16 UTC (permalink / raw)
To: linux-serial, linux-arch, linux-arm-kernel
Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
alexandre.belloni, linux-kernel, Ludovic Desroches
Hi,
This set of patches adds support for the ISO7816 standard. The USART devices in
Microchip SoCs have an ISO7816 mode. It allows to let the USART managing
the CLK and I/O signals of a smart card.
Nicolas Ferre (3):
tty/serial_core: add ISO7816 infrastructure
tty/serial: atmel: add ISO7816 support
tty/serial: atmel: manage shutdown in case of RS485 or ISO7816 mode
drivers/tty/serial/atmel_serial.c | 179 +++++++++++++++++++++++++++++++++++---
drivers/tty/serial/atmel_serial.h | 3 +-
drivers/tty/serial/serial_core.c | 49 +++++++++++
include/linux/serial_core.h | 3 +
include/uapi/asm-generic/ioctls.h | 2 +
include/uapi/linux/serial.h | 17 ++++
6 files changed, 241 insertions(+), 12 deletions(-)
--
2.12.2
^ permalink raw reply
* [PATCH 1/3] tty/serial_core: add ISO7816 infrastructure
From: Ludovic Desroches @ 2018-07-11 13:16 UTC (permalink / raw)
To: linux-serial, linux-arch, linux-arm-kernel
Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
alexandre.belloni, linux-kernel, Ludovic Desroches
In-Reply-To: <20180711131638.12622-1-ludovic.desroches@microchip.com>
From: Nicolas Ferre <nicolas.ferre@microchip.com>
Add the ISO7816 ioctl and associated accessors and data structure.
Drivers can then use this common implementation to handle ISO7816.
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
[ludovic.desroches@microchip.com: squash and rebase, removal of gpios, checkpatch fixes]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
drivers/tty/serial/serial_core.c | 49 +++++++++++++++++++++++++++++++++++++++
include/linux/serial_core.h | 3 +++
include/uapi/asm-generic/ioctls.h | 2 ++
include/uapi/linux/serial.h | 17 ++++++++++++++
4 files changed, 71 insertions(+)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c14a453f73c..c89ac59f6f8c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1301,6 +1301,47 @@ static int uart_set_rs485_config(struct uart_port *port,
return 0;
}
+static int uart_get_iso7816_config(struct uart_port *port,
+ struct serial_iso7816 __user *iso7816)
+{
+ unsigned long flags;
+ struct serial_iso7816 aux;
+
+ spin_lock_irqsave(&port->lock, flags);
+ aux = port->iso7816;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (copy_to_user(iso7816, &aux, sizeof(aux)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int uart_set_iso7816_config(struct uart_port *port,
+ struct serial_iso7816 __user *iso7816_user)
+{
+ struct serial_iso7816 iso7816;
+ int ret;
+ unsigned long flags;
+
+ if (!port->iso7816_config)
+ return -ENOIOCTLCMD;
+
+ if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ret = port->iso7816_config(port, &iso7816);
+ spin_unlock_irqrestore(&port->lock, flags);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
+ return -EFAULT;
+
+ return 0;
+}
+
/*
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
@@ -1385,6 +1426,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg);
break;
+
+ case TIOCSISO7816:
+ ret = uart_set_iso7816_config(state->uart_port, uarg);
+ break;
+
+ case TIOCGISO7816:
+ ret = uart_get_iso7816_config(state->uart_port, uarg);
+ break;
default:
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 06ea4eeb09ab..d6e7747ffd46 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -137,6 +137,8 @@ struct uart_port {
void (*handle_break)(struct uart_port *);
int (*rs485_config)(struct uart_port *,
struct serial_rs485 *rs485);
+ int (*iso7816_config)(struct uart_port *,
+ struct serial_iso7816 *iso7816);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
@@ -253,6 +255,7 @@ struct uart_port {
struct attribute_group *attr_group; /* port specific attributes */
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485;
+ struct serial_iso7816 iso7816;
void *private_data; /* generic platform data pointer */
};
diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/ioctls.h
index 040651735662..0e5c79726c2d 100644
--- a/include/uapi/asm-generic/ioctls.h
+++ b/include/uapi/asm-generic/ioctls.h
@@ -66,6 +66,8 @@
#ifndef TIOCSRS485
#define TIOCSRS485 0x542F
#endif
+#define TIOCGISO7816 0x5430
+#define TIOCSISO7816 0x5431
#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 3fdd0dee8b41..93eb3c496ff1 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -132,4 +132,21 @@ struct serial_rs485 {
are a royal PITA .. */
};
+/*
+ * Serial interface for controlling ISO7816 settings on chips with suitable
+ * support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by
+ * your platform.
+ */
+struct serial_iso7816 {
+ __u32 flags; /* ISO7816 feature flags */
+#define SER_ISO7816_ENABLED (1 << 0)
+#define SER_ISO7816_T_PARAM (0x0f << 4)
+#define SER_ISO7816_T(t) (((t) & 0x0f) << 4)
+ __u32 tg;
+ __u32 sc_fi;
+ __u32 sc_di;
+ __u32 clk;
+ __u32 reserved[5];
+};
+
#endif /* _UAPI_LINUX_SERIAL_H */
--
2.12.2
^ permalink raw reply related
* [PATCH 2/3] tty/serial: atmel: add ISO7816 support
From: Ludovic Desroches @ 2018-07-11 13:16 UTC (permalink / raw)
To: linux-serial, linux-arch, linux-arm-kernel
Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
alexandre.belloni, linux-kernel, Ludovic Desroches
In-Reply-To: <20180711131638.12622-1-ludovic.desroches@microchip.com>
From: Nicolas Ferre <nicolas.ferre@microchip.com>
When mode is set in atmel_config_iso7816() we backup last RS232 mode
for coming back to this mode if requested.
Also allow setup of T=0 and T=1 parameter and basic support in set_termios
function as well.
Report NACK and ITER errors in irq handler.
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
[ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
drivers/tty/serial/atmel_serial.c | 175 +++++++++++++++++++++++++++++++++++---
drivers/tty/serial/atmel_serial.h | 3 +-
2 files changed, 167 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8e4428725848..0118b219f3a8 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -34,6 +34,7 @@
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <asm/div64.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -147,6 +148,8 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct mctrl_gpios *gpios;
+ u32 backup_mode; /* MR saved during iso7816 operations */
+ u32 backup_brgr; /* BRGR saved during iso7816 operations */
unsigned int tx_done_mask;
u32 fifo_size;
u32 rts_high;
@@ -362,6 +365,136 @@ static int atmel_config_rs485(struct uart_port *port,
return 0;
}
+static unsigned int atmel_calc_cd(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int cd;
+ u64 mck_rate;
+
+ mck_rate = (u64)clk_get_rate(atmel_port->clk);
+ dev_dbg(port->dev, "ISO7816 mck_rate = %lld\n", mck_rate);
+ do_div(mck_rate, iso7816conf->clk);
+ cd = mck_rate;
+ dev_dbg(port->dev, "ISO7816 clk = %d. CD = %d\n", iso7816conf->clk, cd);
+ return cd;
+}
+
+static unsigned int atmel_calc_fidi(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ u64 fidi = 0;
+
+ dev_dbg(port->dev, "ISO7816 fi(%d) / di(%d)\n",
+ iso7816conf->sc_fi, iso7816conf->sc_di);
+ if (iso7816conf->sc_fi && iso7816conf->sc_di) {
+ fidi = (u64)iso7816conf->sc_fi;
+ do_div(fidi, iso7816conf->sc_di);
+ }
+ dev_dbg(port->dev, "ISO7816 fidi = 0x%x\n", (u32)fidi);
+ return (u32)fidi;
+}
+
+/* Enable or disable the iso7816 support */
+/* Called with interrupts disabled */
+static int atmel_config_iso7816(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int mode, t;
+ unsigned int cd, fidi;
+ int ret = 0;
+
+ /* Disable RX and TX */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS | ATMEL_US_TXDIS);
+ /* Disable interrupts */
+ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
+
+ mode = atmel_uart_readl(port, ATMEL_US_MR);
+
+ if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
+ /* port not yet in iso7816 mode: store configuration */
+ atmel_port->backup_mode = mode;
+ atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
+ }
+
+ if (iso7816conf->flags & SER_ISO7816_ENABLED) {
+ mode &= ~ATMEL_US_USMODE;
+
+ if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(0)) {
+ mode |= ATMEL_US_USMODE_ISO7816_T0;
+ t = 0;
+ } else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(1)) {
+ mode |= ATMEL_US_USMODE_ISO7816_T1;
+ t = 1;
+ } else {
+ dev_warn(port->dev, "ISO7816 Type not supported. Resetting\n");
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ goto err_out;
+ }
+
+ dev_dbg(port->dev, "Setting USART to ISO7816 mode T%d\n", t);
+
+ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+ | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+ /* NACK configuration */
+ if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(0))
+ mode |= ATMEL_US_DSNACK;
+ else
+ mode |= ATMEL_US_INACK;
+ /* select mck clock, and output */
+ mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+ /* set parity for normal/inverse mode + max iterations */
+ mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | (3 << 24);
+
+ cd = atmel_calc_cd(port, iso7816conf);
+ fidi = atmel_calc_fidi(port, iso7816conf);
+ if (fidi < 0) {
+ dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
+ } else if (fidi == 1 || fidi == 2) {
+ dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
+ ret = -EINVAL;
+ goto err_out;
+ }
+ /* Actually set ISO7816 mode */
+ atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
+ atmel_uart_writel(port, ATMEL_US_BRGR, cd);
+ atmel_uart_writel(port, ATMEL_US_FIDIR, fidi);
+
+ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
+ } else {
+ dev_dbg(port->dev, "Setting UART to RS232\n");
+ /* back to last RS232 settings */
+ mode = atmel_port->backup_mode;
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ atmel_uart_writel(port, ATMEL_US_TTGR, 0);
+ atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
+ atmel_uart_writel(port, ATMEL_US_FIDIR, 0x174);
+
+ if (atmel_use_pdc_tx(port))
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+ ATMEL_US_TXBUFE;
+ else
+ atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+ }
+
+ port->iso7816 = *iso7816conf;
+
+ atmel_uart_writel(port, ATMEL_US_MR, mode);
+
+err_out:
+ /* Enable interrupts */
+ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+ /* Enable RX and TX */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN | ATMEL_US_TXEN);
+
+ return ret;
+}
+
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
@@ -481,8 +614,9 @@ static void atmel_stop_tx(struct uart_port *port)
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_start_rx(port);
}
@@ -500,8 +634,9 @@ static void atmel_start_tx(struct uart_port *port)
return;
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_stop_rx(port);
if (atmel_use_pdc_tx(port))
@@ -799,8 +934,9 @@ static void atmel_complete_tx_dma(void *arg)
*/
if (!uart_circ_empty(xmit))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
- else if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ else if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@@ -1281,6 +1417,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
wake_up_interruptible(&port->state->port.delta_msr_wait);
}
}
+
+ if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
+ dev_err(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
}
/*
@@ -1373,8 +1512,9 @@ static void atmel_tx_pdc(struct uart_port *port)
atmel_uart_writel(port, ATMEL_US_IER,
atmel_port->tx_done_mask);
} else {
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@@ -2099,6 +2239,18 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
atmel_uart_writel(port, ATMEL_US_TTGR,
port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
+ } else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
+ dev_dbg(port->dev, "Setting UART to ISO7816 in termios\n");
+ atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
+ /* select mck clock, and output */
+ mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+ /* set max iterations */
+ mode |= (3 << 24);
+ if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(0))
+ mode |= ATMEL_US_USMODE_ISO7816_T0;
+ else
+ mode |= ATMEL_US_USMODE_ISO7816_T1;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
if (atmel_use_fifo(port) &&
@@ -2175,7 +2327,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
}
quot = cd | fp << ATMEL_US_FP_OFFSET;
- atmel_uart_writel(port, ATMEL_US_BRGR, quot);
+ if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
+ atmel_uart_writel(port, ATMEL_US_BRGR, quot);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
atmel_port->tx_stopped = false;
@@ -2355,6 +2508,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
port->rs485_config = atmel_config_rs485;
+ port->iso7816_config = atmel_config_iso7816;
port->membase = NULL;
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
@@ -2379,7 +2533,8 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
}
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
- if (port->rs485.flags & SER_RS485_ENABLED)
+ if (port->rs485.flags & SER_RS485_ENABLED ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
else if (atmel_use_pdc_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE;
diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h
index ba3a2437cde4..fff51f5fe8bc 100644
--- a/drivers/tty/serial/atmel_serial.h
+++ b/drivers/tty/serial/atmel_serial.h
@@ -124,7 +124,8 @@
#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */
#define ATMEL_US_TG GENMASK(7, 0) /* Timeguard Value */
-#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */
+#define ATMEL_US_FIDIR 0x40 /* FI DI Ratio Register */
+#define ATMEL_US_FIDI GENMASK(15, 0) /* FIDI ratio */
#define ATMEL_US_NER 0x44 /* Number of Errors Register */
#define ATMEL_US_IF 0x4c /* IrDA Filter Register */
--
2.12.2
^ permalink raw reply related
* [PATCH 3/3] tty/serial: atmel: manage shutdown in case of RS485 or ISO7816 mode
From: Ludovic Desroches @ 2018-07-11 13:16 UTC (permalink / raw)
To: linux-serial, linux-arch, linux-arm-kernel
Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
alexandre.belloni, linux-kernel
In-Reply-To: <20180711131638.12622-1-ludovic.desroches@microchip.com>
From: Nicolas Ferre <nicolas.ferre@microchip.com>
In atmel_shutdown() we call atmel_stop_rx() and atmel_stop_tx() functions.
Prevent the rx restart that is implemented in RS485 or ISO7816 modes when
calling atmel_stop_tx() by using the atomic information tasklet_shutdown
that is already in place for this purpose.
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
---
drivers/tty/serial/atmel_serial.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 0118b219f3a8..e4f877e1f3c6 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -617,7 +617,9 @@ static void atmel_stop_tx(struct uart_port *port)
if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
- atmel_start_rx(port);
+ if (!atomic_read(&atmel_port->tasklet_shutdown))
+ atmel_start_rx(port);
+
}
/*
--
2.12.2
^ permalink raw reply related
* [PATCH 3/3] tty/serial: atmel: manage shutdown in case of RS485 or ISO7816 mode
From: Ludovic Desroches @ 2018-07-11 13:26 UTC (permalink / raw)
To: linux-serial, linux-arch, linux-arm-kernel
Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
alexandre.belloni, linux-kernel
In-Reply-To: <20180711131638.12622-1-ludovic.desroches@microchip.com>
From: Nicolas Ferre <nicolas.ferre@microchip.com>
In atmel_shutdown() we call atmel_stop_rx() and atmel_stop_tx() functions.
Prevent the rx restart that is implemented in RS485 or ISO7816 modes when
calling atmel_stop_tx() by using the atomic information tasklet_shutdown
that is already in place for this purpose.
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
---
drivers/tty/serial/atmel_serial.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 0118b219f3a8..e4f877e1f3c6 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -617,7 +617,9 @@ static void atmel_stop_tx(struct uart_port *port)
if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
- atmel_start_rx(port);
+ if (!atomic_read(&atmel_port->tasklet_shutdown))
+ atmel_start_rx(port);
+
}
/*
--
2.12.2
^ permalink raw reply related
* Re: [PATCH v4 3/3] serial: 8250_dw: add fractional divisor support
From: Andy Shevchenko @ 2018-07-11 14:23 UTC (permalink / raw)
To: Jisheng Zhang
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-kernel, linux-arm-kernel,
linux-serial
In-Reply-To: <20180711144125.7d4e6a73@xhacker.debian>
On Wed, 2018-07-11 at 14:41 +0800, Jisheng Zhang wrote:
> On Tue, 10 Jul 2018 19:19:21 +0300 Andy Shevchenko wrote:
> > > +/*
> > > + * divisor = div(I) + div(F)
> > > + * "I" means integer, "F" means fractional
> > > + * quot = div(I) = clk / (16 * baud)
> > > + * frac = div(F) * 2^dlf_size
> > > + *
> > > + * let rem = clk % (16 * baud)
> > > + * we have: div(F) * (16 * baud) = rem
> > > + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) /
> > > (16
> > > * baud)
> > > + */
> > > + quot = p->uartclk / (16 * baud);
> > > + rem = p->uartclk % (16 * baud);
> > > + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, 16 * baud
> My python coding skill is limited. So I wrote a simple c program to
> do the check for common clks and baudrate combination. All passed. I
> paste the code here:
>
OK, I wrote test case in Python:
https://gist.github.com/andy-shev/5e980f1d752617ba814725248556ac19
Looks good to me.
Please, send v6 and assume my Reviewed-by for entire series.
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH v4] uart: fix race between uart_put_char() and uart_shutdown()
From: Tycho Andersen @ 2018-07-11 16:07 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: linux-serial, linux-kernel, Serge E . Hallyn, Tycho Andersen
In-Reply-To: <20180706212220.GC3583@cisco.lan>
We have reports of the following crash:
PID: 7 TASK: ffff88085c6d61c0 CPU: 1 COMMAND: "kworker/u25:0"
#0 [ffff88085c6db710] machine_kexec at ffffffff81046239
#1 [ffff88085c6db760] crash_kexec at ffffffff810fc248
#2 [ffff88085c6db830] oops_end at ffffffff81008ae7
#3 [ffff88085c6db860] no_context at ffffffff81050b8f
#4 [ffff88085c6db8b0] __bad_area_nosemaphore at ffffffff81050d75
#5 [ffff88085c6db900] bad_area_nosemaphore at ffffffff81050e83
#6 [ffff88085c6db910] __do_page_fault at ffffffff8105132e
#7 [ffff88085c6db9b0] do_page_fault at ffffffff8105152c
#8 [ffff88085c6db9c0] page_fault at ffffffff81a3f122
[exception RIP: uart_put_char+149]
RIP: ffffffff814b67b5 RSP: ffff88085c6dba78 RFLAGS: 00010006
RAX: 0000000000000292 RBX: ffffffff827c5120 RCX: 0000000000000081
RDX: 0000000000000000 RSI: 000000000000005f RDI: ffffffff827c5120
RBP: ffff88085c6dba98 R8: 000000000000012c R9: ffffffff822ea320
R10: ffff88085fe4db04 R11: 0000000000000001 R12: ffff881059f9c000
R13: 0000000000000001 R14: 000000000000005f R15: 0000000000000fba
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#9 [ffff88085c6dbaa0] tty_put_char at ffffffff81497544
#10 [ffff88085c6dbac0] do_output_char at ffffffff8149c91c
#11 [ffff88085c6dbae0] __process_echoes at ffffffff8149cb8b
#12 [ffff88085c6dbb30] commit_echoes at ffffffff8149cdc2
#13 [ffff88085c6dbb60] n_tty_receive_buf_fast at ffffffff8149e49b
#14 [ffff88085c6dbbc0] __receive_buf at ffffffff8149ef5a
#15 [ffff88085c6dbc20] n_tty_receive_buf_common at ffffffff8149f016
#16 [ffff88085c6dbca0] n_tty_receive_buf2 at ffffffff8149f194
#17 [ffff88085c6dbcb0] flush_to_ldisc at ffffffff814a238a
#18 [ffff88085c6dbd50] process_one_work at ffffffff81090be2
#19 [ffff88085c6dbe20] worker_thread at ffffffff81091b4d
#20 [ffff88085c6dbeb0] kthread at ffffffff81096384
#21 [ffff88085c6dbf50] ret_from_fork at ffffffff81a3d69f
after slogging through some dissasembly:
ffffffff814b6720 <uart_put_char>:
ffffffff814b6720: 55 push %rbp
ffffffff814b6721: 48 89 e5 mov %rsp,%rbp
ffffffff814b6724: 48 83 ec 20 sub $0x20,%rsp
ffffffff814b6728: 48 89 1c 24 mov %rbx,(%rsp)
ffffffff814b672c: 4c 89 64 24 08 mov %r12,0x8(%rsp)
ffffffff814b6731: 4c 89 6c 24 10 mov %r13,0x10(%rsp)
ffffffff814b6736: 4c 89 74 24 18 mov %r14,0x18(%rsp)
ffffffff814b673b: e8 b0 8e 58 00 callq ffffffff81a3f5f0 <mcount>
ffffffff814b6740: 4c 8b a7 88 02 00 00 mov 0x288(%rdi),%r12
ffffffff814b6747: 45 31 ed xor %r13d,%r13d
ffffffff814b674a: 41 89 f6 mov %esi,%r14d
ffffffff814b674d: 49 83 bc 24 70 01 00 cmpq $0x0,0x170(%r12)
ffffffff814b6754: 00 00
ffffffff814b6756: 49 8b 9c 24 80 01 00 mov 0x180(%r12),%rbx
ffffffff814b675d: 00
ffffffff814b675e: 74 2f je ffffffff814b678f <uart_put_char+0x6f>
ffffffff814b6760: 48 89 df mov %rbx,%rdi
ffffffff814b6763: e8 a8 67 58 00 callq ffffffff81a3cf10 <_raw_spin_lock_irqsave>
ffffffff814b6768: 41 8b 8c 24 78 01 00 mov 0x178(%r12),%ecx
ffffffff814b676f: 00
ffffffff814b6770: 89 ca mov %ecx,%edx
ffffffff814b6772: f7 d2 not %edx
ffffffff814b6774: 41 03 94 24 7c 01 00 add 0x17c(%r12),%edx
ffffffff814b677b: 00
ffffffff814b677c: 81 e2 ff 0f 00 00 and $0xfff,%edx
ffffffff814b6782: 75 23 jne ffffffff814b67a7 <uart_put_char+0x87>
ffffffff814b6784: 48 89 c6 mov %rax,%rsi
ffffffff814b6787: 48 89 df mov %rbx,%rdi
ffffffff814b678a: e8 e1 64 58 00 callq ffffffff81a3cc70 <_raw_spin_unlock_irqrestore>
ffffffff814b678f: 44 89 e8 mov %r13d,%eax
ffffffff814b6792: 48 8b 1c 24 mov (%rsp),%rbx
ffffffff814b6796: 4c 8b 64 24 08 mov 0x8(%rsp),%r12
ffffffff814b679b: 4c 8b 6c 24 10 mov 0x10(%rsp),%r13
ffffffff814b67a0: 4c 8b 74 24 18 mov 0x18(%rsp),%r14
ffffffff814b67a5: c9 leaveq
ffffffff814b67a6: c3 retq
ffffffff814b67a7: 49 8b 94 24 70 01 00 mov 0x170(%r12),%rdx
ffffffff814b67ae: 00
ffffffff814b67af: 48 63 c9 movslq %ecx,%rcx
ffffffff814b67b2: 41 b5 01 mov $0x1,%r13b
ffffffff814b67b5: 44 88 34 0a mov %r14b,(%rdx,%rcx,1)
ffffffff814b67b9: 41 8b 94 24 78 01 00 mov 0x178(%r12),%edx
ffffffff814b67c0: 00
ffffffff814b67c1: 83 c2 01 add $0x1,%edx
ffffffff814b67c4: 81 e2 ff 0f 00 00 and $0xfff,%edx
ffffffff814b67ca: 41 89 94 24 78 01 00 mov %edx,0x178(%r12)
ffffffff814b67d1: 00
ffffffff814b67d2: eb b0 jmp ffffffff814b6784 <uart_put_char+0x64>
ffffffff814b67d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
ffffffff814b67db: 00 00 00 00 00
for our build, this is crashing at:
circ->buf[circ->head] = c;
Looking in uart_port_startup(), it seems that circ->buf (state->xmit.buf)
protected by the "per-port mutex", which based on uart_port_check() is
state->port.mutex. Indeed, the lock acquired in uart_put_char() is
uport->lock, i.e. not the same lock.
Anyway, since the lock is not acquired, if uart_shutdown() is called, the
last chunk of that function may release state->xmit.buf before its assigned
to null, and cause the race above.
To fix it, let's lock uport->lock when allocating/deallocating
state->xmit.buf in addition to the per-port mutex.
v2: switch to locking uport->lock on allocation/deallocation instead of
locking the per-port mutex in uart_put_char. Note that since
uport->lock is a spin lock, we have to switch the allocation to
GFP_ATOMIC.
v3: move the allocation outside the lock, so we can switch back to
GFP_KERNEL
v4: * switch to positive condition of state->xmit.buf in
uart_port_startup()
* declare `flags` on its own line
* use the result of uart_port_lock() in uart_shutdown() to avoid
uninitialized warning
* don't use the uart_port_lock/unlock macros in uart_port_startup,
instead test against uport directly; the compiler can't seem to "see"
through the macros/ref/unref calls to not warn about uninitialized
flags. We don't need to do a ref here since we hold the per-port
mutex anyway.
Signed-off-by: Tycho Andersen <tycho@tycho.ws>
---
drivers/tty/serial/serial_core.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c14a453f73c..406e8382d3de 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
{
struct uart_port *uport = uart_port_check(state);
unsigned long page;
+ unsigned long flags;
int retval = 0;
if (uport->type == PORT_UNKNOWN)
@@ -196,15 +197,20 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* Initialise and allocate the transmit and temporary
* buffer.
*/
- if (!state->xmit.buf) {
- /* This is protected by the per port mutex */
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ if (uport)
+ spin_lock_irqsave(&uport->lock, flags);
+ if (state->xmit.buf) {
+ free_page(page);
+ } else {
state->xmit.buf = (unsigned char *) page;
uart_circ_clear(&state->xmit);
}
+ if (uport)
+ spin_unlock_irqrestore(&uport->lock, flags);
retval = uport->ops->startup(uport);
if (retval == 0) {
@@ -263,6 +269,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{
struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port;
+ unsigned long flags;
/*
* Set the TTY IO error marker
@@ -295,10 +302,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/*
* Free the transmit buffer page.
*/
+ uport = uart_port_lock(state, flags);
if (state->xmit.buf) {
free_page((unsigned long)state->xmit.buf);
state->xmit.buf = NULL;
}
+ uart_port_unlock(uport, flags);
}
/**
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v4] uart: fix race between uart_put_char() and uart_shutdown()
From: Serge E. Hallyn @ 2018-07-11 19:24 UTC (permalink / raw)
To: Tycho Andersen
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, linux-kernel,
Serge E . Hallyn
In-Reply-To: <20180711160744.32074-1-tycho@tycho.ws>
Quoting Tycho Andersen (tycho@tycho.ws):
> We have reports of the following crash:
>
> PID: 7 TASK: ffff88085c6d61c0 CPU: 1 COMMAND: "kworker/u25:0"
> #0 [ffff88085c6db710] machine_kexec at ffffffff81046239
> #1 [ffff88085c6db760] crash_kexec at ffffffff810fc248
> #2 [ffff88085c6db830] oops_end at ffffffff81008ae7
> #3 [ffff88085c6db860] no_context at ffffffff81050b8f
> #4 [ffff88085c6db8b0] __bad_area_nosemaphore at ffffffff81050d75
> #5 [ffff88085c6db900] bad_area_nosemaphore at ffffffff81050e83
> #6 [ffff88085c6db910] __do_page_fault at ffffffff8105132e
> #7 [ffff88085c6db9b0] do_page_fault at ffffffff8105152c
> #8 [ffff88085c6db9c0] page_fault at ffffffff81a3f122
> [exception RIP: uart_put_char+149]
> RIP: ffffffff814b67b5 RSP: ffff88085c6dba78 RFLAGS: 00010006
> RAX: 0000000000000292 RBX: ffffffff827c5120 RCX: 0000000000000081
> RDX: 0000000000000000 RSI: 000000000000005f RDI: ffffffff827c5120
> RBP: ffff88085c6dba98 R8: 000000000000012c R9: ffffffff822ea320
> R10: ffff88085fe4db04 R11: 0000000000000001 R12: ffff881059f9c000
> R13: 0000000000000001 R14: 000000000000005f R15: 0000000000000fba
> ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
> #9 [ffff88085c6dbaa0] tty_put_char at ffffffff81497544
> #10 [ffff88085c6dbac0] do_output_char at ffffffff8149c91c
> #11 [ffff88085c6dbae0] __process_echoes at ffffffff8149cb8b
> #12 [ffff88085c6dbb30] commit_echoes at ffffffff8149cdc2
> #13 [ffff88085c6dbb60] n_tty_receive_buf_fast at ffffffff8149e49b
> #14 [ffff88085c6dbbc0] __receive_buf at ffffffff8149ef5a
> #15 [ffff88085c6dbc20] n_tty_receive_buf_common at ffffffff8149f016
> #16 [ffff88085c6dbca0] n_tty_receive_buf2 at ffffffff8149f194
> #17 [ffff88085c6dbcb0] flush_to_ldisc at ffffffff814a238a
> #18 [ffff88085c6dbd50] process_one_work at ffffffff81090be2
> #19 [ffff88085c6dbe20] worker_thread at ffffffff81091b4d
> #20 [ffff88085c6dbeb0] kthread at ffffffff81096384
> #21 [ffff88085c6dbf50] ret_from_fork at ffffffff81a3d69f
>
> after slogging through some dissasembly:
>
> ffffffff814b6720 <uart_put_char>:
> ffffffff814b6720: 55 push %rbp
> ffffffff814b6721: 48 89 e5 mov %rsp,%rbp
> ffffffff814b6724: 48 83 ec 20 sub $0x20,%rsp
> ffffffff814b6728: 48 89 1c 24 mov %rbx,(%rsp)
> ffffffff814b672c: 4c 89 64 24 08 mov %r12,0x8(%rsp)
> ffffffff814b6731: 4c 89 6c 24 10 mov %r13,0x10(%rsp)
> ffffffff814b6736: 4c 89 74 24 18 mov %r14,0x18(%rsp)
> ffffffff814b673b: e8 b0 8e 58 00 callq ffffffff81a3f5f0 <mcount>
> ffffffff814b6740: 4c 8b a7 88 02 00 00 mov 0x288(%rdi),%r12
> ffffffff814b6747: 45 31 ed xor %r13d,%r13d
> ffffffff814b674a: 41 89 f6 mov %esi,%r14d
> ffffffff814b674d: 49 83 bc 24 70 01 00 cmpq $0x0,0x170(%r12)
> ffffffff814b6754: 00 00
> ffffffff814b6756: 49 8b 9c 24 80 01 00 mov 0x180(%r12),%rbx
> ffffffff814b675d: 00
> ffffffff814b675e: 74 2f je ffffffff814b678f <uart_put_char+0x6f>
> ffffffff814b6760: 48 89 df mov %rbx,%rdi
> ffffffff814b6763: e8 a8 67 58 00 callq ffffffff81a3cf10 <_raw_spin_lock_irqsave>
> ffffffff814b6768: 41 8b 8c 24 78 01 00 mov 0x178(%r12),%ecx
> ffffffff814b676f: 00
> ffffffff814b6770: 89 ca mov %ecx,%edx
> ffffffff814b6772: f7 d2 not %edx
> ffffffff814b6774: 41 03 94 24 7c 01 00 add 0x17c(%r12),%edx
> ffffffff814b677b: 00
> ffffffff814b677c: 81 e2 ff 0f 00 00 and $0xfff,%edx
> ffffffff814b6782: 75 23 jne ffffffff814b67a7 <uart_put_char+0x87>
> ffffffff814b6784: 48 89 c6 mov %rax,%rsi
> ffffffff814b6787: 48 89 df mov %rbx,%rdi
> ffffffff814b678a: e8 e1 64 58 00 callq ffffffff81a3cc70 <_raw_spin_unlock_irqrestore>
> ffffffff814b678f: 44 89 e8 mov %r13d,%eax
> ffffffff814b6792: 48 8b 1c 24 mov (%rsp),%rbx
> ffffffff814b6796: 4c 8b 64 24 08 mov 0x8(%rsp),%r12
> ffffffff814b679b: 4c 8b 6c 24 10 mov 0x10(%rsp),%r13
> ffffffff814b67a0: 4c 8b 74 24 18 mov 0x18(%rsp),%r14
> ffffffff814b67a5: c9 leaveq
> ffffffff814b67a6: c3 retq
> ffffffff814b67a7: 49 8b 94 24 70 01 00 mov 0x170(%r12),%rdx
> ffffffff814b67ae: 00
> ffffffff814b67af: 48 63 c9 movslq %ecx,%rcx
> ffffffff814b67b2: 41 b5 01 mov $0x1,%r13b
> ffffffff814b67b5: 44 88 34 0a mov %r14b,(%rdx,%rcx,1)
> ffffffff814b67b9: 41 8b 94 24 78 01 00 mov 0x178(%r12),%edx
> ffffffff814b67c0: 00
> ffffffff814b67c1: 83 c2 01 add $0x1,%edx
> ffffffff814b67c4: 81 e2 ff 0f 00 00 and $0xfff,%edx
> ffffffff814b67ca: 41 89 94 24 78 01 00 mov %edx,0x178(%r12)
> ffffffff814b67d1: 00
> ffffffff814b67d2: eb b0 jmp ffffffff814b6784 <uart_put_char+0x64>
> ffffffff814b67d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
> ffffffff814b67db: 00 00 00 00 00
>
> for our build, this is crashing at:
>
> circ->buf[circ->head] = c;
>
> Looking in uart_port_startup(), it seems that circ->buf (state->xmit.buf)
> protected by the "per-port mutex", which based on uart_port_check() is
> state->port.mutex. Indeed, the lock acquired in uart_put_char() is
> uport->lock, i.e. not the same lock.
>
> Anyway, since the lock is not acquired, if uart_shutdown() is called, the
> last chunk of that function may release state->xmit.buf before its assigned
> to null, and cause the race above.
>
> To fix it, let's lock uport->lock when allocating/deallocating
> state->xmit.buf in addition to the per-port mutex.
>
> v2: switch to locking uport->lock on allocation/deallocation instead of
> locking the per-port mutex in uart_put_char. Note that since
> uport->lock is a spin lock, we have to switch the allocation to
> GFP_ATOMIC.
> v3: move the allocation outside the lock, so we can switch back to
> GFP_KERNEL
> v4: * switch to positive condition of state->xmit.buf in
> uart_port_startup()
> * declare `flags` on its own line
> * use the result of uart_port_lock() in uart_shutdown() to avoid
> uninitialized warning
> * don't use the uart_port_lock/unlock macros in uart_port_startup,
> instead test against uport directly; the compiler can't seem to "see"
> through the macros/ref/unref calls to not warn about uninitialized
> flags. We don't need to do a ref here since we hold the per-port
> mutex anyway.
>
> Signed-off-by: Tycho Andersen <tycho@tycho.ws>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Thanks, Tycho.
> ---
> drivers/tty/serial/serial_core.c | 19 ++++++++++++++-----
> 1 file changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 9c14a453f73c..406e8382d3de 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> {
> struct uart_port *uport = uart_port_check(state);
> unsigned long page;
> + unsigned long flags;
> int retval = 0;
>
> if (uport->type == PORT_UNKNOWN)
> @@ -196,15 +197,20 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> * Initialise and allocate the transmit and temporary
> * buffer.
> */
> - if (!state->xmit.buf) {
> - /* This is protected by the per port mutex */
> - page = get_zeroed_page(GFP_KERNEL);
> - if (!page)
> - return -ENOMEM;
> + page = get_zeroed_page(GFP_KERNEL);
> + if (!page)
> + return -ENOMEM;
>
> + if (uport)
> + spin_lock_irqsave(&uport->lock, flags);
> + if (state->xmit.buf) {
> + free_page(page);
> + } else {
> state->xmit.buf = (unsigned char *) page;
> uart_circ_clear(&state->xmit);
> }
> + if (uport)
> + spin_unlock_irqrestore(&uport->lock, flags);
>
> retval = uport->ops->startup(uport);
> if (retval == 0) {
> @@ -263,6 +269,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
> {
> struct uart_port *uport = uart_port_check(state);
> struct tty_port *port = &state->port;
> + unsigned long flags;
>
> /*
> * Set the TTY IO error marker
> @@ -295,10 +302,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
> /*
> * Free the transmit buffer page.
> */
> + uport = uart_port_lock(state, flags);
> if (state->xmit.buf) {
> free_page((unsigned long)state->xmit.buf);
> state->xmit.buf = NULL;
> }
> + uart_port_unlock(uport, flags);
> }
>
> /**
> --
> 2.17.1
^ permalink raw reply
* Re: [PATCH v4] uart: fix race between uart_put_char() and uart_shutdown()
From: Serge E. Hallyn @ 2018-07-11 19:49 UTC (permalink / raw)
To: Tycho Andersen
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, linux-kernel,
Serge E . Hallyn
In-Reply-To: <20180711160744.32074-1-tycho@tycho.ws>
Quoting Tycho Andersen (tycho@tycho.ws):
> We have reports of the following crash:
>
> PID: 7 TASK: ffff88085c6d61c0 CPU: 1 COMMAND: "kworker/u25:0"
> #0 [ffff88085c6db710] machine_kexec at ffffffff81046239
> #1 [ffff88085c6db760] crash_kexec at ffffffff810fc248
> #2 [ffff88085c6db830] oops_end at ffffffff81008ae7
> #3 [ffff88085c6db860] no_context at ffffffff81050b8f
> #4 [ffff88085c6db8b0] __bad_area_nosemaphore at ffffffff81050d75
> #5 [ffff88085c6db900] bad_area_nosemaphore at ffffffff81050e83
> #6 [ffff88085c6db910] __do_page_fault at ffffffff8105132e
> #7 [ffff88085c6db9b0] do_page_fault at ffffffff8105152c
> #8 [ffff88085c6db9c0] page_fault at ffffffff81a3f122
> [exception RIP: uart_put_char+149]
> RIP: ffffffff814b67b5 RSP: ffff88085c6dba78 RFLAGS: 00010006
> RAX: 0000000000000292 RBX: ffffffff827c5120 RCX: 0000000000000081
> RDX: 0000000000000000 RSI: 000000000000005f RDI: ffffffff827c5120
> RBP: ffff88085c6dba98 R8: 000000000000012c R9: ffffffff822ea320
> R10: ffff88085fe4db04 R11: 0000000000000001 R12: ffff881059f9c000
> R13: 0000000000000001 R14: 000000000000005f R15: 0000000000000fba
> ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
> #9 [ffff88085c6dbaa0] tty_put_char at ffffffff81497544
> #10 [ffff88085c6dbac0] do_output_char at ffffffff8149c91c
> #11 [ffff88085c6dbae0] __process_echoes at ffffffff8149cb8b
> #12 [ffff88085c6dbb30] commit_echoes at ffffffff8149cdc2
> #13 [ffff88085c6dbb60] n_tty_receive_buf_fast at ffffffff8149e49b
> #14 [ffff88085c6dbbc0] __receive_buf at ffffffff8149ef5a
> #15 [ffff88085c6dbc20] n_tty_receive_buf_common at ffffffff8149f016
> #16 [ffff88085c6dbca0] n_tty_receive_buf2 at ffffffff8149f194
> #17 [ffff88085c6dbcb0] flush_to_ldisc at ffffffff814a238a
> #18 [ffff88085c6dbd50] process_one_work at ffffffff81090be2
> #19 [ffff88085c6dbe20] worker_thread at ffffffff81091b4d
> #20 [ffff88085c6dbeb0] kthread at ffffffff81096384
> #21 [ffff88085c6dbf50] ret_from_fork at ffffffff81a3d69f
>
> after slogging through some dissasembly:
>
> ffffffff814b6720 <uart_put_char>:
> ffffffff814b6720: 55 push %rbp
> ffffffff814b6721: 48 89 e5 mov %rsp,%rbp
> ffffffff814b6724: 48 83 ec 20 sub $0x20,%rsp
> ffffffff814b6728: 48 89 1c 24 mov %rbx,(%rsp)
> ffffffff814b672c: 4c 89 64 24 08 mov %r12,0x8(%rsp)
> ffffffff814b6731: 4c 89 6c 24 10 mov %r13,0x10(%rsp)
> ffffffff814b6736: 4c 89 74 24 18 mov %r14,0x18(%rsp)
> ffffffff814b673b: e8 b0 8e 58 00 callq ffffffff81a3f5f0 <mcount>
> ffffffff814b6740: 4c 8b a7 88 02 00 00 mov 0x288(%rdi),%r12
> ffffffff814b6747: 45 31 ed xor %r13d,%r13d
> ffffffff814b674a: 41 89 f6 mov %esi,%r14d
> ffffffff814b674d: 49 83 bc 24 70 01 00 cmpq $0x0,0x170(%r12)
> ffffffff814b6754: 00 00
> ffffffff814b6756: 49 8b 9c 24 80 01 00 mov 0x180(%r12),%rbx
> ffffffff814b675d: 00
> ffffffff814b675e: 74 2f je ffffffff814b678f <uart_put_char+0x6f>
> ffffffff814b6760: 48 89 df mov %rbx,%rdi
> ffffffff814b6763: e8 a8 67 58 00 callq ffffffff81a3cf10 <_raw_spin_lock_irqsave>
> ffffffff814b6768: 41 8b 8c 24 78 01 00 mov 0x178(%r12),%ecx
> ffffffff814b676f: 00
> ffffffff814b6770: 89 ca mov %ecx,%edx
> ffffffff814b6772: f7 d2 not %edx
> ffffffff814b6774: 41 03 94 24 7c 01 00 add 0x17c(%r12),%edx
> ffffffff814b677b: 00
> ffffffff814b677c: 81 e2 ff 0f 00 00 and $0xfff,%edx
> ffffffff814b6782: 75 23 jne ffffffff814b67a7 <uart_put_char+0x87>
> ffffffff814b6784: 48 89 c6 mov %rax,%rsi
> ffffffff814b6787: 48 89 df mov %rbx,%rdi
> ffffffff814b678a: e8 e1 64 58 00 callq ffffffff81a3cc70 <_raw_spin_unlock_irqrestore>
> ffffffff814b678f: 44 89 e8 mov %r13d,%eax
> ffffffff814b6792: 48 8b 1c 24 mov (%rsp),%rbx
> ffffffff814b6796: 4c 8b 64 24 08 mov 0x8(%rsp),%r12
> ffffffff814b679b: 4c 8b 6c 24 10 mov 0x10(%rsp),%r13
> ffffffff814b67a0: 4c 8b 74 24 18 mov 0x18(%rsp),%r14
> ffffffff814b67a5: c9 leaveq
> ffffffff814b67a6: c3 retq
> ffffffff814b67a7: 49 8b 94 24 70 01 00 mov 0x170(%r12),%rdx
> ffffffff814b67ae: 00
> ffffffff814b67af: 48 63 c9 movslq %ecx,%rcx
> ffffffff814b67b2: 41 b5 01 mov $0x1,%r13b
> ffffffff814b67b5: 44 88 34 0a mov %r14b,(%rdx,%rcx,1)
> ffffffff814b67b9: 41 8b 94 24 78 01 00 mov 0x178(%r12),%edx
> ffffffff814b67c0: 00
> ffffffff814b67c1: 83 c2 01 add $0x1,%edx
> ffffffff814b67c4: 81 e2 ff 0f 00 00 and $0xfff,%edx
> ffffffff814b67ca: 41 89 94 24 78 01 00 mov %edx,0x178(%r12)
> ffffffff814b67d1: 00
> ffffffff814b67d2: eb b0 jmp ffffffff814b6784 <uart_put_char+0x64>
> ffffffff814b67d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
> ffffffff814b67db: 00 00 00 00 00
>
> for our build, this is crashing at:
>
> circ->buf[circ->head] = c;
>
> Looking in uart_port_startup(), it seems that circ->buf (state->xmit.buf)
> protected by the "per-port mutex", which based on uart_port_check() is
> state->port.mutex. Indeed, the lock acquired in uart_put_char() is
> uport->lock, i.e. not the same lock.
>
> Anyway, since the lock is not acquired, if uart_shutdown() is called, the
> last chunk of that function may release state->xmit.buf before its assigned
> to null, and cause the race above.
>
> To fix it, let's lock uport->lock when allocating/deallocating
> state->xmit.buf in addition to the per-port mutex.
>
> v2: switch to locking uport->lock on allocation/deallocation instead of
> locking the per-port mutex in uart_put_char. Note that since
> uport->lock is a spin lock, we have to switch the allocation to
> GFP_ATOMIC.
> v3: move the allocation outside the lock, so we can switch back to
> GFP_KERNEL
> v4: * switch to positive condition of state->xmit.buf in
> uart_port_startup()
> * declare `flags` on its own line
> * use the result of uart_port_lock() in uart_shutdown() to avoid
> uninitialized warning
> * don't use the uart_port_lock/unlock macros in uart_port_startup,
> instead test against uport directly; the compiler can't seem to "see"
> through the macros/ref/unref calls to not warn about uninitialized
> flags. We don't need to do a ref here since we hold the per-port
> mutex anyway.
>
> Signed-off-by: Tycho Andersen <tycho@tycho.ws>
One question: would it be worth doing:
> ---
> drivers/tty/serial/serial_core.c | 19 ++++++++++++++-----
> 1 file changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 9c14a453f73c..406e8382d3de 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> {
> struct uart_port *uport = uart_port_check(state);
> unsigned long page;
> + unsigned long flags;
> int retval = 0;
>
> if (uport->type == PORT_UNKNOWN)
> @@ -196,15 +197,20 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> * Initialise and allocate the transmit and temporary
> * buffer.
> */
> - if (!state->xmit.buf) {
> - /* This is protected by the per port mutex */
> - page = get_zeroed_page(GFP_KERNEL);
> - if (!page)
> - return -ENOMEM;
> + page = get_zeroed_page(GFP_KERNEL);
ignoring the alloc failure here. (leave a comment for worried
future reviewers) Then,
> + if (!page)
> + return -ENOMEM;
>
> + if (uport)
> + spin_lock_irqsave(&uport->lock, flags);
> + if (state->xmit.buf) {
> + free_page(page);
> + } else {
here if page is NULL (unlock and) return ENOMEM.
Since it looks like this fn is called on every device open, that
would seem to minimize getting lots of needless ENOMEMs.
Another alternative is to just wait to do the alloc until we
get here, and drop the spinlock here if we need to alloc. Then
retake the lock, re-check state->xmit.buf; If that is now not
null then free_page(page), or if it is still NULL and page alloc
failed, then return ENOEMEM). That is uglier code, but is
probably the best behavior.
Still the original patch fixes the real bug so I'm fine with it
as well.
> state->xmit.buf = (unsigned char *) page;
> uart_circ_clear(&state->xmit);
> }
> + if (uport)
> + spin_unlock_irqrestore(&uport->lock, flags);
>
> retval = uport->ops->startup(uport);
> if (retval == 0) {
> @@ -263,6 +269,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
> {
> struct uart_port *uport = uart_port_check(state);
> struct tty_port *port = &state->port;
> + unsigned long flags;
>
> /*
> * Set the TTY IO error marker
> @@ -295,10 +302,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
> /*
> * Free the transmit buffer page.
> */
> + uport = uart_port_lock(state, flags);
> if (state->xmit.buf) {
> free_page((unsigned long)state->xmit.buf);
> state->xmit.buf = NULL;
> }
> + uart_port_unlock(uport, flags);
> }
>
> /**
> --
> 2.17.1
^ permalink raw reply
* Re: [PATCH v4] uart: fix race between uart_put_char() and uart_shutdown()
From: Tycho Andersen @ 2018-07-11 20:00 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, linux-kernel
In-Reply-To: <20180711194908.GA27217@mail.hallyn.com>
On Wed, Jul 11, 2018 at 02:49:08PM -0500, Serge E. Hallyn wrote:
> Quoting Tycho Andersen (tycho@tycho.ws):
> > We have reports of the following crash:
> >
> > PID: 7 TASK: ffff88085c6d61c0 CPU: 1 COMMAND: "kworker/u25:0"
> > #0 [ffff88085c6db710] machine_kexec at ffffffff81046239
> > #1 [ffff88085c6db760] crash_kexec at ffffffff810fc248
> > #2 [ffff88085c6db830] oops_end at ffffffff81008ae7
> > #3 [ffff88085c6db860] no_context at ffffffff81050b8f
> > #4 [ffff88085c6db8b0] __bad_area_nosemaphore at ffffffff81050d75
> > #5 [ffff88085c6db900] bad_area_nosemaphore at ffffffff81050e83
> > #6 [ffff88085c6db910] __do_page_fault at ffffffff8105132e
> > #7 [ffff88085c6db9b0] do_page_fault at ffffffff8105152c
> > #8 [ffff88085c6db9c0] page_fault at ffffffff81a3f122
> > [exception RIP: uart_put_char+149]
> > RIP: ffffffff814b67b5 RSP: ffff88085c6dba78 RFLAGS: 00010006
> > RAX: 0000000000000292 RBX: ffffffff827c5120 RCX: 0000000000000081
> > RDX: 0000000000000000 RSI: 000000000000005f RDI: ffffffff827c5120
> > RBP: ffff88085c6dba98 R8: 000000000000012c R9: ffffffff822ea320
> > R10: ffff88085fe4db04 R11: 0000000000000001 R12: ffff881059f9c000
> > R13: 0000000000000001 R14: 000000000000005f R15: 0000000000000fba
> > ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
> > #9 [ffff88085c6dbaa0] tty_put_char at ffffffff81497544
> > #10 [ffff88085c6dbac0] do_output_char at ffffffff8149c91c
> > #11 [ffff88085c6dbae0] __process_echoes at ffffffff8149cb8b
> > #12 [ffff88085c6dbb30] commit_echoes at ffffffff8149cdc2
> > #13 [ffff88085c6dbb60] n_tty_receive_buf_fast at ffffffff8149e49b
> > #14 [ffff88085c6dbbc0] __receive_buf at ffffffff8149ef5a
> > #15 [ffff88085c6dbc20] n_tty_receive_buf_common at ffffffff8149f016
> > #16 [ffff88085c6dbca0] n_tty_receive_buf2 at ffffffff8149f194
> > #17 [ffff88085c6dbcb0] flush_to_ldisc at ffffffff814a238a
> > #18 [ffff88085c6dbd50] process_one_work at ffffffff81090be2
> > #19 [ffff88085c6dbe20] worker_thread at ffffffff81091b4d
> > #20 [ffff88085c6dbeb0] kthread at ffffffff81096384
> > #21 [ffff88085c6dbf50] ret_from_fork at ffffffff81a3d69f
> >
> > after slogging through some dissasembly:
> >
> > ffffffff814b6720 <uart_put_char>:
> > ffffffff814b6720: 55 push %rbp
> > ffffffff814b6721: 48 89 e5 mov %rsp,%rbp
> > ffffffff814b6724: 48 83 ec 20 sub $0x20,%rsp
> > ffffffff814b6728: 48 89 1c 24 mov %rbx,(%rsp)
> > ffffffff814b672c: 4c 89 64 24 08 mov %r12,0x8(%rsp)
> > ffffffff814b6731: 4c 89 6c 24 10 mov %r13,0x10(%rsp)
> > ffffffff814b6736: 4c 89 74 24 18 mov %r14,0x18(%rsp)
> > ffffffff814b673b: e8 b0 8e 58 00 callq ffffffff81a3f5f0 <mcount>
> > ffffffff814b6740: 4c 8b a7 88 02 00 00 mov 0x288(%rdi),%r12
> > ffffffff814b6747: 45 31 ed xor %r13d,%r13d
> > ffffffff814b674a: 41 89 f6 mov %esi,%r14d
> > ffffffff814b674d: 49 83 bc 24 70 01 00 cmpq $0x0,0x170(%r12)
> > ffffffff814b6754: 00 00
> > ffffffff814b6756: 49 8b 9c 24 80 01 00 mov 0x180(%r12),%rbx
> > ffffffff814b675d: 00
> > ffffffff814b675e: 74 2f je ffffffff814b678f <uart_put_char+0x6f>
> > ffffffff814b6760: 48 89 df mov %rbx,%rdi
> > ffffffff814b6763: e8 a8 67 58 00 callq ffffffff81a3cf10 <_raw_spin_lock_irqsave>
> > ffffffff814b6768: 41 8b 8c 24 78 01 00 mov 0x178(%r12),%ecx
> > ffffffff814b676f: 00
> > ffffffff814b6770: 89 ca mov %ecx,%edx
> > ffffffff814b6772: f7 d2 not %edx
> > ffffffff814b6774: 41 03 94 24 7c 01 00 add 0x17c(%r12),%edx
> > ffffffff814b677b: 00
> > ffffffff814b677c: 81 e2 ff 0f 00 00 and $0xfff,%edx
> > ffffffff814b6782: 75 23 jne ffffffff814b67a7 <uart_put_char+0x87>
> > ffffffff814b6784: 48 89 c6 mov %rax,%rsi
> > ffffffff814b6787: 48 89 df mov %rbx,%rdi
> > ffffffff814b678a: e8 e1 64 58 00 callq ffffffff81a3cc70 <_raw_spin_unlock_irqrestore>
> > ffffffff814b678f: 44 89 e8 mov %r13d,%eax
> > ffffffff814b6792: 48 8b 1c 24 mov (%rsp),%rbx
> > ffffffff814b6796: 4c 8b 64 24 08 mov 0x8(%rsp),%r12
> > ffffffff814b679b: 4c 8b 6c 24 10 mov 0x10(%rsp),%r13
> > ffffffff814b67a0: 4c 8b 74 24 18 mov 0x18(%rsp),%r14
> > ffffffff814b67a5: c9 leaveq
> > ffffffff814b67a6: c3 retq
> > ffffffff814b67a7: 49 8b 94 24 70 01 00 mov 0x170(%r12),%rdx
> > ffffffff814b67ae: 00
> > ffffffff814b67af: 48 63 c9 movslq %ecx,%rcx
> > ffffffff814b67b2: 41 b5 01 mov $0x1,%r13b
> > ffffffff814b67b5: 44 88 34 0a mov %r14b,(%rdx,%rcx,1)
> > ffffffff814b67b9: 41 8b 94 24 78 01 00 mov 0x178(%r12),%edx
> > ffffffff814b67c0: 00
> > ffffffff814b67c1: 83 c2 01 add $0x1,%edx
> > ffffffff814b67c4: 81 e2 ff 0f 00 00 and $0xfff,%edx
> > ffffffff814b67ca: 41 89 94 24 78 01 00 mov %edx,0x178(%r12)
> > ffffffff814b67d1: 00
> > ffffffff814b67d2: eb b0 jmp ffffffff814b6784 <uart_put_char+0x64>
> > ffffffff814b67d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
> > ffffffff814b67db: 00 00 00 00 00
> >
> > for our build, this is crashing at:
> >
> > circ->buf[circ->head] = c;
> >
> > Looking in uart_port_startup(), it seems that circ->buf (state->xmit.buf)
> > protected by the "per-port mutex", which based on uart_port_check() is
> > state->port.mutex. Indeed, the lock acquired in uart_put_char() is
> > uport->lock, i.e. not the same lock.
> >
> > Anyway, since the lock is not acquired, if uart_shutdown() is called, the
> > last chunk of that function may release state->xmit.buf before its assigned
> > to null, and cause the race above.
> >
> > To fix it, let's lock uport->lock when allocating/deallocating
> > state->xmit.buf in addition to the per-port mutex.
> >
> > v2: switch to locking uport->lock on allocation/deallocation instead of
> > locking the per-port mutex in uart_put_char. Note that since
> > uport->lock is a spin lock, we have to switch the allocation to
> > GFP_ATOMIC.
> > v3: move the allocation outside the lock, so we can switch back to
> > GFP_KERNEL
> > v4: * switch to positive condition of state->xmit.buf in
> > uart_port_startup()
> > * declare `flags` on its own line
> > * use the result of uart_port_lock() in uart_shutdown() to avoid
> > uninitialized warning
> > * don't use the uart_port_lock/unlock macros in uart_port_startup,
> > instead test against uport directly; the compiler can't seem to "see"
> > through the macros/ref/unref calls to not warn about uninitialized
> > flags. We don't need to do a ref here since we hold the per-port
> > mutex anyway.
> >
> > Signed-off-by: Tycho Andersen <tycho@tycho.ws>
>
> One question: would it be worth doing:
>
> > ---
> > drivers/tty/serial/serial_core.c | 19 ++++++++++++++-----
> > 1 file changed, 14 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> > index 9c14a453f73c..406e8382d3de 100644
> > --- a/drivers/tty/serial/serial_core.c
> > +++ b/drivers/tty/serial/serial_core.c
> > @@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> > {
> > struct uart_port *uport = uart_port_check(state);
> > unsigned long page;
> > + unsigned long flags;
> > int retval = 0;
> >
> > if (uport->type == PORT_UNKNOWN)
> > @@ -196,15 +197,20 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
> > * Initialise and allocate the transmit and temporary
> > * buffer.
> > */
> > - if (!state->xmit.buf) {
> > - /* This is protected by the per port mutex */
> > - page = get_zeroed_page(GFP_KERNEL);
> > - if (!page)
> > - return -ENOMEM;
> > + page = get_zeroed_page(GFP_KERNEL);
>
> ignoring the alloc failure here. (leave a comment for worried
> future reviewers) Then,
>
> > + if (!page)
> > + return -ENOMEM;
> >
> > + if (uport)
> > + spin_lock_irqsave(&uport->lock, flags);
> > + if (state->xmit.buf) {
> > + free_page(page);
> > + } else {
>
> here if page is NULL (unlock and) return ENOMEM.
>
> Since it looks like this fn is called on every device open, that
> would seem to minimize getting lots of needless ENOMEMs.
>
> Another alternative is to just wait to do the alloc until we
> get here, and drop the spinlock here if we need to alloc. Then
> retake the lock, re-check state->xmit.buf; If that is now not
> null then free_page(page), or if it is still NULL and page alloc
> failed, then return ENOEMEM). That is uglier code, but is
> probably the best behavior.
>
> Still the original patch fixes the real bug so I'm fine with it
> as well.
Sure, I'm happy to implement whichever of these we think is best.
Greg?
Thanks,
Tycho
^ permalink raw reply
* Re: [PATCH 1/3] tty/serial_core: add ISO7816 infrastructure
From: kbuild test robot @ 2018-07-11 21:52 UTC (permalink / raw)
Cc: kbuild-all, linux-serial, linux-arch, linux-arm-kernel, gregkh,
jslaby, arnd, richard.genoud, nicolas.ferre, alexandre.belloni,
linux-kernel, Ludovic Desroches
In-Reply-To: <20180711131638.12622-2-ludovic.desroches@microchip.com>
[-- Attachment #1: Type: text/plain, Size: 4373 bytes --]
Hi Nicolas,
I love your patch! Yet something to improve:
[auto build test ERROR on tty/tty-testing]
[also build test ERROR on v4.18-rc4 next-20180711]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ludovic-Desroches/add-ISO7816-support/20180712-052207
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: sparc64-allyesconfig (attached as .config)
compiler: sparc64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=sparc64
All errors (new ones prefixed by >>):
drivers/tty/serial/serial_core.c: In function 'uart_ioctl':
drivers/tty/serial/serial_core.c:1430:7: error: 'TIOCSISO7816' undeclared (first use in this function); did you mean 'TIOCSRS485'?
case TIOCSISO7816:
^~~~~~~~~~~~
TIOCSRS485
drivers/tty/serial/serial_core.c:1430:7: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/tty/serial/serial_core.c:1434:7: error: 'TIOCGISO7816' undeclared (first use in this function); did you mean 'TIOCSISO7816'?
case TIOCGISO7816:
^~~~~~~~~~~~
TIOCSISO7816
vim +1434 drivers/tty/serial/serial_core.c
1344
1345 /*
1346 * Called via sys_ioctl. We can use spin_lock_irq() here.
1347 */
1348 static int
1349 uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
1350 {
1351 struct uart_state *state = tty->driver_data;
1352 struct tty_port *port = &state->port;
1353 struct uart_port *uport;
1354 void __user *uarg = (void __user *)arg;
1355 int ret = -ENOIOCTLCMD;
1356
1357
1358 /*
1359 * These ioctls don't rely on the hardware to be present.
1360 */
1361 switch (cmd) {
1362 case TIOCGSERIAL:
1363 ret = uart_get_info_user(port, uarg);
1364 break;
1365
1366 case TIOCSSERIAL:
1367 down_write(&tty->termios_rwsem);
1368 ret = uart_set_info_user(tty, state, uarg);
1369 up_write(&tty->termios_rwsem);
1370 break;
1371
1372 case TIOCSERCONFIG:
1373 down_write(&tty->termios_rwsem);
1374 ret = uart_do_autoconfig(tty, state);
1375 up_write(&tty->termios_rwsem);
1376 break;
1377
1378 case TIOCSERGWILD: /* obsolete */
1379 case TIOCSERSWILD: /* obsolete */
1380 ret = 0;
1381 break;
1382 }
1383
1384 if (ret != -ENOIOCTLCMD)
1385 goto out;
1386
1387 if (tty_io_error(tty)) {
1388 ret = -EIO;
1389 goto out;
1390 }
1391
1392 /*
1393 * The following should only be used when hardware is present.
1394 */
1395 switch (cmd) {
1396 case TIOCMIWAIT:
1397 ret = uart_wait_modem_status(state, arg);
1398 break;
1399 }
1400
1401 if (ret != -ENOIOCTLCMD)
1402 goto out;
1403
1404 mutex_lock(&port->mutex);
1405 uport = uart_port_check(state);
1406
1407 if (!uport || tty_io_error(tty)) {
1408 ret = -EIO;
1409 goto out_up;
1410 }
1411
1412 /*
1413 * All these rely on hardware being present and need to be
1414 * protected against the tty being hung up.
1415 */
1416
1417 switch (cmd) {
1418 case TIOCSERGETLSR: /* Get line status register */
1419 ret = uart_get_lsr_info(tty, state, uarg);
1420 break;
1421
1422 case TIOCGRS485:
1423 ret = uart_get_rs485_config(uport, uarg);
1424 break;
1425
1426 case TIOCSRS485:
1427 ret = uart_set_rs485_config(uport, uarg);
1428 break;
1429
> 1430 case TIOCSISO7816:
1431 ret = uart_set_iso7816_config(state->uart_port, uarg);
1432 break;
1433
> 1434 case TIOCGISO7816:
1435 ret = uart_get_iso7816_config(state->uart_port, uarg);
1436 break;
1437 default:
1438 if (uport->ops->ioctl)
1439 ret = uport->ops->ioctl(uport, cmd, arg);
1440 break;
1441 }
1442 out_up:
1443 mutex_unlock(&port->mutex);
1444 out:
1445 return ret;
1446 }
1447
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 54391 bytes --]
^ permalink raw reply
* Re: [PATCH v4 1/1] arm64: dts: mediatek: add mt6765 support
From: Mars Cheng @ 2018-07-12 0:06 UTC (permalink / raw)
To: Matthias Brugger
Cc: devicetree, CC Hwang, wsd_upstream, Marc Zyngier, Loda Chou,
linux-kernel, Rob Herring, linux-mediatek, linux-serial,
linux-arm-kernel
In-Reply-To: <7a3becb3-510b-5763-5b66-5e14ebf7c974@gmail.com>
Hi Matthias
On Tue, 2018-07-10 at 12:52 +0200, Matthias Brugger wrote:
>
> On 10/07/18 01:04, Mars Cheng wrote:
[...]
> > pmic/pwrap/i2c/rtc/kpd/spi/wdt/cqdma/auxadc/pwm/cmdq/disp. We have
> > dedicated owners to handle them and will cowork tightly with members to
> > make sure things happen in the following weeks.
> >
>
> Ok, so let's wait until pinctrl driver is submitted. I'd prefer if you could add
> the clk driver to this series. This way we can get rid of the dummy clocks in
> the device tree.
>
Got it, I will submit this series with clk support in v5. and pinctrl
after that.
> > For previous chips, we did have no enough support after shell. It is due
> > to fast pace of smartphone SoC and other resource issues. We also know
> > that is no excuse so that we already confirmed owners and their
> > schedules for mt6765.
> >
> > If there is any suggestion, please let us know.
> >
>
> I know that smartphone SoC is a fast paced business. Never the less I'm
> convinced that the basic building blocks won't change much from one version to
> another. And that mainline support for the previous version of your SoC will
> help you to get your new drivers faster upstream.
>
> For me the best example is the mt7622 which got to a reasonable upstream support
> quite fast, thanks to a good foundation of mt7623 in mainline. I'd love to see
> that happen on the smartphone SoCs as well.
>
> Not to mention that upstream support will help you internally when you have to
> rebase your BSP code-base to a new kernel version.
>
> That said I think it is good news that you have already defined owner for the
> different devices and hope to see submissions for them in the near future :)
> As a suggestion I would say that upstream submission takes time and effort and
> it will help your engineers if they can allocate some time to do so. But that's
> most probably a management decision and all engineers know that management bases
> it's decision on some hard-to-understandable abbreviations like EBITDA etc. ;)
>
> Best regards,
> Matthias
Thanks for your suggestions. We will try to catch up on this mission :-)
^ permalink raw reply
* Re: [PATCH 1/3] tty/serial_core: add ISO7816 infrastructure
From: kbuild test robot @ 2018-07-12 0:10 UTC (permalink / raw)
Cc: kbuild-all, linux-serial, linux-arch, linux-arm-kernel, gregkh,
jslaby, arnd, richard.genoud, nicolas.ferre, alexandre.belloni,
linux-kernel, Ludovic Desroches
In-Reply-To: <20180711131638.12622-2-ludovic.desroches@microchip.com>
[-- Attachment #1: Type: text/plain, Size: 4350 bytes --]
Hi Nicolas,
I love your patch! Yet something to improve:
[auto build test ERROR on tty/tty-testing]
[also build test ERROR on v4.18-rc4 next-20180711]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ludovic-Desroches/add-ISO7816-support/20180712-052207
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 8.1.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=xtensa
All errors (new ones prefixed by >>):
drivers/tty/serial/serial_core.c: In function 'uart_ioctl':
drivers/tty/serial/serial_core.c:1430:7: error: 'TIOCSISO7816' undeclared (first use in this function); did you mean 'TIOCSRS485'?
case TIOCSISO7816:
^~~~~~~~~~~~
TIOCSRS485
drivers/tty/serial/serial_core.c:1430:7: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/tty/serial/serial_core.c:1434:7: error: 'TIOCGISO7816' undeclared (first use in this function); did you mean 'TIOCGRS485'?
case TIOCGISO7816:
^~~~~~~~~~~~
TIOCGRS485
vim +1434 drivers/tty/serial/serial_core.c
1344
1345 /*
1346 * Called via sys_ioctl. We can use spin_lock_irq() here.
1347 */
1348 static int
1349 uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
1350 {
1351 struct uart_state *state = tty->driver_data;
1352 struct tty_port *port = &state->port;
1353 struct uart_port *uport;
1354 void __user *uarg = (void __user *)arg;
1355 int ret = -ENOIOCTLCMD;
1356
1357
1358 /*
1359 * These ioctls don't rely on the hardware to be present.
1360 */
1361 switch (cmd) {
1362 case TIOCGSERIAL:
1363 ret = uart_get_info_user(port, uarg);
1364 break;
1365
1366 case TIOCSSERIAL:
1367 down_write(&tty->termios_rwsem);
1368 ret = uart_set_info_user(tty, state, uarg);
1369 up_write(&tty->termios_rwsem);
1370 break;
1371
1372 case TIOCSERCONFIG:
1373 down_write(&tty->termios_rwsem);
1374 ret = uart_do_autoconfig(tty, state);
1375 up_write(&tty->termios_rwsem);
1376 break;
1377
1378 case TIOCSERGWILD: /* obsolete */
1379 case TIOCSERSWILD: /* obsolete */
1380 ret = 0;
1381 break;
1382 }
1383
1384 if (ret != -ENOIOCTLCMD)
1385 goto out;
1386
1387 if (tty_io_error(tty)) {
1388 ret = -EIO;
1389 goto out;
1390 }
1391
1392 /*
1393 * The following should only be used when hardware is present.
1394 */
1395 switch (cmd) {
1396 case TIOCMIWAIT:
1397 ret = uart_wait_modem_status(state, arg);
1398 break;
1399 }
1400
1401 if (ret != -ENOIOCTLCMD)
1402 goto out;
1403
1404 mutex_lock(&port->mutex);
1405 uport = uart_port_check(state);
1406
1407 if (!uport || tty_io_error(tty)) {
1408 ret = -EIO;
1409 goto out_up;
1410 }
1411
1412 /*
1413 * All these rely on hardware being present and need to be
1414 * protected against the tty being hung up.
1415 */
1416
1417 switch (cmd) {
1418 case TIOCSERGETLSR: /* Get line status register */
1419 ret = uart_get_lsr_info(tty, state, uarg);
1420 break;
1421
1422 case TIOCGRS485:
1423 ret = uart_get_rs485_config(uport, uarg);
1424 break;
1425
1426 case TIOCSRS485:
1427 ret = uart_set_rs485_config(uport, uarg);
1428 break;
1429
> 1430 case TIOCSISO7816:
1431 ret = uart_set_iso7816_config(state->uart_port, uarg);
1432 break;
1433
> 1434 case TIOCGISO7816:
1435 ret = uart_get_iso7816_config(state->uart_port, uarg);
1436 break;
1437 default:
1438 if (uport->ops->ioctl)
1439 ret = uport->ops->ioctl(uport, cmd, arg);
1440 break;
1441 }
1442 out_up:
1443 mutex_unlock(&port->mutex);
1444 out:
1445 return ret;
1446 }
1447
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 54028 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox