Merge branch 'use-enum-to-represent-the-napi-threaded-state'

Samiullah Khawaja says:

====================
Use enum to represent the NAPI threaded state

Instead of using 0/1 to represent the NAPI threaded states use enum
(disabled/enabled) to represent the NAPI threaded states.

This patch series is a subset of patches from the following patch series:
https://lore.kernel.org/20250718232052.1266188-1-skhawaja@google.com

The first 3 patches are being sent separately as per the feedback to
replace the usage of 0/1 as NAPI threaded states with enum. See:
https://lore.kernel.org/20250721164856.1d2208e4@kernel.org
====================

Link: https://patch.msgid.link/20250723013031.2911384-1-skhawaja@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-07-24 18:34:59 -07:00
18 changed files with 95 additions and 54 deletions

View File

@@ -85,6 +85,10 @@ definitions:
name: qstats-scope
type: flags
entries: [queue]
-
name: napi-threaded
type: enum
entries: [disabled, enabled]
attribute-sets:
-
@@ -286,11 +290,10 @@ attribute-sets:
-
name: threaded
doc: Whether the NAPI is configured to operate in threaded polling
mode. If this is set to 1 then the NAPI context operates in
threaded polling mode.
type: uint
checks:
max: 1
mode. If this is set to enabled then the NAPI context operates
in threaded polling mode.
type: u32
enum: napi-threaded
-
name: xsk-info
attributes: []

View File

@@ -68,6 +68,7 @@ unsigned_char addr_assign_type
unsigned_char addr_len
unsigned_char upper_level
unsigned_char lower_level
u8 threaded napi_poll(napi_enable,netif_set_threaded)
unsigned_short neigh_priv_len
unsigned_short padded
unsigned_short dev_id
@@ -165,7 +166,6 @@ struct sfp_bus* sfp_bus
struct lock_class_key* qdisc_tx_busylock
bool proto_down
unsigned:1 wol_enabled
unsigned:1 threaded napi_poll(napi_enable,netif_set_threaded)
unsigned_long:1 see_all_hwtstamp_requests
unsigned_long:1 change_proto_down
unsigned_long:1 netns_immutable

View File

@@ -2688,7 +2688,7 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->mii.mdio_write = atl1c_mdio_write;
adapter->mii.phy_id_mask = 0x1f;
adapter->mii.reg_num_mask = MDIO_CTRL_REG_MASK;
netif_set_threaded(netdev, true);
netif_threaded_enable(netdev);
for (i = 0; i < adapter->rx_queue_count; ++i)
netif_napi_add(netdev, &adapter->rrd_ring[i].napi,
atl1c_clean_rx);

View File

@@ -156,7 +156,7 @@ static int mlxsw_pci_napi_devs_init(struct mlxsw_pci *mlxsw_pci)
}
strscpy(mlxsw_pci->napi_dev_rx->name, "mlxsw_rx",
sizeof(mlxsw_pci->napi_dev_rx->name));
netif_set_threaded(mlxsw_pci->napi_dev_rx, true);
netif_threaded_enable(mlxsw_pci->napi_dev_rx);
return 0;

View File

@@ -3075,7 +3075,7 @@ static int ravb_probe(struct platform_device *pdev)
if (info->coalesce_irqs) {
netdev_sw_irq_coalesce_default_on(ndev);
if (num_present_cpus() == 1)
netif_set_threaded(ndev, true);
netif_threaded_enable(ndev);
}
/* Network device register */

View File

@@ -366,7 +366,7 @@ static int wg_newlink(struct net_device *dev,
if (ret < 0)
goto err_free_handshake_queue;
netif_set_threaded(dev, true);
netif_threaded_enable(dev);
ret = register_netdevice(dev);
if (ret < 0)
goto err_uninit_ratelimiter;

View File

@@ -936,7 +936,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar)
bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
netif_set_threaded(ar->napi_dev, true);
netif_threaded_enable(ar->napi_dev);
ath10k_core_napi_enable(ar);
/* IRQs are left enabled when we restart due to a firmware crash */
if (!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))

View File

@@ -369,7 +369,7 @@ struct napi_config {
u64 irq_suspend_timeout;
u32 defer_hard_irqs;
cpumask_t affinity_mask;
bool threaded;
u8 threaded;
unsigned int napi_id;
};
@@ -589,8 +589,9 @@ static inline bool napi_complete(struct napi_struct *n)
return napi_complete_done(n, 0);
}
int netif_set_threaded(struct net_device *dev, bool threaded);
int dev_set_threaded(struct net_device *dev, bool threaded);
void netif_threaded_enable(struct net_device *dev);
int dev_set_threaded(struct net_device *dev,
enum netdev_napi_threaded threaded);
void napi_disable(struct napi_struct *n);
void napi_disable_locked(struct napi_struct *n);
@@ -1872,6 +1873,7 @@ enum netdev_reg_state {
* @addr_len: Hardware address length
* @upper_level: Maximum depth level of upper devices.
* @lower_level: Maximum depth level of lower devices.
* @threaded: napi threaded state.
* @neigh_priv_len: Used in neigh_alloc()
* @dev_id: Used to differentiate devices that share
* the same link layer address
@@ -2011,8 +2013,6 @@ enum netdev_reg_state {
* switch driver and used to set the phys state of the
* switch port.
*
* @threaded: napi threaded mode is enabled
*
* @irq_affinity_auto: driver wants the core to store and re-assign the IRQ
* affinity. Set by netif_enable_irq_affinity(), then
* the driver must create a persistent napi by
@@ -2248,6 +2248,7 @@ struct net_device {
unsigned char addr_len;
unsigned char upper_level;
unsigned char lower_level;
u8 threaded;
unsigned short neigh_priv_len;
unsigned short dev_id;
@@ -2429,7 +2430,6 @@ struct net_device {
struct sfp_bus *sfp_bus;
struct lock_class_key *qdisc_tx_busylock;
bool proto_down;
bool threaded;
bool irq_affinity_auto;
bool rx_cpu_rmap_auto;

View File

@@ -534,6 +534,12 @@ static inline void gro_normal_list(struct gro_node *gro)
gro->rx_count = 0;
}
static inline void gro_flush_normal(struct gro_node *gro, bool flush_old)
{
gro_flush(gro, flush_old);
gro_normal_list(gro);
}
/* Queue one GRO_NORMAL SKB up for list processing. If batch size exceeded,
* pass the whole batch up to the stack.
*/

View File

@@ -77,6 +77,11 @@ enum netdev_qstats_scope {
NETDEV_QSTATS_SCOPE_QUEUE = 1,
};
enum netdev_napi_threaded {
NETDEV_NAPI_THREADED_DISABLED,
NETDEV_NAPI_THREADED_ENABLED,
};
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,

View File

@@ -282,8 +282,7 @@ static void cpu_map_gro_flush(struct bpf_cpu_map_entry *rcpu, bool empty)
* This is equivalent to how NAPI decides whether to perform a full
* flush.
*/
gro_flush(&rcpu->gro, !empty && HZ >= 1000);
gro_normal_list(&rcpu->gro);
gro_flush_normal(&rcpu->gro, !empty && HZ >= 1000);
}
static int cpu_map_kthread_run(void *data)

View File

@@ -6578,8 +6578,7 @@ bool napi_complete_done(struct napi_struct *n, int work_done)
* it, we need to bound somehow the time packets are kept in
* the GRO layer.
*/
gro_flush(&n->gro, !!timeout);
gro_normal_list(&n->gro);
gro_flush_normal(&n->gro, !!timeout);
if (unlikely(!list_empty(&n->poll_list))) {
/* If n->poll_list is not empty, we need to mask irqs */
@@ -6649,8 +6648,7 @@ static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule)
}
/* Flush too old packets. If HZ < 1000, flush all packets */
gro_flush(&napi->gro, HZ >= 1000);
gro_normal_list(&napi->gro);
gro_flush_normal(&napi->gro, HZ >= 1000);
clear_bit(NAPI_STATE_SCHED, &napi->state);
}
@@ -6965,7 +6963,8 @@ static void napi_stop_kthread(struct napi_struct *napi)
napi->thread = NULL;
}
int napi_set_threaded(struct napi_struct *napi, bool threaded)
int napi_set_threaded(struct napi_struct *napi,
enum netdev_napi_threaded threaded)
{
if (threaded) {
if (!napi->thread) {
@@ -6990,7 +6989,8 @@ int napi_set_threaded(struct napi_struct *napi, bool threaded)
return 0;
}
int netif_set_threaded(struct net_device *dev, bool threaded)
int netif_set_threaded(struct net_device *dev,
enum netdev_napi_threaded threaded)
{
struct napi_struct *napi;
int err = 0;
@@ -7002,7 +7002,7 @@ int netif_set_threaded(struct net_device *dev, bool threaded)
if (!napi->thread) {
err = napi_kthread_create(napi);
if (err) {
threaded = false;
threaded = NETDEV_NAPI_THREADED_DISABLED;
break;
}
}
@@ -7031,7 +7031,23 @@ int netif_set_threaded(struct net_device *dev, bool threaded)
return err;
}
EXPORT_SYMBOL(netif_set_threaded);
/**
* netif_threaded_enable() - enable threaded NAPIs
* @dev: net_device instance
*
* Enable threaded mode for the NAPI instances of the device. This may be useful
* for devices where multiple NAPI instances get scheduled by a single
* interrupt. Threaded NAPI allows moving the NAPI processing to cores other
* than the core where IRQ is mapped.
*
* This function should be called before @dev is registered.
*/
void netif_threaded_enable(struct net_device *dev)
{
WARN_ON_ONCE(netif_set_threaded(dev, NETDEV_NAPI_THREADED_ENABLED));
}
EXPORT_SYMBOL(netif_threaded_enable);
/**
* netif_queue_set_napi - Associate queue with the napi
@@ -7346,7 +7362,7 @@ void netif_napi_add_weight_locked(struct net_device *dev,
* threaded mode will not be enabled in napi_enable().
*/
if (dev->threaded && napi_kthread_create(napi))
dev->threaded = false;
dev->threaded = NETDEV_NAPI_THREADED_DISABLED;
netif_napi_set_irq_locked(napi, -1);
}
EXPORT_SYMBOL(netif_napi_add_weight_locked);
@@ -7515,8 +7531,7 @@ static int __napi_poll(struct napi_struct *n, bool *repoll)
}
/* Flush too old packets. If HZ < 1000, flush all packets */
gro_flush(&n->gro, HZ >= 1000);
gro_normal_list(&n->gro);
gro_flush_normal(&n->gro, HZ >= 1000);
/* Some drivers may have called napi_schedule
* prior to exhausting their budget.

View File

@@ -315,12 +315,19 @@ static inline void napi_set_irq_suspend_timeout(struct napi_struct *n,
WRITE_ONCE(n->irq_suspend_timeout, timeout);
}
static inline bool napi_get_threaded(struct napi_struct *n)
static inline enum netdev_napi_threaded napi_get_threaded(struct napi_struct *n)
{
return test_bit(NAPI_STATE_THREADED, &n->state);
if (test_bit(NAPI_STATE_THREADED, &n->state))
return NETDEV_NAPI_THREADED_ENABLED;
return NETDEV_NAPI_THREADED_DISABLED;
}
int napi_set_threaded(struct napi_struct *n, bool threaded);
int napi_set_threaded(struct napi_struct *n,
enum netdev_napi_threaded threaded);
int netif_set_threaded(struct net_device *dev,
enum netdev_napi_threaded threaded);
int rps_cpumask_housekeeping(struct cpumask *mask);

View File

@@ -368,7 +368,8 @@ void netdev_state_change(struct net_device *dev)
}
EXPORT_SYMBOL(netdev_state_change);
int dev_set_threaded(struct net_device *dev, bool threaded)
int dev_set_threaded(struct net_device *dev,
enum netdev_napi_threaded threaded)
{
int ret;

View File

@@ -97,7 +97,7 @@ static const struct nla_policy netdev_napi_set_nl_policy[NETDEV_A_NAPI_THREADED
[NETDEV_A_NAPI_DEFER_HARD_IRQS] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_napi_defer_hard_irqs_range),
[NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT] = { .type = NLA_UINT, },
[NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT] = { .type = NLA_UINT, },
[NETDEV_A_NAPI_THREADED] = NLA_POLICY_MAX(NLA_UINT, 1),
[NETDEV_A_NAPI_THREADED] = NLA_POLICY_MAX(NLA_U32, 1),
};
/* NETDEV_CMD_BIND_TX - do */

View File

@@ -333,7 +333,7 @@ netdev_nl_napi_set_config(struct napi_struct *napi, struct genl_info *info)
int ret;
threaded = nla_get_uint(info->attrs[NETDEV_A_NAPI_THREADED]);
ret = napi_set_threaded(napi, !!threaded);
ret = napi_set_threaded(napi, threaded);
if (ret)
return ret;
}

View File

@@ -77,6 +77,11 @@ enum netdev_qstats_scope {
NETDEV_QSTATS_SCOPE_QUEUE = 1,
};
enum netdev_napi_threaded {
NETDEV_NAPI_THREADED_DISABLED,
NETDEV_NAPI_THREADED_ENABLED,
};
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,

View File

@@ -52,14 +52,14 @@ def napi_set_threaded(nf) -> None:
napi1_id = napis[1]['id']
# set napi threaded and verify
nf.napi_set({'id': napi0_id, 'threaded': 1})
nf.napi_set({'id': napi0_id, 'threaded': "enabled"})
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 1)
ksft_eq(napi0['threaded'], "enabled")
ksft_ne(napi0.get('pid'), None)
# check it is not set for napi1
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 0)
ksft_eq(napi1['threaded'], "disabled")
ksft_eq(napi1.get('pid'), None)
ip(f"link set dev {nsim.ifname} down")
@@ -67,18 +67,18 @@ def napi_set_threaded(nf) -> None:
# verify if napi threaded is still set
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 1)
ksft_eq(napi0['threaded'], "enabled")
ksft_ne(napi0.get('pid'), None)
# check it is still not set for napi1
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 0)
ksft_eq(napi1['threaded'], "disabled")
ksft_eq(napi1.get('pid'), None)
# unset napi threaded and verify
nf.napi_set({'id': napi0_id, 'threaded': 0})
nf.napi_set({'id': napi0_id, 'threaded': "disabled"})
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 0)
ksft_eq(napi0['threaded'], "disabled")
ksft_eq(napi0.get('pid'), None)
# set threaded at device level
@@ -86,10 +86,10 @@ def napi_set_threaded(nf) -> None:
# check napi threaded is set for both napis
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 1)
ksft_eq(napi0['threaded'], "enabled")
ksft_ne(napi0.get('pid'), None)
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 1)
ksft_eq(napi1['threaded'], "enabled")
ksft_ne(napi1.get('pid'), None)
# unset threaded at device level
@@ -97,16 +97,16 @@ def napi_set_threaded(nf) -> None:
# check napi threaded is unset for both napis
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 0)
ksft_eq(napi0['threaded'], "disabled")
ksft_eq(napi0.get('pid'), None)
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 0)
ksft_eq(napi1['threaded'], "disabled")
ksft_eq(napi1.get('pid'), None)
# set napi threaded for napi0
nf.napi_set({'id': napi0_id, 'threaded': 1})
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 1)
ksft_eq(napi0['threaded'], "enabled")
ksft_ne(napi0.get('pid'), None)
# unset threaded at device level
@@ -114,10 +114,10 @@ def napi_set_threaded(nf) -> None:
# check napi threaded is unset for both napis
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 0)
ksft_eq(napi0['threaded'], "disabled")
ksft_eq(napi0.get('pid'), None)
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 0)
ksft_eq(napi1['threaded'], "disabled")
ksft_eq(napi1.get('pid'), None)
def dev_set_threaded(nf) -> None:
@@ -141,10 +141,10 @@ def dev_set_threaded(nf) -> None:
# check napi threaded is set for both napis
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 1)
ksft_eq(napi0['threaded'], "enabled")
ksft_ne(napi0.get('pid'), None)
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 1)
ksft_eq(napi1['threaded'], "enabled")
ksft_ne(napi1.get('pid'), None)
# unset threaded
@@ -152,10 +152,10 @@ def dev_set_threaded(nf) -> None:
# check napi threaded is unset for both napis
napi0 = nf.napi_get({'id': napi0_id})
ksft_eq(napi0['threaded'], 0)
ksft_eq(napi0['threaded'], "disabled")
ksft_eq(napi0.get('pid'), None)
napi1 = nf.napi_get({'id': napi1_id})
ksft_eq(napi1['threaded'], 0)
ksft_eq(napi1['threaded'], "disabled")
ksft_eq(napi1.get('pid'), None)
def nsim_rxq_reset_down(nf) -> None: