18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/****************************************************************************
38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards
48c2ecf20Sopenharmony_ci * Copyright 2018 Solarflare Communications Inc.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License version 2 as published
88c2ecf20Sopenharmony_ci * by the Free Software Foundation, incorporated herein by reference.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "net_driver.h"
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include "efx_channels.h"
148c2ecf20Sopenharmony_ci#include "efx.h"
158c2ecf20Sopenharmony_ci#include "efx_common.h"
168c2ecf20Sopenharmony_ci#include "tx_common.h"
178c2ecf20Sopenharmony_ci#include "rx_common.h"
188c2ecf20Sopenharmony_ci#include "nic.h"
198c2ecf20Sopenharmony_ci#include "sriov.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* This is the first interrupt mode to try out of:
228c2ecf20Sopenharmony_ci * 0 => MSI-X
238c2ecf20Sopenharmony_ci * 1 => MSI
248c2ecf20Sopenharmony_ci * 2 => legacy
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ciunsigned int efx_interrupt_mode = EFX_INT_MODE_MSIX;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
298c2ecf20Sopenharmony_ci * i.e. the number of CPUs among which we may distribute simultaneous
308c2ecf20Sopenharmony_ci * interrupt handling.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
338c2ecf20Sopenharmony_ci * The default (0) means to assign an interrupt to each core.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ciunsigned int rss_cpus;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic unsigned int irq_adapt_low_thresh = 8000;
388c2ecf20Sopenharmony_cimodule_param(irq_adapt_low_thresh, uint, 0644);
398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq_adapt_low_thresh,
408c2ecf20Sopenharmony_ci		 "Threshold score for reducing IRQ moderation");
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic unsigned int irq_adapt_high_thresh = 16000;
438c2ecf20Sopenharmony_cimodule_param(irq_adapt_high_thresh, uint, 0644);
448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq_adapt_high_thresh,
458c2ecf20Sopenharmony_ci		 "Threshold score for increasing IRQ moderation");
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* This is the weight assigned to each of the (per-channel) virtual
488c2ecf20Sopenharmony_ci * NAPI devices.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic int napi_weight = 64;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/***************
538c2ecf20Sopenharmony_ci * Housekeeping
548c2ecf20Sopenharmony_ci ***************/
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint efx_channel_dummy_op_int(struct efx_channel *channel)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid efx_channel_dummy_op_void(struct efx_channel *channel)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const struct efx_channel_type efx_default_channel_type = {
668c2ecf20Sopenharmony_ci	.pre_probe		= efx_channel_dummy_op_int,
678c2ecf20Sopenharmony_ci	.post_remove		= efx_channel_dummy_op_void,
688c2ecf20Sopenharmony_ci	.get_name		= efx_get_channel_name,
698c2ecf20Sopenharmony_ci	.copy			= efx_copy_channel,
708c2ecf20Sopenharmony_ci	.want_txqs		= efx_default_channel_want_txqs,
718c2ecf20Sopenharmony_ci	.keep_eventq		= false,
728c2ecf20Sopenharmony_ci	.want_pio		= true,
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/*************
768c2ecf20Sopenharmony_ci * INTERRUPTS
778c2ecf20Sopenharmony_ci *************/
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic unsigned int efx_wanted_parallelism(struct efx_nic *efx)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	cpumask_var_t thread_mask;
828c2ecf20Sopenharmony_ci	unsigned int count;
838c2ecf20Sopenharmony_ci	int cpu;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (rss_cpus) {
868c2ecf20Sopenharmony_ci		count = rss_cpus;
878c2ecf20Sopenharmony_ci	} else {
888c2ecf20Sopenharmony_ci		if (unlikely(!zalloc_cpumask_var(&thread_mask, GFP_KERNEL))) {
898c2ecf20Sopenharmony_ci			netif_warn(efx, probe, efx->net_dev,
908c2ecf20Sopenharmony_ci				   "RSS disabled due to allocation failure\n");
918c2ecf20Sopenharmony_ci			return 1;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		count = 0;
958c2ecf20Sopenharmony_ci		for_each_online_cpu(cpu) {
968c2ecf20Sopenharmony_ci			if (!cpumask_test_cpu(cpu, thread_mask)) {
978c2ecf20Sopenharmony_ci				++count;
988c2ecf20Sopenharmony_ci				cpumask_or(thread_mask, thread_mask,
998c2ecf20Sopenharmony_ci					   topology_sibling_cpumask(cpu));
1008c2ecf20Sopenharmony_ci			}
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		free_cpumask_var(thread_mask);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (count > EFX_MAX_RX_QUEUES) {
1078c2ecf20Sopenharmony_ci		netif_cond_dbg(efx, probe, efx->net_dev, !rss_cpus, warn,
1088c2ecf20Sopenharmony_ci			       "Reducing number of rx queues from %u to %u.\n",
1098c2ecf20Sopenharmony_ci			       count, EFX_MAX_RX_QUEUES);
1108c2ecf20Sopenharmony_ci		count = EFX_MAX_RX_QUEUES;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* If RSS is requested for the PF *and* VFs then we can't write RSS
1148c2ecf20Sopenharmony_ci	 * table entries that are inaccessible to VFs
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_SRIOV
1178c2ecf20Sopenharmony_ci	if (efx->type->sriov_wanted) {
1188c2ecf20Sopenharmony_ci		if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
1198c2ecf20Sopenharmony_ci		    count > efx_vf_size(efx)) {
1208c2ecf20Sopenharmony_ci			netif_warn(efx, probe, efx->net_dev,
1218c2ecf20Sopenharmony_ci				   "Reducing number of RSS channels from %u to %u for "
1228c2ecf20Sopenharmony_ci				   "VF support. Increase vf-msix-limit to use more "
1238c2ecf20Sopenharmony_ci				   "channels on the PF.\n",
1248c2ecf20Sopenharmony_ci				   count, efx_vf_size(efx));
1258c2ecf20Sopenharmony_ci			count = efx_vf_size(efx);
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci#endif
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return count;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int efx_allocate_msix_channels(struct efx_nic *efx,
1348c2ecf20Sopenharmony_ci				      unsigned int max_channels,
1358c2ecf20Sopenharmony_ci				      unsigned int extra_channels,
1368c2ecf20Sopenharmony_ci				      unsigned int parallelism)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	unsigned int n_channels = parallelism;
1398c2ecf20Sopenharmony_ci	int vec_count;
1408c2ecf20Sopenharmony_ci	int n_xdp_tx;
1418c2ecf20Sopenharmony_ci	int n_xdp_ev;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (efx_separate_tx_channels)
1448c2ecf20Sopenharmony_ci		n_channels *= 2;
1458c2ecf20Sopenharmony_ci	n_channels += extra_channels;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* To allow XDP transmit to happen from arbitrary NAPI contexts
1488c2ecf20Sopenharmony_ci	 * we allocate a TX queue per CPU. We share event queues across
1498c2ecf20Sopenharmony_ci	 * multiple tx queues, assuming tx and ev queues are both
1508c2ecf20Sopenharmony_ci	 * maximum size.
1518c2ecf20Sopenharmony_ci	 */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	n_xdp_tx = num_possible_cpus();
1548c2ecf20Sopenharmony_ci	n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, EFX_MAX_TXQ_PER_CHANNEL);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	vec_count = pci_msix_vec_count(efx->pci_dev);
1578c2ecf20Sopenharmony_ci	if (vec_count < 0)
1588c2ecf20Sopenharmony_ci		return vec_count;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	max_channels = min_t(unsigned int, vec_count, max_channels);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Check resources.
1638c2ecf20Sopenharmony_ci	 * We need a channel per event queue, plus a VI per tx queue.
1648c2ecf20Sopenharmony_ci	 * This may be more pessimistic than it needs to be.
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci	if (n_channels + n_xdp_ev > max_channels) {
1678c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
1688c2ecf20Sopenharmony_ci			  "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n",
1698c2ecf20Sopenharmony_ci			  n_xdp_ev, n_channels, max_channels);
1708c2ecf20Sopenharmony_ci		efx->n_xdp_channels = 0;
1718c2ecf20Sopenharmony_ci		efx->xdp_tx_per_channel = 0;
1728c2ecf20Sopenharmony_ci		efx->xdp_tx_queue_count = 0;
1738c2ecf20Sopenharmony_ci	} else if (n_channels + n_xdp_tx > efx->max_vis) {
1748c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
1758c2ecf20Sopenharmony_ci			  "Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n",
1768c2ecf20Sopenharmony_ci			  n_xdp_tx, n_channels, efx->max_vis);
1778c2ecf20Sopenharmony_ci		efx->n_xdp_channels = 0;
1788c2ecf20Sopenharmony_ci		efx->xdp_tx_per_channel = 0;
1798c2ecf20Sopenharmony_ci		efx->xdp_tx_queue_count = 0;
1808c2ecf20Sopenharmony_ci	} else {
1818c2ecf20Sopenharmony_ci		efx->n_xdp_channels = n_xdp_ev;
1828c2ecf20Sopenharmony_ci		efx->xdp_tx_per_channel = EFX_MAX_TXQ_PER_CHANNEL;
1838c2ecf20Sopenharmony_ci		efx->xdp_tx_queue_count = n_xdp_tx;
1848c2ecf20Sopenharmony_ci		n_channels += n_xdp_ev;
1858c2ecf20Sopenharmony_ci		netif_dbg(efx, drv, efx->net_dev,
1868c2ecf20Sopenharmony_ci			  "Allocating %d TX and %d event queues for XDP\n",
1878c2ecf20Sopenharmony_ci			  n_xdp_tx, n_xdp_ev);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (vec_count < n_channels) {
1918c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
1928c2ecf20Sopenharmony_ci			  "WARNING: Insufficient MSI-X vectors available (%d < %u).\n",
1938c2ecf20Sopenharmony_ci			  vec_count, n_channels);
1948c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
1958c2ecf20Sopenharmony_ci			  "WARNING: Performance may be reduced.\n");
1968c2ecf20Sopenharmony_ci		n_channels = vec_count;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	n_channels = min(n_channels, max_channels);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	efx->n_channels = n_channels;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Ignore XDP tx channels when creating rx channels. */
2048c2ecf20Sopenharmony_ci	n_channels -= efx->n_xdp_channels;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (efx_separate_tx_channels) {
2078c2ecf20Sopenharmony_ci		efx->n_tx_channels =
2088c2ecf20Sopenharmony_ci			min(max(n_channels / 2, 1U),
2098c2ecf20Sopenharmony_ci			    efx->max_tx_channels);
2108c2ecf20Sopenharmony_ci		efx->tx_channel_offset =
2118c2ecf20Sopenharmony_ci			n_channels - efx->n_tx_channels;
2128c2ecf20Sopenharmony_ci		efx->n_rx_channels =
2138c2ecf20Sopenharmony_ci			max(n_channels -
2148c2ecf20Sopenharmony_ci			    efx->n_tx_channels, 1U);
2158c2ecf20Sopenharmony_ci	} else {
2168c2ecf20Sopenharmony_ci		efx->n_tx_channels = min(n_channels, efx->max_tx_channels);
2178c2ecf20Sopenharmony_ci		efx->tx_channel_offset = 0;
2188c2ecf20Sopenharmony_ci		efx->n_rx_channels = n_channels;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	efx->n_rx_channels = min(efx->n_rx_channels, parallelism);
2228c2ecf20Sopenharmony_ci	efx->n_tx_channels = min(efx->n_tx_channels, parallelism);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	efx->xdp_channel_offset = n_channels;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev,
2278c2ecf20Sopenharmony_ci		  "Allocating %u RX channels\n",
2288c2ecf20Sopenharmony_ci		  efx->n_rx_channels);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return efx->n_channels;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* Probe the number and type of interrupts we are able to obtain, and
2348c2ecf20Sopenharmony_ci * the resulting numbers of channels and RX queues.
2358c2ecf20Sopenharmony_ci */
2368c2ecf20Sopenharmony_ciint efx_probe_interrupts(struct efx_nic *efx)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	unsigned int extra_channels = 0;
2398c2ecf20Sopenharmony_ci	unsigned int rss_spread;
2408c2ecf20Sopenharmony_ci	unsigned int i, j;
2418c2ecf20Sopenharmony_ci	int rc;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++)
2448c2ecf20Sopenharmony_ci		if (efx->extra_channel_type[i])
2458c2ecf20Sopenharmony_ci			++extra_channels;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
2488c2ecf20Sopenharmony_ci		unsigned int parallelism = efx_wanted_parallelism(efx);
2498c2ecf20Sopenharmony_ci		struct msix_entry xentries[EFX_MAX_CHANNELS];
2508c2ecf20Sopenharmony_ci		unsigned int n_channels;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		rc = efx_allocate_msix_channels(efx, efx->max_channels,
2538c2ecf20Sopenharmony_ci						extra_channels, parallelism);
2548c2ecf20Sopenharmony_ci		if (rc >= 0) {
2558c2ecf20Sopenharmony_ci			n_channels = rc;
2568c2ecf20Sopenharmony_ci			for (i = 0; i < n_channels; i++)
2578c2ecf20Sopenharmony_ci				xentries[i].entry = i;
2588c2ecf20Sopenharmony_ci			rc = pci_enable_msix_range(efx->pci_dev, xentries, 1,
2598c2ecf20Sopenharmony_ci						   n_channels);
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci		if (rc < 0) {
2628c2ecf20Sopenharmony_ci			/* Fall back to single channel MSI */
2638c2ecf20Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
2648c2ecf20Sopenharmony_ci				  "could not enable MSI-X\n");
2658c2ecf20Sopenharmony_ci			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_MSI)
2668c2ecf20Sopenharmony_ci				efx->interrupt_mode = EFX_INT_MODE_MSI;
2678c2ecf20Sopenharmony_ci			else
2688c2ecf20Sopenharmony_ci				return rc;
2698c2ecf20Sopenharmony_ci		} else if (rc < n_channels) {
2708c2ecf20Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
2718c2ecf20Sopenharmony_ci				  "WARNING: Insufficient MSI-X vectors"
2728c2ecf20Sopenharmony_ci				  " available (%d < %u).\n", rc, n_channels);
2738c2ecf20Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
2748c2ecf20Sopenharmony_ci				  "WARNING: Performance may be reduced.\n");
2758c2ecf20Sopenharmony_ci			n_channels = rc;
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (rc > 0) {
2798c2ecf20Sopenharmony_ci			for (i = 0; i < efx->n_channels; i++)
2808c2ecf20Sopenharmony_ci				efx_get_channel(efx, i)->irq =
2818c2ecf20Sopenharmony_ci					xentries[i].vector;
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Try single interrupt MSI */
2868c2ecf20Sopenharmony_ci	if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
2878c2ecf20Sopenharmony_ci		efx->n_channels = 1;
2888c2ecf20Sopenharmony_ci		efx->n_rx_channels = 1;
2898c2ecf20Sopenharmony_ci		efx->n_tx_channels = 1;
2908c2ecf20Sopenharmony_ci		efx->tx_channel_offset = 0;
2918c2ecf20Sopenharmony_ci		efx->n_xdp_channels = 0;
2928c2ecf20Sopenharmony_ci		efx->xdp_channel_offset = efx->n_channels;
2938c2ecf20Sopenharmony_ci		rc = pci_enable_msi(efx->pci_dev);
2948c2ecf20Sopenharmony_ci		if (rc == 0) {
2958c2ecf20Sopenharmony_ci			efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
2968c2ecf20Sopenharmony_ci		} else {
2978c2ecf20Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
2988c2ecf20Sopenharmony_ci				  "could not enable MSI\n");
2998c2ecf20Sopenharmony_ci			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_LEGACY)
3008c2ecf20Sopenharmony_ci				efx->interrupt_mode = EFX_INT_MODE_LEGACY;
3018c2ecf20Sopenharmony_ci			else
3028c2ecf20Sopenharmony_ci				return rc;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* Assume legacy interrupts */
3078c2ecf20Sopenharmony_ci	if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
3088c2ecf20Sopenharmony_ci		efx->n_channels = 1 + (efx_separate_tx_channels ? 1 : 0);
3098c2ecf20Sopenharmony_ci		efx->n_rx_channels = 1;
3108c2ecf20Sopenharmony_ci		efx->n_tx_channels = 1;
3118c2ecf20Sopenharmony_ci		efx->tx_channel_offset = efx_separate_tx_channels ? 1 : 0;
3128c2ecf20Sopenharmony_ci		efx->n_xdp_channels = 0;
3138c2ecf20Sopenharmony_ci		efx->xdp_channel_offset = efx->n_channels;
3148c2ecf20Sopenharmony_ci		efx->legacy_irq = efx->pci_dev->irq;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Assign extra channels if possible, before XDP channels */
3188c2ecf20Sopenharmony_ci	efx->n_extra_tx_channels = 0;
3198c2ecf20Sopenharmony_ci	j = efx->xdp_channel_offset;
3208c2ecf20Sopenharmony_ci	for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
3218c2ecf20Sopenharmony_ci		if (!efx->extra_channel_type[i])
3228c2ecf20Sopenharmony_ci			continue;
3238c2ecf20Sopenharmony_ci		if (j <= efx->tx_channel_offset + efx->n_tx_channels) {
3248c2ecf20Sopenharmony_ci			efx->extra_channel_type[i]->handle_no_channel(efx);
3258c2ecf20Sopenharmony_ci		} else {
3268c2ecf20Sopenharmony_ci			--j;
3278c2ecf20Sopenharmony_ci			efx_get_channel(efx, j)->type =
3288c2ecf20Sopenharmony_ci				efx->extra_channel_type[i];
3298c2ecf20Sopenharmony_ci			if (efx_channel_has_tx_queues(efx_get_channel(efx, j)))
3308c2ecf20Sopenharmony_ci				efx->n_extra_tx_channels++;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	rss_spread = efx->n_rx_channels;
3358c2ecf20Sopenharmony_ci	/* RSS might be usable on VFs even if it is disabled on the PF */
3368c2ecf20Sopenharmony_ci#ifdef CONFIG_SFC_SRIOV
3378c2ecf20Sopenharmony_ci	if (efx->type->sriov_wanted) {
3388c2ecf20Sopenharmony_ci		efx->rss_spread = ((rss_spread > 1 ||
3398c2ecf20Sopenharmony_ci				    !efx->type->sriov_wanted(efx)) ?
3408c2ecf20Sopenharmony_ci				   rss_spread : efx_vf_size(efx));
3418c2ecf20Sopenharmony_ci		return 0;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci#endif
3448c2ecf20Sopenharmony_ci	efx->rss_spread = rss_spread;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP)
3508c2ecf20Sopenharmony_civoid efx_set_interrupt_affinity(struct efx_nic *efx)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct efx_channel *channel;
3538c2ecf20Sopenharmony_ci	unsigned int cpu;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
3568c2ecf20Sopenharmony_ci		cpu = cpumask_local_spread(channel->channel,
3578c2ecf20Sopenharmony_ci					   pcibus_to_node(efx->pci_dev->bus));
3588c2ecf20Sopenharmony_ci		irq_set_affinity_hint(channel->irq, cpumask_of(cpu));
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_civoid efx_clear_interrupt_affinity(struct efx_nic *efx)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	struct efx_channel *channel;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
3678c2ecf20Sopenharmony_ci		irq_set_affinity_hint(channel->irq, NULL);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci#else
3708c2ecf20Sopenharmony_civoid
3718c2ecf20Sopenharmony_ciefx_set_interrupt_affinity(struct efx_nic *efx __attribute__ ((unused)))
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_civoid
3768c2ecf20Sopenharmony_ciefx_clear_interrupt_affinity(struct efx_nic *efx __attribute__ ((unused)))
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_civoid efx_remove_interrupts(struct efx_nic *efx)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct efx_channel *channel;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* Remove MSI/MSI-X interrupts */
3868c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
3878c2ecf20Sopenharmony_ci		channel->irq = 0;
3888c2ecf20Sopenharmony_ci	pci_disable_msi(efx->pci_dev);
3898c2ecf20Sopenharmony_ci	pci_disable_msix(efx->pci_dev);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* Remove legacy interrupt */
3928c2ecf20Sopenharmony_ci	efx->legacy_irq = 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/***************
3968c2ecf20Sopenharmony_ci * EVENT QUEUES
3978c2ecf20Sopenharmony_ci ***************/
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/* Create event queue
4008c2ecf20Sopenharmony_ci * Event queue memory allocations are done only once.  If the channel
4018c2ecf20Sopenharmony_ci * is reset, the memory buffer will be reused; this guards against
4028c2ecf20Sopenharmony_ci * errors during channel reset and also simplifies interrupt handling.
4038c2ecf20Sopenharmony_ci */
4048c2ecf20Sopenharmony_ciint efx_probe_eventq(struct efx_channel *channel)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct efx_nic *efx = channel->efx;
4078c2ecf20Sopenharmony_ci	unsigned long entries;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev,
4108c2ecf20Sopenharmony_ci		  "chan %d create event queue\n", channel->channel);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Build an event queue with room for one event per tx and rx buffer,
4138c2ecf20Sopenharmony_ci	 * plus some extra for link state events and MCDI completions.
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128);
4168c2ecf20Sopenharmony_ci	EFX_WARN_ON_PARANOID(entries > EFX_MAX_EVQ_SIZE);
4178c2ecf20Sopenharmony_ci	channel->eventq_mask = max(entries, EFX_MIN_EVQ_SIZE) - 1;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return efx_nic_probe_eventq(channel);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci/* Prepare channel's event queue */
4238c2ecf20Sopenharmony_ciint efx_init_eventq(struct efx_channel *channel)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct efx_nic *efx = channel->efx;
4268c2ecf20Sopenharmony_ci	int rc;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	EFX_WARN_ON_PARANOID(channel->eventq_init);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev,
4318c2ecf20Sopenharmony_ci		  "chan %d init event queue\n", channel->channel);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	rc = efx_nic_init_eventq(channel);
4348c2ecf20Sopenharmony_ci	if (rc == 0) {
4358c2ecf20Sopenharmony_ci		efx->type->push_irq_moderation(channel);
4368c2ecf20Sopenharmony_ci		channel->eventq_read_ptr = 0;
4378c2ecf20Sopenharmony_ci		channel->eventq_init = true;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci	return rc;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/* Enable event queue processing and NAPI */
4438c2ecf20Sopenharmony_civoid efx_start_eventq(struct efx_channel *channel)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	netif_dbg(channel->efx, ifup, channel->efx->net_dev,
4468c2ecf20Sopenharmony_ci		  "chan %d start event queue\n", channel->channel);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Make sure the NAPI handler sees the enabled flag set */
4498c2ecf20Sopenharmony_ci	channel->enabled = true;
4508c2ecf20Sopenharmony_ci	smp_wmb();
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	napi_enable(&channel->napi_str);
4538c2ecf20Sopenharmony_ci	efx_nic_eventq_read_ack(channel);
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci/* Disable event queue processing and NAPI */
4578c2ecf20Sopenharmony_civoid efx_stop_eventq(struct efx_channel *channel)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	if (!channel->enabled)
4608c2ecf20Sopenharmony_ci		return;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	napi_disable(&channel->napi_str);
4638c2ecf20Sopenharmony_ci	channel->enabled = false;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_civoid efx_fini_eventq(struct efx_channel *channel)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	if (!channel->eventq_init)
4698c2ecf20Sopenharmony_ci		return;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	netif_dbg(channel->efx, drv, channel->efx->net_dev,
4728c2ecf20Sopenharmony_ci		  "chan %d fini event queue\n", channel->channel);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	efx_nic_fini_eventq(channel);
4758c2ecf20Sopenharmony_ci	channel->eventq_init = false;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_civoid efx_remove_eventq(struct efx_channel *channel)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	netif_dbg(channel->efx, drv, channel->efx->net_dev,
4818c2ecf20Sopenharmony_ci		  "chan %d remove event queue\n", channel->channel);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	efx_nic_remove_eventq(channel);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci/**************************************************************************
4878c2ecf20Sopenharmony_ci *
4888c2ecf20Sopenharmony_ci * Channel handling
4898c2ecf20Sopenharmony_ci *
4908c2ecf20Sopenharmony_ci *************************************************************************/
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
4938c2ecf20Sopenharmony_cistatic void efx_filter_rfs_expire(struct work_struct *data)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	struct delayed_work *dwork = to_delayed_work(data);
4968c2ecf20Sopenharmony_ci	struct efx_channel *channel;
4978c2ecf20Sopenharmony_ci	unsigned int time, quota;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	channel = container_of(dwork, struct efx_channel, filter_work);
5008c2ecf20Sopenharmony_ci	time = jiffies - channel->rfs_last_expiry;
5018c2ecf20Sopenharmony_ci	quota = channel->rfs_filter_count * time / (30 * HZ);
5028c2ecf20Sopenharmony_ci	if (quota >= 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota)))
5038c2ecf20Sopenharmony_ci		channel->rfs_last_expiry += time;
5048c2ecf20Sopenharmony_ci	/* Ensure we do more work eventually even if NAPI poll is not happening */
5058c2ecf20Sopenharmony_ci	schedule_delayed_work(dwork, 30 * HZ);
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci#endif
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci/* Allocate and initialise a channel structure. */
5108c2ecf20Sopenharmony_cistatic struct efx_channel *efx_alloc_channel(struct efx_nic *efx, int i)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
5138c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
5148c2ecf20Sopenharmony_ci	struct efx_channel *channel;
5158c2ecf20Sopenharmony_ci	int j;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
5188c2ecf20Sopenharmony_ci	if (!channel)
5198c2ecf20Sopenharmony_ci		return NULL;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	channel->efx = efx;
5228c2ecf20Sopenharmony_ci	channel->channel = i;
5238c2ecf20Sopenharmony_ci	channel->type = &efx_default_channel_type;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	for (j = 0; j < EFX_MAX_TXQ_PER_CHANNEL; j++) {
5268c2ecf20Sopenharmony_ci		tx_queue = &channel->tx_queue[j];
5278c2ecf20Sopenharmony_ci		tx_queue->efx = efx;
5288c2ecf20Sopenharmony_ci		tx_queue->queue = -1;
5298c2ecf20Sopenharmony_ci		tx_queue->label = j;
5308c2ecf20Sopenharmony_ci		tx_queue->channel = channel;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
5348c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
5358c2ecf20Sopenharmony_ci#endif
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	rx_queue = &channel->rx_queue;
5388c2ecf20Sopenharmony_ci	rx_queue->efx = efx;
5398c2ecf20Sopenharmony_ci	timer_setup(&rx_queue->slow_fill, efx_rx_slow_fill, 0);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return channel;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ciint efx_init_channels(struct efx_nic *efx)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	unsigned int i;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	for (i = 0; i < EFX_MAX_CHANNELS; i++) {
5498c2ecf20Sopenharmony_ci		efx->channel[i] = efx_alloc_channel(efx, i);
5508c2ecf20Sopenharmony_ci		if (!efx->channel[i])
5518c2ecf20Sopenharmony_ci			return -ENOMEM;
5528c2ecf20Sopenharmony_ci		efx->msi_context[i].efx = efx;
5538c2ecf20Sopenharmony_ci		efx->msi_context[i].index = i;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* Higher numbered interrupt modes are less capable! */
5578c2ecf20Sopenharmony_ci	efx->interrupt_mode = min(efx->type->min_interrupt_mode,
5588c2ecf20Sopenharmony_ci				  efx_interrupt_mode);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	efx->max_channels = EFX_MAX_CHANNELS;
5618c2ecf20Sopenharmony_ci	efx->max_tx_channels = EFX_MAX_CHANNELS;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_civoid efx_fini_channels(struct efx_nic *efx)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	unsigned int i;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	for (i = 0; i < EFX_MAX_CHANNELS; i++)
5718c2ecf20Sopenharmony_ci		if (efx->channel[i]) {
5728c2ecf20Sopenharmony_ci			kfree(efx->channel[i]);
5738c2ecf20Sopenharmony_ci			efx->channel[i] = NULL;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/* Allocate and initialise a channel structure, copying parameters
5788c2ecf20Sopenharmony_ci * (but not resources) from an old channel structure.
5798c2ecf20Sopenharmony_ci */
5808c2ecf20Sopenharmony_cistruct efx_channel *efx_copy_channel(const struct efx_channel *old_channel)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
5838c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
5848c2ecf20Sopenharmony_ci	struct efx_channel *channel;
5858c2ecf20Sopenharmony_ci	int j;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
5888c2ecf20Sopenharmony_ci	if (!channel)
5898c2ecf20Sopenharmony_ci		return NULL;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	*channel = *old_channel;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	channel->napi_dev = NULL;
5948c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&channel->napi_str.napi_hash_node);
5958c2ecf20Sopenharmony_ci	channel->napi_str.napi_id = 0;
5968c2ecf20Sopenharmony_ci	channel->napi_str.state = 0;
5978c2ecf20Sopenharmony_ci	memset(&channel->eventq, 0, sizeof(channel->eventq));
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	for (j = 0; j < EFX_MAX_TXQ_PER_CHANNEL; j++) {
6008c2ecf20Sopenharmony_ci		tx_queue = &channel->tx_queue[j];
6018c2ecf20Sopenharmony_ci		if (tx_queue->channel)
6028c2ecf20Sopenharmony_ci			tx_queue->channel = channel;
6038c2ecf20Sopenharmony_ci		tx_queue->buffer = NULL;
6048c2ecf20Sopenharmony_ci		tx_queue->cb_page = NULL;
6058c2ecf20Sopenharmony_ci		memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	rx_queue = &channel->rx_queue;
6098c2ecf20Sopenharmony_ci	rx_queue->buffer = NULL;
6108c2ecf20Sopenharmony_ci	memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
6118c2ecf20Sopenharmony_ci	timer_setup(&rx_queue->slow_fill, efx_rx_slow_fill, 0);
6128c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
6138c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
6148c2ecf20Sopenharmony_ci#endif
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return channel;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int efx_probe_channel(struct efx_channel *channel)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
6228c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
6238c2ecf20Sopenharmony_ci	int rc;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	netif_dbg(channel->efx, probe, channel->efx->net_dev,
6268c2ecf20Sopenharmony_ci		  "creating channel %d\n", channel->channel);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	rc = channel->type->pre_probe(channel);
6298c2ecf20Sopenharmony_ci	if (rc)
6308c2ecf20Sopenharmony_ci		goto fail;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	rc = efx_probe_eventq(channel);
6338c2ecf20Sopenharmony_ci	if (rc)
6348c2ecf20Sopenharmony_ci		goto fail;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	efx_for_each_channel_tx_queue(tx_queue, channel) {
6378c2ecf20Sopenharmony_ci		rc = efx_probe_tx_queue(tx_queue);
6388c2ecf20Sopenharmony_ci		if (rc)
6398c2ecf20Sopenharmony_ci			goto fail;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	efx_for_each_channel_rx_queue(rx_queue, channel) {
6438c2ecf20Sopenharmony_ci		rc = efx_probe_rx_queue(rx_queue);
6448c2ecf20Sopenharmony_ci		if (rc)
6458c2ecf20Sopenharmony_ci			goto fail;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	channel->rx_list = NULL;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return 0;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cifail:
6538c2ecf20Sopenharmony_ci	efx_remove_channel(channel);
6548c2ecf20Sopenharmony_ci	return rc;
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_civoid efx_get_channel_name(struct efx_channel *channel, char *buf, size_t len)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	struct efx_nic *efx = channel->efx;
6608c2ecf20Sopenharmony_ci	const char *type;
6618c2ecf20Sopenharmony_ci	int number;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	number = channel->channel;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (number >= efx->xdp_channel_offset &&
6668c2ecf20Sopenharmony_ci	    !WARN_ON_ONCE(!efx->n_xdp_channels)) {
6678c2ecf20Sopenharmony_ci		type = "-xdp";
6688c2ecf20Sopenharmony_ci		number -= efx->xdp_channel_offset;
6698c2ecf20Sopenharmony_ci	} else if (efx->tx_channel_offset == 0) {
6708c2ecf20Sopenharmony_ci		type = "";
6718c2ecf20Sopenharmony_ci	} else if (number < efx->tx_channel_offset) {
6728c2ecf20Sopenharmony_ci		type = "-rx";
6738c2ecf20Sopenharmony_ci	} else {
6748c2ecf20Sopenharmony_ci		type = "-tx";
6758c2ecf20Sopenharmony_ci		number -= efx->tx_channel_offset;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci	snprintf(buf, len, "%s%s-%d", efx->name, type, number);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_civoid efx_set_channel_names(struct efx_nic *efx)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct efx_channel *channel;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
6858c2ecf20Sopenharmony_ci		channel->type->get_name(channel,
6868c2ecf20Sopenharmony_ci					efx->msi_context[channel->channel].name,
6878c2ecf20Sopenharmony_ci					sizeof(efx->msi_context[0].name));
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ciint efx_probe_channels(struct efx_nic *efx)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct efx_channel *channel;
6938c2ecf20Sopenharmony_ci	int rc;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* Restart special buffer allocation */
6968c2ecf20Sopenharmony_ci	efx->next_buffer_table = 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	/* Probe channels in reverse, so that any 'extra' channels
6998c2ecf20Sopenharmony_ci	 * use the start of the buffer table. This allows the traffic
7008c2ecf20Sopenharmony_ci	 * channels to be resized without moving them or wasting the
7018c2ecf20Sopenharmony_ci	 * entries before them.
7028c2ecf20Sopenharmony_ci	 */
7038c2ecf20Sopenharmony_ci	efx_for_each_channel_rev(channel, efx) {
7048c2ecf20Sopenharmony_ci		rc = efx_probe_channel(channel);
7058c2ecf20Sopenharmony_ci		if (rc) {
7068c2ecf20Sopenharmony_ci			netif_err(efx, probe, efx->net_dev,
7078c2ecf20Sopenharmony_ci				  "failed to create channel %d\n",
7088c2ecf20Sopenharmony_ci				  channel->channel);
7098c2ecf20Sopenharmony_ci			goto fail;
7108c2ecf20Sopenharmony_ci		}
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci	efx_set_channel_names(efx);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	return 0;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cifail:
7178c2ecf20Sopenharmony_ci	efx_remove_channels(efx);
7188c2ecf20Sopenharmony_ci	return rc;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_civoid efx_remove_channel(struct efx_channel *channel)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
7248c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	netif_dbg(channel->efx, drv, channel->efx->net_dev,
7278c2ecf20Sopenharmony_ci		  "destroy chan %d\n", channel->channel);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	efx_for_each_channel_rx_queue(rx_queue, channel)
7308c2ecf20Sopenharmony_ci		efx_remove_rx_queue(rx_queue);
7318c2ecf20Sopenharmony_ci	efx_for_each_channel_tx_queue(tx_queue, channel)
7328c2ecf20Sopenharmony_ci		efx_remove_tx_queue(tx_queue);
7338c2ecf20Sopenharmony_ci	efx_remove_eventq(channel);
7348c2ecf20Sopenharmony_ci	channel->type->post_remove(channel);
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_civoid efx_remove_channels(struct efx_nic *efx)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct efx_channel *channel;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
7428c2ecf20Sopenharmony_ci		efx_remove_channel(channel);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	kfree(efx->xdp_tx_queues);
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ciint efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel,
7508c2ecf20Sopenharmony_ci			   *ptp_channel = efx_ptp_channel(efx);
7518c2ecf20Sopenharmony_ci	struct efx_ptp_data *ptp_data = efx->ptp_data;
7528c2ecf20Sopenharmony_ci	unsigned int i, next_buffer_table = 0;
7538c2ecf20Sopenharmony_ci	u32 old_rxq_entries, old_txq_entries;
7548c2ecf20Sopenharmony_ci	int rc, rc2;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	rc = efx_check_disabled(efx);
7578c2ecf20Sopenharmony_ci	if (rc)
7588c2ecf20Sopenharmony_ci		return rc;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	/* Not all channels should be reallocated. We must avoid
7618c2ecf20Sopenharmony_ci	 * reallocating their buffer table entries.
7628c2ecf20Sopenharmony_ci	 */
7638c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
7648c2ecf20Sopenharmony_ci		struct efx_rx_queue *rx_queue;
7658c2ecf20Sopenharmony_ci		struct efx_tx_queue *tx_queue;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		if (channel->type->copy)
7688c2ecf20Sopenharmony_ci			continue;
7698c2ecf20Sopenharmony_ci		next_buffer_table = max(next_buffer_table,
7708c2ecf20Sopenharmony_ci					channel->eventq.index +
7718c2ecf20Sopenharmony_ci					channel->eventq.entries);
7728c2ecf20Sopenharmony_ci		efx_for_each_channel_rx_queue(rx_queue, channel)
7738c2ecf20Sopenharmony_ci			next_buffer_table = max(next_buffer_table,
7748c2ecf20Sopenharmony_ci						rx_queue->rxd.index +
7758c2ecf20Sopenharmony_ci						rx_queue->rxd.entries);
7768c2ecf20Sopenharmony_ci		efx_for_each_channel_tx_queue(tx_queue, channel)
7778c2ecf20Sopenharmony_ci			next_buffer_table = max(next_buffer_table,
7788c2ecf20Sopenharmony_ci						tx_queue->txd.index +
7798c2ecf20Sopenharmony_ci						tx_queue->txd.entries);
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	efx_device_detach_sync(efx);
7838c2ecf20Sopenharmony_ci	efx_stop_all(efx);
7848c2ecf20Sopenharmony_ci	efx_soft_disable_interrupts(efx);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	/* Clone channels (where possible) */
7878c2ecf20Sopenharmony_ci	memset(other_channel, 0, sizeof(other_channel));
7888c2ecf20Sopenharmony_ci	for (i = 0; i < efx->n_channels; i++) {
7898c2ecf20Sopenharmony_ci		channel = efx->channel[i];
7908c2ecf20Sopenharmony_ci		if (channel->type->copy)
7918c2ecf20Sopenharmony_ci			channel = channel->type->copy(channel);
7928c2ecf20Sopenharmony_ci		if (!channel) {
7938c2ecf20Sopenharmony_ci			rc = -ENOMEM;
7948c2ecf20Sopenharmony_ci			goto out;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci		other_channel[i] = channel;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/* Swap entry counts and channel pointers */
8008c2ecf20Sopenharmony_ci	old_rxq_entries = efx->rxq_entries;
8018c2ecf20Sopenharmony_ci	old_txq_entries = efx->txq_entries;
8028c2ecf20Sopenharmony_ci	efx->rxq_entries = rxq_entries;
8038c2ecf20Sopenharmony_ci	efx->txq_entries = txq_entries;
8048c2ecf20Sopenharmony_ci	for (i = 0; i < efx->n_channels; i++)
8058c2ecf20Sopenharmony_ci		swap(efx->channel[i], other_channel[i]);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* Restart buffer table allocation */
8088c2ecf20Sopenharmony_ci	efx->next_buffer_table = next_buffer_table;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	for (i = 0; i < efx->n_channels; i++) {
8118c2ecf20Sopenharmony_ci		channel = efx->channel[i];
8128c2ecf20Sopenharmony_ci		if (!channel->type->copy)
8138c2ecf20Sopenharmony_ci			continue;
8148c2ecf20Sopenharmony_ci		rc = efx_probe_channel(channel);
8158c2ecf20Sopenharmony_ci		if (rc)
8168c2ecf20Sopenharmony_ci			goto rollback;
8178c2ecf20Sopenharmony_ci		efx_init_napi_channel(efx->channel[i]);
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ciout:
8218c2ecf20Sopenharmony_ci	efx->ptp_data = NULL;
8228c2ecf20Sopenharmony_ci	/* Destroy unused channel structures */
8238c2ecf20Sopenharmony_ci	for (i = 0; i < efx->n_channels; i++) {
8248c2ecf20Sopenharmony_ci		channel = other_channel[i];
8258c2ecf20Sopenharmony_ci		if (channel && channel->type->copy) {
8268c2ecf20Sopenharmony_ci			efx_fini_napi_channel(channel);
8278c2ecf20Sopenharmony_ci			efx_remove_channel(channel);
8288c2ecf20Sopenharmony_ci			kfree(channel);
8298c2ecf20Sopenharmony_ci		}
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	efx->ptp_data = ptp_data;
8338c2ecf20Sopenharmony_ci	rc2 = efx_soft_enable_interrupts(efx);
8348c2ecf20Sopenharmony_ci	if (rc2) {
8358c2ecf20Sopenharmony_ci		rc = rc ? rc : rc2;
8368c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
8378c2ecf20Sopenharmony_ci			  "unable to restart interrupts on channel reallocation\n");
8388c2ecf20Sopenharmony_ci		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
8398c2ecf20Sopenharmony_ci	} else {
8408c2ecf20Sopenharmony_ci		efx_start_all(efx);
8418c2ecf20Sopenharmony_ci		efx_device_attach_if_not_resetting(efx);
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci	return rc;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cirollback:
8468c2ecf20Sopenharmony_ci	/* Swap back */
8478c2ecf20Sopenharmony_ci	efx->rxq_entries = old_rxq_entries;
8488c2ecf20Sopenharmony_ci	efx->txq_entries = old_txq_entries;
8498c2ecf20Sopenharmony_ci	for (i = 0; i < efx->n_channels; i++)
8508c2ecf20Sopenharmony_ci		swap(efx->channel[i], other_channel[i]);
8518c2ecf20Sopenharmony_ci	efx_ptp_update_channel(efx, ptp_channel);
8528c2ecf20Sopenharmony_ci	goto out;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ciint efx_set_channels(struct efx_nic *efx)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
8588c2ecf20Sopenharmony_ci	struct efx_channel *channel;
8598c2ecf20Sopenharmony_ci	unsigned int next_queue = 0;
8608c2ecf20Sopenharmony_ci	int xdp_queue_number;
8618c2ecf20Sopenharmony_ci	int rc;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (efx->xdp_tx_queue_count) {
8648c2ecf20Sopenharmony_ci		EFX_WARN_ON_PARANOID(efx->xdp_tx_queues);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		/* Allocate array for XDP TX queue lookup. */
8678c2ecf20Sopenharmony_ci		efx->xdp_tx_queues = kcalloc(efx->xdp_tx_queue_count,
8688c2ecf20Sopenharmony_ci					     sizeof(*efx->xdp_tx_queues),
8698c2ecf20Sopenharmony_ci					     GFP_KERNEL);
8708c2ecf20Sopenharmony_ci		if (!efx->xdp_tx_queues)
8718c2ecf20Sopenharmony_ci			return -ENOMEM;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* We need to mark which channels really have RX and TX
8758c2ecf20Sopenharmony_ci	 * queues, and adjust the TX queue numbers if we have separate
8768c2ecf20Sopenharmony_ci	 * RX-only and TX-only channels.
8778c2ecf20Sopenharmony_ci	 */
8788c2ecf20Sopenharmony_ci	xdp_queue_number = 0;
8798c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
8808c2ecf20Sopenharmony_ci		if (channel->channel < efx->n_rx_channels)
8818c2ecf20Sopenharmony_ci			channel->rx_queue.core_index = channel->channel;
8828c2ecf20Sopenharmony_ci		else
8838c2ecf20Sopenharmony_ci			channel->rx_queue.core_index = -1;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		if (channel->channel >= efx->tx_channel_offset) {
8868c2ecf20Sopenharmony_ci			if (efx_channel_is_xdp_tx(channel)) {
8878c2ecf20Sopenharmony_ci				efx_for_each_channel_tx_queue(tx_queue, channel) {
8888c2ecf20Sopenharmony_ci					tx_queue->queue = next_queue++;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci					/* We may have a few left-over XDP TX
8918c2ecf20Sopenharmony_ci					 * queues owing to xdp_tx_queue_count
8928c2ecf20Sopenharmony_ci					 * not dividing evenly by EFX_MAX_TXQ_PER_CHANNEL.
8938c2ecf20Sopenharmony_ci					 * We still allocate and probe those
8948c2ecf20Sopenharmony_ci					 * TXQs, but never use them.
8958c2ecf20Sopenharmony_ci					 */
8968c2ecf20Sopenharmony_ci					if (xdp_queue_number < efx->xdp_tx_queue_count) {
8978c2ecf20Sopenharmony_ci						netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n",
8988c2ecf20Sopenharmony_ci							  channel->channel, tx_queue->label,
8998c2ecf20Sopenharmony_ci							  xdp_queue_number, tx_queue->queue);
9008c2ecf20Sopenharmony_ci						efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
9018c2ecf20Sopenharmony_ci						xdp_queue_number++;
9028c2ecf20Sopenharmony_ci					}
9038c2ecf20Sopenharmony_ci				}
9048c2ecf20Sopenharmony_ci			} else {
9058c2ecf20Sopenharmony_ci				efx_for_each_channel_tx_queue(tx_queue, channel) {
9068c2ecf20Sopenharmony_ci					tx_queue->queue = next_queue++;
9078c2ecf20Sopenharmony_ci					netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is HW %u\n",
9088c2ecf20Sopenharmony_ci						  channel->channel, tx_queue->label,
9098c2ecf20Sopenharmony_ci						  tx_queue->queue);
9108c2ecf20Sopenharmony_ci				}
9118c2ecf20Sopenharmony_ci			}
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci	WARN_ON(xdp_queue_number != efx->xdp_tx_queue_count);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
9178c2ecf20Sopenharmony_ci	if (rc)
9188c2ecf20Sopenharmony_ci		return rc;
9198c2ecf20Sopenharmony_ci	return netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cibool efx_default_channel_want_txqs(struct efx_channel *channel)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	return channel->channel - channel->efx->tx_channel_offset <
9258c2ecf20Sopenharmony_ci		channel->efx->n_tx_channels;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci/*************
9298c2ecf20Sopenharmony_ci * START/STOP
9308c2ecf20Sopenharmony_ci *************/
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ciint efx_soft_enable_interrupts(struct efx_nic *efx)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct efx_channel *channel, *end_channel;
9358c2ecf20Sopenharmony_ci	int rc;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	BUG_ON(efx->state == STATE_DISABLED);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	efx->irq_soft_enabled = true;
9408c2ecf20Sopenharmony_ci	smp_wmb();
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
9438c2ecf20Sopenharmony_ci		if (!channel->type->keep_eventq) {
9448c2ecf20Sopenharmony_ci			rc = efx_init_eventq(channel);
9458c2ecf20Sopenharmony_ci			if (rc)
9468c2ecf20Sopenharmony_ci				goto fail;
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci		efx_start_eventq(channel);
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	efx_mcdi_mode_event(efx);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	return 0;
9548c2ecf20Sopenharmony_cifail:
9558c2ecf20Sopenharmony_ci	end_channel = channel;
9568c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
9578c2ecf20Sopenharmony_ci		if (channel == end_channel)
9588c2ecf20Sopenharmony_ci			break;
9598c2ecf20Sopenharmony_ci		efx_stop_eventq(channel);
9608c2ecf20Sopenharmony_ci		if (!channel->type->keep_eventq)
9618c2ecf20Sopenharmony_ci			efx_fini_eventq(channel);
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return rc;
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_civoid efx_soft_disable_interrupts(struct efx_nic *efx)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	struct efx_channel *channel;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (efx->state == STATE_DISABLED)
9728c2ecf20Sopenharmony_ci		return;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	efx_mcdi_mode_poll(efx);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	efx->irq_soft_enabled = false;
9778c2ecf20Sopenharmony_ci	smp_wmb();
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (efx->legacy_irq)
9808c2ecf20Sopenharmony_ci		synchronize_irq(efx->legacy_irq);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
9838c2ecf20Sopenharmony_ci		if (channel->irq)
9848c2ecf20Sopenharmony_ci			synchronize_irq(channel->irq);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		efx_stop_eventq(channel);
9878c2ecf20Sopenharmony_ci		if (!channel->type->keep_eventq)
9888c2ecf20Sopenharmony_ci			efx_fini_eventq(channel);
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	/* Flush the asynchronous MCDI request queue */
9928c2ecf20Sopenharmony_ci	efx_mcdi_flush_async(efx);
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ciint efx_enable_interrupts(struct efx_nic *efx)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	struct efx_channel *channel, *end_channel;
9988c2ecf20Sopenharmony_ci	int rc;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/* TODO: Is this really a bug? */
10018c2ecf20Sopenharmony_ci	BUG_ON(efx->state == STATE_DISABLED);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	if (efx->eeh_disabled_legacy_irq) {
10048c2ecf20Sopenharmony_ci		enable_irq(efx->legacy_irq);
10058c2ecf20Sopenharmony_ci		efx->eeh_disabled_legacy_irq = false;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	efx->type->irq_enable_master(efx);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10118c2ecf20Sopenharmony_ci		if (channel->type->keep_eventq) {
10128c2ecf20Sopenharmony_ci			rc = efx_init_eventq(channel);
10138c2ecf20Sopenharmony_ci			if (rc)
10148c2ecf20Sopenharmony_ci				goto fail;
10158c2ecf20Sopenharmony_ci		}
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	rc = efx_soft_enable_interrupts(efx);
10198c2ecf20Sopenharmony_ci	if (rc)
10208c2ecf20Sopenharmony_ci		goto fail;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	return 0;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_cifail:
10258c2ecf20Sopenharmony_ci	end_channel = channel;
10268c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10278c2ecf20Sopenharmony_ci		if (channel == end_channel)
10288c2ecf20Sopenharmony_ci			break;
10298c2ecf20Sopenharmony_ci		if (channel->type->keep_eventq)
10308c2ecf20Sopenharmony_ci			efx_fini_eventq(channel);
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	efx->type->irq_disable_non_ev(efx);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return rc;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_civoid efx_disable_interrupts(struct efx_nic *efx)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	struct efx_channel *channel;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	efx_soft_disable_interrupts(efx);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10458c2ecf20Sopenharmony_ci		if (channel->type->keep_eventq)
10468c2ecf20Sopenharmony_ci			efx_fini_eventq(channel);
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	efx->type->irq_disable_non_ev(efx);
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_civoid efx_start_channels(struct efx_nic *efx)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
10558c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
10568c2ecf20Sopenharmony_ci	struct efx_channel *channel;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10598c2ecf20Sopenharmony_ci		efx_for_each_channel_tx_queue(tx_queue, channel) {
10608c2ecf20Sopenharmony_ci			efx_init_tx_queue(tx_queue);
10618c2ecf20Sopenharmony_ci			atomic_inc(&efx->active_queues);
10628c2ecf20Sopenharmony_ci		}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		efx_for_each_channel_rx_queue(rx_queue, channel) {
10658c2ecf20Sopenharmony_ci			efx_init_rx_queue(rx_queue);
10668c2ecf20Sopenharmony_ci			atomic_inc(&efx->active_queues);
10678c2ecf20Sopenharmony_ci			efx_stop_eventq(channel);
10688c2ecf20Sopenharmony_ci			efx_fast_push_rx_descriptors(rx_queue, false);
10698c2ecf20Sopenharmony_ci			efx_start_eventq(channel);
10708c2ecf20Sopenharmony_ci		}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci		WARN_ON(channel->rx_pkt_n_frags);
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_civoid efx_stop_channels(struct efx_nic *efx)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
10798c2ecf20Sopenharmony_ci	struct efx_rx_queue *rx_queue;
10808c2ecf20Sopenharmony_ci	struct efx_channel *channel;
10818c2ecf20Sopenharmony_ci	int rc = 0;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	/* Stop RX refill */
10848c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10858c2ecf20Sopenharmony_ci		efx_for_each_channel_rx_queue(rx_queue, channel)
10868c2ecf20Sopenharmony_ci			rx_queue->refill_enabled = false;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
10908c2ecf20Sopenharmony_ci		/* RX packet processing is pipelined, so wait for the
10918c2ecf20Sopenharmony_ci		 * NAPI handler to complete.  At least event queue 0
10928c2ecf20Sopenharmony_ci		 * might be kept active by non-data events, so don't
10938c2ecf20Sopenharmony_ci		 * use napi_synchronize() but actually disable NAPI
10948c2ecf20Sopenharmony_ci		 * temporarily.
10958c2ecf20Sopenharmony_ci		 */
10968c2ecf20Sopenharmony_ci		if (efx_channel_has_rx_queue(channel)) {
10978c2ecf20Sopenharmony_ci			efx_stop_eventq(channel);
10988c2ecf20Sopenharmony_ci			efx_start_eventq(channel);
10998c2ecf20Sopenharmony_ci		}
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	if (efx->type->fini_dmaq)
11038c2ecf20Sopenharmony_ci		rc = efx->type->fini_dmaq(efx);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (rc) {
11068c2ecf20Sopenharmony_ci		netif_err(efx, drv, efx->net_dev, "failed to flush queues\n");
11078c2ecf20Sopenharmony_ci	} else {
11088c2ecf20Sopenharmony_ci		netif_dbg(efx, drv, efx->net_dev,
11098c2ecf20Sopenharmony_ci			  "successfully flushed all queues\n");
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx) {
11138c2ecf20Sopenharmony_ci		efx_for_each_channel_rx_queue(rx_queue, channel)
11148c2ecf20Sopenharmony_ci			efx_fini_rx_queue(rx_queue);
11158c2ecf20Sopenharmony_ci		efx_for_each_channel_tx_queue(tx_queue, channel)
11168c2ecf20Sopenharmony_ci			efx_fini_tx_queue(tx_queue);
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/**************************************************************************
11218c2ecf20Sopenharmony_ci *
11228c2ecf20Sopenharmony_ci * NAPI interface
11238c2ecf20Sopenharmony_ci *
11248c2ecf20Sopenharmony_ci *************************************************************************/
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci/* Process channel's event queue
11278c2ecf20Sopenharmony_ci *
11288c2ecf20Sopenharmony_ci * This function is responsible for processing the event queue of a
11298c2ecf20Sopenharmony_ci * single channel.  The caller must guarantee that this function will
11308c2ecf20Sopenharmony_ci * never be concurrently called more than once on the same channel,
11318c2ecf20Sopenharmony_ci * though different channels may be being processed concurrently.
11328c2ecf20Sopenharmony_ci */
11338c2ecf20Sopenharmony_cistatic int efx_process_channel(struct efx_channel *channel, int budget)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	struct efx_tx_queue *tx_queue;
11368c2ecf20Sopenharmony_ci	struct list_head rx_list;
11378c2ecf20Sopenharmony_ci	int spent;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (unlikely(!channel->enabled))
11408c2ecf20Sopenharmony_ci		return 0;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	/* Prepare the batch receive list */
11438c2ecf20Sopenharmony_ci	EFX_WARN_ON_PARANOID(channel->rx_list != NULL);
11448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rx_list);
11458c2ecf20Sopenharmony_ci	channel->rx_list = &rx_list;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	efx_for_each_channel_tx_queue(tx_queue, channel) {
11488c2ecf20Sopenharmony_ci		tx_queue->pkts_compl = 0;
11498c2ecf20Sopenharmony_ci		tx_queue->bytes_compl = 0;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	spent = efx_nic_process_eventq(channel, budget);
11538c2ecf20Sopenharmony_ci	if (spent && efx_channel_has_rx_queue(channel)) {
11548c2ecf20Sopenharmony_ci		struct efx_rx_queue *rx_queue =
11558c2ecf20Sopenharmony_ci			efx_channel_get_rx_queue(channel);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		efx_rx_flush_packet(channel);
11588c2ecf20Sopenharmony_ci		efx_fast_push_rx_descriptors(rx_queue, true);
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* Update BQL */
11628c2ecf20Sopenharmony_ci	efx_for_each_channel_tx_queue(tx_queue, channel) {
11638c2ecf20Sopenharmony_ci		if (tx_queue->bytes_compl) {
11648c2ecf20Sopenharmony_ci			netdev_tx_completed_queue(tx_queue->core_txq,
11658c2ecf20Sopenharmony_ci						  tx_queue->pkts_compl,
11668c2ecf20Sopenharmony_ci						  tx_queue->bytes_compl);
11678c2ecf20Sopenharmony_ci		}
11688c2ecf20Sopenharmony_ci	}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	/* Receive any packets we queued up */
11718c2ecf20Sopenharmony_ci	netif_receive_skb_list(channel->rx_list);
11728c2ecf20Sopenharmony_ci	channel->rx_list = NULL;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	return spent;
11758c2ecf20Sopenharmony_ci}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_cistatic void efx_update_irq_mod(struct efx_nic *efx, struct efx_channel *channel)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	int step = efx->irq_mod_step_us;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	if (channel->irq_mod_score < irq_adapt_low_thresh) {
11828c2ecf20Sopenharmony_ci		if (channel->irq_moderation_us > step) {
11838c2ecf20Sopenharmony_ci			channel->irq_moderation_us -= step;
11848c2ecf20Sopenharmony_ci			efx->type->push_irq_moderation(channel);
11858c2ecf20Sopenharmony_ci		}
11868c2ecf20Sopenharmony_ci	} else if (channel->irq_mod_score > irq_adapt_high_thresh) {
11878c2ecf20Sopenharmony_ci		if (channel->irq_moderation_us <
11888c2ecf20Sopenharmony_ci		    efx->irq_rx_moderation_us) {
11898c2ecf20Sopenharmony_ci			channel->irq_moderation_us += step;
11908c2ecf20Sopenharmony_ci			efx->type->push_irq_moderation(channel);
11918c2ecf20Sopenharmony_ci		}
11928c2ecf20Sopenharmony_ci	}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	channel->irq_count = 0;
11958c2ecf20Sopenharmony_ci	channel->irq_mod_score = 0;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci/* NAPI poll handler
11998c2ecf20Sopenharmony_ci *
12008c2ecf20Sopenharmony_ci * NAPI guarantees serialisation of polls of the same device, which
12018c2ecf20Sopenharmony_ci * provides the guarantee required by efx_process_channel().
12028c2ecf20Sopenharmony_ci */
12038c2ecf20Sopenharmony_cistatic int efx_poll(struct napi_struct *napi, int budget)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	struct efx_channel *channel =
12068c2ecf20Sopenharmony_ci		container_of(napi, struct efx_channel, napi_str);
12078c2ecf20Sopenharmony_ci	struct efx_nic *efx = channel->efx;
12088c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
12098c2ecf20Sopenharmony_ci	unsigned int time;
12108c2ecf20Sopenharmony_ci#endif
12118c2ecf20Sopenharmony_ci	int spent;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	netif_vdbg(efx, intr, efx->net_dev,
12148c2ecf20Sopenharmony_ci		   "channel %d NAPI poll executing on CPU %d\n",
12158c2ecf20Sopenharmony_ci		   channel->channel, raw_smp_processor_id());
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	spent = efx_process_channel(channel, budget);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	xdp_do_flush_map();
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (spent < budget) {
12228c2ecf20Sopenharmony_ci		if (efx_channel_has_rx_queue(channel) &&
12238c2ecf20Sopenharmony_ci		    efx->irq_rx_adaptive &&
12248c2ecf20Sopenharmony_ci		    unlikely(++channel->irq_count == 1000)) {
12258c2ecf20Sopenharmony_ci			efx_update_irq_mod(efx, channel);
12268c2ecf20Sopenharmony_ci		}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
12298c2ecf20Sopenharmony_ci		/* Perhaps expire some ARFS filters */
12308c2ecf20Sopenharmony_ci		time = jiffies - channel->rfs_last_expiry;
12318c2ecf20Sopenharmony_ci		/* Would our quota be >= 20? */
12328c2ecf20Sopenharmony_ci		if (channel->rfs_filter_count * time >= 600 * HZ)
12338c2ecf20Sopenharmony_ci			mod_delayed_work(system_wq, &channel->filter_work, 0);
12348c2ecf20Sopenharmony_ci#endif
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		/* There is no race here; although napi_disable() will
12378c2ecf20Sopenharmony_ci		 * only wait for napi_complete(), this isn't a problem
12388c2ecf20Sopenharmony_ci		 * since efx_nic_eventq_read_ack() will have no effect if
12398c2ecf20Sopenharmony_ci		 * interrupts have already been disabled.
12408c2ecf20Sopenharmony_ci		 */
12418c2ecf20Sopenharmony_ci		if (napi_complete_done(napi, spent))
12428c2ecf20Sopenharmony_ci			efx_nic_eventq_read_ack(channel);
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	return spent;
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_civoid efx_init_napi_channel(struct efx_channel *channel)
12498c2ecf20Sopenharmony_ci{
12508c2ecf20Sopenharmony_ci	struct efx_nic *efx = channel->efx;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	channel->napi_dev = efx->net_dev;
12538c2ecf20Sopenharmony_ci	netif_napi_add(channel->napi_dev, &channel->napi_str,
12548c2ecf20Sopenharmony_ci		       efx_poll, napi_weight);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_civoid efx_init_napi(struct efx_nic *efx)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	struct efx_channel *channel;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
12628c2ecf20Sopenharmony_ci		efx_init_napi_channel(channel);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_civoid efx_fini_napi_channel(struct efx_channel *channel)
12668c2ecf20Sopenharmony_ci{
12678c2ecf20Sopenharmony_ci	if (channel->napi_dev)
12688c2ecf20Sopenharmony_ci		netif_napi_del(&channel->napi_str);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	channel->napi_dev = NULL;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_civoid efx_fini_napi(struct efx_nic *efx)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct efx_channel *channel;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	efx_for_each_channel(channel, efx)
12788c2ecf20Sopenharmony_ci		efx_fini_napi_channel(channel);
12798c2ecf20Sopenharmony_ci}
1280