* [PATCH net-next v13 02/10] net: phy: phy_link_topology: Track ports in phy_link_topology
From: Maxime Chevallier @ 2026-07-01 11:04 UTC (permalink / raw)
To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, Heiner Kallweit
Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
Daniel Golle, Dimitri Fedrau, Frank Wunderlich
In-Reply-To: <20260701110427.143945-1-maxime.chevallier@bootlin.com>
phy_port is aimed at representing the various physical interfaces of a
net_device. They can be controlled by various components in the link,
such as the Ethernet PHY, the Ethernet MAC, and SFP module, etc.
Let's therefore make so we keep track of all the ports connected to a
netdev in phy_link_topology. The only ports added for now are phy-driven
ports.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_link_topology.c | 53 +++++++++++++++++++++++++++++
include/linux/phy_link_topology.h | 18 ++++++++++
include/linux/phy_port.h | 2 ++
net/core/dev.c | 1 +
4 files changed, 74 insertions(+)
diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link_topology.c
index 99f1842afcbd..a7ff36a12c4e 100644
--- a/drivers/net/phy/phy_link_topology.c
+++ b/drivers/net/phy/phy_link_topology.c
@@ -7,6 +7,7 @@
*/
#include <linux/phy_link_topology.h>
+#include <linux/phy_port.h>
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include <linux/xarray.h>
@@ -23,6 +24,9 @@ static int netdev_alloc_phy_link_topology(struct net_device *dev)
xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1);
topo->next_phy_index = 1;
+ xa_init_flags(&topo->ports, XA_FLAGS_ALLOC1);
+ topo->next_port_index = 1;
+
dev->link_topo = topo;
return 0;
@@ -45,12 +49,45 @@ static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_device *d
return dev->link_topo;
}
+int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port)
+{
+ struct phy_link_topology *topo;
+ int ret;
+
+ topo = phy_link_topo_get_or_alloc(dev);
+ if (IS_ERR(topo))
+ return PTR_ERR(topo);
+
+ /* Attempt to re-use a previously allocated port_id */
+ if (port->id)
+ ret = xa_insert(&topo->ports, port->id, port, GFP_KERNEL);
+ else
+ ret = xa_alloc_cyclic(&topo->ports, &port->id, port,
+ xa_limit_32b, &topo->next_port_index,
+ GFP_KERNEL);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_link_topo_add_port);
+
+void phy_link_topo_del_port(struct net_device *dev, struct phy_port *port)
+{
+ struct phy_link_topology *topo = dev->link_topo;
+
+ if (!topo)
+ return;
+
+ xa_erase(&topo->ports, port->id);
+}
+EXPORT_SYMBOL_GPL(phy_link_topo_del_port);
+
int phy_link_topo_add_phy(struct net_device *dev,
struct phy_device *phy,
enum phy_upstream upt, void *upstream)
{
struct phy_link_topology *topo;
struct phy_device_node *pdn;
+ struct phy_port *port;
int ret;
/* ethtool ops may run without rtnl_lock, and rtnl_lock is what
@@ -99,8 +136,20 @@ int phy_link_topo_add_phy(struct net_device *dev,
if (ret < 0)
goto err;
+ /* Add all the PHY's ports to the topology */
+ list_for_each_entry(port, &phy->ports, head) {
+ ret = phy_link_topo_add_port(dev, port);
+ if (ret)
+ goto del_ports;
+ }
+
return 0;
+del_ports:
+ list_for_each_entry_continue_reverse(port, &phy->ports, head)
+ phy_link_topo_del_port(dev, port);
+
+ xa_erase(&topo->phys, phy->phyindex);
err:
kfree(pdn);
return ret;
@@ -112,10 +161,14 @@ void phy_link_topo_del_phy(struct net_device *dev,
{
struct phy_link_topology *topo = dev->link_topo;
struct phy_device_node *pdn;
+ struct phy_port *port;
if (!topo)
return;
+ list_for_each_entry(port, &phy->ports, head)
+ phy_link_topo_del_port(dev, port);
+
pdn = xa_erase(&topo->phys, phy->phyindex);
/* We delete the PHY from the topology, however we don't re-set the
diff --git a/include/linux/phy_link_topology.h b/include/linux/phy_link_topology.h
index 95575f68d5bc..296ee514ba46 100644
--- a/include/linux/phy_link_topology.h
+++ b/include/linux/phy_link_topology.h
@@ -16,11 +16,15 @@
struct xarray;
struct phy_device;
+struct phy_port;
struct sfp_bus;
struct phy_link_topology {
struct xarray phys;
u32 next_phy_index;
+
+ struct xarray ports;
+ u32 next_port_index;
};
struct phy_device_node {
@@ -48,6 +52,9 @@ int phy_link_topo_add_phy(struct net_device *dev,
void phy_link_topo_del_phy(struct net_device *dev, struct phy_device *phy);
+int phy_link_topo_add_port(struct net_device *dev, struct phy_port *port);
+void phy_link_topo_del_port(struct net_device *dev, struct phy_port *port);
+
static inline struct phy_device *
phy_link_topo_get_phy(struct net_device *dev, u32 phyindex)
{
@@ -77,6 +84,17 @@ static inline void phy_link_topo_del_phy(struct net_device *dev,
{
}
+static inline int phy_link_topo_add_port(struct net_device *dev,
+ struct phy_port *port)
+{
+ return 0;
+}
+
+static inline void phy_link_topo_del_port(struct net_device *dev,
+ struct phy_port *port)
+{
+}
+
static inline struct phy_device *
phy_link_topo_get_phy(struct net_device *dev, u32 phyindex)
{
diff --git a/include/linux/phy_port.h b/include/linux/phy_port.h
index 0ef0f5ce4709..4e2a3fdd2f2e 100644
--- a/include/linux/phy_port.h
+++ b/include/linux/phy_port.h
@@ -36,6 +36,7 @@ struct phy_port_ops {
/**
* struct phy_port - A representation of a network device physical interface
*
+ * @id: Unique identifier for the port within the topology
* @head: Used by the port's parent to list ports
* @parent_type: The type of device this port is directly connected to
* @phy: If the parent is PHY_PORT_PHYDEV, the PHY controlling that port
@@ -52,6 +53,7 @@ struct phy_port_ops {
* @is_sfp: Indicates if this port drives an SFP cage.
*/
struct phy_port {
+ u32 id;
struct list_head head;
enum phy_port_parent parent_type;
union {
diff --git a/net/core/dev.c b/net/core/dev.c
index 4b3d5cfdf6e0..d3a4c0b61615 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11304,6 +11304,7 @@ static void netdev_free_phy_link_topology(struct net_device *dev)
if (IS_ENABLED(CONFIG_PHYLIB) && topo) {
xa_destroy(&topo->phys);
+ xa_destroy(&topo->ports);
kfree(topo);
dev->link_topo = NULL;
}
--
2.54.0
^ permalink raw reply related
* [PATCH net-next v13 01/10] net: phy: phy_link_topology: Add a helper for opportunistic alloc
From: Maxime Chevallier @ 2026-07-01 11:04 UTC (permalink / raw)
To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, Heiner Kallweit
Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
Daniel Golle, Dimitri Fedrau, Frank Wunderlich
In-Reply-To: <20260701110427.143945-1-maxime.chevallier@bootlin.com>
The phy_link_topology structure stores information about the PHY-related
components connected to a net_device. It is opportunistically allocated,
when we add the first item to the topology, as this is not relevant for
all kinds of net_devices.
In preparation for the addition of phy_port tracking in the topology,
let's make a dedicated helper for that allocation sequence.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/phy/phy_link_topology.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/phy_link_topology.c b/drivers/net/phy/phy_link_topology.c
index 4134de7ae313..99f1842afcbd 100644
--- a/drivers/net/phy/phy_link_topology.c
+++ b/drivers/net/phy/phy_link_topology.c
@@ -28,11 +28,28 @@ static int netdev_alloc_phy_link_topology(struct net_device *dev)
return 0;
}
+static struct phy_link_topology *phy_link_topo_get_or_alloc(struct net_device *dev)
+{
+ int ret;
+
+ if (dev->link_topo)
+ return dev->link_topo;
+
+ /* The topology is allocated the first time we add an object to it.
+ * It is freed alongside the netdev.
+ */
+ ret = netdev_alloc_phy_link_topology(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dev->link_topo;
+}
+
int phy_link_topo_add_phy(struct net_device *dev,
struct phy_device *phy,
enum phy_upstream upt, void *upstream)
{
- struct phy_link_topology *topo = dev->link_topo;
+ struct phy_link_topology *topo;
struct phy_device_node *pdn;
int ret;
@@ -45,13 +62,9 @@ int phy_link_topo_add_phy(struct net_device *dev,
if (WARN_ON_ONCE(netdev_need_ops_lock(dev)))
return -EOPNOTSUPP;
- if (!topo) {
- ret = netdev_alloc_phy_link_topology(dev);
- if (ret)
- return ret;
-
- topo = dev->link_topo;
- }
+ topo = phy_link_topo_get_or_alloc(dev);
+ if (IS_ERR(topo))
+ return PTR_ERR(topo);
pdn = kzalloc_obj(*pdn);
if (!pdn)
--
2.54.0
^ permalink raw reply related
* [PATCH net-next v13 00/10] net: phy_port: SFP modules representation and phy_port listing
From: Maxime Chevallier @ 2026-07-01 11:04 UTC (permalink / raw)
To: davem, Andrew Lunn, Jakub Kicinski, Eric Dumazet, Paolo Abeni,
Russell King, Heiner Kallweit
Cc: Maxime Chevallier, netdev, linux-kernel, thomas.petazzoni,
Christophe Leroy, Herve Codina, Florian Fainelli, Vladimir Oltean,
Köry Maincent, Marek Behún, Oleksij Rempel,
Nicolò Veronese, Simon Horman, mwojtas, Romain Gantois,
Daniel Golle, Dimitri Fedrau, Frank Wunderlich
Hello everyone,
Here's V13 for the phy_port improved SFP support and netlink interface.
V13 rebases on net-next, which includes some fixes for more
sashiko-reported issues, mostly on a cleanup path in patch 5.
This work extends on the recent addition of phy_port representation to enable
listing the front-facing ports of an interface. For now, we don't control
these ports, we merely list their presence and their capabilities.
As the most common use-case of multi-port interfaces is combo-ports that
provide both RJ45 and SFP connectors on a single MAC, there's a lot of
SFP stuff in this series.
This series is in 2 main parts. The first one aims at representing the
SFP cages and modules using phy_port, as combo-ports with RJ45 + SFP are
by far the most common cases for multi-connector setups.
The second part is the netlink interface to list those ports, now that
most use-cases are covered.
Let's see what we can do with some examples of the new ethtool API :
- Get MII interfaces supported by an empty SFP cage :
# ethtool --show-ports eth3
Port for eth3:
Port id: 1
Supported MII interfaces : sgmii, 1000base-x, 2500base-x
Port type: sfp
- Get Combo-ports supported modes, on each port :
# ethtool --show-ports eth1
Port for eth1:
Port id: 1
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
10000baseT/Full
2500baseT/Full
5000baseT/Full
Port type: mdi
Port for eth1:
Port id: 2
Supported MII interfaces : 10gbase-r
Port type: sfp
- Get Achievable linkmodes on a SFP module (combo port with a DAC in the
SFP cage)
# ethtool --show-ports eth1
Port for eth1:
Port id: 1
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
10000baseT/Full
2500baseT/Full
5000baseT/Full
Port type: mdi
Port for eth1:
Port id: 2
Supported MII interfaces : 10gbase-r
Port type: sfp
Port for eth1:
Port id: 3
Upstream id: 2
Supported link modes: 10000baseCR/Full
Port type: mdi
Note that here, we have 3 ports :
- The Copper port
- The SFP Cage itself, marked as 'occupied'
- The SFP module
This series builds on top of phy_port and phy_link_topology to allow
tracking the ports of an interface. We maintain a list of supported
linkmodes/interfaces on each port, which allows for fine-grained
reporting of each port's capability.
What this series doesn't do :
- We don't support selecting which port is active. This is the next step.
- We only support PHY-driven combo ports. The end-goal of this whole
journey that started with phy_link_topology is to get support for MII
muxes, such as the one we have on the Turris Omnia. This will eventually
be upstreamed as well.
If you want to play around with it, here's [1] the patched ethtool that I've
been using to produce the outputs above.
Thanks !
Maxime
[1] : https://github.com/minimaxwell/ethtool/tree/mc/ethtool_port
Changelog :
Changes in V13:
- Rebase on net-next
- Fix the SFP bus cleanup path in patch 5
Changes in V12:
V12: https://lore.kernel.org/r/20260615153907.862987-1-maxime.chevallier@bootlin.com
- Rebased on net-next, including fixes on the phy probing and cleanup
paths
- Rebased on Jakub's netdev_ops_locked changes in phy_link_topology
- Fixed some typos reported by Andrew and sashiko in the documentation
Changes in v11:
V11:https://lore.kernel.org/r/20260521121040.1199622-1-maxime.chevallier@bootlin.com
- Aggregated Andrew's reviews :)
- Removed the "vacant" field, replaced it with "upstream_port"
Changes in V10:
V10: https://lore.kernel.org/r/20260513130521.1064094-1-maxime.chevallier@bootlin.com
- Rebase on net-next
- Rename phylink/phy_device sfp_bus_port to sfp_cage_port
- Sashiko's reviews were mostly unrealistic or wrong :(
Changes in V9:
V9: https://lore.kernel.org/r/20260403123755.175742-1-maxime.chevallier@bootlin.com
- Added missing netlink doc updates for u8->u32 conversion
- Removed dead code with a condition that can never be true in
phylink's mod_port code
- Fixed the error path in phy_sfp_connect_phy
Changes in v8:
V8: https://lore.kernel.org/r/20260325081937.571115-1-maxime.chevallier@bootlin.com
- Set the new phydev.has_sfp_mod_phy field when we're sure that no
errors occured
- Fix formatting of the copyright info in ethnl port
- Use a policy to validate the range of port_id
- Use GENL_REQ_ATTR_CHECK
- alpha-sort headers
- use u32 in netlink messages
- return better error codes
- don't check the skb len, the core does that
Changes in V7:
V7: https://lore.kernel.org/all/20260309152747.702373-1-maxime.chevallier@bootlin.com/
- Changed the port cleanup path to use list_for_each_entry_continue_reverse
- Adjusted the cleanup path in phylink for the port vacant state
- Pass the right cmd for the netlink dump message
Changes in V6:
V6: https://lore.kernel.org/r/20260304145444.442334-1-maxime.chevallier@bootlin.com
- Added some comments in th mod_port cleanup
- changed some kmalloc to kmalloc_obj
- Removed some phy_link_topo_del_port that wasn't needed
Changes in V5:
V5: https://lore.kernel.org/r/20260205092317.755906-1-maxime.chevallier@bootlin.com
- Fixed a check on a potentially un-initialized pointer, reported by
Simon
- Fixed a documentation formatting issue
- Remove a stray pr_info
- Rebased on net-next
Changes in V4:
V4 : https://lore.kernel.org/netdev/20260203172839.548524-1-maxime.chevallier@bootlin.com/
- Add a cleanup patch for the of port parsing
- Added a match to sync the port's linkmodes with the PHY's for OF
ports
- Added RTNL assert in the port_get topo helper
- nullify the bus port for phylink support
- Fix some typos
Changes in V3:
V3: https://lore.kernel.org/netdev/20260201151249.642015-1-maxime.chevallier@bootlin.com/
- Remove the sfp bus ops for nophy, and use .module_start() as
suggested by Russell
- Added missing cleanup for the topology, as per AI review
- Fixed a few typos as per Romain's review
- Changed "occupied" to "vacant" as per Romain's review
- Added missing checks for null ports, per AI review
Changes in V2:
V2: https://lore.kernel.org/netdev/20260128204526.170927-1-maxime.chevallier@bootlin.com/
- Fix the cleanup path of phy_link_topo_add_phy, as per AI review
- Fix the cleanup path of phy_sfp_probe, as per AI review
- Fix the call-site of the disconnect_nophy sfp bus ops, per AI review
- Fix the netdev-less case uin phylink, per AI review
- Fix the prototype of phy_link_topo_get_port for the stubs
- Dropped patch 11. It ended-up breaking 'allnoconfig', so instead we
built a phy_interface_names array in net/ethtool/netlink.c
- Fix an ethool-netlink spec discrepancy with the type of an attribute
- Fix the size computation in the netlink port API
- Fix the cleanup path in the netlink port API
V1: https://lore.kernel.org/netdev/20260127134202.8208-1-maxime.chevallier@bootlin.com/
Maxime Chevallier (10):
net: phy: phy_link_topology: Add a helper for opportunistic alloc
net: phy: phy_link_topology: Track ports in phy_link_topology
net: phylink: Register a phy_port for MAC-driven SFP cages
net: phy: Create SFP phy_port before registering upstream
net: phy: Represent PHY-less SFP modules with phy_port
net: phy: phy_port: Store information about a port's upstream
net: phy: phy_link_topology: Add a helper to retrieve ports
netlink: specs: Add ethernet port listing with ethtool
net: ethtool: Introduce ethtool command to list ports
Documentation: networking: Update the phy_port infrastructure
description
Documentation/netlink/specs/ethtool.yaml | 50 +++
Documentation/networking/ethtool-netlink.rst | 34 ++
Documentation/networking/phy-port.rst | 26 +-
MAINTAINERS | 1 +
drivers/net/phy/phy-caps.h | 2 +
drivers/net/phy/phy_caps.c | 26 ++
drivers/net/phy/phy_device.c | 183 ++++++++-
drivers/net/phy/phy_link_topology.c | 82 +++-
drivers/net/phy/phylink.c | 128 +++++-
include/linux/phy.h | 10 +
include/linux/phy_link_topology.h | 39 ++
include/linux/phy_port.h | 5 +
.../uapi/linux/ethtool_netlink_generated.h | 19 +
net/core/dev.c | 1 +
net/ethtool/Makefile | 2 +-
net/ethtool/netlink.c | 25 ++
net/ethtool/netlink.h | 9 +
net/ethtool/port.c | 373 ++++++++++++++++++
18 files changed, 981 insertions(+), 34 deletions(-)
create mode 100644 net/ethtool/port.c
--
2.54.0
^ permalink raw reply
* [PATCH] firmware: qcom: scm: add missing IRQ_DOMAIN select to QCOM_SCM
From: Julian Braha @ 2026-07-01 11:03 UTC (permalink / raw)
To: andersson
Cc: sumit.garg, linux-arm-msm, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, konradybcio,
robh, krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, sumit.garg,
harshal.dev, Julian Braha
'drivers/firmware/qcom/qcom_scm.c' calls 'irq_create_fwspec_mapping'
so it will fail to compile if IRQ_DOMAIN is disabled:
drivers/firmware/qcom/qcom_scm.c: In function ‘qcom_scm_get_waitq_irq’:
drivers/firmware/qcom/qcom_scm.c:2512:16: error: implicit declaration
of function ‘irq_create_fwspec_mapping’; did you mean
‘irq_create_of_mapping’? [-Wimplicit-function-declaration]
2512 | return irq_create_fwspec_mapping(&fwspec);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| irq_create_of_mapping
A patch-set in review proposes making QCOM_SCM visible in the kconfig
frontend, so let's ensure that it's safe for users to enable:
https://lore.kernel.org/lkml/akS_6izxrhgK-I22@sumit-xelite/
Signed-off-by: Julian Braha <julianbraha@gmail.com>
---
drivers/firmware/qcom/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index b477d54b495a..9d137fa2aa23 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -7,6 +7,7 @@
menu "Qualcomm firmware drivers"
config QCOM_SCM
+ select IRQ_DOMAIN
select QCOM_TZMEM
tristate
--
2.54.0
^ permalink raw reply related
* Re: [PATCH bpf-next v5 1/3] bpf: Add BPF_FIB_LOOKUP_VLAN flag to bpf_fib_lookup() helper
From: Toke Høiland-Jørgensen @ 2026-07-01 11:02 UTC (permalink / raw)
To: David Ahern, Avinash Duduskar, ast, daniel, andrii
Cc: eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil,
john.fastabend, sdf, davem, edumazet, kuba, pabeni, horms, shuah,
hawk, yatsenko, leon.hwang, kpsingh, a.s.protopopov, ameryhung,
rongtao, eyal.birger, bpf, netdev, linux-kernel, linux-kselftest
In-Reply-To: <916191fc-2e10-4449-b82b-c086d90283ae@kernel.org>
David Ahern <dsahern@kernel.org> writes:
> On 6/30/26 10:04 AM, Toke Høiland-Jørgensen wrote:
>> David Ahern <dsahern@kernel.org> writes:
>>
>>> On 6/30/26 4:00 AM, Toke Høiland-Jørgensen wrote:
>>>>> It does not make sense to require a flag to get lookup output. vlan
>>>>> proto of 0 is not valid, so it is a clear indication that the vlan
>>>>> output parameters were not set during the lookup.
>>>>
>>>> Okay, so we could just unconditionally set the VLAN fields, but if we
>>>> start rewriting the ifindex that would be a change of the existing
>>>> behaviour that could break existing applications, no?
>>>
>>> Consistently dealing with upper devices is one of the reasons I never
>>> sent patches for vlan support.
>>>
>>> xdp support is at the driver layer for real (physical) devices. The fib
>>> lookup is going to return the vlan device index - a virtual device.
>>> Support for xdp should not be propagated to virtual devices; it goes
>>> against the intent of xdp. Any trip down this path will have to decide
>>> how to handle vlan-in-vlan use cases. Where is the line drawn for fast
>>> networking?
>>
>> Right, which is why we need building blocks that makes it possible for
>> XDP programs to do the right thing in the BPF code :)
>>
>> A helper that resolves the parent could be used for stacked VLANs as
>> well (just calling the helper multiple times).
>>
>>>> Specifically, if an XDP application has a table of the interfaces it
>>>> forwards between, today they'd get a VLAN interface ifindex, which would
>>>> not be in that table, and the application would return XDP_PASS. Whereas
>>>> if we change the ifindex and populate the VLAN tag, suddenly the
>>>> interface would be in the table, but because the application doesn't
>>>> read the returned VLAN tag, it will end up sending packets out without
>>>> tagging them, leading to broken forwarding.
>>>
>>> I have not followed developments over the past few years. Does XDP have
>>> support for vlan acceleration in the Tx path now? You really want that
>>> to deal with vlans and not replicating s/w processing in ebpf.
>>
>> It does not, no. There's TX metadata for AF_XDP, but VLAN support is not
>> in there (see include/uapi/linux/if_xdp.h).
>>
>> Doesn't mean software VLAN handling can't be useful, though; there are
>> use cases other than the very high end where XDP can speed things up
>> even if it has to write a VLAN tag or two...
>>
>>>> So if we don't want the flag, we'd need some other mechanism to resolve
>>>> the parent ifindex, AFAICT? Maybe a xdp_get_parent_ifindex() kfunc, say?
>>>> That could also be made generic for other stacked interface types, I
>>>> suppose.
>>>>
>>>> WDYT?
>>>
>>> dealing with stacked devices is hard :-)
>>>
>>> What is the return is a bond device or a vlan on a bond device?
>>
>> Well, bond devices have XDP support, so you can just redirect to those :)
>>
>> But yeah, each type of stacked device would need to pass different
>> information through to the XDP program, and the program would need to
>> support those. Building a single XDP program that supports all of them
>> will require quite a bit of code, and would probably not perform super
>> well. But most deployments have distinct subsets of features they need,
>> so this does not have to be a blocker, IMO?
>>
>
> Seems to me the fib_lookup for xdp needs to return the bottom device,
> not the vlan device, for forwarding to work. That's why I added the
> fields to the struct. That allows the program to push the vlan header if
> required. My preference (dream?) was that Tx path had support to tell
> the redirect the vlan and h/w added it on send.
Sure, returning the bottom device index with the VLAN tag makes sense,
and that's basically what this series does (but bails out on stacked
VLANs). However, that's not what the helper does today, which is why the
flag is there, to opt-in to the new behaviour. I don't think we can just
change the ifindex without breaking existing applications (as noted
up-thread).
> But really, once stacked devices come into play, I just wanted to make
> sure thought is given to different use cases. As you know the lookup
> struct if hard bound to 64B and it is trying to cover a lot of use cases.
Agreed, I don't think we can handle stacked devices in this helper. But
we could split it out into a new one. Something like:
struct lower_device_info {
enum device_type type;
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
} vlan;
/* add other types here */
};
int xdp_get_lower_device(int ifindex, struct lower_device_info *info);
called like:
int xdp_program(struct xdp_md *ctx)
{
struct lower_device_info dev_info = {};
int ifindex, ret;
ifindex = find_destination(ctx); /* does fib lookup, or something else */
while ((ret = xdp_get_lower_device_info(ifindex, &dev_info)) > 0) {
if (dev_info.type == VLAN) {
push_vlan_tag(ctx, &dev_info.vlan);
ifindex = ret;
} else {
return XDP_PASS; /* we only handle VLAN devices */
}
}
return bpf_redirect(ifindex, 0);
}
With a helper like this, we obviously don't strictly speaking need to
change the fib lookup helper at all. However, for the single-tagged VLAN
case, I think supporting it directly in the fib lookup could still have
value, as an optimisation: it saves an extra call for resolving the
ifindex, and the fields are already there. So I think my preference
would be to merge this series as-is, and then follow up with a new kfunc
to handle the stacked case. But we could also just drop this series and
go straight to the new kfunc.
WDYT?
-Toke
^ permalink raw reply
* Re: [PATCH v8 10/14] media: qcom: Pass proper PAS ID to set_remote_state API
From: Konrad Dybcio @ 2026-07-01 11:01 UTC (permalink / raw)
To: Sumit Garg
Cc: andersson, linux-arm-msm, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, konradybcio,
robh, krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <akTFZgKBQYQUYxx4@sumit-xelite>
On 7/1/26 9:44 AM, Sumit Garg wrote:
> On Tue, Jun 30, 2026 at 02:42:25PM +0200, Konrad Dybcio wrote:
>> On 6/26/26 3:34 PM, Sumit Garg wrote:
>>> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
>>>
>>> As per testing the SCM backend just ignores it while OP-TEE makes
>>> use of it to for proper book keeping purpose.
>>>
>>> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>>> Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
>>> Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
>>> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
>>> ---
>>> drivers/media/platform/qcom/iris/iris_firmware.c | 2 +-
>>> drivers/media/platform/qcom/venus/firmware.c | 2 +-
>>> 2 files changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
>>> index ea9654dd679e..d2e7ba4f37e3 100644
>>> --- a/drivers/media/platform/qcom/iris/iris_firmware.c
>>> +++ b/drivers/media/platform/qcom/iris/iris_firmware.c
>>> @@ -110,5 +110,5 @@ int iris_fw_unload(struct iris_core *core)
>>>
>>> int iris_set_hw_state(struct iris_core *core, bool resume)
>>> {
>>> - return qcom_pas_set_remote_state(resume, 0);
>>> + return qcom_pas_set_remote_state(resume, IRIS_PAS_ID);
>>> }
>>> diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
>>> index 3a38ff985822..3c0727ea137d 100644
>>> --- a/drivers/media/platform/qcom/venus/firmware.c
>>> +++ b/drivers/media/platform/qcom/venus/firmware.c
>>> @@ -59,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume)
>>> int ret;
>>>
>>> if (core->use_tz) {
>>> - ret = qcom_pas_set_remote_state(resume, 0);
>>> + ret = qcom_pas_set_remote_state(resume, VENUS_PAS_ID);
>>
>> This should not be in the middle of a mildly related series..
>> The PAS IDs should be centralized into a single header. And the
>> name of the driver shouldn't be part of the define. I would guesstimate
>> that on the secure side it's probably called VPU or VIDEO
>
> I agree with your comments, this is something I would also like to
> consolidate on OP-TEE side as well: see discussion here [1].
>
> However, the patch itself was needed to do book keeping on OP-TEE side
> but I can drop it since anyhow the video isn't functional yet in
> upstream dependent on the proper IOMMU support.
For this patch.. I think QCTZ may be ignoring the argument so it
may not matter.. on a second thought you already have it reviewed
and it's already a cross-subsys merge so might as well pull it in,
worst case scenario it'll revert cleanly
Once this lands, please move all PAS defines to.. hmm.. qcom_pas.h
sounds like a good candidate?
Konrad
^ permalink raw reply
* Re: [PATCH net 4/9] netfilter: nf_conntrack_sip: validate skb_dst() before accessing it
From: Pablo Neira Ayuso @ 2026-07-01 11:01 UTC (permalink / raw)
To: Florian Westphal
Cc: netdev, Paolo Abeni, David S. Miller, Eric Dumazet,
Jakub Kicinski, netfilter-devel
In-Reply-To: <akS1W7XGQ3LiP0LC@strlen.de>
On Wed, Jul 01, 2026 at 08:36:11AM +0200, Florian Westphal wrote:
> Florian Westphal <fw@strlen.de> wrote:
> > From: Pablo Neira Ayuso <pablo@netfilter.org>
> >
> > tc ingress and openvswitch do not guarantee routing information to be
> > available. These subsystems use the conntrack helper infrastructure, and
> > the SIP helper relies on the skb_dst() to be present if
> > sip_external_media is set to 1 (which is disabled by default as a module
> > parameter).
>
> The sashiko drive-by appears real, I submitted a patch for it.
> Its not a regression added by this patch but a unrelated issue.
>
> https://patchwork.ozlabs.org/project/netfilter-devel/patch/20260701062922.9660-1-fw@strlen.de/
Is skb_ensure_writable() bogus here?
As you said, skb is already linearized. As for clones, they should
only happen in br_netfilter? In such case, it should be br_netfilter
that should be audited not to pass cloned skbuffs before calling the
inet hooks.
^ permalink raw reply
* [PATCH iwl-net 2/2] ice: fix stats array overflow via proper realloc
From: Przemek Kitszel @ 2026-07-01 10:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski
Cc: netdev, Tony Nguyen, Aleksandr Loktionov, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Jedrzej Jagielski,
Piotr Kwapulinski, Przemek Kitszel
In-Reply-To: <20260701104141.9740-1-przemyslaw.kitszel@intel.com>
Integrate ice_vsi_alloc_stat_arrays() with realloc variant.
Instead of keeping two functions for stat arrays allocation, change the
ice_vsi_realloc_stat_arrays() to handle initial condition (no vsi_stat
entry) and replace ice_vsi_alloc_stat_arrays() by the more generic
ice_vsi_realloc_stat_arrays().
Note that VSIs of ICE_VSI_CHNL type are ignored in realloc variant as they
were in the replaced ice_vsi_alloc_stat_arrays().
This is a fix for stats array overflow that occurs when VF is given more
queues (an operation that will be more frequent, and by bigger increase,
when we will merge my "XLVF" series).
Splat for increasing number of queues thanks to Michal Schmidt:
KASAN detects the bug:
==================================================================
BUG: KASAN: slab-out-of-bounds in ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
Read of size 8 at addr ffff88810affea60 by task kworker/u131:7/221
CPU: 24 UID: 0 PID: 221 Comm: kworker/u131:7 Not tainted 7.1.0-rc1+ #1 PREEMPT(lazy)
...
Workqueue: ice ice_service_task [ice]
Call Trace:
<TASK>
...
kasan_report+0xd7/0x120
ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
ice_vsi_cfg_def+0x12e2/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_reset_vf+0x858/0xf80 [ice]
ice_vc_request_qs_msg+0x1da/0x290 [ice]
ice_vc_process_vf_msg+0xb15/0x1430 [ice]
__ice_clean_ctrlq+0x70d/0x9d0 [ice]
ice_service_task+0x840/0xf20 [ice]
process_one_work+0x690/0xff0
worker_thread+0x4d9/0xd20
kthread+0x322/0x410
ret_from_fork+0x332/0x660
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 2439:
kasan_save_stack+0x1c/0x40
kasan_save_track+0x10/0x30
__kasan_kmalloc+0x96/0xb0
__kmalloc_noprof+0x1d8/0x580
ice_vsi_cfg_def+0x115c/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_vsi_setup+0x180/0x320 [ice]
ice_start_vfs+0x1f3/0x590 [ice]
ice_ena_vfs+0x66d/0x798 [ice]
ice_sriov_configure.cold+0xe4/0x121 [ice]
sriov_numvfs_store+0x279/0x480
kernfs_fop_write_iter+0x331/0x4f0
vfs_write+0x4c4/0xe40
ksys_write+0x10c/0x240
do_syscall_64+0xd9/0x650
entry_SYSCALL_64_after_hwframe+0x76/0x7e
The buggy address belongs to the object at ffff88810affea40
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 0 bytes to the right of
allocated 32-byte region [ffff88810affea40, ffff88810affea60)
Fixes: 2a2cb4c6c181 ("ice: replace ice_vf_recreate_vsi() with ice_vf_reconfig_vsi()")
Closes: https://redhat.atlassian.net/browse/RHEL-164321
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
This is an alternative to the fix [1] by Michal Schmidt, which were
blocked due to AI feedback. My fix was already developed before Michal's,
just not public back then. We have agreed to go on with my version.
[1] https://lore.kernel.org/netdev/20260520183501.3360810-3-anthony.l.nguyen@intel.com
---
drivers/net/ethernet/intel/ice/ice_lib.c | 57 +++++-------------------
1 file changed, 11 insertions(+), 46 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index e48ee5940f17..ae167b42c558 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -513,51 +513,6 @@ static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data)
return IRQ_HANDLED;
}
-/**
- * ice_vsi_alloc_stat_arrays - Allocate statistics arrays
- * @vsi: VSI pointer
- */
-static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi)
-{
- struct ice_vsi_stats *vsi_stat;
- struct ice_pf *pf = vsi->back;
-
- if (vsi->type == ICE_VSI_CHNL)
- return 0;
- if (!pf->vsi_stats)
- return -ENOENT;
-
- if (pf->vsi_stats[vsi->idx])
- /* realloc will happen in rebuild path */
- return 0;
-
- vsi_stat = kzalloc_obj(*vsi_stat);
- if (!vsi_stat)
- return -ENOMEM;
-
- vsi_stat->tx_ring_stats =
- kzalloc_objs(*vsi_stat->tx_ring_stats, vsi->alloc_txq);
- if (!vsi_stat->tx_ring_stats)
- goto err_alloc_tx;
-
- vsi_stat->rx_ring_stats =
- kzalloc_objs(*vsi_stat->rx_ring_stats, vsi->alloc_rxq);
- if (!vsi_stat->rx_ring_stats)
- goto err_alloc_rx;
-
- pf->vsi_stats[vsi->idx] = vsi_stat;
-
- return 0;
-
-err_alloc_rx:
- kfree(vsi_stat->rx_ring_stats);
-err_alloc_tx:
- kfree(vsi_stat->tx_ring_stats);
- kfree(vsi_stat);
- pf->vsi_stats[vsi->idx] = NULL;
- return -ENOMEM;
-}
-
/**
* ice_vsi_alloc_def - set default values for already allocated VSI
* @vsi: ptr to VSI
@@ -2319,7 +2274,17 @@ static int ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
u16 prev_txq = vsi->alloc_txq;
u16 prev_rxq = vsi->alloc_rxq;
+ if (vsi->type == ICE_VSI_CHNL)
+ return 0;
+
vsi_stat = pf->vsi_stats[vsi->idx];
+ if (!vsi_stat) {
+ vsi_stat = kzalloc_obj(*vsi_stat);
+ if (!vsi_stat)
+ return -ENOMEM;
+
+ pf->vsi_stats[vsi->idx] = vsi_stat;
+ }
if (req_txq < prev_txq) {
for (int i = req_txq; i < prev_txq; i++) {
@@ -2379,7 +2344,7 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
return ret;
/* allocate memory for Tx/Rx ring stat pointers */
- ret = ice_vsi_alloc_stat_arrays(vsi);
+ ret = ice_vsi_realloc_stat_arrays(vsi);
if (ret)
goto unroll_vsi_alloc;
--
2.54.0
^ permalink raw reply related
* [PATCH iwl-net 1/2] ice: move ice_vsi_realloc_stat_arrays() up
From: Przemek Kitszel @ 2026-07-01 10:41 UTC (permalink / raw)
To: intel-wired-lan, Michal Schmidt, Jakub Kicinski
Cc: netdev, Tony Nguyen, Aleksandr Loktionov, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Jedrzej Jagielski,
Piotr Kwapulinski, Przemek Kitszel
Move ice_vsi_realloc_stat_arrays() up, to allow calling it from
ice_vsi_cfg_def() by the next commit.
Fix kdoc for touched code. One line break removed, "int i" scope
minimized to the loop, no changes otherwise.
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
drivers/net/ethernet/intel/ice/ice_lib.c | 119 +++++++++++------------
1 file changed, 59 insertions(+), 60 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 8cdc4fda89e9..e48ee5940f17 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -2303,6 +2303,65 @@ static int ice_vsi_cfg_tc_lan(struct ice_pf *pf, struct ice_vsi *vsi)
return 0;
}
+/**
+ * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones
+ * @vsi: VSI pointer
+ * Return: 0 on success or -ENOMEM on allocation failure.
+ */
+static int ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
+{
+ u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq;
+ u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq;
+ struct ice_ring_stats **tx_ring_stats;
+ struct ice_ring_stats **rx_ring_stats;
+ struct ice_vsi_stats *vsi_stat;
+ struct ice_pf *pf = vsi->back;
+ u16 prev_txq = vsi->alloc_txq;
+ u16 prev_rxq = vsi->alloc_rxq;
+
+ vsi_stat = pf->vsi_stats[vsi->idx];
+
+ if (req_txq < prev_txq) {
+ for (int i = req_txq; i < prev_txq; i++) {
+ if (vsi_stat->tx_ring_stats[i]) {
+ kfree_rcu(vsi_stat->tx_ring_stats[i], rcu);
+ WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL);
+ }
+ }
+ }
+
+ tx_ring_stats = vsi_stat->tx_ring_stats;
+ vsi_stat->tx_ring_stats =
+ krealloc_array(vsi_stat->tx_ring_stats, req_txq,
+ sizeof(*vsi_stat->tx_ring_stats),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!vsi_stat->tx_ring_stats) {
+ vsi_stat->tx_ring_stats = tx_ring_stats;
+ return -ENOMEM;
+ }
+
+ if (req_rxq < prev_rxq) {
+ for (int i = req_rxq; i < prev_rxq; i++) {
+ if (vsi_stat->rx_ring_stats[i]) {
+ kfree_rcu(vsi_stat->rx_ring_stats[i], rcu);
+ WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL);
+ }
+ }
+ }
+
+ rx_ring_stats = vsi_stat->rx_ring_stats;
+ vsi_stat->rx_ring_stats =
+ krealloc_array(vsi_stat->rx_ring_stats, req_rxq,
+ sizeof(*vsi_stat->rx_ring_stats),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!vsi_stat->rx_ring_stats) {
+ vsi_stat->rx_ring_stats = rx_ring_stats;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
/**
* ice_vsi_cfg_def - configure default VSI based on the type
* @vsi: pointer to VSI
@@ -3011,66 +3070,6 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
}
}
-/**
- * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones
- * @vsi: VSI pointer
- */
-static int
-ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
-{
- u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq;
- u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq;
- struct ice_ring_stats **tx_ring_stats;
- struct ice_ring_stats **rx_ring_stats;
- struct ice_vsi_stats *vsi_stat;
- struct ice_pf *pf = vsi->back;
- u16 prev_txq = vsi->alloc_txq;
- u16 prev_rxq = vsi->alloc_rxq;
- int i;
-
- vsi_stat = pf->vsi_stats[vsi->idx];
-
- if (req_txq < prev_txq) {
- for (i = req_txq; i < prev_txq; i++) {
- if (vsi_stat->tx_ring_stats[i]) {
- kfree_rcu(vsi_stat->tx_ring_stats[i], rcu);
- WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL);
- }
- }
- }
-
- tx_ring_stats = vsi_stat->tx_ring_stats;
- vsi_stat->tx_ring_stats =
- krealloc_array(vsi_stat->tx_ring_stats, req_txq,
- sizeof(*vsi_stat->tx_ring_stats),
- GFP_KERNEL | __GFP_ZERO);
- if (!vsi_stat->tx_ring_stats) {
- vsi_stat->tx_ring_stats = tx_ring_stats;
- return -ENOMEM;
- }
-
- if (req_rxq < prev_rxq) {
- for (i = req_rxq; i < prev_rxq; i++) {
- if (vsi_stat->rx_ring_stats[i]) {
- kfree_rcu(vsi_stat->rx_ring_stats[i], rcu);
- WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL);
- }
- }
- }
-
- rx_ring_stats = vsi_stat->rx_ring_stats;
- vsi_stat->rx_ring_stats =
- krealloc_array(vsi_stat->rx_ring_stats, req_rxq,
- sizeof(*vsi_stat->rx_ring_stats),
- GFP_KERNEL | __GFP_ZERO);
- if (!vsi_stat->rx_ring_stats) {
- vsi_stat->rx_ring_stats = rx_ring_stats;
- return -ENOMEM;
- }
-
- return 0;
-}
-
/**
* ice_vsi_rebuild - Rebuild VSI after reset
* @vsi: VSI to be rebuild
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v4 1/7] dt-bindings: mtd: jedec,spi-nor: allow the SFDP to be exposed via NVMEM
From: Linus Walleij @ 2026-07-01 10:53 UTC (permalink / raw)
To: Michael Walle
Cc: Manikandan Muralidharan, pratyush, mwalle, takahiro.kuwano,
miquel.raynal, richard, vigneshr, robh, krzk+dt, conor+dt, srini,
nicolas.ferre, alexandre.belloni, claudiu.beznea, linux,
richardcochran, arnd, linux-mtd, devicetree, linux-kernel,
linux-arm-kernel, netdev
In-Reply-To: <DJN3HIIAY4LE.3MXU9Q2YFSCJJ@walle.cc>
On Wed, Jul 1, 2026 at 10:34 AM Michael Walle <michael@walle.cc> wrote:
> If I'm correct, this is the old style, see commit bd912c991d2e
> ("dt-bindings: nvmem: layouts: add fixed-layout"). So it should
> eventually look like:
>
> sfdp {
> compatible = "jedec,sfdp";
(...)
> Also I'm not sure if we really need to add the "nvmem-cells" here.
> IIRC in MTD it was there to tell a driver to add an nvmem device to
> an already existing compatible/node.
>
> Apart from the MTD case, I've just found qcom,smem-part,yaml which
> has compatible = "nvmem-cells".
You're right, I was using old information, discard my comments...
Reviewed-by: Linus Walleij <linusw@kernel.org>
I think my comment in the driver to check for the compatible
instead of the node name is still valid though.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH net-next v9 5/5] net: wangxun: add pcie error handler
From: Breno Leitao @ 2026-07-01 10:44 UTC (permalink / raw)
To: Jiawen Wu
Cc: netdev, Mengyuan Lou, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Richard Cochran, Russell King,
Aleksandr Loktionov, Jacob Keller, Michal Swiatkowski,
Simon Horman, Kees Cook, Larysa Zaremba, Greg Kroah-Hartman,
Thomas Gleixner, Rongguang Wei,
Uwe Kleine-König (The Capable Hub), Fabio Baltieri
In-Reply-To: <20260701072357.33984-6-jiawenwu@trustnetic.com>
On Wed, Jul 01, 2026 at 03:23:57PM +0800, Jiawen Wu wrote:
> +static pci_ers_result_t wx_io_slot_reset(struct pci_dev *pdev)
> +{
> + struct wx *wx = pci_get_drvdata(pdev);
> + pci_ers_result_t result;
> +
> + if (pci_enable_device_mem(pdev)) {
> + wx_err(wx, "Cannot re-enable PCI device after reset.\n");
> + result = PCI_ERS_RESULT_DISCONNECT;
> + } else {
> + /* make all memory operations done before clearing the flag */
> + smp_mb__before_atomic();
> + clear_bit(WX_STATE_DISABLED, wx->state);
> + clear_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> + pci_set_master(pdev);
> + pci_restore_state(pdev);
> + pci_wake_from_d3(pdev, false);
> +
> + rtnl_lock();
> + if (netif_running(wx->netdev) && wx->down_suspend)
> + wx->down_suspend(wx);
> + if (wx->do_reset)
> + wx->do_reset(wx->netdev, false);
> + rtnl_unlock();
> + result = PCI_ERS_RESULT_RECOVERED;
> + }
> +
> + pci_aer_clear_nonfatal_status(pdev);
After bfcb79fca19d ("PCI/ERR: Run error recovery callbacks for all
affected devices"), AER errors are always cleared by the PCI core and
drivers don't need to do it themselves.
^ permalink raw reply
* [PATCH net 7/7] sfc: support pio mapping based on cxl
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Edward Cree
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
A PIO buffer is a region of device memory to which the driver can write a
packet for TX, with the device handling the transmit doorbell without
requiring a DMA for getting the packet data, which helps reducing latency
in certain exchanges. With CXL mem protocol this latency can be lowered
further.
With a device supporting CXL and successfully initialised, use the cxl
region to map the memory range and use this mapping for PIO buffers.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20260630151346.31201-6-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/ef10.c | 41 ++++++++++++++++++++++-----
drivers/net/ethernet/sfc/efx_cxl.c | 1 +
drivers/net/ethernet/sfc/net_driver.h | 2 ++
drivers/net/ethernet/sfc/nic.h | 3 ++
4 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 7e04f115bbaa..73bc064929f6 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <net/udp_tunnel.h>
+#include "efx_cxl.h"
/* Hardware control for EF10 architecture including 'Huntington'. */
@@ -106,7 +107,7 @@ static int efx_ef10_get_vf_index(struct efx_nic *efx)
static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
- MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V4_OUT_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V7_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
@@ -177,6 +178,12 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
efx->num_mac_stats);
}
+ if (outlen < MC_CMD_GET_CAPABILITIES_V7_OUT_LEN)
+ nic_data->datapath_caps3 = 0;
+ else
+ nic_data->datapath_caps3 = MCDI_DWORD(outbuf,
+ GET_CAPABILITIES_V7_OUT_FLAGS3);
+
return 0;
}
@@ -1140,6 +1147,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
unsigned int channel_vis, pio_write_vi_base, max_vis;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
unsigned int uc_mem_map_size, wc_mem_map_size;
+#ifdef CONFIG_SFC_CXL
+ struct efx_probe_data *probe_data;
+#endif
void __iomem *membase;
int rc;
@@ -1263,8 +1273,23 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
iounmap(efx->membase);
efx->membase = membase;
- /* Set up the WC mapping if needed */
- if (wc_mem_map_size) {
+ if (!wc_mem_map_size)
+ goto skip_pio;
+
+ /* Set up the WC mapping */
+
+#ifdef CONFIG_SFC_CXL
+ probe_data = container_of(efx, struct efx_probe_data, efx);
+ if ((nic_data->datapath_caps3 &
+ (1 << MC_CMD_GET_CAPABILITIES_V7_OUT_CXL_CONFIG_ENABLE_LBN)) &&
+ probe_data->cxl_pio_initialised) {
+ /* Using PIO through CXL mapping */
+ nic_data->pio_write_base = probe_data->cxl->ctpio_cxl;
+ nic_data->pio_write_vi_base = pio_write_vi_base;
+ } else
+#endif
+ {
+ /* Using legacy PIO BAR mapping */
nic_data->wc_membase = ioremap_wc(efx->membase_phys +
uc_mem_map_size,
wc_mem_map_size);
@@ -1279,12 +1304,14 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
nic_data->wc_membase +
(pio_write_vi_base * efx->vi_stride + ER_DZ_TX_PIOBUF -
uc_mem_map_size);
-
- rc = efx_ef10_link_piobufs(efx);
- if (rc)
- efx_ef10_free_piobufs(efx);
}
+ rc = efx_ef10_link_piobufs(efx);
+ if (rc)
+ efx_ef10_free_piobufs(efx);
+
+skip_pio:
+
netif_dbg(efx, probe, efx->net_dev,
"memory BAR at %pa (virtual %p+%x UC, %p+%x WC)\n",
&efx->membase_phys, efx->membase, uc_mem_map_size,
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 3e7c950f83e9..348d7404cd7a 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -88,6 +88,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
return -ENOMEM;
}
+ probe_data->cxl_pio_initialised = true;
probe_data->cxl = cxl;
return 0;
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 563e6a6e85f1..3964b2c56609 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1206,12 +1206,14 @@ struct efx_cxl;
* @pci_dev: The PCI device
* @efx: Efx NIC details
* @cxl: details of related cxl objects
+ * @cxl_pio_initialised: cxl initialization outcome.
*/
struct efx_probe_data {
struct pci_dev *pci_dev;
struct efx_nic efx;
#ifdef CONFIG_SFC_CXL
struct efx_cxl *cxl;
+ bool cxl_pio_initialised;
#endif
};
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index ec3b2df43b68..7480f9995dfb 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -152,6 +152,8 @@ enum {
* %MC_CMD_GET_CAPABILITIES response)
* @datapath_caps2: Further Capabilities of datapath firmware (FLAGS2 field of
* %MC_CMD_GET_CAPABILITIES response)
+ * @datapath_caps3: Further Capabilities of datapath firmware (FLAGS3 field of
+ * %MC_CMD_GET_CAPABILITIES response)
* @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU
* @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU
* @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot
@@ -187,6 +189,7 @@ struct efx_ef10_nic_data {
bool must_check_datapath_caps;
u32 datapath_caps;
u32 datapath_caps2;
+ u32 datapath_caps3;
unsigned int rx_dpcpu_fw_id;
unsigned int tx_dpcpu_fw_id;
bool must_probe_vswitching;
--
2.34.1
^ permalink raw reply related
* [PATCH net 5/7] sfc: Initialize cxl dpa
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Ben Cheatham, Jonathan Cameron,
Edward Cree
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Use cxl_set_capacity() for DPA initialization as no mailbox is
available.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20260630151346.31201-4-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/efx_cxl.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 704b0ebae937..18b535b3ea40 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -68,6 +68,11 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
*/
cxl->cxlds.media_ready = true;
+ if (cxl_set_capacity(&cxl->cxlds, EFX_CTPIO_BUFFER_SIZE)) {
+ pci_err(pci_dev, "dpa capacity setup failed\n");
+ return -ENODEV;
+ }
+
probe_data->cxl = cxl;
return 0;
--
2.34.1
^ permalink raw reply related
* [PATCH net 6/7] sfc: obtain and map cxl range using devm_cxl_probe_mem
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Edward Cree, Dan Williams
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Use core API for safely obtain the CXL range linked to an HDM committed
by the BIOS. Map such a range for being used as the ctpio buffer.
A potential user space action through sysfs unbinding or core cxl
modules remove will trigger sfc driver device detachment, with that case
not racing with this mapping as this is done during driver probe and
therefore protected with device lock against those user space actions.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: Dan Williams <djbw@kernel.org>
Link: https://patch.msgid.link/20260630151346.31201-5-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/efx.c | 2 ++
drivers/net/ethernet/sfc/efx_cxl.c | 23 +++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 3 +++
3 files changed, 28 insertions(+)
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 61cbb6cfc360..3806cd3dd7f4 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -984,6 +984,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_fini_io(efx);
probe_data = container_of(efx, struct efx_probe_data, efx);
+ efx_cxl_exit(probe_data);
pci_dbg(efx->pci_dev, "shutdown successful\n");
@@ -1242,6 +1243,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
return 0;
fail3:
+ efx_cxl_exit(probe_data);
efx_fini_io(efx);
fail2:
efx_fini_struct(efx);
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 18b535b3ea40..3e7c950f83e9 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -18,6 +18,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
{
struct efx_nic *efx = &probe_data->efx;
struct pci_dev *pci_dev = efx->pci_dev;
+ struct range cxl_pio_range;
struct efx_cxl *cxl;
u16 dvsec;
int rc;
@@ -73,9 +74,31 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
return -ENODEV;
}
+ cxl->cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl_pio_range);
+ if (IS_ERR(cxl->cxlmd)) {
+ pci_err(pci_dev, "CXL accel memdev creation failed\n");
+ return PTR_ERR(cxl->cxlmd);
+ }
+
+ cxl->ctpio_cxl = ioremap_wc(cxl_pio_range.start,
+ range_len(&cxl_pio_range));
+ if (!cxl->ctpio_cxl) {
+ pci_err(pci_dev, "CXL ioremap region (%pra) failed\n",
+ &cxl_pio_range);
+ return -ENOMEM;
+ }
+
probe_data->cxl = cxl;
return 0;
}
+void efx_cxl_exit(struct efx_probe_data *probe_data)
+{
+ if (!probe_data->cxl)
+ return;
+
+ iounmap(probe_data->cxl->ctpio_cxl);
+}
+
MODULE_IMPORT_NS("CXL");
diff --git a/drivers/net/ethernet/sfc/efx_cxl.h b/drivers/net/ethernet/sfc/efx_cxl.h
index 04e46278464d..3e2705cb063f 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.h
+++ b/drivers/net/ethernet/sfc/efx_cxl.h
@@ -20,10 +20,13 @@ struct efx_probe_data;
struct efx_cxl {
struct cxl_dev_state cxlds;
struct cxl_memdev *cxlmd;
+ void __iomem *ctpio_cxl;
};
int efx_cxl_init(struct efx_probe_data *probe_data);
+void efx_cxl_exit(struct efx_probe_data *probe_data);
#else
static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
+static inline void efx_cxl_exit(struct efx_probe_data *probe_data) {}
#endif
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH net 2/7] cxl: Support dpa without a mailbox
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Ben Cheatham, Jonathan Cameron,
Edward Cree
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Type3 relies on mailbox CXL_MBOX_OP_IDENTIFY command for initializing
memdev state params which end up being used for DPA initialization.
Allow a Type2 driver to initialize DPA simply by giving the size of its
volatile hardware partition.
Move related functions to memdev.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20260629183727.51502-3-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/cxl/core/core.h | 2 ++
drivers/cxl/core/mbox.c | 51 +----------------------------
drivers/cxl/core/memdev.c | 67 +++++++++++++++++++++++++++++++++++++++
include/cxl/cxl.h | 2 ++
4 files changed, 72 insertions(+), 50 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 07555ae63859..f7cebb026552 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -101,6 +101,8 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
struct dentry *cxl_debugfs_create_dir(const char *dir);
int cxl_dpa_set_part(struct cxl_endpoint_decoder *cxled,
enum cxl_partition_mode mode);
+struct cxl_memdev_state;
+int cxl_mem_get_partition_info(struct cxl_memdev_state *mds);
int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size);
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 7c6c5b7450a5..97b1e61ad018 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1152,7 +1152,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL");
*
* See CXL @8.2.9.5.2.1 Get Partition Info
*/
-static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
+int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
struct cxl_mbox_get_partition_info pi;
@@ -1308,55 +1308,6 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
return -EBUSY;
}
-static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
-{
- int i = info->nr_partitions;
-
- if (size == 0)
- return;
-
- info->part[i].range = (struct range) {
- .start = start,
- .end = start + size - 1,
- };
- info->part[i].mode = mode;
- info->nr_partitions++;
-}
-
-int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
-{
- struct cxl_dev_state *cxlds = &mds->cxlds;
- struct device *dev = cxlds->dev;
- int rc;
-
- if (!cxlds->media_ready) {
- info->size = 0;
- return 0;
- }
-
- info->size = mds->total_bytes;
-
- if (mds->partition_align_bytes == 0) {
- add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
- add_part(info, mds->volatile_only_bytes,
- mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
- return 0;
- }
-
- rc = cxl_mem_get_partition_info(mds);
- if (rc) {
- dev_err(dev, "Failed to query partition information\n");
- return rc;
- }
-
- add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
- add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
- CXL_PARTMODE_PMEM);
-
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
-
int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 33a3d2e7b13a..2e457b1ebc7d 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -594,6 +594,73 @@ bool is_cxl_memdev(const struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL");
+static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
+{
+ int i = info->nr_partitions;
+
+ if (size == 0)
+ return;
+
+ info->part[i].range = (struct range) {
+ .start = start,
+ .end = start + size - 1,
+ };
+ info->part[i].mode = mode;
+ info->nr_partitions++;
+}
+
+int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
+{
+ struct cxl_dev_state *cxlds = &mds->cxlds;
+ struct device *dev = cxlds->dev;
+ int rc;
+
+ if (!cxlds->media_ready) {
+ info->size = 0;
+ return 0;
+ }
+
+ info->size = mds->total_bytes;
+
+ if (mds->partition_align_bytes == 0) {
+ add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
+ add_part(info, mds->volatile_only_bytes,
+ mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
+ return 0;
+ }
+
+ rc = cxl_mem_get_partition_info(mds);
+ if (rc) {
+ dev_err(dev, "Failed to query partition information\n");
+ return rc;
+ }
+
+ add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
+ add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
+ CXL_PARTMODE_PMEM);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
+
+
+/**
+ * cxl_set_capacity: initialize dpa by a driver without a mailbox.
+ *
+ * @cxlds: pointer to cxl_dev_state
+ * @capacity: device volatile memory size
+ */
+int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity)
+{
+ struct cxl_dpa_info range_info = {
+ .size = capacity,
+ };
+
+ add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM);
+ return cxl_dpa_setup(cxlds, &range_info);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_set_capacity, "CXL");
+
/**
* set_exclusive_cxl_commands() - atomically disable user cxl commands
* @mds: The device state to operate on
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 016c74fb747c..802b143de83d 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -226,4 +226,6 @@ struct cxl_dev_state *_devm_cxl_dev_state_create(struct device *dev,
struct cxl_memdev *devm_cxl_probe_mem(struct cxl_dev_state *cxlds,
struct range *range);
+
+int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity);
#endif /* __CXL_CXL_H__ */
--
2.34.1
^ permalink raw reply related
* [PATCH net 3/7] sfc: add cxl support
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Jonathan Cameron, Edward Cree, Alison Schofield,
Dan Williams
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Add CXL initialization based on new CXL API for accel drivers and make
it dependent on kernel CXL configuration.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260630151346.31201-2-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/Kconfig | 9 +++++
drivers/net/ethernet/sfc/Makefile | 1 +
drivers/net/ethernet/sfc/efx.c | 16 ++++++++-
drivers/net/ethernet/sfc/efx_cxl.c | 50 +++++++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 29 ++++++++++++++++
drivers/net/ethernet/sfc/net_driver.h | 8 +++++
6 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.c
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.h
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index c4c43434f314..979f2801e2a8 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -66,6 +66,15 @@ config SFC_MCDI_LOGGING
Driver-Interface) commands and responses, allowing debugging of
driver/firmware interaction. The tracing is actually enabled by
a sysfs file 'mcdi_logging' under the PCI device.
+config SFC_CXL
+ bool "Solarflare SFC9100-family CXL support"
+ depends on SFC && CXL_BUS >= SFC
+ default SFC
+ help
+ This enables SFC CXL support if the kernel is configuring CXL for
+ using CTPIO with CXL.mem. The SFC device with CXL support and
+ with a CXL-aware firmware can be used for minimizing latencies
+ when sending through CTPIO.
source "drivers/net/ethernet/sfc/falcon/Kconfig"
source "drivers/net/ethernet/sfc/siena/Kconfig"
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index d99039ec468d..bb0f1891cde6 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -13,6 +13,7 @@ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
mae.o tc.o tc_bindings.o tc_counters.o \
tc_encap_actions.o tc_conntrack.o
+sfc-$(CONFIG_SFC_CXL) += efx_cxl.o
obj-$(CONFIG_SFC) += sfc.o
obj-$(CONFIG_SFC_FALCON) += falcon/
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 8f136a11d396..61cbb6cfc360 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -34,6 +34,7 @@
#include "selftest.h"
#include "sriov.h"
#include "efx_devlink.h"
+#include "efx_cxl.h"
#include "mcdi_port_common.h"
#include "mcdi_pcol.h"
@@ -981,12 +982,14 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_pci_remove_main(efx);
efx_fini_io(efx);
+
+ probe_data = container_of(efx, struct efx_probe_data, efx);
+
pci_dbg(efx->pci_dev, "shutdown successful\n");
efx_fini_devlink_and_unlock(efx);
efx_fini_struct(efx);
free_netdev(efx->net_dev);
- probe_data = container_of(efx, struct efx_probe_data, efx);
kfree(probe_data);
};
@@ -1190,6 +1193,17 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail2;
+ /* A successful cxl initialization implies a CXL region created to be
+ * used for PIO buffers. If there is no CXL support legacy PIO buffers
+ * defined at specific PCI BAR regions will be used. If there is CXL
+ * support and the cxl initialization fails, the driver probe fails.
+ */
+ rc = efx_cxl_init(probe_data);
+ if (rc) {
+ pci_err(pci_dev, "CXL initialization failed with error %d\n", rc);
+ goto fail3;
+ }
+
rc = efx_pci_probe_post_io(efx);
if (rc) {
/* On failure, retry once immediately.
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
new file mode 100644
index 000000000000..be252af972ab
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ *
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2025, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/pci.h>
+
+#include "net_driver.h"
+#include "efx_cxl.h"
+
+#define EFX_CTPIO_BUFFER_SIZE SZ_256M
+
+int efx_cxl_init(struct efx_probe_data *probe_data)
+{
+ struct efx_nic *efx = &probe_data->efx;
+ struct pci_dev *pci_dev = efx->pci_dev;
+ struct efx_cxl *cxl;
+ u16 dvsec;
+
+ /* Is the device configured with and using CXL? */
+ if (!pcie_is_cxl(pci_dev))
+ return 0;
+
+ dvsec = pci_find_dvsec_capability(pci_dev, PCI_VENDOR_ID_CXL,
+ PCI_DVSEC_CXL_DEVICE);
+ if (!dvsec) {
+ pci_info(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability not found\n");
+ return 0;
+ }
+
+ pci_dbg(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability found\n");
+
+ /* Create a cxl_dev_state embedded in the cxl struct using cxl core api
+ * specifying no mbox available.
+ */
+ cxl = devm_cxl_dev_state_create(&pci_dev->dev, CXL_DEVTYPE_DEVMEM,
+ pci_get_dsn(pci_dev), dvsec,
+ struct efx_cxl, cxlds, false);
+
+ if (!cxl)
+ return -ENOMEM;
+
+ probe_data->cxl = cxl;
+
+ return 0;
+}
+
+MODULE_IMPORT_NS("CXL");
diff --git a/drivers/net/ethernet/sfc/efx_cxl.h b/drivers/net/ethernet/sfc/efx_cxl.h
new file mode 100644
index 000000000000..04e46278464d
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_cxl.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2025, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_CXL_H
+#define EFX_CXL_H
+
+#ifdef CONFIG_SFC_CXL
+
+#include <cxl/cxl.h>
+
+struct efx_probe_data;
+
+struct efx_cxl {
+ struct cxl_dev_state cxlds;
+ struct cxl_memdev *cxlmd;
+};
+
+int efx_cxl_init(struct efx_probe_data *probe_data);
+#else
+static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
+#endif
+#endif
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index b98c259f672d..563e6a6e85f1 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1197,14 +1197,22 @@ struct efx_nic {
atomic_t n_rx_noskb_drops;
};
+#ifdef CONFIG_SFC_CXL
+struct efx_cxl;
+#endif
+
/**
* struct efx_probe_data - State after hardware probe
* @pci_dev: The PCI device
* @efx: Efx NIC details
+ * @cxl: details of related cxl objects
*/
struct efx_probe_data {
struct pci_dev *pci_dev;
struct efx_nic efx;
+#ifdef CONFIG_SFC_CXL
+ struct efx_cxl *cxl;
+#endif
};
static inline struct efx_nic *efx_netdev_priv(struct net_device *dev)
--
2.34.1
^ permalink raw reply related
* [PATCH net 4/7] sfc: Map cxl regs
From: alejandro.lucero-palau @ 2026-07-01 11:38 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Jonathan Cameron, Ben Cheatham,
Edward Cree
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Use cxl core functions for discovering and mapping CXL device registers.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20260630151346.31201-3-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/efx_cxl.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index be252af972ab..704b0ebae937 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -7,6 +7,8 @@
#include <linux/pci.h>
+#include <cxl/cxl.h>
+#include <cxl/pci.h>
#include "net_driver.h"
#include "efx_cxl.h"
@@ -18,6 +20,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
struct pci_dev *pci_dev = efx->pci_dev;
struct efx_cxl *cxl;
u16 dvsec;
+ int rc;
/* Is the device configured with and using CXL? */
if (!pcie_is_cxl(pci_dev))
@@ -42,6 +45,29 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
if (!cxl)
return -ENOMEM;
+ rc = cxl_pci_setup_regs(pci_dev, CXL_REGLOC_RBI_COMPONENT,
+ &cxl->cxlds.reg_map);
+ if (rc) {
+ pci_err(pci_dev, "No component registers\n");
+ return rc;
+ }
+
+ if (!cxl->cxlds.reg_map.component_map.hdm_decoder.valid) {
+ pci_err(pci_dev, "Expected HDM component register not found\n");
+ return -ENODEV;
+ }
+
+ if (!cxl->cxlds.reg_map.component_map.ras.valid) {
+ pci_err(pci_dev, "Expected RAS component register not found\n");
+ return -ENODEV;
+ }
+
+ /* Set media ready explicitly as there are neither mailbox for checking
+ * this state nor the CXL register involved, both not mandatory for
+ * type2.
+ */
+ cxl->cxlds.media_ready = true;
+
probe_data->cxl = cxl;
return 0;
--
2.34.1
^ permalink raw reply related
* [PATCH net 0/7] pull request: sfc 2026-07-01
From: alejandro.lucero-palau @ 2026-07-01 11:37 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang; +Cc: Alejandro Lucero
From: Alejandro Lucero <alucerop@amd.com>
Dear net maintainers,
here are the last CXL core changes for enabling CXL Type2 drivers to
initialize a CXL-capable device plus the netdev sfc driver changes using
this new CXL core Type2 support.
Please pull or let me know of any problem!
Thank you,
Alejandro
The following changes since commit dc59e4fea9d83f03bad6bddf3fa2e52491777482:
Linux 7.2-rc1 (2026-06-28 12:01:31 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git tags/sfc-net-pullrequest-20260630
for you to fetch changes up to bd6550bcdb0c0bcc6e29706ffe2e64708192342b:
sfc: support pio mapping based on cxl (2026-06-30 15:24:16 -0700)
----------------------------------------------------------------
SFC changes for CXL type2 enabling
----------------------------------------------------------------
Alejandro Lucero (7):
cxl: Support Type2 cxl regs mapping
cxl: Support dpa without a mailbox
sfc: add cxl support
sfc: Map cxl regs
sfc: Initialize cxl dpa
sfc: obtain and map cxl range using devm_cxl_probe_mem
sfc: support pio mapping based on cxl
drivers/cxl/core/core.h | 2 +
drivers/cxl/core/mbox.c | 51 +------------
drivers/cxl/core/memdev.c | 67 ++++++++++++++++
drivers/cxl/core/pci.c | 1 +
drivers/cxl/core/port.c | 1 +
drivers/cxl/core/regs.c | 1 +
drivers/cxl/cxlpci.h | 12 ---
drivers/cxl/pci.c | 1 +
drivers/net/ethernet/sfc/Kconfig | 9 +++
drivers/net/ethernet/sfc/Makefile | 1 +
drivers/net/ethernet/sfc/ef10.c | 41 ++++++++--
drivers/net/ethernet/sfc/efx.c | 18 ++++-
drivers/net/ethernet/sfc/efx_cxl.c | 105 ++++++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 32 ++++++++
drivers/net/ethernet/sfc/net_driver.h | 10 +++
drivers/net/ethernet/sfc/nic.h | 3 +
include/cxl/cxl.h | 2 +
include/cxl/pci.h | 22 ++++++
18 files changed, 309 insertions(+), 70 deletions(-)
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.c
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.h
create mode 100644 include/cxl/pci.h
--
2.34.1
^ permalink raw reply
* [PATCH net 1/7] cxl: Support Type2 cxl regs mapping
From: alejandro.lucero-palau @ 2026-07-01 11:37 UTC (permalink / raw)
To: netdev, kuba, davem, edumazet, pabeni, horms, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Jonathan Cameron, Ben Cheatham,
Edward Cree
In-Reply-To: <20260701113805.14072-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Export cxl core functions for a Type2 driver being able to discover and
map the device registers.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Link: https://patch.msgid.link/20260629183727.51502-2-alejandro.lucero-palau@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/cxl/core/pci.c | 1 +
drivers/cxl/core/port.c | 1 +
drivers/cxl/core/regs.c | 1 +
drivers/cxl/cxlpci.h | 12 ------------
drivers/cxl/pci.c | 1 +
include/cxl/pci.h | 22 ++++++++++++++++++++++
6 files changed, 26 insertions(+), 12 deletions(-)
create mode 100644 include/cxl/pci.h
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index e4338fd7e01b..9d807c1a002c 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
+#include <cxl/pci.h>
#include <linux/aer.h>
#include <cxlpci.h>
#include <cxlmem.h>
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 1215ee4f4035..cb633e19151b 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <linux/node.h>
#include <cxl/einj.h>
+#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <cxl.h>
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 93710cf4f0a6..20c2d9fbcfe7 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <pmu.h>
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index b826eb53cf7b..110ec9c44f09 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -13,16 +13,6 @@
*/
#define CXL_PCI_DEFAULT_MAX_VECTORS 16
-/* Register Block Identifier (RBI) */
-enum cxl_regloc_type {
- CXL_REGLOC_RBI_EMPTY = 0,
- CXL_REGLOC_RBI_COMPONENT,
- CXL_REGLOC_RBI_VIRT,
- CXL_REGLOC_RBI_MEMDEV,
- CXL_REGLOC_RBI_PMU,
- CXL_REGLOC_RBI_TYPES
-};
-
/*
* Table Access DOE, CDAT Read Entry Response
*
@@ -112,6 +102,4 @@ static inline void devm_cxl_port_ras_setup(struct cxl_port *port)
}
#endif
-int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
- struct cxl_register_map *map);
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 267c679b0b3c..bb892dbfdd6d 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/io.h>
+#include <cxl/pci.h>
#include <cxl/mailbox.h>
#include "cxlmem.h"
#include "cxlpci.h"
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
new file mode 100644
index 000000000000..3e0000015871
--- /dev/null
+++ b/include/cxl/pci.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+
+#ifndef __CXL_CXL_PCI_H__
+#define __CXL_CXL_PCI_H__
+
+/* Register Block Identifier (RBI) */
+enum cxl_regloc_type {
+ CXL_REGLOC_RBI_EMPTY = 0,
+ CXL_REGLOC_RBI_COMPONENT,
+ CXL_REGLOC_RBI_VIRT,
+ CXL_REGLOC_RBI_MEMDEV,
+ CXL_REGLOC_RBI_PMU,
+ CXL_REGLOC_RBI_TYPES
+};
+
+struct cxl_register_map;
+struct pci_dev;
+
+int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
+ struct cxl_register_map *map);
+#endif
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 3/6] firmware: qcom: scm: Add support for setting Bluetooth power modes
From: Konrad Dybcio @ 2026-07-01 10:40 UTC (permalink / raw)
To: george.moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
Konrad Dybcio, Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-3-02770f03b6bb@outlook.com>
On 6/29/26 3:01 PM, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
>
> The Bluetooth subsystem (BTSS) on the IPQ5018 SoC supports setting power
> modes which are required to be configured through a Secure Channel
> Manager (SCM) call to TrustZone. However, not all Trusted Execution
> Environment (QSEE) images support this call, so first check if the call
> is available.
>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
I'm amazed changing this setting is a secure operation
[...]
> +/**
> + * qcom_scm_pas_set_bluetooth_power_mode() - Configure power optimization mode
> + * for the Bluetooth subsystem (BTSS)
> + * @pas_id: peripheral authentication service id
> + * @val: 0x0 for normal operation, 0x4 for ECO mode
If there's just two values, maybe we should make this take a `bool eco_mode`?
> + *
> + * Return: 0 on success, negative errno on failure.
> + * Returns -EOPNOTSUPP if the firmware configuration call is unavailable.
> + */
> +int qcom_scm_pas_set_bluetooth_power_mode(u32 pas_id, u32 val)
> +{
> + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
> + QCOM_SCM_PIL_PAS_BT_PWR_MODE))
> + return -EOPNOTSUPP;
> +
> + return __qcom_scm_pas_set_bluetooth_power_mode(pas_id, val);
Let's just inline the whole definition here - it's single-use anyway
Konrad
^ permalink raw reply
* Re: [PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p
From: Bartosz Golaszewski @ 2026-07-01 10:39 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Geert Uytterhoeven, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
Alexandre Torgue, Giuseppe Cavallaro, Chen-Yu Tsai,
Jernej Skrabec, Neil Armstrong, Kevin Hilman, Jerome Brunet,
Shawn Guo, Fabio Estevam, Jan Petrous, s32, Mohd Ayaan Anwar,
Romain Gantois, Magnus Damm, Maxime Ripard, Christophe Roullier,
Radu Rendec, linux-arm-msm, devicetree, linux-kernel, netdev,
linux-stm32, linux-arm-kernel, Drew Fustini, linux-sunxi,
linux-amlogic, linux-mips, imx, linux-renesas-soc, linux-rockchip,
sophgo, linux-riscv, Bartosz Golaszewski, Bartosz Golaszewski,
Vinod Koul
In-Reply-To: <CAMRc=MfgAB8bc6PD-6jw_KR0uNBfH+PO2XtCeL1SUF2nCiT0xg@mail.gmail.com>
On Tue, 30 Jun 2026 15:44:16 +0200, Bartosz Golaszewski <brgl@kernel.org> said:
> On Tue, 30 Jun 2026 12:23:16 +0200, Vinod Koul <vkoul@kernel.org> said:
>> On 29-06-26, 16:51, Geert Uytterhoeven wrote:
>>> > Russell King asked me to put the PHY logic for SCMI pm domains into the PHY
>>> > driver instead of the MAC driver where it was previously. Instead of cramming
>>> > both HLOS and firmware handling into the same driver, I figured it makes more
>>> > sense to have a dedicated, cleaner driver as the two share very little code (if
>>> > any).
>>>
>>> I think you are mixing up DT bindings and driver implementation?
>>
>> Should the bindings change if we have different driver and firmware
>> implementations? Isn't binding supposed to be agnostic of
>> implementations..?
>>
>
> The way sa8255p implements SCMI is with SMC exclusively but - since even base
> support is not yet upstream - maybe it would be possible to expose SCMI clocks
> like some platforms do and reuse the same binding.
>
> Would it make sense?
>
> Bart
>
Scratch that. The firmware on sa8255p does not expose SCMI clock protocol, we
can only use devfs with this PHY so it's either the same binding document with
different properties depending on compatible or two separate bindings. I prefer
the latter because it's cleaner.
Bartosz
^ permalink raw reply
* [PATCH] selftests: mptcp: mptcp_diag: fix stack buffer overflow in get_subflow_info()
From: Jiangshan Yi @ 2026-07-01 10:38 UTC (permalink / raw)
To: geliang, martineau, matttbe
Cc: davem, edumazet, kuba, pabeni, horms, shuah, netdev, mptcp,
linux-kselftest, linux-kernel, 13667453960, Jiangshan Yi
get_subflow_info() parses the subflow address string with:
char saddr[64], daddr[64];
ret = sscanf(subflow_addrs, "%[^:]:%d %[^:]:%d",
saddr, &sport, daddr, &dport);
The subflow_addrs buffer holds up to 1024 bytes and is taken directly
from the command line ("-c" argument). The "%[^:]" conversions have no
maximum field width, so if the address substring before the ':' exceeds
63 bytes, sscanf() writes past the end of the 64-byte saddr/daddr stack
buffers. This overflows the stack, corrupting adjacent stack data such
as the saved return address, and can crash the tool or lead to
out-of-bounds writes controlled by user-supplied input.
Bound both string conversions to the destination buffer size by adding
an explicit maximum field width of 63 (leaving room for the terminating
NUL), so at most 63 bytes are written into each 64-byte buffer:
ret = sscanf(subflow_addrs, "%63[^:]:%d %63[^:]:%d",
saddr, &sport, daddr, &dport);
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_diag.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_diag.c b/tools/testing/selftests/net/mptcp/mptcp_diag.c
index 5e222ba977e4..02ac93f794fe 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_diag.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_diag.c
@@ -377,7 +377,7 @@ static void get_subflow_info(char *subflow_addrs)
int ret;
int fd;
- ret = sscanf(subflow_addrs, "%[^:]:%d %[^:]:%d", saddr, &sport, daddr, &dport);
+ ret = sscanf(subflow_addrs, "%63[^:]:%d %63[^:]:%d", saddr, &sport, daddr, &dport);
if (ret != 4)
die_perror("IP PORT Pairs has style problems!");
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] net: airoha: fix MIB stats collection to be lossless
From: Aniket Negi @ 2026-07-01 10:29 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev,
linux-kernel, aniket.negi
In-Reply-To: <akS48y8gCJf-EmTP@lore-desk>
> Maybe better mib_prev?
Ok sure will update. mib_prev is cleaner and more concise.
> Since now we do not reset the MIB counters in airoha_update_hw_stats(), we can
> get rid of the for loop there and just call airoha_dev_get_hw_stats() with the
> provided dev pointer. Even better, just rename airoha_dev_get_hw_stats() in
> airoha_update_hw_stats() and move the spinlock there. What do you think?
I am aligned with your suggestion, Since after removing MIB reset logic, there isn't need to iterate over all devs on airoha_gdm_port. This will simplify the code significantly.
I'll refactor as follows:
1. Remove the for loop in airoha_update_hw_stats()
2. Rename airoha_dev_get_hw_stats() to airoha_update_hw_stats()
3) move the spinlock into the renamed function.
Best Regards,
Aniket Negi
^ permalink raw reply
* Re: [PATCH net 8/8] ixgbe: only access vfinfo and mv_list under RCU lock
From: Corinna Vinschen @ 2026-07-01 10:15 UTC (permalink / raw)
To: Jakub Kicinski
Cc: anthony.l.nguyen, davem, pabeni, edumazet, andrew+netdev, netdev,
alexander.nowlin, Corinna Vinschen
In-Reply-To: <20260523001605.1757032-1-kuba@kernel.org>
Hi Jakub, hi others,
sorry for the late reply, I was AFK for two months.
I scanned the review points and most of them raise important questions.
This mail is only to let you know that I started looking into them
and I will follow up with a new patch in the next few weeks.
Thanks,
Corinna
On May 22 17:16, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> ixgbe: only access vfinfo and mv_list under RCU lock
>
> This change drops the vfs_lock spinlock in favour of RCU protection
> for adapter->vfinfo and adapter->mv_list, marking them __rcu and
> converting readers to rcu_dereference()/rcu_read_lock() and writers
> to rcu_replace_pointer()/kfree_rcu(). The goal is to address a
> crash observed when ixgbe_disable_sriov() races with
> ixgbe_service_task() / ixgbe_msg_task() readers.
>
> > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
> > index 9b8217523fd2..8849b9f42bf6 100644
> > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
> > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
> > @@ -808,10 +810,10 @@ struct ixgbe_adapter {
> > /* SR-IOV */
> > DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
> > unsigned int num_vfs;
> > - struct vf_data_storage *vfinfo;
> > + struct vf_data_storage __rcu *vfinfo;
> > int vf_rate_link_speed;
> > struct vf_macvlans vf_mvs;
> > - struct vf_macvlans *mv_list;
> > + struct vf_macvlans __rcu *mv_list;
>
> [Medium]
> After this conversion, is ixgbe_handle_mdd_event() in
> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c still consistent
> with the new annotations? It contains:
>
> if (adapter->vfinfo && ixgbe_check_mdd_event(adapter)) {
>
> That bare load of an __rcu pointer is not wrapped in
> rcu_read_lock() and does not use rcu_access_pointer() or
> rcu_dereference(), so sparse will flag it and the access
> bypasses the RCU discipline used elsewhere in the file. The
> commit message says RCU is used "throughout the driver" — was
> this site simply missed during the conversion?
>
> [ ... ]
>
> > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> > index 2646ee6f295f..d82c7dfc6580 100644
> > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>
> [ ... ]
>
> > @@ -8267,22 +8293,27 @@ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
> > @@ -8309,9 +8340,15 @@ static void ixgbe_check_for_bad_vf(struct ixgbe_adapter *adapter)
> >
> > /* check status reg for all VFs owned by this PF */
> > for (vf = 0; vf < adapter->num_vfs; ++vf) {
> > - struct pci_dev *vfdev = adapter->vfinfo[vf].vfdev;
> > + struct vf_data_storage *vfinfo;
> > + struct pci_dev *vfdev = NULL;
> > u16 status_reg;
> >
> > + rcu_read_lock();
> > + vfinfo = rcu_dereference(adapter->vfinfo);
> > + if (vfinfo)
> > + vfdev = vfinfo[vf].vfdev;
> > + rcu_read_unlock();
> > if (!vfdev)
> > continue;
> > pci_read_config_word(vfdev, PCI_STATUS, &status_reg);
>
> [High]
> Can vfdev still be used safely after rcu_read_unlock() here?
>
> The RCU section only protects the lifetime of the vfinfo array,
> not the lifetime of the pci_dev whose pointer was stored in it.
> ixgbe_disable_sriov() drops the reference taken by
> ixgbe_get_vfs() with pci_dev_put(vfdev) and then proceeds to
> pci_disable_sriov(), either of which can free the pci_dev
> concurrently with the subsequent pci_read_config_word() and the
> pcie_flr(vfdev) reached through ixgbe_bad_vf_abort().
>
> Should this path take pci_dev_get(vfdev) before dropping the
> rcu_read_unlock(), and pci_dev_put() after the config-space
> access and FLR are complete?
>
> This appears to predate this patch (the prior code dereferenced
> vfdev outside any lifetime-extending section as well), but the
> RCU conversion seems like a natural opportunity to address it.
>
> [ ... ]
>
> > @@ -10071,20 +10114,26 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex,
> > {
> > struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
> > unsigned int num_vfs = adapter->num_vfs, vf;
> > + struct vf_data_storage *vfinfo;
> > struct netdev_nested_priv priv;
> > struct upper_walk_data data;
> > struct net_device *upper;
> >
> > /* redirect to a SRIOV VF */
> > - for (vf = 0; vf < num_vfs; ++vf) {
> > - upper = pci_get_drvdata(adapter->vfinfo[vf].vfdev);
> > - if (upper->ifindex == ifindex) {
> > - *queue = vf * __ALIGN_MASK(1, ~vmdq->mask);
> > - *action = vf + 1;
> > - *action <<= ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
> > - return 0;
> > + rcu_read_lock();
> > + vfinfo = rcu_dereference(adapter->vfinfo);
> > + if (vfinfo)
> > + for (vf = 0; vf < num_vfs; ++vf) {
> > + upper = pci_get_drvdata(vfinfo[vf].vfdev);
>
> [High]
> Can the captured num_vfs and the freshly-dereferenced vfinfo
> disagree in size here?
>
> num_vfs is sampled from adapter->num_vfs before rcu_read_lock(),
> while vfinfo is observed inside the RCU section. ixgbe_disable_sriov()
> runs under PCI device_lock (not rtnl), sets adapter->num_vfs = 0,
> and rcu_replace_pointer()s vfinfo. A subsequent
> __ixgbe_enable_sriov(N2) can publish a smaller vfinfo array of
> size N2 < num_vfs before the loop runs. The access vfinfo[vf]
> for vf >= N2 is then a heap out-of-bounds read.
>
> Should num_vfs be sampled inside the rcu_read_lock() and bounded
> by the actual size of the published vfinfo, or should
> adapter->num_vfs be updated as part of the same rcu_assign_pointer
> publication so readers can rely on a consistent pair?
>
> [ ... ]
>
> > @@ -9744,15 +9781,21 @@ static int ixgbe_ndo_get_vf_stats(struct net_device *netdev, int vf,
> > struct ifla_vf_stats *vf_stats)
> > {
> > struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
> > + struct vf_data_storage *vfinfo;
> >
> > if (vf < 0 || vf >= adapter->num_vfs)
> > return -EINVAL;
> >
> > - vf_stats->rx_packets = adapter->vfinfo[vf].vfstats.gprc;
> > - vf_stats->rx_bytes = adapter->vfinfo[vf].vfstats.gorc;
> > - vf_stats->tx_packets = adapter->vfinfo[vf].vfstats.gptc;
> > - vf_stats->tx_bytes = adapter->vfinfo[vf].vfstats.gotc;
> > - vf_stats->multicast = adapter->vfinfo[vf].vfstats.mprc;
> > + rcu_read_lock();
> > + vfinfo = rcu_dereference(adapter->vfinfo);
> > + if (vfinfo) {
> > + vf_stats->rx_packets = vfinfo[vf].vfstats.gprc;
> > + vf_stats->rx_bytes = vfinfo[vf].vfstats.gorc;
> > + vf_stats->tx_packets = vfinfo[vf].vfstats.gptc;
> > + vf_stats->tx_bytes = vfinfo[vf].vfstats.gotc;
> > + vf_stats->multicast = vfinfo[vf].vfstats.mprc;
> > + }
> > + rcu_read_unlock();
>
> [High]
> This pattern recurs in many of the rtnl ndo handlers (set_vf_mac,
> set_vf_spoofchk, set_vf_rss_query_en, set_vf_trust, set_vf_vlan,
> set_vf_bw, get_vf_config, get_vf_stats): the bound check
>
> if (vf >= adapter->num_vfs)
> return -EINVAL;
>
> is performed before rcu_read_lock(). Between that check and the
> later rcu_dereference, ixgbe_disable_sriov() (under PCI device_lock,
> not rtnl) can set num_vfs = 0 and __ixgbe_enable_sriov() can
> republish vfinfo at a smaller size N2.
>
> For ixgbe_ndo_get_vf_config() the resulting OOB read is then
> memcpy'd into struct ifla_vf_info and returned to userspace via
> netlink, which would expose adjacent kernel heap. For the setter
> ndos and the mailbox-driven setters, this is an out-of-bounds
> write.
>
> Should the vf range check be repeated against the size of the
> freshly observed vfinfo, ideally with num_vfs and vfinfo
> published together so the pair is self-consistent?
>
> > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
> > index 431d77da15a5..80f22a8e7af4 100644
> > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
> > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
>
> [ ... ]
>
> > @@ -206,31 +214,28 @@ int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
> > {
> > unsigned int num_vfs = adapter->num_vfs, vf;
> > struct ixgbe_hw *hw = &adapter->hw;
> > - unsigned long flags;
> > + struct vf_data_storage *vfinfo;
> > + struct vf_macvlans *mv_list;
> > int rss;
> >
> > - spin_lock_irqsave(&adapter->vfs_lock, flags);
> > - /* set num VFs to 0 to prevent access to vfinfo */
> > + /* set num VFs to 0 so readers bail out early */
> > adapter->num_vfs = 0;
> > - spin_unlock_irqrestore(&adapter->vfs_lock, flags);
> > +
> > + vfinfo = rcu_replace_pointer(adapter->vfinfo, NULL, 1);
> > + mv_list = rcu_replace_pointer(adapter->mv_list, NULL, 1);
>
> [Low]
> The lockdep predicate passed to rcu_replace_pointer() is the
> literal 1, which makes the writer-side assertion always succeed
> and provides no verification. The patch simultaneously removes
> vfs_lock and shifts to an implicit (undocumented) reliance on
> some caller serialization for the writer.
>
> Could lockdep_is_held() of the actual writer-side lock (for
> example the PCI device_lock or rtnl_lock, whichever is intended)
> be used here so a future regression that calls
> ixgbe_disable_sriov() outside that context is caught by lockdep?
>
> [ ... ]
>
> > @@ -643,10 +668,16 @@ static void ixgbe_clear_vf_vlans(struct ixgbe_adapter *adapter, u32 vf)
> > static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
> > int vf, int index, unsigned char *mac_addr)
> > {
> > - struct vf_macvlans *entry;
> > + struct vf_macvlans *mv_list, *entry;
> > bool found = false;
> > int retval = 0;
> >
> > + lockdep_assert_in_rcu_read_lock();
> > + /* vf_mvs entries point into the mv_list array */
> > + mv_list = rcu_dereference(adapter->mv_list);
> > + if (!mv_list)
> > + return 0;
> > +
> > if (index <= 1) {
> > list_for_each_entry(entry, &adapter->vf_mvs.l, l) {
>
> [High]
> Is non-RCU list iteration safe here while only rcu_read_lock()
> is held?
>
> The list head &adapter->vf_mvs.l is mutated by the writer side
> without RCU-aware primitives. ixgbe_alloc_vf_macvlans() does:
>
> INIT_LIST_HEAD(&adapter->vf_mvs.l);
> ...
> list_add(&mv_list[i].l, &adapter->vf_mvs.l);
>
> and ixgbe_disable_sriov() kfree_rcu()s mv_list but never
> reinitialises &adapter->vf_mvs.l, so on a subsequent
> re-enable the writer concurrently zeros and re-links the head
> while a reader walks it.
>
> Should list_for_each_entry() be list_for_each_entry_rcu(), and
> the writer use INIT_LIST_HEAD_RCU() / list_add_rcu()? Otherwise
> the reader can observe torn next/prev loads or follow into
> freed/re-used entries.
>
> [ ... ]
>
> > @@ -780,16 +816,25 @@ static void ixgbe_vf_clear_mbx(struct ixgbe_adapter *adapter, u32 vf)
> > static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
> > int vf, unsigned char *mac_addr)
> > {
> > + struct vf_data_storage *vfinfo;
> > int retval;
> >
> > - ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
> > + rcu_read_lock();
> > + vfinfo = rcu_dereference(adapter->vfinfo);
> > + if (!vfinfo) {
> > + rcu_read_unlock();
> > + return -EINVAL;
> > + }
> > +
> > + ixgbe_del_mac_filter(adapter, vfinfo[vf].vf_mac_addresses, vf);
> > retval = ixgbe_add_mac_filter(adapter, mac_addr, vf);
> > if (retval >= 0)
> > - memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr,
> > + memcpy(vfinfo[vf].vf_mac_addresses, mac_addr,
> > ETH_ALEN);
>
> [ ... ]
>
> > @@ -1537,21 +1677,34 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter)
> > int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
> > {
> > struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
> > + struct vf_data_storage *vfinfo;
> > int retval;
> >
> > if (vf >= adapter->num_vfs)
> > return -EINVAL;
> >
> > + rcu_read_lock();
> > + vfinfo = rcu_dereference(adapter->vfinfo);
> > + if (!vfinfo) {
> > + rcu_read_unlock();
> > + return 0;
> > + }
> > +
> > if (is_valid_ether_addr(mac)) {
> > dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n",
> > mac, vf);
> > dev_info(&adapter->pdev->dev, "Reload the VF driver to make this change effective.");
> >
> > retval = ixgbe_set_vf_mac(adapter, vf, mac);
> > if (retval >= 0) {
> > - adapter->vfinfo[vf].pf_set_mac = true;
> > + vfinfo[vf].pf_set_mac = true;
>
> [High]
> Can vfinfo here and the vfinfo observed inside ixgbe_set_vf_mac()
> end up pointing at different objects?
>
> ixgbe_ndo_set_vf_mac() captures vfinfo via its own rcu_dereference,
> then calls ixgbe_set_vf_mac() which independently does:
>
> rcu_read_lock();
> vfinfo = rcu_dereference(adapter->vfinfo);
> ...
> memcpy(vfinfo[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
>
> Nesting rcu_read_lock() is fine, but each rcu_dereference()
> observes whatever pointer is currently published. If
> ixgbe_disable_sriov() followed by __ixgbe_enable_sriov() races
> between the two dereferences, the inner copy lands in the new
> array while the outer pf_set_mac = true write lands in the old
> array. The two pieces of state then disagree, which seems to
> break the "attempted to override administratively set MAC"
> enforcement on subsequent VF mailbox messages. If the new
> vfinfo is shorter than vf, the inner memcpy is also a heap
> out-of-bounds write.
>
> Should ixgbe_ndo_set_vf_mac() pass its already-captured vfinfo
> into ixgbe_set_vf_mac() so both writes go to the same object,
> or otherwise structure the call so a single rcu_dereference
> covers all writes for one operation?
^ permalink raw reply
* Re: [PATCH net 1/2] vsock/virtio: collapse receive queue under memory pressure
From: Stefano Garzarella @ 2026-07-01 10:13 UTC (permalink / raw)
To: Paolo Abeni
Cc: netdev, Jason Wang, Jakub Kicinski, Michael S. Tsirkin, kvm,
virtualization, Xuan Zhuo, Eric Dumazet, Simon Horman,
linux-kernel, Stefan Hajnoczi, David S. Miller,
Eugenio Pérez, stable, Brien Oberstein
In-Reply-To: <6a6be4b0-e02d-46ca-b8bf-c27bd681d253@redhat.com>
On Tue, Jun 30, 2026 at 11:53:04AM +0200, Paolo Abeni wrote:
>On 6/26/26 3:48 PM, Stefano Garzarella wrote:
>> From: Stefano Garzarella <sgarzare@redhat.com>
>>
>> When many small packets accumulate in the receive queue, the skb overhead
>> can exceed buf_alloc even while the payload is within bounds. This causes
>> virtio_transport_inc_rx_pkt() to reject packets, leading to connection
>> resets during large transfers under backpressure.
>>
>> The issue was reported by Brien, who has a reproducer, but it is also
>> easily reproducible with iperf-vsock [1] using a small packet size:
>>
>> iperf3 --vsock -c $CID -l 129
>>
>> which fails immediately without this patch but with commit 059b7dbd20a6
>> ("vsock/virtio: fix potential unbounded skb queue").
>>
>> Inspired by TCP's tcp_collapse() which solves a similar problem, add
>> virtio_transport_collapse_rx_queue() that walks the receive queue and
>> re-copies data into compact linear skbs to reduce the overhead.
>>
>> The collapse is triggered from virtio_transport_recv_enqueue() when
>> virtio_transport_inc_rx_pkt() fails. A pre-scan counts the eligible bytes
>> to size each allocation precisely, avoiding waste for isolated small
>> packets. Partially consumed skbs are kept as-is to preserve
>> buf_used/fwd_cnt accounting, EOM-marked skbs to maintain SEQPACKET
>> message boundaries, and skbs already larger than the collapse target
>> because they already have a good data-to-overhead ratio.
>>
>> [1] https://github.com/stefano-garzarella/iperf-vsock
>>
>> Fixes: 059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue")
>> Cc: stable@vger.kernel.org
>> Reported-by: Brien Oberstein <brienpub@gmail.com>
>> Closes: https://lore.kernel.org/netdev/618701dd023e$063de350$12b9a9f0$@gmail.com/
>> Tested-by: Brien Oberstein <brienpub@gmail.com>
>> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
>> ---
>> net/vmw_vsock/virtio_transport_common.c | 148 +++++++++++++++++++++++-
>> 1 file changed, 146 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>> index 09475007165b..304ea424995d 100644
>> --- a/net/vmw_vsock/virtio_transport_common.c
>> +++ b/net/vmw_vsock/virtio_transport_common.c
>> @@ -420,6 +420,137 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>> return ret;
>> }
>>
>> +static bool virtio_transport_can_collapse(struct sk_buff *skb,
>> + unsigned int size)
>
>Why passing a `size` argument here? AFAICS the actual argument is always
>a constant and IMHO rightfully so.
This comes from a previous implementation where this was not constant.
With the current code, I agree that a macro should be better.
I'll fix it.
>
>> +{
>> + /* skbs that are partially consumed, mark a SEQPACKET message boundary,
>> + * or are already large enough should not be collapsed: they either
>> + * need special accounting, carry protocol state, or already have a
>> + * good data-to-overhead ratio.
>> + */
>> + if (VIRTIO_VSOCK_SKB_CB(skb)->offset)
>> + return false;
>> + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags) & VIRTIO_VSOCK_SEQ_EOM)
>> + return false;
>> + if (skb->len >= size)
>> + return false;
>> + return true;
>> +}
>> +
>> +/* Iterate through the packets in the queue starting from the current skb to
>> + * count the number of bytes we can collapse.
>> + */
>> +static unsigned int
>> +virtio_transport_collapse_size(struct sk_buff *skb,
>> + struct sk_buff_head *queue,
>> + unsigned int max_size)
>> +{
>> + unsigned int target = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
>> +
>> + while ((skb = skb_peek_next(skb, queue)) &&
>> + virtio_transport_can_collapse(skb, max_size)) {
>> + unsigned int len = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
>> +
>> + if (len > max_size - target)
>> + return target;
>> +
>> + target += len;
>> + }
>> +
>> + return target;
>> +}
>> +
>> +/* Called under lock_sock when skb overhead exceeds the budget. */
>> +static void virtio_transport_collapse_rx_queue(struct virtio_vsock_sock *vvs)
>> +{
>> + /* Use the same linear allocation threshold as virtio_vsock_alloc_skb()
>> + * to avoid adding pressure on the page allocator.
>> + */
>> + unsigned int collapse_max = SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM,
>> + PAGE_ALLOC_COSTLY_ORDER);
>> + struct sk_buff *skb, *next_skb, *new_skb = NULL;
>> + struct sk_buff_head new_queue;
>> +
>> + __skb_queue_head_init(&new_queue);
>> +
>> + skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) {
>
>If the queue is relevantly big, walking all of it may take a significant
>amount of time/cache misses and causes traffic burstines. I think you
>could add an additional stop condition, i.e. when the current queue size
>is below a reasonable threshold (allowing the current packet to be
>inserted plus some more slack).
Makes sense, any suggestion on the threshold?
I was thinking something like this: merge until we have space for at
least 2 skbs (because for now we estimate the overhead based on the
number of skbs, but in the future I'd like to support truesize), but
still trying to fill collapse_max as much as possible.
Does that make sense, or should we be more aggressive?
>
>/P
>
>> + struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
>> + u32 src_off = VIRTIO_VSOCK_SKB_CB(skb)->offset;
>> + u32 src_len = skb->len - src_off;
>> + bool keep = false;
>> +
>> + if (!virtio_transport_can_collapse(skb, collapse_max)) {
>
>Minor nit, possibly something alike the following lead to more
>compact/more readable code:
>
>
> keep = !virtio_transport_can_collapse(skb, collapse_max);
> if (keep) {
>
Yeah, so I can remove the initialization to false. I'll change it.
>> + /* Finalize pending collapsed skb to preserve packet
>> + * ordering.
>> + */
>> + if (new_skb) {
>> + __skb_queue_tail(&new_queue, new_skb);
>> + new_skb = NULL;
>> + }
>> + keep = true;
>> + goto next;
>> + }
>> +
>> + /* Finalize if this packet won't fit in the remaining tailroom,
>> + * so we can allocate a right-sized new_skb.
>> + */
>> + if (new_skb && src_len > skb_tailroom(new_skb)) {
>> + __skb_queue_tail(&new_queue, new_skb);
>> + new_skb = NULL;
>
>Possibly introduce an helper for the above 2 statements?
Do you mean something like this?
static void virtio_transport_queue_skb(struct sk_buff_head *queue,
struct sk_buff **skb)
{
__skb_queue_tail(queue, *skb);
*skb = NULL;
}
Not sure, just for 2 places, but if you prefer it, I can change.
Thanks,
Stefano
^ 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