* [PATCH v2 net-next 07/14] net: enetc: differentiate phylink capabilities for pseudo-MAC and standalone MAC
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Claudiu Manoil <claudiu.manoil@nxp.com>
The ENETC pseudo-MACs are proprietary internal links that do not
implement any standard MII interface, so restrict their supported PHY
interface modes to PHY_INTERFACE_MODE_INTERNAL only.
Since pseudo-MACs can operate at any speed between 10Mbps and 25Gbps
in multiples of 10Mbps, set their MAC capabilities to cover the full
range of standard full-duplex speeds: 10/100/1000/2500/5000/10000/
20000/25000 Mbps.
For standalone ENETC, expand the supported interface modes to include
10GBASER and XGMII in addition to the existing RGMII, SGMII, 1000BASEX,
2500BASEX and USXGMII modes, with MAC capabilities up to 10G. MAC_1000
is replaced with MAC_1000FD to explicitly exclude 1000M half-duplex,
which is not supported.
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 2 +-
.../freescale/enetc/enetc_pf_common.c | 47 ++++++++++++++-----
2 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 06a9f1ee0970..8839cfb49bcf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/* Copyright 2017-2019 NXP */
+/* Copyright 2017-2019, 2025-2026 NXP */
#include <linux/timer.h>
#include <linux/pci.h>
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 3597cb81a7cc..6ccf9b909054 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/* Copyright 2024 NXP */
+/* Copyright 2024-2026 NXP */
#include <linux/fsl/enetc_mdio.h>
#include <linux/of_mdio.h>
@@ -359,7 +359,9 @@ static bool enetc_port_has_pcs(struct enetc_pf *pf)
return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
- pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
+ pf->if_mode == PHY_INTERFACE_MODE_USXGMII ||
+ pf->if_mode == PHY_INTERFACE_MODE_10GBASER ||
+ pf->if_mode == PHY_INTERFACE_MODE_XGMII);
}
int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
@@ -400,25 +402,44 @@ int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
{
struct enetc_pf *pf = enetc_si_priv(priv->si);
struct phylink *phylink;
+ unsigned long mac_caps;
int err;
pf->phylink_config.dev = &priv->ndev->dev;
pf->phylink_config.type = PHYLINK_NETDEV;
- pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
- MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
pf->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_SGMII,
- pf->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_1000BASEX,
- pf->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_2500BASEX,
- pf->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_USXGMII,
- pf->phylink_config.supported_interfaces);
- phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
+ mac_caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
+ if (!enetc_is_pseudo_mac(priv->si)) {
+ mac_caps |= MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD;
+
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ pf->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ pf->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX,
+ pf->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_USXGMII,
+ pf->phylink_config.supported_interfaces);
+
+ if (!is_enetc_rev1(priv->si)) {
+ mac_caps |= MAC_5000FD | MAC_10000FD;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
+ pf->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_XGMII,
+ pf->phylink_config.supported_interfaces);
+ }
+
+ phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
+ } else {
+ mac_caps |= MAC_10FD | MAC_100FD | MAC_1000FD | MAC_2500FD |
+ MAC_5000FD | MAC_10000FD | MAC_20000FD |
+ MAC_25000FD;
+ }
+
+ pf->phylink_config.mac_capabilities = mac_caps;
phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
pf->if_mode, ops);
if (IS_ERR(phylink)) {
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 06/14] net: enetc: simplify enetc4_set_port_speed()
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
Since phylink only passes valid speed values to mac_link_up, the switch
statement with its default fallback to SPEED_10 is unnecessary. Replace
it with a direct call to PCR_PSPEED_VAL(). Also update PCR_PSPEED_VAL()
to use FIELD_PREP() for proper field masking instead of an open-coded
shift.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_hw.h | 2 +-
.../net/ethernet/freescale/enetc/enetc4_pf.c | 19 +++----------------
2 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 6a8f2ed56017..dea1fd0b8175 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -148,7 +148,7 @@
#define PCR_L2DOSE BIT(4)
#define PCR_TIMER_CS BIT(8)
#define PCR_PSPEED GENMASK(29, 16)
-#define PCR_PSPEED_VAL(speed) (((speed) / 10 - 1) << 16)
+#define PCR_PSPEED_VAL(s) FIELD_PREP(PCR_PSPEED, ((s) / 10 - 1))
/* Port MAC address register 0/1 */
#define ENETC4_PMAR0 0x4020
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index b966637572a7..db7bad2c3cbd 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -631,23 +631,10 @@ static void enetc4_set_port_speed(struct enetc_ndev_priv *priv, int speed)
if (speed == old_speed)
return;
- val = enetc_port_rd(&priv->si->hw, ENETC4_PCR);
- val &= ~PCR_PSPEED;
-
- switch (speed) {
- case SPEED_100:
- case SPEED_1000:
- case SPEED_2500:
- case SPEED_10000:
- val |= (PCR_PSPEED & PCR_PSPEED_VAL(speed));
- break;
- case SPEED_10:
- default:
- val |= (PCR_PSPEED & PCR_PSPEED_VAL(SPEED_10));
- }
-
- priv->speed = speed;
+ val = enetc_port_rd(&priv->si->hw, ENETC4_PCR) & (~PCR_PSPEED);
+ val |= PCR_PSPEED_VAL(speed);
enetc_port_wr(&priv->si->hw, ENETC4_PCR, val);
+ priv->speed = speed;
}
static void enetc4_set_rgmii_mac(struct enetc_pf *pf, int speed, int duplex)
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 05/14] net: enetc: use PCI device name for debugfs directory
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
enetc_create_debugfs() is called right after register_netdev(), at which
point ndev->name still holds the format template "eth%d" rather than the
final assigned name (e.g., via udev rules).
Use pci_name() instead of netdev_name() to name the debugfs directory.
The PCI device name is unique, stable, and available from the start,
making it a more reliable identifier for the debugfs entry.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
index 4a769d9e5679..be378bf8f74d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
@@ -81,10 +81,9 @@ DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);
void enetc_create_debugfs(struct enetc_si *si)
{
- struct net_device *ndev = si->ndev;
struct dentry *root;
- root = debugfs_create_dir(netdev_name(ndev), NULL);
+ root = debugfs_create_dir(pci_name(si->pdev), NULL);
if (IS_ERR(root))
return;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 04/14] net: enetc: improve MAFT entry management with bitmap tracking
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
Replace the counter-based MAFT entry tracking (num_mfe/mac_filter_num)
with a bitmap (maft_eid_bitmap) stored in struct ntmp_user, which is a
more appropriate place for NTMP resource management.
The bitmap approach brings two improvements. First, the entry deletion
in enetc4_pf_clear_maft_entries() now checks the return value of
ntmp_maft_delete_entry() and only clears the corresponding bit on
success, keeping hardware and software state in sync. Previously, the
counter was reset unconditionally regardless of whether the hardware
deletion actually succeeded.
Second, entry allocation in enetc4_pf_add_maft_entries() uses
ntmp_lookup_free_eid() to find available IDs dynamically, with an
upfront capacity check via bitmap_weight() to avoid partial failures.
The MAFT entry count is moved into ntmp_user.maft_num_entries and
initialized once during enetc4_init_ntmp_user(). Helper functions
enetc4_ntmp_bitmap_init() and enetc4_ntmp_bitmap_free() manage the
bitmap lifetime. The debugfs show function is updated accordingly to
iterate over set bits under rtnl_lock().
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../ethernet/freescale/enetc/enetc4_debugfs.c | 30 ++++--
.../net/ethernet/freescale/enetc/enetc4_pf.c | 97 ++++++++++++++-----
.../net/ethernet/freescale/enetc/enetc_pf.h | 3 -
include/linux/fsl/ntmp.h | 2 +
4 files changed, 96 insertions(+), 36 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
index 1b1591dce73d..4a769d9e5679 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
@@ -31,9 +31,11 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
struct enetc_si *si = s->private;
struct enetc_hw *hw = &si->hw;
struct maft_entry_data maft;
+ struct ntmp_user *user;
struct enetc_pf *pf;
- int i, err, num_si;
- u32 val;
+ u32 val, entry_id;
+ int i, num_si;
+ int err = 0;
pf = enetc_si_priv(si);
num_si = pf->caps.num_vsi + 1;
@@ -50,22 +52,30 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
for (i = 0; i < num_si; i++)
enetc_show_si_mac_hash_filter(s, i);
- if (!pf->num_mfe)
- return 0;
+ user = &si->ntmp_user;
+ rtnl_lock();
+
+ if (bitmap_empty(user->maft_eid_bitmap, user->maft_num_entries))
+ goto unlock_rtnl;
/* MAC address filter table */
seq_puts(s, "MAC address filter table\n");
- for (i = 0; i < pf->num_mfe; i++) {
+ for_each_set_bit(entry_id, user->maft_eid_bitmap,
+ user->maft_num_entries) {
memset(&maft, 0, sizeof(maft));
- err = ntmp_maft_query_entry(&si->ntmp_user, i, &maft);
+ err = ntmp_maft_query_entry(user, entry_id, &maft);
if (err)
- return err;
+ goto unlock_rtnl;
- seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i,
- maft.keye.mac_addr, le16_to_cpu(maft.cfge.si_bitmap));
+ seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n",
+ entry_id, maft.keye.mac_addr,
+ le16_to_cpu(maft.cfge.si_bitmap));
}
- return 0;
+unlock_rtnl:
+ rtnl_unlock();
+
+ return err;
}
DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index a02b01753ff2..b966637572a7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -32,9 +32,6 @@ static void enetc4_get_port_caps(struct enetc_pf *pf)
val = enetc_port_rd(hw, ENETC4_PMCAPR);
pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0;
-
- val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
- pf->caps.mac_filter_num = val & PSIMAFCAPR_NUM_MAC_AFTE;
}
static void enetc4_get_psi_hw_features(struct enetc_si *si)
@@ -92,31 +89,45 @@ static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf)
{
- int i;
+ struct ntmp_user *user = &pf->si->ntmp_user;
+ u32 entry_id;
- for (i = 0; i < pf->num_mfe; i++)
- ntmp_maft_delete_entry(&pf->si->ntmp_user, i);
-
- pf->num_mfe = 0;
+ for_each_set_bit(entry_id, user->maft_eid_bitmap,
+ user->maft_num_entries) {
+ if (!ntmp_maft_delete_entry(user, entry_id))
+ ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id);
+ }
}
static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
struct netdev_hw_addr_list *uc)
{
+ struct ntmp_user *user = &pf->si->ntmp_user;
+ int mac_cnt = netdev_hw_addr_list_count(uc);
struct maft_entry_data maft = {};
struct netdev_hw_addr *ha;
+ u32 available_entries;
u16 si_bit = BIT(0);
+ u32 entry_id;
int err;
+ available_entries = user->maft_num_entries -
+ bitmap_weight(user->maft_eid_bitmap,
+ user->maft_num_entries);
+
+ if (mac_cnt > available_entries)
+ return -ENOSPC;
+
maft.cfge.si_bitmap = cpu_to_le16(si_bit);
netdev_hw_addr_list_for_each(ha, uc) {
+ entry_id = ntmp_lookup_free_eid(user->maft_eid_bitmap,
+ user->maft_num_entries);
ether_addr_copy(maft.keye.mac_addr, ha->addr);
- err = ntmp_maft_add_entry(&pf->si->ntmp_user, pf->num_mfe,
- &maft);
- if (unlikely(err))
+ err = ntmp_maft_add_entry(user, entry_id, &maft);
+ if (unlikely(err)) {
+ ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id);
goto clear_maft_entries;
-
- pf->num_mfe++;
+ }
}
return 0;
@@ -146,10 +157,10 @@ static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
struct netdev_hw_addr_list *uc)
{
- int mac_cnt = netdev_hw_addr_list_count(uc);
struct enetc_si *si = pf->si;
+ int err;
- if (!mac_cnt) {
+ if (netdev_hw_addr_list_empty(uc)) {
/* clear both MAC hash and exact filters */
enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
@@ -157,21 +168,19 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
return 0;
}
- if (mac_cnt > pf->caps.mac_filter_num)
- return -ENOSPC;
-
- /* Set temporary unicast hash filters in case of Rx loss when
+ /* Set temporary unicast hash filter in case of Rx loss when
* updating MAC address filter table
*/
enetc4_pf_set_uc_hash_filter(pf, uc);
enetc4_pf_clear_maft_entries(pf);
- if (!enetc4_pf_add_maft_entries(pf, uc)) {
+ err = enetc4_pf_add_maft_entries(pf, uc);
+ if (!err) {
enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
enetc_set_si_uc_hash_filter(si, 0, 0);
}
- return 0;
+ return err;
}
static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
@@ -393,18 +402,60 @@ static void enetc4_configure_port(struct enetc_pf *pf)
enetc_set_default_rss_key(pf);
}
+static void enetc4_get_ntmp_caps(struct enetc_si *si)
+{
+ struct ntmp_user *user = &si->ntmp_user;
+ struct enetc_hw *hw = &si->hw;
+ u32 val;
+
+ val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
+ user->maft_num_entries = FIELD_GET(PSIMAFCAPR_NUM_MAC_AFTE, val);
+}
+
+static int enetc4_ntmp_bitmap_init(struct ntmp_user *user)
+{
+ user->maft_eid_bitmap = bitmap_zalloc(user->maft_num_entries,
+ GFP_KERNEL);
+ if (!user->maft_eid_bitmap)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void enetc4_ntmp_bitmap_free(struct ntmp_user *user)
+{
+ bitmap_free(user->maft_eid_bitmap);
+ user->maft_eid_bitmap = NULL;
+}
+
static int enetc4_init_ntmp_user(struct enetc_si *si)
{
struct ntmp_user *user = &si->ntmp_user;
+ int err;
/* For ENETC 4.1, all table versions are 0 */
memset(&user->tbl, 0, sizeof(user->tbl));
- return enetc4_setup_cbdr(si);
+ err = enetc4_setup_cbdr(si);
+ if (err)
+ return err;
+
+ enetc4_get_ntmp_caps(si);
+ err = enetc4_ntmp_bitmap_init(user);
+ if (err)
+ goto teardown_cbdr;
+
+ return 0;
+
+teardown_cbdr:
+ enetc4_teardown_cbdr(si);
+
+ return err;
}
static void enetc4_free_ntmp_user(struct enetc_si *si)
{
+ enetc4_ntmp_bitmap_free(&si->ntmp_user);
enetc4_teardown_cbdr(si);
}
@@ -422,7 +473,7 @@ static int enetc4_pf_init(struct enetc_pf *pf)
err = enetc4_init_ntmp_user(pf->si);
if (err) {
- dev_err(dev, "Failed to init CBDR\n");
+ dev_err(dev, "Failed to init NTMP user\n");
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 285b7e5c48fd..6f15f9ea1664 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -22,7 +22,6 @@ struct enetc_port_caps {
int num_msix;
int num_rx_bdr;
int num_tx_bdr;
- int mac_filter_num;
};
struct enetc_pf;
@@ -60,8 +59,6 @@ struct enetc_pf {
struct enetc_port_caps caps;
const struct enetc_pf_ops *ops;
-
- int num_mfe; /* number of mac address filter table entries */
};
#define phylink_to_enetc_pf(config) \
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index d3b6c476b91a..764ef2892608 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -75,8 +75,10 @@ struct ntmp_user {
/* NTMP table bitmaps for resource management */
u32 ett_bitmap_size;
u32 ect_bitmap_size;
+ u16 maft_num_entries;
unsigned long *ett_gid_bitmap; /* only valid for switch */
unsigned long *ect_gid_bitmap; /* only valid for switch */
+ unsigned long *maft_eid_bitmap; /* only valid for ENETC */
};
struct maft_entry_data {
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 03/14] net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The current ndo_set_rx_mode() is called under netif_addr_lock spinlock
with BHs disabled, which prevents drivers from sleeping. To work around
this limitation, the enetc driver uses a dedicated workqueue to defer
MAC address list updates to a sleepable context.
Since commit 3554b4345d85 ("net: introduce ndo_set_rx_mode_async and
netdev_rx_mode_work") introduced the ndo_set_rx_mode_async() callback,
drivers can now handle address list updates directly in a sleepable
context.
Therefore, convert the enetc driver to use ndo_set_rx_mode_async() and
remove the dedicated workqueue and the deferred work item accordingly.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 178 ++++++------------
2 files changed, 58 insertions(+), 122 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 04a5dd5ea6c7..06a9f1ee0970 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -324,8 +324,6 @@ struct enetc_si {
const struct enetc_drvdata *drvdata;
const struct enetc_si_ops *ops;
- struct workqueue_struct *workqueue;
- struct work_struct rx_mode_task;
struct dentry *debugfs_root;
struct enetc_msg_swbd msg; /* Only valid for VSI */
};
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 48a74db90ed5..a02b01753ff2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -101,24 +101,23 @@ static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf)
}
static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
- struct enetc_mac_addr *mac,
- int mac_cnt)
+ struct netdev_hw_addr_list *uc)
{
struct maft_entry_data maft = {};
+ struct netdev_hw_addr *ha;
u16 si_bit = BIT(0);
- int i, err;
+ int err;
maft.cfge.si_bitmap = cpu_to_le16(si_bit);
- for (i = 0; i < mac_cnt; i++) {
- ether_addr_copy(maft.keye.mac_addr, mac[i].addr);
- err = ntmp_maft_add_entry(&pf->si->ntmp_user, i, &maft);
- if (unlikely(err)) {
- pf->num_mfe = i;
+ netdev_hw_addr_list_for_each(ha, uc) {
+ ether_addr_copy(maft.keye.mac_addr, ha->addr);
+ err = ntmp_maft_add_entry(&pf->si->ntmp_user, pf->num_mfe,
+ &maft);
+ if (unlikely(err))
goto clear_maft_entries;
- }
- }
- pf->num_mfe = mac_cnt;
+ pf->num_mfe++;
+ }
return 0;
@@ -128,23 +127,29 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
return err;
}
-static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
+static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
{
- int max_num_mfe = pf->caps.mac_filter_num;
- struct enetc_mac_filter mac_filter = {};
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_addr *mac_tbl;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[UC];
struct netdev_hw_addr *ha;
- int i = 0, err;
- int mac_cnt;
u64 hash;
- netif_addr_lock_bh(ndev);
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, uc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(pf->si, 0, hash);
+}
+
+static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
+{
+ int mac_cnt = netdev_hw_addr_list_count(uc);
+ struct enetc_si *si = pf->si;
- mac_cnt = netdev_uc_count(ndev);
if (!mac_cnt) {
- netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
@@ -152,79 +157,42 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
return 0;
}
- if (mac_cnt > max_num_mfe) {
- err = -ENOSPC;
- goto unlock_netif_addr;
- }
-
- mac_tbl = kzalloc_objs(*mac_tbl, mac_cnt, GFP_ATOMIC);
- if (!mac_tbl) {
- err = -ENOMEM;
- goto unlock_netif_addr;
- }
-
- netdev_for_each_uc_addr(ha, ndev) {
- enetc_add_mac_addr_ht_filter(&mac_filter, ha->addr);
- ether_addr_copy(mac_tbl[i++].addr, ha->addr);
- }
-
- netif_addr_unlock_bh(ndev);
+ if (mac_cnt > pf->caps.mac_filter_num)
+ return -ENOSPC;
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
enetc4_pf_clear_maft_entries(pf);
- if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
+ if (!enetc4_pf_add_maft_entries(pf, uc)) {
+ enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
enetc_set_si_uc_hash_filter(si, 0, 0);
-
- kfree(mac_tbl);
+ }
return 0;
-
-unlock_netif_addr:
- netif_addr_unlock_bh(ndev);
-
- return err;
}
-static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *mc)
{
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_filter *mac_filter;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[MC];
struct netdev_hw_addr *ha;
u64 hash;
- netif_addr_lock_bh(ndev);
- if (type & ENETC_MAC_FILTER_TYPE_UC) {
- mac_filter = &pf->mac_filter[UC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_uc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
- }
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, mc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- if (type & ENETC_MAC_FILTER_TYPE_MC) {
- mac_filter = &pf->mac_filter[MC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_mc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_mc_hash_filter(si, 0, hash);
- }
- netif_addr_unlock_bh(ndev);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(pf->si, 0, hash);
}
-static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
/* Currently, the MAC address filter table (MAFT) only has 4 entries,
* and multiple multicast addresses for filtering will be configured
@@ -232,15 +200,16 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
* unicast filtering. If the number of unicast addresses exceeds the
* table capacity, the MAC hash filter will be used.
*/
- if (type & ENETC_MAC_FILTER_TYPE_UC && enetc4_pf_set_uc_exact_filter(pf)) {
+ if (type & ENETC_MAC_FILTER_TYPE_UC &&
+ enetc4_pf_set_uc_exact_filter(pf, uc)) {
/* Fall back to the MAC hash filter */
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
/* Clear the old MAC exact filter */
enetc4_pf_clear_maft_entries(pf);
}
if (type & ENETC_MAC_FILTER_TYPE_MC)
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
+ enetc4_pf_set_mc_hash_filter(pf, mc);
}
static const struct enetc_pf_ops enetc4_pf_ops = {
@@ -467,17 +436,17 @@ static void enetc4_pf_free(struct enetc_pf *pf)
enetc4_free_ntmp_user(pf->si);
}
-static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
+static int enetc4_pf_set_rx_mode(struct net_device *ndev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
- struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
- struct enetc_pf *pf = enetc_si_priv(si);
- struct net_device *ndev = si->ndev;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_si *si = priv->si;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
- rtnl_lock();
-
if (ndev->flags & IFF_PROMISC) {
uc_promisc = true;
mc_promisc = true;
@@ -500,17 +469,9 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
- enetc4_pf_set_mac_filter(pf, type);
-
- rtnl_unlock();
-}
+ enetc4_pf_set_mac_filter(pf, type, uc, mc);
-static void enetc4_pf_set_rx_mode(struct net_device *ndev)
-{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_si *si = priv->si;
-
- queue_work(si->workqueue, &si->rx_mode_task);
+ return 0;
}
static int enetc4_pf_set_features(struct net_device *ndev,
@@ -540,7 +501,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_start_xmit = enetc_xmit,
.ndo_get_stats = enetc_get_stats,
.ndo_set_mac_address = enetc_pf_set_mac_addr,
- .ndo_set_rx_mode = enetc4_pf_set_rx_mode,
+ .ndo_set_rx_mode_async = enetc4_pf_set_rx_mode,
.ndo_set_features = enetc4_pf_set_features,
.ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid,
@@ -983,19 +944,6 @@ static void enetc4_link_deinit(struct enetc_ndev_priv *priv)
enetc_mdiobus_destroy(pf);
}
-static int enetc4_psi_wq_task_init(struct enetc_si *si)
-{
- char wq_name[24];
-
- INIT_WORK(&si->rx_mode_task, enetc4_psi_do_set_rx_mode);
- snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
- si->workqueue = create_singlethread_workqueue(wq_name);
- if (!si->workqueue)
- return -ENOMEM;
-
- return 0;
-}
-
static int enetc4_pf_netdev_create(struct enetc_si *si)
{
struct device *dev = &si->pdev->dev;
@@ -1036,12 +984,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
if (err)
goto err_link_init;
- err = enetc4_psi_wq_task_init(si);
- if (err) {
- dev_err(dev, "Failed to init workqueue\n");
- goto err_wq_init;
- }
-
err = register_netdev(ndev);
if (err) {
dev_err(dev, "Failed to register netdev\n");
@@ -1051,8 +993,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
return 0;
err_reg_netdev:
- destroy_workqueue(si->workqueue);
-err_wq_init:
enetc4_link_deinit(priv);
err_link_init:
enetc_free_msix(priv);
@@ -1070,8 +1010,6 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
struct net_device *ndev = si->ndev;
unregister_netdev(ndev);
- cancel_work(&si->rx_mode_task);
- destroy_workqueue(si->workqueue);
enetc4_link_deinit(priv);
enetc_free_msix(priv);
free_netdev(ndev);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 01/14] net: enetc: extract common helpers for MAC promiscuous mode setting
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIPMMR (Port Station Interface Promiscuous MAC Mode Register) in
ENETC v4 has the same bit layout as the PSIPMR register in ENETC v1: bit
n controls unicast promiscuous mode for SI n, and bit (n + 16) controls
multicast promiscuous mode for SI n. The only difference between the two
hardware generations is the register address offset.
Since the register functionality is identical, the MAC promiscuous mode
setting code can be shared between ENETC v1 and v4 drivers.
Rename ENETC_PSIPMR to ENETC_PSIPMMR in enetc_hw.h to match the actual
register name used in the reference manual, and extract two new common
helper functions, enetc_set_si_uc_promisc() and
enetc_set_si_mc_promisc(), into enetc_pf_common.c. These helpers select
the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove the v4-specific enetc4_pf_set_si_mac_promisc() function from
enetc4_pf.c and the duplicate PSIPMMR_SI_MAC_UP/MP macro definitions
from enetc4_hw.h, as they are now superseded by the shared code.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_hw.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 21 +--------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 7 +--
.../net/ethernet/freescale/enetc/enetc_pf.c | 11 ++---
.../freescale/enetc/enetc_pf_common.c | 44 +++++++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
7 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index f18437556a0e..6a8f2ed56017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -69,8 +69,6 @@
/* Port Station interface promiscuous MAC mode register */
#define ENETC4_PSIPMMR 0x200
-#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */
-#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16)
/* Port Station interface promiscuous VLAN mode register */
#define ENETC4_PSIPVMR 0x204
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 437a15bbb47b..304ec069654d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,24 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
- bool uc_promisc, bool mc_promisc)
-{
- u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
-
- if (uc_promisc)
- val |= PSIPMMR_SI_MAC_UP(si);
- else
- val &= ~PSIPMMR_SI_MAC_UP(si);
-
- if (mc_promisc)
- val |= PSIPMMR_SI_MAC_MP(si);
- else
- val &= ~PSIPMMR_SI_MAC_MP(si);
-
- enetc_port_wr(hw, ENETC4_PSIPMMR, val);
-}
-
static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
u64 hash)
{
@@ -515,7 +497,8 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
type = ENETC_MAC_FILTER_TYPE_ALL;
}
- enetc4_pf_set_si_mac_promisc(hw, 0, uc_promisc, mc_promisc);
+ enetc_set_si_uc_promisc(si, 0, uc_promisc);
+ enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 71f376ef1be1..07b7832f2427 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -29,7 +29,7 @@ static const u32 enetc_rxbdr_regs[] = {
};
static const u32 enetc_port_regs[] = {
- ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0),
+ ENETC_PMR, ENETC_PSR, ENETC_PSIPMMR, ENETC_PSIPMAR0(0),
ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1,
ENETC_PSICFGR0(0), ENETC_PRFSCAPR, ENETC_PTCMSDUR(0),
ENETC_PM0_CMD_CFG, ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index bf99b65d7598..66bfda60da9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -180,9 +180,10 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PMR_PSPEED_1000M BIT(9)
#define ENETC_PMR_PSPEED_2500M BIT(10)
#define ENETC_PSR 0x0004 /* RO */
-#define ENETC_PSIPMR 0x0018
-#define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */
-#define ENETC_PSIPMR_SET_MP(n) BIT((n) + 16)
+#define ENETC_PSIPMMR 0x0018
+#define PSIPMMR_SI_MAC_UP(n) BIT(n) /* n = SI index */
+#define PSIPMMR_SI_MAC_MP(n) BIT((n) + 16)
+
#define ENETC_PSIPVMR 0x001c
#define ENETC_VLAN_PROMISC_MAP_ALL 0x7
#define ENETC_PSIPVMR_SET_VP(simap) ((simap) & 0x7)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 2d687bb8c3a0..a97d2e2dd07b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -159,21 +159,17 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct enetc_hw *hw = &priv->si->hw;
bool uprom = false, mprom = false;
struct enetc_mac_filter *filter;
struct netdev_hw_addr *ha;
- u32 psipmr = 0;
bool em;
if (ndev->flags & IFF_PROMISC) {
/* enable promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
uprom = true;
mprom = true;
} else if (ndev->flags & IFF_ALLMULTI) {
/* enable multi cast promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_MP(0);
mprom = true;
}
@@ -211,9 +207,8 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
/* update PF entries */
enetc_sync_mac_filters(pf);
- psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
- ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
- enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
+ enetc_set_si_uc_promisc(priv->si, 0, uprom);
+ enetc_set_si_mc_promisc(priv->si, 0, mprom);
}
static void enetc_set_loopback(struct net_device *ndev, bool en)
@@ -474,7 +469,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
- enetc_port_wr(hw, ENETC_PSIPMR, 0);
+ enetc_port_wr(hw, ENETC_PSIPMMR, 0);
/* enable port */
enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 6e5d2f869915..b0c0dc668e34 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -87,6 +87,50 @@ int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
}
EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_UP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_UP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_promisc);
+
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_MP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_MP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 57d2e0ebd2b0..a619fb8fed9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -17,6 +17,8 @@ void enetc_set_default_rss_key(struct enetc_pf *pf);
int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 02/14] net: enetc: extract common helpers for MAC hash filter configuration
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260702025714.456233-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIUMHFR and PSIMMHFR registers in ENETC v4 have the same bit layout
as in ENETC v1. The only difference between the two hardware generations
is the register address offsets.
Since the register functionality is identical, the MAC hash filter
configuration code can be shared between the ENETC v1 and v4 drivers.
Extract two new common helper functions, enetc_set_si_uc_hash_filter()
and enetc_set_si_mc_hash_filter(), into enetc_pf_common.c. These helpers
select the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove v1-specific enetc_clear_mac_ht_flt() and enetc_set_mac_ht_flt()
from enetc_pf.c, and v4-specific enetc4_pf_set_si_uc_hash_filter() and
enetc4_pf_set_si_mc_hash_filter() from enetc4_pf.c, as they are now
superseded by the shared implementations.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 43 +++++++---------
.../net/ethernet/freescale/enetc/enetc_pf.c | 51 +++++--------------
.../freescale/enetc/enetc_pf_common.c | 40 +++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
4 files changed, 73 insertions(+), 63 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 304ec069654d..48a74db90ed5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,20 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
-}
-
-static void enetc4_pf_set_si_mc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
-}
-
static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -147,11 +133,12 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
int max_num_mfe = pf->caps.mac_filter_num;
struct enetc_mac_filter mac_filter = {};
struct net_device *ndev = pf->si->ndev;
- struct enetc_hw *hw = &pf->si->hw;
struct enetc_mac_addr *mac_tbl;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
int i = 0, err;
int mac_cnt;
+ u64 hash;
netif_addr_lock_bh(ndev);
@@ -159,7 +146,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
if (!mac_cnt) {
netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
return 0;
@@ -186,11 +173,13 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- enetc4_pf_set_si_uc_hash_filter(hw, 0, *mac_filter.mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
enetc4_pf_clear_maft_entries(pf);
if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
kfree(mac_tbl);
@@ -206,8 +195,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
{
struct net_device *ndev = pf->si->ndev;
struct enetc_mac_filter *mac_filter;
- struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
+ u64 hash;
netif_addr_lock_bh(ndev);
if (type & ENETC_MAC_FILTER_TYPE_UC) {
@@ -216,8 +206,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_uc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_uc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
}
if (type & ENETC_MAC_FILTER_TYPE_MC) {
@@ -226,8 +217,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_mc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_mc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(si, 0, hash);
}
netif_addr_unlock_bh(ndev);
}
@@ -480,7 +472,6 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
struct enetc_pf *pf = enetc_si_priv(si);
struct net_device *ndev = si->ndev;
- struct enetc_hw *hw = &si->hw;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
@@ -501,12 +492,12 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
}
if (mc_promisc)
- enetc4_pf_set_si_mc_hash_filter(hw, 0, 0);
+ enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
enetc4_pf_set_mac_filter(pf, type);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index a97d2e2dd07b..db2a800a7aaf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -80,37 +80,6 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
filter->mac_addr_cnt++;
}
-static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0);
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0);
- }
-}
-
-static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
- unsigned long hash)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
- upper_32_bits(hash));
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx),
- upper_32_bits(hash));
- }
-}
-
static void enetc_sync_mac_filters(struct enetc_pf *pf)
{
struct enetc_mac_filter *f = pf->mac_filter;
@@ -122,12 +91,16 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
for (i = 0; i < MADDR_TYPE; i++, f++) {
bool em = (f->mac_addr_cnt == 1) && (i == UC);
bool clear = !f->mac_addr_cnt;
+ u64 hash;
if (clear) {
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, 0);
+ }
- enetc_clear_mac_ht_flt(si, 0, i);
continue;
}
@@ -135,7 +108,7 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
if (em) {
int err;
- enetc_clear_mac_ht_flt(si, 0, UC);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
err = enetc_set_mac_flt_entry(si, pos, f->mac_addr,
BIT(0));
@@ -147,11 +120,15 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
err);
}
+ bitmap_to_arr64(&hash, f->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
/* hash table filter, clear EM filter for UC entries */
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
-
- enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, hash);
+ }
}
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index b0c0dc668e34..3597cb81a7cc 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -131,6 +131,46 @@ void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
}
EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psiumhfr0_off, psiumhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psiumhfr0_off = ENETC_PSIUMHFR0(si_id, err);
+ psiumhfr1_off = ENETC_PSIUMHFR1(si_id);
+ } else {
+ psiumhfr0_off = ENETC4_PSIUMHFR0(si_id);
+ psiumhfr1_off = ENETC4_PSIUMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psiumhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psiumhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter);
+
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psimmhfr0_off, psimmhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psimmhfr0_off = ENETC_PSIMMHFR0(si_id, err);
+ psimmhfr1_off = ENETC_PSIMMHFR1(si_id);
+ } else {
+ psimmhfr0_off = ENETC4_PSIMMHFR0(si_id);
+ psimmhfr1_off = ENETC4_PSIMMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index a619fb8fed9c..bf9029b0a017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -19,6 +19,8 @@ int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v2 net-next 00/14] net: enetc: cleanups and improvements
From: wei.fang @ 2026-07-02 2:57 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
From: Wei Fang <wei.fang@nxp.com>
The first group of patches (1, 2, 5-7) eliminates code duplication
between the ENETC v1 and v4 drivers. Since both hardware generations
share identical register layouts for MAC promiscuous mode, MAC hash
filters, and VLAN promiscuous mode - differing only in register address
offsets - common helper functions are extracted into enetc_pf_common.c
and shared by both drivers.
Patch 3 converts ndo_set_rx_mode() to ndo_set_rx_mode_async(), removing
the dedicated workqueue that was previously needed to defer MAC address
list updates to a sleepable context.
Patch 4 replaces counter-based MAFT entry tracking with a bitmap, which
keeps hardware and software state in sync and avoids partial failures
during entry allocation.
Patches 8 and 9 fix phylink-related issues: removing invalid code from
enetc4_pl_mac_link_up() and properly differentiating phylink capabilities
between pseudo-MAC and standalone MAC.
The remaining patches (10-14) are minor cleanups: removing a redundant
VLAN promiscuous mode initialization in probe, using the PCI device name
for the debugfs directory, simplifying port speed configuration, removing
a redundant num_vsi field, using alloc_etherdev_mqs() for the VF driver,
and using kzalloc_flex() for a flexible array allocation.
---
v2:
1. Modify the error log when enetc4_init_ntmp_user() fails
2. Only set PHY_INTERFACE_MODE_10GBASER and PHY_INTERFACE_MODE_XGMII for
ENETC v4, including MAC_5000FD and MAC_10000FD speeds
3. Improve the commit message of patch 13
v1 link: https://lore.kernel.org/imx/20260630072036.382761-1-wei.fang@oss.nxp.com/
---
Claudiu Manoil (1):
net: enetc: differentiate phylink capabilities for pseudo-MAC and
standalone MAC
Wei Fang (13):
net: enetc: extract common helpers for MAC promiscuous mode setting
net: enetc: extract common helpers for MAC hash filter configuration
net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
net: enetc: improve MAFT entry management with bitmap tracking
net: enetc: use PCI device name for debugfs directory
net: enetc: simplify enetc4_set_port_speed()
net: enetc: remove invalid code from enetc4_pl_mac_link_up()
net: enetc: remove enetc4_set_default_si_vlan_promisc()
net: enetc: refactor SI VLAN promiscuous mode configuration
net: enetc: move enetc_set_si_vlan_promisc() to enetc_pf_common.c
net: enetc: remove redundant num_vsi field from enetc_port_caps
net: enetc: use alloc_etherdev_mqs() to create netdev for VF driver
net: enetc: use kzalloc_flex() for enetc_psfp_gate allocation
drivers/net/ethernet/freescale/enetc/enetc.h | 4 +-
.../ethernet/freescale/enetc/enetc4_debugfs.c | 42 +-
.../net/ethernet/freescale/enetc/enetc4_hw.h | 6 +-
.../net/ethernet/freescale/enetc/enetc4_pf.c | 412 +++++++-----------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 12 +-
.../net/ethernet/freescale/enetc/enetc_pf.c | 93 +---
.../net/ethernet/freescale/enetc/enetc_pf.h | 5 -
.../freescale/enetc/enetc_pf_common.c | 153 ++++++-
.../freescale/enetc/enetc_pf_common.h | 5 +
.../net/ethernet/freescale/enetc/enetc_qos.c | 4 +-
.../net/ethernet/freescale/enetc/enetc_vf.c | 3 +-
include/linux/fsl/ntmp.h | 2 +
13 files changed, 353 insertions(+), 390 deletions(-)
--
2.34.1
^ permalink raw reply
* Re: [PATCH v3 5/6] irqchip/gic-v3-its: some minor improvement in comments
From: Kemeng Shi @ 2026-07-02 2:46 UTC (permalink / raw)
To: Thomas Gleixner, maz; +Cc: linux-arm-kernel, linux-kernel
In-Reply-To: <87wlvgou1b.ffs@fw13>
在 2026/7/1 0:46:40, Thomas Gleixner 写道:
> On Tue, Jun 23 2026 at 10:01, Kemeng Shi wrote:
>
>> 1. "If it some" -> "If some"
>> 2. "by table by reading" -> by reading"
>> 3. "reading bit at offset '62'" -> "reading GITS_BASER_INDIRECT"
>
> Please don't enumerate WHAT the patch is doing. We all can see that from
> the patch itself.
>
> Something like that is sufficient and clear enough:
>
> 'Fix grammar and replace a bit number with the symbol for better
> readability'
Thanks for all the review and corrections to this patchset. I'm sorry
for these sloppy mistakes and will fix them in the next version.
^ permalink raw reply
* [PATCH v13 04/15] arm64: support WFET in smp_cond_load_relaxed_timeout()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
To handle WFET use __cmpwait_timeout() similarly to __cmpwait(). These
call out to the respective __cmpwait_case_timeout_##sz(),
__cmpwait_case_##sz() functions.
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
Notes: does not address sashiko comments on overshoot or range
issues [1]. As mentioned earlier, these are okay or addressed
in review.
[1] https://lore.kernel.org/all/20260608082735.830451F00899@smtp.kernel.org/
---
arch/arm64/include/asm/barrier.h | 8 +++--
arch/arm64/include/asm/cmpxchg.h | 62 +++++++++++++++++++++++++-------
2 files changed, 55 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 6190e178db51..fbd71cd4ef4e 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -224,8 +224,8 @@ do { \
extern bool arch_timer_evtstrm_available(void);
/*
- * In the common case, cpu_poll_relax() sits waiting in __cmpwait_relaxed()
- * for the ptr value to change.
+ * In the common case, cpu_poll_relax() sits waiting in __cmpwait_relaxed()/
+ * __cmpwait_relaxed_timeout() for the ptr value to change.
*
* Since this period is reasonably long, choose SMP_TIMEOUT_POLL_COUNT
* to be 1, so smp_cond_load_{relaxed,acquire}_timeout() does a
@@ -234,7 +234,9 @@ extern bool arch_timer_evtstrm_available(void);
#define SMP_TIMEOUT_POLL_COUNT 1
#define cpu_poll_relax(ptr, val, timeout_ns) do { \
- if (arch_timer_evtstrm_available()) \
+ if (alternative_has_cap_unlikely(ARM64_HAS_WFXT)) \
+ __cmpwait_relaxed_timeout(ptr, val, timeout_ns); \
+ else if (arch_timer_evtstrm_available()) \
__cmpwait_relaxed(ptr, val); \
else \
cpu_relax(); \
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index 6cf3cd6873f5..9e4cdc9e41d1 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -12,6 +12,7 @@
#include <asm/barrier.h>
#include <asm/lse.h>
+#include <asm/delay-const.h>
/*
* We need separate acquire parameters for ll/sc and lse, since the full
@@ -212,7 +213,8 @@ __CMPXCHG_GEN(_mb)
#define __CMPWAIT_CASE(w, sfx, sz) \
static inline void __cmpwait_case_##sz(volatile void *ptr, \
- unsigned long val) \
+ unsigned long val, \
+ u64 __maybe_unused timeout_ns) \
{ \
unsigned long tmp; \
\
@@ -235,20 +237,52 @@ __CMPWAIT_CASE( , , 64);
#undef __CMPWAIT_CASE
-#define __CMPWAIT_GEN(sfx) \
-static __always_inline void __cmpwait##sfx(volatile void *ptr, \
- unsigned long val, \
- int size) \
+#define __CMPWAIT_TIMEOUT_CASE(w, sfx, sz) \
+static inline void __cmpwait_case_timeout_##sz(volatile void *ptr, \
+ unsigned long val, \
+ u64 timeout_ns) \
+{ \
+ unsigned long tmp; \
+ u64 ecycles = __delay_cycles() + \
+ NSECS_TO_CYCLES(timeout_ns); \
+ asm volatile( \
+ " sevl\n" \
+ " wfe\n" \
+ " ldxr" #sfx "\t%" #w "[tmp], %[v]\n" \
+ " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \
+ " cbnz %" #w "[tmp], 2f\n" \
+ " msr s0_3_c1_c0_0, %[ecycles]\n" \
+ "2:" \
+ : [tmp] "=&r" (tmp), [v] "+Q" (*(u##sz *)ptr) \
+ : [val] "r" (val), [ecycles] "r" (ecycles)); \
+}
+
+__CMPWAIT_TIMEOUT_CASE(w, b, 8);
+__CMPWAIT_TIMEOUT_CASE(w, h, 16);
+__CMPWAIT_TIMEOUT_CASE(w, , 32);
+__CMPWAIT_TIMEOUT_CASE( , , 64);
+
+#undef __CMPWAIT_TIMEOUT_CASE
+
+#define __CMPWAIT_GEN(timeout, sfx) \
+static __always_inline void __cmpwait##timeout##sfx(volatile void *ptr, \
+ unsigned long val, \
+ u64 timeout_ns, \
+ int size) \
{ \
switch (size) { \
case 1: \
- return __cmpwait_case##sfx##_8(ptr, (u8)val); \
+ return __cmpwait_case##timeout##sfx##_8(ptr, (u8)val, \
+ timeout_ns); \
case 2: \
- return __cmpwait_case##sfx##_16(ptr, (u16)val); \
+ return __cmpwait_case##timeout##sfx##_16(ptr, (u16)val, \
+ timeout_ns); \
case 4: \
- return __cmpwait_case##sfx##_32(ptr, val); \
+ return __cmpwait_case##timeout##sfx##_32(ptr, val, \
+ timeout_ns); \
case 8: \
- return __cmpwait_case##sfx##_64(ptr, val); \
+ return __cmpwait_case##timeout##sfx##_64(ptr, val, \
+ timeout_ns); \
default: \
BUILD_BUG(); \
} \
@@ -256,11 +290,15 @@ static __always_inline void __cmpwait##sfx(volatile void *ptr, \
unreachable(); \
}
-__CMPWAIT_GEN()
+__CMPWAIT_GEN( , )
+__CMPWAIT_GEN(_timeout, )
#undef __CMPWAIT_GEN
-#define __cmpwait_relaxed(ptr, val) \
- __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr)))
+#define __cmpwait_relaxed_timeout(ptr, val, timeout_ns) \
+ __cmpwait_timeout((ptr), (unsigned long)(val), timeout_ns, sizeof(*(ptr)))
+
+#define __cmpwait_relaxed(ptr, val) \
+ __cmpwait((ptr), (unsigned long)(val), 0, sizeof(*(ptr)))
#endif /* __ASM_CMPXCHG_H */
--
2.43.7
^ permalink raw reply related
* Re: [PATCH v6 2/2] clk: amlogic: Add A9 peripherals clock controller driver
From: Jian Hu @ 2026-07-02 2:24 UTC (permalink / raw)
To: Jerome Brunet, Jian Hu via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao, Kevin Hilman,
Martin Blumenstingl, Brian Masney, linux-amlogic, linux-clk,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <1jwlve7m4i.fsf@starbuckisacylon.baylibre.com>
On 7/1/2026 11:41 PM, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
> On mer. 01 juil. 2026 at 16:30, Jian Hu via B4 Relay <devnull+jian.hu.amlogic.com@kernel.org> wrote:
>
>> From: Jian Hu <jian.hu@amlogic.com>
>>
>> Add the peripherals clock controller driver for the Amlogic A9 SoC family.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> ---
>> drivers/clk/meson/Kconfig | 15 +
>> drivers/clk/meson/Makefile | 1 +
>> drivers/clk/meson/a9-peripherals.c | 2089 ++++++++++++++++++++++++++++++++++++
>> 3 files changed, 2105 insertions(+)
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index b71299898197..5152868e2ee6 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -132,6 +132,21 @@ config COMMON_CLK_A1_PERIPHERALS
>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>> controller to work.
>>
>> +config COMMON_CLK_A9_PERIPHERALS
>> + tristate "Amlogic A9 SoC peripherals clock controller support"
>> + depends on ARM64 || COMPILE_TEST
>> + default ARCH_MESON
>> + select COMMON_CLK_MESON_REGMAP
>> + select COMMON_CLK_MESON_CLKC_UTILS
>> + select COMMON_CLK_MESON_DUALDIV
>> + select COMMON_CLK_MESON_VID_PLL_DIV
>> + imply COMMON_CLK_SCMI
>> + imply COMMON_CLK_A9_PLL
> As mentioned by Sashiko, This is problematic because the symbol does
> exist yet. This should be removed for now. It can be added back when
> support for the PLL controllers is added
>
> I'm otherwise happy with this version.
> If it is ok with you, I'll apply it with the line above removed.
>
Yes, that's fine with me.
Please remove the 'imply COMMON_CLK_A9_PLL' line when applying.
Thanks for your review.
[ ... ]
> --
> Jerome
--
Jian
^ permalink raw reply
* [PATCH v13 01/15] asm-generic: barrier: Add smp_cond_load_relaxed_timeout()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
Add smp_cond_load_relaxed_timeout(), which extends
smp_cond_load_relaxed() to allow waiting for a duration.
We loop around waiting for the condition variable to change while
peridically doing a time-check. The loop uses cpu_poll_relax() to slow
down the busy-wait, which, unless overridden by the architecture
code, amounts to a cpu_relax().
Note that there are two ways for the time-check to fail: the timeout
case or, @time_expr_ns returning an invalid value (negative or zero).
The second failure mode allows for clocks attached to the clock-domain
of @cond_expr -- which might cease to operate meaningfully once some
state internal to @cond_expr has changed -- to fail.
Evaluation of @time_expr_ns: in the fastpath we want to keep the
performance close to smp_cond_load_relaxed(). So defer evaluation
of the potentially costly @time_expr_ns to the slowpath.
This also means that there will always be some hardware dependent
duration that has passed in cpu_poll_relax() iterations at the time
of first evaluation. Additionally cpu_poll_relax() is not guaranteed
to return at timeout boundary. In sum, expect timeout overshoot when
we exit due to expiration of the timeout.
The number of spin iterations before time-check, SMP_TIMEOUT_POLL_COUNT
is chosen to be 200 by default. With a cpu_poll_relax() iteration
taking ~20-30 cycles (measured on a variety of x86 platforms), we
expect a time-check every ~4000-6000 cycles.
The outer limit of the overshoot is double that when working with the
parameters above. This might be higher or lower depending on the
implementation of cpu_poll_relax() across architectures.
Lastly, config option ARCH_HAS_CPU_RELAX indicates availability of a
cpu_poll_relax() that is cheaper than polling. This might be relevant
for cases with a long timeout.
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-arch@vger.kernel.org
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
Notes: adds a justification for arguments taken in cpu_poll_relax() [1].
As mentioned in v12, I'm not addressing issues with potential timeout
range issues (around S64_MAX, or during early boot) [1][2]. These are best
handled in code review instead of overcomplicating the implementation.
[1] https://lore.kernel.org/all/7d2189443a0181a123e53e5ea93f3a905b1cb4d71d5d6bdfa27a77ed4be65448@mail.kernel.org/
[2] https://lore.kernel.org/all/20260608082501.BC5A91F00898@smtp.kernel.org/
---
include/asm-generic/barrier.h | 83 +++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index b99cb57dfccc..d53e75a92598 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -273,6 +273,85 @@ do { \
})
#endif
+/*
+ * Number of times we iterate in the loop before doing the time check.
+ * Note that the iteration count assumes that the loop condition is
+ * relatively cheap.
+ */
+#ifndef SMP_TIMEOUT_POLL_COUNT
+#define SMP_TIMEOUT_POLL_COUNT 200
+#endif
+
+/*
+ * cpu_poll_relax() stitches up two kinds of primitives: ones that provide
+ * a momentary blip in the pipeline (ex. cpu_relax() on x86).
+ * The second support waiting for @ptr value to change, coupled with a
+ * with a precise (or imprecise) timeout.
+ *
+ * cpu_poll_relax() keeps them together, because its utility is in minimizing
+ * expensive operations while polling on @ptr waiting for it to change.
+ * The arguments to cpu_poll_relax() are only needed for the waiting
+ * primitives.
+ *
+ * Also note that platforms with a suitable cpu_poll_relax() are expected
+ * to define ARCH_HAS_CPU_RELAX.
+ */
+#ifndef cpu_poll_relax
+#define cpu_poll_relax(ptr, val, timeout_ns) cpu_relax()
+#endif
+
+/**
+ * smp_cond_load_relaxed_timeout() - (Spin) wait for cond with no ordering
+ * guarantees until a timeout expires.
+ * @ptr: pointer to the variable to wait on.
+ * @cond_expr: boolean expression to wait for.
+ * @time_expr_ns: expression that evaluates to monotonic time (in ns) or,
+ * on failure, returns a negative value.
+ * @timeout_ns: timeout value in ns
+ * Both of the above are assumed to be compatible with s64; the signed
+ * value is used to handle the failure case in @time_expr_ns.
+ *
+ * Equivalent to using READ_ONCE() on the condition variable.
+ *
+ * Callers that expect to wait for prolonged durations might want
+ * to take into account the availability of ARCH_HAS_CPU_RELAX.
+ *
+ * Note that @ptr is expected to point to a memory address. Using this
+ * interface with MMIO will be slower (since SMP_TIMEOUT_POLL_COUNT is
+ * tuned for memory) and might also break in interesting architecture
+ * dependent ways.
+ */
+#ifndef smp_cond_load_relaxed_timeout
+#define smp_cond_load_relaxed_timeout(ptr, cond_expr, \
+ time_expr_ns, timeout_ns) \
+({ \
+ typeof(ptr) __PTR = (ptr); \
+ __unqual_scalar_typeof(*(ptr)) VAL; \
+ u32 __count = 0, __spin = SMP_TIMEOUT_POLL_COUNT; \
+ s64 __timeout = (s64)timeout_ns; \
+ s64 __time_now, __time_end = 0; \
+ \
+ for (;;) { \
+ VAL = READ_ONCE(*__PTR); \
+ if (cond_expr) \
+ break; \
+ cpu_poll_relax(__PTR, VAL, (u64)__timeout); \
+ if (++__count < __spin) \
+ continue; \
+ __time_now = (s64)(time_expr_ns); \
+ if (unlikely(__time_end == 0)) \
+ __time_end = __time_now + __timeout; \
+ __timeout = __time_end - __time_now; \
+ if (__time_now <= 0 || __timeout <= 0) { \
+ VAL = READ_ONCE(*__PTR); \
+ break; \
+ } \
+ __count = 0; \
+ } \
+ (typeof(*(ptr)))VAL; \
+})
+#endif
+
/*
* pmem_wmb() ensures that all stores for which the modification
* are written to persistent storage by preceding instructions have
--
2.43.7
^ permalink raw reply related
* [PATCH v13 03/15] arm64/delay: move some constants out to a separate header
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora,
Bjorn Andersson, Konrad Dybcio, Christoph Lameter
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
Moves some constants and functions related to xloops, cycles computation
out to a new header. Also make __delay_cycles() available outside of
arch/arm64/lib/delay.c.
Rename some macros in qcom/rpmh-rsc.c which were occupying the same
namespace.
No functional change.
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Bjorn Andersson <andersson@kernel.org>
Cc: Konrad Dybcio <konradybcio@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Reviewed-by: Christoph Lameter <cl@linux.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
arch/arm64/include/asm/delay-const.h | 28 ++++++++++++++++++++++++++++
arch/arm64/lib/delay.c | 15 ++++-----------
drivers/soc/qcom/rpmh-rsc.c | 8 ++++----
3 files changed, 36 insertions(+), 15 deletions(-)
create mode 100644 arch/arm64/include/asm/delay-const.h
diff --git a/arch/arm64/include/asm/delay-const.h b/arch/arm64/include/asm/delay-const.h
new file mode 100644
index 000000000000..2a5acfb7bff1
--- /dev/null
+++ b/arch/arm64/include/asm/delay-const.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_DELAY_CONST_H
+#define _ASM_DELAY_CONST_H
+
+#include <linux/types.h>
+#include <asm/param.h> /* For HZ */
+
+/* 2**32 / 1000000 (rounded up) */
+#define __usecs_to_xloops_mult 0x10C7UL
+
+/* 2**32 / 1000000000 (rounded up) */
+#define __nsecs_to_xloops_mult 0x5UL
+
+extern unsigned long loops_per_jiffy;
+static inline unsigned long xloops_to_cycles(unsigned long xloops)
+{
+ return (xloops * loops_per_jiffy * HZ) >> 32;
+}
+
+#define USECS_TO_CYCLES(time_usecs) \
+ xloops_to_cycles((time_usecs) * __usecs_to_xloops_mult)
+
+#define NSECS_TO_CYCLES(time_nsecs) \
+ xloops_to_cycles((time_nsecs) * __nsecs_to_xloops_mult)
+
+u64 notrace __delay_cycles(void);
+
+#endif /* _ASM_DELAY_CONST_H */
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
index e278e060e78a..c660a7ea26dd 100644
--- a/arch/arm64/lib/delay.c
+++ b/arch/arm64/lib/delay.c
@@ -12,17 +12,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timex.h>
+#include <asm/delay-const.h>
#include <clocksource/arm_arch_timer.h>
-#define USECS_TO_CYCLES(time_usecs) \
- xloops_to_cycles((time_usecs) * 0x10C7UL)
-
-static inline unsigned long xloops_to_cycles(unsigned long xloops)
-{
- return (xloops * loops_per_jiffy * HZ) >> 32;
-}
-
/*
* Force the use of CNTVCT_EL0 in order to have the same base as WFxT.
* This avoids some annoying issues when CNTVOFF_EL2 is not reset 0 on a
@@ -32,7 +25,7 @@ static inline unsigned long xloops_to_cycles(unsigned long xloops)
* Note that userspace cannot change the offset behind our back either,
* as the vcpu mutex is held as long as KVM_RUN is in progress.
*/
-static cycles_t notrace __delay_cycles(void)
+u64 notrace __delay_cycles(void)
{
guard(preempt_notrace)();
return __arch_counter_get_cntvct_stable();
@@ -73,12 +66,12 @@ EXPORT_SYMBOL(__const_udelay);
void __udelay(unsigned long usecs)
{
- __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
+ __const_udelay(usecs * __usecs_to_xloops_mult);
}
EXPORT_SYMBOL(__udelay);
void __ndelay(unsigned long nsecs)
{
- __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
+ __const_udelay(nsecs * __nsecs_to_xloops_mult);
}
EXPORT_SYMBOL(__ndelay);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index c6f7d5c9c493..ad5ec5c0de0a 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -146,10 +146,10 @@ enum {
* +---------------------------------------------------+
*/
-#define USECS_TO_CYCLES(time_usecs) \
- xloops_to_cycles((time_usecs) * 0x10C7UL)
+#define RPMH_USECS_TO_CYCLES(time_usecs) \
+ rpmh_xloops_to_cycles((time_usecs) * 0x10C7UL)
-static inline unsigned long xloops_to_cycles(u64 xloops)
+static inline unsigned long rpmh_xloops_to_cycles(u64 xloops)
{
return (xloops * loops_per_jiffy * HZ) >> 32;
}
@@ -819,7 +819,7 @@ void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
wakeup_us = ktime_to_us(wakeup);
/* Convert the wakeup to arch timer scale */
- wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
+ wakeup_cycles = RPMH_USECS_TO_CYCLES(wakeup_us);
wakeup_cycles += arch_timer_read_counter();
exit:
--
2.43.7
^ permalink raw reply related
* Re: [PATCH v13 15/15] barrier: add clock tests for smp_cond_load_relaxed_timeout()
From: bot+bpf-ci @ 2026-07-02 2:11 UTC (permalink / raw)
To: ankur.a.arora, linux-kernel, linux-arch, linux-arm-kernel,
linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, ankur.a.arora, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
In-Reply-To: <20260702013334.140905-16-ankur.a.arora@oracle.com>
[-- Attachment #1: Type: text/plain, Size: 2842 bytes --]
> diff --git a/lib/tests/barrier-timeout-test.c b/lib/tests/barrier-timeout-test.c
> index 4226fb6456b3..ec78f8533006 100644
> --- a/lib/tests/barrier-timeout-test.c
> +++ b/lib/tests/barrier-timeout-test.c
[ ... ]
> @@ -112,8 +114,64 @@ static void test_smp_cond_timeout(struct kunit *test)
> KUNIT_EXPECT_GE(test, runtime, timeout_ns);
> }
>
> +static s64 synthetic_clock(struct clock_state *clk)
> +{
> + clk->end_time += clk->extra;
> + clk->niters++;
> +
> + return clk->end_time;
> +}
> +
> +
> +struct smp_cond_expiry_params {
> + char *desc;
> + s64 timeout;
> + s64 clk_inc;
> + u32 niters;
> +};
> +
> +static const struct smp_cond_expiry_params expiry_params_list[] = {
> + { .clk_inc = (0x1ULL << 28), .timeout = 0, .niters = 1, .desc = "0", },
> + { .clk_inc = (0x1ULL << 28), .timeout = 1, .niters = 2, .desc = "1", },
> + { .clk_inc = (0x1ULL << 28), .timeout = (0x1ULL << 30), .niters = 1 + (1 << (30-28)), .desc = "1<<30", },
> + { .clk_inc = (0x1ULL << 28), .timeout = S32_MAX, .niters = 1 + (1 << (31-28)), .desc = "S32_MAX", },
> + { .clk_inc = (0x1ULL << 28), .timeout = U32_MAX, .niters = 1 + (1 << (32-28)), .desc = "U32_MAX", },
> + { .clk_inc = (0x1ULL << 28), .timeout = (0x1ULL << 33), .niters = 1 + (1 << (33-28)), .desc = "1<<33", },
> +};
> +
> +static void expiry_param_to_desc(const struct smp_cond_expiry_params *p, char *desc)
> +{
> + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "smp_cond_%s_timeout: clock-%s, timeout=%s, iterations=%u",
> + "relaxed", "synthetic", p->desc, p->niters);
> +}
This isn't a bug, but since "relaxed" and "synthetic" never vary here,
could they be written directly into the format string rather than passed
through %s?
> +
> +static void test_smp_cond_expiry(struct kunit *test)
> +{
> + const struct smp_cond_expiry_params *p = test->param_value;
> + struct clock_state clk = {
> + .start_time = 0,
> + .end_time = 0,
> + .extra = p->clk_inc,
> + .niters = 0,
> + };
> + s64 runtime;
> +
> + flag = 0;
> + smp_cond_load_relaxed_timeout(&flag,
> + 0,
> + synthetic_clock(&clk),
> + p->timeout);
> +
> + runtime = (u64)clk.end_time - (u64)clk.start_time;
> + KUNIT_EXPECT_EQ(test, clk.niters, p->niters);
> + KUNIT_EXPECT_GE(test, runtime, p->timeout);
> +}
> +
> +
> +KUNIT_ARRAY_PARAM(smp_cond_expiry_params, expiry_params_list, expiry_param_to_desc);
> static struct kunit_case barrier_timeout_test_cases[] = {
> KUNIT_CASE_PARAM(test_smp_cond_timeout, smp_cond_update_params_gen_params),
> + KUNIT_CASE_PARAM(test_smp_cond_expiry, smp_cond_expiry_params_gen_params),
> {}
> };
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/28559763019
^ permalink raw reply
* Re: [PATCH v13 01/15] asm-generic: barrier: Add smp_cond_load_relaxed_timeout()
From: bot+bpf-ci @ 2026-07-02 2:11 UTC (permalink / raw)
To: ankur.a.arora, linux-kernel, linux-arch, linux-arm-kernel,
linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, ankur.a.arora, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
In-Reply-To: <20260702013334.140905-2-ankur.a.arora@oracle.com>
[-- Attachment #1: Type: text/plain, Size: 2697 bytes --]
> diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
> index b99cb57dfccc..d1e9ed15bbfc 100644
> --- a/include/asm-generic/barrier.h
> +++ b/include/asm-generic/barrier.h
> @@ -273,6 +273,85 @@ do { \
> })
> #endif
>
> +/*
> + * Number of times we iterate in the loop before doing the time check.
> + * Note that the iteration count assumes that the loop condition is
> + * relatively cheap.
> + */
> +#ifndef SMP_TIMEOUT_POLL_COUNT
> +#define SMP_TIMEOUT_POLL_COUNT 200
> +#endif
[ ... ]
> +#ifndef cpu_poll_relax
> +#define cpu_poll_relax(ptr, val, timeout_ns) cpu_relax()
> +#endif
[ ... ]
> +#ifndef smp_cond_load_relaxed_timeout
> +#define smp_cond_load_relaxed_timeout(ptr, cond_expr, \
> + time_expr_ns, timeout_ns) \
> +({ \
> + typeof(ptr) __PTR = (ptr); \
> + __unqual_scalar_typeof(*(ptr)) VAL; \
> + u32 __count = 0, __spin = SMP_TIMEOUT_POLL_COUNT; \
> + s64 __timeout = (s64)timeout_ns; \
> + s64 __time_now, __time_end = 0; \
> + \
> + for (;;) { \
> + VAL = READ_ONCE(*__PTR); \
> + if (cond_expr) \
> + break; \
> + cpu_poll_relax(__PTR, VAL, (u64)__timeout); \
This same point came up during review of v11. David Laight noted that
__timeout here is a relative value, and that passing it straight to
cpu_poll_relax() is only safe when cpu_poll_relax() ignores its timeout
argument, as the generic cpu_relax() fallback does.
For an arm64 WFE/WFET style cpu_poll_relax() that actually waits on the
supplied timeout, would this spin roughly SMP_TIMEOUT_POLL_COUNT *
timeout_ns before the first time-check?
> + if (++__count < __spin) \
> + continue; \
> + __time_now = (s64)(time_expr_ns); \
> + if (unlikely(__time_end == 0)) \
> + __time_end = __time_now + __timeout; \
__time_end is only initialized here, after the first cpu_poll_relax()
call has already run with the full relative __timeout, so the initial
wait is not counted against the timeout window.
Would it be worth converting the relative timeout to an absolute end-time
once up front, or at least documenting that the effective timeout can be
roughly doubled for such an implementation?
> + __timeout = __time_end - __time_now; \
> + if (__time_now <= 0 || __timeout <= 0) { \
> + VAL = READ_ONCE(*__PTR); \
> + break; \
> + } \
> + __count = 0; \
> + } \
> + (typeof(*(ptr)))VAL; \
> +})
> +#endif
> +
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/28559763019
^ permalink raw reply
* Re: [PATCH 1/2] coresight: Fix clock refcount imbalance on platform remove
From: Jie Gan @ 2026-07-02 1:56 UTC (permalink / raw)
To: Leo Yan
Cc: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Anshuman Khandual, Yeoreum Yun, Yuanfang Zhang, Maxime Coquelin,
Alexandre Torgue, Tingwei Zhang, coresight, linux-arm-kernel,
linux-kernel, linux-stm32
In-Reply-To: <5218878b-c91f-4d14-ba12-68edf7b3f4a7@oss.qualcomm.com>
Hi Leo,
On 7/2/2026 8:59 AM, Jie Gan wrote:
> Hi Leo,
>
> On 7/2/2026 12:23 AM, Leo Yan wrote:
>> On Wed, Jul 01, 2026 at 02:05:02PM +0800, Jie Gan wrote:
>>
>>> After probe, pm_runtime_put() allows the device to suspend and the
>>> runtime suspend callback disables the same clocks. During remove the
>>> device is left runtime suspended, so pm_runtime_disable() freezes it
>>> with the clocks already disabled. The devm cleanup that runs afterwards
>>> calls clk_disable_unprepare() a second time, underflowing the clock
>>> enable refcount.
>>
>> Thanks for fixing the issue.
>>
>> The problem is that if the device has already been runtime suspended and
>> its clock has been disabled, afterwards when remove the device, the devm
>> cleanup disables the clock again, resulting in clock count underflow.
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/
>>> drivers/hwtracing/coresight/coresight-funnel.c
>>> index 0abc11f0690c..4c5b94640e6a 100644
>>> --- a/drivers/hwtracing/coresight/coresight-funnel.c
>>> +++ b/drivers/hwtracing/coresight/coresight-funnel.c
>>> @@ -334,6 +334,7 @@ static void funnel_platform_remove(struct
>>> platform_device *pdev)
>>> return;
>>> funnel_remove(&pdev->dev);
>>> + pm_runtime_get_sync(&pdev->dev);
>>> pm_runtime_disable(&pdev->dev);
>>
>> Let's use the funnel driver for the discussion. Once we agree on the
>> approach, we can apply the same change to the other CoreSight platform
>> drivers.
>>
>> How about the following teardown?
>>
>> static void funnel_platform_remove(struct platform_device *pdev)
>> {
>> struct funnel_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
>> + int ret;
>>
>> if (WARN_ON(!drvdata))
>> return;
>>
>> + ret = pm_runtime_get_sync(&pdev->dev);
>> + if (ret < 0)
>> + dev_warn(&pdev->dev, "failed to resume before remove:
>> %d\n", ret);
>> +
>> funnel_remove(&pdev->dev);
>> +
>> pm_runtime_disable(&pdev->dev);
>> + pm_runtime_set_suspended(&pdev->dev);
>> + pm_runtime_put_noidle(&pdev->dev);
>> }
>
> This proposal looks good to me. I forgot to add pm_runtime_put_noidle to
> drop the useless reference which created by pm_runtime_get_sync.
>
I dropped the line to check the return value for simplifying.
Here is the final version from my part, can you please help to review again?
static void funnel_platform_remove(struct platform_device *pdev)
{
struct funnel_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
if (WARN_ON(!drvdata))
return;
- funnel_remove(&pdev->dev);
+ /*
+ * Resume the device so its clocks are enabled again, balancing the
+ * clk_disable_unprepare() that devm runs when the driver detaches.
+ * Then mark it suspended and drop the usage count taken here.
+ */
pm_runtime_get_sync(&pdev->dev);
+ funnel_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
}
Thanks,
Jie
> Thanks,
> Jie
>
>>
>> The idea is to first resume the device with pm_runtime_get_sync(), then
>> perform the remove (which is safe if they need to access or clean up
>> hardware state), and finally clean up the runtime PM states. I mainly
>> referred to drivers/iio/adc/stm32-adc.c.
>>
>> Thanks,
>> Leo
>
^ permalink raw reply
* [PATCH v2] selftests/arm64: fix spelling errors in comments
From: Wang Yan @ 2026-07-02 1:52 UTC (permalink / raw)
To: catalin.marinas, will, shuah
Cc: linux-arm-kernel, linux-kselftest, linux-kernel, Wang Yan
Fix two spelling mistakes in arm64 selftest comments:
- "whcih" -> "which" (arm64/gcs/libc-gcs.c)
- "resutls" -> "results" (arm64/pauth/pac.c)
Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
---
tools/testing/selftests/arm64/gcs/libc-gcs.c | 2 +-
tools/testing/selftests/arm64/pauth/pac.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c
index 72e82bfbecc9..ddb0b2b20155 100644
--- a/tools/testing/selftests/arm64/gcs/libc-gcs.c
+++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c
@@ -130,7 +130,7 @@ TEST(gcs_find_terminator)
* We can access a GCS via ptrace
*
* This could usefully have a fixture but note that each test is
- * fork()ed into a new child whcih causes issues. Might be better to
+ * fork()ed into a new child which causes issues. Might be better to
* lift at least some of this out into a separate, non-harness, test
* program.
*/
diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c
index 67d138057707..f4b859c75a5a 100644
--- a/tools/testing/selftests/arm64/pauth/pac.c
+++ b/tools/testing/selftests/arm64/pauth/pac.c
@@ -292,7 +292,7 @@ TEST(single_thread_different_keys)
/*
* fork() does not change keys. Only exec() does so call a worker program.
- * Its only job is to sign a value and report back the resutls
+ * Its only job is to sign a value and report back the results
*/
TEST(exec_changed_keys)
{
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v2 2/4] dt-bindings: phy: nuvoton,ma35d1-usb2-phy: extend for dual-port OTG support
From: Joey Lu @ 2026-07-02 1:49 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Arnd Bergmann, Catalin Marinas, Jacky Huang,
Shan-Chun Hung, Hui-Ping Chen, Joey Lu, linux-phy, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <0f5a408b-5c55-4cd2-831a-49316c9912c9@kernel.org>
On 6/30/2026 2:16 PM, Krzysztof Kozlowski wrote:
> On 29/06/2026 12:40, Joey Lu wrote:
>> On 6/25/2026 3:58 PM, Krzysztof Kozlowski wrote:
>>> On Thu, Jun 25, 2026 at 10:39:56AM +0800, Joey Lu wrote:
>>>> properties:
>>>> compatible:
>>>> enum:
>>>> - nuvoton,ma35d1-usb2-phy
>>>>
>>>> + reg:
>>>> + maxItems: 1
>>>> +
>>>> "#phy-cells":
>>>> - const: 0
>>>> + const: 1
>>>> + description:
>>>> + The single cell selects the PHY port. 0 selects the OTG port (USB0,
>>>> + shared with DWC2 gadget controller) and 1 selects the host-only port
>>>> + (USB1).
>>>>
>>>> - clocks:
>>>> - maxItems: 1
>>> This is odd, considering that parent does not have clocks. So explain me
>>> this:
>>> 1. USB PHY needed clocks.
>>> 2. You extend USB PHY to cover second part.
>>> 3. That extension for second part means that clocks are not needed.
>>> Really, how? How is it possible in hardware?
>> The hardware has two independent clock domains:
>>
>> - The PHY analog block takes the 24 MHz HXT as its reference, wired
>> directly to the PHY's internal PLL, which derives the required
>> operating
>> frequencies internally. This reference path is entirely outside the SoC
>> software clock tree; no software-gatable clock gate needs to be enabled
>> for the PHY to power up and lock its PLL. The only software control the
>> PHY driver exercises is toggling each PHY's Power-On Reset (POR) bit,
>> which resides in the SYS register block. The driver accesses this via
>> the parent regmap
>>
>> - `HUSBH0_GATE` / `HUSBH1_GATE` / `USBD_GATE` are AHB/APB bus interface
>> clocks for the host and gadget (EHCI, OHCI, DWC2). They gate
>> the register-access path between the CPU and each controller, not
>> the PHY
>> analog circuitry itself.
>>
>> The original single-port driver enabled `HUSBH0_GATE` as if it belonged
>> to the
>> PHY, but that gate is actually owned by EHCI0/OHCI0 and is already
>> managed by
>> those controller drivers through their own `clocks` DTS bindings. The PHY
>> driver was redundantly enabling the same gate.
>>
>> When extending the driver to cover PHY1, the same pattern held: EHCI1/OHCI1
>> manage `HUSBH1_GATE` themselves. There is no clock that belongs
>> exclusively to
>> the PHY, so `clocks` will be dropped from the PHY binding entirely.
> What driver has to do with it?
>
> You did not answer the question. How adding missing OTG to existing
> device causes that hardware to lose a clock? How is it possible?
>
To answer the hardware question directly: adding OTG support does not
cause the hardware to lose a clock. The hardware clock topology is
identical in both the single-port and dual-port cases.
The PHY analog block derives its reference from the 24 MHz HXT crystal
through an always-on path via the PHY's internal PLL. No software-gated
clock in the kernel clock tree sits in this path. The PHY's power-on and
reset state is managed through USBPMISCR in the SYS register block, which
the driver accesses via the nuvoton,sys regmap outside the clock tree.
`HUSBH0_GATE` gates the AHB bus interface to the EHCI0/OHCI0 host
controllers that share PHY0. This relationship is the same in both the
single-port and dual-port configurations.
>>>> + nuvoton,rcalcode:
>>>> + $ref: /schemas/types.yaml#/definitions/uint32-array
>>>> + minItems: 1
>>>> + maxItems: 2
>>> You should require two values. I understand that any PHY is optional,
>>> thus you skip the entry, so how would you provide value for PHY1 only?
>> `nuvoton,rcalcode` will be changed to require exactly two values
>> (`minItems: 2, maxItems: 2`), one for PHY0 and one for PHY1 respectively.
>> The property will remain optional overall; when absent, each port
>> retains its
>> power-on default value loaded at hardware initialisation. When present, both
>> entries must be supplied.
> So are you going to implement it or not?
>
Yes, I will implement this change in the next version of the patchset.
>>>> + items:
>>>> + minimum: 0
>>>> + maximum: 15
>>>> + description:
>>>> + Resistor calibration trim codes for PHY0 and PHY1 respectively.
>>>> + Each 4-bit value is written to the RCALCODE field in USBPMISCR and
>>>> + adjusts the PHY's internal termination resistance. Both entries are
>>>> + optional; when absent the hardware reset default is used.
>>>>
>>>> - nuvoton,sys:
>>>> - $ref: /schemas/types.yaml#/definitions/phandle
>>>> + nuvoton,oc-active-high:
>>>> + type: boolean
>>>> description:
>>>> - phandle to syscon for checking the PHY clock status.
>>>> + When present, the over-current detect input from the VBUS power switch
>>>> + is treated as active-high. The default (property absent) is active-low.
>>>> + This setting is shared by both USB host ports.
>>>>
>>>> required:
>>>> - compatible
>>>> + - reg
>>> That's ABI break which was not explained in the commit msg - neither
>>> specifying impact nor actually providing reasons why you break ABI.
>>>
>>> And honestly, you have no resources here except the address, so now it
>>> is clear that this should be folded into parent. See DTS101 talk slides.
>> The commit message will be updated to explicitly acknowledge the ABI break:
>> existing DTS files that contain a standalone `usb-phy` node without a `reg`
>> property will fail dt-schema validation after this change. The impact is
>> limited to the MA35D1 SoC; no upstream DTS for this SoC existed before this
>> patch series, so no in-tree board files are broken. The break is intentional
> But all of out of tree users are broken.
On reflection, the approach is being revised to eliminate the ABI break
entirely.
The next revision will keep the existing `nuvoton,ma35d1-usb2-phy` binding
intact with all its current required properties (`compatible`, `clocks`,
`nuvoton,sys`, `#phy-cells`). New OTG and dual-port capability will be
expressed as strictly optional backward-compatible additions:
- `#phy-cells` updated from `const: 0` to `enum: [0, 1]`. Existing DTS
with `#phy-cells = <0>` continues to validate and behave as before.
New DTS opting into dual-port uses `#phy-cells = <1>`.
- `nuvoton,rcalcode`: optional, exactly two values when present.
- `nuvoton,oc-active-high`: optional boolean.
>
> Best regards,
> Krzysztof
^ permalink raw reply
* Re: [PATCH 2/2] iio: adc: Add Nuvoton MA35D1 EADC driver
From: Chi-Wen Weng @ 2026-07-02 1:41 UTC (permalink / raw)
To: Jonathan Cameron
Cc: robh, krzk+dt, conor+dt, dlechner, nuno.sa, andy,
linux-arm-kernel, linux-iio, devicetree, linux-kernel, cwweng
In-Reply-To: <20260701221115.544e33fd@jic23-huawei>
Hi Jonathan,
Thanks for the review.
> Look at the ACQUIRE() macros for claim direct stuff (in iio.h)
> and then use guard() for this. Be careful to add {} to define scope
> to being this case block. May not save much code but it will be easeir
> to read than this currently is.
Understood. I will switch the direct read path to
IIO_DEV_ACQUIRE_DIRECT_MODE() / IIO_DEV_ACQUIRE_FAILED() and use
guard(mutex) for the driver lock. I will also add a scope around the
IIO_CHAN_INFO_RAW case block.
> Move assignment down to just above the loop. Makes it easier for
> reviewers to associate the initial value with what is going on.
Will do.
> For new code
> ret = devm_mutex_init(&adc->lock);
> if (ret)
> return ret;
Will fix this in v2.
> Second part of this is set by the triggered_buffer call later. So
don't set it
> here.
Understood. I will keep only INDIO_DIRECT_MODE here and let
devm_iio_triggered_buffer_setup() set the triggered-buffer mode.
> Failing suspend because a buffer is enabled is unlikely to be popular.
> Can you not save necessary state and restore so buffered capture
continues
> on resume?
Yes, I will rework the PM callbacks so suspend does not fail just because
the buffer is enabled.
For v2, I plan to suspend the IIO triggering path, stop the EADC
conversion/interrupt path, save the state needed for buffered capture,
and then disable the ADC and its clock. On resume, I will re-enable the
clock, reinitialize the ADC, restore the scan configuration, and restart
the buffered conversion path if it was active before suspend.
Thanks,
Chi-Wen
^ permalink raw reply
* [PATCH v13 15/15] barrier: add clock tests for smp_cond_load_relaxed_timeout()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
Add a few clock tests for smp_cond_load_relaxed_timeout(). These
ensure that the implementation doesn't do anything funny stuff with the
clock (like multiple accesses per iteration.)
Also ensure that we handle edge cases sanely. Note that two edge cases
fail: S64_MAX and U64_MAX. However, both of those are quite far out
and if needed, can be addressed in the implementation of the interface.
Also, this tests only smp_cond_load_relaxed_timeout(). The acquire
variant uses an identical clock path and testing wouldn't add anything.
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
Notes: removed the test case for timeout=-1 (a negative timeout value is not
supported). This also addresses the comment about the test for timeout=-1
only being incidentally correct [1].
Also add test cases for timeout=0, timeout=1.
[1] https://lore.kernel.org/all/20260608083449.171881F00898@smtp.kernel.org/
---
lib/tests/barrier-timeout-test.c | 58 ++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/lib/tests/barrier-timeout-test.c b/lib/tests/barrier-timeout-test.c
index 4226fb6456b3..ec78f8533006 100644
--- a/lib/tests/barrier-timeout-test.c
+++ b/lib/tests/barrier-timeout-test.c
@@ -19,6 +19,8 @@ MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
struct clock_state {
s64 start_time;
s64 end_time;
+ s64 extra;
+ u32 niters;
};
#define TIMEOUT_MSEC 2
@@ -112,8 +114,64 @@ static void test_smp_cond_timeout(struct kunit *test)
KUNIT_EXPECT_GE(test, runtime, timeout_ns);
}
+static s64 synthetic_clock(struct clock_state *clk)
+{
+ clk->end_time += clk->extra;
+ clk->niters++;
+
+ return clk->end_time;
+}
+
+
+struct smp_cond_expiry_params {
+ char *desc;
+ s64 timeout;
+ s64 clk_inc;
+ u32 niters;
+};
+
+static const struct smp_cond_expiry_params expiry_params_list[] = {
+ { .clk_inc = (0x1ULL << 28), .timeout = 0, .niters = 1, .desc = "0", },
+ { .clk_inc = (0x1ULL << 28), .timeout = 1, .niters = 2, .desc = "1", },
+ { .clk_inc = (0x1ULL << 28), .timeout = (0x1ULL << 30), .niters = 1 + (1 << (30-28)), .desc = "1<<30", },
+ { .clk_inc = (0x1ULL << 28), .timeout = S32_MAX, .niters = 1 + (1 << (31-28)), .desc = "S32_MAX", },
+ { .clk_inc = (0x1ULL << 28), .timeout = U32_MAX, .niters = 1 + (1 << (32-28)), .desc = "U32_MAX", },
+ { .clk_inc = (0x1ULL << 28), .timeout = (0x1ULL << 33), .niters = 1 + (1 << (33-28)), .desc = "1<<33", },
+};
+
+static void expiry_param_to_desc(const struct smp_cond_expiry_params *p, char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "smp_cond_%s_timeout: clock-%s, timeout=%s, iterations=%u",
+ "relaxed", "synthetic", p->desc, p->niters);
+}
+
+static void test_smp_cond_expiry(struct kunit *test)
+{
+ const struct smp_cond_expiry_params *p = test->param_value;
+ struct clock_state clk = {
+ .start_time = 0,
+ .end_time = 0,
+ .extra = p->clk_inc,
+ .niters = 0,
+ };
+ s64 runtime;
+
+ flag = 0;
+ smp_cond_load_relaxed_timeout(&flag,
+ 0,
+ synthetic_clock(&clk),
+ p->timeout);
+
+ runtime = (u64)clk.end_time - (u64)clk.start_time;
+ KUNIT_EXPECT_EQ(test, clk.niters, p->niters);
+ KUNIT_EXPECT_GE(test, runtime, p->timeout);
+}
+
+
+KUNIT_ARRAY_PARAM(smp_cond_expiry_params, expiry_params_list, expiry_param_to_desc);
static struct kunit_case barrier_timeout_test_cases[] = {
KUNIT_CASE_PARAM(test_smp_cond_timeout, smp_cond_update_params_gen_params),
+ KUNIT_CASE_PARAM(test_smp_cond_expiry, smp_cond_expiry_params_gen_params),
{}
};
--
2.43.7
^ permalink raw reply related
* [PATCH v13 13/15] arm64/delay: enable testing smp_cond_load_relaxed_timeout()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
This enables the barrier tests to be built as a module.
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
arch/arm64/lib/delay.c | 2 ++
drivers/clocksource/arm_arch_timer.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
index c660a7ea26dd..dfb102ce3009 100644
--- a/arch/arm64/lib/delay.c
+++ b/arch/arm64/lib/delay.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timex.h>
+#include <kunit/visibility.h>
#include <asm/delay-const.h>
#include <clocksource/arm_arch_timer.h>
@@ -30,6 +31,7 @@ u64 notrace __delay_cycles(void)
guard(preempt_notrace)();
return __arch_counter_get_cntvct_stable();
}
+EXPORT_SYMBOL_IF_KUNIT(__delay_cycles);
void __delay(unsigned long cycles)
{
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4adf756423de..91ab8552ead8 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -28,6 +28,7 @@
#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/ptp_kvm.h>
+#include <kunit/visibility.h>
#include <asm/arch_timer.h>
#include <asm/virt.h>
@@ -897,6 +898,7 @@ bool arch_timer_evtstrm_available(void)
*/
return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available);
}
+EXPORT_SYMBOL_IF_KUNIT(arch_timer_evtstrm_available);
static struct arch_timer_kvm_info arch_timer_kvm_info;
--
2.43.7
^ permalink raw reply related
* [PATCH v13 14/15] barrier: add tests for smp_cond_load_*_timeout()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
Add success and failure case tests for smp_cond_load_*_timeout().
Success or failure cases depend on the expected bit being set (or not).
Additionally in failure cases smp_cond_load_*_timeout() cannot return
before timeout.
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
lib/Kconfig.debug | 10 +++
lib/tests/Makefile | 1 +
lib/tests/barrier-timeout-test.c | 128 +++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+)
create mode 100644 lib/tests/barrier-timeout-test.c
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294..bb499c316caf 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2406,6 +2406,16 @@ config FPROBE_SANITY_TEST
Say N if you are unsure.
+config BARRIER_TIMEOUT_TEST
+ tristate "KUnit tests for smp_cond_load_relaxed_timeout()"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Builds KUnit tests that validate wake-up and timeout handling paths
+ in smp_cond_load_relaxed_timeout().
+
+ Say N if you are unsure.
+
config BACKTRACE_SELF_TEST
tristate "Self test for the backtrace code"
depends on DEBUG_KERNEL
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 4ead57602eac..291cc9d1bf76 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -21,6 +21,7 @@ CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
+obj-$(CONFIG_BARRIER_TIMEOUT_TEST) += barrier-timeout-test.o
obj-$(CONFIG_GLOB_KUNIT_TEST) += glob_kunit.o
obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o
obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
diff --git a/lib/tests/barrier-timeout-test.c b/lib/tests/barrier-timeout-test.c
new file mode 100644
index 000000000000..4226fb6456b3
--- /dev/null
+++ b/lib/tests/barrier-timeout-test.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit tests exercising smp_cond_load_relaxed_timeout().
+ *
+ * Copyright (c) 2026, Oracle Corp.
+ * Author: Ankur Arora <ankur.a.arora@oracle.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/sched/clock.h>
+#include <linux/delay.h>
+#include <asm/barrier.h>
+#include <kunit/test.h>
+#include <kunit/visibility.h>
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+struct clock_state {
+ s64 start_time;
+ s64 end_time;
+};
+
+#define TIMEOUT_MSEC 2
+#define TEST_FLAG_VAL BIT(2)
+static unsigned int flag;
+
+static s64 basic_clock(struct clock_state *clk)
+{
+ clk->end_time = local_clock();
+ return clk->end_time;
+}
+
+static void update_flags(void)
+{
+ WRITE_ONCE(flag, TEST_FLAG_VAL);
+}
+
+static s64 mocked_clock(struct clock_state *clk)
+{
+ s64 clk_mid = clk->start_time + (TIMEOUT_MSEC * NSEC_PER_MSEC)/2;
+
+ clk->end_time = local_clock();
+ if (clk->end_time >= clk_mid)
+ update_flags();
+ return clk->end_time;
+}
+
+typedef s64 (*clkfn_t)(struct clock_state *);
+struct smp_cond_update_params {
+ clkfn_t clock;
+ bool acquire;
+ bool succeeds;
+};
+
+static const struct smp_cond_update_params update_params_list[] = {
+ /* mocked-clock updates flag inline. */
+ { .clock = &mocked_clock, .succeeds = true, .acquire = false, },
+ { .clock = &mocked_clock, .succeeds = true, .acquire = true, },
+
+ /* basic-clock doesn't update flag. */
+ { .clock = &basic_clock, .succeeds = false, .acquire = true, },
+ { .clock = &basic_clock, .succeeds = false, .acquire = false, },
+};
+
+static void param_to_desc(const struct smp_cond_update_params *p, char *desc)
+{
+ char *clk, *update;
+
+ if (p->clock == &mocked_clock) {
+ clk = "mocked";
+ update = "inline";
+ } else if (p->clock == &basic_clock) {
+ clk = "basic";
+ update = "none";
+ }
+
+
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "smp_cond_%s_timeout: clock-%s, update=%s",
+ p->acquire ? "acquire" : "relaxed", clk, update);
+}
+
+KUNIT_ARRAY_PARAM(smp_cond_update_params, update_params_list, param_to_desc);
+
+
+static void test_smp_cond_timeout(struct kunit *test)
+{
+ const struct smp_cond_update_params *p = test->param_value;
+ struct clock_state clk = {
+ .start_time = local_clock(),
+ .end_time = local_clock(),
+ };
+ s64 runtime, timeout_ns = TIMEOUT_MSEC * NSEC_PER_MSEC;
+ unsigned int result;
+
+ flag = 0;
+ if (p->acquire) {
+ result = smp_cond_load_acquire_timeout(&flag,
+ (VAL & TEST_FLAG_VAL),
+ p->clock(&clk),
+ timeout_ns);
+ } else {
+ result = smp_cond_load_relaxed_timeout(&flag,
+ (VAL & TEST_FLAG_VAL),
+ p->clock(&clk),
+ timeout_ns);
+ }
+
+ runtime = clk.end_time - clk.start_time;
+ KUNIT_EXPECT_EQ(test, (bool)(result & TEST_FLAG_VAL), p->succeeds);
+ if (!p->succeeds)
+ KUNIT_EXPECT_GE(test, runtime, timeout_ns);
+}
+
+static struct kunit_case barrier_timeout_test_cases[] = {
+ KUNIT_CASE_PARAM(test_smp_cond_timeout, smp_cond_update_params_gen_params),
+ {}
+};
+
+static struct kunit_suite barrier_timeout_test_suite = {
+ .name = "smp-cond-load-*-timeout",
+ .test_cases = barrier_timeout_test_cases,
+};
+
+kunit_test_suite(barrier_timeout_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for smp_cond_load_relaxed_timeout()");
+MODULE_LICENSE("GPL");
--
2.43.7
^ permalink raw reply related
* [PATCH v13 12/15] cpuidle/poll_state: Wait for need-resched via tif_need_resched_relaxed_wait()
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
The inner loop in poll_idle() polls over the thread_info flags,
waiting to see if the thread has TIF_NEED_RESCHED set. The loop
exits once the condition is met, or if the poll time limit has
been exceeded.
To minimize the number of instructions executed in each iteration,
the time check is rate-limited. In addition, each loop iteration
executes cpu_relax() which on certain platforms provides a hint to
the pipeline that the loop busy-waits, allowing the processor to
reduce power consumption.
Switch over to tif_need_resched_relaxed_wait() instead, since that
provides exactly that.
However, since we want to minimize power consumption in idle, building
of cpuidle/poll_state.c continues to depend on CONFIG_ARCH_HAS_CPU_RELAX
as that serves as an indicator that the platform supports an optimized
version of tif_need_resched_relaxed_wait() (via
smp_cond_load_acquire_timeout()).
Cc: Rafael J. Wysocki <rafael@kernel.org>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: linux-pm@vger.kernel.org
Suggested-by: Rafael J. Wysocki <rafael@kernel.org>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Tested-by: Haris Okanovic <harisokn@amazon.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
Notes: does not address comment about breaking the timeout contract [1].
as the interface isn't meant to be precise.
[1] https://lore.kernel.org/all/20260608083136.20A521F00898@smtp.kernel.org/
---
drivers/cpuidle/poll_state.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c
index c7524e4c522a..7443b3e971ba 100644
--- a/drivers/cpuidle/poll_state.c
+++ b/drivers/cpuidle/poll_state.c
@@ -6,41 +6,22 @@
#include <linux/cpuidle.h>
#include <linux/export.h>
#include <linux/irqflags.h>
-#include <linux/sched.h>
-#include <linux/sched/clock.h>
#include <linux/sched/idle.h>
#include <linux/sprintf.h>
#include <linux/types.h>
-#define POLL_IDLE_RELAX_COUNT 200
-
static int __cpuidle poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
- u64 time_start;
-
- time_start = local_clock_noinstr();
-
dev->poll_time_limit = false;
raw_local_irq_enable();
if (!current_set_polling_and_test()) {
- unsigned int loop_count = 0;
u64 limit;
limit = cpuidle_poll_time(drv, dev);
- while (!need_resched()) {
- cpu_relax();
- if (loop_count++ < POLL_IDLE_RELAX_COUNT)
- continue;
-
- loop_count = 0;
- if (local_clock_noinstr() - time_start > limit) {
- dev->poll_time_limit = true;
- break;
- }
- }
+ dev->poll_time_limit = !tif_need_resched_relaxed_wait(limit);
}
raw_local_irq_disable();
--
2.43.7
^ permalink raw reply related
* [PATCH v13 11/15] sched: add need-resched timed wait interface
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora,
Ingo Molnar
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
Add tif_bitset_relaxed_wait() (and tif_need_resched_relaxed_wait()
which wraps it) which takes the thread_info bit and timeout duration
as parameters and waits until the bit is set or for the expiration
of the timeout.
The wait is implemented via smp_cond_load_relaxed_timeout().
smp_cond_load_relaxed_timeout() essentially provides the pattern used
in poll_idle() where we spin in a loop waiting for the flag to change
until a timeout occurs.
tif_need_resched_relaxed_wait() allows us to abstract out the internals
of waiting, scheduler specific details etc.
Placed in linux/sched/idle.h instead of linux/thread_info.h to work
around recursive include hell.
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rafael J. Wysocki <rafael@kernel.org>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: linux-pm@vger.kernel.org
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
include/linux/sched/idle.h | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/include/linux/sched/idle.h b/include/linux/sched/idle.h
index 8465ff1f20d1..ddee9b019895 100644
--- a/include/linux/sched/idle.h
+++ b/include/linux/sched/idle.h
@@ -3,6 +3,7 @@
#define _LINUX_SCHED_IDLE_H
#include <linux/sched.h>
+#include <linux/sched/clock.h>
enum cpu_idle_type {
__CPU_NOT_IDLE = 0,
@@ -113,4 +114,32 @@ static __always_inline void current_clr_polling(void)
}
#endif
+/*
+ * Caller needs to make sure that the thread context cannot be preempted
+ * or migrated, so current_thread_info() cannot change from under us.
+ *
+ * This also allows us to safely stay in the local_clock domain.
+ */
+static __always_inline bool tif_bitset_relaxed_wait(int tif, u64 timeout_ns)
+{
+ unsigned long flags;
+
+ flags = smp_cond_load_relaxed_timeout(¤t_thread_info()->flags,
+ (VAL & BIT(tif)),
+ local_clock_noinstr(),
+ timeout_ns);
+ return flags & BIT(tif);
+}
+
+/**
+ * tif_need_resched_relaxed_wait() - Wait for need-resched being set
+ * with no ordering guarantees until a timeout expires.
+ *
+ * @timeout_ns: timeout value.
+ */
+static __always_inline bool tif_need_resched_relaxed_wait(u64 timeout_ns)
+{
+ return tif_bitset_relaxed_wait(TIF_NEED_RESCHED, timeout_ns);
+}
+
#endif /* _LINUX_SCHED_IDLE_H */
--
2.43.7
^ permalink raw reply related
* [PATCH v13 09/15] bpf/rqspinlock: switch check_timeout() to a clock interface
From: Ankur Arora @ 2026-07-02 1:33 UTC (permalink / raw)
To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
rdunlap, david.laight.linux, broonie, joao.m.martins,
boris.ostrovsky, konrad.wilk, ashok.bhat, Ankur Arora
In-Reply-To: <20260702013334.140905-1-ankur.a.arora@oracle.com>
check_timeout() gets the current time value and depending on how
much time has passed, checks for deadlock or times out, returning 0
or -errno on deadlock or timeout.
Switch this out to a clock style interface, where it functions as a
clock in the "lock-domain", returning the current time until a
deadlock or timeout occurs. Once a deadlock or timeout has occurred,
it stops functioning as a clock and returns error.
Also adjust the RES_CHECK_TIMEOUT macro to discard the clock value
when updating the explicit return status.
Cc: bpf@vger.kernel.org
Cc: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
---
kernel/bpf/rqspinlock.c | 45 +++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 15 deletions(-)
diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c
index e4e338cdb437..0ec17ebb67c1 100644
--- a/kernel/bpf/rqspinlock.c
+++ b/kernel/bpf/rqspinlock.c
@@ -196,8 +196,12 @@ static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask)
return 0;
}
-static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
- struct rqspinlock_timeout *ts)
+/*
+ * Returns current monotonic time in ns on success or, negative errno
+ * value on failure due to timeout expiration or detection of deadlock.
+ */
+static noinline s64 clock_deadlock(rqspinlock_t *lock, u32 mask,
+ struct rqspinlock_timeout *ts)
{
u64 prev = ts->cur;
u64 time;
@@ -207,7 +211,7 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
return -EDEADLK;
ts->cur = ktime_get_mono_fast_ns();
ts->timeout_end = ts->cur + ts->duration;
- return 0;
+ return (s64)ts->cur;
}
time = ktime_get_mono_fast_ns();
@@ -219,11 +223,15 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
* checks.
*/
if (prev + NSEC_PER_MSEC < time) {
+ int ret;
ts->cur = time;
- return check_deadlock_ABBA(lock, mask);
+ ret = check_deadlock_ABBA(lock, mask);
+ if (ret)
+ return ret;
+
}
- return 0;
+ return (s64)time;
}
/*
@@ -231,15 +239,22 @@ static noinline int check_timeout(rqspinlock_t *lock, u32 mask,
* as the macro does internal amortization for us.
*/
#ifndef res_smp_cond_load_acquire
-#define RES_CHECK_TIMEOUT(ts, ret, mask) \
- ({ \
- if (!(ts).spin++) \
- (ret) = check_timeout((lock), (mask), &(ts)); \
- (ret); \
+#define RES_CHECK_TIMEOUT(ts, ret, mask) \
+ ({ \
+ s64 __timeval_err = 0; \
+ if (!(ts).spin++) \
+ __timeval_err = clock_deadlock((lock), (mask), &(ts)); \
+ (ret) = __timeval_err < 0 ? __timeval_err : 0; \
+ __timeval_err; \
})
#else
-#define RES_CHECK_TIMEOUT(ts, ret, mask) \
- ({ (ret) = check_timeout((lock), (mask), &(ts)); })
+#define RES_CHECK_TIMEOUT(ts, ret, mask) \
+ ({ \
+ s64 __timeval_err; \
+ __timeval_err = clock_deadlock((lock), (mask), &(ts)); \
+ (ret) = __timeval_err < 0 ? __timeval_err : 0; \
+ __timeval_err; \
+ })
#endif
/*
@@ -281,7 +296,7 @@ int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock)
val = atomic_read(&lock->val);
if (val || !atomic_try_cmpxchg(&lock->val, &val, 1)) {
- if (RES_CHECK_TIMEOUT(ts, ret, ~0u))
+ if (RES_CHECK_TIMEOUT(ts, ret, ~0u) < 0)
goto out;
cpu_relax();
goto retry;
@@ -406,7 +421,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
*/
if (val & _Q_LOCKED_MASK) {
RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
- res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_MASK));
+ res_smp_cond_load_acquire(&lock->locked, !VAL || RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_MASK) < 0);
}
if (ret) {
@@ -568,7 +583,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
*/
RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT * 2);
val = res_atomic_cond_read_acquire(&lock->val, !(VAL & _Q_LOCKED_PENDING_MASK) ||
- RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_PENDING_MASK));
+ RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_PENDING_MASK) < 0);
/* Disable queue destruction when we detect deadlocks. */
if (ret == -EDEADLK) {
--
2.43.7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox