* Re: [PATCH v1 2/7] serdev: add dev_pm_domain_attach|detach()
From: Sean Wang @ 2018-04-26 5:29 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Rob Herring, Mark Rutland, Johan Hedberg, devicetree,
Bluez mailing list, linux-arm-kernel, linux-mediatek, LKML,
Rob Herring, Ulf Hansson, Greg Kroah-Hartman, Jiri Slaby,
linux-serial
In-Reply-To: <FD85DED4-589C-4113-8A8B-BC5A39494130@holtmann.org>
On Tue, 2018-04-03 at 12:29 +0200, Marcel Holtmann wrote:
> Hi Sean,
>
> > In order to open up the required power gate before any operation can be
> > effectively performed over the serial bus between CPU and serdev, it's
> > clearly essential to add common attach functions for PM domains to serdev
> > at the probe phase.
> >
> > Similarly, the relevant dettach function for the PM domains should be
> > properly and reversely added at the remove phase.
> >
> > Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> > Cc: Rob Herring <robh@kernel.org>
> > Cc: Ulf Hansson <ulf.hansson@linaro.org>
> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Cc: Jiri Slaby <jslaby@suse.com>
> > Cc: linux-serial@vger.kernel.org
> > ---
> > drivers/tty/serdev/core.c | 14 +++++++++++++-
> > 1 file changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> > index df93b72..c93d8ee 100644
> > --- a/drivers/tty/serdev/core.c
> > +++ b/drivers/tty/serdev/core.c
> > @@ -13,6 +13,7 @@
> > #include <linux/module.h>
> > #include <linux/of.h>
> > #include <linux/of_device.h>
> > +#include <linux/pm_domain.h>
> > #include <linux/serdev.h>
> > #include <linux/slab.h>
> >
> > @@ -330,8 +331,16 @@ EXPORT_SYMBOL_GPL(serdev_device_set_tiocm);
> > static int serdev_drv_probe(struct device *dev)
> > {
> > const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
> > + int ret;
> > +
> > + ret = dev_pm_domain_attach(dev, true);
> > + if (ret != -EPROBE_DEFER) {
> > + ret = sdrv->probe(to_serdev_device(dev));
> > + if (ret)
> > + dev_pm_domain_detach(dev, true);
> > + }
>
> so if this is deferred, when does the serdev device gets probed?
>
driver probe deferral mechanism is supported in driver core
deferred_probe_initcall makes sure that deferred probing is
delayed until late_initcall time.
Below is a few of word I got from drivers/base/core.c I thought it helps
to understand the mechanism in complete picture
* If a required resource is not available yet, a driver can
request probing to be deferred by returning -EPROBE_DEFER from
its probe hook.
* A driver returning -EPROBE_DEFER causes the device to be added to the
pending list. A successful driver probe will trigger moving all devices
from the pending to the active list so that the workqueue will
eventually retry them.
> >
> > - return sdrv->probe(to_serdev_device(dev));
> > + return ret;
> > }
> >
> > static int serdev_drv_remove(struct device *dev)
> > @@ -339,6 +348,9 @@ static int serdev_drv_remove(struct device *dev)
> > const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
> > if (sdrv->remove)
> > sdrv->remove(to_serdev_device(dev));
> > +
> > + dev_pm_domain_detach(dev, true);
> > +
> > return 0;
> > }
>
> Regards
>
> Marcel
>
^ permalink raw reply
* [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-26 10:54 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Peter Maydell, Linus Walleij, Wei Xu, Russell King, linux-serial
This is an update to a previous RFC v3 [1], to fix a problem observed by
the qemu community that causes serial input to hang when booting a
simulated system with data already queued in the UART FIFO [2].
RFC v3 did not solve the problem by itself, due to the problem being
triggered again in pl011_enable_interrupts() after working around it
in pl011_hwinit(). See the updated commit message in the patch for
details.
This patch is intended to supersede the previous RFCs, so please test
_without_ RFC v2 (or 3) applied.
If you can, please:
a) Check that you can still reproduce the bug on mainline without this
patch.
b) Check whether this patch fixes the problem.
Cheers
---Dave
[1] [RFC PATCH v3] tty: pl011: Avoid spuriously stuck-off interrupts
http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/573120.html
[2] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
before enabled the interruption
https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
Dave Martin (1):
tty: pl011: Avoid spuriously stuck-off interrupts
drivers/tty/serial/amba-pl011.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--
2.1.4
^ permalink raw reply
* [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-26 10:54 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Peter Maydell, Linus Walleij, Wei Xu, Russell King, linux-serial
In-Reply-To: <1524740081-4979-1-git-send-email-Dave.Martin@arm.com>
Commit 9b96fbacda34 ("serial: PL011: clear pending interrupts")
clears the RX and receive timeout interrupts on pl011 startup, to
avoid a screaming-interrupt scenario that can occur when the
firmware or bootloader leaves these interrupts asserted.
This has been noted as an issue when running Linux on qemu [1].
Unfortunately, the above fix seems to lead to potential
misbehaviour if the RX FIFO interrupt is asserted _non_ spuriously
on driver startup, if the RX FIFO is also already full to the
trigger level.
Clearing the RX FIFO interrupt does not change the FIFO fill level.
In this scenario, because the interrupt is now clear and because
the FIFO is already full to the trigger level, no new assertion of
the RX FIFO interrupt can occur unless the FIFO is drained back
below the trigger level. This never occurs because the pl011
driver is waiting for an RX FIFO interrupt to tell it that there is
something to read, and does not read the FIFO at all until that
interrupt occurs.
Thus, simply clearing "spurious" interrupts on startup may be
misguided, since there is no way to be sure that the interrupts are
truly spurious, and things can go wrong if they are not.
This patch instead clears the interrupt condition by draining the
RX FIFO during UART startup, after clearing any potentially
spurious interrupt. This should ensure that an interrupt will
definitely be asserted if the RX FIFO subsequently becomes
sufficiently full.
The drain is done at the point of enabling interrupts only. This
means that it will occur any time the UART is newly opened through
the tty layer. It will not apply to polled-mode use of the UART by
kgdboc: since that scenario cannot use interrupts by design, this
should not matter. kgdboc will interact badly with "normal" use of
the UART in any case: this patch makes no attempt to paper over
such issues.
This patch does not attempt to address the case where the RX FIFO
fills faster than it can be drained: that is a pathological
hardware design problem that is beyond the scope of the driver to
work around.
[1] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
before enabled the interruption
https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
Reported-by: Wei Xu <xuwei5@hisilicon.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Peter Maydell <peter.maydell@linaro.org>
Fixes: 9b96fbacda34 ("serial: PL011: clear pending interrupts")
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
Changes since RFC v3:
* Move the RX FIFO drain to pl011_enable_interrupts(). The
rationale for this is explained in the updated commit message
above.
---
drivers/tty/serial/amba-pl011.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 4b40a5b..a6ccb85 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1731,6 +1731,16 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
/* Clear out any spuriously appearing RX interrupts */
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
+
+ /*
+ * RXIS is asserted only when the RX FIFO transitions from below
+ * to above the trigger threshold. If the RX FIFO is already
+ * full to the threshold this can't happen and RXIS will now be
+ * stuck off. Drain the RX FIFO explicitly to fix this:
+ */
+ while (!(pl011_read(uap, REG_FR) & UART01x_FR_RXFE))
+ pl011_read(uap, REG_DR);
+
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM;
--
2.1.4
^ permalink raw reply related
* Re: [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Peter Maydell @ 2018-04-26 12:11 UTC (permalink / raw)
To: Dave Martin
Cc: Andrew Jones, Ciro Santilli, Linus Walleij, Russell King, Wei Xu,
linux-serial, arm-mail-list
In-Reply-To: <1524740081-4979-1-git-send-email-Dave.Martin@arm.com>
On 26 April 2018 at 11:54, Dave Martin <Dave.Martin@arm.com> wrote:
> This is an update to a previous RFC v3 [1], to fix a problem observed by
> the qemu community that causes serial input to hang when booting a
> simulated system with data already queued in the UART FIFO [2].
>
> RFC v3 did not solve the problem by itself, due to the problem being
> triggered again in pl011_enable_interrupts() after working around it
> in pl011_hwinit(). See the updated commit message in the patch for
> details.
>
> This patch is intended to supersede the previous RFCs, so please test
> _without_ RFC v2 (or 3) applied.
>
> If you can, please:
>
> a) Check that you can still reproduce the bug on mainline without this
> patch.
>
> b) Check whether this patch fixes the problem.
Adding back to the CC list the people who might be able to do
this testing...
Link to v4 patch:
https://patchwork.kernel.org/patch/10365551/
thanks
-- PMM
^ permalink raw reply
* Re: [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-26 13:01 UTC (permalink / raw)
To: Peter Maydell
Cc: Andrew Jones, Ciro Santilli, Linus Walleij, Russell King, Wei Xu,
linux-serial, arm-mail-list
In-Reply-To: <CAFEAcA9aVWC2M4cExTgPdwGqAOofWgm-61FUuZHNFWvFeNiHJA@mail.gmail.com>
On Thu, Apr 26, 2018 at 01:11:41PM +0100, Peter Maydell wrote:
> On 26 April 2018 at 11:54, Dave Martin <Dave.Martin@arm.com> wrote:
> > This is an update to a previous RFC v3 [1], to fix a problem observed by
> > the qemu community that causes serial input to hang when booting a
> > simulated system with data already queued in the UART FIFO [2].
> >
> > RFC v3 did not solve the problem by itself, due to the problem being
> > triggered again in pl011_enable_interrupts() after working around it
> > in pl011_hwinit(). See the updated commit message in the patch for
> > details.
> >
> > This patch is intended to supersede the previous RFCs, so please test
> > _without_ RFC v2 (or 3) applied.
> >
> > If you can, please:
> >
> > a) Check that you can still reproduce the bug on mainline without this
> > patch.
> >
> > b) Check whether this patch fixes the problem.
>
> Adding back to the CC list the people who might be able to do
> this testing...
> Link to v4 patch:
> https://patchwork.kernel.org/patch/10365551/
Dang. Thanks!
(Sorry guys)
---Dave
^ permalink raw reply
* Re: [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Andrew Jones @ 2018-04-26 13:42 UTC (permalink / raw)
To: Peter Maydell
Cc: Ciro Santilli, Linus Walleij, Russell King, Wei Xu, linux-serial,
Dave Martin, arm-mail-list
In-Reply-To: <CAFEAcA9aVWC2M4cExTgPdwGqAOofWgm-61FUuZHNFWvFeNiHJA@mail.gmail.com>
On Thu, Apr 26, 2018 at 01:11:41PM +0100, Peter Maydell wrote:
> On 26 April 2018 at 11:54, Dave Martin <Dave.Martin@arm.com> wrote:
> > This is an update to a previous RFC v3 [1], to fix a problem observed by
> > the qemu community that causes serial input to hang when booting a
> > simulated system with data already queued in the UART FIFO [2].
> >
> > RFC v3 did not solve the problem by itself, due to the problem being
> > triggered again in pl011_enable_interrupts() after working around it
> > in pl011_hwinit(). See the updated commit message in the patch for
> > details.
> >
> > This patch is intended to supersede the previous RFCs, so please test
> > _without_ RFC v2 (or 3) applied.
> >
> > If you can, please:
> >
> > a) Check that you can still reproduce the bug on mainline without this
> > patch.
> >
> > b) Check whether this patch fixes the problem.
>
> Adding back to the CC list the people who might be able to do
> this testing...
> Link to v4 patch:
> https://patchwork.kernel.org/patch/10365551/
>
Tested-by: Andrew Jones <drjones@redhat.com>
And
Reviewed-by: Andrew Jones <drjones@redhat.com>
as this patch is consistent with what I expected was needed back
when I reported the issue[*]. I was just too dense to realize
that we didn't need to "reset" the FIFO, but rather just drain it.
Thanks,
drew
[*] https://lkml.org/lkml/2016/8/1/247
^ permalink raw reply
* [RFC PATCH 0/3] serial: uartps: Add run time support for more IPs than hardcoded 2
From: Michal Simek @ 2018-04-26 14:08 UTC (permalink / raw)
To: linux-kernel, monstr, gnomes, Alexander Graf
Cc: devicetree, Jiri Slaby, Greg Kroah-Hartman, Rob Herring,
linux-serial, Frank Rowand, linux-arm-kernel
Hi,
this series is trying to address discussion I had with Alan in past
https://patchwork.kernel.org/patch/9738445/.
It is moving uart_register_driver() to probe function like it is done in
pl011 driver.
And also introducing new function for alias compatibility checking to
resolve cases where some IPs have alias and some of them not.
This case is detected in pl011_probe_dt_alias() but not properly solved.
Also keep status of free ids/minor numbers in bitmap to know what's the
next unallocated number.
The same solution can be used in pl011, uart16550 and uartlite to really
get unified kernel.
Tested on these use cases:
Notes:
ff000000 is the first PS uart listed in dtsi
ff010000 is the second PS uart listed in dtsi
Standard zcu102 setting
serial0 = &uart0;
serial1 = &uart1;
[ 0.196628] ff000000.serial: ttyPS0 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.642542] ff010000.serial: ttyPS1 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
Swapped zcu102 setting
serial0 = &uart1;
serial1 = &uart0;
[ 0.196472] ff000000.serial: ttyPS1 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.196824] ff010000.serial: ttyPS0 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
uart0 on alias higher then MAX uart ports
serial0 = &uart1;
serial200 = &uart0;
[ 0.176793] ff000000.serial: ttyPS200 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.177288] ff010000.serial: ttyPS0 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
Both uarts on higher aliases
serial1 = &uart1;
serial2 = &uart0;
[ 0.196470] ff000000.serial: ttyPS2 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.196823] ff010000.serial: ttyPS1 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
uart0 not listed but it is probed first that's why should be ttyPS0 but
there is uart1 via alias
serial0 = &uart1;
[ 0.176656] xuartps ff000000.serial: No serial alias passed. Using
the first free id
[ 0.176671] xuartps ff000000.serial: Validate id 0
[ 0.176680] xuartps ff000000.serial: The empty id is 0
[ 0.176692] xuartps ff000000.serial: ID 0 already taken - skipped
[ 0.176701] xuartps ff000000.serial: Validate id 1
[ 0.176710] xuartps ff000000.serial: The empty id is 1
[ 0.176719] xuartps ff000000.serial: Selected ID 1 allocation passed
[ 0.176760] ff000000.serial: ttyPS1 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.177104] ff010000.serial: ttyPS0 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
uart0 not listed but it is probed first that's why should be ttyPS0
serial1 = &uart1;
[ 0.176661] xuartps ff000000.serial: No serial alias passed. Using
the first free id
[ 0.176676] xuartps ff000000.serial: Validate id 0
[ 0.176686] xuartps ff000000.serial: The empty id is 0
[ 0.176696] xuartps ff000000.serial: Selected ID 0 allocation passed
[ 0.176737] ff000000.serial: ttyPS0 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.177069] ff010000.serial: ttyPS1 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
uarts not listed in aliases list
[ 0.176673] xuartps ff000000.serial: No serial alias passed. Using
the first free id
[ 0.176687] xuartps ff000000.serial: Validate id 0
[ 0.176697] xuartps ff000000.serial: The empty id is 0
[ 0.176707] xuartps ff000000.serial: Selected ID 0 allocation passed
[ 0.176746] ff000000.serial: ttyPS0 at MMIO 0xff000000 (irq = 33,
base_baud = 6250000) is a xuartps
[ 0.177057] xuartps ff010000.serial: No serial alias passed. Using
the first free id
[ 0.177070] xuartps ff010000.serial: Validate id 0
[ 0.177079] xuartps ff010000.serial: The empty id is 0
[ 0.177089] xuartps ff010000.serial: Selected ID 0 allocation failed
[ 0.177098] xuartps ff010000.serial: Validate id 1
[ 0.177107] xuartps ff010000.serial: The empty id is 1
[ 0.177116] xuartps ff010000.serial: Selected ID 1 allocation passed
[ 0.177149] ff010000.serial: ttyPS1 at MMIO 0xff010000 (irq = 34,
base_baud = 6250000) is a xuartps
Thanks,
Michal
Michal Simek (3):
of: base: Introduce of_alias_check_id() to check alias IDs
serial: uartps: Move register to probe based on run time detection
serial: uartps: Change uart ports allocation
drivers/of/base.c | 49 +++++++++++
drivers/tty/serial/xilinx_uartps.c | 128 +++++++++++++++++++++++------
include/linux/of.h | 2 +
3 files changed, 153 insertions(+), 26 deletions(-)
--
2.17.0
^ permalink raw reply
* [RFC PATCH 2/3] serial: uartps: Move register to probe based on run time detection
From: Michal Simek @ 2018-04-26 14:08 UTC (permalink / raw)
To: linux-kernel, monstr, gnomes, Alexander Graf
Cc: Jiri Slaby, linux-serial, Greg Kroah-Hartman, linux-arm-kernel
In-Reply-To: <cover.1524751696.git.michal.simek@xilinx.com>
Find out the highest serial alias and allocate that amount of
structures/minor numbers to be able to handle all of them.
Origin setting that there are two prealocated CDNS_UART_NR_PORTS is kept
there.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
Discussed here: https://patchwork.kernel.org/patch/9738445/
The same solution is done in pl011 driver.
---
drivers/tty/serial/xilinx_uartps.c | 32 ++++++++++++++++--------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 0fc9de20843c..ffb5b66a05b5 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1432,6 +1432,22 @@ static int cdns_uart_probe(struct platform_device *pdev)
struct cdns_uart *cdns_uart_data;
const struct of_device_id *match;
+ if (!cdns_uart_uart_driver.state) {
+ rc = of_alias_get_highest_id("serial");
+ if (rc >= CDNS_UART_NR_PORTS) {
+ /* serial2 means 3 ports that's why rc(2) + 1 here */
+ rc += 1;
+ /* Rewrite default setup which is using 2 ports */
+ cdns_uart_uart_driver.nr = rc;
+ }
+
+ rc = uart_register_driver(&cdns_uart_uart_driver);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to register driver\n");
+ return rc;
+ }
+ }
+
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL);
if (!cdns_uart_data)
@@ -1622,28 +1638,14 @@ static struct platform_driver cdns_uart_platform_driver = {
static int __init cdns_uart_init(void)
{
- int retval = 0;
-
- /* Register the cdns_uart driver with the serial core */
- retval = uart_register_driver(&cdns_uart_uart_driver);
- if (retval)
- return retval;
-
/* Register the platform driver */
- retval = platform_driver_register(&cdns_uart_platform_driver);
- if (retval)
- uart_unregister_driver(&cdns_uart_uart_driver);
-
- return retval;
+ return platform_driver_register(&cdns_uart_platform_driver);
}
static void __exit cdns_uart_exit(void)
{
/* Unregister the platform driver */
platform_driver_unregister(&cdns_uart_platform_driver);
-
- /* Unregister the cdns_uart driver */
- uart_unregister_driver(&cdns_uart_uart_driver);
}
arch_initcall(cdns_uart_init);
--
2.17.0
^ permalink raw reply related
* [RFC PATCH 3/3] serial: uartps: Change uart ports allocation
From: Michal Simek @ 2018-04-26 14:08 UTC (permalink / raw)
To: linux-kernel, monstr, gnomes, Alexander Graf
Cc: Jiri Slaby, linux-serial, Greg Kroah-Hartman, linux-arm-kernel
In-Reply-To: <cover.1524751696.git.michal.simek@xilinx.com>
For ips which have alias algorightm all the tim using that alias and
minor number. It means serial20 alias ends up as ttyPS20.
If aliases are not setup for enabled core the first unused position is
used but that's need to be checked if it is really empty because another
instance doesn't need to be probed. of_alias_check_id() does that test.
If alias pointing to different not compatible IP, it is free to use.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
drivers/tty/serial/xilinx_uartps.c | 96 ++++++++++++++++++++++++++----
1 file changed, 85 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index ffb5b66a05b5..7c616b48c117 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -45,6 +45,9 @@ static int rx_timeout = 10;
module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
+/* The inuse bitfield is recording which IDs are free/used by the driver. */
+static unsigned long *inuse;
+
/* Register offsets for the UART. */
#define CDNS_UART_CR 0x00 /* Control Register */
#define CDNS_UART_MR 0x04 /* Mode Register */
@@ -1418,6 +1421,75 @@ static const struct of_device_id cdns_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
+static int cdns_get_id(struct platform_device *pdev)
+{
+ int id;
+
+ /* Look for a serialN alias */
+ id = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (id < 0) {
+ dev_warn(&pdev->dev,
+ "No serial alias passed. Using the first free id\n");
+
+ /*
+ * Start with id 0 and check if there is no serial0 alias
+ * which points to device which is compatible with this driver.
+ * If alias exists then try next free position.
+ */
+ id = 0;
+
+ for (;;) {
+ dev_dbg(&pdev->dev, "Validate id %d\n", id);
+ id = find_next_zero_bit(inuse, id,
+ cdns_uart_uart_driver.nr);
+
+ dev_dbg(&pdev->dev, "The empty id is %d\n", id);
+ /* Check if ID is empty */
+
+ if (of_alias_check_id(cdns_uart_of_match,
+ "serial", id)) {
+ dev_dbg(&pdev->dev,
+ "ID %d already taken - skipped\n", id);
+ /* Try next one */
+ id++;
+ continue;
+ }
+
+ /* It shouldn't happen anytime */
+ if (id >= cdns_uart_uart_driver.nr) {
+ dev_dbg(&pdev->dev,
+ "ID %d is greater than NR of ports\n",
+ cdns_uart_uart_driver.nr);
+ return -ENXIO;
+ }
+
+ /* Break the loop if bit is taken */
+ if (!test_and_set_bit(id, inuse)) {
+ dev_dbg(&pdev->dev,
+ "Selected ID %d allocation passed\n",
+ id);
+ break;
+ }
+ dev_dbg(&pdev->dev,
+ "Selected ID %d allocation failed\n", id);
+ /* if taking bit fails then try next one */
+ id++;
+ }
+ } else {
+ /*
+ * If alias was found there is no reason to check
+ * anything else
+ */
+ if (test_and_set_bit(id, inuse)) {
+ dev_dbg(&pdev->dev,
+ "ID %d allocation failed\n", id);
+ return -EAGAIN;
+ }
+ }
+
+ return id;
+}
+
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@@ -1446,6 +1518,13 @@ static int cdns_uart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to register driver\n");
return rc;
}
+
+ /* Create bitfield to record which ids are free */
+ inuse = devm_kcalloc(&pdev->dev,
+ BITS_TO_LONGS(cdns_uart_uart_driver.nr),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!inuse)
+ return -ENOMEM;
}
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
@@ -1463,6 +1542,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
cdns_uart_data->quirks = data->quirks;
}
+ id = cdns_get_id(pdev);
+ if (id < 0)
+ return id;
+
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(cdns_uart_data->pclk)) {
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
@@ -1515,16 +1598,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
&cdns_uart_data->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
#endif
- /* Look for a serialN alias */
- id = of_alias_get_id(pdev->dev.of_node, "serial");
- if (id < 0)
- id = 0;
-
- if (id >= CDNS_UART_NR_PORTS) {
- dev_err(&pdev->dev, "Cannot get uart_port structure\n");
- rc = -ENODEV;
- goto err_out_notif_unreg;
- }
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
@@ -1583,10 +1656,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
return 0;
err_out_pm_disable:
+ clear_bit(port->line, inuse);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
-err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
@@ -1618,6 +1691,7 @@ static int cdns_uart_remove(struct platform_device *pdev)
#endif
rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
port->mapbase = 0;
+ clear_bit(port->line, inuse);
clk_disable_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk);
pm_runtime_disable(&pdev->dev);
--
2.17.0
^ permalink raw reply related
* [PATCH] tty/serial: atmel: use port->name as name in request_irq()
From: Sebastian Andrzej Siewior @ 2018-04-26 15:06 UTC (permalink / raw)
To: linux-serial
Cc: Alexandre Belloni, Peter Hurley, Richard Genoud,
Greg Kroah-Hartman, Jiri Slaby, tglx, linux-arm-kernel
I was puzzled while looking at /proc/interrupts and random things showed
up between reboots. This occurred more often but I realised it later. The
"correct" output should be:
|38: 11861 atmel-aic5 2 Level ttyS0
but I saw sometimes
|38: 6426 atmel-aic5 2 Level tty1
and I accounted it wrongly as correct. This is use after free and the
former example randomly got the "old" pointer which pointed to the same
content. With SLAB_FREELIST_RANDOM and HARDENED I even got
|38: 7067 atmel-aic5 2 Level E=Started User Manager for UID 0
or other nonsense.
As it turns out the tty, pointer that is accessed in atmel_startup(), is
freed() before atmel_shutdown(). It seems to happen quite often that the
tty for ttyS0 is allocated and freed while ->shutdown is not invoked. I
don't do anything special - just a systemd boot :)
It seems not to happen in v4.1.51 but it happens in v4.9 and v4.17-rc2
so if it broke accidentally it was not recently.
Use port->name as the IRQ name for request_irq(). This exists as long as
the driver is loaded so no use-after-free here.
Cc: stable@vger.kernel.org
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/tty/serial/atmel_serial.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index e287fe8f10fc..d3189816740e 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1757,7 +1757,6 @@ static int atmel_startup(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- struct tty_struct *tty = port->state->port.tty;
int retval;
/*
@@ -1772,8 +1771,7 @@ static int atmel_startup(struct uart_port *port)
* Allocate the IRQ
*/
retval = request_irq(port->irq, atmel_interrupt,
- IRQF_SHARED | IRQF_COND_SUSPEND,
- tty ? tty->name : "atmel_serial", port);
+ IRQF_SHARED | IRQF_COND_SUSPEND, port->name, port);
if (retval) {
dev_err(port->dev, "atmel_startup - Can't get irq\n");
return retval;
--
2.17.0
^ permalink raw reply related
* Re: [PATCH] tty/serial: atmel: use port->name as name in request_irq()
From: Sebastian Andrzej Siewior @ 2018-04-26 15:12 UTC (permalink / raw)
To: linux-serial
Cc: Alexandre Belloni, Peter Hurley, Richard Genoud,
Greg Kroah-Hartman, Jiri Slaby, tglx, linux-arm-kernel
In-Reply-To: <20180426150625.q5tqcb7fzchvkb5d@linutronix.de>
On 2018-04-26 17:06:25 [+0200], To linux-serial@vger.kernel.org wrote:
> It seems not to happen in v4.1.51 but it happens in v4.9 and v4.17-rc2
> so if it broke accidentally it was not recently.
This is what I used to check:
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -170,7 +170,7 @@ void free_tty_struct(struct tty_struct *tty)
put_device(tty->dev);
kfree(tty->write_buf);
tty->magic = 0xDEADDEAD;
- kfree(tty);
+ strcpy(tty->name, "GONE");
}
static inline struct tty_struct *file_tty(struct file *file)
If this is unknown and a bisect is requested, please let me know.
Sebastian
^ permalink raw reply
* Re: [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-26 15:25 UTC (permalink / raw)
To: Andrew Jones
Cc: Peter Maydell, Ciro Santilli, Linus Walleij, Russell King, Wei Xu,
linux-serial, arm-mail-list
In-Reply-To: <20180426134201.mwnkib4ch4dcqnqi@kamzik.brq.redhat.com>
On Thu, Apr 26, 2018 at 03:42:01PM +0200, Andrew Jones wrote:
> On Thu, Apr 26, 2018 at 01:11:41PM +0100, Peter Maydell wrote:
> > On 26 April 2018 at 11:54, Dave Martin <Dave.Martin@arm.com> wrote:
> > > This is an update to a previous RFC v3 [1], to fix a problem observed by
> > > the qemu community that causes serial input to hang when booting a
> > > simulated system with data already queued in the UART FIFO [2].
> > >
> > > RFC v3 did not solve the problem by itself, due to the problem being
> > > triggered again in pl011_enable_interrupts() after working around it
> > > in pl011_hwinit(). See the updated commit message in the patch for
> > > details.
> > >
> > > This patch is intended to supersede the previous RFCs, so please test
> > > _without_ RFC v2 (or 3) applied.
> > >
> > > If you can, please:
> > >
> > > a) Check that you can still reproduce the bug on mainline without this
> > > patch.
> > >
> > > b) Check whether this patch fixes the problem.
> >
> > Adding back to the CC list the people who might be able to do
> > this testing...
> > Link to v4 patch:
> > https://patchwork.kernel.org/patch/10365551/
> >
>
> Tested-by: Andrew Jones <drjones@redhat.com>
>
> And
>
> Reviewed-by: Andrew Jones <drjones@redhat.com>
>
> as this patch is consistent with what I expected was needed back
> when I reported the issue[*]. I was just too dense to realize
> that we didn't need to "reset" the FIFO, but rather just drain it.
Thanks for the testing and review!
There seem to be a few ways to solve this, and it's hard to know which
ne is best. This at least looks simple now.
Possibly there is a way to reset the FIFO on a real PL011, but I ignored
the possibility since there is definitely no way to do that on e.g.,
SBSA UART. Draining the FIFO by hand ought to work on all variants IIUC.
Cheers
---Dave
>
> Thanks,
> drew
>
> [*] https://lkml.org/lkml/2016/8/1/247
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-27 10:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Peter Maydell, Andrew Jones, Ciro Santilli, Linus Walleij,
Russell King, Wei Xu, linux-serial
This is an update to a previous RFC [1], to fix a problem observed by
the qemu community that causes serial input to hang when booting a
simulated system with data already queued in the UART FIFO [2].
This patch could cause problems for people that are actually relying
on chars queued in the PL011 RX FIFO during boot or while the UART is
closed. There are no guarantees about such things working in general.
In either case, there is no protection against RX FIFO overflow or
reprogramming of the UART parameters while Linux is not actively
receiving chars.
Cheers
---Dave
[1] [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/574033.html
[2] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
before enabled the interruption
https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
Dave Martin (1):
tty: pl011: Avoid spuriously stuck-off interrupts
drivers/tty/serial/amba-pl011.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--
2.1.4
^ permalink raw reply
* [PATCH] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-27 10:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Peter Maydell, Andrew Jones, Ciro Santilli, Linus Walleij,
Russell King, Wei Xu, linux-serial
In-Reply-To: <1524823545-11309-1-git-send-email-Dave.Martin@arm.com>
Commit 9b96fbacda34 ("serial: PL011: clear pending interrupts")
clears the RX and receive timeout interrupts on pl011 startup, to
avoid a screaming-interrupt scenario that can occur when the
firmware or bootloader leaves these interrupts asserted.
This has been noted as an issue when running Linux on qemu [1].
Unfortunately, the above fix seems to lead to potential
misbehaviour if the RX FIFO interrupt is asserted _non_ spuriously
on driver startup, if the RX FIFO is also already full to the
trigger level.
Clearing the RX FIFO interrupt does not change the FIFO fill level.
In this scenario, because the interrupt is now clear and because
the FIFO is already full to the trigger level, no new assertion of
the RX FIFO interrupt can occur unless the FIFO is drained back
below the trigger level. This never occurs because the pl011
driver is waiting for an RX FIFO interrupt to tell it that there is
something to read, and does not read the FIFO at all until that
interrupt occurs.
Thus, simply clearing "spurious" interrupts on startup may be
misguided, since there is no way to be sure that the interrupts are
truly spurious, and things can go wrong if they are not.
This patch instead clears the interrupt condition by draining the
RX FIFO during UART startup, after clearing any potentially
spurious interrupt. This should ensure that an interrupt will
definitely be asserted if the RX FIFO subsequently becomes
sufficiently full.
The drain is done at the point of enabling interrupts only. This
means that it will occur any time the UART is newly opened through
the tty layer. It will not apply to polled-mode use of the UART by
kgdboc: since that scenario cannot use interrupts by design, this
should not matter. kgdboc will interact badly with "normal" use of
the UART in any case: this patch makes no attempt to paper over
such issues.
This patch does not attempt to address the case where the RX FIFO
fills faster than it can be drained: that is a pathological
hardware design problem that is beyond the scope of the driver to
work around.
[1] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
before enabled the interruption
https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
Reported-by: Wei Xu <xuwei5@hisilicon.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Peter Maydell <peter.maydell@linaro.org>
Fixes: 9b96fbacda34 ("serial: PL011: clear pending interrupts")
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
---
drivers/tty/serial/amba-pl011.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 4b40a5b..a6ccb85 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1731,6 +1731,16 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
/* Clear out any spuriously appearing RX interrupts */
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
+
+ /*
+ * RXIS is asserted only when the RX FIFO transitions from below
+ * to above the trigger threshold. If the RX FIFO is already
+ * full to the threshold this can't happen and RXIS will now be
+ * stuck off. Drain the RX FIFO explicitly to fix this:
+ */
+ while (!(pl011_read(uap, REG_FR) & UART01x_FR_RXFE))
+ pl011_read(uap, REG_DR);
+
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM;
--
2.1.4
^ permalink raw reply related
* Re: [PATCH] tty/serial: atmel: use port->name as name in request_irq()
From: Richard Genoud @ 2018-04-27 10:31 UTC (permalink / raw)
To: Sebastian Andrzej Siewior, linux-serial
Cc: Alexandre Belloni, Peter Hurley, Greg Kroah-Hartman, Jiri Slaby,
tglx, linux-arm-kernel
In-Reply-To: <20180426151222.6vw67lwqmu6ffgnw@linutronix.de>
Hi Sebastian,
On 26/04/2018 17:12, Sebastian Andrzej Siewior wrote:
> On 2018-04-26 17:06:25 [+0200], To linux-serial@vger.kernel.org wrote:
>> It seems not to happen in v4.1.51 but it happens in v4.9 and v4.17-rc2
>> so if it broke accidentally it was not recently.
>
> This is what I used to check:
>
> diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
> --- a/drivers/tty/tty_io.c
> +++ b/drivers/tty/tty_io.c
> @@ -170,7 +170,7 @@ void free_tty_struct(struct tty_struct *tty)
> put_device(tty->dev);
> kfree(tty->write_buf);
> tty->magic = 0xDEADDEAD;
> - kfree(tty);
> + strcpy(tty->name, "GONE");
> }
>
> static inline struct tty_struct *file_tty(struct file *file)
>
> If this is unknown and a bisect is requested, please let me know.
Indeed, this will be appreciated.
I'm quite curious to find the commit that led to this.
Thanks !
>
> Sebastian
>
Richard
^ permalink raw reply
* [PATCH v2] serial: 8250_of: Add IO space support
From: John Garry @ 2018-04-27 10:36 UTC (permalink / raw)
To: gregkh, jslaby, joel, p.zabel, arnd, fcooper, sergei.shtylyov,
yamada.masahiro, khoroshilov
Cc: linux-serial, linux-kernel, andriy.shevchenko, linuxarm,
John Garry
Currently the 8250_of driver only supports MEM IO type
accesses.
Some development boards (Huawei D03, specifically) require
IO space access for 8250-compatible OF driver support, so
add it.
The modification is quite simple: just set the port iotype
and associated flags depending on the device address
resource type.
Signed-off-by: John Garry <john.garry@huawei.com>
---
Changes v1->v2:
- rebase to Greg's tty-testing branch
- use resource_type() helper
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 3de8d6a..bfb37f0 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -92,13 +92,43 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
goto err_unprepare;
}
+ port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
+ UPF_FIXED_TYPE;
spin_lock_init(&port->lock);
- port->mapbase = resource.start;
- port->mapsize = resource_size(&resource);
- /* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0)
- port->mapbase += prop;
+ if (resource_type(&resource) == IORESOURCE_IO) {
+ port->iotype = UPIO_PORT;
+ port->iobase = resource.start;
+ } else {
+ port->mapbase = resource.start;
+ port->mapsize = resource_size(&resource);
+
+ /* Check for shifted address mapping */
+ if (of_property_read_u32(np, "reg-offset", &prop) == 0)
+ port->mapbase += prop;
+
+ port->iotype = UPIO_MEM;
+ if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
+ switch (prop) {
+ case 1:
+ port->iotype = UPIO_MEM;
+ break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
+ case 4:
+ port->iotype = of_device_is_big_endian(np) ?
+ UPIO_MEM32BE : UPIO_MEM32;
+ break;
+ default:
+ dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
+ prop);
+ ret = -EINVAL;
+ goto err_dispose;
+ }
+ }
+ port->flags |= UPF_IOREMAP;
+ }
/* Check for registers offset within the devices address range */
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
@@ -114,26 +144,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->line = ret;
port->irq = irq_of_parse_and_map(np, 0);
- port->iotype = UPIO_MEM;
- if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
- switch (prop) {
- case 1:
- port->iotype = UPIO_MEM;
- break;
- case 2:
- port->iotype = UPIO_MEM16;
- break;
- case 4:
- port->iotype = of_device_is_big_endian(np) ?
- UPIO_MEM32BE : UPIO_MEM32;
- break;
- default:
- dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
- prop);
- ret = -EINVAL;
- goto err_dispose;
- }
- }
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) {
@@ -147,8 +157,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->type = type;
port->uartclk = clk;
- port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
- | UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->irqflags |= IRQF_SHARED;
if (of_property_read_bool(np, "no-loopback-test"))
--
1.9.1
^ permalink raw reply related
* [GIT PULL] TTY/Serial fixes for 4.17-rc3
From: Greg KH @ 2018-04-27 14:41 UTC (permalink / raw)
To: Linus Torvalds, Jiri Slaby
Cc: Stephen Rothwell, Andrew Morton, linux-kernel, linux-serial
The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git/ tags/tty-4.17-rc3
for you to fetch changes up to bcdd0ca8cb8730573afebcaae4138f8f4c8eaa20:
tty: Use __GFP_NOFAIL for tty_ldisc_get() (2018-04-25 15:03:44 +0200)
----------------------------------------------------------------
TTY/Serial fixes for 4.17-rc3
Here are some tty and serial driver fixes for reported issues for
4.17-rc3.
Nothing major, but a number of small things:
- device tree fixes/updates for serial ports
- earlycon fixes
- n_gsm fixes
- tty core change reverted to help resolve syszkaller reports
- other serial driver small fixes
All of these have been in linux-next with no reported issues.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----------------------------------------------------------------
Biju Das (1):
serial: sh-sci: Document r8a77470 bindings
Daniel Kurtz (1):
earlycon: Use a pointer table to fix __earlycon_table stride
Geert Uytterhoeven (2):
dt-bindings: meson-uart: DT fix s/clocks-names/clock-names/
dt-bindings: mvebu-uart: DT fix s/interrupts-names/interrupt-names/
Karthikeyan Ramasubramanian (1):
tty: serial: qcom_geni_serial: Use signed variable to get IRQ
Marc Zyngier (1):
serial: mvebu-uart: Fix local flags handling on termios update
Michal Simek (1):
tty: serial: xuartps: Setup early console when uartclk is also passed
Stefan Agner (2):
serial: imx: warn user when using unsupported configuration
serial: imx: fix cached UCR2 read on software reset
Tetsuo Handa (3):
tty: Avoid possible error pointer dereference at tty_ldisc_restore().
tty: Don't call panic() at tty_ldisc_init()
tty: Use __GFP_NOFAIL for tty_ldisc_get()
Tony Lindgren (2):
tty: n_gsm: Fix long delays with control frame timeouts in ADM mode
tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set
.../bindings/serial/amlogic,meson-uart.txt | 2 +-
.../devicetree/bindings/serial/mvebu-uart.txt | 2 +-
.../bindings/serial/renesas,sci-serial.txt | 2 ++
drivers/of/fdt.c | 7 ++++--
drivers/tty/n_gsm.c | 23 ++++++++++++++++-
drivers/tty/serial/earlycon.c | 6 +++--
drivers/tty/serial/imx.c | 19 +++++++++++++-
drivers/tty/serial/mvebu-uart.c | 1 -
drivers/tty/serial/qcom_geni_serial.c | 10 +++++---
drivers/tty/serial/xilinx_uartps.c | 2 +-
drivers/tty/tty_io.c | 5 +++-
drivers/tty/tty_ldisc.c | 29 ++++++++++------------
include/asm-generic/vmlinux.lds.h | 2 +-
include/linux/serial_core.h | 21 ++++++++++------
include/linux/tty.h | 2 +-
15 files changed, 93 insertions(+), 40 deletions(-)
^ permalink raw reply
* drivers/tty/serial/samsung.c s3c24xx_uart_copy_rx_to_tty
From: Nathan Royce @ 2018-04-27 16:41 UTC (permalink / raw)
To: gregkh; +Cc: jslaby, linux-kernel, linux-serial
No idea why, but I will say that something I've done recently was
re-enabl my ath9k_htc wireless adapter which tends to firmware-panic
quite a bit which also sometimes kills off my ppp usb adapter.
I have a script running that monitors the journalctl and restarts
hostapd everytime my ath device firmware-panics and comes back alive.
Same with netctl for my ppp.
The first time I've noticed this particular issue was yesterday when
my ssh session became sluggish and I was eventually forced to pull
power from my odroid. I only have 4 cores enabled, otherwise the usb
issues increase.
I cobbled together a setup with my ATX power supply providing power to
everything (including usb devices and hubs).
*****
Apr 27 10:27:39 computername kernel: [<c041fc38>]
(s3c64xx_serial_handle_irq) from [<c016da24>]
(__handle_irq_event_percpu+0x50/0x11c)
Apr 27 10:28:42 computername systemd-journald[22668]: Missed 5173
kernel messages
Apr 27 10:28:42 computername kernel: CPU: 0 PID: 99 Comm: mmcqd/1
Tainted: G D W 4.14.0-dirty #6
Apr 27 10:28:42 computername kernel: Hardware name: SAMSUNG EXYNOS
(Flattened Device Tree)
Apr 27 10:28:42 computername kernel: [<c010f428>] (unwind_backtrace)
from [<c010ba74>] (show_stack+0x10/0x14)
Apr 27 10:28:42 computername kernel: [<c010ba74>] (show_stack) from
[<c0731e9c>] (dump_stack+0x88/0x9c)
Apr 27 10:28:42 computername kernel: [<c0731e9c>] (dump_stack) from
[<c011cab8>] (__warn+0xe8/0x100)
Apr 27 10:28:42 computername kernel: [<c011cab8>] (__warn) from
[<c011cbc8>] (warn_slowpath_null+0x20/0x28)
Apr 27 10:28:42 computername kernel: [<c011cbc8>] (warn_slowpath_null)
from [<c041f814>] (s3c24xx_uart_copy_rx_to_tty+0xa0/0xd4)
Apr 27 10:28:42 computername kernel: [<c041f814>]
(s3c24xx_uart_copy_rx_to_tty) from [<c041fb84>]
(s3c24xx_serial_rx_chars+0x14c/0x1b8)
Apr 27 10:28:42 computername kernel: [<c041fb84>]
(s3c24xx_serial_rx_chars) from [<c041fc38>]
(s3c64xx_serial_handle_irq+0x48/0x60)
Apr 27 10:28:42 computername kernel: [<c041fc38>]
(s3c64xx_serial_handle_irq) from [<c016da24>]
(__handle_irq_event_percpu+0x50/0x11c)
Apr 27 10:28:42 computername kernel: [<c016da24>]
(__handle_irq_event_percpu) from [<c016db1c>]
(handle_irq_event_percpu+0x2c/0x7c)
Apr 27 10:28:42 computername kernel: [<c016db1c>]
(handle_irq_event_percpu) from [<c016dba4>]
(handle_irq_event+0x38/0x5c)
Apr 27 10:28:42 computername kernel: [<c016dba4>] (handle_irq_event)
from [<c0171448>] (handle_fasteoi_irq+0xa4/0x158)
Apr 27 10:28:42 computername kernel: [<c0171448>] (handle_fasteoi_irq)
from [<c016cda0>] (generic_handle_irq+0x24/0x34)
Apr 27 10:28:42 computername kernel: [<c016cda0>] (generic_handle_irq)
from [<c016d2b8>] (__handle_domain_irq+0x5c/0xb4)
Apr 27 10:28:42 computername kernel: [<c016d2b8>]
(__handle_domain_irq) from [<c01014d8>] (gic_handle_irq+0x3c/0x78)
Apr 27 10:28:42 computername kernel: [<c01014d8>] (gic_handle_irq)
from [<c010c78c>] (__irq_svc+0x6c/0x90)
Apr 27 10:28:42 computername kernel: Exception stack(0xede8baf8 to 0xede8bb40)
Apr 27 10:28:42 computername kernel: bae0:
ede8bcf4 ede98c80
Apr 27 10:28:42 computername kernel: bb00: 00000000 00000002 a00c0113
eddfec00 ede8bce0 00000000 ee20f904 ede8bd58
Apr 27 10:28:42 computername kernel: bb20: 00000100 c0c02080 c0801550
ede8bb48 c074c7dc c074c7e0 600c0113 ffffffff
Apr 27 10:28:42 computername kernel: [<c010c78c>] (__irq_svc) from
[<c074c7e0>] (_raw_spin_unlock_irqrestore+0x10/0x14)
Apr 27 10:28:42 computername kernel: [<c074c7e0>]
(_raw_spin_unlock_irqrestore) from [<c05aecb0>]
(dw_mci_request_end+0xa8/0xdc)
Apr 27 10:28:42 computername kernel: [<c05aecb0>] (dw_mci_request_end)
from [<c05af000>] (dw_mci_tasklet_func+0x31c/0x3dc)
Apr 27 10:28:42 computername kernel: [<c05af000>]
(dw_mci_tasklet_func) from [<c0121808>] (tasklet_action+0x7c/0x118)
Apr 27 10:28:42 computername kernel: [<c0121808>] (tasklet_action)
from [<c01015f8>] (__do_softirq+0xe0/0x248)
Apr 27 10:28:42 computername kernel: [<c01015f8>] (__do_softirq) from
[<c0121bf8>] (irq_exit+0xd8/0x140)
Apr 27 10:28:42 computername kernel: [<c0121bf8>] (irq_exit) from
[<c016d2bc>] (__handle_domain_irq+0x60/0xb4)
Apr 27 10:28:42 computername kernel: [<c016d2bc>]
(__handle_domain_irq) from [<c01014d8>] (gic_handle_irq+0x3c/0x78)
Apr 27 10:28:42 computername kernel: [<c01014d8>] (gic_handle_irq)
from [<c010c78c>] (__irq_svc+0x6c/0x90)
Apr 27 10:28:42 computername kernel: Exception stack(0xede8bc28 to 0xede8bc70)
Apr 27 10:28:42 computername kernel: bc20: ede8bcf4
ede98c80 00000000 00000001 7fffffff ede8bcf4
Apr 27 10:28:42 computername kernel: bc40: ede8a000 00000002 00000000
c0c05448 00000000 ede8bcf0 00000100 ede8bc78
Apr 27 10:28:42 computername kernel: bc60: c074c7ec c074c7f0 600c0013 ffffffff
Apr 27 10:28:42 computername kernel: [<c010c78c>] (__irq_svc) from
[<c074c7f0>] (_raw_spin_unlock_irq+0xc/0x10)
Apr 27 10:28:42 computername kernel: [<c074c7f0>]
(_raw_spin_unlock_irq) from [<c0748324>] (wait_for_common+0xa0/0x168)
Apr 27 10:28:42 computername kernel: [<c0748324>] (wait_for_common)
from [<c05921b0>] (mmc_wait_for_req_done+0x8c/0x110)
Apr 27 10:28:42 computername kernel: [<c05921b0>]
(mmc_wait_for_req_done) from [<c0592e34>] (mmc_wait_for_cmd+0x68/0x9c)
Apr 27 10:28:42 computername kernel: [<c0592e34>] (mmc_wait_for_cmd)
from [<c0598de4>] (__mmc_send_status+0x68/0x98)
Apr 27 10:28:42 computername kernel: [<c0598de4>] (__mmc_send_status)
from [<c05a0fac>] (card_busy_detect+0x64/0x150)
Apr 27 10:28:42 computername kernel: [<c05a0fac>] (card_busy_detect)
from [<c05a2378>] (mmc_blk_err_check+0x180/0x5bc)
Apr 27 10:28:42 computername kernel: [<c05a2378>] (mmc_blk_err_check)
from [<c05929d4>] (mmc_start_areq+0xb0/0x3bc)
Apr 27 10:28:42 computername kernel: [<c05929d4>] (mmc_start_areq)
from [<c05a35f4>] (mmc_blk_issue_rw_rq+0xb8/0x39c)
Apr 27 10:28:42 computername kernel: [<c05a35f4>]
(mmc_blk_issue_rw_rq) from [<c05a3ec0>] (mmc_blk_issue_rq+0x1a4/0x844)
Apr 27 10:28:42 computername kernel: [<c05a3ec0>] (mmc_blk_issue_rq)
from [<c05a4624>] (mmc_queue_thread+0xc4/0x164)
Apr 27 10:28:42 computername kernel: [<c05a4624>] (mmc_queue_thread)
from [<c0139b18>] (kthread+0x14c/0x154)
Apr 27 10:28:42 computername kernel: [<c0139b18>] (kthread) from
[<c0107e50>] (ret_from_fork+0x14/0x24)
Apr 27 10:28:42 computername kernel: ---[ end trace 2f940e396221e98e ]---
Apr 27 10:28:42 computername kernel: samsung-uart 12c20000.serial:
RxData copy to tty layer failed
Apr 27 10:28:42 computername kernel: ------------[ cut here ]------------
Apr 27 10:28:42 computername kernel: WARNING: CPU: 0 PID: 21972 at
drivers/tty/serial/samsung.c:381 s3c24xx_uart_copy_rx_to_tty+0xa0/0xd4
Apr 27 10:28:42 computername kernel: Modules linked in: tun cmac ccm
md5 ppp_deflate ppp_async arc4 ppp_generic slhc ath9k_htc ath9k_common
ath9k_hw ath mac80211 cfg80211 option usb_wwan rfkill hid_logitech_dj
usbserial bridge stp llc nf_log_ipv6 ip6table_filter ip6t_MASQUERADE
n>
Apr 27 10:28:42 computername kernel: dvb_core videobuf2_v4l2 videodev
videobuf2_core nfsd auth_rpcgss oid_registry nfs_acl lockd grace
sunrpc crypto_user ip_tables x_tables
Apr 27 10:28:42 computername kernel: CPU: 0 PID: 21972 Comm:
kworker/0:1 Tainted: G D W 4.14.0-dirty #6
Apr 27 10:28:42 computername kernel: Hardware name: SAMSUNG EXYNOS
(Flattened Device Tree)
Apr 27 10:28:42 computername kernel: Workqueue: events dbs_work_handler
Apr 27 10:28:42 computername kernel: [<c010f428>] (unwind_backtrace)
from [<c010ba74>] (show_stack+0x10/0x14)
Apr 27 10:28:42 computername kernel: [<c010ba74>] (show_stack) from
[<c0731e9c>] (dump_stack+0x88/0x9c)
Apr 27 10:28:42 computername kernel: [<c0731e9c>] (dump_stack) from
[<c011cab8>] (__warn+0xe8/0x100)
Apr 27 10:28:42 computername kernel: [<c011cab8>] (__warn) from
[<c011cbc8>] (warn_slowpath_null+0x20/0x28)
Apr 27 10:28:42 computername kernel: [<c011cbc8>] (warn_slowpath_null)
from [<c041f814>] (s3c24xx_uart_copy_rx_to_tty+0xa0/0xd4)
Apr 27 10:28:42 computername kernel: [<c041f814>]
(s3c24xx_uart_copy_rx_to_tty) from [<c041fb84>]
(s3c24xx_serial_rx_chars+0x14c/0x1b8)
Apr 27 10:28:42 computername kernel: [<c041fb84>]
(s3c24xx_serial_rx_chars) from [<c041fc38>]
(s3c64xx_serial_handle_irq+0x48/0x60)
Apr 27 10:28:42 computername kernel: [<c041fc38>]
(s3c64xx_serial_handle_irq) from [<c016da24>]
(__handle_irq_event_percpu+0x50/0x11c)
Apr 27 10:28:42 computername kernel: [<c016da24>]
(__handle_irq_event_percpu) from [<c016db1c>]
(handle_irq_event_percpu+0x2c/0x7c)
Apr 27 10:28:42 computername kernel: [<c016db1c>]
(handle_irq_event_percpu) from [<c016dba4>]
(handle_irq_event+0x38/0x5c)
Apr 27 10:28:42 computername kernel: [<c016dba4>] (handle_irq_event)
from [<c0171448>] (handle_fasteoi_irq+0xa4/0x158)
Apr 27 10:28:42 computername kernel: [<c0171448>] (handle_fasteoi_irq)
from [<c016cda0>] (generic_handle_irq+0x24/0x34)
Apr 27 10:28:42 computername kernel: [<c016cda0>] (generic_handle_irq)
from [<c016d2b8>] (__handle_domain_irq+0x5c/0xb4)
Apr 27 10:28:42 computername kernel: [<c016d2b8>]
(__handle_domain_irq) from [<c01014d8>] (gic_handle_irq+0x3c/0x78)
Apr 27 10:28:42 computername kernel: [<c01014d8>] (gic_handle_irq)
from [<c010c78c>] (__irq_svc+0x6c/0x90)
Apr 27 10:28:42 computername kernel: Exception stack(0xdd101db0 to 0xdd101df8)
Apr 27 10:28:42 computername kernel: 1da0:
d35fdb77 00000000 c0c055d4 f080e000
Apr 27 10:28:42 computername kernel: 1dc0: c0c85640 036b7fbe 2e241000
00000002 c0c055d4 0000005f fd5c0698 00003172
Apr 27 10:28:42 computername kernel: 1de0: 00000002 dd101e00 c0182644
c05b4e5c 600c0013 ffffffff
Apr 27 10:28:42 computername kernel: [<c010c78c>] (__irq_svc) from
[<c05b4e5c>] (exynos4_frc_read+0x14/0x18)
Apr 27 10:28:42 computername kernel: [<c05b4e5c>] (exynos4_frc_read)
from [<c0182644>] (ktime_get+0x44/0xdc)
Apr 27 10:28:42 computername kernel: [<c0182644>] (ktime_get) from
[<c0190c60>] (get_cpu_idle_time_us+0x48/0x140)
Apr 27 10:28:42 computername kernel: [<c0190c60>]
(get_cpu_idle_time_us) from [<c058a9c4>]
(get_cpu_idle_time+0x48/0x18c)
Apr 27 10:28:42 computername kernel: [<c058a9c4>] (get_cpu_idle_time)
from [<c058e28c>] (dbs_update+0xa8/0x25c)
Apr 27 10:28:42 computername kernel: [<c058e28c>] (dbs_update) from
[<c058da80>] (od_dbs_update+0x48/0x160)
Apr 27 10:28:42 computername kernel: [<c058da80>] (od_dbs_update) from
[<c058e0f4>] (dbs_work_handler+0x2c/0x54)
Apr 27 10:28:42 computername kernel: [<c058e0f4>] (dbs_work_handler)
from [<c0133e6c>] (process_one_work+0x1d8/0x404)
Apr 27 10:28:42 computername kernel: [<c0133e6c>] (process_one_work)
from [<c0134c18>] (worker_thread+0x50/0x598)
Apr 27 10:28:42 computername kernel: [<c0134c18>] (worker_thread) from
[<c0139b18>] (kthread+0x14c/0x154)
Apr 27 10:28:42 computername kernel: [<c0139b18>] (kthread) from
[<c0107e50>] (ret_from_fork+0x14/0x24)
Apr 27 10:28:42 computername kernel: ---[ end trace 2f940e396221e98f ]---
*****
^ permalink raw reply
* Re: [PATCH v3 03/20] crypto: Remove depends on HAS_DMA in case of platform dependency
From: Herbert Xu @ 2018-04-28 8:24 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Ulf Hansson, Wolfram Sang, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-fpga-u79uwXL29TY76Z2rM5mHXA,
linux-remoteproc-u79uwXL29TY76Z2rM5mHXA,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, Bjorn Andersson, Eric Anholt,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
linux1394-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Christoph Hellwig, Stefan Wahren, Boris Brezillon,
Richard Weinberger, Jassi Brar, Marek Vasut,
linux-serial-u79uwXL29TY76Z2rM5mHXA, Matias Bjorling,
linux-media-u79uwXL29TY76Z2rM5mHXA, Ohad Ben-Cohen,
devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b, Alan Tull,
Bartlomiej Zolnierkiewicz, linux-kernel
In-Reply-To: <1523987360-18760-4-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
On Tue, Apr 17, 2018 at 07:49:03PM +0200, Geert Uytterhoeven wrote:
> Remove dependencies on HAS_DMA where a Kconfig symbol depends on another
> symbol that implies HAS_DMA, and, optionally, on "|| COMPILE_TEST".
> In most cases this other symbol is an architecture or platform specific
> symbol, or PCI.
>
> Generic symbols and drivers without platform dependencies keep their
> dependencies on HAS_DMA, to prevent compiling subsystems or drivers that
> cannot work anyway.
>
> This simplifies the dependencies, and allows to improve compile-testing.
>
> Signed-off-by: Geert Uytterhoeven <geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
> Reviewed-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Acked-by: Herbert Xu <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
> ---
> v3:
> - Add Acked-by,
> - Rebase to v4.17-rc1,
>
> v2:
> - Add Reviewed-by, Acked-by,
> - Drop RFC state,
> - Split per subsystem.
> ---
> drivers/crypto/Kconfig | 14 ++++----------
> 1 file changed, 4 insertions(+), 10 deletions(-)
Patch applied. Thanks.
--
Email: Herbert Xu <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] tty: pl011: Avoid spuriously stuck-off interrupts
From: Greg KH @ 2018-04-29 13:18 UTC (permalink / raw)
To: Dave Martin
Cc: Peter Maydell, Andrew Jones, Ciro Santilli, Linus Walleij,
Russell King, Wei Xu, linux-serial, linux-arm-kernel
In-Reply-To: <1524823545-11309-1-git-send-email-Dave.Martin@arm.com>
On Fri, Apr 27, 2018 at 11:05:44AM +0100, Dave Martin wrote:
> This is an update to a previous RFC [1], to fix a problem observed by
> the qemu community that causes serial input to hang when booting a
> simulated system with data already queued in the UART FIFO [2].
>
> This patch could cause problems for people that are actually relying
> on chars queued in the PL011 RX FIFO during boot or while the UART is
> closed. There are no guarantees about such things working in general.
> In either case, there is no protection against RX FIFO overflow or
> reprogramming of the UART parameters while Linux is not actively
> receiving chars.
>
> Cheers
> ---Dave
>
> [1] [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
> http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/574033.html
>
> [2] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
> before enabled the interruption
> https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
>
> Dave Martin (1):
> tty: pl011: Avoid spuriously stuck-off interrupts
>
> drivers/tty/serial/amba-pl011.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> --
> 2.1.4
There is no patch here, did something go wrong?
You do not need a "cover letter" for a single patch...
thanks,
greg k-h
^ permalink raw reply
* [PATCH] serial: sh-sci: Use spin_{try}lock_irqsave instead of open coding version
From: Daniel Wagner @ 2018-04-30 8:09 UTC (permalink / raw)
To: linux-kernel
Cc: linux-rt-users, linux-serial, Greg Kroah-Hartman, linux-sh,
Daniel Wagner, Shinya Kuribayashi
From: Daniel Wagner <daniel.wagner@siemens.com>
Commit 40f70c03e33a ("serial: sh-sci: add locking to console write
function to avoid SMP lockup") copied the strategy to avoid locking
problems in conjuncture with the console from the UART8250
driver. Instead using directly spin_{try}lock_irqsave(),
local_irq_save() followed by spin_{try}lock() was used. While this is
correct on mainline, for -rt it is a problem. spin_{try}lock() will
check if it is running in a valid context. Since the local_irq_save()
has already been executed, the context has changed and
spin_{try}lock() will complain. The reason why spin_{try}lock()
complains is that on -rt the spin locks are turned into mutexes and
therefore can sleep. Sleeping with interrupts disabled is not valid.
BUG: sleeping function called from invalid context at /home/wagi/work/rt/v4.4-cip-rt/kernel/locking/rtmutex.c:995
in_atomic(): 0, irqs_disabled(): 128, pid: 778, name: irq/76-eth0
CPU: 0 PID: 778 Comm: irq/76-eth0 Not tainted 4.4.126-test-cip22-rt14-00403-gcd03665c8318 #12
Hardware name: Generic RZ/G1 (Flattened Device Tree)
Backtrace:
[<c00140a0>] (dump_backtrace) from [<c001424c>] (show_stack+0x18/0x1c)
r7:c06b01f0 r6:60010193 r5:00000000 r4:c06b01f0
[<c0014234>] (show_stack) from [<c01d3c94>] (dump_stack+0x78/0x94)
[<c01d3c1c>] (dump_stack) from [<c004c134>] (___might_sleep+0x134/0x194)
r7:60010113 r6:c06d3559 r5:00000000 r4:ffffe000
[<c004c000>] (___might_sleep) from [<c04ded60>] (rt_spin_lock+0x20/0x74)
r5:c06f4d60 r4:c06f4d60
[<c04ded40>] (rt_spin_lock) from [<c02577e4>] (serial_console_write+0x100/0x118)
r5:c06f4d60 r4:c06f4d60
[<c02576e4>] (serial_console_write) from [<c0061060>] (call_console_drivers.constprop.15+0x10c/0x124)
r10:c06d2894 r9:c04e18b0 r8:00000028 r7:00000000 r6:c06d3559 r5:c06d2798
r4:c06b9914 r3:c02576e4
[<c0060f54>] (call_console_drivers.constprop.15) from [<c0062984>] (console_unlock+0x32c/0x430)
r10:c06d30d8 r9:00000028 r8:c06dd518 r7:00000005 r6:00000000 r5:c06d2798
r4:c06d2798 r3:00000028
[<c0062658>] (console_unlock) from [<c0062e1c>] (vprintk_emit+0x394/0x4f0)
r10:c06d2798 r9:c06d30ee r8:00000006 r7:00000005 r6:c06a78fc r5:00000027
r4:00000003
[<c0062a88>] (vprintk_emit) from [<c0062fa0>] (vprintk+0x28/0x30)
r10:c060bd46 r9:00001000 r8:c06b9a90 r7:c06b9a90 r6:c06b994c r5:c06b9a3c
r4:c0062fa8
[<c0062f78>] (vprintk) from [<c0062fb8>] (vprintk_default+0x10/0x14)
[<c0062fa8>] (vprintk_default) from [<c009cd30>] (printk+0x78/0x84)
[<c009ccbc>] (printk) from [<c025afdc>] (credit_entropy_bits+0x17c/0x2cc)
r3:00000001 r2:decade60 r1:c061a5ee r0:c061a523
r4:00000006
[<c025ae60>] (credit_entropy_bits) from [<c025bf74>] (add_interrupt_randomness+0x160/0x178)
r10:466e7196 r9:1f536000 r8:fffeef74 r7:00000000 r6:c06b9a60 r5:c06b9a3c
r4:dfbcf680
[<c025be14>] (add_interrupt_randomness) from [<c006536c>] (irq_thread+0x1e8/0x248)
r10:c006537c r9:c06cdf21 r8:c0064fcc r7:df791c24 r6:df791c00 r5:ffffe000
r4:df525180
[<c0065184>] (irq_thread) from [<c003fba4>] (kthread+0x108/0x11c)
r10:00000000 r9:00000000 r8:c0065184 r7:df791c00 r6:00000000 r5:df791d00
r4:decac000
[<c003fa9c>] (kthread) from [<c00101b8>] (ret_from_fork+0x14/0x3c)
r8:00000000 r7:00000000 r6:00000000 r5:c003fa9c r4:df791d00
Cc: Shinya Kuribayashi <shinya.kuribayashi.px@renesas.com>
Signed-off-by: Daniel Wagner <daniel.wagner@siemens.com>
---
drivers/tty/serial/sh-sci.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index cf8d0955657d..3900711b60fc 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2516,13 +2516,12 @@ static void serial_console_write(struct console *co, const char *s,
unsigned long flags;
int locked = 1;
- local_irq_save(flags);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
- locked = spin_trylock(&port->lock);
+ locked = spin_trylock_irqsave(&port->lock, flags);
else
- spin_lock(&port->lock);
+ spin_lock_irqsave(&port->lock, flags);
/* first save the SCSCR then disable the interrupts */
ctrl = serial_port_in(port, SCSCR);
@@ -2539,8 +2538,7 @@ static void serial_console_write(struct console *co, const char *s,
serial_port_out(port, SCSCR, ctrl);
if (locked)
- spin_unlock(&port->lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
static int serial_console_setup(struct console *co, char *options)
--
2.14.3
^ permalink raw reply related
* Re: [PATCH] tty: pl011: Avoid spuriously stuck-off interrupts
From: Dave Martin @ 2018-04-30 12:49 UTC (permalink / raw)
To: Greg KH
Cc: Peter Maydell, Andrew Jones, Ciro Santilli, Linus Walleij,
Russell King, Wei Xu, linux-serial, linux-arm-kernel
In-Reply-To: <20180429131857.GC23018@kroah.com>
On Sun, Apr 29, 2018 at 03:18:57PM +0200, Greg KH wrote:
> On Fri, Apr 27, 2018 at 11:05:44AM +0100, Dave Martin wrote:
> > This is an update to a previous RFC [1], to fix a problem observed by
> > the qemu community that causes serial input to hang when booting a
> > simulated system with data already queued in the UART FIFO [2].
> >
> > This patch could cause problems for people that are actually relying
> > on chars queued in the PL011 RX FIFO during boot or while the UART is
> > closed. There are no guarantees about such things working in general.
> > In either case, there is no protection against RX FIFO overflow or
> > reprogramming of the UART parameters while Linux is not actively
> > receiving chars.
> >
> > Cheers
> > ---Dave
> >
> > [1] [RFC PATCH v4] tty: pl011: Avoid spuriously stuck-off interrupts
> > http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/574033.html
> >
> > [2] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
> > before enabled the interruption
> > https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
> >
> > Dave Martin (1):
> > tty: pl011: Avoid spuriously stuck-off interrupts
> >
> > drivers/tty/serial/amba-pl011.c | 10 ++++++++++
> > 1 file changed, 10 insertions(+)
> >
> > --
> > 2.1.4
>
> There is no patch here, did something go wrong?
>
> You do not need a "cover letter" for a single patch...
I wanted to provide some additional context for the benefit of people
who'd been reviewing earler RFCs for this change, though I could have
put it under the tearoff instead.
I was expecting --cover-letter to generate [PATCH 0/1] and [PATCH 1/1]
Subject lines, but it seems that it doesn't do that.
To clarify, there is only intended to be one patch here.
Do you want me to repost?
Cheers
---Dave
^ permalink raw reply
* [PATCH 0/3] sh: make early_platform code SuperH-specific
From: Bartosz Golaszewski @ 2018-04-30 16:35 UTC (permalink / raw)
To: Sekhar Nori, Kevin Hilman, David Lechner, Michael Turquette,
Stephen Boyd, Arnd Bergmann, Greg Kroah-Hartman, Mark Rutland,
Yoshinori Sato, Rich Felker, Andy Shevchenko, Marc Zyngier,
Rafael J . Wysocki, Peter Rosin, Jiri Slaby, Thomas Gleixner,
Daniel Lezcano
Cc: linux-arm-kernel, linux-kernel, linux-serial, linux-sh,
Bartosz Golaszewski
I recently started a discussion about the need for a proper early device
probing mechanism[1]. One that would be based on real platform drivers
and support both platform data and device tree.
While we're far from reaching any consensus on the implementation, Arnd
suggested that I start off by moving the SuperH-specific early platform
drivers implementation to arch/sh[2].
This series is the first attempt at making way for a new, less hacky
implementation.
The first patch removes the last instance of a non-sh driver using the
early_platform API. It can be removed since ARM no longer probes early
drivers.
The second patch moves all the early_platform code to arch/sh.
The last patch prefixes all early_platform symbols with 'sh_'.
[1] https://lkml.org/lkml/2018/4/26/657
[2] https://lkml.org/lkml/2018/4/27/239
Bartosz Golaszewski (3):
clocksource: timer-ti-dm: remove the early platform driver
registration
platform: move the early platform device support to arch/sh
sh: add the sh_ prefix to early platform symbols
arch/sh/drivers/Makefile | 2 +-
arch/sh/drivers/platform_early.c | 346 +++++++++++++++++++++++++
arch/sh/include/asm/platform_early.h | 61 +++++
arch/sh/kernel/cpu/sh2/setup-sh7619.c | 4 +-
arch/sh/kernel/cpu/sh2a/setup-mxg.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7264.c | 3 +-
arch/sh/kernel/cpu/sh2a/setup-sh7269.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh3.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7705.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh770x.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh7710.c | 3 +-
arch/sh/kernel/cpu/sh3/setup-sh7720.c | 3 +-
arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 3 +-
arch/sh/kernel/cpu/sh4/setup-sh7750.c | 9 +-
arch/sh/kernel/cpu/sh4/setup-sh7760.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7734.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 4 +-
arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 3 +-
arch/sh/kernel/cpu/sh4a/setup-shx3.c | 3 +-
arch/sh/kernel/cpu/sh5/setup-sh5.c | 3 +-
arch/sh/kernel/setup.c | 3 +-
arch/sh/kernel/time.c | 5 +-
drivers/base/platform.c | 288 --------------------
drivers/clocksource/sh_cmt.c | 6 +-
drivers/clocksource/sh_mtu2.c | 8 +-
drivers/clocksource/sh_tmu.c | 8 +-
drivers/clocksource/timer-ti-dm.c | 1 -
drivers/tty/serial/sh-sci.c | 5 +-
include/linux/platform_device.h | 52 ----
41 files changed, 491 insertions(+), 387 deletions(-)
create mode 100644 arch/sh/drivers/platform_early.c
create mode 100644 arch/sh/include/asm/platform_early.h
--
2.17.0
^ permalink raw reply
* [PATCH 1/3] clocksource: timer-ti-dm: remove the early platform driver registration
From: Bartosz Golaszewski @ 2018-04-30 16:35 UTC (permalink / raw)
To: Sekhar Nori, Kevin Hilman, David Lechner, Michael Turquette,
Stephen Boyd, Arnd Bergmann, Greg Kroah-Hartman, Mark Rutland,
Yoshinori Sato, Rich Felker, Andy Shevchenko, Marc Zyngier,
Rafael J . Wysocki, Peter Rosin, Jiri Slaby, Thomas Gleixner,
Daniel Lezcano
Cc: linux-arm-kernel, linux-kernel, linux-serial, linux-sh,
Bartosz Golaszewski
In-Reply-To: <20180430163556.2560-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This driver is no longer used as an early platform driver. Remove the
registration macro.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/clocksource/timer-ti-dm.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 4cce6b224b87..595124074821 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -991,7 +991,6 @@ static struct platform_driver omap_dm_timer_driver = {
},
};
-early_platform_init("earlytimer", &omap_dm_timer_driver);
module_platform_driver(omap_dm_timer_driver);
MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
--
2.17.0
^ permalink raw reply related
* [PATCH 2/3] platform: move the early platform device support to arch/sh
From: Bartosz Golaszewski @ 2018-04-30 16:35 UTC (permalink / raw)
To: Sekhar Nori, Kevin Hilman, David Lechner, Michael Turquette,
Stephen Boyd, Arnd Bergmann, Greg Kroah-Hartman, Mark Rutland,
Yoshinori Sato, Rich Felker, Andy Shevchenko, Marc Zyngier,
Rafael J . Wysocki, Peter Rosin, Jiri Slaby, Thomas Gleixner,
Daniel Lezcano
Cc: linux-arm-kernel, linux-kernel, linux-serial, linux-sh,
Bartosz Golaszewski
In-Reply-To: <20180430163556.2560-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
SuperH is the only user of the current implementation of early platform
device support. We want to introduce a more robust approach to early
probing. As the first step - move all the current early platform code
to arch/sh.
In order not to export internal drivers/base functions to arch code for
this temporary solution - copy the two needed routines for driver
matching from drivers/base/platform.c to arch/sh/drivers/platform_early.c.
Also: call early_platform_cleanup() from subsys_initcall() so that it's
called after all early devices are probed.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
arch/sh/drivers/Makefile | 2 +-
arch/sh/drivers/platform_early.c | 346 +++++++++++++++++++++++++
arch/sh/include/asm/platform_early.h | 61 +++++
arch/sh/kernel/cpu/sh2/setup-sh7619.c | 2 +
arch/sh/kernel/cpu/sh2a/setup-mxg.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7264.c | 1 +
arch/sh/kernel/cpu/sh2a/setup-sh7269.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh3.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7705.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh770x.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7710.c | 1 +
arch/sh/kernel/cpu/sh3/setup-sh7720.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh7750.c | 1 +
arch/sh/kernel/cpu/sh4/setup-sh7760.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7734.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 2 +
arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 1 +
arch/sh/kernel/cpu/sh4a/setup-shx3.c | 1 +
arch/sh/kernel/cpu/sh5/setup-sh5.c | 1 +
arch/sh/kernel/setup.c | 1 +
arch/sh/kernel/time.c | 1 +
drivers/base/platform.c | 288 --------------------
drivers/clocksource/sh_mtu2.c | 2 +
drivers/clocksource/sh_tmu.c | 2 +
drivers/tty/serial/sh-sci.c | 1 +
include/linux/platform_device.h | 52 ----
39 files changed, 446 insertions(+), 341 deletions(-)
create mode 100644 arch/sh/drivers/platform_early.c
create mode 100644 arch/sh/include/asm/platform_early.h
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index 3e93b434e604..56b0acace6e7 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -3,7 +3,7 @@
# Makefile for the Linux SuperH-specific device drivers.
#
-obj-y += dma/
+obj-y += dma/ platform_early.o
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_SUPERHYWAY) += superhyway/
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
new file mode 100644
index 000000000000..bc094f6eb366
--- /dev/null
+++ b/arch/sh/drivers/platform_early.c
@@ -0,0 +1,346 @@
+// SPDX--License-Identifier: GPL-2.0
+
+#include <asm/platform_early.h>
+#include <linux/pm.h>
+
+static __initdata LIST_HEAD(early_platform_driver_list);
+static __initdata LIST_HEAD(early_platform_device_list);
+
+static const struct platform_device_id *
+platform_match_id(const struct platform_device_id *id,
+ struct platform_device *pdev)
+{
+ while (id->name[0]) {
+ if (strcmp(pdev->name, id->name) == 0) {
+ pdev->id_entry = id;
+ return id;
+ }
+ id++;
+ }
+ return NULL;
+}
+
+static int platform_match(struct device *dev, struct device_driver *drv)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct platform_driver *pdrv = to_platform_driver(drv);
+
+ /* When driver_override is set, only bind to the matching driver */
+ if (pdev->driver_override)
+ return !strcmp(pdev->driver_override, drv->name);
+
+ /* Then try to match against the id table */
+ if (pdrv->id_table)
+ return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+ /* fall-back to driver name match */
+ return (strcmp(pdev->name, drv->name) == 0);
+}
+
+#ifdef CONFIG_PM
+static void device_pm_init_common(struct device *dev)
+{
+ if (!dev->power.early_init) {
+ spin_lock_init(&dev->power.lock);
+ dev->power.qos = NULL;
+ dev->power.early_init = true;
+ }
+}
+
+static void pm_runtime_early_init(struct device *dev)
+{
+ dev->power.disable_depth = 1;
+ device_pm_init_common(dev);
+}
+#else
+static void pm_runtime_early_init(struct device *dev) {}
+#endif
+
+/**
+ * early_platform_driver_register - register early platform driver
+ * @epdrv: early_platform driver structure
+ * @buf: string passed from early_param()
+ *
+ * Helper function for early_platform_init() / early_platform_init_buffer()
+ */
+int __init early_platform_driver_register(struct early_platform_driver *epdrv,
+ char *buf)
+{
+ char *tmp;
+ int n;
+
+ /* Simply add the driver to the end of the global list.
+ * Drivers will by default be put on the list in compiled-in order.
+ */
+ if (!epdrv->list.next) {
+ INIT_LIST_HEAD(&epdrv->list);
+ list_add_tail(&epdrv->list, &early_platform_driver_list);
+ }
+
+ /* If the user has specified device then make sure the driver
+ * gets prioritized. The driver of the last device specified on
+ * command line will be put first on the list.
+ */
+ n = strlen(epdrv->pdrv->driver.name);
+ if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
+ list_move(&epdrv->list, &early_platform_driver_list);
+
+ /* Allow passing parameters after device name */
+ if (buf[n] == '\0' || buf[n] == ',')
+ epdrv->requested_id = -1;
+ else {
+ epdrv->requested_id = simple_strtoul(&buf[n + 1],
+ &tmp, 10);
+
+ if (buf[n] != '.' || (tmp == &buf[n + 1])) {
+ epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+ n = 0;
+ } else
+ n += strcspn(&buf[n + 1], ",") + 1;
+ }
+
+ if (buf[n] == ',')
+ n++;
+
+ if (epdrv->bufsize) {
+ memcpy(epdrv->buffer, &buf[n],
+ min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
+ epdrv->buffer[epdrv->bufsize - 1] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * early_platform_add_devices - adds a number of early platform devices
+ * @devs: array of early platform devices to add
+ * @num: number of early platform devices in array
+ *
+ * Used by early architecture code to register early platform devices and
+ * their platform data.
+ */
+void __init early_platform_add_devices(struct platform_device **devs, int num)
+{
+ struct device *dev;
+ int i;
+
+ /* simply add the devices to list */
+ for (i = 0; i < num; i++) {
+ dev = &devs[i]->dev;
+
+ if (!dev->devres_head.next) {
+ pm_runtime_early_init(dev);
+ INIT_LIST_HEAD(&dev->devres_head);
+ list_add_tail(&dev->devres_head,
+ &early_platform_device_list);
+ }
+ }
+}
+
+/**
+ * early_platform_driver_register_all - register early platform drivers
+ * @class_str: string to identify early platform driver class
+ *
+ * Used by architecture code to register all early platform drivers
+ * for a certain class. If omitted then only early platform drivers
+ * with matching kernel command line class parameters will be registered.
+ */
+void __init early_platform_driver_register_all(char *class_str)
+{
+ /* The "class_str" parameter may or may not be present on the kernel
+ * command line. If it is present then there may be more than one
+ * matching parameter.
+ *
+ * Since we register our early platform drivers using early_param()
+ * we need to make sure that they also get registered in the case
+ * when the parameter is missing from the kernel command line.
+ *
+ * We use parse_early_options() to make sure the early_param() gets
+ * called at least once. The early_param() may be called more than
+ * once since the name of the preferred device may be specified on
+ * the kernel command line. early_platform_driver_register() handles
+ * this case for us.
+ */
+ parse_early_options(class_str);
+}
+
+/**
+ * early_platform_match - find early platform device matching driver
+ * @epdrv: early platform driver structure
+ * @id: id to match against
+ */
+static struct platform_device * __init
+early_platform_match(struct early_platform_driver *epdrv, int id)
+{
+ struct platform_device *pd;
+
+ list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+ if (pd->id == id)
+ return pd;
+
+ return NULL;
+}
+
+/**
+ * early_platform_left - check if early platform driver has matching devices
+ * @epdrv: early platform driver structure
+ * @id: return true if id or above exists
+ */
+static int __init early_platform_left(struct early_platform_driver *epdrv,
+ int id)
+{
+ struct platform_device *pd;
+
+ list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+ if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+ if (pd->id >= id)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * early_platform_driver_probe_id - probe drivers matching class_str and id
+ * @class_str: string to identify early platform driver class
+ * @id: id to match against
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ */
+static int __init early_platform_driver_probe_id(char *class_str,
+ int id,
+ int nr_probe)
+{
+ struct early_platform_driver *epdrv;
+ struct platform_device *match;
+ int match_id;
+ int n = 0;
+ int left = 0;
+
+ list_for_each_entry(epdrv, &early_platform_driver_list, list) {
+ /* only use drivers matching our class_str */
+ if (strcmp(class_str, epdrv->class_str))
+ continue;
+
+ if (id == -2) {
+ match_id = epdrv->requested_id;
+ left = 1;
+
+ } else {
+ match_id = id;
+ left += early_platform_left(epdrv, id);
+
+ /* skip requested id */
+ switch (epdrv->requested_id) {
+ case EARLY_PLATFORM_ID_ERROR:
+ case EARLY_PLATFORM_ID_UNSET:
+ break;
+ default:
+ if (epdrv->requested_id == id)
+ match_id = EARLY_PLATFORM_ID_UNSET;
+ }
+ }
+
+ switch (match_id) {
+ case EARLY_PLATFORM_ID_ERROR:
+ pr_warn("%s: unable to parse %s parameter\n",
+ class_str, epdrv->pdrv->driver.name);
+ /* fall-through */
+ case EARLY_PLATFORM_ID_UNSET:
+ match = NULL;
+ break;
+ default:
+ match = early_platform_match(epdrv, match_id);
+ }
+
+ if (match) {
+ /*
+ * Set up a sensible init_name to enable
+ * dev_name() and others to be used before the
+ * rest of the driver core is initialized.
+ */
+ if (!match->dev.init_name && slab_is_available()) {
+ if (match->id != -1)
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s.%d",
+ match->name,
+ match->id);
+ else
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s",
+ match->name);
+
+ if (!match->dev.init_name)
+ return -ENOMEM;
+ }
+
+ if (epdrv->pdrv->probe(match))
+ pr_warn("%s: unable to probe %s early.\n",
+ class_str, match->name);
+ else
+ n++;
+ }
+
+ if (n >= nr_probe)
+ break;
+ }
+
+ if (left)
+ return n;
+ else
+ return -ENODEV;
+}
+
+/**
+ * early_platform_driver_probe - probe a class of registered drivers
+ * @class_str: string to identify early platform driver class
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ * @user_only: only probe user specified early platform devices
+ *
+ * Used by architecture code to probe registered early platform drivers
+ * within a certain class. For probe to happen a registered early platform
+ * device matching a registered early platform driver is needed.
+ */
+int __init early_platform_driver_probe(char *class_str,
+ int nr_probe,
+ int user_only)
+{
+ int k, n, i;
+
+ n = 0;
+ for (i = -2; n < nr_probe; i++) {
+ k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
+
+ if (k < 0)
+ break;
+
+ n += k;
+
+ if (user_only)
+ break;
+ }
+
+ return n;
+}
+
+/**
+ * early_platform_cleanup - clean up early platform code
+ */
+static int __init early_platform_cleanup(void)
+{
+ struct platform_device *pd, *pd2;
+
+ /* clean up the devres list used to chain devices */
+ list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
+ dev.devres_head) {
+ list_del(&pd->dev.devres_head);
+ memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
+ }
+
+ return 0;
+}
+/*
+ * This must happen once after all early devices are probed but before probing
+ * real platform devices.
+ */
+subsys_initcall(early_platform_cleanup);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
new file mode 100644
index 000000000000..4590ab757d5f
--- /dev/null
+++ b/arch/sh/include/asm/platform_early.h
@@ -0,0 +1,61 @@
+/* SPDX--License-Identifier: GPL-2.0 */
+
+#ifndef __PLATFORM_EARLY__
+#define __PLATFORM_EARLY__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+struct early_platform_driver {
+ const char *class_str;
+ struct platform_driver *pdrv;
+ struct list_head list;
+ int requested_id;
+ char *buffer;
+ int bufsize;
+};
+
+#define EARLY_PLATFORM_ID_UNSET -2
+#define EARLY_PLATFORM_ID_ERROR -3
+
+extern int early_platform_driver_register(struct early_platform_driver *epdrv,
+ char *buf);
+extern void early_platform_add_devices(struct platform_device **devs, int num);
+
+static inline int is_early_platform_device(struct platform_device *pdev)
+{
+ return !pdev->dev.driver;
+}
+
+extern void early_platform_driver_register_all(char *class_str);
+extern int early_platform_driver_probe(char *class_str,
+ int nr_probe, int user_only);
+
+#define early_platform_init(class_string, platdrv) \
+ early_platform_init_buffer(class_string, platdrv, NULL, 0)
+
+#ifndef MODULE
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static __initdata struct early_platform_driver early_driver = { \
+ .class_str = class_string, \
+ .buffer = buf, \
+ .bufsize = bufsiz, \
+ .pdrv = platdrv, \
+ .requested_id = EARLY_PLATFORM_ID_UNSET, \
+}; \
+static int __init early_platform_driver_setup_func(char *buffer) \
+{ \
+ return early_platform_driver_register(&early_driver, buffer); \
+} \
+early_param(class_string, early_platform_driver_setup_func)
+#else /* MODULE */
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static inline char *early_platform_driver_setup_func(void) \
+{ \
+ return bufsiz ? buf : NULL; \
+}
+#endif /* MODULE */
+
+#endif /* __PLATFORM_EARLY__ */
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index d08db08dec38..6707e92955aa 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -15,6 +15,8 @@
#include <linux/sh_eth.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index 060fdd369f09..d33568a12fad 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -12,6 +12,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index c1301f68d3cd..b258c5c3af60 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -14,6 +14,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index 32ec732e28e5..db3f8df8d76d 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -13,6 +13,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 8d8d354851ce..e1be4fedc739 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -14,6 +14,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
index ab71eab690fd..b5bed10d0d72 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
@@ -14,6 +14,7 @@
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
index c7e81b20967c..248a6732397a 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
@@ -15,6 +15,7 @@
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh3.c b/arch/sh/kernel/cpu/sh3/setup-sh3.c
index 53be70b98116..65a83ea4bde4 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh3.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh3.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
/* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index f6e392e0d27e..7ec8c11c2f7a 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -17,6 +17,7 @@
#include <linux/sh_intc.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 59a88611df55..20839dd40a2f 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -21,6 +21,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <cpu/serial.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index ea52410b430d..780ccd202bab 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -16,6 +16,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index bf34b4e2e9ef..723bd9c04c8a 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -22,6 +22,7 @@
#include <linux/sh_intc.h>
#include <linux/usb/ohci_pdriver.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
#include <cpu/serial.h>
static struct resource rtc_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 2623f820d510..4a5fa86006cd 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -15,6 +15,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 57d30689204d..abb3703c2273 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -16,6 +16,7 @@
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <generated/machtypes.h>
+#include <asm/platform_early.h>
static struct resource rtc_resources[] = {
[0] = {
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index e51fe1734e13..649f4dcb5935 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -14,6 +14,7 @@
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
enum {
UNUSED = 0,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 5788073a7c30..73715a635048 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -15,6 +15,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/clock.h>
+#include <asm/platform_early.h>
/* Serial */
static struct plat_sci_port scif0_platform_data = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 646918713d9a..942856048112 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -18,6 +18,7 @@
#include <linux/sh_intc.h>
#include <linux/usb/r8a66597.h>
#include <asm/clock.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 6b3a26e61abb..bf60456a8012 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -21,6 +21,7 @@
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <asm/siu.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
#include <cpu/sh7722.h>
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index 1c1b3c469831..d25d3c3b44ab 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/sh7723.h>
/* Serial */
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index c20258b18775..0eeadabc8065 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -27,6 +27,7 @@
#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
#include <cpu/sh7724.h>
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
index 8c0c9da6b5b3..bed9d01fa85f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/irq.h>
+#include <asm/platform_early.h>
#include <cpu/sh7734.h>
/* SCIF */
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index a46a19b49e08..b5b19e81a8dc 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -22,6 +22,7 @@
#include <linux/usb/ohci_pdriver.h>
#include <cpu/dma-register.h>
#include <cpu/sh7757.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index 40e6cda914d3..51a6c64f860e 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/serial_sci.h>
#include <linux/usb/ohci_pdriver.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 82e3bdf2e1b6..77f228e20599 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -14,6 +14,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_TOIE,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index d90ff67a4633..1e8dc7480330 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -16,6 +16,8 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <cpu/dma-register.h>
+#include <asm/platform_early.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_CKE1,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index b0d6f82f2d71..eda0d61ebf71 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -17,6 +17,7 @@
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
#include <cpu/dma-register.h>
static struct plat_sci_port scif0_platform_data = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 17aac38a6e90..77226a60c36f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -26,6 +26,7 @@
#include <linux/usb/ohci_pdriver.h>
#include <cpu/dma-register.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_REIE | SCSCR_CKE1,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index ee14d92d840f..83feaf0a4aae 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -17,6 +17,7 @@
#include <linux/sh_intc.h>
#include <cpu/shx3.h>
#include <asm/mmzone.h>
+#include <asm/platform_early.h>
/*
* This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c
index 084a9cc99175..8ebd26a9fd90 100644
--- a/arch/sh/kernel/cpu/sh5/setup-sh5.c
+++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/sh_timer.h>
#include <asm/addrspace.h>
+#include <asm/platform_early.h>
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_IOREMAP,
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index d34e998b809f..c9610a2b0888 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -44,6 +44,7 @@
#include <asm/mmu_context.h>
#include <asm/mmzone.h>
#include <asm/sparsemem.h>
+#include <asm/platform_early.h>
/*
* Initialize loops_per_jiffy as 10000000 (1000MIPS).
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index fcd5e41977d1..674d8413491b 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -21,6 +21,7 @@
#include <linux/rtc.h>
#include <asm/clock.h>
#include <asm/rtc.h>
+#include <asm/platform_early.h>
/* Dummy RTC ops */
static void null_rtc_get_time(struct timespec *tv)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 8075ddc70a17..70b156ee267a 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1150,8 +1150,6 @@ int __init platform_bus_init(void)
{
int error;
- early_platform_cleanup();
-
error = device_register(&platform_bus);
if (error) {
put_device(&platform_bus);
@@ -1185,289 +1183,3 @@ u64 dma_get_required_mask(struct device *dev)
}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
#endif
-
-static __initdata LIST_HEAD(early_platform_driver_list);
-static __initdata LIST_HEAD(early_platform_device_list);
-
-/**
- * early_platform_driver_register - register early platform driver
- * @epdrv: early_platform driver structure
- * @buf: string passed from early_param()
- *
- * Helper function for early_platform_init() / early_platform_init_buffer()
- */
-int __init early_platform_driver_register(struct early_platform_driver *epdrv,
- char *buf)
-{
- char *tmp;
- int n;
-
- /* Simply add the driver to the end of the global list.
- * Drivers will by default be put on the list in compiled-in order.
- */
- if (!epdrv->list.next) {
- INIT_LIST_HEAD(&epdrv->list);
- list_add_tail(&epdrv->list, &early_platform_driver_list);
- }
-
- /* If the user has specified device then make sure the driver
- * gets prioritized. The driver of the last device specified on
- * command line will be put first on the list.
- */
- n = strlen(epdrv->pdrv->driver.name);
- if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
- list_move(&epdrv->list, &early_platform_driver_list);
-
- /* Allow passing parameters after device name */
- if (buf[n] == '\0' || buf[n] == ',')
- epdrv->requested_id = -1;
- else {
- epdrv->requested_id = simple_strtoul(&buf[n + 1],
- &tmp, 10);
-
- if (buf[n] != '.' || (tmp == &buf[n + 1])) {
- epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
- n = 0;
- } else
- n += strcspn(&buf[n + 1], ",") + 1;
- }
-
- if (buf[n] == ',')
- n++;
-
- if (epdrv->bufsize) {
- memcpy(epdrv->buffer, &buf[n],
- min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
- epdrv->buffer[epdrv->bufsize - 1] = '\0';
- }
- }
-
- return 0;
-}
-
-/**
- * early_platform_add_devices - adds a number of early platform devices
- * @devs: array of early platform devices to add
- * @num: number of early platform devices in array
- *
- * Used by early architecture code to register early platform devices and
- * their platform data.
- */
-void __init early_platform_add_devices(struct platform_device **devs, int num)
-{
- struct device *dev;
- int i;
-
- /* simply add the devices to list */
- for (i = 0; i < num; i++) {
- dev = &devs[i]->dev;
-
- if (!dev->devres_head.next) {
- pm_runtime_early_init(dev);
- INIT_LIST_HEAD(&dev->devres_head);
- list_add_tail(&dev->devres_head,
- &early_platform_device_list);
- }
- }
-}
-
-/**
- * early_platform_driver_register_all - register early platform drivers
- * @class_str: string to identify early platform driver class
- *
- * Used by architecture code to register all early platform drivers
- * for a certain class. If omitted then only early platform drivers
- * with matching kernel command line class parameters will be registered.
- */
-void __init early_platform_driver_register_all(char *class_str)
-{
- /* The "class_str" parameter may or may not be present on the kernel
- * command line. If it is present then there may be more than one
- * matching parameter.
- *
- * Since we register our early platform drivers using early_param()
- * we need to make sure that they also get registered in the case
- * when the parameter is missing from the kernel command line.
- *
- * We use parse_early_options() to make sure the early_param() gets
- * called at least once. The early_param() may be called more than
- * once since the name of the preferred device may be specified on
- * the kernel command line. early_platform_driver_register() handles
- * this case for us.
- */
- parse_early_options(class_str);
-}
-
-/**
- * early_platform_match - find early platform device matching driver
- * @epdrv: early platform driver structure
- * @id: id to match against
- */
-static struct platform_device * __init
-early_platform_match(struct early_platform_driver *epdrv, int id)
-{
- struct platform_device *pd;
-
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
- if (platform_match(&pd->dev, &epdrv->pdrv->driver))
- if (pd->id == id)
- return pd;
-
- return NULL;
-}
-
-/**
- * early_platform_left - check if early platform driver has matching devices
- * @epdrv: early platform driver structure
- * @id: return true if id or above exists
- */
-static int __init early_platform_left(struct early_platform_driver *epdrv,
- int id)
-{
- struct platform_device *pd;
-
- list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
- if (platform_match(&pd->dev, &epdrv->pdrv->driver))
- if (pd->id >= id)
- return 1;
-
- return 0;
-}
-
-/**
- * early_platform_driver_probe_id - probe drivers matching class_str and id
- * @class_str: string to identify early platform driver class
- * @id: id to match against
- * @nr_probe: number of platform devices to successfully probe before exiting
- */
-static int __init early_platform_driver_probe_id(char *class_str,
- int id,
- int nr_probe)
-{
- struct early_platform_driver *epdrv;
- struct platform_device *match;
- int match_id;
- int n = 0;
- int left = 0;
-
- list_for_each_entry(epdrv, &early_platform_driver_list, list) {
- /* only use drivers matching our class_str */
- if (strcmp(class_str, epdrv->class_str))
- continue;
-
- if (id == -2) {
- match_id = epdrv->requested_id;
- left = 1;
-
- } else {
- match_id = id;
- left += early_platform_left(epdrv, id);
-
- /* skip requested id */
- switch (epdrv->requested_id) {
- case EARLY_PLATFORM_ID_ERROR:
- case EARLY_PLATFORM_ID_UNSET:
- break;
- default:
- if (epdrv->requested_id == id)
- match_id = EARLY_PLATFORM_ID_UNSET;
- }
- }
-
- switch (match_id) {
- case EARLY_PLATFORM_ID_ERROR:
- pr_warn("%s: unable to parse %s parameter\n",
- class_str, epdrv->pdrv->driver.name);
- /* fall-through */
- case EARLY_PLATFORM_ID_UNSET:
- match = NULL;
- break;
- default:
- match = early_platform_match(epdrv, match_id);
- }
-
- if (match) {
- /*
- * Set up a sensible init_name to enable
- * dev_name() and others to be used before the
- * rest of the driver core is initialized.
- */
- if (!match->dev.init_name && slab_is_available()) {
- if (match->id != -1)
- match->dev.init_name =
- kasprintf(GFP_KERNEL, "%s.%d",
- match->name,
- match->id);
- else
- match->dev.init_name =
- kasprintf(GFP_KERNEL, "%s",
- match->name);
-
- if (!match->dev.init_name)
- return -ENOMEM;
- }
-
- if (epdrv->pdrv->probe(match))
- pr_warn("%s: unable to probe %s early.\n",
- class_str, match->name);
- else
- n++;
- }
-
- if (n >= nr_probe)
- break;
- }
-
- if (left)
- return n;
- else
- return -ENODEV;
-}
-
-/**
- * early_platform_driver_probe - probe a class of registered drivers
- * @class_str: string to identify early platform driver class
- * @nr_probe: number of platform devices to successfully probe before exiting
- * @user_only: only probe user specified early platform devices
- *
- * Used by architecture code to probe registered early platform drivers
- * within a certain class. For probe to happen a registered early platform
- * device matching a registered early platform driver is needed.
- */
-int __init early_platform_driver_probe(char *class_str,
- int nr_probe,
- int user_only)
-{
- int k, n, i;
-
- n = 0;
- for (i = -2; n < nr_probe; i++) {
- k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
-
- if (k < 0)
- break;
-
- n += k;
-
- if (user_only)
- break;
- }
-
- return n;
-}
-
-/**
- * early_platform_cleanup - clean up early platform code
- */
-void __init early_platform_cleanup(void)
-{
- struct platform_device *pd, *pd2;
-
- /* clean up the devres list used to chain devices */
- list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
- dev.devres_head) {
- list_del(&pd->dev.devres_head);
- memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
- }
-}
-
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 53aa7e92a7d7..ad53df35bf47 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -31,6 +31,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <asm/platform_early.h>
+
struct sh_mtu2_device;
struct sh_mtu2_channel {
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 31d881621e41..25f72124b737 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -32,6 +32,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <asm/platform_early.h>
+
enum sh_tmu_model {
SH_TMU,
SH_TMU_SH3,
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index fdbbff547106..702c370c3694 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -54,6 +54,7 @@
#ifdef CONFIG_SUPERH
#include <asm/sh_bios.h>
+#include <asm/platform_early.h>
#endif
#include "serial_mctrl_gpio.h"
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 49f634d96118..099aaf804b50 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -284,58 +284,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
#define platform_register_drivers(drivers, count) \
__platform_register_drivers(drivers, count, THIS_MODULE)
-/* early platform driver interface */
-struct early_platform_driver {
- const char *class_str;
- struct platform_driver *pdrv;
- struct list_head list;
- int requested_id;
- char *buffer;
- int bufsize;
-};
-
-#define EARLY_PLATFORM_ID_UNSET -2
-#define EARLY_PLATFORM_ID_ERROR -3
-
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
- char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
-
-static inline int is_early_platform_device(struct platform_device *pdev)
-{
- return !pdev->dev.driver;
-}
-
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
- int nr_probe, int user_only);
-extern void early_platform_cleanup(void);
-
-#define early_platform_init(class_string, platdrv) \
- early_platform_init_buffer(class_string, platdrv, NULL, 0)
-
-#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = { \
- .class_str = class_string, \
- .buffer = buf, \
- .bufsize = bufsiz, \
- .pdrv = platdrv, \
- .requested_id = EARLY_PLATFORM_ID_UNSET, \
-}; \
-static int __init early_platform_driver_setup_func(char *buffer) \
-{ \
- return early_platform_driver_register(&early_driver, buffer); \
-} \
-early_param(class_string, early_platform_driver_setup_func)
-#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void) \
-{ \
- return bufsiz ? buf : NULL; \
-}
-#endif /* MODULE */
-
#ifdef CONFIG_SUSPEND
extern int platform_pm_suspend(struct device *dev);
extern int platform_pm_resume(struct device *dev);
--
2.17.0
^ permalink raw reply related
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