* [PATCH v2 10/10] MIPS: DEC: Ensure RTC platform device deregistration upon failure
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Switch RTC platform device registration from platform_device_register()
to platform_add_devices() so as to make sure any failure will result in
automatic device deregistration.
Fixes: fae67ad43114 ("arch/mips/dec: switch DECstation systems to rtc-cmos")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
No change from v1 (8/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604110042130.29980@angie.orcam.me.uk/>.
---
arch/mips/dec/platform.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
linux-mips-dec-platform-rtc-unregister.diff
Index: linux-macro/arch/mips/dec/platform.c
===================================================================
--- linux-macro.orig/arch/mips/dec/platform.c
+++ linux-macro/arch/mips/dec/platform.c
@@ -38,6 +38,10 @@ static struct platform_device dec_rtc_de
.num_resources = ARRAY_SIZE(dec_rtc_resources),
};
+static struct platform_device *dec_rtc_devices[] __initdata = {
+ &dec_rtc_device,
+};
+
static struct resource dec_dz_resources[] = {
{ .name = "dz", .flags = IORESOURCE_MEM, },
{ .name = "dz", .flags = IORESOURCE_IRQ, },
@@ -137,7 +141,7 @@ static int __init dec_add_devices(void)
}
num_zs = i;
- ret1 = platform_device_register(&dec_rtc_device);
+ ret1 = platform_add_devices(dec_rtc_devices, 1);
ret2 = IS_ENABLED(CONFIG_32BIT) ?
platform_add_devices(dec_dz_devices, num_dz) : 0;
ret3 = platform_add_devices(dec_zs_devices, num_zs);
^ permalink raw reply
* [PATCH v2 09/10] serial: dz: Enable modular build
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Enable modular build since the driver now has a proper module_exit()
handler. There's nothing specific to DZ hardware to prevent driver
unloading and reloading from working.
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
No change from v1 (7/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604130133470.29980@angie.orcam.me.uk/>.
---
drivers/tty/serial/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
linux-serial-dz-module.diff
Index: linux-macro/drivers/tty/serial/Kconfig
===================================================================
--- linux-macro.orig/drivers/tty/serial/Kconfig
+++ linux-macro/drivers/tty/serial/Kconfig
@@ -335,7 +335,7 @@ config SERIAL_MAX310X
Say Y here if you want to support this ICs.
config SERIAL_DZ
- bool "DECstation DZ serial driver"
+ tristate "DECstation DZ serial driver"
depends on MACH_DECSTATION && 32BIT
select SERIAL_CORE
default y
^ permalink raw reply
* [PATCH v2 08/10] serial: zs: Convert to use a platform device
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Prevent a crash from happening as the first serial port is initialised:
Console: switching to mono frame buffer device 160x64
fb0: PMAG-AA frame buffer device at tc0
DECstation Z85C30 serial driver version 0.10
CPU 0 Unable to handle kernel paging request at virtual address 0000002c, epc == 803ab00c, ra == 803aafe0
Oops[#1]:
CPU: 0 PID: 1 Comm: swapper Not tainted 6.4.0-rc3-00031-g84a9582fd203-dirty #57
$ 0 : 00000000 10012c00 803aaeb0 00000000
$ 4 : 80e12f60 80e12f50 80e12f58 81000030
$ 8 : 00000000 805ff37c 00000000 33433538
$12 : 65732030 00000006 80c2915d 6c616972
$16 : 80e12f00 807b7630 00000000 00000000
$20 : 00000004 00000348 000001a0 807623b8
$24 : 00000018 00000000
$28 : 80c24000 80c25d60 8078b148 803aafe0
Hi : 00000000
Lo : 00000000
epc : 803ab00c serial_base_ctrl_add+0x78/0xf4
ra : 803aafe0 serial_base_ctrl_add+0x4c/0xf4
Status: 10012c03 KERNEL EXL IE
Cause : 00000008 (ExcCode 02)
BadVA : 0000002c
PrId : 00000440 (R4400SC)
Modules linked in:
Process swapper (pid: 1, threadinfo=(ptrval), task=(ptrval), tls=00000000)
Stack : 80760000 00000cc0 00400044 00400040 803aa02c 80d61ab8 00000000 807b7630
80760000 807623b8 807b7628 803aa644 80386998 00000000 80e17780 80220f68
80e17780 80d61ab8 80c17d80 80e17780 80e17780 8063c798 80e17780 80383fa0
00000010 80e17780 00000000 80386998 807a0000 00000000 00400040 8038f848
807623b8 80d61ab8 00000004 80e17780 00000000 803a68e4 80c25e2c 803bb884
...
Call Trace:
[<803ab00c>] serial_base_ctrl_add+0x78/0xf4
[<803aa644>] serial_core_register_port+0x174/0x69c
[<8077e9ac>] zs_init+0xc8/0xfc
[<800404d4>] do_one_initcall+0x40/0x2ac
[<8076cecc>] kernel_init_freeable+0x1e4/0x270
[<80605bec>] kernel_init+0x20/0x108
[<800431e8>] ret_from_kernel_thread+0x14/0x1c
Code: 2442aeb0 ae120024 ae0200d0 <8c67002c> 50e00001 8c670000 3c06806e 3c05806e afb30010
---[ end trace 0000000000000000 ]---
(report at the offending commit) -- where a pointer is dereferenced that
has been derived from a null pointer to the port's parent device.
Since no device is available with legacy probing and it's not anymore a
preferable way to discover devices anyway, switch the driver to using a
platform device and use it as the port's parent device. Update resource
handling accordingly and only request the actual span of addresses used
within the slot, which will have had its resource already requested by
generic platform device code.
Use platform_driver_probe() not just because SCC devices are fixed with
solder on board and not straightforward to remove, but foremost because
the associated TTY's major device number is the same as used by the dz
driver and the first driver to claim it will prevent the other one from
using it. Either one DZ device or some SCC devices will be present in a
given system but never both at a time, and therefore we want the major
device number to be claimed by the first driver to actually successfully
bind to its device and platform_driver_probe() is a way to fulfil that.
An unfortunate consequence of the switch to a platform device is we now
hand the console over from the bootconsole much later in the bootstrap.
The firmware console handler appears good enough though to work so late
and in particular with interrupts enabled.
Since there is one way only remaining to reach zs_reset() now, remove
the port initialisation marker as no longer needed and go through the
channel reset unconditionally.
Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # needs to use .remove_new for <= 6.10
---
No change from v1 (6/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604110034160.29980@angie.orcam.me.uk/>.
---
arch/mips/dec/platform.c | 60 ++++++++++++++-
drivers/tty/serial/zs.c | 184 +++++++++++++++++------------------------------
drivers/tty/serial/zs.h | 1
3 files changed, 125 insertions(+), 120 deletions(-)
linux-serial-zs-platform.diff
Index: linux-macro/arch/mips/dec/platform.c
===================================================================
--- linux-macro.orig/arch/mips/dec/platform.c
+++ linux-macro/arch/mips/dec/platform.c
@@ -13,6 +13,7 @@
#include <asm/bootinfo.h>
#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/kn01.h>
#include <asm/dec/kn02.h>
#include <asm/dec/system.h>
@@ -53,10 +54,37 @@ static struct platform_device *dec_dz_de
&dec_dz_device,
};
+static struct resource dec_zs_resources[][2] = {
+ {
+ { .name = "scc0", .flags = IORESOURCE_MEM, },
+ { .name = "scc0", .flags = IORESOURCE_IRQ, },
+ },
+ {
+ { .name = "scc1", .flags = IORESOURCE_MEM, },
+ { .name = "scc1", .flags = IORESOURCE_IRQ, },
+ },
+};
+
+static struct platform_device dec_zs_device[] = {
+ {
+ .name = "zs",
+ .id = 0,
+ .resource = dec_zs_resources[0],
+ .num_resources = ARRAY_SIZE(dec_zs_resources[0]),
+ },
+ {
+ .name = "zs",
+ .id = 1,
+ .resource = dec_zs_resources[1],
+ .num_resources = ARRAY_SIZE(dec_zs_resources[1]),
+ },
+};
+
static int __init dec_add_devices(void)
{
- int ret1, ret2;
- int num_dz;
+ struct platform_device *dec_zs_devices[ARRAY_SIZE(dec_zs_device)];
+ int ret1, ret2, ret3;
+ int num_dz, num_zs;
int irq, i;
dec_rtc_resources[0].start = RTC_PORT(0);
@@ -84,10 +112,36 @@ static int __init dec_add_devices(void)
}
num_dz = i;
+ i = 0;
+ irq = dec_interrupt[DEC_IRQ_SCC0];
+ if (irq >= 0) {
+ resource_size_t base = dec_kn_slot_base + IOASIC_SCC0;
+
+ dec_zs_device[i].resource[0].start = base;
+ dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
+ dec_zs_device[i].resource[1].start = irq;
+ dec_zs_device[i].resource[1].end = irq;
+ dec_zs_devices[i] = &dec_zs_device[i];
+ i++;
+ }
+ irq = dec_interrupt[DEC_IRQ_SCC1];
+ if (irq >= 0) {
+ resource_size_t base = dec_kn_slot_base + IOASIC_SCC1;
+
+ dec_zs_device[i].resource[0].start = base;
+ dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
+ dec_zs_device[i].resource[1].start = irq;
+ dec_zs_device[i].resource[1].end = irq;
+ dec_zs_devices[i] = &dec_zs_device[i];
+ i++;
+ }
+ num_zs = i;
+
ret1 = platform_device_register(&dec_rtc_device);
ret2 = IS_ENABLED(CONFIG_32BIT) ?
platform_add_devices(dec_dz_devices, num_dz) : 0;
- return ret1 ? ret1 : ret2;
+ ret3 = platform_add_devices(dec_zs_devices, num_zs);
+ return ret1 ? ret1 : ret2 ? ret2 : ret3;
}
device_initcall(dec_add_devices);
Index: linux-macro/drivers/tty/serial/zs.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/zs.c
+++ linux-macro/drivers/tty/serial/zs.c
@@ -56,6 +56,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/major.h>
+#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/spinlock.h>
@@ -66,10 +67,6 @@
#include <linux/atomic.h>
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/system.h>
-
#include "zs.h"
@@ -79,7 +76,7 @@ MODULE_LICENSE("GPL");
static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
-static char zs_version[] __initdata = "0.10";
+static char zs_version[] __initdata = "0.11";
/*
* It would be nice to dynamically allocate everything that
@@ -98,12 +95,8 @@ static char zs_version[] __initdata = "0
#define to_zport(uport) container_of(uport, struct zs_port, port)
-struct zs_parms {
- resource_size_t scc[ZS_NUM_SCCS];
- int irq[ZS_NUM_SCCS];
-};
-
static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+static struct uart_driver zs_reg;
/*
* Set parameters in WR5, WR12, WR13 such as not to interfere
@@ -839,16 +832,15 @@ static void zs_reset(struct zs_port *zpo
spin_lock_irqsave(&scc->zlock, flags);
irq = !irqs_disabled_flags(flags);
- if (!zport->initialised) {
- /* Reset the pointer first, just in case... */
- read_zsreg(zport, R0);
- /* And let the current transmission finish. */
- zs_line_drain(zport, irq);
- write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
- udelay(10);
- write_zsreg(zport, R9, 0);
- zport->initialised = 1;
- }
+
+ /* Reset the pointer first, just in case... */
+ read_zsreg(zport, R0);
+ /* And let the current transmission finish. */
+ zs_line_drain(zport, irq);
+ write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
+ udelay(10);
+ write_zsreg(zport, R9, 0);
+
load_zsregs(zport, zport->regs, irq);
spin_unlock_irqrestore(&scc->zlock, flags);
}
@@ -1055,63 +1047,62 @@ static const struct uart_ops zs_ops = {
/*
* Initialize Z85C30 port structures.
*/
-static int __init zs_probe_sccs(void)
+static int __init zs_probe(struct platform_device *pdev)
{
- static int probed;
- struct zs_parms zs_parms;
- int chip, side, irq;
- int n_chips = 0;
+ struct resource *mem_resource, *irq_resource;
+ int chip, side;
int i;
- if (probed)
- return 0;
-
- irq = dec_interrupt[DEC_IRQ_SCC0];
- if (irq >= 0) {
- zs_parms.scc[n_chips] = IOASIC_SCC0;
- zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
- n_chips++;
- }
- irq = dec_interrupt[DEC_IRQ_SCC1];
- if (irq >= 0) {
- zs_parms.scc[n_chips] = IOASIC_SCC1;
- zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
- n_chips++;
- }
- if (!n_chips)
- return -ENXIO;
+ mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mem_resource || !irq_resource)
+ return -ENODEV;
- probed = 1;
+ chip = pdev->id;
+ spin_lock_init(&zs_sccs[chip].zlock);
+ for (side = 0; side < ZS_NUM_CHAN; side++) {
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
- for (chip = 0; chip < n_chips; chip++) {
- spin_lock_init(&zs_sccs[chip].zlock);
- for (side = 0; side < ZS_NUM_CHAN; side++) {
- struct zs_port *zport = &zs_sccs[chip].zport[side];
- struct uart_port *uport = &zport->port;
+ zport->scc = &zs_sccs[chip];
+ zport->clk_mode = 16;
- zport->scc = &zs_sccs[chip];
- zport->clk_mode = 16;
+ uport->dev = &pdev->dev;
+ uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_ZS_CONSOLE);
+ uport->irq = irq_resource->start;
+ uport->uartclk = ZS_CLOCK;
+ uport->fifosize = 1;
+ uport->iotype = UPIO_MEM;
+ uport->flags = UPF_BOOT_AUTOCONF;
+ uport->ops = &zs_ops;
+ uport->line = chip * ZS_NUM_CHAN + side;
+ uport->mapbase = mem_resource->start +
+ (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
- uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_ZS_CONSOLE);
- uport->irq = zs_parms.irq[chip];
- uport->uartclk = ZS_CLOCK;
- uport->fifosize = 1;
- uport->iotype = UPIO_MEM;
- uport->flags = UPF_BOOT_AUTOCONF;
- uport->ops = &zs_ops;
- uport->line = chip * ZS_NUM_CHAN + side;
- uport->mapbase = dec_kn_slot_base +
- zs_parms.scc[chip] +
- (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+ for (i = 0; i < ZS_NUM_REGS; i++)
+ zport->regs[i] = zs_init_regs[i];
- for (i = 0; i < ZS_NUM_REGS; i++)
- zport->regs[i] = zs_init_regs[i];
- }
+ if (uart_add_one_port(&zs_reg, uport))
+ uport->dev = NULL;
}
return 0;
}
+static void __exit zs_remove(struct platform_device *pdev)
+{
+ int chip, side;
+
+ chip = pdev->id;
+ for (side = ZS_NUM_CHAN - 1; side >= 0; side--) {
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
+
+ if (uport->dev)
+ uart_remove_one_port(&zs_reg, uport);
+ }
+}
+
#ifdef CONFIG_SERIAL_ZS_CONSOLE
static void zs_console_putchar(struct uart_port *uport, unsigned char ch)
@@ -1192,20 +1183,14 @@ static int __init zs_console_setup(struc
int bits = 8;
int parity = 'n';
int flow = 'n';
- int ret;
-
- ret = zs_map_port(uport);
- if (ret)
- return ret;
-
- zs_reset(zport);
+ if (!zport->scc)
+ return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(uport, co, baud, parity, bits, flow);
}
-static struct uart_driver zs_reg;
static struct console zs_console = {
.name = "ttyS",
.write = zs_console_write,
@@ -1216,23 +1201,6 @@ static struct console zs_console = {
.data = &zs_reg,
};
-/*
- * Register console.
- */
-static int __init zs_serial_console_init(void)
-{
- int ret;
-
- ret = zs_probe_sccs();
- if (ret)
- return ret;
- register_console(&zs_console);
-
- return 0;
-}
-
-console_initcall(zs_serial_console_init);
-
#define SERIAL_ZS_CONSOLE &zs_console
#else
#define SERIAL_ZS_CONSOLE NULL
@@ -1248,47 +1216,31 @@ static struct uart_driver zs_reg = {
.cons = SERIAL_ZS_CONSOLE,
};
+static struct platform_driver zs_driver = {
+ .remove = __exit_p(zs_remove),
+ .driver = { .name = "zs" },
+};
+
/* zs_init inits the driver. */
static int __init zs_init(void)
{
- int i, ret;
+ int ret;
pr_info("%s%s\n", zs_name, zs_version);
- /* Find out how many Z85C30 SCCs we have. */
- ret = zs_probe_sccs();
- if (ret)
- return ret;
-
ret = uart_register_driver(&zs_reg);
if (ret)
return ret;
+ ret = platform_driver_probe(&zs_driver, zs_probe);
+ if (ret)
+ uart_unregister_driver(&zs_reg);
- for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
- struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
- struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
- struct uart_port *uport = &zport->port;
-
- if (zport->scc)
- uart_add_one_port(&zs_reg, uport);
- }
-
- return 0;
+ return ret;
}
static void __exit zs_exit(void)
{
- int i;
-
- for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
- struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
- struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
- struct uart_port *uport = &zport->port;
-
- if (zport->scc)
- uart_remove_one_port(&zs_reg, uport);
- }
-
+ platform_driver_unregister(&zs_driver);
uart_unregister_driver(&zs_reg);
}
Index: linux-macro/drivers/tty/serial/zs.h
===================================================================
--- linux-macro.orig/drivers/tty/serial/zs.h
+++ linux-macro/drivers/tty/serial/zs.h
@@ -22,7 +22,6 @@
struct zs_port {
struct zs_scc *scc; /* Containing SCC. */
struct uart_port port; /* Underlying UART. */
- int initialised; /* For the console port. */
int clk_mode; /* May be 1, 16, 32, or 64. */
^ permalink raw reply
* [PATCH v2 07/10] serial: dz: Convert to use a platform device
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Prevent a crash from happening as the first serial port is initialised:
Console: switching to colour frame buffer device 160x64
tgafb: SFB+ detected, rev=0x02
fb0: Digital ZLX-E1 frame buffer device at 0x1e000000
DECstation DZ serial driver version 1.04
CPU 0 Unable to handle kernel paging request at virtual address 000000bc, epc == 8048b3a4, ra == 80470a78
Oops[#1]:
CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.19.0-dirty #35 NONE
$ 0 : 00000000 1000ac00 00000004 804707ac
$ 4 : 00000000 80e20850 80e20858 81000030
$ 8 : 00000000 8072c81c 00000008 fefefeff
$12 : 6c616972 00000006 80c5917f 69726420
$16 : 80e20800 00000000 808f8968 80e20800
$20 : 00000000 807f5a90 808b0094 808d3bc8
$24 : 00000018 80479030
$28 : 80c2e000 80c2fd70 00000069 80470a78
Hi : 00000004
Lo : 00000000
epc : 8048b3a4 __dev_fwnode+0x0/0xc
ra : 80470a78 serial_base_ctrl_add+0xa0/0x168
Status: 1000ac04 IEp
Cause : 30000008 (ExcCode 02)
BadVA : 000000bc
PrId : 00000220 (R3000)
Modules linked in:
Process swapper/0 (pid: 1, threadinfo=(ptrval), task=(ptrval), tls=00000000)
Stack : 00400044 00400040 8046f4cc 00000000 808a6148 808a0000 808f8968 8086983c
808e0000 8046fc84 1000ac01 00000028 80e20700 802ba3f8 80e20700 80d34a94
80c1b900 80e20700 80e20700 80e20700 80e20700 80444650 00000000 00000000
00000000 807f5a90 808b0094 80447080 00400040 808e0000 80d34a94 808a6148
80d34a94 00000004 80e20700 00000000 8076974c 80469810 80c2fe3c 1000ac01
...
Call Trace:
[<8048b3a4>] __dev_fwnode+0x0/0xc
[<80470a78>] serial_base_ctrl_add+0xa0/0x168
[<8046fc84>] serial_core_register_port+0x1c8/0x974
[<808c6af0>] dz_init+0x74/0xc8
[<800470e0>] do_one_initcall+0x44/0x2d4
[<808b111c>] kernel_init_freeable+0x258/0x308
[<8072e434>] kernel_init+0x20/0x114
[<80049cd0>] ret_from_kernel_thread+0x14/0x1c
Code: 27bd0018 03e00008 2402ffea <8c8200bc> 03e00008 00000000 27bdffc0 afbe0038 afb30024
---[ end trace 0000000000000000 ]---
-- where a pointer is dereferenced that has been derived from a null
pointer to the port's parent device.
Since no device is available with legacy probing and it's not anymore a
preferable way to discover devices anyway, switch the driver to using a
platform device and use it as the port's parent device. Update resource
handling accordingly and only request the actual span of addresses used
within the slot, which will have had its resource already requested by
generic platform device code.
Use platform_driver_probe() not just because the DZ device is fixed with
solder on board and not straightforward to remove, but foremost because
the associated TTY's major device number is the same as used by the zs
driver and the first driver to claim it will prevent the other one from
using it. Either one DZ device or some SCC devices will be present in a
given system but never both at a time, and therefore we want the major
device number to be claimed by the first driver to actually successfully
bind to its device and platform_driver_probe() is a way to fulfil that.
An unfortunate consequence of the switch to a platform device is we now
hand the console over from the bootconsole much later in the bootstrap.
The firmware console handler appears good enough though to work so late
and in particular with interrupts enabled.
Conversely only starting the console port so late lets the reset code
fully utilise our delay handlers, so switch from udelay() to fsleep()
for transmitter draining so as to avoid busy-waiting for an excessive
amount of time.
Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # needs to use .remove_new for <= 6.10
---
No change from v1 (5/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604102351280.29980@angie.orcam.me.uk/>.
---
arch/mips/dec/platform.c | 55 +++++++++++++++++++++-
drivers/tty/serial/dz.c | 116 ++++++++++++++++++++++-------------------------
2 files changed, 110 insertions(+), 61 deletions(-)
linux-serial-dz-platform.diff
Index: linux-macro/arch/mips/dec/platform.c
===================================================================
--- linux-macro.orig/arch/mips/dec/platform.c
+++ linux-macro/arch/mips/dec/platform.c
@@ -10,6 +10,13 @@
#include <linux/mc146818rtc.h>
#include <linux/platform_device.h>
+#include <asm/bootinfo.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/system.h>
+
static struct resource dec_rtc_resources[] = {
{
.name = "rtc",
@@ -30,11 +37,57 @@ static struct platform_device dec_rtc_de
.num_resources = ARRAY_SIZE(dec_rtc_resources),
};
+static struct resource dec_dz_resources[] = {
+ { .name = "dz", .flags = IORESOURCE_MEM, },
+ { .name = "dz", .flags = IORESOURCE_IRQ, },
+};
+
+static struct platform_device dec_dz_device = {
+ .name = "dz",
+ .id = PLATFORM_DEVID_NONE,
+ .resource = dec_dz_resources,
+ .num_resources = ARRAY_SIZE(dec_dz_resources),
+};
+
+static struct platform_device *dec_dz_devices[] __initdata = {
+ &dec_dz_device,
+};
+
static int __init dec_add_devices(void)
{
+ int ret1, ret2;
+ int num_dz;
+ int irq, i;
+
dec_rtc_resources[0].start = RTC_PORT(0);
dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;
- return platform_device_register(&dec_rtc_device);
+
+ i = 0;
+ irq = dec_interrupt[DEC_IRQ_DZ11];
+ if (IS_ENABLED(CONFIG_32BIT) && irq >= 0) {
+ resource_size_t base;
+
+ switch (mips_machtype) {
+ case MACH_DS23100:
+ case MACH_DS5100:
+ base = dec_kn_slot_base + KN01_DZ11;
+ break;
+ default:
+ base = dec_kn_slot_base + KN02_DZ11;
+ break;
+ }
+ dec_dz_device.resource[0].start = base;
+ dec_dz_device.resource[0].end = base + dec_kn_slot_size - 1;
+ dec_dz_device.resource[1].start = irq;
+ dec_dz_device.resource[1].end = irq;
+ i++;
+ }
+ num_dz = i;
+
+ ret1 = platform_device_register(&dec_rtc_device);
+ ret2 = IS_ENABLED(CONFIG_32BIT) ?
+ platform_add_devices(dec_dz_devices, num_dz) : 0;
+ return ret1 ? ret1 : ret2;
}
device_initcall(dec_add_devices);
Index: linux-macro/drivers/tty/serial/dz.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/dz.c
+++ linux-macro/drivers/tty/serial/dz.c
@@ -40,6 +40,7 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/sysrq.h>
@@ -48,14 +49,6 @@
#include <linux/atomic.h>
#include <linux/io.h>
-#include <asm/bootinfo.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/kn01.h>
-#include <asm/dec/kn02.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/system.h>
#include "dz.h"
@@ -65,7 +58,9 @@ MODULE_LICENSE("GPL");
static char dz_name[] __initdata = "DECstation DZ serial driver version ";
-static char dz_version[] __initdata = "1.04";
+static char dz_version[] __initdata = "1.05";
+
+#define DZ_IO_SIZE 0x20 /* IOMEM space size. */
struct dz_port {
struct dz_mux *mux;
@@ -81,6 +76,7 @@ struct dz_mux {
};
static struct dz_mux dz_mux;
+static struct uart_driver dz_reg;
static inline struct dz_port *to_dport(struct uart_port *uport)
{
@@ -564,7 +560,7 @@ static void dz_reset(struct dz_port *dpo
iob();
udelay(2); /* 1.4us TRDY recovery. */
}
- udelay(1200); /* Transmitter drain. */
+ fsleep(1200); /* Transmitter drain. */
}
dz_out(dport, DZ_CSR, DZ_CLR);
@@ -681,14 +677,13 @@ static void dz_release_port(struct uart_
map_guard = atomic_add_return(-1, &mux->map_guard);
if (!map_guard)
- release_mem_region(uport->mapbase, dec_kn_slot_size);
+ release_mem_region(uport->mapbase, DZ_IO_SIZE);
}
static int dz_map_port(struct uart_port *uport)
{
if (!uport->membase)
- uport->membase = ioremap(uport->mapbase,
- dec_kn_slot_size);
+ uport->membase = ioremap(uport->mapbase, DZ_IO_SIZE);
if (!uport->membase) {
printk(KERN_ERR "dz: Cannot map MMIO\n");
return -ENOMEM;
@@ -704,8 +699,7 @@ static int dz_request_port(struct uart_p
map_guard = atomic_add_return(1, &mux->map_guard);
if (map_guard == 1) {
- if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
- "dz")) {
+ if (!request_mem_region(uport->mapbase, DZ_IO_SIZE, "dz")) {
atomic_add(-1, &mux->map_guard);
printk(KERN_ERR
"dz: Unable to reserve MMIO resource\n");
@@ -716,7 +710,7 @@ static int dz_request_port(struct uart_p
if (ret) {
map_guard = atomic_add_return(-1, &mux->map_guard);
if (!map_guard)
- release_mem_region(uport->mapbase, dec_kn_slot_size);
+ release_mem_region(uport->mapbase, DZ_IO_SIZE);
return ret;
}
return 0;
@@ -768,20 +762,15 @@ static const struct uart_ops dz_ops = {
.verify_port = dz_verify_port,
};
-static void __init dz_init_ports(void)
+static int __init dz_probe(struct platform_device *pdev)
{
- static int first = 1;
- unsigned long base;
+ struct resource *mem_resource, *irq_resource;
int line;
- if (!first)
- return;
- first = 0;
-
- if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
- base = dec_kn_slot_base + KN01_DZ11;
- else
- base = dec_kn_slot_base + KN02_DZ11;
+ mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mem_resource || !irq_resource)
+ return -ENODEV;
for (line = 0; line < DZ_NB_PORT; line++) {
struct dz_port *dport = &dz_mux.dport[line];
@@ -789,14 +778,33 @@ static void __init dz_init_ports(void)
dport->mux = &dz_mux;
- uport->irq = dec_interrupt[DEC_IRQ_DZ11];
+ uport->dev = &pdev->dev;
+ uport->irq = irq_resource->start;
uport->fifosize = 1;
uport->iotype = UPIO_MEM;
uport->flags = UPF_BOOT_AUTOCONF;
uport->ops = &dz_ops;
uport->line = line;
- uport->mapbase = base;
+ uport->mapbase = mem_resource->start;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_DZ_CONSOLE);
+
+ if (uart_add_one_port(&dz_reg, uport))
+ uport->dev = NULL;
+ }
+
+ return 0;
+}
+
+static void __exit dz_remove(struct platform_device *pdev)
+{
+ int line;
+
+ for (line = DZ_NB_PORT - 1; line >= 0; line--) {
+ struct dz_port *dport = &dz_mux.dport[line];
+ struct uart_port *uport = &dport->port;
+
+ if (uport->dev)
+ uart_remove_one_port(&dz_reg, uport);
}
}
@@ -879,21 +887,14 @@ static int __init dz_console_setup(struc
int bits = 8;
int parity = 'n';
int flow = 'n';
- int ret;
-
- ret = dz_map_port(uport);
- if (ret)
- return ret;
-
- dz_reset(dport);
+ if (!dport->mux)
+ return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&dport->port, co, baud, parity, bits, flow);
+ return uart_set_options(uport, co, baud, parity, bits, flow);
}
-static struct uart_driver dz_reg;
static struct console dz_console = {
.name = "ttyS",
.write = dz_console_print,
@@ -904,18 +905,6 @@ static struct console dz_console = {
.data = &dz_reg,
};
-static int __init dz_serial_console_init(void)
-{
- if (!IOASIC) {
- dz_init_ports();
- register_console(&dz_console);
- return 0;
- } else
- return -ENXIO;
-}
-
-console_initcall(dz_serial_console_init);
-
#define SERIAL_DZ_CONSOLE &dz_console
#else
#define SERIAL_DZ_CONSOLE NULL
@@ -931,25 +920,32 @@ static struct uart_driver dz_reg = {
.cons = SERIAL_DZ_CONSOLE,
};
+static struct platform_driver dz_driver = {
+ .remove = __exit_p(dz_remove),
+ .driver = { .name = "dz" },
+};
+
static int __init dz_init(void)
{
- int ret, i;
-
- if (IOASIC)
- return -ENXIO;
+ int ret;
printk("%s%s\n", dz_name, dz_version);
- dz_init_ports();
-
ret = uart_register_driver(&dz_reg);
if (ret)
return ret;
+ ret = platform_driver_probe(&dz_driver, dz_probe);
+ if (ret)
+ uart_unregister_driver(&dz_reg);
- for (i = 0; i < DZ_NB_PORT; i++)
- uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
+ return ret;
+}
- return 0;
+static void __exit dz_exit(void)
+{
+ platform_driver_unregister(&dz_driver);
+ uart_unregister_driver(&dz_reg);
}
module_init(dz_init);
+module_exit(dz_exit);
^ permalink raw reply
* [PATCH v2 06/10] serial: zs: Switch to using channel reset
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Switch the driver to using the channel reset rather than hardware reset,
simplifying handling by removing an interference between channels that
causes the other channel to become uninitialised afterwards.
There is little difference between the two kinds of reset in terms of
register settings that result, and we initialise the whole register set
right away anyway. However this prevents a hang from happening should
the console output handler in the firmware try to access the other port
whose transmitter has been disabled and line parameters messed up.
For example this will happen if the keyboard port (port A) is chosen for
the system console, unusually but not insanely for a headless system, as
the port is wired to a standard DA-15 connector and an adapter can be
easily made. Or with the next change in place this would happen for the
regular console port (port B), since the keyboard port (port A) will be
initialised first.
Just remove the unnecessary complication then, a channel reset is good
enough. We still need the initialisation marker, now per channel rather
than per SCC, as for the console port zs_reset() will be called twice:
once early on via zs_serial_console_init() for the console setup only,
and then again via zs_config_port() as the port is associated with a TTY
device.
Fixes: 8b4a40809e53 ("zs: move to the serial subsystem")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.23+
---
No change from v1 (4/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604122134330.29980@angie.orcam.me.uk/>.
---
drivers/tty/serial/zs.c | 7 ++++---
drivers/tty/serial/zs.h | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
linux-serial-zs-reset-channel.diff
Index: linux-macro/drivers/tty/serial/zs.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/zs.c
+++ linux-macro/drivers/tty/serial/zs.c
@@ -832,21 +832,22 @@ static void zs_shutdown(struct uart_port
static void zs_reset(struct zs_port *zport)
{
+ struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
struct zs_scc *scc = zport->scc;
int irq;
unsigned long flags;
spin_lock_irqsave(&scc->zlock, flags);
irq = !irqs_disabled_flags(flags);
- if (!scc->initialised) {
+ if (!zport->initialised) {
/* Reset the pointer first, just in case... */
read_zsreg(zport, R0);
/* And let the current transmission finish. */
zs_line_drain(zport, irq);
- write_zsreg(zport, R9, FHWRES);
+ write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
udelay(10);
write_zsreg(zport, R9, 0);
- scc->initialised = 1;
+ zport->initialised = 1;
}
load_zsregs(zport, zport->regs, irq);
spin_unlock_irqrestore(&scc->zlock, flags);
Index: linux-macro/drivers/tty/serial/zs.h
===================================================================
--- linux-macro.orig/drivers/tty/serial/zs.h
+++ linux-macro/drivers/tty/serial/zs.h
@@ -22,6 +22,7 @@
struct zs_port {
struct zs_scc *scc; /* Containing SCC. */
struct uart_port port; /* Underlying UART. */
+ int initialised; /* For the console port. */
int clk_mode; /* May be 1, 16, 32, or 64. */
@@ -41,7 +42,6 @@ struct zs_scc {
struct zs_port zport[2];
spinlock_t zlock;
atomic_t irq_guard;
- int initialised;
};
#endif /* __KERNEL__ */
^ permalink raw reply
* [PATCH v2 05/10] serial: zs: Fix bootconsole handover lockup
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Calling zs_reset() in the course of setting up the serial device causes
line parameters to be reset and the transmitter disabled. We've been
lucky in that no message is usually produced to the kernel log between
this call and the later call to uart_set_options() in the course of
console setup done by zs_serial_console_init(), or the system would hang
as the console output handler in the firmware tried to access a port
whose transmitter has been disabled and line parameters messed up.
This will change with the next change to the driver, so fix zs_reset()
such that line parameters are set for 9600n8 console operation as with
the system firmware and the transmitter re-enabled after reset. This
also means zs_pm() serves no purpose anymore, so drop it.
Switch to using the channel reset rather than the hardware reset, since
this simplifies handling by removing the interfere
Fixes: 8b4a40809e53 ("zs: move to the serial subsystem")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.23+
---
No change from v1 (3/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604102346290.29980@angie.orcam.me.uk/>.
---
drivers/tty/serial/zs.c | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
linux-serial-zs-prom-console.diff
Index: linux-macro/drivers/tty/serial/zs.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/zs.c
+++ linux-macro/drivers/tty/serial/zs.c
@@ -105,18 +105,24 @@ struct zs_parms {
static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+/*
+ * Set parameters in WR5, WR12, WR13 such as not to interfere
+ * with the initial PROM-based console. Otherwise any output
+ * produced before the console handover would cause the system
+ * firmware to hang (TxENAB) or produce rubbish (Tx8, B9600).
+ */
static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
0, /* write 0 */
PAR_SPEC, /* write 1 */
0, /* write 2 */
0, /* write 3 */
X16CLK | SB1, /* write 4 */
- 0, /* write 5 */
+ Tx8 | TxENAB, /* write 5 */
0, 0, 0, /* write 6, 7, 8 */
MIE | DLC | NV, /* write 9 */
NRZ, /* write 10 */
TCBR | RCBR, /* write 11 */
- 0, 0, /* BRG time constant, write 12 + 13 */
+ 0x16, 0x00, /* BRG time constant, write 12 + 13 */
BRSRC | BRENABL, /* write 14 */
0, /* write 15 */
};
@@ -956,23 +962,6 @@ static void zs_set_termios(struct uart_p
spin_unlock_irqrestore(&scc->zlock, flags);
}
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void zs_pm(struct uart_port *uport, unsigned int state,
- unsigned int oldstate)
-{
- struct zs_port *zport = to_zport(uport);
-
- if (state < 3)
- zport->regs[5] |= TxENAB;
- else
- zport->regs[5] &= ~TxENAB;
- write_zsreg(zport, R5, zport->regs[5]);
-}
-
static const char *zs_type(struct uart_port *uport)
{
@@ -1055,7 +1044,6 @@ static const struct uart_ops zs_ops = {
.startup = zs_startup,
.shutdown = zs_shutdown,
.set_termios = zs_set_termios,
- .pm = zs_pm,
.type = zs_type,
.release_port = zs_release_port,
.request_port = zs_request_port,
@@ -1210,7 +1198,6 @@ static int __init zs_console_setup(struc
return ret;
zs_reset(zport);
- zs_pm(uport, 0, -1);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
^ permalink raw reply
* [PATCH v2 04/10] serial: dz: Fix bootconsole handover lockup
From: Maciej W. Rozycki @ 2026-05-01 23:14 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
Calling dz_reset() in the course of setting up the serial device causes
line parameters to be reset and the transmitter disabled. We've been
lucky in that no message is usually produced to the kernel log between
this call and the later call to uart_set_options() in the course of
console setup done by dz_serial_console_init(), or the system would hang
as the console output handler in the firmware tried to access a port
whose transmitter has been disabled and line parameters messed up.
This will change with the next change to the driver, so fix dz_reset()
such that line parameters are set for 9600n8 console operation as with
the system firmware and the transmitter re-enabled after reset. This
also means dz_pm() serves no purpose anymore, so drop it.
Fixes: e6ee512f5a77 ("dz.c: Resource management")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.25+
---
No change from v1 (2/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604102338300.29980@angie.orcam.me.uk/>.
---
drivers/tty/serial/dz.c | 36 ++++++++++++------------------------
1 file changed, 12 insertions(+), 24 deletions(-)
linux-serial-dz-prom-console.diff
Index: linux-macro/drivers/tty/serial/dz.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/dz.c
+++ linux-macro/drivers/tty/serial/dz.c
@@ -571,6 +571,18 @@ static void dz_reset(struct dz_port *dpo
while (dz_in(dport, DZ_CSR) & DZ_CLR);
iob();
+ /*
+ * Set parameters across all lines such as not to interfere
+ * with the initial PROM-based console. Otherwise any output
+ * produced before the console handover would cause the system
+ * firmware to produce rubbish.
+ */
+ for (int line = 0; line < DZ_NB_PORT; line++)
+ dz_out(dport, DZ_LPR, DZ_B9600 | DZ_CS8 | line);
+
+ /* Re-enable transmission for the initial PROM-based console. */
+ dz_out(dport, DZ_TCR, tcr);
+
/* Enable scanning. */
dz_out(dport, DZ_CSR, DZ_MSE);
@@ -654,26 +666,6 @@ static void dz_set_termios(struct uart_p
uart_port_unlock_irqrestore(&dport->port, flags);
}
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void dz_pm(struct uart_port *uport, unsigned int state,
- unsigned int oldstate)
-{
- struct dz_port *dport = to_dport(uport);
- unsigned long flags;
-
- uart_port_lock_irqsave(&dport->port, &flags);
- if (state < 3)
- dz_start_tx(&dport->port);
- else
- dz_stop_tx(&dport->port);
- uart_port_unlock_irqrestore(&dport->port, flags);
-}
-
-
static const char *dz_type(struct uart_port *uport)
{
return "DZ";
@@ -769,7 +761,6 @@ static const struct uart_ops dz_ops = {
.startup = dz_startup,
.shutdown = dz_shutdown,
.set_termios = dz_set_termios,
- .pm = dz_pm,
.type = dz_type,
.release_port = dz_release_port,
.request_port = dz_request_port,
@@ -894,10 +885,7 @@ static int __init dz_console_setup(struc
if (ret)
return ret;
- spin_lock_init(&dport->port.lock); /* For dz_pm(). */
-
dz_reset(dport);
- dz_pm(uport, 0, -1);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
^ permalink raw reply
* [PATCH v2 03/10] serial: dz: Fix bootconsole message clobbering at chip reset
From: Maciej W. Rozycki @ 2026-05-01 23:14 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
In the DZ interface as implemented by the DC7085 gate array the serial
transmitters are double buffered, meaning that at the time a transmitter
is ready to accept the next character there is one in the transmit shift
register still being sent to the line. Issuing a master clear at this
time causes this character to be lost, so wait an extra amount of time
sufficient for the transmit shift register to drain at 9600bps, which is
the baud rate setting used by the firmware console.
Mind the specified 1.4us TRDY recovery time in the course and continue
using iob() as the completion barrier, since the platforms involved use
a write buffer that can delay and combine writes, and reorder them with
respect to reads regardless of the MMIO locations accessed and we still
lack a platform-independent handler for that.
When called from dz_serial_console_init() this is too early for fsleep()
to work and even before lpj has been calculated and therefore the delay
is actually not sufficient for the transmitter to drain and is merely a
placeholder now. This will be addressed in a follow-up change.
Fixes: e6ee512f5a77 ("dz.c: Resource management")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.25+
---
No change from v1 (1/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604121508060.29980@angie.orcam.me.uk/>.
---
drivers/tty/serial/dz.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
linux-serial-dz-reset-drain.diff
Index: linux-macro/drivers/tty/serial/dz.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/dz.c
+++ linux-macro/drivers/tty/serial/dz.c
@@ -542,10 +542,31 @@ static int dz_encode_baud_rate(unsigned
static void dz_reset(struct dz_port *dport)
{
struct dz_mux *mux = dport->mux;
+ unsigned short tcr;
+ int loops = 10000;
if (mux->initialised)
return;
+ tcr = dz_in(dport, DZ_TCR);
+
+ /* Do not disturb any ongoing transmissions. */
+ if (dz_in(dport, DZ_CSR) & DZ_MSE) {
+ unsigned short csr, mask;
+
+ mask = tcr;
+ while ((mask & DZ_LNENB) && loops--) {
+ csr = dz_in(dport, DZ_CSR);
+ if (!(csr & DZ_TRDY))
+ continue;
+ mask &= ~(1 << ((csr & DZ_TLINE) >> 8));
+ dz_out(dport, DZ_TCR, mask);
+ iob();
+ udelay(2); /* 1.4us TRDY recovery. */
+ }
+ udelay(1200); /* Transmitter drain. */
+ }
+
dz_out(dport, DZ_CSR, DZ_CLR);
while (dz_in(dport, DZ_CSR) & DZ_CLR);
iob();
^ permalink raw reply
* [PATCH v2 02/10] MIPS: DEC: Prevent initial console buffer from landing in XKPHYS
From: Maciej W. Rozycki @ 2026-05-01 23:14 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
In 64-bit configurations calling the initial console output handler from
a kernel thread other than the initial one will result in a situation
where the stack has been placed in the XKPHYS 64-bit memory segment and
consequently so has been the buffer allocated there that is used as the
argument corresponding to the `%s' output conversion specifier for the
firmware's printf() entry point.
This 64-bit address will then be truncated by 32-bit firmware, resulting
in an attempt to access the wrong memory location, which in turn will
cause all kinds of unpredictable behaviour, such as a kernel crash:
Console: colour dummy device 160x64
Calibrating delay loop... 49.36 BogoMIPS (lpj=192512)
pid_max: default: 32768 minimum: 301
CPU 0 Unable to handle kernel paging request at virtual address 000000000203bd00, epc == ffffffffbfc08364, ra == ffffffffbfc08800
Oops[#1]:
CPU: 0 PID: 0 Comm: swapper Not tainted 5.18.0-rc2-00254-gfb649bda6f56-dirty #121
$ 0 : 0000000000000000 0000000000000001 0000000000000023 ffffffff80684ba0
$ 4 : 000000000203bd00 ffffffffbfc0f3b4 ffffffffffffffff 0000000000000073
$ 8 : 0a303d7469000000 0000000000000000 0000000000000073 ffffffffbfc0f473
$12 : 0000000000000002 0000000000000000 ffffffff80684c1c 0000000000000000
$16 : 0000000000000000 ffffffff80596dc9 0000000000000000 ffffffffbfc09240
$20 : ffffffff80684c40 ffffffffbfc0f400 000000000000002d 000000000000002b
$24 : ffffffffffffffbf 000000000203bd00
$28 : ffffffff805f0000 ffffffff80684b58 0000000000000030 ffffffffbfc08800
Hi : 0000000000000000
Lo : 0000000000000aa8
epc : ffffffffbfc08364 0xffffffffbfc08364
ra : ffffffffbfc08800 0xffffffffbfc08800
Status: 140120e2 KX SX UX KERNEL EXL
Cause : 00000008 (ExcCode 02)
BadVA : 000000000203bd00
PrId : 00000430 (R4000SC)
Modules linked in:
Process swapper (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
Stack : 0000000000000000 0000000000000000 0000000000000000 0000004d0000004d
80684cc0806a2a40 80596dc80000004d 8061000000000000 bfc0850c80684c38
0000000000000000 000000000203bd00 0000000000000000 0000000000000000
0000000000000000 00000000bfc0f3b4 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000002500000000 0000000000000000 0000000000000000 802c1a7400000000
0203bd0080596dc8 0203bd4d69000000 6c61632000000018 5f746567646e6172
6c616320625f6d6f 5f736e5f6d6f7266 206361323778302b 303d74696e726320
806a0a38806b0000 806a0a38806b0000 00000000806b0000 80683c58806b0000
...
Call Trace:
Code: a082ffff 03e00008 00601021 <80820000> 00001821 10400005 24840001 80820000 24630001
---[ end trace 0000000000000000 ]---
Kernel panic - not syncing: Fatal exception in interrupt
KN04 V2.1k (PC: 0xa0026768, SP: 0x806848e8)
>>
In this case the pointer in $4 was truncated from 0x980000000203bd00 to
0x000000000203bd00.
This may happen when no final console driver has been enabled in the
configuration and consequently the initial console continues being used
late into bootstrap or with an upcoming change that will switch the zs
driver to use a platform device, which in turn will make the console
handover happen only after other kernel threads have already been
started.
Fix the issue by making the buffer static and initdata, and therefore
placed in the CKSEG0 32-bit compatibility segment, observing that the
console output handler is called with the console lock held, implying
no need for this code to be reentrant. Add an assertion to verify the
buffer actually has been placed in a compatibility segment.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.12+
---
New change in v2.
---
arch/mips/dec/prom/console.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
linux-mips-dec-prom-console-xkphys.diff
Index: linux-macro/arch/mips/dec/prom/console.c
===================================================================
--- linux-macro.orig/arch/mips/dec/prom/console.c
+++ linux-macro/arch/mips/dec/prom/console.c
@@ -2,8 +2,9 @@
/*
* DECstation PROM-based early console support.
*
- * Copyright (C) 2004, 2007 Maciej W. Rozycki
+ * Copyright (C) 2004, 2007, 2026 Maciej W. Rozycki
*/
+#include <linux/bug.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -14,9 +15,11 @@
static void __init prom_console_write(struct console *con, const char *s,
unsigned int c)
{
- char buf[81];
+ static char buf[81] __initdata = { 0 };
unsigned int chunk = sizeof(buf) - 1;
+ BUG_ON((long)buf != (int)buf);
+
while (c > 0) {
if (chunk > c)
chunk = c;
^ permalink raw reply
* [PATCH v2 01/10] MIPS: DEC: Ensure 32-bit stack location for o32 prom_printf()
From: Maciej W. Rozycki @ 2026-05-01 23:14 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>
In 64-bit configurations calling any firmware entry points from a kernel
thread other than the initial one will result in a situation where the
stack has been placed in the XKPHYS 64-bit memory segment.
Consequently the stack pointer is no longer a 32-bit value and when the
32-bit firmware code called uses 32-bit ALU operations to manipulate the
stack pointer, the calculated result is incorrect (in fact in the 64-bit
MIPS ISA almost all 32-bit ALU operations will produce an unpredictable
result when executed on 64-bit data) and control goes astray.
This may happen when no final console driver has been enabled in the
configuration and consequently the initial console continues being used
late into bootstrap, or with an upcoming change that will switch the zs
driver to use a platform device, which in turn will make the console
handover happen only after other kernel threads have already been
started, and the kernel will hang at:
pid_max: default: 32768 minimum: 301
or somewhat later, but always before:
cblist_init_generic: Setting adjustable number of callback queues.
has been printed.
It seems that only the prom_printf() entry point is affected. Of all
the other entry points wired only rex_slot_address() and rex_gettcinfo()
are called from a kernel thread other than the initial one, specifically
kernel_init(), and they are leaf functions that do no business with the
stack, having worked with no issue ever since 64-bit support was added
for the platform back in 2002.
To address this issue then, arrange for the stack to be switched in the
o32 wrapper as required for prom_printf() only, by supplying call_o32()
with a pointer to a chunk of initdata space, which is placed in the
CKSEG0 32-bit compatibility segment, observing that prom_printf() is
only called from console output handler and therefore with the console
lock held, implying no need for this code to be reentrant.
Other firmware entry points may be called with interrupts enabled and no
lock held, and may therefore require that call_o32() be reentrant. They
trigger no issue at this point and "if it ain't broke, don't fix it," so
just leave them alone.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.12+
---
New change in v2.
---
arch/mips/dec/prom/init.c | 6 +++++-
arch/mips/include/asm/dec/prom.h | 15 +++++++++++++--
2 files changed, 18 insertions(+), 3 deletions(-)
linux-mips-dec-call-o32-stack.diff
Index: linux-macro/arch/mips/dec/prom/init.c
===================================================================
--- linux-macro.orig/arch/mips/dec/prom/init.c
+++ linux-macro/arch/mips/dec/prom/init.c
@@ -3,7 +3,7 @@
* init.c: PROM library initialisation code.
*
* Copyright (C) 1998 Harald Koerfgen
- * Copyright (C) 2002, 2004 Maciej W. Rozycki
+ * Copyright (C) 2002, 2004, 2026 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -20,6 +20,10 @@
#include <asm/dec/prom.h>
+#ifdef CONFIG_64BIT
+unsigned long o32_stk[O32_STK_SIZE] __initdata = { 0 };
+#endif
+
int (*__rex_bootinit)(void);
int (*__rex_bootread)(void);
int (*__rex_getbitmap)(memmap *);
Index: linux-macro/arch/mips/include/asm/dec/prom.h
===================================================================
--- linux-macro.orig/arch/mips/include/asm/dec/prom.h
+++ linux-macro/arch/mips/include/asm/dec/prom.h
@@ -4,7 +4,7 @@
*
* DECstation PROM interface.
*
- * Copyright (C) 2002 Maciej W. Rozycki
+ * Copyright (C) 2002, 2026 Maciej W. Rozycki
*
* Based on arch/mips/dec/prom/prom.h by the Anonymous.
*/
@@ -97,6 +97,17 @@ extern int (*__pmax_close)(int);
#ifdef CONFIG_64BIT
+#define O32_STK_SIZE 512
+extern unsigned long o32_stk[];
+
+/* Switch the stack if outside the 32-bit address space. */
+static inline unsigned long *o32_get_stk(void)
+{
+ long fp = (long)__builtin_frame_address(0);
+
+ return fp != (int)fp ? o32_stk + O32_STK_SIZE : NULL;
+}
+
/*
* On MIPS64 we have to call PROM functions via a helper
* dispatcher to accommodate ABI incompatibilities.
@@ -128,7 +139,7 @@ int __DEC_PROM_O32(_prom_printf, (int (*
#define prom_getchar() _prom_getchar(__prom_getchar, NULL)
#define prom_getenv(x) _prom_getenv(__prom_getenv, NULL, x)
-#define prom_printf(x...) _prom_printf(__prom_printf, NULL, x)
+#define prom_printf(x...) _prom_printf(__prom_printf, o32_get_stk(), x)
#else /* !CONFIG_64BIT */
^ permalink raw reply
* [PATCH v2 00/10] MIPS: DEC: Fix serial device regressions + RTC cleanup
From: Maciej W. Rozycki @ 2026-05-01 23:14 UTC (permalink / raw)
To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-mips, linux-serial, linux-serial
Hi,
This is v2 of the series, addressing fallout for 64-bit configurations
where the initial console ouutput handler that uses calls into 32-bit
firmware has to ensure no register input including the stack pointer is
outside the 32-bit range, now that the handler is now also called from
kernel threads other beyond the initial one.
Two extra introductory changes, 01/10 and 02/10 have now been added to
platform code. No modification has been made to original changes. The
original description follows, updated for patch renumbering.
Starting from commit 84a9582fd203 ("serial: core: Start managing serial
controllers to enable runtime PM") drivers for serial devices used with
the DEC platform have stopped working due to a null pointer dereference in
the serial core, which means a kernel crash at bootstrap if the relevant
driver has been enabled, as is usually the case for the system console.
This patch series addresses the issue by switching the drivers away from
legacy probing to using platform devices. A notable consequence of this
is the serial console is only switched from the bootconsole handler that
uses firmware calls over to our serial driver at the time the driver is
being properly brought up. This causes messages to be produced to the
console between the device reset and console setup, which in turn causes
the firmware still being called via the bootconsole handler to loop
forever owing to the transmitter having been disabled.
Both drivers are affected and therefore introductory changes 04/10 and
05/10 are included to fix the issue by doing a rudimentary device setup
right after reset, using parameters compatible with those used by the
firmware (9600n8). There are auxiliary changes 03/10 and 06/10 included
as well, that respectively prevent a message corruption regression from
happening at reset due to the change in timing of messages produced to the
console with the dz driver switch to the platform device, and simplify
reset handling in the zs driver by issuing a channel rather hardware
reset. Then 07/10 and 08/10 actually switch the respective drivers to use
platform devices.
A tiny update follows, 09/10, that enables modular build for the dz
driver, not to be backported as not a bug fix.
Finally 10/10 is a small cleanup for the existing RTC device, included in
the series and then last only, due to a mechanical dependency and neither
for backporting, as it only addresses a code quality issue for a failure
scenario that is not expected to trigger in reality.
See individual change descriptions for details. Verified with a 5000/200
machine for the dz driver, and with 5000/150 and 5000/260 systems for the
zs driver.
Please apply.
Previous iterations:
- v1 at: <https://lore.kernel.org/r/alpine.DEB.2.21.2604102250060.29980@angie.orcam.me.uk/>.
Maciej
^ permalink raw reply
* Re: [PATCH v2 02/15] serial: core: add uart_iotype_mmio/legacy_io helper functions
From: Andy Shevchenko @ 2026-05-01 11:48 UTC (permalink / raw)
To: Hugo Villeneuve
Cc: Greg Kroah-Hartman, Jiri Slaby, ilpo.jarvinen, linux-kernel,
linux-serial, Hugo Villeneuve
In-Reply-To: <20260430113011.fea8a6edca8d864429a63fd5@hugovil.com>
On Thu, Apr 30, 2026 at 11:30:11AM -0400, Hugo Villeneuve wrote:
> On Thu, 30 Apr 2026 17:08:25 +0200
> Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> > On Tue, Apr 28, 2026 at 01:53:48PM -0400, Hugo Villeneuve wrote:
...
> > > +bool uart_iotype_legacy_io(enum uart_iotype iotype)
> >
> > Why do we use 'legacy'? Still in use in modern CPUs...
>
> TBH I do not remember exactly where i got this, but what would you
> suggest?
>
> Maybe:
> uart_iotype_io()
Yep!
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH] serial: atmel: honor CREAD in atmel_set_termios
From: Rakesh Alasyam @ 2026-05-01 8:13 UTC (permalink / raw)
To: richard.genoud, gregkh, jirislaby
Cc: nicolas.ferre, alexandre.belloni, claudiu.beznea, linux-serial,
linux-kernel, linux-arm-kernel, Rakesh Alasyam
Ignore received characters when CREAD is cleared by adding RXRDY
to ignore_status_mask.
This replaces an existing TODO in the driver.
Signed-off-by: Rakesh Alasyam <alasyamrakesh77@gmail.com>
---
drivers/tty/serial/atmel_serial.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 5d8c1cfc1c60..5b062d8ccabe 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2184,8 +2184,8 @@ static void atmel_set_termios(struct uart_port *port,
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ATMEL_US_OVRE;
}
- /* TODO: Ignore all characters if CREAD is set.*/
-
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= ATMEL_US_RXRDY;
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v7 0/4] rust: add basic serial device bus abstractions
From: Rob Herring @ 2026-04-30 19:58 UTC (permalink / raw)
To: Markus Probst
Cc: Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Kari Argillander,
Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
Simona Vetter, linux-serial, linux-kernel, rust-for-linux,
linux-pm, driver-core, dri-devel
In-Reply-To: <20260429-rust_serdev-v7-0-0d89c791b5c8@posteo.de>
On Wed, Apr 29, 2026 at 08:21:30PM +0200, Markus Probst wrote:
> This patch series adds the serdev device bus rust abstraction into the
> kernel.
>
> This abstraction will be used by a driver,
> which targets the MCU devices in Synology devices.
>
> Kari Argillander also messaged me, stating that he wants to write a
> watchdog driver with this abstraction (needing initial device data).
>
> @Rob: Are you willing to maintain these rust abstractions yourself,
> as you are the expert on this subsystem, otherwise I would take care of
> it with a "SERIAL DEVICE BUS [RUST]" section in the MAINTAINERS file. In
> the second case, I assume you are going to pick those patches as-is into
> your tree, after they have been reviewed?
Well I can ignore the Rust part as much as I ignore the C serdev part...
Honestly, I need to find someone else to maintain all of it as I don't
really have the bandwidth. I don't think we should split it though.
And I don't have a tree for serdev. Greg picks up the serdev patches. If
the Rust folks are fine with them, then I am.
Rob
^ permalink raw reply
* Re: [PATCH v2 02/15] serial: core: add uart_iotype_mmio/legacy_io helper functions
From: Hugo Villeneuve @ 2026-04-30 15:30 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Greg Kroah-Hartman, Jiri Slaby, ilpo.jarvinen, linux-kernel,
linux-serial, Hugo Villeneuve
In-Reply-To: <afNwaUf8esqaqxUe@black.igk.intel.com>
On Thu, 30 Apr 2026 17:08:25 +0200
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Tue, Apr 28, 2026 at 01:53:48PM -0400, Hugo Villeneuve wrote:
>
> > To help simplify code that check on the io type mode of the port.
>
> ...
>
> > +bool uart_iotype_legacy_io(enum uart_iotype iotype)
>
> Why do we use 'legacy'? Still in use in modern CPUs...
TBH I do not remember exactly where i got this, but what would you
suggest?
Maybe:
uart_iotype_io()
Hugo.
^ permalink raw reply
* Re: [PATCH v2 02/15] serial: core: add uart_iotype_mmio/legacy_io helper functions
From: Andy Shevchenko @ 2026-04-30 15:08 UTC (permalink / raw)
To: Hugo Villeneuve
Cc: Greg Kroah-Hartman, Jiri Slaby, ilpo.jarvinen, linux-kernel,
linux-serial, Hugo Villeneuve
In-Reply-To: <20260428-tty-upio-v2-2-01c1857cf761@dimonoff.com>
On Tue, Apr 28, 2026 at 01:53:48PM -0400, Hugo Villeneuve wrote:
> To help simplify code that check on the io type mode of the port.
...
> +bool uart_iotype_legacy_io(enum uart_iotype iotype)
Why do we use 'legacy'? Still in use in modern CPUs...
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 05/15] serial: core: replace snprintf with more robust scnprintf
From: Andy Shevchenko @ 2026-04-30 15:07 UTC (permalink / raw)
To: Hugo Villeneuve
Cc: Greg Kroah-Hartman, Jiri Slaby, ilpo.jarvinen, linux-kernel,
linux-serial, Hugo Villeneuve
In-Reply-To: <20260428-tty-upio-v2-5-01c1857cf761@dimonoff.com>
On Tue, Apr 28, 2026 at 01:53:51PM -0400, Hugo Villeneuve wrote:
>
> Use scnprintf() so we could perhaps one day get rid of snprintf() entirely.
Ah, now I understand the approach in earlycon. Hmm... Still not sure which one
I prefer (it's not related to the contents of this patch anyway).
...
> default:
> strscpy(address, "*unknown*", sizeof(address));
Side note: This may use 2-argument strscpy().
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 08/15] serial: earlycon: use uart_iotype_*() to simplify code
From: Andy Shevchenko @ 2026-04-30 15:03 UTC (permalink / raw)
To: Hugo Villeneuve
Cc: Greg Kroah-Hartman, Jiri Slaby, ilpo.jarvinen, linux-kernel,
linux-serial, Hugo Villeneuve
In-Reply-To: <20260428-tty-upio-v2-8-01c1857cf761@dimonoff.com>
On Tue, Apr 28, 2026 at 01:53:54PM -0400, Hugo Villeneuve wrote:
> Make use of new functions uart_iotype_mmio() and uart_iotype_legacy_io()
> to simplify and improve code readability.
...
> + char address[64] = "";
TBH, I prefer two pr_info() calls as that approach
- doesn't require temporary buffer
- doesn't use heavy s*printf() on top of the existing printing
- doesn't limit the flexibility of each of the strings (64 might
become not enough in some cases, however unlikely to happen)
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [tty:tty-testing] BUILD SUCCESS a2083fd1fa7aa0ef5cd8fd92396da0de2d0654b0
From: kernel test robot @ 2026-04-30 14:42 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-serial
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
branch HEAD: a2083fd1fa7aa0ef5cd8fd92396da0de2d0654b0 serial: qcom: Unify user-visible "Qualcomm" name
elapsed time: 4137m
configs tested: 191
configs skipped: 2
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc defconfig gcc-15.2.0
arc randconfig-001 gcc-8.5.0
arc randconfig-001-20260430 gcc-8.5.0
arc randconfig-002 gcc-8.5.0
arc randconfig-002-20260430 gcc-8.5.0
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm defconfig gcc-15.2.0
arm randconfig-001 gcc-8.5.0
arm randconfig-001-20260430 gcc-8.5.0
arm randconfig-002 gcc-8.5.0
arm randconfig-002-20260430 gcc-8.5.0
arm randconfig-003 gcc-8.5.0
arm randconfig-003-20260430 gcc-8.5.0
arm randconfig-004 gcc-8.5.0
arm randconfig-004-20260430 gcc-8.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001 clang-23
arm64 randconfig-001-20260430 clang-23
arm64 randconfig-002 clang-23
arm64 randconfig-002-20260430 clang-23
arm64 randconfig-003 clang-23
arm64 randconfig-003-20260430 clang-23
arm64 randconfig-004 clang-23
arm64 randconfig-004-20260430 clang-23
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001 clang-23
csky randconfig-001-20260430 clang-23
csky randconfig-002 clang-23
csky randconfig-002-20260430 clang-23
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001-20260430 gcc-14.3.0
hexagon randconfig-002-20260430 gcc-14.3.0
i386 allmodconfig clang-20
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260430 gcc-14
i386 buildonly-randconfig-002-20260430 gcc-14
i386 buildonly-randconfig-003-20260430 gcc-14
i386 buildonly-randconfig-004-20260430 gcc-14
i386 buildonly-randconfig-005-20260430 gcc-14
i386 buildonly-randconfig-006-20260430 gcc-14
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260430 clang-20
i386 randconfig-002-20260430 clang-20
i386 randconfig-003-20260430 clang-20
i386 randconfig-004-20260430 clang-20
i386 randconfig-005-20260430 clang-20
i386 randconfig-006-20260430 clang-20
i386 randconfig-007-20260430 clang-20
i386 randconfig-011 clang-20
i386 randconfig-011-20260430 clang-20
i386 randconfig-012 clang-20
i386 randconfig-012-20260430 clang-20
i386 randconfig-013 clang-20
i386 randconfig-013-20260430 clang-20
i386 randconfig-014 clang-20
i386 randconfig-014-20260430 clang-20
i386 randconfig-015 clang-20
i386 randconfig-015-20260430 clang-20
i386 randconfig-016 clang-20
i386 randconfig-016-20260430 clang-20
i386 randconfig-017 clang-20
i386 randconfig-017-20260430 clang-20
loongarch allmodconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001-20260430 gcc-14.3.0
loongarch randconfig-002-20260430 gcc-14.3.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k defconfig clang-19
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
mips xway_defconfig clang-23
nios2 allmodconfig clang-23
nios2 allnoconfig clang-23
nios2 defconfig clang-19
nios2 randconfig-001-20260430 gcc-14.3.0
nios2 randconfig-002-20260430 gcc-14.3.0
openrisc allmodconfig clang-23
openrisc allnoconfig clang-23
openrisc defconfig gcc-15.2.0
openrisc simple_smp_defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allyesconfig clang-19
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260430 gcc-13.4.0
parisc randconfig-002-20260430 gcc-13.4.0
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc mvme5100_defconfig gcc-15.2.0
powerpc pasemi_defconfig clang-23
powerpc randconfig-001-20260430 gcc-13.4.0
powerpc randconfig-002-20260430 gcc-13.4.0
powerpc64 randconfig-001-20260430 gcc-13.4.0
powerpc64 randconfig-002-20260430 gcc-13.4.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001 clang-23
riscv randconfig-001-20260430 clang-23
riscv randconfig-002 clang-23
riscv randconfig-002-20260430 clang-23
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001 clang-23
s390 randconfig-001-20260430 clang-23
s390 randconfig-002 clang-23
s390 randconfig-002-20260430 clang-23
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allyesconfig clang-19
sh defconfig gcc-14
sh randconfig-001 clang-23
sh randconfig-001-20260430 clang-23
sh randconfig-002 clang-23
sh randconfig-002-20260430 clang-23
sh se7206_defconfig gcc-15.2.0
sparc allnoconfig clang-23
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260430 gcc-12.5.0
sparc randconfig-002-20260430 gcc-12.5.0
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260430 gcc-12.5.0
sparc64 randconfig-002-20260430 gcc-12.5.0
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260430 gcc-12.5.0
um randconfig-002-20260430 gcc-12.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260430 gcc-14
x86_64 buildonly-randconfig-002-20260430 gcc-14
x86_64 buildonly-randconfig-003-20260430 gcc-14
x86_64 buildonly-randconfig-004-20260430 gcc-14
x86_64 buildonly-randconfig-005-20260430 gcc-14
x86_64 buildonly-randconfig-006-20260430 gcc-14
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-011-20260430 clang-20
x86_64 randconfig-012-20260430 clang-20
x86_64 randconfig-013-20260430 clang-20
x86_64 randconfig-014-20260430 clang-20
x86_64 randconfig-015-20260430 clang-20
x86_64 randconfig-016-20260430 clang-20
x86_64 randconfig-071-20260430 gcc-14
x86_64 randconfig-072-20260430 gcc-14
x86_64 randconfig-073-20260430 gcc-14
x86_64 randconfig-074-20260430 gcc-14
x86_64 randconfig-075-20260430 gcc-14
x86_64 randconfig-076-20260430 gcc-14
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allyesconfig clang-23
xtensa randconfig-001-20260430 gcc-12.5.0
xtensa randconfig-002-20260430 gcc-12.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v1] serial: qcom-geni: Avoid probing debug console UART without console support
From: kernel test robot @ 2026-04-30 14:40 UTC (permalink / raw)
To: Aniket Randive, gregkh, jirislaby, linux-arm-msm, linux-kernel,
linux-serial, praveen.talari, anup.kulkarni, dmitry.baryshkov,
viken.dadhaniya
Cc: oe-kbuild-all, Aniket Randive
In-Reply-To: <20260413072501.263871-1-aniket.randive@oss.qualcomm.com>
Hi Aniket,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Aniket-Randive/serial-qcom-geni-Avoid-probing-debug-console-UART-without-console-support/20260423-150710
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260413072501.263871-1-aniket.randive%40oss.qualcomm.com
patch subject: [PATCH v1] serial: qcom-geni: Avoid probing debug console UART without console support
config: csky-randconfig-001-20260430 (https://download.01.org/0day-ci/archive/20260430/202604302204.1qhU6zO5-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604302204.1qhU6zO5-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604302204.1qhU6zO5-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/tty/serial/qcom_geni_serial.c:2011:43: warning: 'sa8255p_qcom_geni_console_data' defined but not used [-Wunused-const-variable=]
2011 | static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/tty/serial/qcom_geni_serial.c:1995:43: warning: 'qcom_geni_console_data' defined but not used [-Wunused-const-variable=]
1995 | static const struct qcom_geni_device_data qcom_geni_console_data = {
| ^~~~~~~~~~~~~~~~~~~~~~
vim +/sa8255p_qcom_geni_console_data +2011 drivers/tty/serial/qcom_geni_serial.c
c4f528795d1add Karthikeyan Ramasubramanian 2018-03-14 1994
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 @1995 static const struct qcom_geni_device_data qcom_geni_console_data = {
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 1996 .console = true,
2aaa43c7077833 Bartosz Golaszewski 2022-12-29 1997 .mode = GENI_SE_FIFO,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 1998 .resources_init = geni_serial_resource_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 1999 .set_rate = geni_serial_set_rate,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2000 .power_state = geni_serial_resource_state,
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2001 };
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2002
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2003 static const struct qcom_geni_device_data qcom_geni_uart_data = {
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2004 .console = false,
2aaa43c7077833 Bartosz Golaszewski 2022-12-29 2005 .mode = GENI_SE_DMA,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2006 .resources_init = geni_serial_resource_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2007 .set_rate = geni_serial_set_rate,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2008 .power_state = geni_serial_resource_state,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2009 };
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2010
abffd1e6c4f1c9 Praveen Talari 2025-11-10 @2011 static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2012 .console = true,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2013 .mode = GENI_SE_FIFO,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2014 .pd_data = {
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2015 .pd_flags = PD_FLAG_DEV_LINK_ON,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2016 .pd_names = (const char*[]) { "power", "perf" },
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2017 .num_pd_names = 2,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2018 },
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2019 .resources_init = geni_serial_pwr_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2020 .set_rate = geni_serial_set_level,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2021 };
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2022
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH] serial: 8250_port: recognize UPIO_AU
From: Manuel Lauss @ 2026-04-30 13:58 UTC (permalink / raw)
To: linux-serial; +Cc: Manuel Lauss
My MIPS Alchemy systems generate the following warning during
probe of the 8250 driver:
WARNING: drivers/tty/serial/8250/8250_port.c:462 at set_io_from_upio+0xfc/0x124, CPU#0: swapper/0/1
Unsupported UART type 4
[...]
[<80521d40>] set_io_from_upio+0xfc/0x124
[<80521dfc>] serial8250_set_defaults+0x94/0xe0
[<80520fb4>] serial8250_register_8250_port+0x288/0x51c
[<805214ec>] serial8250_probe+0x160/0x1e8
[<8053b5f0>] platform_probe+0x64/0x90
The least invasive fix is to recognize UPIO_AU (type 4) in set_io_from_upio()
and do nothing, since all parameters have already been set up in
8250_rt288x.c::au_platform_setup().
Run-tested on Alchemy Au1300 platform.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
drivers/tty/serial/8250/8250_port.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index af78cc02f38e..02e6cdefdbac 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -458,6 +458,8 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = io_serial_out;
break;
#endif
+ case UPIO_AU:
+ break;
default:
WARN(p->iotype != UPIO_PORT || p->iobase,
"Unsupported UART type %x\n", p->iotype);
--
2.54.0
^ permalink raw reply related
* [PATCH net-next 2/3] ppp: unify two channel structs
From: Qingfang Deng @ 2026-04-30 9:05 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Jiri Kosina, David Sterba, Greg Kroah-Hartman,
Jiri Slaby, Mitchell Blank Jr, Chas Williams, Simon Horman,
James Chapman, Qingfang Deng, Kees Cook,
Sebastian Andrzej Siewior, Taegu Ha, Guillaume Nault,
Eric Woudstra, Arnd Bergmann, Dawid Osuchowski, Breno Leitao,
linux-ppp, netdev, linux-kernel, linux-serial, linux-atm-general
In-Reply-To: <20260430090532.244758-1-qingfang.deng@linux.dev>
Historically, PPP maintained two separate structures for a channel:
'struct channel' was internal to ppp_generic.c, while 'struct ppp_channel'
was the public interface that drivers were required to embed. This
duplication was redundant and forced drivers to manage the lifecycle of
the public structure.
Unify these two structures into a single 'struct ppp_channel', which is
now internal to ppp_generic.c. Drivers now use a 'ppp_channel_conf'
structure to specify registration parameters and receive an opaque
pointer to the allocated channel.
Key changes:
- ppp_register_channel() and ppp_register_net_channel() now return
a 'struct ppp_channel *' instead of taking a pointer to a driver-
embedded structure.
- 'struct ppp_channel_ops' methods now take the driver's 'private'
pointer directly as their first argument, simplifying driver logic.
- ppp_unregister_channel() now takes the opaque pointer.
- Multilink-specific fields are unified and handled via the new
configuration structure.
This cleanup simplifies the driver interface and makes the channel
lifecycle management more robust by centralizing allocation in the PPP
generic layer.
Assisted-by: Gemini:gemini-3-flash
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
---
drivers/net/ppp/ppp_async.c | 51 +++++-----
drivers/net/ppp/ppp_generic.c | 161 +++++++++++++++----------------
drivers/net/ppp/ppp_synctty.c | 51 +++++-----
drivers/net/ppp/pppoe.c | 34 ++++---
drivers/net/ppp/pppox.c | 4 +-
drivers/net/ppp/pptp.c | 40 ++++----
drivers/tty/ipwireless/network.c | 30 +++---
include/linux/if_pppox.h | 2 +-
include/linux/ppp_channel.h | 49 ++++++----
net/atm/pppoatm.c | 61 ++++++------
net/l2tp/l2tp_ppp.c | 34 ++++---
11 files changed, 271 insertions(+), 246 deletions(-)
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index 93a7b0f6c4e7..faa299cc3db9 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -67,7 +67,7 @@ struct asyncppp {
refcount_t refcnt;
struct completion dead;
- struct ppp_channel chan; /* interface to generic ppp layer */
+ struct ppp_channel *chan; /* interface to generic ppp layer */
unsigned char obuf[OBUFSIZE];
};
@@ -95,12 +95,12 @@ MODULE_ALIAS_LDISC(N_PPP);
* Prototypes.
*/
static int ppp_async_encode(struct asyncppp *ap);
-static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);
+static int ppp_async_send(void *private, struct sk_buff *skb);
static int ppp_async_push(struct asyncppp *ap);
static void ppp_async_flush_output(struct asyncppp *ap);
static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
const u8 *flags, int count);
-static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,
+static int ppp_async_ioctl(void *private, unsigned int cmd,
unsigned long arg);
static void ppp_async_process(struct tasklet_struct *t);
@@ -155,9 +155,10 @@ static void ap_put(struct asyncppp *ap)
static int
ppp_asynctty_open(struct tty_struct *tty)
{
+ struct ppp_channel_conf conf = {};
+ struct ppp_channel *chan;
struct asyncppp *ap;
int err;
- int speed;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
@@ -185,14 +186,18 @@ ppp_asynctty_open(struct tty_struct *tty)
refcount_set(&ap->refcnt, 1);
init_completion(&ap->dead);
- ap->chan.private = ap;
- ap->chan.ops = &async_ops;
- ap->chan.mtu = PPP_MRU;
- speed = tty_get_baud_rate(tty);
- ap->chan.speed = speed;
- err = ppp_register_channel(&ap->chan);
- if (err)
+ conf.private = ap;
+ conf.ops = &async_ops;
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = PPP_MRU;
+ conf.speed = tty_get_baud_rate(tty);
+#endif
+ chan = ppp_register_channel(&conf);
+ if (!chan) {
+ err = -ENOMEM;
goto out_free;
+ }
+ ap->chan = chan;
tty->disc_data = ap;
tty->receive_room = 65536;
@@ -235,7 +240,7 @@ ppp_asynctty_close(struct tty_struct *tty)
wait_for_completion(&ap->dead);
tasklet_kill(&ap->tsk);
- ppp_unregister_channel(&ap->chan);
+ ppp_unregister_channel(ap->chan);
kfree_skb(ap->rpkt);
skb_queue_purge(&ap->rqueue);
kfree_skb(ap->tpkt);
@@ -293,14 +298,14 @@ ppp_asynctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
switch (cmd) {
case PPPIOCGCHAN:
err = -EFAULT;
- if (put_user(ppp_channel_index(&ap->chan), p))
+ if (put_user(ppp_channel_index(ap->chan), p))
break;
err = 0;
break;
case PPPIOCGUNIT:
err = -EFAULT;
- if (put_user(ppp_unit_number(&ap->chan), p))
+ if (put_user(ppp_unit_number(ap->chan), p))
break;
err = 0;
break;
@@ -391,9 +396,9 @@ ppp_async_init(void)
* The following routines provide the PPP channel interface.
*/
static int
-ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
+ppp_async_ioctl(void *private, unsigned int cmd, unsigned long arg)
{
- struct asyncppp *ap = chan->private;
+ struct asyncppp *ap = private;
void __user *argp = (void __user *)arg;
int __user *p = argp;
int err, val;
@@ -491,13 +496,13 @@ static void ppp_async_process(struct tasklet_struct *t)
/* process received packets */
while ((skb = skb_dequeue(&ap->rqueue)) != NULL) {
if (skb->cb[0])
- ppp_input_error(&ap->chan);
- ppp_input(&ap->chan, skb);
+ ppp_input_error(ap->chan);
+ ppp_input(ap->chan, skb);
}
/* try to push more stuff out */
if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap))
- ppp_output_wakeup(&ap->chan);
+ ppp_output_wakeup(ap->chan);
}
/*
@@ -620,9 +625,9 @@ ppp_async_encode(struct asyncppp *ap)
* at some later time.
*/
static int
-ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb)
+ppp_async_send(void *private, struct sk_buff *skb)
{
- struct asyncppp *ap = chan->private;
+ struct asyncppp *ap = private;
ppp_async_push(ap);
@@ -733,7 +738,7 @@ ppp_async_flush_output(struct asyncppp *ap)
}
spin_unlock_bh(&ap->xmit_lock);
if (done)
- ppp_output_wakeup(&ap->chan);
+ ppp_output_wakeup(ap->chan);
}
/*
@@ -992,7 +997,7 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
if (inbound)
ap->mru = val;
else
- ap->chan.mtu = val;
+ ppp_channel_update_mtu(ap->chan, val);
break;
case LCP_ASYNCMAP:
val = get_unaligned_be32(data + 2);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index aef42a69b63c..de59a2c44b77 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -106,7 +106,7 @@ struct ppp_file {
#define PF_TO_X(pf, X) container_of(pf, X, file)
#define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp)
-#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel)
+#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct ppp_channel)
struct ppp_xmit_recursion {
struct task_struct *owner;
@@ -172,10 +172,11 @@ struct ppp {
* Private data structure for each channel.
* This includes the data structure used for multilink.
*/
-struct channel {
+struct ppp_channel {
struct ppp_file file; /* stuff for read/write/poll */
struct list_head list; /* link in all/new_channels list */
- struct ppp_channel *chan; /* public channel data structure */
+ const struct ppp_channel_ops *ops; /* operations for this channel */
+ void *private; /* channel private data */
struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */
spinlock_t downl; /* protects `chan', file.xq dequeue */
struct ppp __rcu *ppp; /* ppp unit we're connected to */
@@ -183,11 +184,13 @@ struct channel {
netns_tracker ns_tracker;
struct list_head clist; /* link in list of channels per unit */
spinlock_t upl; /* protects `ppp' and 'bridge' */
- struct channel __rcu *bridge; /* "bridged" ppp channel */
+ struct ppp_channel __rcu *bridge; /* "bridged" ppp channel */
+ bool direct_xmit; /* no qdisc, xmit directly */
#ifdef CONFIG_PPP_MULTILINK
u8 avail; /* flag used in multilink stuff */
u8 had_frag; /* >= 1 fragments have been sent */
u32 lastseq; /* MP: last sequence # received */
+ int mtu; /* max transmit packet size */
int speed; /* speed of the corresponding ppp channel*/
#endif /* CONFIG_PPP_MULTILINK */
};
@@ -265,16 +268,16 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb);
static int ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb);
static int ppp_push(struct ppp *ppp, struct sk_buff *skb);
-static void ppp_channel_push(struct channel *pch);
+static void ppp_channel_push(struct ppp_channel *pch);
static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb,
- struct channel *pch);
+ struct ppp_channel *pch);
static void ppp_receive_error(struct ppp *ppp);
static void ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb);
static struct sk_buff *ppp_decompress_frame(struct ppp *ppp,
struct sk_buff *skb);
#ifdef CONFIG_PPP_MULTILINK
static void ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb,
- struct channel *pch);
+ struct ppp_channel *pch);
static void ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb);
static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp);
static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb);
@@ -288,10 +291,10 @@ static int ppp_create_interface(struct net *net, struct file *file, int *unit);
static void init_ppp_file(struct ppp_file *pf, int kind);
static void ppp_release_interface(struct ppp *ppp);
static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit);
-static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
-static int ppp_connect_channel(struct channel *pch, int unit);
-static int ppp_disconnect_channel(struct channel *pch);
-static void ppp_release_channel(struct channel *pch);
+static struct ppp_channel *ppp_find_channel(struct ppp_net *pn, int unit);
+static int ppp_connect_channel(struct ppp_channel *pch, int unit);
+static int ppp_disconnect_channel(struct ppp_channel *pch);
+static void ppp_release_channel(struct ppp_channel *pch);
static int unit_get(struct idr *p, void *ptr, int min);
static int unit_set(struct idr *p, void *ptr, int n);
static void unit_put(struct idr *p, int n);
@@ -638,7 +641,7 @@ static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
* Once successfully bridged, each channel holds a reference on the other
* to prevent it being freed while the bridge is extant.
*/
-static int ppp_bridge_channels(struct channel *pch, struct channel *pchb)
+static int ppp_bridge_channels(struct ppp_channel *pch, struct ppp_channel *pchb)
{
spin_lock(&pch->upl);
if (rcu_dereference_protected(pch->ppp, lockdep_is_held(&pch->upl)) ||
@@ -676,9 +679,9 @@ static int ppp_bridge_channels(struct channel *pch, struct channel *pchb)
return -EALREADY;
}
-static int ppp_unbridge_channels(struct channel *pch)
+static int ppp_unbridge_channels(struct ppp_channel *pch)
{
- struct channel *pchb, *pchbb;
+ struct ppp_channel *pchb, *pchbb;
spin_lock(&pch->upl);
pchb = rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl));
@@ -745,8 +748,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (pf->kind == CHANNEL) {
- struct channel *pch, *pchb;
- struct ppp_channel *chan;
+ struct ppp_channel *pch, *pchb;
struct ppp_net *pn;
pch = PF_TO_CHANNEL(pf);
@@ -788,10 +790,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
default:
down_read(&pch->chan_sem);
- chan = pch->chan;
err = -ENOTTY;
- if (!pch->file.dead && chan->ops->ioctl)
- err = chan->ops->ioctl(chan, cmd, arg);
+ if (!pch->file.dead && pch->ops->ioctl)
+ err = pch->ops->ioctl(pch->private, cmd, arg);
up_read(&pch->chan_sem);
}
goto out;
@@ -1044,7 +1045,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
{
int unit, err = -EFAULT;
struct ppp *ppp;
- struct channel *chan;
+ struct ppp_channel *chan;
struct ppp_net *pn;
int __user *p = (int __user *)arg;
@@ -1586,21 +1587,19 @@ static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
struct ppp *ppp = netdev_priv(ctx->dev);
- struct ppp_channel *chan;
- struct channel *pch;
+ struct ppp_channel *pch;
if (ppp->flags & SC_MULTILINK)
return -EOPNOTSUPP;
- pch = list_first_or_null_rcu(&ppp->channels, struct channel, clist);
+ pch = list_first_or_null_rcu(&ppp->channels, struct ppp_channel, clist);
if (!pch)
return -ENODEV;
- chan = pch->chan;
- if (!chan->ops->fill_forward_path)
+ if (!pch->ops->fill_forward_path)
return -EOPNOTSUPP;
- return chan->ops->fill_forward_path(ctx, path, chan);
+ return pch->ops->fill_forward_path(ctx, path, pch->private);
}
static const struct net_device_ops ppp_netdev_ops = {
@@ -1901,7 +1900,6 @@ static int
ppp_push(struct ppp *ppp, struct sk_buff *skb)
{
struct list_head *list;
- struct channel *pch;
list = &ppp->channels;
if (list_empty(list)) {
@@ -1911,15 +1909,14 @@ ppp_push(struct ppp *ppp, struct sk_buff *skb)
}
if ((ppp->flags & SC_MULTILINK) == 0) {
- struct ppp_channel *chan;
+ struct ppp_channel *pch;
int ret;
/* not doing multilink: send it down the first channel */
list = list->next;
- pch = list_entry(list, struct channel, clist);
+ pch = list_entry(list, struct ppp_channel, clist);
spin_lock(&pch->downl);
- chan = pch->chan;
- if (unlikely(!chan->direct_xmit && skb_linearize(skb))) {
+ if (unlikely(!pch->direct_xmit && skb_linearize(skb))) {
/* channel requires a linear skb but linearization
* failed
*/
@@ -1928,7 +1925,7 @@ ppp_push(struct ppp *ppp, struct sk_buff *skb)
goto out;
}
- ret = chan->ops->start_xmit(chan, skb);
+ ret = pch->ops->start_xmit(pch->private, skb);
out:
spin_unlock(&pch->downl);
@@ -1967,9 +1964,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
int totfree;
unsigned char *p, *q;
struct list_head *list;
- struct channel *pch;
+ struct ppp_channel *pch;
struct sk_buff *frag;
- struct ppp_channel *chan;
totspeed = 0; /*total bitrate of the bundle*/
nfree = 0; /* # channels which have no packet already queued */
@@ -1984,8 +1980,6 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
list_for_each_entry(pch, &ppp->channels, clist) {
pch->avail = 1;
navail++;
- pch->speed = pch->chan->speed;
-
if (skb_queue_empty(&pch->file.xq) || !pch->had_frag) {
if (pch->speed == 0)
nzero++;
@@ -2041,7 +2035,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
i = 0;
continue;
}
- pch = list_entry(list, struct channel, clist);
+ pch = list_entry(list, struct ppp_channel, clist);
++i;
if (!pch->avail)
continue;
@@ -2108,7 +2102,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
* MTU counts only the payload excluding the protocol field.
* (RFC1661 Section 2)
*/
- mtu = pch->chan->mtu - (hdrlen - 2);
+ mtu = pch->mtu - (hdrlen - 2);
if (mtu < 4)
mtu = 4;
if (flen > mtu)
@@ -2135,9 +2129,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
memcpy(q + hdrlen, p, flen);
/* try to send it down the channel */
- chan = pch->chan;
if (!skb_queue_empty(&pch->file.xq) ||
- !chan->ops->start_xmit(chan, frag))
+ !pch->ops->start_xmit(pch->private, frag))
skb_queue_tail(&pch->file.xq, frag);
pch->had_frag = 1;
p += flen;
@@ -2162,7 +2155,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
#endif /* CONFIG_PPP_MULTILINK */
/* Try to send data out on a channel */
-static void __ppp_channel_push(struct channel *pch, struct ppp *ppp)
+static void __ppp_channel_push(struct ppp_channel *pch, struct ppp *ppp)
{
struct sk_buff *skb;
@@ -2170,7 +2163,7 @@ static void __ppp_channel_push(struct channel *pch, struct ppp *ppp)
if (!pch->file.dead) {
while (!skb_queue_empty(&pch->file.xq)) {
skb = skb_dequeue(&pch->file.xq);
- if (!pch->chan->ops->start_xmit(pch->chan, skb)) {
+ if (!pch->ops->start_xmit(pch->private, skb)) {
/* put the packet back and try again later */
skb_queue_head(&pch->file.xq, skb);
break;
@@ -2192,7 +2185,7 @@ static void __ppp_channel_push(struct channel *pch, struct ppp *ppp)
}
}
-static void ppp_channel_push(struct channel *pch)
+static void ppp_channel_push(struct ppp_channel *pch)
{
struct ppp_xmit_recursion *xmit_recursion;
struct ppp *ppp;
@@ -2223,7 +2216,7 @@ struct ppp_mp_skb_parm {
#define PPP_MP_CB(skb) ((struct ppp_mp_skb_parm *)((skb)->cb))
static inline void
-ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
+ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct ppp_channel *pch)
{
ppp_recv_lock(ppp);
if (!ppp->closing)
@@ -2278,9 +2271,9 @@ static bool ppp_decompress_proto(struct sk_buff *skb)
* If not, the caller must handle the frame by normal recv mechanisms.
* Returns true if the frame is consumed, false otherwise.
*/
-static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
+static bool ppp_channel_bridge_input(struct ppp_channel *pch, struct sk_buff *skb)
{
- struct channel *pchb;
+ struct ppp_channel *pchb;
rcu_read_lock();
pchb = rcu_dereference(pch->bridge);
@@ -2295,7 +2288,7 @@ static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
}
skb_scrub_packet(skb, !net_eq(pch->chan_net, pchb->chan_net));
- if (!pchb->chan->ops->start_xmit(pchb->chan, skb))
+ if (!pchb->ops->start_xmit(pchb->private, skb))
kfree_skb(skb);
outl:
@@ -2308,9 +2301,8 @@ static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
}
void
-ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
+ppp_input(struct ppp_channel *pch, struct sk_buff *skb)
{
- struct channel *pch = chan->ppp;
struct ppp *ppp;
int proto;
@@ -2352,9 +2344,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
}
void
-ppp_input_error(struct ppp_channel *chan)
+ppp_input_error(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
struct ppp *ppp;
if (!pch)
@@ -2375,7 +2366,7 @@ ppp_input_error(struct ppp_channel *chan)
* The receive side of the ppp unit is locked.
*/
static void
-ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
+ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct ppp_channel *pch)
{
skb_checksum_complete_unset(skb);
#ifdef CONFIG_PPP_MULTILINK
@@ -2611,10 +2602,10 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
* as many completed frames as we can.
*/
static void
-ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
+ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct ppp_channel *pch)
{
u32 mask, seq;
- struct channel *ch;
+ struct ppp_channel *ch;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
@@ -2885,6 +2876,13 @@ ppp_mp_reconstruct(struct ppp *ppp)
return skb;
}
+
+/* Update the MTU of a multilink channel */
+void ppp_channel_update_mtu(struct ppp_channel *pch, int mtu)
+{
+ pch->mtu = mtu;
+}
+EXPORT_SYMBOL(ppp_channel_update_mtu);
#endif /* CONFIG_PPP_MULTILINK */
/*
@@ -2892,29 +2890,33 @@ ppp_mp_reconstruct(struct ppp *ppp)
*/
/* Create a new, unattached ppp channel. */
-int ppp_register_channel(struct ppp_channel *chan)
+struct ppp_channel *ppp_register_channel(const struct ppp_channel_conf *conf)
{
- return ppp_register_net_channel(current->nsproxy->net_ns, chan);
+ return ppp_register_net_channel(current->nsproxy->net_ns, conf);
}
/* Create a new, unattached ppp channel for specified net. */
-int ppp_register_net_channel(struct net *net, struct ppp_channel *chan)
+struct ppp_channel *ppp_register_net_channel(struct net *net,
+ const struct ppp_channel_conf *conf)
{
- struct channel *pch;
+ struct ppp_channel *pch;
struct ppp_net *pn;
- pch = kzalloc_obj(struct channel);
+ pch = kzalloc_obj(struct ppp_channel);
if (!pch)
- return -ENOMEM;
+ return NULL;
pn = ppp_pernet(net);
- pch->chan = chan;
pch->chan_net = get_net_track(net, &pch->ns_tracker, GFP_KERNEL);
- chan->ppp = pch;
init_ppp_file(&pch->file, CHANNEL);
- pch->file.hdrlen = chan->hdrlen;
+ pch->file.hdrlen = conf->hdrlen;
+ pch->ops = conf->ops;
+ pch->private = conf->private;
+ pch->direct_xmit = conf->direct_xmit;
#ifdef CONFIG_PPP_MULTILINK
+ pch->speed = conf->speed;
+ pch->mtu = conf->mtu;
pch->lastseq = -1;
#endif /* CONFIG_PPP_MULTILINK */
init_rwsem(&pch->chan_sem);
@@ -2927,16 +2929,14 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan)
atomic_inc(&channel_count);
spin_unlock_bh(&pn->all_channels_lock);
- return 0;
+ return pch;
}
/*
* Return the index of a channel.
*/
-int ppp_channel_index(struct ppp_channel *chan)
+int ppp_channel_index(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
-
if (pch)
return pch->file.index;
return -1;
@@ -2945,9 +2945,8 @@ int ppp_channel_index(struct ppp_channel *chan)
/*
* Return the PPP unit number to which a channel is connected.
*/
-int ppp_unit_number(struct ppp_channel *chan)
+int ppp_unit_number(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
struct ppp *ppp;
int unit = -1;
@@ -2965,9 +2964,8 @@ int ppp_unit_number(struct ppp_channel *chan)
* Return the PPP device interface name of a channel.
* Caller must hold RCU read lock.
*/
-char *ppp_dev_name(struct ppp_channel *chan)
+char *ppp_dev_name(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
char *name = NULL;
struct ppp *ppp;
@@ -2985,16 +2983,13 @@ char *ppp_dev_name(struct ppp_channel *chan)
* This must be called in process context.
*/
void
-ppp_unregister_channel(struct ppp_channel *chan)
+ppp_unregister_channel(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
struct ppp_net *pn;
if (!pch)
return; /* should never happen */
- chan->ppp = NULL;
-
/*
* This ensures that we have returned from any calls into
* the channel's start_xmit or ioctl routine before we proceed.
@@ -3023,10 +3018,8 @@ ppp_unregister_channel(struct ppp_channel *chan)
* This should be called at BH/softirq level, not interrupt level.
*/
void
-ppp_output_wakeup(struct ppp_channel *chan)
+ppp_output_wakeup(struct ppp_channel *pch)
{
- struct channel *pch = chan->ppp;
-
if (!pch)
return;
ppp_channel_push(pch);
@@ -3459,10 +3452,10 @@ ppp_find_unit(struct ppp_net *pn, int unit)
* we move it to the all_channels list. This is for speed
* when we have a lot of channels in use.
*/
-static struct channel *
+static struct ppp_channel *
ppp_find_channel(struct ppp_net *pn, int unit)
{
- struct channel *pch;
+ struct ppp_channel *pch;
list_for_each_entry(pch, &pn->new_channels, list) {
if (pch->file.index == unit) {
@@ -3483,7 +3476,7 @@ ppp_find_channel(struct ppp_net *pn, int unit)
* Connect a PPP channel to a PPP interface unit.
*/
static int
-ppp_connect_channel(struct channel *pch, int unit)
+ppp_connect_channel(struct ppp_channel *pch, int unit)
{
struct ppp *ppp;
struct ppp_net *pn;
@@ -3511,7 +3504,7 @@ ppp_connect_channel(struct channel *pch, int unit)
ret = -ENOTCONN;
goto outl;
}
- if (pch->chan->direct_xmit)
+ if (pch->direct_xmit)
ppp->dev->priv_flags |= IFF_NO_QUEUE;
else
ppp->dev->priv_flags &= ~IFF_NO_QUEUE;
@@ -3539,7 +3532,7 @@ ppp_connect_channel(struct channel *pch, int unit)
* Disconnect a channel from its ppp unit.
*/
static int
-ppp_disconnect_channel(struct channel *pch)
+ppp_disconnect_channel(struct ppp_channel *pch)
{
struct ppp *ppp;
int err = -EINVAL;
@@ -3565,7 +3558,7 @@ ppp_disconnect_channel(struct channel *pch)
* Drop a reference to a ppp channel and free its memory if the refcount reaches
* zero.
*/
-static void ppp_release_channel(struct channel *pch)
+static void ppp_release_channel(struct ppp_channel *pch)
{
if (!refcount_dec_and_test(&pch->file.refcnt))
return;
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index b7f243b416f8..d84c267f4da1 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -71,7 +71,7 @@ struct syncppp {
refcount_t refcnt;
struct completion dead_cmp;
- struct ppp_channel chan; /* interface to generic ppp layer */
+ struct ppp_channel *chan; /* interface to generic ppp layer */
};
/* Bit numbers in xmit_flags */
@@ -87,8 +87,8 @@ struct syncppp {
* Prototypes.
*/
static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *);
-static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb);
-static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd,
+static int ppp_sync_send(void *private, struct sk_buff *skb);
+static int ppp_sync_ioctl(void *private, unsigned int cmd,
unsigned long arg);
static void ppp_sync_process(struct tasklet_struct *t);
static int ppp_sync_push(struct syncppp *ap);
@@ -155,9 +155,10 @@ static void sp_put(struct syncppp *ap)
static int
ppp_sync_open(struct tty_struct *tty)
{
+ struct ppp_channel_conf conf = {};
+ struct ppp_channel *chan;
struct syncppp *ap;
int err;
- int speed;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
@@ -182,15 +183,19 @@ ppp_sync_open(struct tty_struct *tty)
refcount_set(&ap->refcnt, 1);
init_completion(&ap->dead_cmp);
- ap->chan.private = ap;
- ap->chan.ops = &sync_ops;
- ap->chan.mtu = PPP_MRU;
- ap->chan.hdrlen = 2; /* for A/C bytes */
- speed = tty_get_baud_rate(tty);
- ap->chan.speed = speed;
- err = ppp_register_channel(&ap->chan);
- if (err)
+ conf.private = ap;
+ conf.ops = &sync_ops;
+ conf.hdrlen = 2; /* for A/C bytes */
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = PPP_MRU;
+ conf.speed = tty_get_baud_rate(tty);
+#endif
+ chan = ppp_register_channel(&conf);
+ if (!chan) {
+ err = -ENOMEM;
goto out_free;
+ }
+ ap->chan = chan;
tty->disc_data = ap;
tty->receive_room = 65536;
@@ -233,7 +238,7 @@ ppp_sync_close(struct tty_struct *tty)
wait_for_completion(&ap->dead_cmp);
tasklet_kill(&ap->tsk);
- ppp_unregister_channel(&ap->chan);
+ ppp_unregister_channel(ap->chan);
skb_queue_purge(&ap->rqueue);
kfree_skb(ap->tpkt);
kfree(ap);
@@ -285,14 +290,14 @@ ppp_synctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
switch (cmd) {
case PPPIOCGCHAN:
err = -EFAULT;
- if (put_user(ppp_channel_index(&ap->chan), p))
+ if (put_user(ppp_channel_index(ap->chan), p))
break;
err = 0;
break;
case PPPIOCGUNIT:
err = -EFAULT;
- if (put_user(ppp_unit_number(&ap->chan), p))
+ if (put_user(ppp_unit_number(ap->chan), p))
break;
err = 0;
break;
@@ -383,9 +388,9 @@ ppp_sync_init(void)
* The following routines provide the PPP channel interface.
*/
static int
-ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
+ppp_sync_ioctl(void *private, unsigned int cmd, unsigned long arg)
{
- struct syncppp *ap = chan->private;
+ struct syncppp *ap = private;
int err, val;
u32 accm[8];
void __user *argp = (void __user *)arg;
@@ -483,16 +488,16 @@ static void ppp_sync_process(struct tasklet_struct *t)
while ((skb = skb_dequeue(&ap->rqueue)) != NULL) {
if (skb->len == 0) {
/* zero length buffers indicate error */
- ppp_input_error(&ap->chan);
+ ppp_input_error(ap->chan);
kfree_skb(skb);
}
else
- ppp_input(&ap->chan, skb);
+ ppp_input(ap->chan, skb);
}
/* try to push more stuff out */
if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_sync_push(ap))
- ppp_output_wakeup(&ap->chan);
+ ppp_output_wakeup(ap->chan);
}
/*
@@ -562,9 +567,9 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
* at some later time.
*/
static int
-ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb)
+ppp_sync_send(void *private, struct sk_buff *skb)
{
- struct syncppp *ap = chan->private;
+ struct syncppp *ap = private;
ppp_sync_push(ap);
@@ -649,7 +654,7 @@ ppp_sync_flush_output(struct syncppp *ap)
}
spin_unlock_bh(&ap->xmit_lock);
if (done)
- ppp_output_wakeup(&ap->chan);
+ ppp_output_wakeup(ap->chan);
}
/*
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index bdd61c504a1c..3c08cf6de705 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -357,7 +357,7 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
*/
if (sk->sk_state & PPPOX_BOUND) {
- ppp_input(&po->chan, skb);
+ ppp_input(po->chan, skb);
} else {
if (sock_queue_rcv_skb(sk, skb))
goto abort_kfree;
@@ -631,7 +631,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
po->pppoe_ifindex = 0;
memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa));
- memset(&po->chan, 0, sizeof(po->chan));
+ po->chan = NULL;
po->next = NULL;
po->num = 0;
@@ -640,6 +640,9 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
/* Re-bind in session stage only */
if (stage_session(sp->sa_addr.pppoe.sid)) {
+ struct ppp_channel_conf conf = {};
+ struct ppp_channel *chan;
+
error = -ENODEV;
net = sock_net(sk);
dev = dev_get_by_name(net, sp->sa_addr.pppoe.dev);
@@ -663,20 +666,23 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
if (error < 0)
goto err_put;
- po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
+ conf.hdrlen = (sizeof(struct pppoe_hdr) +
dev->hard_header_len);
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
+#endif
+ conf.private = sk;
+ conf.ops = &pppoe_chan_ops;
+ conf.direct_xmit = true;
- po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
- po->chan.private = sk;
- po->chan.ops = &pppoe_chan_ops;
- po->chan.direct_xmit = true;
-
- error = ppp_register_net_channel(dev_net(dev), &po->chan);
- if (error) {
+ chan = ppp_register_net_channel(dev_net(dev), &conf);
+ if (!chan) {
+ error = -ENOMEM;
delete_item(pn, po->pppoe_pa.sid,
po->pppoe_pa.remote, po->pppoe_ifindex);
goto err_put;
}
+ po->chan = chan;
sk->sk_state = PPPOX_CONNECTED;
}
@@ -897,17 +903,17 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
* sends PPP frame over PPPoE socket
*
***********************************************************************/
-static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+static int pppoe_xmit(void *private, struct sk_buff *skb)
{
- struct sock *sk = chan->private;
+ struct sock *sk = private;
return __pppoe_xmit(sk, skb);
}
static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path,
- const struct ppp_channel *chan)
+ void *private)
{
- struct sock *sk = chan->private;
+ struct sock *sk = private;
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c
index 5861a2f6ce3e..df4fb23a926d 100644
--- a/drivers/net/ppp/pppox.c
+++ b/drivers/net/ppp/pppox.c
@@ -55,7 +55,7 @@ void pppox_unbind_sock(struct sock *sk)
/* Clear connection to ppp device, if attached. */
if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED)) {
- ppp_unregister_channel(&pppox_sk(sk)->chan);
+ ppp_unregister_channel(pppox_sk(sk)->chan);
sk->sk_state = PPPOX_DEAD;
}
}
@@ -80,7 +80,7 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
rc = -EINVAL;
- index = ppp_channel_index(&po->chan);
+ index = ppp_channel_index(po->chan);
if (put_user(index , (int __user *) arg))
break;
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index cc8c102122d8..e49abbe63bf1 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -146,9 +146,9 @@ static struct rtable *pptp_route_output(const struct pppox_sock *po,
return ip_route_output_flow(net, fl4, sk);
}
-static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+static int pptp_xmit(void *private, struct sk_buff *skb)
{
- struct sock *sk = chan->private;
+ struct sock *sk = private;
struct pppox_sock *po = pppox_sk(sk);
struct net *net = sock_net(sk);
struct pptp_opt *opt = &po->proto.pptp;
@@ -338,7 +338,7 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
skb->ip_summed = CHECKSUM_NONE;
skb_set_network_header(skb, skb->head-skb->data);
- ppp_input(&po->chan, skb);
+ ppp_input(po->chan, skb);
return NET_RX_SUCCESS;
}
@@ -422,6 +422,8 @@ static int pptp_connect(struct socket *sock, struct sockaddr_unsized *uservaddr,
struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
+ struct ppp_channel_conf conf = {};
+ struct ppp_channel *chan;
struct rtable *rt;
struct flowi4 fl4;
int error = 0;
@@ -453,9 +455,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr_unsized *uservaddr,
goto end;
}
- po->chan.private = sk;
- po->chan.ops = &pptp_chan_ops;
-
rt = pptp_route_output(po, &fl4);
if (IS_ERR(rt)) {
error = -EHOSTUNREACH;
@@ -463,18 +462,23 @@ static int pptp_connect(struct socket *sock, struct sockaddr_unsized *uservaddr,
}
sk_setup_caps(sk, &rt->dst);
- po->chan.mtu = dst_mtu(&rt->dst);
- if (!po->chan.mtu)
- po->chan.mtu = PPP_MRU;
- po->chan.mtu -= PPTP_HEADER_OVERHEAD;
-
- po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
- po->chan.direct_xmit = true;
- error = ppp_register_channel(&po->chan);
- if (error) {
+ conf.private = sk;
+ conf.ops = &pptp_chan_ops;
+ conf.hdrlen = 2 + sizeof(struct pptp_gre_header);
+ conf.direct_xmit = true;
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = dst_mtu(&rt->dst);
+ if (!conf.mtu)
+ conf.mtu = PPP_MRU;
+ conf.mtu -= PPTP_HEADER_OVERHEAD;
+#endif
+ chan = ppp_register_channel(&conf);
+ if (!chan) {
+ error = -ENOMEM;
pr_err("PPTP: failed to register PPP channel (%d)\n", error);
goto end;
}
+ po->chan = chan;
opt->dst_addr = sp->sa_addr.pptp;
sk->sk_state |= PPPOX_CONNECTED;
@@ -577,10 +581,10 @@ static int pptp_create(struct net *net, struct socket *sock, int kern)
return error;
}
-static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
- unsigned long arg)
+static int pptp_ppp_ioctl(void *private, unsigned int cmd,
+ unsigned long arg)
{
- struct sock *sk = chan->private;
+ struct sock *sk = private;
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
void __user *argp = (void __user *)arg;
diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c
index ad2c5157a018..7ac5a2d02d44 100644
--- a/drivers/tty/ipwireless/network.c
+++ b/drivers/tty/ipwireless/network.c
@@ -88,10 +88,10 @@ static void notify_packet_sent(void *callback_data, unsigned int packet_length)
/*
* Called by the ppp system when it has a packet to send to the hardware.
*/
-static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
+static int ipwireless_ppp_start_xmit(void *private,
struct sk_buff *skb)
{
- struct ipw_network *network = ppp_channel->private;
+ struct ipw_network *network = private;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
@@ -153,10 +153,10 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
}
/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */
-static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,
+static int ipwireless_ppp_ioctl(void *private,
unsigned int cmd, unsigned long arg)
{
- struct ipw_network *network = ppp_channel->private;
+ struct ipw_network *network = private;
int err, val;
u32 accm[8];
int __user *user_arg = (int __user *) arg;
@@ -254,19 +254,17 @@ static void do_go_online(struct work_struct *work_go_online)
spin_lock_irqsave(&network->lock, flags);
if (!network->ppp_channel) {
+ struct ppp_channel_conf conf = {};
struct ppp_channel *channel;
spin_unlock_irqrestore(&network->lock, flags);
- channel = kzalloc_obj(struct ppp_channel);
- if (!channel) {
- printk(KERN_ERR IPWIRELESS_PCCARD_NAME
- ": unable to allocate PPP channel\n");
- return;
- }
- channel->private = network;
- channel->mtu = 16384; /* Wild guess */
- channel->hdrlen = 2;
- channel->ops = &ipwireless_ppp_channel_ops;
+
+ conf.private = network;
+ conf.hdrlen = 2;
+ conf.ops = &ipwireless_ppp_channel_ops;
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = 16384; /* Wild guess */
+#endif
network->flags = 0;
network->rbits = 0;
@@ -275,10 +273,10 @@ static void do_go_online(struct work_struct *work_go_online)
network->xaccm[0] = ~0U;
network->xaccm[3] = 0x60000000U;
network->raccm = ~0U;
- if (ppp_register_channel(channel) < 0) {
+ channel = ppp_register_channel(&conf);
+ if (!channel) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": unable to register PPP channel\n");
- kfree(channel);
return;
}
spin_lock_irqsave(&network->lock, flags);
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 594d6dc3f4c9..a1d7c11182ec 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -40,7 +40,7 @@ struct pptp_opt {
struct pppox_sock {
/* struct sock must be the first member of pppox_sock */
struct sock sk;
- struct ppp_channel chan;
+ struct ppp_channel *chan;
struct pppox_sock __rcu *next; /* for hash table */
union {
struct pppoe_opt pppoe;
diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h
index 2f63e9a6cc88..05f850e6b696 100644
--- a/include/linux/ppp_channel.h
+++ b/include/linux/ppp_channel.h
@@ -27,55 +27,64 @@ struct ppp_channel;
struct ppp_channel_ops {
/* Send a packet (or multilink fragment) on this channel.
Returns 1 if it was accepted, 0 if not. */
- int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
+ int (*start_xmit)(void *private, struct sk_buff *skb);
/* Handle an ioctl call that has come in via /dev/ppp. */
- int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
- int (*fill_forward_path)(struct net_device_path_ctx *,
- struct net_device_path *,
- const struct ppp_channel *);
+ int (*ioctl)(void *private, unsigned int cmd, unsigned long arg);
+ int (*fill_forward_path)(struct net_device_path_ctx *ctx,
+ struct net_device_path *path,
+ void *private);
};
-struct ppp_channel {
+struct ppp_channel_conf {
void *private; /* channel private data */
const struct ppp_channel_ops *ops; /* operations for this channel */
- int mtu; /* max transmit packet size */
int hdrlen; /* amount of headroom channel needs */
- void *ppp; /* opaque to channel */
- int speed; /* transfer rate (bytes/second) */
bool direct_xmit; /* no qdisc, xmit directly */
+#ifdef CONFIG_PPP_MULTILINK
+ int speed; /* transfer rate (bytes/second) */
+ int mtu; /* max transmit packet size */
+#endif
};
#ifdef __KERNEL__
/* Called by the channel when it can send some more data. */
-extern void ppp_output_wakeup(struct ppp_channel *);
+void ppp_output_wakeup(struct ppp_channel *pch);
/* Called by the channel to process a received PPP packet.
The packet should have just the 2-byte PPP protocol header. */
-extern void ppp_input(struct ppp_channel *, struct sk_buff *);
+void ppp_input(struct ppp_channel *pch, struct sk_buff *skb);
/* Called by the channel when an input error occurs, indicating
that we may have missed a packet. */
-extern void ppp_input_error(struct ppp_channel *);
+void ppp_input_error(struct ppp_channel *pch);
-/* Attach a channel to a given PPP unit in specified net. */
-extern int ppp_register_net_channel(struct net *, struct ppp_channel *);
+/* Create a new, unattached ppp channel for specified net. */
+struct ppp_channel *ppp_register_net_channel(struct net *net,
+ const struct ppp_channel_conf *chan);
-/* Attach a channel to a given PPP unit. */
-extern int ppp_register_channel(struct ppp_channel *);
+/* Create a new, unattached ppp channel. */
+struct ppp_channel *ppp_register_channel(const struct ppp_channel_conf *chan);
/* Detach a channel from its PPP unit (e.g. on hangup). */
-extern void ppp_unregister_channel(struct ppp_channel *);
+void ppp_unregister_channel(struct ppp_channel *pch);
/* Get the channel number for a channel */
-extern int ppp_channel_index(struct ppp_channel *);
+int ppp_channel_index(struct ppp_channel *pch);
/* Get the unit number associated with a channel, or -1 if none */
-extern int ppp_unit_number(struct ppp_channel *);
+int ppp_unit_number(struct ppp_channel *pch);
/* Get the device name associated with a channel, or NULL if none.
* Caller must hold RCU read lock.
*/
-extern char *ppp_dev_name(struct ppp_channel *);
+char *ppp_dev_name(struct ppp_channel *pch);
+
+/* Update the MTU of a multilink channel */
+#ifdef CONFIG_PPP_MULTILINK
+void ppp_channel_update_mtu(struct ppp_channel *pch, int mtu);
+#else
+static inline void ppp_channel_update_mtu(struct ppp_channel *pch, int mtu) {}
+#endif
/*
* SMP locking notes:
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index e3c422dc533a..d801233700e7 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -64,7 +64,7 @@ struct pppoatm_vcc {
atomic_t inflight;
unsigned long blocked;
int flags; /* SC_COMP_PROT - compress protocol */
- struct ppp_channel chan; /* interface to generic ppp layer */
+ struct ppp_channel *chan; /* interface to generic ppp layer */
struct tasklet_struct wakeup_tasklet;
};
@@ -91,11 +91,6 @@ static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc)
return (struct pppoatm_vcc *) (atmvcc->user_back);
}
-static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan)
-{
- return (struct pppoatm_vcc *) (chan->private);
-}
-
/*
* We can't do this directly from our _pop handler, since the ppp code
* doesn't want to be called in interrupt context, so we do it from
@@ -105,7 +100,7 @@ static void pppoatm_wakeup_sender(struct tasklet_struct *t)
{
struct pppoatm_vcc *pvcc = from_tasklet(pvcc, t, wakeup_tasklet);
- ppp_output_wakeup(&pvcc->chan);
+ ppp_output_wakeup(pvcc->chan);
}
static void pppoatm_release_cb(struct atm_vcc *atmvcc)
@@ -172,7 +167,7 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
atmvcc->pop = pvcc->old_pop;
atmvcc->release_cb = pvcc->old_release_cb;
tasklet_kill(&pvcc->wakeup_tasklet);
- ppp_unregister_channel(&pvcc->chan);
+ ppp_unregister_channel(pvcc->chan);
atmvcc->user_back = NULL;
kfree(pvcc);
}
@@ -201,7 +196,7 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
skb_pull(skb, LLC_LEN);
break;
case e_autodetect:
- if (pvcc->chan.ppp == NULL) { /* Not bound yet! */
+ if (!pvcc->chan) { /* Not bound yet! */
kfree_skb(skb);
return;
}
@@ -215,7 +210,8 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
!memcmp(skb->data, &pppllc[LLC_LEN],
sizeof(pppllc) - LLC_LEN)) {
pvcc->encaps = e_vc;
- pvcc->chan.mtu += LLC_LEN;
+ ppp_channel_update_mtu(pvcc->chan,
+ atmvcc->qos.txtp.max_sdu - PPP_HDRLEN);
break;
}
pr_debug("Couldn't autodetect yet (skb: %6ph)\n", skb->data);
@@ -223,12 +219,12 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
case e_vc:
break;
}
- ppp_input(&pvcc->chan, skb);
+ ppp_input(pvcc->chan, skb);
return;
error:
kfree_skb(skb);
- ppp_input_error(&pvcc->chan);
+ ppp_input_error(pvcc->chan);
}
static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size)
@@ -286,9 +282,9 @@ static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size)
* as success, just to be clear what we're really doing.
*/
#define DROP_PACKET 1
-static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
+static int pppoatm_send(void *private, struct sk_buff *skb)
{
- struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
+ struct pppoatm_vcc *pvcc = private;
struct atm_vcc *vcc;
int ret;
@@ -367,16 +363,15 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
}
/* This handles ioctls sent to the /dev/ppp interface */
-static int pppoatm_devppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
- unsigned long arg)
+static int pppoatm_devppp_ioctl(void *private, unsigned int cmd,
+ unsigned long arg)
{
+ struct pppoatm_vcc *pvcc = private;
switch (cmd) {
case PPPIOCGFLAGS:
- return put_user(chan_to_pvcc(chan)->flags, (int __user *) arg)
- ? -EFAULT : 0;
+ return put_user(pvcc->flags, (int __user *)arg) ? -EFAULT : 0;
case PPPIOCSFLAGS:
- return get_user(chan_to_pvcc(chan)->flags, (int __user *) arg)
- ? -EFAULT : 0;
+ return get_user(pvcc->flags, (int __user *)arg) ? -EFAULT : 0;
}
return -ENOTTY;
}
@@ -388,9 +383,10 @@ static const struct ppp_channel_ops pppoatm_ops = {
static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
{
+ struct ppp_channel_conf conf = {};
struct atm_backend_ppp be;
struct pppoatm_vcc *pvcc;
- int err;
+ struct ppp_channel *chan;
if (copy_from_user(&be, arg, sizeof be))
return -EFAULT;
@@ -409,16 +405,19 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
pvcc->old_owner = atmvcc->owner;
pvcc->old_release_cb = atmvcc->release_cb;
pvcc->encaps = (enum pppoatm_encaps) be.encaps;
- pvcc->chan.private = pvcc;
- pvcc->chan.ops = &pppoatm_ops;
- pvcc->chan.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN -
+ conf.private = pvcc;
+ conf.ops = &pppoatm_ops;
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN -
(be.encaps == e_vc ? 0 : LLC_LEN);
+#endif
tasklet_setup(&pvcc->wakeup_tasklet, pppoatm_wakeup_sender);
- err = ppp_register_channel(&pvcc->chan);
- if (err != 0) {
+ chan = ppp_register_channel(&conf);
+ if (!chan) {
kfree(pvcc);
- return err;
+ return -ENOMEM;
}
+ pvcc->chan = chan;
atmvcc->user_back = pvcc;
atmvcc->push = pppoatm_push;
atmvcc->pop = pppoatm_pop;
@@ -458,11 +457,11 @@ static int pppoatm_ioctl(struct socket *sock, unsigned int cmd,
return pppoatm_assign_vcc(atmvcc, argp);
}
case PPPIOCGCHAN:
- return put_user(ppp_channel_index(&atmvcc_to_pvcc(atmvcc)->
- chan), (int __user *) argp) ? -EFAULT : 0;
+ return put_user(ppp_channel_index(atmvcc_to_pvcc(atmvcc)->chan),
+ (int __user *)argp) ? -EFAULT : 0;
case PPPIOCGUNIT:
- return put_user(ppp_unit_number(&atmvcc_to_pvcc(atmvcc)->
- chan), (int __user *) argp) ? -EFAULT : 0;
+ return put_user(ppp_unit_number(atmvcc_to_pvcc(atmvcc)->chan),
+ (int __user *)argp) ? -EFAULT : 0;
}
return -ENOIOCTLCMD;
}
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 99d6582f41de..6c7b08f4e49a 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -121,7 +121,7 @@ struct pppol2tp_session {
struct sock *__sk; /* Copy of .sk, for cleanup */
};
-static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+static int pppol2tp_xmit(void *private, struct sk_buff *skb);
static const struct ppp_channel_ops pppol2tp_chan_ops = {
.start_xmit = pppol2tp_xmit,
@@ -221,7 +221,7 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
struct pppox_sock *po;
po = pppox_sk(sk);
- ppp_input(&po->chan, skb);
+ ppp_input(po->chan, skb);
} else {
if (sock_queue_rcv_skb(sk, skb) < 0) {
atomic_long_inc(&session->stats.rx_errors);
@@ -326,9 +326,9 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
* the skb it supplied, not our cloned skb. So we take care to always
* leave the original skb unfreed if we return an error.
*/
-static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+static int pppol2tp_xmit(void *private, struct sk_buff *skb)
{
- struct sock *sk = (struct sock *)chan->private;
+ struct sock *sk = private;
struct l2tp_session *session;
struct l2tp_tunnel *tunnel;
int uhlen, headroom;
@@ -504,7 +504,7 @@ static void pppol2tp_show(struct seq_file *m, void *arg)
if (sk) {
struct pppox_sock *po = pppox_sk(sk);
- seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan));
+ seq_printf(m, " interface %s\n", ppp_dev_name(po->chan));
}
rcu_read_unlock();
}
@@ -612,7 +612,7 @@ static int pppol2tp_sockaddr_get_info(const void *sa, int sa_len,
* numbers and no IP option. Not quite accurate, but the result is mostly
* unused anyway.
*/
-static int pppol2tp_tunnel_mtu(const struct l2tp_tunnel *tunnel)
+static int __maybe_unused pppol2tp_tunnel_mtu(const struct l2tp_tunnel *tunnel)
{
int mtu;
@@ -694,6 +694,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr_unsized *userva
struct l2tp_tunnel *tunnel;
struct pppol2tp_session *ps;
struct l2tp_session_cfg cfg = { 0, };
+ struct ppp_channel_conf conf = {};
+ struct ppp_channel *chan;
bool drop_refcnt = false;
bool new_session = false;
bool new_tunnel = false;
@@ -792,18 +794,22 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr_unsized *userva
* the net device's hard_header_len at registration, which must be
* sufficient regardless of whether sequence numbers are enabled later.
*/
- po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_SEQ;
+ conf.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_SEQ;
- po->chan.private = sk;
- po->chan.ops = &pppol2tp_chan_ops;
- po->chan.mtu = pppol2tp_tunnel_mtu(tunnel);
- po->chan.direct_xmit = true;
+ conf.private = sk;
+ conf.ops = &pppol2tp_chan_ops;
+#ifdef CONFIG_PPP_MULTILINK
+ conf.mtu = pppol2tp_tunnel_mtu(tunnel);
+#endif
+ conf.direct_xmit = true;
- error = ppp_register_net_channel(sock_net(sk), &po->chan);
- if (error) {
+ chan = ppp_register_net_channel(sock_net(sk), &conf);
+ if (!chan) {
+ error = -ENOMEM;
mutex_unlock(&ps->sk_lock);
goto end;
}
+ po->chan = chan;
out_no_ppp:
/* This is how we get the session context from the socket. */
@@ -1550,7 +1556,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
if (sk) {
struct pppox_sock *po = pppox_sk(sk);
- seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan));
+ seq_printf(m, " interface %s\n", ppp_dev_name(po->chan));
}
rcu_read_unlock();
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] dt-bindings: qcom: geni-se-qup: Add compatible for SA8797P SoC
From: Krzysztof Kozlowski @ 2026-04-30 8:05 UTC (permalink / raw)
To: Shawn Guo
Cc: Bjorn Andersson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Praveen Talari, Konrad Dybcio, Dmitry Baryshkov,
Bartosz Golaszewski, Deepti Jaggi, linux-serial, devicetree,
linux-arm-msm, linux-kernel
In-Reply-To: <20260427005901.230237-1-shengchao.guo@oss.qualcomm.com>
On Mon, Apr 27, 2026 at 08:59:01AM +0800, Shawn Guo wrote:
> From: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
>
> Document GENI Serial Engine QUP Wrapper Controller on Nord SA8797P SoC
> which is compatible with SA8255P one.
>
> Signed-off-by: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
> Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
> ---
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v1] serial: qcom-geni: Avoid probing debug console UART without console support
From: kernel test robot @ 2026-04-30 3:42 UTC (permalink / raw)
To: Aniket Randive, gregkh, jirislaby, linux-arm-msm, linux-kernel,
linux-serial, praveen.talari, anup.kulkarni, dmitry.baryshkov,
viken.dadhaniya
Cc: llvm, oe-kbuild-all, Aniket Randive
In-Reply-To: <20260413072501.263871-1-aniket.randive@oss.qualcomm.com>
Hi Aniket,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Aniket-Randive/serial-qcom-geni-Avoid-probing-debug-console-UART-without-console-support/20260423-150710
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260413072501.263871-1-aniket.randive%40oss.qualcomm.com
patch subject: [PATCH v1] serial: qcom-geni: Avoid probing debug console UART without console support
config: s390-randconfig-002-20260430 (https://download.01.org/0day-ci/archive/20260430/202604301151.rPBXnWLg-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604301151.rPBXnWLg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604301151.rPBXnWLg-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/tty/serial/qcom_geni_serial.c:1995:43: warning: unused variable 'qcom_geni_console_data' [-Wunused-const-variable]
1995 | static const struct qcom_geni_device_data qcom_geni_console_data = {
| ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/tty/serial/qcom_geni_serial.c:2011:43: warning: unused variable 'sa8255p_qcom_geni_console_data' [-Wunused-const-variable]
2011 | static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
vim +/qcom_geni_console_data +1995 drivers/tty/serial/qcom_geni_serial.c
c4f528795d1add Karthikeyan Ramasubramanian 2018-03-14 1994
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 @1995 static const struct qcom_geni_device_data qcom_geni_console_data = {
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 1996 .console = true,
2aaa43c7077833 Bartosz Golaszewski 2022-12-29 1997 .mode = GENI_SE_FIFO,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 1998 .resources_init = geni_serial_resource_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 1999 .set_rate = geni_serial_set_rate,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2000 .power_state = geni_serial_resource_state,
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2001 };
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2002
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2003 static const struct qcom_geni_device_data qcom_geni_uart_data = {
40ec6d41c841e2 Bartosz Golaszewski 2022-12-29 2004 .console = false,
2aaa43c7077833 Bartosz Golaszewski 2022-12-29 2005 .mode = GENI_SE_DMA,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2006 .resources_init = geni_serial_resource_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2007 .set_rate = geni_serial_set_rate,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2008 .power_state = geni_serial_resource_state,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2009 };
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2010
abffd1e6c4f1c9 Praveen Talari 2025-11-10 @2011 static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2012 .console = true,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2013 .mode = GENI_SE_FIFO,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2014 .pd_data = {
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2015 .pd_flags = PD_FLAG_DEV_LINK_ON,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2016 .pd_names = (const char*[]) { "power", "perf" },
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2017 .num_pd_names = 2,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2018 },
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2019 .resources_init = geni_serial_pwr_init,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2020 .set_rate = geni_serial_set_level,
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2021 };
abffd1e6c4f1c9 Praveen Talari 2025-11-10 2022
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v7 6/6] ARM: zte: defconfig: Add a zx29 defconfig file
From: Stefan Dösinger @ 2026-04-29 19:13 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Russell King, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Arnd Bergmann,
Krzysztof Kozlowski, Alexandre Belloni, Linus Walleij,
Drew Fustini, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-doc, linux-kernel, linux-arm-kernel, devicetree, soc,
linux-serial, Stefan Dösinger
In-Reply-To: <20260429-send-v7-0-b432e00d2db8@gmail.com>
This enables existing drivers for hardware that is present on this board
even if it is not present in the DT yet.
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Changes: v5 to v6: Regenerate the file with make savedefconfig.
An open question: What's the appropriate name? zx29_defconfig?
zte_defconfig? zte_zx29_defconfig? There's e.g. stm32_defconfig without
an extra mention of STMicro in the name.
---
MAINTAINERS | 1 +
arch/arm/configs/zx29_defconfig | 54 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6f51ba1c5ada..5dc52b84cc09 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3776,6 +3776,7 @@ ARM/ZTE ZX29 SOC SUPPORT
M: Stefan Dösinger <stefandoesinger@gmail.com>
F: Documentation/devicetree/bindings/arm/zte.yaml
F: arch/arm/boot/dts/zte/
+F: arch/arm/configs/zx29_defconfig
F: arch/arm/mach-zte/
ARM/ZYNQ ARCHITECTURE
diff --git a/arch/arm/configs/zx29_defconfig b/arch/arm/configs/zx29_defconfig
new file mode 100644
index 000000000000..54fa62ed56e7
--- /dev/null
+++ b/arch/arm/configs/zx29_defconfig
@@ -0,0 +1,54 @@
+CONFIG_SYSVIPC=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ARCH_ZTE=y
+CONFIG_ARM_PSCI=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CMDLINE="console=ttyAMA0 earlyprintk root=/dev/ram rw"
+CONFIG_CPU_FREQ=y
+CONFIG_CPUFREQ_DT_PLATDEV=y
+# CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_SRAM=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_DEV_BUS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_PINCTRL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_POWER_RESET=y
+CONFIG_MFD_SYSCON=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_HID is not set
+CONFIG_USB_DWC2=y
+CONFIG_USB_GADGET=y
+CONFIG_MMC=y
+CONFIG_MMC_DW=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_SIMPLE=y
+CONFIG_JFFS2_FS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
--
2.53.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