diff mbox series

[net-next,v2,3/4] Extend napi threaded polling to allow kthread based busy polling

Message ID 20250123231236.2657321-4-skhawaja@google.com (mailing list archive)
State Deferred
Delegated to: Netdev Maintainers
Headers show
Series Add support to do threaded napi busy poll | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; GEN HAS DIFF 2 files changed, 33 insertions(+);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 41 this patch: 44
netdev/build_tools success Errors and warnings before: 26 (+1) this patch: 26 (+1)
netdev/cc_maintainers warning 9 maintainers not CCed: donald.hunter@gmail.com linux-doc@vger.kernel.org willemb@google.com andrew+netdev@lunn.ch jacob.e.keller@intel.com jdamato@fastly.com horms@kernel.org corbet@lwn.net chris.snook@gmail.com
netdev/build_clang success Errors and warnings before: 7102 this patch: 7102
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 4116 this patch: 4119
netdev/checkpatch warning CHECK: Assignment operator '=' should be on the previous line WARNING: line length of 85 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 121 this patch: 121
netdev/source_inline success Was 0 now: 0

Commit Message

Samiullah Khawaja Jan. 23, 2025, 11:12 p.m. UTC
Add a new state to napi state enum:

- STATE_THREADED_BUSY_POLL
  Threaded busy poll is enabled/running for this napi.

Following changes are introduced in the napi scheduling and state logic:

- When threaded busy poll is enabled through sysfs it also enables
  NAPI_STATE_THREADED so a kthread is created per napi. It also sets
  NAPI_STATE_THREADED_BUSY_POLL bit on each napi to indicate that we are
  supposed to busy poll for each napi.

- When napi is scheduled with STATE_SCHED_THREADED and associated
  kthread is woken up, the kthread owns the context. If
  NAPI_STATE_THREADED_BUSY_POLL and NAPI_SCHED_THREADED both are set
  then it means that we can busy poll.

- To keep busy polling and to avoid scheduling of the interrupts, the
  napi_complete_done returns false when both SCHED_THREADED and
  THREADED_BUSY_POLL flags are set. Also napi_complete_done returns
  early to avoid the STATE_SCHED_THREADED being unset.

- If at any point STATE_THREADED_BUSY_POLL is unset, the
  napi_complete_done will run and unset the SCHED_THREADED bit also.
  This will make the associated kthread go to sleep as per existing
  logic.

Signed-off-by: Samiullah Khawaja <skhawaja@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
 Documentation/ABI/testing/sysfs-class-net     |  3 +-
 Documentation/netlink/specs/netdev.yaml       | 12 ++--
 Documentation/networking/napi.rst             | 67 ++++++++++++++++-
 .../net/ethernet/atheros/atl1c/atl1c_main.c   |  2 +-
 include/linux/netdevice.h                     | 20 ++++--
 include/uapi/linux/netdev.h                   |  6 ++
 net/core/dev.c                                | 72 ++++++++++++++++---
 net/core/net-sysfs.c                          |  2 +-
 net/core/netdev-genl-gen.c                    |  2 +-
 net/core/netdev-genl.c                        |  2 +-
 tools/include/uapi/linux/netdev.h             |  6 ++
 11 files changed, 168 insertions(+), 26 deletions(-)

Comments

kernel test robot Jan. 24, 2025, 1:18 p.m. UTC | #1
Hi Samiullah,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Samiullah-Khawaja/Add-support-to-set-napi-threaded-for-individual-napi/20250124-071412
base:   net-next/main
patch link:    https://lore.kernel.org/r/20250123231236.2657321-4-skhawaja%40google.com
patch subject: [PATCH net-next v2 3/4] Extend napi threaded polling to allow kthread based busy polling
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20250124/202501242114.hSuOcqsi-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250124/202501242114.hSuOcqsi-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501242114.hSuOcqsi-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/renesas/ravb_main.c: In function 'ravb_probe':
>> drivers/net/ethernet/renesas/ravb_main.c:3078:48: warning: implicit conversion from 'enum <anonymous>' to 'enum netdev_napi_threaded' [-Wenum-conversion]
    3078 |                         dev_set_threaded(ndev, true);
         |                                                ^~~~
--
   drivers/net/ethernet/mellanox/mlxsw/pci.c: In function 'mlxsw_pci_napi_devs_init':
>> drivers/net/ethernet/mellanox/mlxsw/pci.c:159:50: warning: implicit conversion from 'enum <anonymous>' to 'enum netdev_napi_threaded' [-Wenum-conversion]
     159 |         dev_set_threaded(mlxsw_pci->napi_dev_rx, true);
         |                                                  ^~~~
--
   drivers/net/wireless/ath/ath10k/snoc.c: In function 'ath10k_snoc_hif_start':
>> drivers/net/wireless/ath/ath10k/snoc.c:938:40: warning: implicit conversion from 'enum <anonymous>' to 'enum netdev_napi_threaded' [-Wenum-conversion]
     938 |         dev_set_threaded(ar->napi_dev, true);
         |                                        ^~~~


vim +3078 drivers/net/ethernet/renesas/ravb_main.c

32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2901  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2902  static int ravb_probe(struct platform_device *pdev)
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2903  {
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2904  	struct device_node *np = pdev->dev.of_node;
ebb091461a9e14 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2905  	const struct ravb_hw_info *info;
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2906  	struct reset_control *rstc;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2907  	struct ravb_private *priv;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2908  	struct net_device *ndev;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2909  	struct resource *res;
32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2910  	int error, q;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2911  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2912  	if (!np) {
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2913  		dev_err(&pdev->dev,
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2914  			"this driver is required to be instantiated from device tree\n");
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2915  		return -EINVAL;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2916  	}
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2917  
b1768e3dc47792 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2918  	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2919  	if (IS_ERR(rstc))
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2920  		return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2921  				     "failed to get cpg reset\n");
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2922  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2923  	ndev = alloc_etherdev_mqs(sizeof(struct ravb_private),
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2924  				  NUM_TX_QUEUE, NUM_RX_QUEUE);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2925  	if (!ndev)
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2926  		return -ENOMEM;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2927  
8912ed25daf6fc drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2928  	info = of_device_get_match_data(&pdev->dev);
8912ed25daf6fc drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2929  
8912ed25daf6fc drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2930  	ndev->features = info->net_features;
8912ed25daf6fc drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2931  	ndev->hw_features = info->net_hw_features;
546875ccba938b drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-10-15  2932  	ndev->vlan_features = info->vlan_features;
4d86d381862714 drivers/net/ethernet/renesas/ravb_main.c Simon Horman       2017-10-04  2933  
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  2934  	error = reset_control_deassert(rstc);
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  2935  	if (error)
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  2936  		goto out_free_netdev;
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  2937  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2938  	SET_NETDEV_DEV(ndev, &pdev->dev);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2939  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2940  	priv = netdev_priv(ndev);
ebb091461a9e14 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-18  2941  	priv->info = info;
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  2942  	priv->rstc = rstc;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2943  	priv->ndev = ndev;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2944  	priv->pdev = pdev;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2945  	priv->num_tx_ring[RAVB_BE] = BE_TX_RING_SIZE;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2946  	priv->num_rx_ring[RAVB_BE] = BE_RX_RING_SIZE;
1091da579d7ccd drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-12  2947  	if (info->nc_queues) {
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2948  		priv->num_tx_ring[RAVB_NC] = NC_TX_RING_SIZE;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2949  		priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
a92f4f0662bf2c drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-01  2950  	}
a92f4f0662bf2c drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-01  2951  
32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2952  	error = ravb_setup_irqs(priv);
32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2953  	if (error)
32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2954  		goto out_reset_assert;
32f012b8c01ca9 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2955  
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2956  	priv->clk = devm_clk_get(&pdev->dev, NULL);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2957  	if (IS_ERR(priv->clk)) {
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2958  		error = PTR_ERR(priv->clk);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2959  		goto out_reset_assert;
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2960  	}
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2961  
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2962  	if (info->gptp_ref_clk) {
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2963  		priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp");
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2964  		if (IS_ERR(priv->gptp_clk)) {
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2965  			error = PTR_ERR(priv->gptp_clk);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2966  			goto out_reset_assert;
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2967  		}
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2968  	}
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2969  
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2970  	priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk");
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2971  	if (IS_ERR(priv->refclk)) {
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2972  		error = PTR_ERR(priv->refclk);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2973  		goto out_reset_assert;
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2974  	}
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2975  	clk_prepare(priv->refclk);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2976  
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2977  	platform_set_drvdata(pdev, ndev);
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  2978  	pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  2979  	pm_runtime_use_autosuspend(&pdev->dev);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2980  	pm_runtime_enable(&pdev->dev);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2981  	error = pm_runtime_resume_and_get(&pdev->dev);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2982  	if (error < 0)
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2983  		goto out_rpm_disable;
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2984  
e89a2cdb1cca51 drivers/net/ethernet/renesas/ravb_main.c Yang Yingliang     2021-06-09  2985  	priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2986  	if (IS_ERR(priv->addr)) {
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2987  		error = PTR_ERR(priv->addr);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2988  		goto out_rpm_put;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2989  	}
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2990  
e89a2cdb1cca51 drivers/net/ethernet/renesas/ravb_main.c Yang Yingliang     2021-06-09  2991  	/* The Ether-specific entries in the device structure. */
e89a2cdb1cca51 drivers/net/ethernet/renesas/ravb_main.c Yang Yingliang     2021-06-09  2992  	ndev->base_addr = res->start;
e89a2cdb1cca51 drivers/net/ethernet/renesas/ravb_main.c Yang Yingliang     2021-06-09  2993  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2994  	spin_lock_init(&priv->lock);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2995  	INIT_WORK(&priv->work, ravb_tx_timeout_work);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  2996  
0c65b2b90d13c1 drivers/net/ethernet/renesas/ravb_main.c Andrew Lunn        2019-11-04  2997  	error = of_get_phy_mode(np, &priv->phy_interface);
0c65b2b90d13c1 drivers/net/ethernet/renesas/ravb_main.c Andrew Lunn        2019-11-04  2998  	if (error && error != -ENODEV)
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  2999  		goto out_rpm_put;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3000  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3001  	priv->no_avb_link = of_property_read_bool(np, "renesas,no-ether-link");
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3002  	priv->avb_link_active_low =
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3003  		of_property_read_bool(np, "renesas,ether-link-active-low");
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3004  
1d63864299cafa drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-09-18  3005  	ndev->max_mtu = info->tx_max_frame_size -
e82700b8662ce5 drivers/net/ethernet/renesas/ravb_main.c Niklas Söderlund   2024-03-04  3006  		(ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
75efa06f457bbe drivers/net/ethernet/renesas/ravb_main.c Niklas Söderlund   2018-02-16  3007  	ndev->min_mtu = ETH_MIN_MTU;
75efa06f457bbe drivers/net/ethernet/renesas/ravb_main.c Niklas Söderlund   2018-02-16  3008  
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3009  	/* FIXME: R-Car Gen2 has 4byte alignment restriction for tx buffer
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3010  	 * Use two descriptor to handle such situation. First descriptor to
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3011  	 * handle aligned data buffer and second descriptor to handle the
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3012  	 * overflow data because of alignment.
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3013  	 */
c81d894226b944 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3014  	priv->num_tx_desc = info->aligned_tx ? 2 : 1;
f543305da9b5a5 drivers/net/ethernet/renesas/ravb_main.c Kazuya Mizuguchi   2018-09-19  3015  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3016  	/* Set function */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3017  	ndev->netdev_ops = &ravb_netdev_ops;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3018  	ndev->ethtool_ops = &ravb_ethtool_ops;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3019  
f384ab481cab6a drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3020  	error = ravb_compute_gti(ndev);
b3d39a8805c510 drivers/net/ethernet/renesas/ravb_main.c Simon Horman       2015-11-20  3021  	if (error)
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3022  		goto out_rpm_put;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3023  
a6f51f2efa742d drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-10-01  3024  	ravb_parse_delay_mode(np, ndev);
61fccb2d6274f7 drivers/net/ethernet/renesas/ravb_main.c Kazuya Mizuguchi   2017-01-27  3025  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3026  	/* Allocate descriptor base address table */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3027  	priv->desc_bat_size = sizeof(struct ravb_desc) * DBAT_ENTRY_NUM;
e2dbb33ad9545d drivers/net/ethernet/renesas/ravb_main.c Kazuya Mizuguchi   2015-09-30  3028  	priv->desc_bat = dma_alloc_coherent(ndev->dev.parent, priv->desc_bat_size,
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3029  					    &priv->desc_bat_dma, GFP_KERNEL);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3030  	if (!priv->desc_bat) {
c451113291c193 drivers/net/ethernet/renesas/ravb_main.c Simon Horman       2015-11-02  3031  		dev_err(&pdev->dev,
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3032  			"Cannot allocate desc base address table (size %d bytes)\n",
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3033  			priv->desc_bat_size);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3034  		error = -ENOMEM;
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3035  		goto out_rpm_put;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3036  	}
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3037  	for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++)
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3038  		priv->desc_bat[q].die_dt = DT_EOS;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3039  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3040  	/* Initialise HW timestamp list */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3041  	INIT_LIST_HEAD(&priv->ts_skb_list);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3042  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3043  	/* Debug message level */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3044  	priv->msg_enable = RAVB_DEF_MSG_ENABLE;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3045  
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3046  	/* Set config mode as this is needed for PHY initialization. */
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3047  	error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3048  	if (error)
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3049  		goto out_rpm_put;
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3050  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3051  	/* Read and set MAC address */
83216e3988cd19 drivers/net/ethernet/renesas/ravb_main.c Michael Walle      2021-04-12  3052  	ravb_read_mac_address(np, ndev);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3053  	if (!is_valid_ether_addr(ndev->dev_addr)) {
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3054  		dev_warn(&pdev->dev,
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3055  			 "no valid MAC address supplied, using a random one\n");
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3056  		eth_hw_addr_random(ndev);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3057  	}
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3058  
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3059  	/* MDIO bus init */
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3060  	error = ravb_mdio_init(priv);
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3061  	if (error) {
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3062  		dev_err(&pdev->dev, "failed to initialize MDIO\n");
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3063  		goto out_reset_mode;
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3064  	}
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3065  
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3066  	/* Undo previous switch to config opmode. */
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3067  	error = ravb_set_opmode(ndev, CCC_OPC_RESET);
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3068  	if (error)
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3069  		goto out_mdio_release;
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3070  
b48b89f9c189d2 drivers/net/ethernet/renesas/ravb_main.c Jakub Kicinski     2022-09-27  3071  	netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll);
1091da579d7ccd drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-12  3072  	if (info->nc_queues)
b48b89f9c189d2 drivers/net/ethernet/renesas/ravb_main.c Jakub Kicinski     2022-09-27  3073  		netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3074  
65c482bc226ab2 drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04  3075  	if (info->coalesce_irqs) {
7b39c1814ce3bc drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04  3076  		netdev_sw_irq_coalesce_default_on(ndev);
65c482bc226ab2 drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04  3077  		if (num_present_cpus() == 1)
65c482bc226ab2 drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04 @3078  			dev_set_threaded(ndev, true);
65c482bc226ab2 drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04  3079  	}
7b39c1814ce3bc drivers/net/ethernet/renesas/ravb_main.c Paul Barker        2024-06-04  3080  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3081  	/* Network device register */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3082  	error = register_netdev(ndev);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3083  	if (error)
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3084  		goto out_napi_del;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3085  
3e3d647715d401 drivers/net/ethernet/renesas/ravb_main.c Niklas Söderlund   2017-08-01  3086  	device_set_wakeup_capable(&pdev->dev, 1);
3e3d647715d401 drivers/net/ethernet/renesas/ravb_main.c Niklas Söderlund   2017-08-01  3087  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3088  	/* Print device information */
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3089  	netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3090  		    (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3091  
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  3092  	pm_runtime_mark_last_busy(&pdev->dev);
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  3093  	pm_runtime_put_autosuspend(&pdev->dev);
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  3094  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3095  	return 0;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3096  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3097  out_napi_del:
1091da579d7ccd drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-12  3098  	if (info->nc_queues)
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3099  		netif_napi_del(&priv->napi[RAVB_NC]);
a92f4f0662bf2c drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-10-01  3100  
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3101  	netif_napi_del(&priv->napi[RAVB_BE]);
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3102  out_mdio_release:
77972b55fb9d35 drivers/net/ethernet/renesas/ravb_main.c Geert Uytterhoeven 2020-09-22  3103  	ravb_mdio_release(priv);
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3104  out_reset_mode:
76fd52c1007785 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3105  	ravb_set_opmode(ndev, CCC_OPC_RESET);
e2dbb33ad9545d drivers/net/ethernet/renesas/ravb_main.c Kazuya Mizuguchi   2015-09-30  3106  	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3107  			  priv->desc_bat_dma);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3108  out_rpm_put:
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3109  	pm_runtime_put(&pdev->dev);
88b74831faaee4 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  3110  out_rpm_disable:
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3111  	pm_runtime_disable(&pdev->dev);
48f894ab07c444 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-14  3112  	pm_runtime_dont_use_autosuspend(&pdev->dev);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3113  	clk_unprepare(priv->refclk);
a654f6e875b753 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2024-02-02  3114  out_reset_assert:
0d13a1a464a023 drivers/net/ethernet/renesas/ravb_main.c Biju Das           2021-08-25  3115  	reset_control_assert(rstc);
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  3116  out_free_netdev:
d8eb6ea4b302e7 drivers/net/ethernet/renesas/ravb_main.c Claudiu Beznea     2023-11-28  3117  	free_netdev(ndev);
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3118  	return error;
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3119  }
c156633f135326 drivers/net/ethernet/renesas/ravb.c      Sergei Shtylyov    2015-06-11  3120
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net
index ebf21beba846..15d7d36a8294 100644
--- a/Documentation/ABI/testing/sysfs-class-net
+++ b/Documentation/ABI/testing/sysfs-class-net
@@ -343,7 +343,7 @@  Date:		Jan 2021
 KernelVersion:	5.12
 Contact:	netdev@vger.kernel.org
 Description:
-		Boolean value to control the threaded mode per device. User could
+		Integer value to control the threaded mode per device. User could
 		set this value to enable/disable threaded mode for all napi
 		belonging to this device, without the need to do device up/down.
 
@@ -351,4 +351,5 @@  Description:
 		== ==================================
 		0  threaded mode disabled for this dev
 		1  threaded mode enabled for this dev
+		2  threaded mode enabled, and busy polling enabled.
 		== ==================================
diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 785240d60df6..db3bf1eb9a63 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -78,6 +78,10 @@  definitions:
     name: qstats-scope
     type: flags
     entries: [ queue ]
+  -
+    name: napi-threaded
+    type: enum
+    entries: [ disable, enable, busy-poll-enable ]
 
 attribute-sets:
   -
@@ -271,11 +275,11 @@  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.
+             mode. If this is set to `enable` then the NAPI context operates
+             in threaded polling mode. If this is set to `busy-poll-enable`
+             then the NAPI kthread also does busypolling.
         type: u32
-        checks:
-          max: 1
+        enum: napi-threaded
   -
     name: queue
     attributes:
diff --git a/Documentation/networking/napi.rst b/Documentation/networking/napi.rst
index 41926e7a3dd4..edecc21f0bca 100644
--- a/Documentation/networking/napi.rst
+++ b/Documentation/networking/napi.rst
@@ -232,7 +232,9 @@  are not well known).
 Busy polling is enabled by either setting ``SO_BUSY_POLL`` on
 selected sockets or using the global ``net.core.busy_poll`` and
 ``net.core.busy_read`` sysctls. An io_uring API for NAPI busy polling
-also exists.
+also exists. Threaded polling of NAPI also has a mode to busy poll for
+packets (:ref:`threaded busy polling<threaded_busy_poll>`) using the same
+thread that is used for NAPI processing.
 
 epoll-based busy polling
 ------------------------
@@ -395,6 +397,69 @@  Therefore, setting ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` is
 the recommended usage, because otherwise setting ``irq-suspend-timeout``
 might not have any discernible effect.
 
+.. _threaded_busy_poll:
+
+Threaded NAPI busy polling
+--------------------------
+
+Threaded napi allows processing of packets from each NAPI in a kthread in
+kernel. Threaded napi busy polling extends this and adds support to do
+continuous busy polling of this napi. This can be used to enable busy polling
+independent of userspace application or the API (epoll, io_uring, raw sockets)
+being used in userspace to process the packets.
+
+It can be enabled for each NAPI using netlink interface or at device level using
+the threaded NAPI sysctl.
+
+For example, using following script:
+
+.. code-block:: bash
+
+  $ kernel-source/tools/net/ynl/pyynl/cli.py \
+            --spec Documentation/netlink/specs/netdev.yaml \
+            --do napi-set \
+            --json='{"id": 66,
+                     "threaded": "busy-poll-enable"}'
+
+
+Enabling it for each NAPI allows finer control to enable busy pollling for
+only a set of NIC queues which will get traffic with low latency requirements.
+
+Depending on application requirement, user might want to set affinity of the
+kthread that is busy polling each NAPI. User might also want to set priority
+and the scheduler of the thread depending on the latency requirements.
+
+For a hard low-latency application, user might want to dedicate the full core
+for the NAPI polling so the NIC queue descriptors are picked up from the queue
+as soon as they appear. For more relaxed low-latency requirement, user might
+want to share the core with other threads.
+
+Once threaded busy polling is enabled for a NAPI, PID of the kthread can be
+fetched using netlink interface so the affinity, priority and scheduler
+configuration can be done.
+
+For example, following script can be used to fetch the pid:
+
+.. code-block:: bash
+
+  $ kernel-source/tools/net/ynl/pyynl/cli.py \
+            --spec Documentation/netlink/specs/netdev.yaml \
+            --do napi-get \
+            --json='{"id": 66}'
+
+This will output something like following, the pid `258` is the PID of the
+kthread that is polling this NAPI.
+
+.. code-block:: bash
+
+  $ {'defer-hard-irqs': 0,
+     'gro-flush-timeout': 0,
+     'id': 66,
+     'ifindex': 2,
+     'irq-suspend-timeout': 0,
+     'pid': 258,
+     'threaded': 'enable'}
+
 .. _threaded:
 
 Threaded NAPI
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index c571614b1d50..513328476770 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -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;
-	dev_set_threaded(netdev, true);
+	dev_set_threaded(netdev, NETDEV_NAPI_THREADED_ENABLE);
 	for (i = 0; i < adapter->rx_queue_count; ++i)
 		netif_napi_add(netdev, &adapter->rrd_ring[i].napi,
 			       atl1c_clean_rx);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6afba24b18d1..9d6bb0d719b3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -352,7 +352,7 @@  struct napi_config {
 	u64 gro_flush_timeout;
 	u64 irq_suspend_timeout;
 	u32 defer_hard_irqs;
-	bool threaded;
+	u8 threaded;
 	unsigned int napi_id;
 };
 
@@ -410,6 +410,8 @@  enum {
 	NAPI_STATE_PREFER_BUSY_POLL,	/* prefer busy-polling over softirq processing*/
 	NAPI_STATE_THREADED,		/* The poll is performed inside its own thread*/
 	NAPI_STATE_SCHED_THREADED,	/* Napi is currently scheduled in threaded mode */
+	NAPI_STATE_THREADED_BUSY_POLL,	/* The threaded napi poller will busy poll */
+	NAPI_STATE_SCHED_THREADED_BUSY_POLL,  /* The threaded napi poller is busy polling */
 };
 
 enum {
@@ -423,8 +425,14 @@  enum {
 	NAPIF_STATE_PREFER_BUSY_POLL	= BIT(NAPI_STATE_PREFER_BUSY_POLL),
 	NAPIF_STATE_THREADED		= BIT(NAPI_STATE_THREADED),
 	NAPIF_STATE_SCHED_THREADED	= BIT(NAPI_STATE_SCHED_THREADED),
+	NAPIF_STATE_THREADED_BUSY_POLL	= BIT(NAPI_STATE_THREADED_BUSY_POLL),
+	NAPIF_STATE_SCHED_THREADED_BUSY_POLL
+				= BIT(NAPI_STATE_SCHED_THREADED_BUSY_POLL),
 };
 
+#define NAPIF_STATE_THREADED_BUSY_POLL_MASK \
+	(NAPIF_STATE_THREADED | NAPIF_STATE_THREADED_BUSY_POLL)
+
 enum gro_result {
 	GRO_MERGED,
 	GRO_MERGED_FREE,
@@ -571,16 +579,18 @@  static inline bool napi_complete(struct napi_struct *n)
 	return napi_complete_done(n, 0);
 }
 
-int dev_set_threaded(struct net_device *dev, bool threaded);
+int dev_set_threaded(struct net_device *dev,
+		     enum netdev_napi_threaded threaded);
 
 /*
  * napi_set_threaded - set napi threaded state
  * @napi: NAPI context
- * @threaded: whether this napi does threaded polling
+ * @threaded: threading mode
  *
  * Return 0 on success and negative errno on failure.
  */
-int napi_set_threaded(struct napi_struct *napi, bool threaded);
+int napi_set_threaded(struct napi_struct *napi,
+		      enum netdev_napi_threaded threaded);
 
 void napi_disable(struct napi_struct *n);
 void napi_disable_locked(struct napi_struct *n);
@@ -2404,7 +2414,7 @@  struct net_device {
 	struct sfp_bus		*sfp_bus;
 	struct lock_class_key	*qdisc_tx_busylock;
 	bool			proto_down;
-	bool			threaded;
+	u8			threaded;
 
 	/* priv_flags_slow, ungrouped to save space */
 	unsigned long		see_all_hwtstamp_requests:1;
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 829648b2ef65..c2a9dbb361f6 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -74,6 +74,12 @@  enum netdev_qstats_scope {
 	NETDEV_QSTATS_SCOPE_QUEUE = 1,
 };
 
+enum netdev_napi_threaded {
+	NETDEV_NAPI_THREADED_DISABLE,
+	NETDEV_NAPI_THREADED_ENABLE,
+	NETDEV_NAPI_THREADED_BUSY_POLL_ENABLE,
+};
+
 enum {
 	NETDEV_A_DEV_IFINDEX = 1,
 	NETDEV_A_DEV_PAD,
diff --git a/net/core/dev.c b/net/core/dev.c
index 484947ad5410..8a5fde81f0b8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -78,6 +78,7 @@ 
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/sched/isolation.h>
+#include <linux/sched/types.h>
 #include <linux/sched/mm.h>
 #include <linux/smpboot.h>
 #include <linux/mutex.h>
@@ -6403,7 +6404,8 @@  bool napi_complete_done(struct napi_struct *n, int work_done)
 	 *    the guarantee we will be called later.
 	 */
 	if (unlikely(n->state & (NAPIF_STATE_NPSVC |
-				 NAPIF_STATE_IN_BUSY_POLL)))
+				 NAPIF_STATE_IN_BUSY_POLL |
+				 NAPIF_STATE_SCHED_THREADED_BUSY_POLL)))
 		return false;
 
 	if (work_done) {
@@ -6792,8 +6794,10 @@  static void init_gro_hash(struct napi_struct *napi)
 	napi->gro_bitmask = 0;
 }
 
-int napi_set_threaded(struct napi_struct *napi, bool threaded)
+int napi_set_threaded(struct napi_struct *napi,
+		      enum netdev_napi_threaded threaded)
 {
+	unsigned long val;
 	if (napi->dev->threaded)
 		return -EINVAL;
 
@@ -6811,14 +6815,20 @@  int napi_set_threaded(struct napi_struct *napi, bool threaded)
 
 	/* Make sure kthread is created before THREADED bit is set. */
 	smp_mb__before_atomic();
-	assign_bit(NAPI_STATE_THREADED, &napi->state, threaded);
+	val = 0;
+	if (threaded == NETDEV_NAPI_THREADED_BUSY_POLL_ENABLE)
+		val |= NAPIF_STATE_THREADED_BUSY_POLL;
+	if (threaded)
+		val |= NAPIF_STATE_THREADED;
+	set_mask_bits(&napi->state, NAPIF_STATE_THREADED_BUSY_POLL_MASK, val);
 
 	return 0;
 }
 
-int dev_set_threaded(struct net_device *dev, bool threaded)
+int dev_set_threaded(struct net_device *dev, enum netdev_napi_threaded threaded)
 {
 	struct napi_struct *napi;
+	unsigned long val;
 	int err = 0;
 
 	netdev_assert_locked_or_invisible(dev);
@@ -6826,17 +6836,22 @@  int dev_set_threaded(struct net_device *dev, bool threaded)
 	if (dev->threaded == threaded)
 		return 0;
 
+	val = 0;
 	if (threaded) {
 		/* Check if threaded is set at napi level already */
 		list_for_each_entry(napi, &dev->napi_list, dev_list)
 			if (test_bit(NAPI_STATE_THREADED, &napi->state))
 				return -EINVAL;
 
+		val |= NAPIF_STATE_THREADED;
+		if (threaded == NETDEV_NAPI_THREADED_BUSY_POLL_ENABLE)
+			val |= NAPIF_STATE_THREADED_BUSY_POLL;
+
 		list_for_each_entry(napi, &dev->napi_list, dev_list) {
 			if (!napi->thread) {
 				err = napi_kthread_create(napi);
 				if (err) {
-					threaded = false;
+					threaded = NETDEV_NAPI_THREADED_DISABLE;
 					break;
 				}
 			}
@@ -6855,9 +6870,13 @@  int dev_set_threaded(struct net_device *dev, bool threaded)
 	 * polled. In this case, the switch between threaded mode and
 	 * softirq mode will happen in the next round of napi_schedule().
 	 * This should not cause hiccups/stalls to the live traffic.
+	 *
+	 * Switch to busy_poll threaded napi will occur after the threaded
+	 * napi is scheduled.
 	 */
 	list_for_each_entry(napi, &dev->napi_list, dev_list)
-		assign_bit(NAPI_STATE_THREADED, &napi->state, threaded);
+		set_mask_bits(&napi->state,
+			      NAPIF_STATE_THREADED_BUSY_POLL_MASK, val);
 
 	return err;
 }
@@ -7235,7 +7254,7 @@  static int napi_thread_wait(struct napi_struct *napi)
 	return -1;
 }
 
-static void napi_threaded_poll_loop(struct napi_struct *napi)
+static void napi_threaded_poll_loop(struct napi_struct *napi, bool busy_poll)
 {
 	struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
 	struct softnet_data *sd;
@@ -7264,22 +7283,53 @@  static void napi_threaded_poll_loop(struct napi_struct *napi)
 		}
 		skb_defer_free_flush(sd);
 		bpf_net_ctx_clear(bpf_net_ctx);
+
+		/* Push the skbs up the stack if busy polling. */
+		if (busy_poll)
+			__napi_gro_flush_helper(napi);
 		local_bh_enable();
 
-		if (!repoll)
+		/* If busy polling then do not break here because we need to
+		 * call cond_resched and rcu_softirq_qs_periodic to prevent
+		 * watchdog warnings.
+		 */
+		if (!repoll && !busy_poll)
 			break;
 
 		rcu_softirq_qs_periodic(last_qs);
 		cond_resched();
+
+		if (!repoll)
+			break;
 	}
 }
 
 static int napi_threaded_poll(void *data)
 {
 	struct napi_struct *napi = data;
+	bool busy_poll_sched;
+	unsigned long val;
+	bool busy_poll;
+
+	while (!napi_thread_wait(napi)) {
+		/* Once woken up, this means that we are scheduled as threaded
+		 * napi and this thread owns the napi context, if busy poll
+		 * state is set then we busy poll this napi.
+		 */
+		val = READ_ONCE(napi->state);
+		busy_poll = val & NAPIF_STATE_THREADED_BUSY_POLL;
+		busy_poll_sched = val & NAPIF_STATE_SCHED_THREADED_BUSY_POLL;
+
+		/* Do not busy poll if napi is disabled. */
+		if (unlikely(val & NAPIF_STATE_DISABLE))
+			busy_poll = false;
+
+		if (busy_poll != busy_poll_sched)
+			assign_bit(NAPI_STATE_SCHED_THREADED_BUSY_POLL,
+				   &napi->state, busy_poll);
 
-	while (!napi_thread_wait(napi))
-		napi_threaded_poll_loop(napi);
+		napi_threaded_poll_loop(napi, busy_poll);
+	}
 
 	return 0;
 }
@@ -12497,7 +12547,7 @@  static void run_backlog_napi(unsigned int cpu)
 {
 	struct softnet_data *sd = per_cpu_ptr(&softnet_data, cpu);
 
-	napi_threaded_poll_loop(&sd->backlog);
+	napi_threaded_poll_loop(&sd->backlog, false);
 }
 
 static void backlog_napi_setup(unsigned int cpu)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 07cb99b114bd..beb496bcb633 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -657,7 +657,7 @@  static int modify_napi_threaded(struct net_device *dev, unsigned long val)
 	if (list_empty(&dev->napi_list))
 		return -EOPNOTSUPP;
 
-	if (val != 0 && val != 1)
+	if (val > NETDEV_NAPI_THREADED_BUSY_POLL_ENABLE)
 		return -EOPNOTSUPP;
 
 	ret = dev_set_threaded(dev, val);
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index a1f80e687f53..b572beba42e7 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -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_U32, 1),
+	[NETDEV_A_NAPI_THREADED] = NLA_POLICY_MAX(NLA_U32, 2),
 };
 
 /* Ops table for netdev */
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index 208c3dd768ec..7ae5f3ed0961 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -329,7 +329,7 @@  netdev_nl_napi_set_config(struct napi_struct *napi, struct genl_info *info)
 
 	if (info->attrs[NETDEV_A_NAPI_THREADED]) {
 		threaded = nla_get_u32(info->attrs[NETDEV_A_NAPI_THREADED]);
-		napi_set_threaded(napi, !!threaded);
+		napi_set_threaded(napi, threaded);
 	}
 
 	if (info->attrs[NETDEV_A_NAPI_DEFER_HARD_IRQS]) {
diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index 829648b2ef65..c2a9dbb361f6 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -74,6 +74,12 @@  enum netdev_qstats_scope {
 	NETDEV_QSTATS_SCOPE_QUEUE = 1,
 };
 
+enum netdev_napi_threaded {
+	NETDEV_NAPI_THREADED_DISABLE,
+	NETDEV_NAPI_THREADED_ENABLE,
+	NETDEV_NAPI_THREADED_BUSY_POLL_ENABLE,
+};
+
 enum {
 	NETDEV_A_DEV_IFINDEX = 1,
 	NETDEV_A_DEV_PAD,