--- /dev/null
+From f7d240f727b67cffaa0a1c5becfe5f224f1fdc5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jun 2026 20:41:10 +0000
+Subject: page_pool: Fix use-after-free in page_pool_recycle_in_ring
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Dong Chenchen <dongchenchen2@huawei.com>
+
+[ Upstream commit 271683bb2cf32e5126c592b5d5e6a756fa374fd9 ]
+
+syzbot reported a uaf in page_pool_recycle_in_ring:
+
+BUG: KASAN: slab-use-after-free in lock_release+0x151/0xa30 kernel/locking/lockdep.c:5862
+Read of size 8 at addr ffff8880286045a0 by task syz.0.284/6943
+
+root cause is:
+
+page_pool_recycle_in_ring
+ ptr_ring_produce
+ spin_lock(&r->producer_lock);
+ WRITE_ONCE(r->queue[r->producer++], ptr)
+ //recycle last page to pool
+ page_pool_release
+ page_pool_scrub
+ page_pool_empty_ring
+ ptr_ring_consume
+ page_pool_return_page //release all page
+ __page_pool_destroy
+ free_percpu(pool->recycle_stats);
+ free(pool) //free
+
+ spin_unlock(&r->producer_lock); //pool->ring uaf read
+ recycle_stat_inc(pool, ring);
+
+page_pool can be free while page pool recycle the last page in ring.
+Add producer-lock barrier to page_pool_release to prevent the page
+pool from being free before all pages have been recycled.
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Link: https://lore.kernel.org/netdev/20250513083123.3514193-1-dongchenchen2@huawei.com
+Fixes: ff7d6b27f894 ("page_pool: refurbish version of page_pool code")
+Reported-by: syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=204a4382fcb3311f3858
+Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com>
+Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Reviewed-by: Mina Almasry <almasrymina@google.com>
+Link: https://patch.msgid.link/20250527114152.3119109-1-dongchenchen2@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[v5.10: introduced page_pool_producer_lock/unlock helpers inline since
+ prerequisite commit 368d3cb406cd ("page_pool: fix inconsistency for
+ page_pool_ring_[un]lock()") depends on page_pool_put_page_bulk which
+ does not exist in 5.10; used in_serving_softirq() per 5.10 convention;
+ kept struct page * API (no netmem_ref); dropped recycle_stat_inc change
+ as page pool stats do not exist in this tree]
+Signed-off-by: Bjoern Doebel <doebel@amazon.de>
+Assisted-by: Claude:claude-opus-4-6-v1
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/page_pool.c | 39 +++++++++++++++++++++++++++++++++------
+ 1 file changed, 33 insertions(+), 6 deletions(-)
+
+diff --git a/net/core/page_pool.c b/net/core/page_pool.c
+index 15ad99330bb9b1..09d98fcf669f2c 100644
+--- a/net/core/page_pool.c
++++ b/net/core/page_pool.c
+@@ -318,16 +318,39 @@ static void page_pool_return_page(struct page_pool *pool, struct page *page)
+ */
+ }
+
++static bool page_pool_producer_lock(struct page_pool *pool)
++ __acquires(&pool->ring.producer_lock)
++{
++ bool in_softirq = in_serving_softirq();
++
++ if (in_softirq)
++ spin_lock(&pool->ring.producer_lock);
++ else
++ spin_lock_bh(&pool->ring.producer_lock);
++
++ return in_softirq;
++}
++
++static void page_pool_producer_unlock(struct page_pool *pool,
++ bool in_softirq)
++ __releases(&pool->ring.producer_lock)
++{
++ if (in_softirq)
++ spin_unlock(&pool->ring.producer_lock);
++ else
++ spin_unlock_bh(&pool->ring.producer_lock);
++}
++
+ static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page)
+ {
+- int ret;
++ bool in_softirq, ret;
++
+ /* BH protection not needed if current is serving softirq */
+- if (in_serving_softirq())
+- ret = ptr_ring_produce(&pool->ring, page);
+- else
+- ret = ptr_ring_produce_bh(&pool->ring, page);
++ in_softirq = page_pool_producer_lock(pool);
++ ret = !__ptr_ring_produce(&pool->ring, page);
++ page_pool_producer_unlock(pool, in_softirq);
+
+- return (ret == 0) ? true : false;
++ return ret;
+ }
+
+ /* Only allow direct recycling in special circumstances, into the
+@@ -464,10 +487,14 @@ static void page_pool_scrub(struct page_pool *pool)
+
+ static int page_pool_release(struct page_pool *pool)
+ {
++ bool in_softirq;
+ int inflight;
+
+ page_pool_scrub(pool);
+ inflight = page_pool_inflight(pool);
++ /* Acquire producer lock to make sure producers have exited. */
++ in_softirq = page_pool_producer_lock(pool);
++ page_pool_producer_unlock(pool, in_softirq);
+ if (!inflight)
+ page_pool_free(pool);
+
+--
+2.53.0
+
--- /dev/null
+From 95b067a4c8d4af9c34a5b260f2f24a1e732fe538 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:10:42 +0100
+Subject: serial: dz: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 upstream.
+
+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 the
+transmitter of which 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+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Avoid C99+ 'for' loop initial declaration for 5.10.y. ]
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/dz.c | 37 +++++++++++++------------------------
+ 1 file changed, 13 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
+index fdd025c1b5e163..a4c7b5413100a3 100644
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -546,6 +546,7 @@ static void dz_reset(struct dz_port *dport)
+ struct dz_mux *mux = dport->mux;
+ unsigned short tcr;
+ int loops = 10000;
++ int line;
+
+ if (mux->initialised)
+ return;
+@@ -573,6 +574,18 @@ static void dz_reset(struct dz_port *dport)
+ 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 (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);
+
+@@ -653,26 +666,6 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ spin_unlock_irqrestore(&dport->port.lock, 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;
+-
+- spin_lock_irqsave(&dport->port.lock, flags);
+- if (state < 3)
+- dz_start_tx(&dport->port);
+- else
+- dz_stop_tx(&dport->port);
+- spin_unlock_irqrestore(&dport->port.lock, flags);
+-}
+-
+-
+ static const char *dz_type(struct uart_port *uport)
+ {
+ return "DZ";
+@@ -768,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,
+@@ -893,10 +885,7 @@ static int __init dz_console_setup(struct console *co, char *options)
+ 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);
+--
+2.53.0
+
usb-serial-cypress_m8-fix-memory-corruption-with-sma.patch
usb-serial-digi_acceleport-fix-memory-corruption-wit.patch
xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
+serial-dz-fix-bootconsole-handover-lockup.patch
+page_pool-fix-use-after-free-in-page_pool_recycle_in.patch
+team-move-team-device-type-change-at-the-end-of-team.patch
--- /dev/null
+From f08f92fbc8e5a65bcedc98f8ad914aae4fa6a53f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 16:47:00 +0300
+Subject: team: Move team device type change at the end of team_port_add
+
+From: Nikola Z. Ivanov <zlatistiv@gmail.com>
+
+commit 0ae9cfc454ea5ead5f3ddbdfe2e70270d8e2c8ef upstream.
+
+Attempting to add a port device that is already up will expectedly fail,
+but not before modifying the team device header_ops.
+
+In the case of the syzbot reproducer the gre0 device is
+already in state UP when it attempts to add it as a
+port device of team0, this fails but before that
+header_ops->create of team0 is changed from eth_header to ipgre_header
+in the call to team_dev_type_check_change.
+
+Later when we end up in ipgre_header() struct ip_tunnel* points to nonsense
+as the private data of the device still holds a struct team.
+
+Example sequence of iproute2 commands to reproduce the hang/BUG():
+ip link add dev team0 type team
+ip link add dev gre0 type gre
+ip link set dev gre0 up
+ip link set dev gre0 master team0
+ip link set dev team0 up
+ping -I team0 1.1.1.1
+
+Move team_dev_type_check_change down where all other checks have passed
+as it changes the dev type with no way to restore it in case
+one of the checks that follow it fail.
+
+Also make sure to preserve the origial mtu assignment:
+ - If port_dev is not the same type as dev, dev takes mtu from port_dev
+ - If port_dev is the same type as dev, port_dev takes mtu from dev
+
+This is done by adding a conditional before the call to dev_set_mtu
+to prevent it from assigning port_dev->mtu = dev->mtu and instead
+letting team_dev_type_check_change assign dev->mtu = port_dev->mtu.
+The conditional is needed because the patch moves the call to
+team_dev_type_check_change past dev_set_mtu.
+
+Testing:
+ - team device driver in-tree selftests
+ - Add/remove various devices as slaves of team device
+ - syzbot
+
+Reported-by: syzbot+a2a3b519de727b0f7903@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=a2a3b519de727b0f7903
+Fixes: 1d76efe1577b ("team: add support for non-ethernet devices")
+Signed-off-by: Nikola Z. Ivanov <zlatistiv@gmail.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Link: https://patch.msgid.link/20251122002027.695151-1-zlatistiv@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Alexey: backport to 5.10: adjust path from
+drivers/net/team/team_core.c to drivers/net/team/team.c ]
+Signed-off-by: Alexey Panov <apanov@astralinux.ru>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/team/team.c | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
+index 03cc3da8c3c119..0b62e204c7bb1c 100644
+--- a/drivers/net/team/team.c
++++ b/drivers/net/team/team.c
+@@ -1180,10 +1180,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
+ return -EPERM;
+ }
+
+- err = team_dev_type_check_change(dev, port_dev);
+- if (err)
+- return err;
+-
+ if (port_dev->flags & IFF_UP) {
+ NL_SET_ERR_MSG(extack, "Device is up. Set it down before adding it as a team port");
+ netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
+@@ -1201,10 +1197,16 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
+ INIT_LIST_HEAD(&port->qom_list);
+
+ port->orig.mtu = port_dev->mtu;
+- err = dev_set_mtu(port_dev, dev->mtu);
+- if (err) {
+- netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
+- goto err_set_mtu;
++ /*
++ * MTU assignment will be handled in team_dev_type_check_change
++ * if dev and port_dev are of different types
++ */
++ if (dev->type == port_dev->type) {
++ err = dev_set_mtu(port_dev, dev->mtu);
++ if (err) {
++ netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
++ goto err_set_mtu;
++ }
+ }
+
+ memcpy(port->orig.dev_addr, port_dev->dev_addr, port_dev->addr_len);
+@@ -1279,6 +1281,10 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
+ }
+ }
+
++ err = team_dev_type_check_change(dev, port_dev);
++ if (err)
++ goto err_set_dev_type;
++
+ if (dev->flags & IFF_UP) {
+ netif_addr_lock_bh(dev);
+ dev_uc_sync_multiple(port_dev, dev);
+@@ -1297,6 +1303,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
+
+ return 0;
+
++err_set_dev_type:
+ err_set_slave_promisc:
+ __team_option_inst_del_port(team, port);
+
+--
+2.53.0
+
--- /dev/null
+From 2ee7e0cfd03da3ced85cc863d45e3c60ac8d5bb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:09:15 +0100
+Subject: serial: dz: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 upstream.
+
+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 the
+transmitter of which 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+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Avoid C99+ 'for' loop initial declaration for 5.15.y. ]
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/dz.c | 37 +++++++++++++------------------------
+ 1 file changed, 13 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
+index 6d74ba5a5a431c..05f22e76a50893 100644
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -546,6 +546,7 @@ static void dz_reset(struct dz_port *dport)
+ struct dz_mux *mux = dport->mux;
+ unsigned short tcr;
+ int loops = 10000;
++ int line;
+
+ if (mux->initialised)
+ return;
+@@ -573,6 +574,18 @@ static void dz_reset(struct dz_port *dport)
+ 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 (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);
+
+@@ -653,26 +666,6 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ spin_unlock_irqrestore(&dport->port.lock, 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;
+-
+- spin_lock_irqsave(&dport->port.lock, flags);
+- if (state < 3)
+- dz_start_tx(&dport->port);
+- else
+- dz_stop_tx(&dport->port);
+- spin_unlock_irqrestore(&dport->port.lock, flags);
+-}
+-
+-
+ static const char *dz_type(struct uart_port *uport)
+ {
+ return "DZ";
+@@ -768,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,
+@@ -893,10 +885,7 @@ static int __init dz_console_setup(struct console *co, char *options)
+ 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);
+--
+2.53.0
+
hid-core-fix-size_t-specifier-in-hid_report_raw_even.patch
usb-serial-digi_acceleport-fix-memory-corruption-wit.patch
xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
+serial-dz-fix-bootconsole-handover-lockup.patch
--- /dev/null
+From 7dfd9db0a06c94ebba4a089803fb88d620feff5b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 14:07:44 +0800
+Subject: bpf/bonding: reject vlan+srcmac xmit_hash_policy change when XDP is
+ loaded
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 479d589b40b836442bbdadc3fdb37f001bb67f26 ]
+
+bond_option_mode_set() already rejects mode changes that would make a
+loaded XDP program incompatible via bond_xdp_check(). However,
+bond_option_xmit_hash_policy_set() has no such guard.
+
+For 802.3ad and balance-xor modes, bond_xdp_check() returns false when
+xmit_hash_policy is vlan+srcmac, because the 802.1q payload is usually
+absent due to hardware offload. This means a user can:
+
+1. Attach a native XDP program to a bond in 802.3ad/balance-xor mode
+ with a compatible xmit_hash_policy (e.g. layer2+3).
+2. Change xmit_hash_policy to vlan+srcmac while XDP remains loaded.
+
+This leaves bond->xdp_prog set but bond_xdp_check() now returning false
+for the same device. When the bond is later destroyed, dev_xdp_uninstall()
+calls bond_xdp_set(dev, NULL, NULL) to remove the program, which hits
+the bond_xdp_check() guard and returns -EOPNOTSUPP, triggering:
+
+WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL))
+
+Fix this by rejecting xmit_hash_policy changes to vlan+srcmac when an
+XDP program is loaded on a bond in 802.3ad or balance-xor mode.
+
+commit 39a0876d595b ("net, bonding: Disallow vlan+srcmac with XDP")
+introduced bond_xdp_check() which returns false for 802.3ad/balance-xor
+modes when xmit_hash_policy is vlan+srcmac. The check was wired into
+bond_xdp_set() to reject XDP attachment with an incompatible policy, but
+the symmetric path -- preventing xmit_hash_policy from being changed to an
+incompatible value after XDP is already loaded -- was left unguarded in
+bond_option_xmit_hash_policy_set().
+
+Note:
+commit 094ee6017ea0 ("bonding: check xdp prog when set bond mode")
+later added a similar guard to bond_option_mode_set(), but
+bond_option_xmit_hash_policy_set() remained unprotected.
+
+Reported-by: syzbot+5a287bcdc08104bc3132@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/6995aff6.050a0220.2eeac1.014e.GAE@google.com/T/
+Fixes: 39a0876d595b ("net, bonding: Disallow vlan+srcmac with XDP")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Link: https://patch.msgid.link/20260226080306.98766-2-jiayuan.chen@linux.dev
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Rajani Kantha <681739313@139.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_main.c | 9 +++++++--
+ drivers/net/bonding/bond_options.c | 2 ++
+ include/net/bonding.h | 1 +
+ 3 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 0e078252b52a98..f2e97f640467de 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -322,7 +322,7 @@ bool bond_sk_check(struct bonding *bond)
+ }
+ }
+
+-bool bond_xdp_check(struct bonding *bond, int mode)
++bool __bond_xdp_check(int mode, int xmit_policy)
+ {
+ switch (mode) {
+ case BOND_MODE_ROUNDROBIN:
+@@ -333,7 +333,7 @@ bool bond_xdp_check(struct bonding *bond, int mode)
+ /* vlan+srcmac is not supported with XDP as in most cases the 802.1q
+ * payload is not in the packet due to hardware offload.
+ */
+- if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
++ if (xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
+ return true;
+ fallthrough;
+ default:
+@@ -341,6 +341,11 @@ bool bond_xdp_check(struct bonding *bond, int mode)
+ }
+ }
+
++bool bond_xdp_check(struct bonding *bond, int mode)
++{
++ return __bond_xdp_check(mode, bond->params.xmit_policy);
++}
++
+ /*---------------------------------- VLAN -----------------------------------*/
+
+ /* In the following 2 functions, bond_vlan_rx_add_vid and bond_vlan_rx_kill_vid,
+diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
+index 40731d180bb505..3d15b340b5c939 100644
+--- a/drivers/net/bonding/bond_options.c
++++ b/drivers/net/bonding/bond_options.c
+@@ -1590,6 +1590,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond,
+ static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+ {
++ if (bond->xdp_prog && !__bond_xdp_check(BOND_MODE(bond), newval->value))
++ return -EOPNOTSUPP;
+ netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
+ newval->string, newval->value);
+ bond->params.xmit_policy = newval->value;
+diff --git a/include/net/bonding.h b/include/net/bonding.h
+index 06a048d716b19f..f2dee8cefa1963 100644
+--- a/include/net/bonding.h
++++ b/include/net/bonding.h
+@@ -704,6 +704,7 @@ void bond_debug_register(struct bonding *bond);
+ void bond_debug_unregister(struct bonding *bond);
+ void bond_debug_reregister(struct bonding *bond);
+ const char *bond_mode_name(int mode);
++bool __bond_xdp_check(int mode, int xmit_policy);
+ bool bond_xdp_check(struct bonding *bond, int mode);
+ void bond_setup(struct net_device *bond_dev);
+ unsigned int bond_get_num_tx_queues(void);
+--
+2.53.0
+
--- /dev/null
+From 2da11212366aba0c1bf79f16b66427d269b95a77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:07:17 +0100
+Subject: serial: dz: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 upstream.
+
+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 the
+transmitter of which 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+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/dz.c | 36 ++++++++++++------------------------
+ 1 file changed, 12 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
+index a16738799418ca..d80bbd95a7f786 100644
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -573,6 +573,18 @@ static void dz_reset(struct dz_port *dport)
+ 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);
+
+@@ -656,26 +668,6 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ spin_unlock_irqrestore(&dport->port.lock, 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;
+-
+- spin_lock_irqsave(&dport->port.lock, flags);
+- if (state < 3)
+- dz_start_tx(&dport->port);
+- else
+- dz_stop_tx(&dport->port);
+- spin_unlock_irqrestore(&dport->port.lock, flags);
+-}
+-
+-
+ static const char *dz_type(struct uart_port *uport)
+ {
+ return "DZ";
+@@ -771,7 +763,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,
+@@ -896,10 +887,7 @@ static int __init dz_console_setup(struct console *co, char *options)
+ 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);
+--
+2.53.0
+
xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
netfilter-nf_tables-restore-set-elements-when-delete.patch
usb-serial-cypress_m8-fix-memory-corruption-with-sma.patch
+serial-dz-fix-bootconsole-handover-lockup.patch
+bpf-bonding-reject-vlan-srcmac-xmit_hash_policy-chan.patch
--- /dev/null
+From ee1b7c23dd4b3a823f24bd0514852e5255b8fa63 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jun 2026 16:47:53 +0300
+Subject: iommu: Skip PASID validation for devices without PASID capability
+
+From: Tushar Dave <tdave@nvidia.com>
+
+[ Upstream commit b3f6fcd8404f9f92262303369bb877ec5d188a81 ]
+
+Generally PASID support requires ACS settings that usually create
+single device groups, but there are some niche cases where we can get
+multi-device groups and still have working PASID support. The primary
+issue is that PCI switches are not required to treat PASID tagged TLPs
+specially so appropriate ACS settings are required to route all TLPs to
+the host bridge if PASID is going to work properly.
+
+pci_enable_pasid() does check that each device that will use PASID has
+the proper ACS settings to achieve this routing.
+
+However, no-PASID devices can be combined with PASID capable devices
+within the same topology using non-uniform ACS settings. In this case
+the no-PASID devices may not have strict route to host ACS flags and
+end up being grouped with the PASID devices.
+
+This configuration fails to allow use of the PASID within the iommu
+core code which wrongly checks if the no-PASID device supports PASID.
+
+Fix this by ignoring no-PASID devices during the PASID validation. They
+will never issue a PASID TLP anyhow so they can be ignored.
+
+Fixes: c404f55c26fc ("iommu: Validate the PASID in iommu_attach_device_pasid()")
+Cc: stable@vger.kernel.org
+Signed-off-by: Tushar Dave <tdave@nvidia.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
+Link: https://lore.kernel.org/r/20250520011937.3230557-1-tdave@nvidia.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+
+[ Refactored to apply cleanly without support attaching PASID to the blocked domain ]
+Signed-off-by: Dmitrii Chervov <fary.ru@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/iommu.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
+index 0ad55649e2d007..62e1d637250318 100644
+--- a/drivers/iommu/iommu.c
++++ b/drivers/iommu/iommu.c
+@@ -3341,9 +3341,11 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
+ int ret;
+
+ for_each_group_device(group, device) {
+- ret = domain->ops->set_dev_pasid(domain, device->dev, pasid);
+- if (ret)
+- goto err_revert;
++ if (device->dev->iommu->max_pasids > 0) {
++ ret = domain->ops->set_dev_pasid(domain, device->dev, pasid);
++ if (ret)
++ goto err_revert;
++ }
+ }
+
+ return 0;
+@@ -3355,7 +3357,8 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
+
+ if (device == last_gdev)
+ break;
+- ops->remove_dev_pasid(device->dev, pasid, domain);
++ if (device->dev->iommu->max_pasids > 0)
++ ops->remove_dev_pasid(device->dev, pasid, domain);
+ }
+ return ret;
+ }
+@@ -3368,8 +3371,10 @@ static void __iommu_remove_group_pasid(struct iommu_group *group,
+ const struct iommu_ops *ops;
+
+ for_each_group_device(group, device) {
+- ops = dev_iommu_ops(device->dev);
+- ops->remove_dev_pasid(device->dev, pasid, domain);
++ if (device->dev->iommu->max_pasids > 0) {
++ ops = dev_iommu_ops(device->dev);
++ ops->remove_dev_pasid(device->dev, pasid, domain);
++ }
+ }
+ }
+
+@@ -3403,7 +3408,13 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
+
+ mutex_lock(&group->mutex);
+ for_each_group_device(group, device) {
+- if (pasid >= device->dev->iommu->max_pasids) {
++ /*
++ * Skip PASID validation for devices without PASID support
++ * (max_pasids = 0). These devices cannot issue transactions
++ * with PASID, so they don't affect group's PASID usage.
++ */
++ if ((device->dev->iommu->max_pasids > 0) &&
++ (pasid >= device->dev->iommu->max_pasids)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+--
+2.53.0
+
usb-serial-cypress_m8-fix-memory-corruption-with-sma.patch
usb-serial-digi_acceleport-fix-memory-corruption-wit.patch
xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
+iommu-skip-pasid-validation-for-devices-without-pasi.patch
+xfrm-hold-dev-ref-until-after-transport_finish-nf_ho.patch
+x86-boot-disable-stack-protector-for-early-boot-code.patch
+x86-kexec-disable-kcov-instrumentation-after-load_se.patch
--- /dev/null
+From 4c4d3ac497d18b33be30ed8e17938dc5e2f7f7cd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jan 2025 14:07:35 -0500
+Subject: x86/boot: Disable stack protector for early boot code
+
+From: Brian Gerst <brgerst@gmail.com>
+
+[ Upstream commit a9a76b38aaf577887103e3ebb41d70e6aa5a4b19 ]
+
+On 64-bit, this will prevent crashes when the canary access is changed
+from %gs:40 to %gs:__stack_chk_guard(%rip). RIP-relative addresses from
+the identity-mapped early boot code will target the wrong address with
+zero-based percpu. KASLR could then shift that address to an unmapped
+page causing a crash on boot.
+
+This early boot code runs well before user-space is active and does not
+need stack protector enabled.
+
+Signed-off-by: Brian Gerst <brgerst@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Link: https://lore.kernel.org/r/20250123190747.745588-4-brgerst@gmail.com
+Stable-dep-of: 917e3ad3321e ("x86/kexec: Disable KCOV instrumentation after load_segments()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/Makefile | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
+index f7918980667a33..f42c0903ef86d4 100644
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -44,6 +44,8 @@ KCOV_INSTRUMENT_unwind_orc.o := n
+ KCOV_INSTRUMENT_unwind_frame.o := n
+ KCOV_INSTRUMENT_unwind_guess.o := n
+
++CFLAGS_head32.o := -fno-stack-protector
++CFLAGS_head64.o := -fno-stack-protector
+ CFLAGS_irq.o := -I $(src)/../include/asm/trace
+
+ obj-y += head_$(BITS).o
+--
+2.53.0
+
--- /dev/null
+From 9c5ef28faa6a652a4adb8983626db2bf6776af82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 16:48:24 +0100
+Subject: x86/kexec: Disable KCOV instrumentation after load_segments()
+
+From: Aleksandr Nogikh <nogikh@google.com>
+
+[ Upstream commit 917e3ad3321e75ca0223d5ccf26ceda116aa51e1 ]
+
+The load_segments() function changes segment registers, invalidating GS base
+(which KCOV relies on for per-cpu data). When CONFIG_KCOV is enabled, any
+subsequent instrumented C code call (e.g. native_gdt_invalidate()) begins
+crashing the kernel in an endless loop.
+
+To reproduce the problem, it's sufficient to do kexec on a KCOV-instrumented
+kernel:
+
+ $ kexec -l /boot/otherKernel
+ $ kexec -e
+
+The real-world context for this problem is enabling crash dump collection in
+syzkaller. For this, the tool loads a panic kernel before fuzzing and then
+calls makedumpfile after the panic. This workflow requires both CONFIG_KEXEC
+and CONFIG_KCOV to be enabled simultaneously.
+
+Adding safeguards directly to the KCOV fast-path (__sanitizer_cov_trace_pc())
+is also undesirable as it would introduce an extra performance overhead.
+
+Disabling instrumentation for the individual functions would be too fragile,
+so disable KCOV instrumentation for the entire machine_kexec_64.c and
+physaddr.c. If coverage-guided fuzzing ever needs these components in the
+future, other approaches should be considered.
+
+The problem is not relevant for 32 bit kernels as CONFIG_KCOV is not supported
+there.
+
+ [ bp: Space out comment for better readability. ]
+
+Fixes: 0d345996e4cb ("x86/kernel: increase kcov coverage under arch/x86/kernel folder")
+Signed-off-by: Aleksandr Nogikh <nogikh@google.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260325154825.551191-1-nogikh@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/Makefile | 14 ++++++++++++++
+ arch/x86/mm/Makefile | 2 ++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
+index f42c0903ef86d4..5f58b5a38cac17 100644
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -44,6 +44,20 @@ KCOV_INSTRUMENT_unwind_orc.o := n
+ KCOV_INSTRUMENT_unwind_frame.o := n
+ KCOV_INSTRUMENT_unwind_guess.o := n
+
++# Disable KCOV to prevent crashes during kexec: load_segments() invalidates
++# the GS base, which KCOV relies on for per-CPU data.
++#
++# As KCOV and KEXEC compatibility should be preserved (e.g. syzkaller is
++# using it to collect crash dumps during kernel fuzzing), disabling
++# KCOV for KEXEC kernels is not an option. Selectively disabling KCOV
++# instrumentation for individual affected functions can be fragile, while
++# adding more checks to KCOV would slow it down.
++#
++# As a compromise solution, disable KCOV instrumentation for the whole
++# source code file. If its coverage is ever needed, other approaches
++# should be considered.
++KCOV_INSTRUMENT_machine_kexec_64.o := n
++
+ CFLAGS_head32.o := -fno-stack-protector
+ CFLAGS_head64.o := -fno-stack-protector
+ CFLAGS_irq.o := -I $(src)/../include/asm/trace
+diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
+index 690fbf48e8538b..60a53baa042793 100644
+--- a/arch/x86/mm/Makefile
++++ b/arch/x86/mm/Makefile
+@@ -5,6 +5,8 @@ KCOV_INSTRUMENT_mem_encrypt.o := n
+ KCOV_INSTRUMENT_mem_encrypt_amd.o := n
+ KCOV_INSTRUMENT_mem_encrypt_identity.o := n
+ KCOV_INSTRUMENT_pgprot.o := n
++# See the "Disable KCOV" comment in arch/x86/kernel/Makefile.
++KCOV_INSTRUMENT_physaddr.o := n
+
+ KASAN_SANITIZE_mem_encrypt.o := n
+ KASAN_SANITIZE_mem_encrypt_amd.o := n
+--
+2.53.0
+
--- /dev/null
+From c23bf6bc628df4f85442f73c1e190b74dae30031 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 14:12:54 +0000
+Subject: xfrm: hold dev ref until after transport_finish NF_HOOK
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 1c428b03840094410c5fb6a5db30640486bbbfcb ]
+
+After async crypto completes, xfrm_input_resume() calls dev_put()
+immediately on re-entry before the skb reaches transport_finish.
+The skb->dev pointer is then used inside NF_HOOK and its okfn,
+which can race with device teardown.
+
+Remove the dev_put from the async resumption entry and instead
+drop the reference after the NF_HOOK call in transport_finish,
+using a saved device pointer since NF_HOOK may consume the skb.
+This covers NF_DROP, NF_QUEUE and NF_STOLEN paths that skip
+the okfn.
+
+For non-transport exits (decaps, gro, drop) and secondary
+async return points, release the reference inline when
+async is set.
+
+Suggested-by: Florian Westphal <fw@strlen.de>
+Fixes: acf568ee859f ("xfrm: Reinject transport-mode packets through tasklet")
+Cc: stable@vger.kernel.org
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+[ net/xfrm/xfrm_input.c: dev_hold/dev_put are unconditional here rather
+than inside !crypto_done as in mainline, and the dev_put in the
+encap_type == -1 async-resumption block does not exist; adapted by
+gating dev_put at resume: with if (!async), adding if (async) dev_put
+at -EINPROGRESS return, gro_cells_receive paths, and drop label. ]
+Signed-off-by: Simon Liebold <simonlie@amazon.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/xfrm4_input.c | 5 ++++-
+ net/ipv6/xfrm6_input.c | 5 ++++-
+ net/xfrm/xfrm_input.c | 14 ++++++++++++--
+ 3 files changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
+index 12a1a0f421956c..adf21d6b6076c1 100644
+--- a/net/ipv4/xfrm4_input.c
++++ b/net/ipv4/xfrm4_input.c
+@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
+ {
+ struct xfrm_offload *xo = xfrm_offload(skb);
+ struct iphdr *iph = ip_hdr(skb);
++ struct net_device *dev = skb->dev;
+
+ iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
+
+@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
+ }
+
+ NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
+- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++ dev_net(dev), NULL, skb, dev, NULL,
+ xfrm4_rcv_encap_finish);
++ if (async)
++ dev_put(dev);
+ return 0;
+ }
+
+diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
+index 9005fc156a20e6..699a001ac16629 100644
+--- a/net/ipv6/xfrm6_input.c
++++ b/net/ipv6/xfrm6_input.c
+@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
+ int xfrm6_transport_finish(struct sk_buff *skb, int async)
+ {
+ struct xfrm_offload *xo = xfrm_offload(skb);
++ struct net_device *dev = skb->dev;
+ int nhlen = -skb_network_offset(skb);
+
+ skb_network_header(skb)[IP6CB(skb)->nhoff] =
+@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
+ }
+
+ NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
+- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++ dev_net(dev), NULL, skb, dev, NULL,
+ xfrm6_transport_finish2);
++ if (async)
++ dev_put(dev);
+ return 0;
+ }
+
+diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
+index 8edcb32735e595..a0a04b87a0c2ab 100644
+--- a/net/xfrm/xfrm_input.c
++++ b/net/xfrm/xfrm_input.c
+@@ -645,10 +645,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+ else
+ nexthdr = x->type->input(x, skb);
+
+- if (nexthdr == -EINPROGRESS)
++ if (nexthdr == -EINPROGRESS) {
++ if (async)
++ dev_put(skb->dev);
+ return 0;
++ }
+ resume:
+- dev_put(skb->dev);
++ if (!async)
++ dev_put(skb->dev);
+
+ spin_lock(&x->lock);
+ if (nexthdr < 0) {
+@@ -716,6 +720,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+ sp->olen = 0;
+ if (skb_valid_dst(skb))
+ skb_dst_drop(skb);
++ if (async)
++ dev_put(skb->dev);
+ gro_cells_receive(&gro_cells, skb);
+ return 0;
+ } else {
+@@ -735,6 +741,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+ sp->olen = 0;
+ if (skb_valid_dst(skb))
+ skb_dst_drop(skb);
++ if (async)
++ dev_put(skb->dev);
+ gro_cells_receive(&gro_cells, skb);
+ return err;
+ }
+@@ -745,6 +753,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+ drop_unlock:
+ spin_unlock(&x->lock);
+ drop:
++ if (async)
++ dev_put(skb->dev);
+ xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
+ kfree_skb(skb);
+ return 0;
+--
+2.53.0
+
--- /dev/null
+From a3b4c1c90c4b845072e7378f644db16db3df589f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:04:20 +0100
+Subject: serial: dz: Convert to use a platform device
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 5d7a49d60b8fda66da60e240fd7315232fa1754f upstream.
+
+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
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062326540.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/dec/platform.c | 55 ++++++++++++++++++-
+ drivers/tty/serial/dz.c | 116 +++++++++++++++++++--------------------
+ 2 files changed, 110 insertions(+), 61 deletions(-)
+
+diff --git a/arch/mips/dec/platform.c b/arch/mips/dec/platform.c
+index c4fcb8c58e01ce..fdecc91ee22abb 100644
+--- a/arch/mips/dec/platform.c
++++ b/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_device = {
+ .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);
+diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
+index 90231ec00ff070..08f2414bf1d92e 100644
+--- a/drivers/tty/serial/dz.c
++++ b/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)
+ {
+@@ -565,7 +561,7 @@ static void dz_reset(struct dz_port *dport)
+ iob();
+ udelay(2); /* 1.4us TRDY recovery. */
+ }
+- udelay(1200); /* Transmitter drain. */
++ fsleep(1200); /* Transmitter drain. */
+ }
+
+ dz_out(dport, DZ_CSR, DZ_CLR);
+@@ -682,14 +678,13 @@ static void dz_release_port(struct uart_port *uport)
+
+ 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;
+@@ -705,8 +700,7 @@ static int dz_request_port(struct uart_port *uport)
+
+ 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");
+@@ -717,7 +711,7 @@ static int dz_request_port(struct uart_port *uport)
+ 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;
+@@ -769,20 +763,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];
+@@ -790,14 +779,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);
+ }
+ }
+
+@@ -880,21 +888,14 @@ static int __init dz_console_setup(struct console *co, char *options)
+ 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,
+@@ -905,18 +906,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
+@@ -932,25 +921,32 @@ static struct uart_driver dz_reg = {
+ .cons = SERIAL_DZ_CONSOLE,
+ };
+
++static struct platform_driver dz_driver = {
++ .remove_new = __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);
+--
+2.53.0
+
--- /dev/null
+From 102c7bfd9a6514c2bd42cc4b7c8bcd740a6d3ead Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:02:50 +0100
+Subject: serial: dz: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 upstream.
+
+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 the
+transmitter of which 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+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/dz.c | 36 ++++++++++++------------------------
+ 1 file changed, 12 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
+index 3cfb68165334e2..90231ec00ff070 100644
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -572,6 +572,18 @@ static void dz_reset(struct dz_port *dport)
+ 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);
+
+@@ -655,26 +667,6 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ spin_unlock_irqrestore(&dport->port.lock, 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;
+-
+- spin_lock_irqsave(&dport->port.lock, flags);
+- if (state < 3)
+- dz_start_tx(&dport->port);
+- else
+- dz_stop_tx(&dport->port);
+- spin_unlock_irqrestore(&dport->port.lock, flags);
+-}
+-
+-
+ static const char *dz_type(struct uart_port *uport)
+ {
+ return "DZ";
+@@ -770,7 +762,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,
+@@ -895,10 +886,7 @@ static int __init dz_console_setup(struct console *co, char *options)
+ 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);
+--
+2.53.0
+
--- /dev/null
+From 4cb0b06a0f5ebe3721a8898c3e2412b918815b6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Jun 2026 04:05:05 +0100
+Subject: serial: zs: Convert to use a platform device
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7cac59d08a73cb866ec51a483a6f3fe0f531947c upstream.
+
+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
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062328480.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/dec/platform.c | 60 +++++++++++-
+ drivers/tty/serial/zs.c | 192 +++++++++++++++------------------------
+ drivers/tty/serial/zs.h | 1 -
+ 3 files changed, 129 insertions(+), 124 deletions(-)
+
+diff --git a/arch/mips/dec/platform.c b/arch/mips/dec/platform.c
+index fdecc91ee22abb..723ce16cbfc0cc 100644
+--- a/arch/mips/dec/platform.c
++++ b/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_devices[] __initdata = {
+ &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);
+diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
+index b58d5af0fdc35c..0e4471af1e9bd5 100644
+--- a/drivers/tty/serial/zs.c
++++ b/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.10";
+
+ #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
+@@ -838,16 +831,15 @@ static void zs_reset(struct zs_port *zport)
+
+ 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);
+ }
+@@ -1054,63 +1046,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;
++ 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;
+
+- 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;
+-
+- probed = 1;
+-
+- 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;
+-
+- 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];
+- }
++ 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;
++
++ 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;
++
++ 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)
+@@ -1191,20 +1182,14 @@ static int __init zs_console_setup(struct console *co, char *options)
+ 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,
+@@ -1215,23 +1200,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
+@@ -1247,47 +1215,31 @@ static struct uart_driver zs_reg = {
+ .cons = SERIAL_ZS_CONSOLE,
+ };
+
++static struct platform_driver zs_driver = {
++ .remove_new = __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);
+ }
+
+diff --git a/drivers/tty/serial/zs.h b/drivers/tty/serial/zs.h
+index 8e51f847bc03f9..e0d3c189b33f66 100644
+--- a/drivers/tty/serial/zs.h
++++ b/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. */
+
+--
+2.53.0
+
landlock-fix-handling-of-disconnected-directories.patch
usb-serial-digi_acceleport-fix-memory-corruption-wit.patch
xhci-tegra-fix-ghost-usb-device-on-dual-role-port-un.patch
+serial-dz-fix-bootconsole-handover-lockup.patch
+serial-dz-convert-to-use-a-platform-device.patch
+serial-zs-convert-to-use-a-platform-device.patch