* Re: [PATCH v2 6/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
From: Manivannan Sadhasivam @ 2026-04-13 8:06 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Richard Cochran, mhi, linux-arm-msm, linux-kernel, netdev,
Imran Shaik, Taniya Das
In-Reply-To: <20260411-tsc_timesync-v2-6-6f25f72987b3@oss.qualcomm.com>
On Sat, Apr 11, 2026 at 01:42:06PM +0530, Krishna Chaitanya Chundru wrote:
> From: Imran Shaik <imran.shaik@oss.qualcomm.com>
>
> This patch introduces the MHI PHC (PTP Hardware Clock) driver, which
> registers a PTP (Precision Time Protocol) clock and communicates with
> the MHI core to get the device side timestamps. These timestamps are
> then exposed to the PTP subsystem, enabling precise time synchronization
> between the host and the device.
>
> The following diagram illustrates the architecture and data flow:
>
> +-------------+ +--------------------+ +--------------+
> |Userspace App|<-->|Kernel PTP framework|<-->|MHI PHC Driver|
> +-------------+ +--------------------+ +--------------+
> |
> v
> +-------------------------------+ +-----------------+
> | MHI Device (Timestamp source) |<------->| MHI Core Driver |
> +-------------------------------+ +-----------------+
>
> - User space applications use the standard Linux PTP interface.
> - The PTP subsystem routes IOCTLs to the MHI PHC driver.
> - The MHI PHC driver communicates with the MHI core to fetch timestamps.
> - The MHI core interacts with the device to retrieve accurate time data.
As mentioned in cover letter, this is misleading.
>
> Co-developed-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Signed-off-by: Imran Shaik <imran.shaik@oss.qualcomm.com>
> ---
> drivers/bus/mhi/host/Kconfig | 8 ++
> drivers/bus/mhi/host/Makefile | 1 +
> drivers/bus/mhi/host/mhi_phc.c | 150 +++++++++++++++++++++++++++++++++++++
> drivers/bus/mhi/host/mhi_phc.h | 28 +++++++
> drivers/bus/mhi/host/pci_generic.c | 23 ++++++
> 5 files changed, 210 insertions(+)
>
> diff --git a/drivers/bus/mhi/host/Kconfig b/drivers/bus/mhi/host/Kconfig
> index da5cd0c9fc620ab595e742c422f1a22a2a84c7b9..b4eabf3e5c56907de93232f02962040e979c3110 100644
> --- a/drivers/bus/mhi/host/Kconfig
> +++ b/drivers/bus/mhi/host/Kconfig
> @@ -29,3 +29,11 @@ config MHI_BUS_PCI_GENERIC
> This driver provides MHI PCI controller driver for devices such as
> Qualcomm SDX55 based PCIe modems.
>
> +config MHI_BUS_PHC
> + bool "MHI PHC driver"
Why not tristate?
> + depends on MHI_BUS_PCI_GENERIC
No, this generic TSC driver cannot depend on a controller driver. It should
purely act as a library.
> + help
> + This driver provides Precision Time Protocol (PTP) clock and
> + communicates with MHI PCI driver to get the device side timestamp,
> + which enables precise time synchronization between the host and
> + the device.
> diff --git a/drivers/bus/mhi/host/Makefile b/drivers/bus/mhi/host/Makefile
> index 859c2f38451c669b3d3014c374b2b957c99a1cfe..5ba244fe7d596834ea535797efd3428963ba0ed0 100644
> --- a/drivers/bus/mhi/host/Makefile
> +++ b/drivers/bus/mhi/host/Makefile
> @@ -4,3 +4,4 @@ mhi-$(CONFIG_MHI_BUS_DEBUG) += debugfs.o
>
> obj-$(CONFIG_MHI_BUS_PCI_GENERIC) += mhi_pci_generic.o
> mhi_pci_generic-y += pci_generic.o
> +mhi_pci_generic-$(CONFIG_MHI_BUS_PHC) += mhi_phc.o
> diff --git a/drivers/bus/mhi/host/mhi_phc.c b/drivers/bus/mhi/host/mhi_phc.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..fa04eb7f6025fa281d86c0a45b5f7d3e61f5ce12
> --- /dev/null
> +++ b/drivers/bus/mhi/host/mhi_phc.c
> @@ -0,0 +1,150 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.
2026
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
Are these headers really needed?
> +#include <linux/mhi.h>
> +#include <linux/ptp_clock_kernel.h>
> +#include "mhi_phc.h"
> +
> +#define NSEC 1000000000ULL
Use existing NSEC_PER_SEC
> +
> +/**
> + * struct mhi_phc_dev - MHI PHC device
> + * @ptp_clock: associated PTP clock
> + * @ptp_clock_info: PTP clock information
> + * @mhi_dev: associated mhi device object
> + * @lock: spinlock
What spinlock? and what is it used for?
> + * @enabled: Flag to track the state of the MHI device
> + */
> +struct mhi_phc_dev {
> + struct ptp_clock *ptp_clock;
> + struct ptp_clock_info ptp_clock_info;
Use single space.
> + struct mhi_device *mhi_dev;
> + spinlock_t lock;
> + bool enabled;
> +};
> +
> +static int qcom_ptp_gettimex64(struct ptp_clock_info *ptp, struct timespec64 *ts,
> + struct ptp_system_timestamp *sts)
> +{
> + struct mhi_phc_dev *phc_dev = container_of(ptp, struct mhi_phc_dev, ptp_clock_info);
> + struct mhi_timesync_info time;
> + ktime_t ktime_cur;
> + unsigned long flags;
> + int ret;
> +
> + spin_lock_irqsave(&phc_dev->lock, flags);
Why spinlock ant not mutex, especially when mhi_get_remote_tsc_time_sync()
performs MMIO reads 4 times with ASPM enabled?
I also doubt that you really need lock here.
> + if (!phc_dev->enabled) {
I don't see a a value of this check. If the intention is to prevent PHC from
being disabled when gettimex64() callback is executing, then kernel POSIX clock
layer already provides that guarantee for you. You don't need to reinvent the
wheel again.
> + ret = -ENODEV;
> + goto err;
> + }
> +
> + ret = mhi_get_remote_tsc_time_sync(phc_dev->mhi_dev, &time);
> + if (ret)
> + goto err;
> +
> + ktime_cur = time.t_dev_hi * NSEC + time.t_dev_lo;
> + *ts = ktime_to_timespec64(ktime_cur);
> +
> + dev_dbg(&phc_dev->mhi_dev->dev, "TSC time stamps sec:%u nsec:%u current:%lld\n",
> + time.t_dev_hi, time.t_dev_lo, ktime_cur);
Move to tracepoint.
> +
> + /* Update pre and post timestamps for PTP_SYS_OFFSET_EXTENDED*/
> + if (sts != NULL) {
if (sts)
> + sts->pre_ts = ktime_to_timespec64(time.t_host_pre);
> + sts->post_ts = ktime_to_timespec64(time.t_host_post);
> + dev_dbg(&phc_dev->mhi_dev->dev, "pre:%lld post:%lld\n",
> + time.t_host_pre, time.t_host_post);
> + }
> +
> +err:
> + spin_unlock_irqrestore(&phc_dev->lock, flags);
> +
> + return ret;
> +}
> +
> +int mhi_phc_start(struct mhi_controller *mhi_cntrl)
> +{
> + struct mhi_phc_dev *phc_dev = dev_get_drvdata(&mhi_cntrl->mhi_dev->dev);
> + unsigned long flags;
> +
> + if (!phc_dev) {
> + dev_err(&mhi_cntrl->mhi_dev->dev, "Driver data is NULL\n");
Can this really happen? Even so, I wouldn't add an error print for this cosmetic
check.
> + return -ENODEV;
> + }
> +
> + spin_lock_irqsave(&phc_dev->lock, flags);
> + phc_dev->enabled = true;
> + spin_unlock_irqrestore(&phc_dev->lock, flags);
> +
> + return 0;
> +}
> +
> +int mhi_phc_stop(struct mhi_controller *mhi_cntrl)
> +{
> + struct mhi_phc_dev *phc_dev = dev_get_drvdata(&mhi_cntrl->mhi_dev->dev);
> + unsigned long flags;
> +
> + if (!phc_dev) {
> + dev_err(&mhi_cntrl->mhi_dev->dev, "Driver data is NULL\n");
> + return -ENODEV;
> + }
Same here.
> +
> + spin_lock_irqsave(&phc_dev->lock, flags);
> + phc_dev->enabled = false;
> + spin_unlock_irqrestore(&phc_dev->lock, flags);
> +
> + return 0;
Getting rid of the check and 'phc_dev->enabled' flag means, I see no point in
mhi_phc_{start/stop}() functions.
> +}
> +
> +static struct ptp_clock_info qcom_ptp_clock_info = {
> + .owner = THIS_MODULE,
> + .gettimex64 = qcom_ptp_gettimex64,
> +};
> +
> +int mhi_phc_init(struct mhi_controller *mhi_cntrl)
> +{
> + struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
> + struct mhi_phc_dev *phc_dev;
> + int ret;
> +
> + phc_dev = devm_kzalloc(&mhi_dev->dev, sizeof(*phc_dev), GFP_KERNEL);
> + if (!phc_dev)
> + return -ENOMEM;
> +
> + phc_dev->mhi_dev = mhi_dev;
> +
> + phc_dev->ptp_clock_info = qcom_ptp_clock_info;
> + strscpy(phc_dev->ptp_clock_info.name, mhi_dev->name, PTP_CLOCK_NAME_LEN);
> +
> + spin_lock_init(&phc_dev->lock);
> +
> + phc_dev->ptp_clock = ptp_clock_register(&phc_dev->ptp_clock_info, &mhi_dev->dev);
> + if (IS_ERR(phc_dev->ptp_clock)) {
> + ret = PTR_ERR(phc_dev->ptp_clock);
> + dev_err(&mhi_dev->dev, "Failed to register PTP clock\n");
> + phc_dev->ptp_clock = NULL;
> + return ret;
> + }
> +
> + dev_set_drvdata(&mhi_dev->dev, phc_dev);
> +
> + dev_dbg(&mhi_dev->dev, "probed MHI PHC dev: %s\n", mhi_dev->name);
Drop this spam.
> + return 0;
> +};
> +
> +void mhi_phc_exit(struct mhi_controller *mhi_cntrl)
> +{
> + struct mhi_phc_dev *phc_dev = dev_get_drvdata(&mhi_cntrl->mhi_dev->dev);
> +
> + if (!phc_dev)
> + return;
> +
> + /* disable the node */
Remove this comment.
> + ptp_clock_unregister(phc_dev->ptp_clock);
> + phc_dev->enabled = false;
> +}
> diff --git a/drivers/bus/mhi/host/mhi_phc.h b/drivers/bus/mhi/host/mhi_phc.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..e6b0866bc768ba5a8ac3e4c40a99aa2050db1389
> --- /dev/null
> +++ b/drivers/bus/mhi/host/mhi_phc.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifdef CONFIG_MHI_BUS_PHC
#if IS_ENABLED()
> +int mhi_phc_init(struct mhi_controller *mhi_cntrl);
> +int mhi_phc_start(struct mhi_controller *mhi_cntrl);
> +int mhi_phc_stop(struct mhi_controller *mhi_cntrl);
> +void mhi_phc_exit(struct mhi_controller *mhi_cntrl);
> +#else
> +static inline int mhi_phc_init(struct mhi_controller *mhi_cntrl)
> +{
> + return 0;
> +}
> +
> +static inline int mhi_phc_start(struct mhi_controller *mhi_cntrl)
> +{
> + return 0;
> +}
> +
> +static inline int mhi_phc_stop(struct mhi_controller *mhi_cntrl)
> +{
> + return 0;
> +}
> +
> +static inline void mhi_phc_exit(struct mhi_controller *mhi_cntrl) {}
> +#endif
> diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
> index b1122c7224bdd469406d96af6d3df342040e1002..6cba5cecd1adb40396bba30c9b2a551898dce871 100644
> --- a/drivers/bus/mhi/host/pci_generic.c
> +++ b/drivers/bus/mhi/host/pci_generic.c
> @@ -16,6 +16,7 @@
> #include <linux/pm_runtime.h>
> #include <linux/timer.h>
> #include <linux/workqueue.h>
> +#include "mhi_phc.h"
>
> #define MHI_PCI_DEFAULT_BAR_NUM 0
>
> @@ -1044,6 +1045,7 @@ struct mhi_pci_device {
> struct timer_list health_check_timer;
> unsigned long status;
> bool reset_on_remove;
> + bool mhi_phc_init_done;
> };
>
> #ifdef readq
> @@ -1084,6 +1086,7 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
> enum mhi_callback cb)
> {
> struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
> + struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
>
> /* Nothing to do for now */
> switch (cb) {
> @@ -1091,9 +1094,21 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
> case MHI_CB_SYS_ERROR:
> dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb);
> pm_runtime_forbid(&pdev->dev);
> + /* Stop PHC */
> + if (mhi_cntrl->tsc_timesync)
> + mhi_phc_stop(mhi_cntrl);
> break;
> case MHI_CB_EE_MISSION_MODE:
> pm_runtime_allow(&pdev->dev);
> + /* Start PHC */
> + if (mhi_cntrl->tsc_timesync) {
> + if (!mhi_pdev->mhi_phc_init_done) {
> + mhi_phc_init(mhi_cntrl);
> + mhi_pdev->mhi_phc_init_done = true;
> + }
This looks weird. Since MISSION_MODE can happen multiple times when the device
is attached, shouldn't you be doing mhi_phc_init() multiple times with the
corresponding mhi_phc_exit() during MHI_CB_SYS_ERROR?
Right now, you call mhi_phc_init() during MISSION_MODE and mhi_phc_exit()
during mhi_pci_remove(). What is the point of keeping /dev/ptpX if the firmware
is crashed?
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* [PATCH net-next v3] net: mctp: don't require received header reserved bits to be zero
From: wit_yuan @ 2026-04-13 8:03 UTC (permalink / raw)
To: jk
Cc: yuanzhaoming901030, yuanzm2, matt, davem, edumazet, kuba, pabeni,
netdev, linux-kernel
From: Yuan Zhaoming <yuanzm2@lenovo.com>
From the MCTP Base specification (DSP0236 v1.2.1), the first byte of
the MCTP header contains a 4 bit reserved field, and 4 bit version.
On our current receive path, we require those 4 reserved bits to be
zero, but the 9500-8i card is non-conformant, and may set these
reserved bits.
DSP0236 states that the reserved bits must be written as zero, and
ignored when read. While the device might not conform to the former,
we should accept these message to conform to the latter.
Relax our check on the MCTP version byte to allow non-zero bits in the
reserved field.
Signed-off-by: Yuan Zhaoming <yuanzm2@lenovo.com>
---
v2: https://lore.kernel.org/netdev/20260410144339.0d1b289a@kernel.org/T/#t
v1: https://lore.kernel.org/netdev/ff147a3f0d27ef2aa6026cc86f9113d56a8c61ac.camel@codeconstruct.com.au/T/#t
---
include/net/mctp.h | 3 +++
net/mctp/route.c | 8 ++++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/include/net/mctp.h b/include/net/mctp.h
index e1e0a69..d8bf907 100644
--- a/include/net/mctp.h
+++ b/include/net/mctp.h
@@ -26,6 +26,9 @@ struct mctp_hdr {
#define MCTP_VER_MIN 1
#define MCTP_VER_MAX 1
+/* Definitions for ver field */
+#define MCTP_HDR_VER_MASK GENMASK(3, 0)
+
/* Definitions for flags_seq_tag field */
#define MCTP_HDR_FLAG_SOM BIT(7)
#define MCTP_HDR_FLAG_EOM BIT(6)
diff --git a/net/mctp/route.c b/net/mctp/route.c
index e69c6f7..62517c9 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -439,6 +439,7 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
struct mctp_hdr *mh;
unsigned int netid;
unsigned long f;
+ u8 ver;
u8 tag, flags;
int rc;
@@ -467,7 +468,8 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
netid = mctp_cb(skb)->net;
skb_pull(skb, sizeof(struct mctp_hdr));
- if (mh->ver != 1)
+ ver = mh->ver & MCTP_HDR_VER_MASK;
+ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
goto out;
flags = mh->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
@@ -1316,6 +1318,7 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
struct mctp_skb_cb *cb;
struct mctp_dst dst;
struct mctp_hdr *mh;
+ u8 ver;
int rc;
rcu_read_lock();
@@ -1334,7 +1337,8 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
/* We have enough for a header; decode and route */
mh = mctp_hdr(skb);
- if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
+ ver = mh->ver & MCTP_HDR_VER_MASK;
+ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
goto err_drop;
/* source must be valid unicast or null; drop reserved ranges and
--
2.43.0
^ permalink raw reply related
* [RFC PATCH 0/2] Decouple ftrace/livepatch from module loader via notifier priority and reverse traversal
From: chensong_2000 @ 2026-04-13 8:01 UTC (permalink / raw)
To: rafael, lenb, mturquette, sboyd, viresh.kumar, agk, snitzer,
mpatocka, bmarzins, song, yukuai, linan122, jason.wessel, danielt,
dianders, horms, davem, edumazet, kuba, pabeni, paulmck, frederic,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, jpoimboe,
jikos, mbenes, pmladek, joe.lawrence, rostedt, mhiramat,
mark.rutland, mathieu.desnoyers
Cc: linux-modules, linux-kernel, linux-trace-kernel, linux-acpi,
linux-clk, linux-pm, live-patching, dm-devel, linux-raid,
kgdb-bugreport, netdev, Song Chen
From: Song Chen <chensong_2000@189.cn>
This patchset addresses a long-standing tight coupling between the
module loader and two of its key consumers: ftrace and livepatch.
Background:
The module loader currently hard-codes direct calls to
ftrace_module_enable(), klp_module_coming(), klp_module_going() and
ftrace_release_mod() inside prepare_coming_module() and the module
unload path. This hard-coding was necessary because the module notifier
chain could not guarantee the strict call ordering that ftrace and
livepatch require:
During MODULE_STATE_COMING, ftrace must run before livepatch, so
that per-module function records are ready before livepatch registers
its ftrace hooks.
During MODULE_STATE_GOING, livepatch must run before ftrace, so that
livepatch removes its hooks before ftrace releases those records.
This symmetric setup/teardown ordering could not be expressed through
the notifier chain because the chain only supported forward (descending
priority) traversal. Without reverse traversal, it was impossible to
guarantee that the GOING order would be the strict inverse of the
COMING order using a single priority value per notifier.
Patch 1 - notifier: replace single-linked list with double-linked list.
Patch 2 - ftrace/klp: decouple from module loader using notifier
priority.
headsup: somehow the smtp of my mailbox doesn't work very well lately,
if i receive return letter, i have to resend, sorry in advance.
Song Chen (2):
kernel/notifier: replace single-linked list with double-linked list
for reverse traversal
kernel/module: Decouple klp and ftrace from load_module
drivers/acpi/sleep.c | 1 -
drivers/clk/clk.c | 2 +-
drivers/cpufreq/cpufreq.c | 2 +-
drivers/md/dm-integrity.c | 1 -
drivers/md/md.c | 1 -
include/linux/module.h | 8 ++
include/linux/notifier.h | 26 ++---
kernel/debug/debug_core.c | 1 -
kernel/livepatch/core.c | 29 ++++-
kernel/module/main.c | 34 +++---
kernel/notifier.c | 219 ++++++++++++++++++++++++++++++++------
kernel/trace/ftrace.c | 38 +++++++
net/ipv4/nexthop.c | 2 +-
13 files changed, 290 insertions(+), 74 deletions(-)
--
2.43.0
^ permalink raw reply
* (no subject)
From: Harry Yoo (Oracle) @ 2026-04-13 7:58 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, Vlastimil Babka, linux-mm, Arnd Bergmann, x86, Lu Baolu,
iommu, Michael Grzeschik, netdev, linux-wireless, Herbert Xu,
linux-crypto, David Woodhouse, Bernie Thompson, linux-fbdev,
Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
sparclinux, Hao Li, Christoph Lameter, David Rientjes,
Roman Gushchin, Shengming Hu
Bcc:
Subject: Re: [patch 14/38] slub: Use prandom instead of get_cycles()
Reply-To:
In-Reply-To: <20260410120318.525653921@kernel.org>
On Fri, Apr 10, 2026 at 02:19:37PM +0200, Thomas Gleixner wrote:
> The decision whether to scan remote nodes is based on a 'random' number
> retrieved via get_cycles(). get_cycles() is about to be removed.
>
> There is already prandom state in the code, so use that instead.
>
> Signed-off-by: Thomas Gleixner <tglx@kernel.org>
> Cc: Vlastimil Babka <vbabka@kernel.org>
> Cc: linux-mm@kvack.org
> ---
Acked-by: Harry Yoo (Oracle) <harry@kernel.org>
Is this for this merge window?
This may conflict with upcoming changes on freelist shuffling [1]
(not queued for slab/for-next yet though), but it should be easy to
resolve.
[Cc'ing Shengming and SLAB ALLOCATOR folks]
[1] https://lore.kernel.org/linux-mm/20260409204352095kKWVYKtZImN59ybO6iRNj@zte.com.cn
--
Cheers,
Harry / Hyeonggon
> mm/slub.c | 37 +++++++++++++++++++++++--------------
> 1 file changed, 23 insertions(+), 14 deletions(-)
>
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -3302,6 +3302,25 @@ static inline struct slab *alloc_slab_pa
> return slab;
> }
>
> +#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
> +static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
> +
> +static unsigned int slab_get_prandom_state(unsigned int limit)
> +{
> + struct rnd_state *state;
> + unsigned int res;
> +
> + /*
> + * An interrupt or NMI handler might interrupt and change
> + * the state in the middle, but that's safe.
> + */
> + state = &get_cpu_var(slab_rnd_state);
> + res = prandom_u32_state(state) % limit;
> + put_cpu_var(slab_rnd_state);
> + return res;
> +}
> +#endif
> +
> #ifdef CONFIG_SLAB_FREELIST_RANDOM
> /* Pre-initialize the random sequence cache */
> static int init_cache_random_seq(struct kmem_cache *s)
> @@ -3365,8 +3384,6 @@ static void *next_freelist_entry(struct
> return (char *)start + idx;
> }
>
> -static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state);
> -
> /* Shuffle the single linked freelist based on a random pre-computed sequence */
> static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab,
> bool allow_spin)
> @@ -3383,15 +3400,7 @@ static bool shuffle_freelist(struct kmem
> if (allow_spin) {
> pos = get_random_u32_below(freelist_count);
> } else {
> - struct rnd_state *state;
> -
> - /*
> - * An interrupt or NMI handler might interrupt and change
> - * the state in the middle, but that's safe.
> - */
> - state = &get_cpu_var(slab_rnd_state);
> - pos = prandom_u32_state(state) % freelist_count;
> - put_cpu_var(slab_rnd_state);
> + pos = slab_get_prandom_state(freelist_count);
> }
>
> page_limit = slab->objects * s->size;
> @@ -3882,7 +3891,7 @@ static void *get_from_any_partial(struct
> * with available objects.
> */
> if (!s->remote_node_defrag_ratio ||
> - get_cycles() % 1024 > s->remote_node_defrag_ratio)
> + slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
> return NULL;
>
> do {
> @@ -7102,7 +7111,7 @@ static unsigned int
>
> /* see get_from_any_partial() for the defrag ratio description */
> if (!s->remote_node_defrag_ratio ||
> - get_cycles() % 1024 > s->remote_node_defrag_ratio)
> + slab_get_prandom_state(1024) > s->remote_node_defrag_ratio)
> return 0;
>
> do {
> @@ -8421,7 +8430,7 @@ void __init kmem_cache_init_late(void)
> flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM | WQ_PERCPU,
> 0);
> WARN_ON(!flushwq);
> -#ifdef CONFIG_SLAB_FREELIST_RANDOM
> +#if defined(CONFIG_SLAB_FREELIST_RANDOM) || defined(CONFIG_NUMA)
> prandom_init_once(&slab_rnd_state);
> #endif
> }
>
>
^ permalink raw reply
* [PATCH] net/sched: sch_dualpi2: fix NULL pointer dereference in dualpi2_change()
From: Kito Xu (veritas501) @ 2026-04-13 7:57 UTC (permalink / raw)
To: Jamal Hadi Salim, Jiri Pirko, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Chia-Yu Chang, netdev, linux-kernel,
Kito Xu (veritas501)
dualpi2_change() uses a trim loop to enforce the new queue limit after a
configuration change. The loop calls qdisc_dequeue_internal(sch, true)
which only dequeues from the C-queue (sch->q) and the requeue list
(sch->gso_skb). It does not dequeue from the L-queue (q->l_queue).
However, the loop continuation condition checks qdisc_qlen(sch), which
reflects the total packet count across both queues because
dualpi2_enqueue_skb() manually increments sch->q.qlen for L-queue
packets (line 418). Similarly, q->memory_used accounts for memory from
both queues.
When all packets reside in the L-queue and the C-queue is empty, the
loop condition remains true but qdisc_dequeue_internal() returns NULL.
The subsequent skb->truesize dereference causes a NULL pointer oops.
An unprivileged user can trigger this from a user namespace:
1. unshare(CLONE_NEWUSER | CLONE_NEWNET)
2. Create a dummy device and attach dualpi2 qdisc
3. Send ECT(1)-marked packets to fill the L-queue
4. Reduce the qdisc limit via RTM_NEWQDISC
[ 17.521319] Oops: general protection fault, probably for non-canonical address 0xdffffc000000001a: 0000 [#1] SMP KASAN NOPTI
[ 17.525206] KASAN: null-ptr-deref in range [0x00000000000000d0-0x00000000000000d7]
[ 17.527710] CPU: 3 UID: 1000 PID: 171 Comm: poc Not tainted 7.0.0-rc7-next-20260410 #10 PREEMPTLAZY
[ 17.530795] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 17.533301] RIP: 0010:dualpi2_change+0xd09/0x1c00
[ 17.535472] Code: ef 83 e7 07 83 c7 03 44 38 cf 7c 09 45 84 c9 0f 85 fb 06 00 00 4c 8d 96 d0 00 00 00 44 8b 8b 5c 02 00 00 4c 89 d7 48 c1 ef 03 <0f> b6 3c 2f 40 84 ff 74 0a 40 80 ff 03 0f 8e fc 06 00 00 4c 89 c7
[ 17.540294] RSP: 0018:ffffc90000bb7360 EFLAGS: 00000202
[ 17.542574] RAX: 0000000000014c3a RBX: ffff88800fe18000 RCX: ffffed1001fc3010
[ 17.543461] RDX: ffff88800fe1825c RSI: 0000000000000000 RDI: 000000000000001a
[ 17.544145] RBP: dffffc0000000000 R08: 0000000000000028 R09: 0000000000171240
[ 17.546982] R10: 00000000000000d0 R11: ffff88800fe18080 R12: ffff88800fe180d0
[ 17.549652] R13: ffff88800fe1825c R14: ffff88800fe18014 R15: ffff88800fe180f8
[ 17.552566] FS: 000000002b3533c0(0000) GS:ffff8880e260f000(0000) knlGS:0000000000000000
[ 17.555942] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 17.556472] CR2: dffffc000000001a CR3: 000000000fb01000 CR4: 00000000003006f0
[ 17.559321] Call Trace:
[ 17.560392] <TASK>
[ 17.560993] ? __asan_memset+0x23/0x50
[ 17.562609] ? __pfx_dualpi2_change+0x10/0x10
[ 17.564265] ? mutex_lock+0x7e/0xd0
[ 17.565628] ? __pfx_mutex_lock+0x10/0x10
[ 17.566886] ? nla_strcmp+0x20/0x100
[ 17.568354] tc_modify_qdisc+0x4ee/0x1d60
[ 17.570211] ? __pfx_tc_modify_qdisc+0x10/0x10
[ 17.571293] ? __pfx_stack_trace_save+0x10/0x10
[ 17.572894] ? mutex_lock+0x7e/0xd0
[ 17.573548] ? __pfx_mutex_lock+0x10/0x10
[ 17.574583] ? security_capable+0x80/0x110
[ 17.576051] rtnetlink_rcv_msg+0x548/0xc10
[ 17.577902] ? __pfx_rtnetlink_rcv_msg+0x10/0x10
[ 17.579170] netlink_rcv_skb+0x12a/0x390
[ 17.580902] ? __pfx_rtnetlink_rcv_msg+0x10/0x10
[ 17.581817] ? __pfx_netlink_rcv_skb+0x10/0x10
[ 17.583064] ? __kasan_slab_alloc+0x89/0x90
[ 17.584753] netlink_unicast+0x5b8/0x980
[ 17.585677] ? __pfx_netlink_unicast+0x10/0x10
[ 17.587312] ? rpm_suspend+0x492/0xe70
[ 17.588612] ? __pfx___alloc_skb+0x10/0x10
[ 17.590473] ? __check_object_size+0x45e/0x650
[ 17.592327] ? rpm_suspend+0x492/0xe70
[ 17.593589] netlink_sendmsg+0x722/0xbb0
[ 17.594452] ? __pfx_netlink_sendmsg+0x10/0x10
[ 17.595192] ? __import_iovec+0x33d/0x5b0
[ 17.596582] ? __pfx_netlink_sendmsg+0x10/0x10
[ 17.598003] ____sys_sendmsg+0x8cf/0xb30
[ 17.599168] ? __pfx_____sys_sendmsg+0x10/0x10
[ 17.599921] ? __pfx_copy_msghdr_from_user+0x10/0x10
[ 17.601616] ? update_cfs_rq_load_avg+0x5a/0x560
[ 17.602924] ___sys_sendmsg+0x104/0x190
[ 17.604318] ? update_irq_load_avg+0xbd/0x18b0
[ 17.604977] ? __pfx____sys_sendmsg+0x10/0x10
[ 17.606505] __sys_sendmsg+0x124/0x1c0
[ 17.607877] ? __pfx___sys_sendmsg+0x10/0x10
[ 17.609867] ? __pfx_handle_softirqs+0x10/0x10
[ 17.611017] do_syscall_64+0x64/0x680
[ 17.612277] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 17.614334] RIP: 0033:0x429d6b
[ 17.615451] Code: 48 89 e5 48 83 ec 20 89 55 ec 48 89 75 f0 89 7d f8 e8 99 e5 02 00 8b 55 ec 48 8b 75 f0 41 89 c0 8b 7d f8 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 2d 44 89 c7 48 89 45 f8 e8 f1 e5 02 00 48 8b
[ 17.619777] RSP: 002b:00007fff81a32560 EFLAGS: 00000293 ORIG_RAX: 000000000000002e
[ 17.621686] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 0000000000429d6b
[ 17.623171] RDX: 0000000000000000 RSI: 00007fff81a325e0 RDI: 0000000000000003
[ 17.625433] RBP: 00007fff81a32580 R08: 0000000000000000 R09: 00007fff81a32797
[ 17.627317] R10: 0000000000000000 R11: 0000000000000293 R12: 00007fff81a32a38
[ 17.629562] R13: 00007fff81a32a48 R14: 00000000004c4848 R15: 0000000000000001
[ 17.630409] </TASK>
[ 17.631205] Modules linked in:
[ 17.633251] ---[ end trace 0000000000000000 ]---
[ 17.634487] RIP: 0010:dualpi2_change+0xd09/0x1c00
[ 17.636511] Code: ef 83 e7 07 83 c7 03 44 38 cf 7c 09 45 84 c9 0f 85 fb 06 00 00 4c 8d 96 d0 00 00 00 44 8b 8b 5c 02 00 00 4c 89 d7 48 c1 ef 03 <0f> b6 3c 2f 40 84 ff 74 0a 40 80 ff 03 0f 8e fc 06 00 00 4c 89 c7
[ 17.641850] RSP: 0018:ffffc90000bb7360 EFLAGS: 00000202
[ 17.643001] RAX: 0000000000014c3a RBX: ffff88800fe18000 RCX: ffffed1001fc3010
[ 17.645928] RDX: ffff88800fe1825c RSI: 0000000000000000 RDI: 000000000000001a
[ 17.647603] RBP: dffffc0000000000 R08: 0000000000000028 R09: 0000000000171240
[ 17.649912] R10: 00000000000000d0 R11: ffff88800fe18080 R12: ffff88800fe180d0
[ 17.652899] R13: ffff88800fe1825c R14: ffff88800fe18014 R15: ffff88800fe180f8
[ 17.655310] FS: 000000002b3533c0(0000) GS:ffff8880e260f000(0000) knlGS:0000000000000000
[ 17.656751] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 17.659213] CR2: dffffc000000001a CR3: 000000000fb01000 CR4: 00000000003006f0
[ 17.661915] Kernel panic - not syncing: Fatal exception in interrupt
[ 17.665688] Kernel Offset: disabled
[ 17.665980] Rebooting in 1 seconds..
Fix this by adding a NULL check after qdisc_dequeue_internal(). When
the C-queue is exhausted but L-queue packets keep qdisc_qlen(sch) above
the limit, the loop breaks safely. Remaining excess L-queue packets will
be drained by the normal dequeue path.
Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc")
Signed-off-by: Kito Xu (veritas501) <hxzene@gmail.com>
---
net/sched/sch_dualpi2.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index fe6f5e889625..746c0e506024 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -870,6 +870,9 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt,
q->memory_used > q->memory_limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, true);
+ if (!skb)
+ break;
+
q->memory_used -= skb->truesize;
qdisc_qstats_backlog_dec(sch, skb);
rtnl_qdisc_drop(skb, sch);
--
2.43.0
^ permalink raw reply related
* [PATCH net 2/2] net: enetc: fix NTMP DMA use-after-free issue
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260413075250.281653-1-wei.fang@nxp.com>
The AI-generated review reported a potential DMA use-after-free issue
[1]. If netc_xmit_ntmp_cmd() times out and returns an error, the pending
command is not explicitly aborted, while ntmp_free_data_mem()
unconditionally frees the DMA buffer. If the buffer has already been
reallocated elsewhere, this may lead to silent memory corruption. Because
the hardware eventually processes the pending command and perform a DMA
write of the response to the physical address of the freed buffer.
To resolve this issue, this patch does the following modifications:
1. Convert cbdr->ring_lock from a spinlock to a mutex
The lock was originally a spinlock in case NTMP operations might be
invoked from atomic context. After downstream support for all NTMP
tables, no such usage has materialized. A mutex lock is now required
because the driver now needs to reclaim used BDs and release associated
DMA memory within the lock's context, while dma_free_coherent() might
sleep.
2. Introduce software command BD (struct netc_swcbd)
The hardware write-back overwrites the addr and len fields of the BD,
so the driver cannot rely on the hardware BD to free the associated DMA
memory. The driver now maintains a software shadow BD storing the DMA
buffer pointer, DMA address, and size. And netc_xmit_ntmp_cmd() only
reclaims older BDs when the number of used BDs reaches
NETC_CBDR_CLEAN_WORK (16). The software BD enables correct DMA memory
release. With this, struct ntmp_dma_buf and ntmp_free_data_mem() are no
longer needed and are removed.
These changes eliminate the DMA use-after-free condition and ensure safe
and consistent BD reclamation and DMA buffer lifecycle management.
Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP")
Link: https://lore.kernel.org/netdev/20260403011729.1795413-1-kuba@kernel.org/ # [1]
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/ntmp.c | 158 ++++++++++--------
.../ethernet/freescale/enetc/ntmp_private.h | 8 +-
include/linux/fsl/ntmp.h | 9 +-
3 files changed, 93 insertions(+), 82 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 1b1ff0446d0a..3efc65443113 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -7,6 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/netc_global.h>
#include <linux/iopoll.h>
+#include <linux/vmalloc.h>
#include "ntmp_private.h"
@@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
if (!cbdr->addr_base)
return -ENOMEM;
+ cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd));
+ if (!cbdr->swcbd) {
+ dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base);
+ return -ENOMEM;
+ }
+
cbdr->dma_size = size;
cbdr->bd_num = cbd_num;
cbdr->regs = *regs;
@@ -52,7 +59,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
NTMP_BASE_ADDR_ALIGN);
- spin_lock_init(&cbdr->ring_lock);
+ mutex_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
@@ -71,10 +78,25 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
}
EXPORT_SYMBOL_GPL(ntmp_init_cbdr);
+static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd)
+{
+ dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ swcbd->buf, swcbd->dma);
+}
+
void ntmp_free_cbdr(struct netc_cbdr *cbdr)
{
/* Disable the Control BD Ring */
netc_write(cbdr->regs.mr, 0);
+
+ for (int i = 0; i < cbdr->bd_num; i++) {
+ struct netc_swcbd *swcbd = &cbdr->swcbd[i];
+
+ if (swcbd->dma)
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ }
+
+ vfree(cbdr->swcbd);
dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base,
cbdr->dma_base);
memset(cbdr, 0, sizeof(*cbdr));
@@ -94,24 +116,28 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index)
static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
{
- union netc_cbd *cbd;
- int i;
+ int i = cbdr->next_to_clean;
- i = cbdr->next_to_clean;
while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
- cbd = ntmp_get_cbd(cbdr, i);
+ union netc_cbd *cbd = ntmp_get_cbd(cbdr, i);
+ struct netc_swcbd *swcbd = &cbdr->swcbd[i];
+
+ ntmp_free_data_mem(cbdr->dev, swcbd);
+ memset(swcbd, 0, sizeof(*swcbd));
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
}
+ dma_wmb();
cbdr->next_to_clean = i;
}
-static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
+static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd,
+ struct netc_swcbd *swcbd)
{
union netc_cbd *cur_cbd;
struct netc_cbdr *cbdr;
- int i, err;
+ int i, err, used_bds;
u16 status;
u32 val;
@@ -120,14 +146,21 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
*/
cbdr = &user->ring[0];
- spin_lock_bh(&cbdr->ring_lock);
+ mutex_lock(&cbdr->ring_lock);
- if (unlikely(!ntmp_get_free_cbd_num(cbdr)))
+ used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr);
+ if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) {
ntmp_clean_cbdr(cbdr);
+ if (unlikely(!ntmp_get_free_cbd_num(cbdr))) {
+ err = -EBUSY;
+ goto cbdr_unlock;
+ }
+ }
i = cbdr->next_to_use;
cur_cbd = ntmp_get_cbd(cbdr, i);
*cur_cbd = *cbd;
+ cbdr->swcbd[i] = *swcbd;
dma_wmb();
/* Update producer index of both software and hardware */
@@ -135,10 +168,9 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
- err = read_poll_timeout_atomic(netc_read, val,
- (val & NETC_CBDRCIR_INDEX) == i,
- NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
- true, cbdr->regs.cir);
+ err = read_poll_timeout(netc_read, val, (val & NETC_CBDRCIR_INDEX) == i,
+ NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
+ true, cbdr->regs.cir);
if (unlikely(err))
goto cbdr_unlock;
@@ -155,36 +187,28 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
dev_err(user->dev, "Command BD error: 0x%04x\n", status);
}
- ntmp_clean_cbdr(cbdr);
- dma_wmb();
-
cbdr_unlock:
- spin_unlock_bh(&cbdr->ring_lock);
+ mutex_unlock(&cbdr->ring_lock);
return err;
}
-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
+static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd,
+ void **buf_align)
{
void *buf;
- buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- &data->dma, GFP_KERNEL);
+ buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN,
+ &swcbd->dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- data->buf = buf;
+ swcbd->buf = buf;
*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
return 0;
}
-static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
-{
- dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
- data->buf, data->dma);
-}
-
static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma,
int len, int table_id, int cmd,
int access_method)
@@ -235,37 +259,36 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id,
u8 tbl_ver, u32 entry_id, u32 req_len,
u32 resp_len)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = max(req_len, resp_len),
};
struct ntmp_req_by_eid *req;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len),
tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete entry 0x%x of %s, err: %pe",
entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
- u32 len, struct ntmp_req_by_eid *req,
- dma_addr_t dma, bool compare_eid)
+ struct ntmp_req_by_eid *req,
+ struct netc_swcbd *swcbd,
+ bool compare_eid)
{
+ u32 len = NTMP_LEN(sizeof(*req), swcbd->size);
struct ntmp_cmn_resp_query *resp;
int cmd = NTMP_CMD_QUERY;
union netc_cbd cbd;
@@ -277,8 +300,9 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
cmd = NTMP_CMD_QU;
/* Request header */
- ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd,
+ NTMP_AM_ENTRY_ID);
+ err = netc_xmit_ntmp_cmd(user, &cbd, swcbd);
if (err) {
dev_err(user->dev,
"Failed to query entry 0x%x of %s, err: %pe\n",
@@ -306,15 +330,14 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_req_add),
};
struct maft_req_add *req;
union netc_cbd cbd;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -323,15 +346,13 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
req->keye = maft->keye;
req->cfge = maft->cfge;
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n",
entry_id, ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
@@ -339,33 +360,27 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id,
struct maft_entry_data *maft)
{
- struct ntmp_dma_buf data = {
- .dev = user->dev,
+ struct netc_swcbd swcbd = {
.size = sizeof(struct maft_resp_query),
};
struct maft_resp_query *resp;
struct ntmp_req_by_eid *req;
int err;
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id);
- err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID,
- NTMP_LEN(sizeof(*req), data.size),
- req, data.dma, true);
+ err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID, req, &swcbd, true);
if (err)
- goto end;
+ return err;
resp = (struct maft_resp_query *)req;
maft->keye = resp->keye;
maft->cfge = resp->cfge;
-end:
- ntmp_free_data_mem(&data);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
@@ -379,8 +394,8 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct rsst_req_update *req;
+ struct netc_swcbd swcbd;
union netc_cbd cbd;
int err, i;
@@ -388,8 +403,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = struct_size(req, groups, count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = struct_size(req, groups, count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
@@ -399,24 +414,22 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
for (i = 0; i < count; i++)
req->groups[i] = (u8)(table[i]);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err)
dev_err(user->dev, "Failed to update RSST entry, err: %pe\n",
ERR_PTR(err));
- ntmp_free_data_mem(&data);
-
return err;
}
EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry);
int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
{
- struct ntmp_dma_buf data = {.dev = user->dev};
struct ntmp_req_by_eid *req;
+ struct netc_swcbd swcbd;
union netc_cbd cbd;
int err, i;
u8 *group;
@@ -425,21 +438,21 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
/* HW only takes in a full 64 entry table */
return -EINVAL;
- data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
- RSST_CFGE_DATA_SIZE(count);
- err = ntmp_alloc_data_mem(&data, (void **)&req);
+ swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
+ RSST_CFGE_DATA_SIZE(count);
+ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Set the request data buffer */
ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0);
- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size),
+ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size),
NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
- err = netc_xmit_ntmp_cmd(user, &cbd);
+ err = netc_xmit_ntmp_cmd(user, &cbd, &swcbd);
if (err) {
dev_err(user->dev, "Failed to query RSST entry, err: %pe\n",
ERR_PTR(err));
- goto end;
+ return err;
}
group = (u8 *)req;
@@ -447,10 +460,7 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
for (i = 0; i < count; i++)
table[i] = group[i];
-end:
- ntmp_free_data_mem(&data);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntmp_rsst_query_entry);
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 7a53db8740db..5ae6f8b92700 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -13,6 +13,7 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
+#define NETC_CBDR_CLEAN_WORK 16
union netc_cbd {
struct {
@@ -55,13 +56,6 @@ union netc_cbd {
} resp_hdr; /* NTMP Response Message Header Format */
};
-struct ntmp_dma_buf {
- struct device *dev;
- size_t size;
- void *buf;
- dma_addr_t dma;
-};
-
struct ntmp_cmn_req_data {
__le16 update_act;
u8 dbg_opt;
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index 916dc4fe7de3..83a449b4d6ec 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -31,6 +31,12 @@ struct netc_tbl_vers {
u8 rsst_ver;
};
+struct netc_swcbd {
+ void *buf;
+ dma_addr_t dma;
+ size_t size;
+};
+
struct netc_cbdr {
struct device *dev;
struct netc_cbdr_regs regs;
@@ -44,9 +50,10 @@ struct netc_cbdr {
void *addr_base_align;
dma_addr_t dma_base;
dma_addr_t dma_base_align;
+ struct netc_swcbd *swcbd;
/* Serialize the order of command BD ring */
- spinlock_t ring_lock;
+ struct mutex ring_lock;
};
struct ntmp_user {
--
2.34.1
^ permalink raw reply related
* [PATCH net 1/2] net: enetc: correct the command BD ring consumer index
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260413075250.281653-1-wei.fang@nxp.com>
The command BD ring cousumer index register has the consumer index as
the lower 10 bits, and the bit 31 is SBE, which indicates whether a
system bus error occurred during execution of the CBD command. So if a
system bus error occurs, reading the register will get the SBE bit set.
However, the current implementation directly uses the register value as
the consumer index without masking it. Therefore, if a system bus error
occurs, an incorrect consumer index will be obtained, causing errors in
the processing of the command BD ring. Thus, we need to mask out the
other bits to obtain the correct consumer index.
Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP")
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/ntmp.c | 7 ++++---
drivers/net/ethernet/freescale/enetc/ntmp_private.h | 1 +
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 0c1d343253bf..1b1ff0446d0a 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -55,7 +55,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
spin_lock_init(&cbdr->ring_lock);
cbdr->next_to_use = netc_read(cbdr->regs.pir);
- cbdr->next_to_clean = netc_read(cbdr->regs.cir);
+ cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX;
/* Step 1: Configure the base address of the Control BD Ring */
netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
@@ -98,7 +98,7 @@ static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
int i;
i = cbdr->next_to_clean;
- while (netc_read(cbdr->regs.cir) != i) {
+ while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) {
cbd = ntmp_get_cbd(cbdr, i);
memset(cbd, 0, sizeof(*cbd));
i = (i + 1) % cbdr->bd_num;
@@ -135,7 +135,8 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
cbdr->next_to_use = i;
netc_write(cbdr->regs.pir, i);
- err = read_poll_timeout_atomic(netc_read, val, val == i,
+ err = read_poll_timeout_atomic(netc_read, val,
+ (val & NETC_CBDRCIR_INDEX) == i,
NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
true, cbdr->regs.cir);
if (unlikely(err))
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 34394e40fddd..7a53db8740db 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -12,6 +12,7 @@
#define NTMP_EID_REQ_LEN 8
#define NETC_CBDR_BD_NUM 256
+#define NETC_CBDRCIR_INDEX GENMASK(9, 0)
union netc_cbd {
struct {
--
2.34.1
^ permalink raw reply related
* [PATCH net 0/2] net: enetc: fix command BD ring issues
From: Wei Fang @ 2026-04-13 7:52 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, chleroy
Cc: netdev, linux-kernel, imx, linuxppc-dev, linux-arm-kernel
Currently, the implementation of command BD ring has two issues, one is
that the driver may obtain wrong consumer index of the ring, because the
driver does not mask out the SBE bit of the CIR value, so a wrong index
will be obtained when a SBE error ouccrs. The other one is that the DMA
buffer may be used after free. If netc_xmit_ntmp_cmd() times out and
returns an error, the pending command is not explicitly aborted, while
ntmp_free_data_mem() unconditionally frees the DMA buffer. If the buffer
has already been reallocated elsewhere, this may lead to silent memory
corruption. Because the hardware eventually processes the pending command
and perform a DMA write of the response to the physical address of the
freed buffer. So this patch set is to fix these two issues.
Wei Fang (2):
net: enetc: correct the command BD ring consumer index
net: enetc: fix NTMP DMA use-after-free issue
drivers/net/ethernet/freescale/enetc/ntmp.c | 161 ++++++++++--------
.../ethernet/freescale/enetc/ntmp_private.h | 9 +-
include/linux/fsl/ntmp.h | 9 +-
3 files changed, 96 insertions(+), 83 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH 6.12.y] netfilter: conntrack: add missing netlink policy validations
From: Li hongliang @ 2026-04-13 7:31 UTC (permalink / raw)
To: gregkh, stable, fw
Cc: patches, linux-kernel, pablo, kadlec, davem, edumazet, kuba,
pabeni, horms, kaber, netfilter-devel, coreteam, netdev, imv4bel
From: Florian Westphal <fw@strlen.de>
[ Upstream commit f900e1d77ee0ef87bfb5ab3fe60f0b3d8ad5ba05 ]
Hyunwoo Kim reports out-of-bounds access in sctp and ctnetlink.
These attributes are used by the kernel without any validation.
Extend the netlink policies accordingly.
Quoting the reporter:
nlattr_to_sctp() assigns the user-supplied CTA_PROTOINFO_SCTP_STATE
value directly to ct->proto.sctp.state without checking that it is
within the valid range. [..]
and: ... with exp->dir = 100, the access at
ct->master->tuplehash[100] reads 5600 bytes past the start of a
320-byte nf_conn object, causing a slab-out-of-bounds read confirmed by
UBSAN.
Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
Fixes: a258860e01b8 ("netfilter: ctnetlink: add full support for SCTP to ctnetlink")
Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/netfilter/nf_conntrack_netlink.c | 2 +-
net/netfilter/nf_conntrack_proto_sctp.c | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 323e147fe282..f51cdfba68fb 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3460,7 +3460,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
#if IS_ENABLED(CONFIG_NF_NAT)
static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
- [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
+ [CTA_EXPECT_NAT_DIR] = NLA_POLICY_MAX(NLA_BE32, IP_CT_DIR_REPLY),
[CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
};
#endif
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 4cc97f971264..fabb2c1ca00a 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -587,7 +587,8 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
}
static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
- [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 },
+ [CTA_PROTOINFO_SCTP_STATE] = NLA_POLICY_MAX(NLA_U8,
+ SCTP_CONNTRACK_HEARTBEAT_SENT),
[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 },
[CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
};
--
2.34.1
^ permalink raw reply related
* [PATCH iwl-net 5/5] iavf: return 0 when TC flower filter not found after qdisc teardown
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Kiran Patil
In-Reply-To: <20260413073035.4082204-1-aleksandr.loktionov@intel.com>
From: Kiran Patil <kiran.patil@intel.com>
When an egress qdisc is destroyed, the driver proactively deletes all
associated cloud filters to prevent stale hardware state, decrementing
num_cloud_filters to zero in the process.
The kernel netdev layer is unaware of this implicit cleanup and may
still try to delete the same filters individually. If the filter is
not found in the driver's list and num_cloud_filters is already zero,
return 0 instead of -EINVAL to avoid confusing upper layers that
believe the filter is still offloaded in hardware.
Fixes: 0075fa0fadd0 ("i40evf: Add support to apply cloud filters")
Signed-off-by: Kiran Patil <kiran.patil@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf_main.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 5e4035b..05aaae9 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -4175,7 +4175,16 @@ static int iavf_delete_clsflower(struct iavf_adapter *adapter,
if (filter) {
filter->del = true;
adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
- } else {
+ } else if (adapter->num_cloud_filters) {
+ /* When the egress qdisc is detached the driver implicitly
+ * deletes all associated cloud filters to prevent stale
+ * hardware entries, reducing num_cloud_filters to zero.
+ * The netdev layer is unaware of this implicit cleanup and
+ * may still request deletion of individual filters. Only
+ * return -EINVAL when a filter lookup fails and
+ * num_cloud_filters is non-zero, indicating a genuine
+ * lookup failure rather than a post-teardown stale delete.
+ */
err = -EINVAL;
}
spin_unlock_bh(&adapter->cloud_filter_list_lock);
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-net 4/5] iavf: fix TC boundary check in iavf_handle_tclass
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Avinash Dayanand
In-Reply-To: <20260413073035.4082204-1-aleksandr.loktionov@intel.com>
From: Avinash Dayanand <avinash.dayanand@intel.com>
The condition `tc < adapter->num_tc` admits any tc value equal to or
greater than num_tc, bypassing the destination-port validation and
allowing traffic to be steered to a non-existent traffic class. Change
the comparison to `tc > adapter->num_tc` to correctly reject
out-of-range TC values.
Fixes: 0075fa0fadd0 ("i40evf: Add support to apply cloud filters")
Signed-off-by: Avinash Dayanand <avinash.dayanand@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index ab5f5adc..5e4035b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -4062,7 +4062,7 @@ static int iavf_handle_tclass(struct iavf_adapter *adapter, u32 tc,
{
if (tc == 0)
return 0;
- if (tc < adapter->num_tc) {
+ if (tc > adapter->num_tc) {
if (!filter->f.data.tcp_spec.dst_port) {
dev_err(&adapter->pdev->dev,
"Specify destination port to redirect to traffic class other than TC0\n");
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-net 3/5] iavf: prevent VSI corruption when ring params changed during reset
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Sylwester Dziedziuch
In-Reply-To: <20260413073035.4082204-1-aleksandr.loktionov@intel.com>
From: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Changing ring parameters via ethtool triggers a VF reset and queue
reconfiguration. If ethtool is called again before the first reset
completes, the second reset races with uninitialised queue state and
can corrupt the VSI resource tree on the PF side.
Return -EAGAIN from iavf_set_ringparam() when the adapter is already
resetting or its queues are disabled.
Fixes: fbb7ddfef253 ("i40evf: core ethtool functionality")
Signed-off-by: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index 1cd1f3f..3909131 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -495,6 +495,11 @@ static int iavf_set_ringparam(struct net_device *netdev,
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
+ if (adapter->state == __IAVF_RESETTING ||
+ (adapter->state == __IAVF_RUNNING &&
+ adapter->flags & IAVF_FLAG_QUEUES_DISABLED))
+ return -EAGAIN;
+
if (ring->tx_pending > IAVF_MAX_TXD ||
ring->tx_pending < IAVF_MIN_TXD ||
ring->rx_pending > IAVF_MAX_RXD ||
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-net 2/5] iavf: fix error path in iavf_request_misc_irq
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
In-Reply-To: <20260413073035.4082204-1-aleksandr.loktionov@intel.com>
From: Piotr Gardocki <piotrx.gardocki@intel.com>
When request_irq() fails the interrupt vector was not registered for
the driver. Calling free_irq() on a vector that was never successfully
requested triggers a kernel warning. Drop the erroneous free_irq()
call from the error path.
Fixes: 5eae00c57f5e ("i40evf: main driver core")
Signed-off-by: Piotr Gardocki <piotrx.gardocki@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf_main.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index dad001a..ab5f5adc 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -587,7 +587,6 @@ static int iavf_request_misc_irq(struct iavf_adapter *adapter)
dev_err(&adapter->pdev->dev,
"request_irq for %s failed: %d\n",
adapter->misc_vector_name, err);
- free_irq(adapter->msix_entries[0].vector, netdev);
}
return err;
}
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-net 1/5] iavf: fix null pointer dereference in iavf_detect_recover_hung
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov
Cc: netdev, Kiran Patil
In-Reply-To: <20260413073035.4082204-1-aleksandr.loktionov@intel.com>
From: Kiran Patil <kiran.patil@intel.com>
During a concurrent reset, q_vectors are freed and re-allocated while
the watchdog task may still be iterating rings in
iavf_detect_recover_hung(). Dereferencing a NULL q_vector inside
iavf_force_wb() results in a crash. Guard against this by skipping
rings whose q_vector is NULL.
Also move the tx_ring declaration into the loop body and drop the
redundant outer NULL initialisation, which the compiler can never
observe since an array-element address is always non-NULL.
Fixes: 9c6c12595b73 ("i40e: Detection and recovery of TX queue hung logic moved to service_task from tx_timeout")
Signed-off-by: Kiran Patil <kiran.patil@intel.com>
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
drivers/net/ethernet/intel/iavf/iavf_txrx.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index 363c42b..e7e7fc9 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -176,7 +176,6 @@ static void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector)
**/
void iavf_detect_recover_hung(struct iavf_vsi *vsi)
{
- struct iavf_ring *tx_ring = NULL;
struct net_device *netdev;
unsigned int i;
int packets;
@@ -195,8 +194,11 @@ void iavf_detect_recover_hung(struct iavf_vsi *vsi)
return;
for (i = 0; i < vsi->back->num_active_queues; i++) {
- tx_ring = &vsi->back->tx_rings[i];
- if (tx_ring && tx_ring->desc) {
+ struct iavf_ring *tx_ring = &vsi->back->tx_rings[i];
+
+ if (!tx_ring || !tx_ring->q_vector)
+ continue;
+ if (tx_ring->desc) {
/* If packet counter has not changed the queue is
* likely stalled, so force an interrupt for this
* queue.
--
2.52.0
^ permalink raw reply related
* [PATCH iwl-net 0/5] iavf: five correctness fixes
From: Aleksandr Loktionov @ 2026-04-13 7:30 UTC (permalink / raw)
To: intel-wired-lan, anthony.l.nguyen, aleksandr.loktionov; +Cc: netdev
Small batch of iavf bug fixes. Patches address a NULL-pointer dereference
crash in the hung-tx detector, a spurious free_irq() call in the misc-IRQ
error path, a VSI-state-corruption race when ethtool changes ring parameters
during an active reset, an inverted TC-boundary comparison that silently
steered frames to non-existing traffic classes, and an -EINVAL that confused
upper layers when a TC flower filter was looked up after its qdisc had
already been torn down.
All five are genuine correctness fixes with no functional changes for the
common path. Best routed via net.
Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Avinash Dayanand (1):
iavf: fix TC boundary check in iavf_handle_tclass
Kiran Patil (2):
iavf: fix null pointer dereference in iavf_detect_recover_hung
iavf: return 0 when TC flower filter not found after qdisc teardown
Piotr Gardocki (1):
iavf: fix error path in iavf_request_misc_irq
Sylwester Dziedziuch (1):
iavf: prevent VSI corruption when ring params changed during reset
drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 5 +++++
drivers/net/ethernet/intel/iavf/iavf_main.c | 14 +++++++++++---
drivers/net/ethernet/intel/iavf/iavf_txrx.c | 8 +++++---
3 files changed, 21 insertions(+), 6 deletions(-)
--
2.52.0
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Russell King (Oracle) @ 2026-04-13 7:28 UTC (permalink / raw)
To: Sam Edwards
Cc: Maxime Chevallier, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
linux-stm32, netdev, Paolo Abeni
In-Reply-To: <adyaS3EauyrNrjMy@shell.armlinux.org.uk>
On Mon, Apr 13, 2026 at 08:24:59AM +0100, Russell King (Oracle) wrote:
> On Sun, Apr 12, 2026 at 06:42:04PM -0700, Sam Edwards wrote:
> > On Sun, Apr 12, 2026 at 7:23 AM Russell King (Oracle)
> > <linux@armlinux.org.uk> wrote:
> > > As the dwmac 5.0 core receive path seems to lock up after the first
> > > RBU, I never see more than one of those at a time.
> > >
> > > Right now, I consider this pretty much unsolvable - I've spent quite
> > > some time looking at it and trying various approaches, nothing seems
> > > to fix it. However, adding dma_rmb() in the descriptor cleanup/refill
> > > paths does seem to improve the situation a little with the 480Mbps
> > > case, because I think it means that we're reading the descriptors in
> > > a more timely manner after the hardware has updated them.
> >
> > Hey Russell,
> >
> > I'd like to repro this but I currently can't boot net-next. My issue
> > is the same as [1], and the patch to fix it [2] isn't yet committed
> > anywhere apparently.
> >
> > This prevents my Jetson Xavier NX from starting at all (and after
> > enough attempts, corrupts eMMC); I'm surprised you're not suffering
> > the same effects. But because this bug lives in the IOMMU subsystem
> > (and it has somewhat inconsistent effects), perhaps this is just a
> > different way it manifests? Could you confirm whether your dwmac hang
> > happens with IOMMU disabled, and/or with [1] reverted or [2] applied?
> >
> > I'm using a defconfig build and a fairly minimal cmdline (just
> > console=, root=, and rootwait).
> >
> > Cheers,
> > Sam
> >
> > [1] https://lore.kernel.org/all/8800a38b-8515-4bbe-af15-0dae81274bf7@nvidia.com/
> > [2] https://lore.kernel.org/all/0-v1-664d3acaabb9+78b-iommu_gather_always_jgg@nvidia.com/
>
> In the second link, there is this sub-thread:
>
> https://lore.kernel.org/all/ee2c2044-e329-4cdd-ac35-9365824d3677@arm.com/
>
> which was committed into -rc as:
>
> 7e0548525abd iommu: Ensure .iotlb_sync is called correctly
>
> which does fix IOMMU problems which caused net-next which reports itself
> as v7.0-rc6 failing to boot with ext4 errors. See:
>
> https://lore.kernel.org/r/adZTGOjjJrVJOcT8@shell.armlinux.org.uk
>
> which resulted in it being merged into v7.0-rc7 just before Thursday's
> net tree merge. Due to the way net-next is operated, that means that
> net-next on Thursday evening gained this fix.
>
> Involving Linus in the problem meant he was aware of it, and explaining
> how netdev works allowed him to delay the merging of the net tree to
> ensure net-next gained the fix.
I'll also state what I've stated previously about the iperf3 problem:
it seems to go back a long time, certainly before I started cleaning
up the stmmac driver which is now well over a year ago.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH v2 2/6] bus: mhi: host: Add support for non-posted TSC timesync feature
From: Manivannan Sadhasivam @ 2026-04-13 7:27 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Richard Cochran, mhi, linux-arm-msm, linux-kernel, netdev,
Vivek Pernamitta
In-Reply-To: <20260411-tsc_timesync-v2-2-6f25f72987b3@oss.qualcomm.com>
On Sat, Apr 11, 2026 at 01:42:02PM +0530, Krishna Chaitanya Chundru wrote:
> From: Vivek Pernamitta <quic_vpernami@quicinc.com>
>
> Implement non-posted time synchronization as described in section 5.1.1
> of the MHI v1.2 specification. The host disables low-power link states
> to minimize latency, reads the local time, issues a MMIO read to the
> device's TIME register.
>
> Add support for initializing this feature and export a function to be
> used by the drivers which does the time synchronization.
>
> MHI reads the device time registers in the MMIO address space pointed to
> by the capability register after disabling all low power modes and keeping
> MHI in M0. Before and after MHI reads, the local time is captured
> and shared for processing.
>
> Signed-off-by: Vivek Pernamitta <quic_vpernami@quicinc.com>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
> drivers/bus/mhi/common.h | 4 +++
> drivers/bus/mhi/host/init.c | 28 ++++++++++++++++
> drivers/bus/mhi/host/internal.h | 9 +++++
> drivers/bus/mhi/host/main.c | 74 +++++++++++++++++++++++++++++++++++++++++
> include/linux/mhi.h | 37 +++++++++++++++++++++
> 5 files changed, 152 insertions(+)
>
> diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
> index 4c316f3d5a68beb01f15cf575b03747096fdcf2c..64f9b2b94387a112bb6b5e20c634c3ba8d6bc78e 100644
> --- a/drivers/bus/mhi/common.h
> +++ b/drivers/bus/mhi/common.h
> @@ -118,6 +118,10 @@
> #define CAP_CAPID_MASK GENMASK(31, 24)
> #define CAP_NEXT_CAP_MASK GENMASK(23, 12)
>
> +/* MHI TSC Timesync */
> +#define TSC_TIMESYNC_TIME_LOW_OFFSET (0x8)
> +#define TSC_TIMESYNC_TIME_HIGH_OFFSET (0xC)
> +
> /* Command Ring Element macros */
> /* No operation command */
> #define MHI_TRE_CMD_NOOP_PTR 0
> diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
> index c2162aa04e810e45ccfbedd20aaa62f892420d31..eb720f671726d919646cbc450cd54bda655a1060 100644
> --- a/drivers/bus/mhi/host/init.c
> +++ b/drivers/bus/mhi/host/init.c
> @@ -498,6 +498,30 @@ static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability)
> return 0;
> }
>
> +static int mhi_init_tsc_timesync(struct mhi_controller *mhi_cntrl)
> +{
> + struct device *dev = &mhi_cntrl->mhi_dev->dev;
> + struct mhi_timesync *mhi_tsc_tsync;
> + u32 time_offset;
> + int ret;
> +
> + time_offset = mhi_find_capability(mhi_cntrl, MHI_CAP_ID_TSC_TIME_SYNC);
> + if (!time_offset)
> + return -ENXIO;
> +
> + mhi_tsc_tsync = devm_kzalloc(dev, sizeof(*mhi_tsc_tsync), GFP_KERNEL);
> + if (!mhi_tsc_tsync)
> + return -ENOMEM;
> +
> + mhi_cntrl->tsc_timesync = mhi_tsc_tsync;
> + mutex_init(&mhi_tsc_tsync->ts_mutex);
> +
> + /* save time_offset for obtaining time via MMIO register reads */
> + mhi_tsc_tsync->time_reg = mhi_cntrl->regs + time_offset;
> +
> + return 0;
> +}
> +
> int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
> {
> u32 val;
> @@ -635,6 +659,10 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
> return ret;
> }
>
> + ret = mhi_init_tsc_timesync(mhi_cntrl);
> + if (ret)
> + dev_dbg(dev, "TSC Time synchronization init failure\n");
> +
> return 0;
> }
>
> diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
> index 7b0ee5e3a12dd585064169b7b884750bf4d8c8db..a0e729e7a1198c1b82c70b6bfe3bc2ee24331229 100644
> --- a/drivers/bus/mhi/host/internal.h
> +++ b/drivers/bus/mhi/host/internal.h
> @@ -15,6 +15,15 @@ extern const struct bus_type mhi_bus_type;
> #define MHI_SOC_RESET_REQ_OFFSET 0xb0
> #define MHI_SOC_RESET_REQ BIT(0)
>
> +/*
> + * With ASPM enabled, the link may enter a low power state, requiring
> + * a wake-up sequence. Use a short burst of back-to-back reads to
> + * transition the link to the active state. Based on testing,
> + * 4 iterations are necessary to ensure reliable wake-up without
> + * excess latency.
> + */
> +#define MHI_NUM_BACK_TO_BACK_READS 4
> +
> struct mhi_ctxt {
> struct mhi_event_ctxt *er_ctxt;
> struct mhi_chan_ctxt *chan_ctxt;
> diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
> index 53c0ffe300702bcc3caa8fd9ea8086203c75b186..b7a727b1a5d1f20b570c62707a991ec5b85bfec7 100644
> --- a/drivers/bus/mhi/host/main.c
> +++ b/drivers/bus/mhi/host/main.c
> @@ -1626,3 +1626,77 @@ int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_
> return 0;
> }
> EXPORT_SYMBOL_GPL(mhi_get_channel_doorbell_offset);
> +
> +static int mhi_get_remote_time(struct mhi_controller *mhi_cntrl, struct mhi_timesync *mhi_tsync,
> + struct mhi_timesync_info *time)
> +{
> + struct device *dev = &mhi_cntrl->mhi_dev->dev;
> + int ret, i;
> +
> + if (!mhi_tsync && !mhi_tsync->time_reg) {
> + dev_err(dev, "Time sync is not supported\n");
> + return -EINVAL;
> + }
> +
> + if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
> + dev_err(dev, "MHI is not in active state, pm_state:%s\n",
> + to_mhi_pm_state_str(mhi_cntrl->pm_state));
> + return -EIO;
> + }
> +
> + /* bring to M0 state */
> + ret = mhi_device_get_sync(mhi_cntrl->mhi_dev);
> + if (ret)
> + return ret;
> +
> + guard(mutex)(&mhi_tsync->ts_mutex);
> + mhi_cntrl->runtime_get(mhi_cntrl);
> +
> + /*
> + * time critical code to fetch device time, delay between these two steps
> + * should be deterministic as possible.
> + */
Thinking more, to be deterministic, ASPM should be disabled at this point. But
we cannot do that safely now from PCI client drivers until this series gets in:
https://lore.kernel.org/linux-arm-msm/20250825-ath-aspm-fix-v2-0-61b2f2db7d89@oss.qualcomm.com/
So let's keep it this way for now, but add a FIXME to disable ASPM.
> + preempt_disable();
> + local_irq_disable();
> +
> + time->t_host_pre = ktime_get_real();
> +
> + /*
> + * To ensure the PCIe link is in L0 when ASPM is enabled, perform series
> + * of back-to-back reads. This is necessary because the link may be in a
> + * low-power state (e.g., L1 or L1ss), and need to be forced it to
> + * transition to L0.
> + */
> + for (i = 0; i < MHI_NUM_BACK_TO_BACK_READS; i++) {
> + ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
> + TSC_TIMESYNC_TIME_LOW_OFFSET, &time->t_dev_lo);
> +
> + ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
> + TSC_TIMESYNC_TIME_HIGH_OFFSET, &time->t_dev_hi);
And an idiomatic way to read 64bit MMIO value in two 32bit read is:
do {
high = read_high();
low = read_low();
} while(high != read_high());
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH net,v2 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: Russell King (Oracle) @ 2026-04-13 7:26 UTC (permalink / raw)
To: KhaiWenTan
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue, maxime.chevallier, ovidiu.panait.rb,
vladimir.oltean, netdev, linux-stm32, linux-arm-kernel,
linux-kernel, yoong.siang.song, hong.aun.looi, khai.wen.tan
In-Reply-To: <20260413020339.68426-1-khai.wen.tan@linux.intel.com>
On Mon, Apr 13, 2026 at 10:03:39AM +0800, KhaiWenTan wrote:
> get_interfaces() will update both the plat->phy_interfaces and
> mdio_bus_data->default_an_inband based on reading a SERDES register. As
> get_interfaces() will be called after default_an_inband had already been
> read, dwmac-intel regressed as a result with incorrect default_an_inband
> value in phylink_config.
>
> Therefore, we moved the priv->plat->get_interfaces() to be executed first
> before assigning mdio_bus_data->default_an_inband to
> config->default_an_inband to ensure default_an_inband is in correct value.
>
> Fixes: d3836052fe09 ("net: stmmac: intel: convert speed_mode_2500() to get_interfaces()")
> Signed-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Thanks!
I'll note that this will cause a conflict with net-next when that is
eventually merged.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Russell King (Oracle) @ 2026-04-13 7:24 UTC (permalink / raw)
To: Sam Edwards
Cc: Maxime Chevallier, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
linux-stm32, netdev, Paolo Abeni
In-Reply-To: <CAH5Ym4hEX15dmJhGBqhhk--_PoFRKRSyE1AomY4D3ipwAz+pKg@mail.gmail.com>
On Sun, Apr 12, 2026 at 06:42:04PM -0700, Sam Edwards wrote:
> On Sun, Apr 12, 2026 at 7:23 AM Russell King (Oracle)
> <linux@armlinux.org.uk> wrote:
> > As the dwmac 5.0 core receive path seems to lock up after the first
> > RBU, I never see more than one of those at a time.
> >
> > Right now, I consider this pretty much unsolvable - I've spent quite
> > some time looking at it and trying various approaches, nothing seems
> > to fix it. However, adding dma_rmb() in the descriptor cleanup/refill
> > paths does seem to improve the situation a little with the 480Mbps
> > case, because I think it means that we're reading the descriptors in
> > a more timely manner after the hardware has updated them.
>
> Hey Russell,
>
> I'd like to repro this but I currently can't boot net-next. My issue
> is the same as [1], and the patch to fix it [2] isn't yet committed
> anywhere apparently.
>
> This prevents my Jetson Xavier NX from starting at all (and after
> enough attempts, corrupts eMMC); I'm surprised you're not suffering
> the same effects. But because this bug lives in the IOMMU subsystem
> (and it has somewhat inconsistent effects), perhaps this is just a
> different way it manifests? Could you confirm whether your dwmac hang
> happens with IOMMU disabled, and/or with [1] reverted or [2] applied?
>
> I'm using a defconfig build and a fairly minimal cmdline (just
> console=, root=, and rootwait).
>
> Cheers,
> Sam
>
> [1] https://lore.kernel.org/all/8800a38b-8515-4bbe-af15-0dae81274bf7@nvidia.com/
> [2] https://lore.kernel.org/all/0-v1-664d3acaabb9+78b-iommu_gather_always_jgg@nvidia.com/
In the second link, there is this sub-thread:
https://lore.kernel.org/all/ee2c2044-e329-4cdd-ac35-9365824d3677@arm.com/
which was committed into -rc as:
7e0548525abd iommu: Ensure .iotlb_sync is called correctly
which does fix IOMMU problems which caused net-next which reports itself
as v7.0-rc6 failing to boot with ext4 errors. See:
https://lore.kernel.org/r/adZTGOjjJrVJOcT8@shell.armlinux.org.uk
which resulted in it being merged into v7.0-rc7 just before Thursday's
net tree merge. Due to the way net-next is operated, that means that
net-next on Thursday evening gained this fix.
Involving Linus in the problem meant he was aware of it, and explaining
how netdev works allowed him to delay the merging of the net tree to
ensure net-next gained the fix.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* [PATCH net v2] RDS: Fix memory leak in rds_rdma_extra_size()
From: Xiaobo Liu @ 2026-04-13 7:00 UTC (permalink / raw)
To: Allison Henderson, David S. Miller
Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, netdev,
linux-rdma, rds-devel, linux-kernel, Xiaobo Liu
Free iov->iov when copy_from_user() or page count validation fails
in rds_rdma_extra_size().
This preserves the existing success path and avoids leaking the
allocated iovec array on error.
Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
---
net/rds/rdma.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index aa6465dc7..91a20c1e2 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -560,6 +560,7 @@ int rds_rdma_extra_size(struct rds_rdma_args *args,
struct rds_iovec *vec;
struct rds_iovec __user *local_vec;
int tot_pages = 0;
+ int ret = 0;
unsigned int nr_pages;
unsigned int i;
@@ -578,16 +579,20 @@ int rds_rdma_extra_size(struct rds_rdma_args *args,
vec = &iov->iov[0];
if (copy_from_user(vec, local_vec, args->nr_local *
- sizeof(struct rds_iovec)))
- return -EFAULT;
+ sizeof(struct rds_iovec))) {
+ ret = -EFAULT;
+ goto out;
+ }
iov->len = args->nr_local;
/* figure out the number of pages in the vector */
for (i = 0; i < args->nr_local; i++, vec++) {
nr_pages = rds_pages_in_vec(vec);
- if (nr_pages == 0)
- return -EINVAL;
+ if (nr_pages == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
tot_pages += nr_pages;
@@ -595,11 +600,20 @@ int rds_rdma_extra_size(struct rds_rdma_args *args,
* nr_pages for one entry is limited to (UINT_MAX>>PAGE_SHIFT)+1,
* so tot_pages cannot overflow without first going negative.
*/
- if (tot_pages < 0)
- return -EINVAL;
+ if (tot_pages < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
}
- return tot_pages * sizeof(struct scatterlist);
+ ret = tot_pages * sizeof(struct scatterlist);
+
+out:
+ if (ret < 0) {
+ kfree(iov->iov);
+ iov->iov = NULL;
+ }
+ return ret;
}
/*
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 2/6] bus: mhi: host: Add support for non-posted TSC timesync feature
From: Manivannan Sadhasivam @ 2026-04-13 6:42 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Richard Cochran, mhi, linux-arm-msm, linux-kernel, netdev,
Vivek Pernamitta
In-Reply-To: <20260411-tsc_timesync-v2-2-6f25f72987b3@oss.qualcomm.com>
On Sat, Apr 11, 2026 at 01:42:02PM +0530, Krishna Chaitanya Chundru wrote:
> From: Vivek Pernamitta <quic_vpernami@quicinc.com>
>
> Implement non-posted time synchronization as described in section 5.1.1
> of the MHI v1.2 specification. The host disables low-power link states
> to minimize latency, reads the local time, issues a MMIO read to the
> device's TIME register.
>
> Add support for initializing this feature and export a function to be
> used by the drivers which does the time synchronization.
>
> MHI reads the device time registers in the MMIO address space pointed to
> by the capability register after disabling all low power modes and keeping
> MHI in M0. Before and after MHI reads, the local time is captured
> and shared for processing.
>
> Signed-off-by: Vivek Pernamitta <quic_vpernami@quicinc.com>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
> drivers/bus/mhi/common.h | 4 +++
> drivers/bus/mhi/host/init.c | 28 ++++++++++++++++
> drivers/bus/mhi/host/internal.h | 9 +++++
> drivers/bus/mhi/host/main.c | 74 +++++++++++++++++++++++++++++++++++++++++
> include/linux/mhi.h | 37 +++++++++++++++++++++
> 5 files changed, 152 insertions(+)
>
> diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
> index 4c316f3d5a68beb01f15cf575b03747096fdcf2c..64f9b2b94387a112bb6b5e20c634c3ba8d6bc78e 100644
> --- a/drivers/bus/mhi/common.h
> +++ b/drivers/bus/mhi/common.h
> @@ -118,6 +118,10 @@
> #define CAP_CAPID_MASK GENMASK(31, 24)
> #define CAP_NEXT_CAP_MASK GENMASK(23, 12)
>
> +/* MHI TSC Timesync */
> +#define TSC_TIMESYNC_TIME_LOW_OFFSET (0x8)
> +#define TSC_TIMESYNC_TIME_HIGH_OFFSET (0xC)
> +
> /* Command Ring Element macros */
> /* No operation command */
> #define MHI_TRE_CMD_NOOP_PTR 0
> diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
> index c2162aa04e810e45ccfbedd20aaa62f892420d31..eb720f671726d919646cbc450cd54bda655a1060 100644
> --- a/drivers/bus/mhi/host/init.c
> +++ b/drivers/bus/mhi/host/init.c
> @@ -498,6 +498,30 @@ static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability)
> return 0;
> }
>
> +static int mhi_init_tsc_timesync(struct mhi_controller *mhi_cntrl)
> +{
> + struct device *dev = &mhi_cntrl->mhi_dev->dev;
> + struct mhi_timesync *mhi_tsc_tsync;
> + u32 time_offset;
> + int ret;
> +
> + time_offset = mhi_find_capability(mhi_cntrl, MHI_CAP_ID_TSC_TIME_SYNC);
> + if (!time_offset)
> + return -ENXIO;
> +
> + mhi_tsc_tsync = devm_kzalloc(dev, sizeof(*mhi_tsc_tsync), GFP_KERNEL);
> + if (!mhi_tsc_tsync)
> + return -ENOMEM;
> +
> + mhi_cntrl->tsc_timesync = mhi_tsc_tsync;
> + mutex_init(&mhi_tsc_tsync->ts_mutex);
> +
> + /* save time_offset for obtaining time via MMIO register reads */
> + mhi_tsc_tsync->time_reg = mhi_cntrl->regs + time_offset;
> +
> + return 0;
> +}
Move all the function definitions from MHI core code to mhi_phc.c.
> +
> int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
> {
> u32 val;
> @@ -635,6 +659,10 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
> return ret;
> }
>
> + ret = mhi_init_tsc_timesync(mhi_cntrl);
> + if (ret)
> + dev_dbg(dev, "TSC Time synchronization init failure\n");
And just keep this call in the MHI core.
> +
> return 0;
> }
>
> diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
> index 7b0ee5e3a12dd585064169b7b884750bf4d8c8db..a0e729e7a1198c1b82c70b6bfe3bc2ee24331229 100644
> --- a/drivers/bus/mhi/host/internal.h
> +++ b/drivers/bus/mhi/host/internal.h
> @@ -15,6 +15,15 @@ extern const struct bus_type mhi_bus_type;
> #define MHI_SOC_RESET_REQ_OFFSET 0xb0
> #define MHI_SOC_RESET_REQ BIT(0)
>
> +/*
> + * With ASPM enabled, the link may enter a low power state, requiring
> + * a wake-up sequence. Use a short burst of back-to-back reads to
> + * transition the link to the active state. Based on testing,
> + * 4 iterations are necessary to ensure reliable wake-up without
> + * excess latency.
> + */
> +#define MHI_NUM_BACK_TO_BACK_READS 4
> +
> struct mhi_ctxt {
> struct mhi_event_ctxt *er_ctxt;
> struct mhi_chan_ctxt *chan_ctxt;
> diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
> index 53c0ffe300702bcc3caa8fd9ea8086203c75b186..b7a727b1a5d1f20b570c62707a991ec5b85bfec7 100644
> --- a/drivers/bus/mhi/host/main.c
> +++ b/drivers/bus/mhi/host/main.c
> @@ -1626,3 +1626,77 @@ int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_
> return 0;
> }
> EXPORT_SYMBOL_GPL(mhi_get_channel_doorbell_offset);
> +
> +static int mhi_get_remote_time(struct mhi_controller *mhi_cntrl, struct mhi_timesync *mhi_tsync,
> + struct mhi_timesync_info *time)
> +{
> + struct device *dev = &mhi_cntrl->mhi_dev->dev;
> + int ret, i;
> +
> + if (!mhi_tsync && !mhi_tsync->time_reg) {
> + dev_err(dev, "Time sync is not supported\n");
> + return -EINVAL;
-EOPNOTSUPP
> + }
> +
> + if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
> + dev_err(dev, "MHI is not in active state, pm_state:%s\n",
> + to_mhi_pm_state_str(mhi_cntrl->pm_state));
> + return -EIO;
> + }
> +
> + /* bring to M0 state */
> + ret = mhi_device_get_sync(mhi_cntrl->mhi_dev);
> + if (ret)
> + return ret;
> +
> + guard(mutex)(&mhi_tsync->ts_mutex);
> + mhi_cntrl->runtime_get(mhi_cntrl);
> +
> + /*
> + * time critical code to fetch device time, delay between these two steps
> + * should be deterministic as possible.
> + */
> + preempt_disable();
> + local_irq_disable();
> +
> + time->t_host_pre = ktime_get_real();
> +
> + /*
> + * To ensure the PCIe link is in L0 when ASPM is enabled, perform series
> + * of back-to-back reads. This is necessary because the link may be in a
> + * low-power state (e.g., L1 or L1ss), and need to be forced it to
> + * transition to L0.
> + */
You should be doing these back-to-back reads only if ASPM is enabled. You can
check that using pcie_aspm_enabled(). Also, see if you can hide this call inside
pci_generic driver to make mhi_phc truly transport agnostic.
> + for (i = 0; i < MHI_NUM_BACK_TO_BACK_READS; i++) {
> + ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
> + TSC_TIMESYNC_TIME_LOW_OFFSET, &time->t_dev_lo);
> +
> + ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
> + TSC_TIMESYNC_TIME_HIGH_OFFSET, &time->t_dev_hi);
> + }
> +
> + time->t_host_post = ktime_get_real();
> +
> + local_irq_enable();
> + preempt_enable();
> +
> + mhi_cntrl->runtime_put(mhi_cntrl);
> +
> + mhi_device_put(mhi_cntrl->mhi_dev);
> +
> + return 0;
> +}
> +
> +int mhi_get_remote_tsc_time_sync(struct mhi_device *mhi_dev, struct mhi_timesync_info *time)
> +{
> + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
> + struct mhi_timesync *mhi_tsc_tsync = mhi_cntrl->tsc_timesync;
> + int ret;
> +
> + ret = mhi_get_remote_time(mhi_cntrl, mhi_tsc_tsync, time);
> + if (ret)
> + dev_err(&mhi_dev->dev, "Failed to get TSC Time Sync value:%d\n", ret);
What is the difference between 'TSC' and 'Time Sync'?
Nit: Space after 'value:'
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(mhi_get_remote_tsc_time_sync);
> diff --git a/include/linux/mhi.h b/include/linux/mhi.h
> index 88ccb3e14f481d6b85c2a314eb74ba960c2d4c81..f39c8ca7c251954f2d83c1227d206b600b88c75f 100644
> --- a/include/linux/mhi.h
> +++ b/include/linux/mhi.h
> @@ -286,6 +286,30 @@ struct mhi_controller_config {
> bool m2_no_db;
> };
>
> +/**
> + * struct mhi_timesync - MHI time synchronization structure
> + * @time_reg: Points to address of Timesync register
> + * @ts_mutex: Mutex for synchronization
> + */
> +struct mhi_timesync {
> + void __iomem *time_reg;
> + struct mutex ts_mutex;
> +};
> +
> +/**
> + * struct mhi_timesync_info - MHI time sync info structure
> + * @t_host_pre: Pre host soc time
> + * @t_host_post: Post host soc time
Get rid of 'soc', it provides no value.
> + * @t_dev_lo: Mhi device time of lower dword
> + * @t_dev_hi: Mhi device time of higher dword
s/Mhi/MHI
> + */
> +struct mhi_timesync_info {
> + ktime_t t_host_pre;
> + ktime_t t_host_post;
> + u32 t_dev_lo;
> + u32 t_dev_hi;
> +};
> +
> /**
> * struct mhi_controller - Master MHI controller structure
> * @name: Device name of the MHI controller
> @@ -323,6 +347,7 @@ struct mhi_controller_config {
> * @mhi_event: MHI event ring configurations table
> * @mhi_cmd: MHI command ring configurations table
> * @mhi_ctxt: MHI device context, shared memory between host and device
> + * @tsc_timesync: MHI TSC timesync
> * @pm_mutex: Mutex for suspend/resume operation
> * @pm_lock: Lock for protecting MHI power management state
> * @timeout_ms: Timeout in ms for state transitions
> @@ -401,6 +426,8 @@ struct mhi_controller {
> struct mhi_cmd *mhi_cmd;
> struct mhi_ctxt *mhi_ctxt;
>
> + struct mhi_timesync *tsc_timesync;
> +
> struct mutex pm_mutex;
> rwlock_t pm_lock;
> u32 timeout_ms;
> @@ -795,4 +822,14 @@ bool mhi_queue_is_full(struct mhi_device *mhi_dev, enum dma_data_direction dir);
> */
> int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_offset);
>
> +/**
> + * mhi_get_remote_tsc_time_sync - get external soc time relative to local soc
Same comment as above
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH net 1/1] tipc: validate Gap ACK blocks in STATE message
From: Ruide Cao @ 2026-04-13 6:01 UTC (permalink / raw)
To: Tung Quang Nguyen, Ren Wei
Cc: jmaloy@redhat.com, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
yifanwucs@gmail.com, tomapufckgml@gmail.com, yuantan098@gmail.com,
bird@lzu.edu.cn, enjou1224z@gmail.com, netdev@vger.kernel.org
In-Reply-To: <GV1P189MB1988963A155568005A37BF7FC6242@GV1P189MB1988.EURP189.PROD.OUTLOOK.COM>
On 4/12/2026 8:06 PM, Tung Quang Nguyen wrote:
>> Subject: [PATCH net 1/1] tipc: validate Gap ACK blocks in STATE message
>>
>> From: Ruide Cao <caoruide123@gmail.com>
>>
>> tipc_get_gap_ack_blks() reads len, ugack_cnt and bgack_cnt directly from
>> msg_data(hdr) before verifying that a STATE message actually contains the
>> fixed Gap ACK block header in its logical data area.
>>
>> A peer that negotiates TIPC_GAP_ACK_BLOCK can send a short STATE message
>> with a declared TIPC payload shorter than struct tipc_gap_ack_blks and still
>> append a few physical bytes after the header. The helper then trusts those
>> bytes as Gap ACK metadata, and the forged bgack_cnt/len values can drive the
>> broadcast receive path into kmemdup() beyond the skb boundary.
> Can you explain how that peer can alter the STATE message ? If it can, what concrete values are used and on what fields of the STATE messages ?
Thanks for the review.
To clarify, the peer is not "altering" an already received STATE
message; it is actively sending a malformed LINK_PROTOCOL/STATE_MSG
after the link has already negotiated the TIPC_GAP_ACK_BLOCK capability.
Concretely, the crafted STATE message is sent with a modified msg_size
so that msg_data_sz(hdr) is 0, but the actual UDP payload still carries
extra physical bytes after the 40-byte TIPC header. Those bytes are then
interpreted as the fixed Gap ACK header. For example:
len = 0x07fc
ugack_cnt = 0xff
bgack_cnt = 0xff
These values are specifically chosen so that the existing sanity check
remains internally consistent:
struct_size(p, gacks, 0xff + 0xff) == 0x07fc
Therefore, the existing sanity check does not reject this case. It only
checks the self-consistency of the attacker-controlled Gap ACK fields;
it completely fails to check if the declared Gap ACK record actually
fits inside the enclosing STATE message's logical payload length.
>> Fix this by rejecting Gap ACK parsing unless the logical STATE payload is large
>> enough to cover the fixed header, and by rejecting declared Gap ACK lengths
>> that are smaller than the fixed header or larger than the logical payload.
>> Return 0 for invalid lengths so malformed Gap ACK data is not treated as a
>> valid payload offset, and drop unicast STATE messages that advertise Gap ACK
>> support but still yield an invalid Gap ACK length. This keeps malformed Gap
>> ACK data ignored without misaligning monitor payload parsing.
>>
>> Fixes: d7626b5acff9 ("tipc: introduce Gap ACK blocks for broadcast link")
>> Cc: stable@kernel.org
>> Reported-by: Yifan Wu <yifanwucs@gmail.com>
>> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
>> Co-developed-by: Yuan Tan <yuantan098@gmail.com>
>> Signed-off-by: Yuan Tan <yuantan098@gmail.com>
>> Suggested-by: Xin Liu <bird@lzu.edu.cn>
>> Tested-by: Ren Wei <enjou1224z@gmail.com>
>> Signed-off-by: Ruide Cao <caoruide123@gmail.com>
>> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
>> ---
>> net/tipc/link.c | 16 ++++++++++++++--
>> 1 file changed, 14 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/tipc/link.c b/net/tipc/link.c index 49dfc098d89b..44678d98939a
>> 100644
>> --- a/net/tipc/link.c
>> +++ b/net/tipc/link.c
>> @@ -1415,12 +1415,22 @@ u16 tipc_get_gap_ack_blks(struct
>> tipc_gap_ack_blks **ga, struct tipc_link *l,
>> struct tipc_msg *hdr, bool uc)
>> {
>> struct tipc_gap_ack_blks *p;
>> - u16 sz = 0;
>> + u16 sz = 0, dlen = msg_data_sz(hdr);
>>
>> /* Does peer support the Gap ACK blocks feature? */
>> if (l->peer_caps & TIPC_GAP_ACK_BLOCK) {
>> + u16 min_sz = struct_size(p, gacks, 0);
>> +
>> + if (dlen < min_sz)
>> + goto ignore;
> This checking is redundant because with existing sanity checking, the invalid gap ACK blocks will not be used to release acked messages in transmit queue.
The `dlen < min_sz` check is required because the existing sanity check
already dereferences `p->len`, `p->ugack_cnt`, and `p->bgack_cnt`.
Without this new check, an Out-of-Bounds (OOB) read occurs before the
old sanity check even has a chance to run.
>> +
>> p = (struct tipc_gap_ack_blks *)msg_data(hdr);
>> sz = ntohs(p->len);
>> + if (sz < min_sz || sz > dlen) {
>> + sz = 0;
>> + goto ignore;
>> + }
> This checking is redundant. Existing sanity checking is good enough.
The `sz < min_sz || sz > dlen` check is not redundant because the old
sanity check completely fails to verify if the declared Gap ACK length
(`sz`) actually fits inside the enclosing STATE message's logical
payload length (`dlen`).
Without checking against `dlen`, an internally consistent spoofed packet
will pass the old check and cause OOB reads during the subsequent block
parsing.
>> +
>> /* Sanity check */
>> if (sz == struct_size(p, gacks, size_add(p->ugack_cnt, p-
>>> bgack_cnt))) {
>> /* Good, check if the desired type exists */ @@ -
>> 1434,6 +1444,8 @@ u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga,
>> struct tipc_link *l,
>> }
>> }
>> }
>> +
>> +ignore:
>> /* Other cases: ignore! */
>> p = NULL;
>>
>> @@ -2270,7 +2282,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct
>> sk_buff *skb,
>> case STATE_MSG:
>> /* Validate Gap ACK blocks, drop if invalid */
>> glen = tipc_get_gap_ack_blks(&ga, l, hdr, true);
>> - if (glen > dlen)
>> + if (glen > dlen || ((l->peer_caps & TIPC_GAP_ACK_BLOCK) &&
>> !glen))
> This checking is redundant. Existing sanity checking is good enough.
The unicast caller-side drop `((l->peer_caps & TIPC_GAP_ACK_BLOCK) &&
!glen)` is also necessary. Once the capability is negotiated, a valid
Gap ACK record MUST have at least the fixed 4-byte header. If `glen ==
0` from such a peer, it indicates a malformed payload.
The STATE message must be dropped here so it is not passed on to
`tipc_mon_rcv()` as if monitor data started at `data + 0`, which would
misalign the monitor payload parsing.
>> break;
>>
>> l->rcv_nxt_state = msg_seqno(hdr) + 1;
>> --
>> 2.34.1
>>
^ permalink raw reply
* Re: [patch 28/38] mips: Select ARCH_HAS_RANDOM_ENTROPY
From: Maciej W. Rozycki @ 2026-04-13 5:47 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik,
netdev, linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
sparclinux
In-Reply-To: <20260410120319.462206386@kernel.org>
On Fri, 10 Apr 2026, Thomas Gleixner wrote:
> The only solution for now is to uninline random_get_entropy(). Fix up all
> other dependencies on the content of asm/timex.h in those files which
> really depend on it.
Oh dear! I'd yet have to fully evaluate the consequences, but offhand
this has clearly turned what compiles to a single CPU instruction on the
vast majority of MIPS platforms into an expensive function call, possibly
also changing the caller from a leaf to a nested function with all the
associated execution penalty. Is there no other way?
Cf. commit 06947aaaf9bf ("MIPS: Implement random_get_entropy with CP0
Random").
Maciej
^ permalink raw reply
* Re: [PATCH v2 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
From: Manivannan Sadhasivam @ 2026-04-13 5:44 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Krishna Chaitanya Chundru, Richard Cochran, mhi, linux-arm-msm,
linux-kernel, netdev, Vivek Pernamitta, Sivareddy Surasani,
Vivek Pernamitta, Imran Shaik, Taniya Das
In-Reply-To: <20260412080951.723295fa@kernel.org>
On Sun, Apr 12, 2026 at 08:09:51AM -0700, Jakub Kicinski wrote:
> On Sat, 11 Apr 2026 13:42:00 +0530 Krishna Chaitanya Chundru wrote:
> > - User space applications use the standard Linux PTP interface.
> > - The PTP subsystem routes IOCTLs to the MHI PHC driver.
> > - The MHI PHC driver communicates with the MHI core to fetch timestamps.
> > - The MHI core interacts with the device to retrieve accurate time data.
This is a misleading statement. Only the 'pci_generic' controller driver interacts
with the device for querying timestamp. MHI bus just acts as a messenger.
>
> Nack, stop adding functionality under the mhi "bus".
> Bus is supposed to be an abstraction into which real drivers plug in.
MHI bus is very similar to the PCI bus. Just like PCI capabilities, MHI also has
capabilities to discover the supported functionalities including timesync. So
for making use of the timesync feature, we need to add some hooks into the MHI
bus layer, but the functionality is added to the separate driver,
'drivers/bus/mhi/host/mhi_phc*'. This is also quite similar to how PCI(e)
features like AER, hotplug are structured.
In this series, timesync API definitions are added mistakenly to the core bus
code, which should be moved to the mhi_phc driver instead.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH net] bnge: return after auxiliary_device_uninit() in error path
From: Vikas Gupta @ 2026-04-13 5:29 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: netdev, linux-kernel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, stable
In-Reply-To: <2026041124-banshee-molecular-0f70@gregkh>
On Sat, Apr 11, 2026 at 4:15 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> When auxiliary_device_add() fails, the error block calls
> auxiliary_device_uninit() but does not return. The uninit drops the
> last reference and synchronously runs bnge_aux_dev_release(), which sets
> bd->auxr_dev = NULL and frees the underlying object. The subsequent
> bd->auxr_dev->net = bd->netdev then dereferences NULL, which is not a
> good thing to have happen when trying to clean up from an error.
>
> Add the missing return, as the auxiliary bus documentation states is a
> requirement (seems that LLM tools read documentation better than humans
> do...)
>
> Cc: Vikas Gupta <vikas.gupta@broadcom.com>
> Cc: Andrew Lunn <andrew+netdev@lunn.ch>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: Jakub Kicinski <kuba@kernel.org>
> Cc: Paolo Abeni <pabeni@redhat.com>
> Fixes: 8ac050ec3b1c ("bng_en: Add RoCE aux device support")
> Cc: stable <stable@kernel.org>
> Assisted-by: gregkh_clanker_t1000
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Vikas Gupta <vikas.gupta@broadcom.com>
> ---
> drivers/net/ethernet/broadcom/bnge/bnge_auxr.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
> index b942076762ef..67e93e17d4d9 100644
> --- a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
> +++ b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c
> @@ -194,6 +194,7 @@ void bnge_rdma_aux_device_add(struct bnge_dev *bd)
> dev_warn(bd->dev, "Failed to add auxiliary device for ROCE\n");
> auxiliary_device_uninit(aux_dev);
> bd->flags &= ~BNGE_EN_ROCE;
> + return;
> }
>
> bd->auxr_dev->net = bd->netdev;
> --
> 2.53.0
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox