xref: /openbmc/linux/drivers/net/ethernet/sfc/siena/efx_channels.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
16e173d3bSMartin Habets // SPDX-License-Identifier: GPL-2.0-only
26e173d3bSMartin Habets /****************************************************************************
36e173d3bSMartin Habets  * Driver for Solarflare network controllers and boards
46e173d3bSMartin Habets  * Copyright 2018 Solarflare Communications Inc.
56e173d3bSMartin Habets  *
66e173d3bSMartin Habets  * This program is free software; you can redistribute it and/or modify it
76e173d3bSMartin Habets  * under the terms of the GNU General Public License version 2 as published
86e173d3bSMartin Habets  * by the Free Software Foundation, incorporated herein by reference.
96e173d3bSMartin Habets  */
106e173d3bSMartin Habets 
116e173d3bSMartin Habets #include "net_driver.h"
126e173d3bSMartin Habets #include <linux/module.h>
136e173d3bSMartin Habets #include <linux/filter.h>
146e173d3bSMartin Habets #include "efx_channels.h"
156e173d3bSMartin Habets #include "efx.h"
166e173d3bSMartin Habets #include "efx_common.h"
176e173d3bSMartin Habets #include "tx_common.h"
186e173d3bSMartin Habets #include "rx_common.h"
196e173d3bSMartin Habets #include "nic.h"
206e173d3bSMartin Habets #include "sriov.h"
216e173d3bSMartin Habets #include "workarounds.h"
226e173d3bSMartin Habets 
236e173d3bSMartin Habets /* This is the first interrupt mode to try out of:
246e173d3bSMartin Habets  * 0 => MSI-X
256e173d3bSMartin Habets  * 1 => MSI
266e173d3bSMartin Habets  * 2 => legacy
276e173d3bSMartin Habets  */
2871ad88f6SMartin Habets unsigned int efx_siena_interrupt_mode = EFX_INT_MODE_MSIX;
296e173d3bSMartin Habets 
306e173d3bSMartin Habets /* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
316e173d3bSMartin Habets  * i.e. the number of CPUs among which we may distribute simultaneous
326e173d3bSMartin Habets  * interrupt handling.
336e173d3bSMartin Habets  *
346e173d3bSMartin Habets  * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
356e173d3bSMartin Habets  * The default (0) means to assign an interrupt to each core.
366e173d3bSMartin Habets  */
3771ad88f6SMartin Habets unsigned int efx_siena_rss_cpus;
386e173d3bSMartin Habets 
396e173d3bSMartin Habets static unsigned int irq_adapt_low_thresh = 8000;
406e173d3bSMartin Habets module_param(irq_adapt_low_thresh, uint, 0644);
416e173d3bSMartin Habets MODULE_PARM_DESC(irq_adapt_low_thresh,
426e173d3bSMartin Habets 		 "Threshold score for reducing IRQ moderation");
436e173d3bSMartin Habets 
446e173d3bSMartin Habets static unsigned int irq_adapt_high_thresh = 16000;
456e173d3bSMartin Habets module_param(irq_adapt_high_thresh, uint, 0644);
466e173d3bSMartin Habets MODULE_PARM_DESC(irq_adapt_high_thresh,
476e173d3bSMartin Habets 		 "Threshold score for increasing IRQ moderation");
486e173d3bSMartin Habets 
496e173d3bSMartin Habets static const struct efx_channel_type efx_default_channel_type;
506e173d3bSMartin Habets 
516e173d3bSMartin Habets /*************
526e173d3bSMartin Habets  * INTERRUPTS
536e173d3bSMartin Habets  *************/
546e173d3bSMartin Habets 
count_online_cores(struct efx_nic * efx,bool local_node)556e173d3bSMartin Habets static unsigned int count_online_cores(struct efx_nic *efx, bool local_node)
566e173d3bSMartin Habets {
576e173d3bSMartin Habets 	cpumask_var_t filter_mask;
586e173d3bSMartin Habets 	unsigned int count;
596e173d3bSMartin Habets 	int cpu;
606e173d3bSMartin Habets 
616e173d3bSMartin Habets 	if (unlikely(!zalloc_cpumask_var(&filter_mask, GFP_KERNEL))) {
626e173d3bSMartin Habets 		netif_warn(efx, probe, efx->net_dev,
636e173d3bSMartin Habets 			   "RSS disabled due to allocation failure\n");
646e173d3bSMartin Habets 		return 1;
656e173d3bSMartin Habets 	}
666e173d3bSMartin Habets 
676e173d3bSMartin Habets 	cpumask_copy(filter_mask, cpu_online_mask);
686e173d3bSMartin Habets 	if (local_node)
696e173d3bSMartin Habets 		cpumask_and(filter_mask, filter_mask,
706e173d3bSMartin Habets 			    cpumask_of_pcibus(efx->pci_dev->bus));
716e173d3bSMartin Habets 
726e173d3bSMartin Habets 	count = 0;
736e173d3bSMartin Habets 	for_each_cpu(cpu, filter_mask) {
746e173d3bSMartin Habets 		++count;
756e173d3bSMartin Habets 		cpumask_andnot(filter_mask, filter_mask, topology_sibling_cpumask(cpu));
766e173d3bSMartin Habets 	}
776e173d3bSMartin Habets 
786e173d3bSMartin Habets 	free_cpumask_var(filter_mask);
796e173d3bSMartin Habets 
806e173d3bSMartin Habets 	return count;
816e173d3bSMartin Habets }
826e173d3bSMartin Habets 
efx_wanted_parallelism(struct efx_nic * efx)836e173d3bSMartin Habets static unsigned int efx_wanted_parallelism(struct efx_nic *efx)
846e173d3bSMartin Habets {
856e173d3bSMartin Habets 	unsigned int count;
866e173d3bSMartin Habets 
8771ad88f6SMartin Habets 	if (efx_siena_rss_cpus) {
8871ad88f6SMartin Habets 		count = efx_siena_rss_cpus;
896e173d3bSMartin Habets 	} else {
906e173d3bSMartin Habets 		count = count_online_cores(efx, true);
916e173d3bSMartin Habets 
926e173d3bSMartin Habets 		/* If no online CPUs in local node, fallback to any online CPUs */
936e173d3bSMartin Habets 		if (count == 0)
946e173d3bSMartin Habets 			count = count_online_cores(efx, false);
956e173d3bSMartin Habets 	}
966e173d3bSMartin Habets 
976e173d3bSMartin Habets 	if (count > EFX_MAX_RX_QUEUES) {
9871ad88f6SMartin Habets 		netif_cond_dbg(efx, probe, efx->net_dev, !efx_siena_rss_cpus,
9971ad88f6SMartin Habets 			       warn,
1006e173d3bSMartin Habets 			       "Reducing number of rx queues from %u to %u.\n",
1016e173d3bSMartin Habets 			       count, EFX_MAX_RX_QUEUES);
1026e173d3bSMartin Habets 		count = EFX_MAX_RX_QUEUES;
1036e173d3bSMartin Habets 	}
1046e173d3bSMartin Habets 
1056e173d3bSMartin Habets 	/* If RSS is requested for the PF *and* VFs then we can't write RSS
1066e173d3bSMartin Habets 	 * table entries that are inaccessible to VFs
1076e173d3bSMartin Habets 	 */
108dfb1cfbdSMartin Habets #ifdef CONFIG_SFC_SIENA_SRIOV
1096e173d3bSMartin Habets 	if (efx->type->sriov_wanted) {
1106e173d3bSMartin Habets 		if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
1116e173d3bSMartin Habets 		    count > efx_vf_size(efx)) {
1126e173d3bSMartin Habets 			netif_warn(efx, probe, efx->net_dev,
1136e173d3bSMartin Habets 				   "Reducing number of RSS channels from %u to %u for "
1146e173d3bSMartin Habets 				   "VF support. Increase vf-msix-limit to use more "
1156e173d3bSMartin Habets 				   "channels on the PF.\n",
1166e173d3bSMartin Habets 				   count, efx_vf_size(efx));
1176e173d3bSMartin Habets 			count = efx_vf_size(efx);
1186e173d3bSMartin Habets 		}
1196e173d3bSMartin Habets 	}
1206e173d3bSMartin Habets #endif
1216e173d3bSMartin Habets 
1226e173d3bSMartin Habets 	return count;
1236e173d3bSMartin Habets }
1246e173d3bSMartin Habets 
efx_allocate_msix_channels(struct efx_nic * efx,unsigned int max_channels,unsigned int extra_channels,unsigned int parallelism)1256e173d3bSMartin Habets static int efx_allocate_msix_channels(struct efx_nic *efx,
1266e173d3bSMartin Habets 				      unsigned int max_channels,
1276e173d3bSMartin Habets 				      unsigned int extra_channels,
1286e173d3bSMartin Habets 				      unsigned int parallelism)
1296e173d3bSMartin Habets {
1306e173d3bSMartin Habets 	unsigned int n_channels = parallelism;
1316e173d3bSMartin Habets 	int vec_count;
1326e173d3bSMartin Habets 	int tx_per_ev;
1336e173d3bSMartin Habets 	int n_xdp_tx;
1346e173d3bSMartin Habets 	int n_xdp_ev;
1356e173d3bSMartin Habets 
1367f9e4b2aSMartin Habets 	if (efx_siena_separate_tx_channels)
1376e173d3bSMartin Habets 		n_channels *= 2;
1386e173d3bSMartin Habets 	n_channels += extra_channels;
1396e173d3bSMartin Habets 
1406e173d3bSMartin Habets 	/* To allow XDP transmit to happen from arbitrary NAPI contexts
1416e173d3bSMartin Habets 	 * we allocate a TX queue per CPU. We share event queues across
1426e173d3bSMartin Habets 	 * multiple tx queues, assuming tx and ev queues are both
1436e173d3bSMartin Habets 	 * maximum size.
1446e173d3bSMartin Habets 	 */
1456e173d3bSMartin Habets 	tx_per_ev = EFX_MAX_EVQ_SIZE / EFX_TXQ_MAX_ENT(efx);
1466e173d3bSMartin Habets 	tx_per_ev = min(tx_per_ev, EFX_MAX_TXQ_PER_CHANNEL);
1476e173d3bSMartin Habets 	n_xdp_tx = num_possible_cpus();
1486e173d3bSMartin Habets 	n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, tx_per_ev);
1496e173d3bSMartin Habets 
1506e173d3bSMartin Habets 	vec_count = pci_msix_vec_count(efx->pci_dev);
1516e173d3bSMartin Habets 	if (vec_count < 0)
1526e173d3bSMartin Habets 		return vec_count;
1536e173d3bSMartin Habets 
1546e173d3bSMartin Habets 	max_channels = min_t(unsigned int, vec_count, max_channels);
1556e173d3bSMartin Habets 
1566e173d3bSMartin Habets 	/* Check resources.
1576e173d3bSMartin Habets 	 * We need a channel per event queue, plus a VI per tx queue.
1586e173d3bSMartin Habets 	 * This may be more pessimistic than it needs to be.
1596e173d3bSMartin Habets 	 */
1606e173d3bSMartin Habets 	if (n_channels >= max_channels) {
1616e173d3bSMartin Habets 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
1626e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1636e173d3bSMartin Habets 			   "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n",
1646e173d3bSMartin Habets 			   n_xdp_ev, n_channels, max_channels);
1656e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1666e173d3bSMartin Habets 			   "XDP_TX and XDP_REDIRECT might decrease device's performance\n");
1676e173d3bSMartin Habets 	} else if (n_channels + n_xdp_tx > efx->max_vis) {
1686e173d3bSMartin Habets 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
1696e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1706e173d3bSMartin Habets 			   "Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n",
1716e173d3bSMartin Habets 			   n_xdp_tx, n_channels, efx->max_vis);
1726e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1736e173d3bSMartin Habets 			   "XDP_TX and XDP_REDIRECT might decrease device's performance\n");
1746e173d3bSMartin Habets 	} else if (n_channels + n_xdp_ev > max_channels) {
1756e173d3bSMartin Habets 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_SHARED;
1766e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1776e173d3bSMartin Habets 			   "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n",
1786e173d3bSMartin Habets 			   n_xdp_ev, n_channels, max_channels);
1796e173d3bSMartin Habets 
1806e173d3bSMartin Habets 		n_xdp_ev = max_channels - n_channels;
1816e173d3bSMartin Habets 		netif_warn(efx, drv, efx->net_dev,
1826e173d3bSMartin Habets 			   "XDP_TX and XDP_REDIRECT will work with reduced performance (%d cpus/tx_queue)\n",
1836e173d3bSMartin Habets 			   DIV_ROUND_UP(n_xdp_tx, tx_per_ev * n_xdp_ev));
1846e173d3bSMartin Habets 	} else {
1856e173d3bSMartin Habets 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_DEDICATED;
1866e173d3bSMartin Habets 	}
1876e173d3bSMartin Habets 
1886e173d3bSMartin Habets 	if (efx->xdp_txq_queues_mode != EFX_XDP_TX_QUEUES_BORROWED) {
1896e173d3bSMartin Habets 		efx->n_xdp_channels = n_xdp_ev;
1906e173d3bSMartin Habets 		efx->xdp_tx_per_channel = tx_per_ev;
1916e173d3bSMartin Habets 		efx->xdp_tx_queue_count = n_xdp_tx;
1926e173d3bSMartin Habets 		n_channels += n_xdp_ev;
1936e173d3bSMartin Habets 		netif_dbg(efx, drv, efx->net_dev,
1946e173d3bSMartin Habets 			  "Allocating %d TX and %d event queues for XDP\n",
1956e173d3bSMartin Habets 			  n_xdp_ev * tx_per_ev, n_xdp_ev);
1966e173d3bSMartin Habets 	} else {
1976e173d3bSMartin Habets 		efx->n_xdp_channels = 0;
1986e173d3bSMartin Habets 		efx->xdp_tx_per_channel = 0;
1996e173d3bSMartin Habets 		efx->xdp_tx_queue_count = n_xdp_tx;
2006e173d3bSMartin Habets 	}
2016e173d3bSMartin Habets 
2026e173d3bSMartin Habets 	if (vec_count < n_channels) {
2036e173d3bSMartin Habets 		netif_err(efx, drv, efx->net_dev,
2046e173d3bSMartin Habets 			  "WARNING: Insufficient MSI-X vectors available (%d < %u).\n",
2056e173d3bSMartin Habets 			  vec_count, n_channels);
2066e173d3bSMartin Habets 		netif_err(efx, drv, efx->net_dev,
2076e173d3bSMartin Habets 			  "WARNING: Performance may be reduced.\n");
2086e173d3bSMartin Habets 		n_channels = vec_count;
2096e173d3bSMartin Habets 	}
2106e173d3bSMartin Habets 
2116e173d3bSMartin Habets 	n_channels = min(n_channels, max_channels);
2126e173d3bSMartin Habets 
2136e173d3bSMartin Habets 	efx->n_channels = n_channels;
2146e173d3bSMartin Habets 
2156e173d3bSMartin Habets 	/* Ignore XDP tx channels when creating rx channels. */
2166e173d3bSMartin Habets 	n_channels -= efx->n_xdp_channels;
2176e173d3bSMartin Habets 
2187f9e4b2aSMartin Habets 	if (efx_siena_separate_tx_channels) {
2196e173d3bSMartin Habets 		efx->n_tx_channels =
2206e173d3bSMartin Habets 			min(max(n_channels / 2, 1U),
2216e173d3bSMartin Habets 			    efx->max_tx_channels);
2226e173d3bSMartin Habets 		efx->tx_channel_offset =
2236e173d3bSMartin Habets 			n_channels - efx->n_tx_channels;
2246e173d3bSMartin Habets 		efx->n_rx_channels =
2256e173d3bSMartin Habets 			max(n_channels -
2266e173d3bSMartin Habets 			    efx->n_tx_channels, 1U);
2276e173d3bSMartin Habets 	} else {
2286e173d3bSMartin Habets 		efx->n_tx_channels = min(n_channels, efx->max_tx_channels);
2296e173d3bSMartin Habets 		efx->tx_channel_offset = 0;
2306e173d3bSMartin Habets 		efx->n_rx_channels = n_channels;
2316e173d3bSMartin Habets 	}
2326e173d3bSMartin Habets 
2336e173d3bSMartin Habets 	efx->n_rx_channels = min(efx->n_rx_channels, parallelism);
2346e173d3bSMartin Habets 	efx->n_tx_channels = min(efx->n_tx_channels, parallelism);
2356e173d3bSMartin Habets 
2366e173d3bSMartin Habets 	efx->xdp_channel_offset = n_channels;
2376e173d3bSMartin Habets 
2386e173d3bSMartin Habets 	netif_dbg(efx, drv, efx->net_dev,
2396e173d3bSMartin Habets 		  "Allocating %u RX channels\n",
2406e173d3bSMartin Habets 		  efx->n_rx_channels);
2416e173d3bSMartin Habets 
2426e173d3bSMartin Habets 	return efx->n_channels;
2436e173d3bSMartin Habets }
2446e173d3bSMartin Habets 
2456e173d3bSMartin Habets /* Probe the number and type of interrupts we are able to obtain, and
2466e173d3bSMartin Habets  * the resulting numbers of channels and RX queues.
2476e173d3bSMartin Habets  */
efx_siena_probe_interrupts(struct efx_nic * efx)24871ad88f6SMartin Habets int efx_siena_probe_interrupts(struct efx_nic *efx)
2496e173d3bSMartin Habets {
2506e173d3bSMartin Habets 	unsigned int extra_channels = 0;
2516e173d3bSMartin Habets 	unsigned int rss_spread;
2526e173d3bSMartin Habets 	unsigned int i, j;
2536e173d3bSMartin Habets 	int rc;
2546e173d3bSMartin Habets 
2556e173d3bSMartin Habets 	for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++)
2566e173d3bSMartin Habets 		if (efx->extra_channel_type[i])
2576e173d3bSMartin Habets 			++extra_channels;
2586e173d3bSMartin Habets 
2596e173d3bSMartin Habets 	if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
2606e173d3bSMartin Habets 		unsigned int parallelism = efx_wanted_parallelism(efx);
2616e173d3bSMartin Habets 		struct msix_entry xentries[EFX_MAX_CHANNELS];
2626e173d3bSMartin Habets 		unsigned int n_channels;
2636e173d3bSMartin Habets 
2646e173d3bSMartin Habets 		rc = efx_allocate_msix_channels(efx, efx->max_channels,
2656e173d3bSMartin Habets 						extra_channels, parallelism);
2666e173d3bSMartin Habets 		if (rc >= 0) {
2676e173d3bSMartin Habets 			n_channels = rc;
2686e173d3bSMartin Habets 			for (i = 0; i < n_channels; i++)
2696e173d3bSMartin Habets 				xentries[i].entry = i;
2706e173d3bSMartin Habets 			rc = pci_enable_msix_range(efx->pci_dev, xentries, 1,
2716e173d3bSMartin Habets 						   n_channels);
2726e173d3bSMartin Habets 		}
2736e173d3bSMartin Habets 		if (rc < 0) {
2746e173d3bSMartin Habets 			/* Fall back to single channel MSI */
2756e173d3bSMartin Habets 			netif_err(efx, drv, efx->net_dev,
2766e173d3bSMartin Habets 				  "could not enable MSI-X\n");
2776e173d3bSMartin Habets 			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_MSI)
2786e173d3bSMartin Habets 				efx->interrupt_mode = EFX_INT_MODE_MSI;
2796e173d3bSMartin Habets 			else
2806e173d3bSMartin Habets 				return rc;
2816e173d3bSMartin Habets 		} else if (rc < n_channels) {
2826e173d3bSMartin Habets 			netif_err(efx, drv, efx->net_dev,
2836e173d3bSMartin Habets 				  "WARNING: Insufficient MSI-X vectors"
2846e173d3bSMartin Habets 				  " available (%d < %u).\n", rc, n_channels);
2856e173d3bSMartin Habets 			netif_err(efx, drv, efx->net_dev,
2866e173d3bSMartin Habets 				  "WARNING: Performance may be reduced.\n");
2876e173d3bSMartin Habets 			n_channels = rc;
2886e173d3bSMartin Habets 		}
2896e173d3bSMartin Habets 
2906e173d3bSMartin Habets 		if (rc > 0) {
2916e173d3bSMartin Habets 			for (i = 0; i < efx->n_channels; i++)
2926e173d3bSMartin Habets 				efx_get_channel(efx, i)->irq =
2936e173d3bSMartin Habets 					xentries[i].vector;
2946e173d3bSMartin Habets 		}
2956e173d3bSMartin Habets 	}
2966e173d3bSMartin Habets 
2976e173d3bSMartin Habets 	/* Try single interrupt MSI */
2986e173d3bSMartin Habets 	if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
2996e173d3bSMartin Habets 		efx->n_channels = 1;
3006e173d3bSMartin Habets 		efx->n_rx_channels = 1;
3016e173d3bSMartin Habets 		efx->n_tx_channels = 1;
30225bde571SÍñigo Huguet 		efx->tx_channel_offset = 0;
3036e173d3bSMartin Habets 		efx->n_xdp_channels = 0;
3046e173d3bSMartin Habets 		efx->xdp_channel_offset = efx->n_channels;
305*e84a1e1eSÍñigo Huguet 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
3066e173d3bSMartin Habets 		rc = pci_enable_msi(efx->pci_dev);
3076e173d3bSMartin Habets 		if (rc == 0) {
3086e173d3bSMartin Habets 			efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
3096e173d3bSMartin Habets 		} else {
3106e173d3bSMartin Habets 			netif_err(efx, drv, efx->net_dev,
3116e173d3bSMartin Habets 				  "could not enable MSI\n");
3126e173d3bSMartin Habets 			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_LEGACY)
3136e173d3bSMartin Habets 				efx->interrupt_mode = EFX_INT_MODE_LEGACY;
3146e173d3bSMartin Habets 			else
3156e173d3bSMartin Habets 				return rc;
3166e173d3bSMartin Habets 		}
3176e173d3bSMartin Habets 	}
3186e173d3bSMartin Habets 
3196e173d3bSMartin Habets 	/* Assume legacy interrupts */
3206e173d3bSMartin Habets 	if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
3217f9e4b2aSMartin Habets 		efx->n_channels = 1 + (efx_siena_separate_tx_channels ? 1 : 0);
3226e173d3bSMartin Habets 		efx->n_rx_channels = 1;
3236e173d3bSMartin Habets 		efx->n_tx_channels = 1;
324974bb793SÍñigo Huguet 		efx->tx_channel_offset = efx_siena_separate_tx_channels ? 1 : 0;
3256e173d3bSMartin Habets 		efx->n_xdp_channels = 0;
3266e173d3bSMartin Habets 		efx->xdp_channel_offset = efx->n_channels;
327*e84a1e1eSÍñigo Huguet 		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
3286e173d3bSMartin Habets 		efx->legacy_irq = efx->pci_dev->irq;
3296e173d3bSMartin Habets 	}
3306e173d3bSMartin Habets 
3316e173d3bSMartin Habets 	/* Assign extra channels if possible, before XDP channels */
3326e173d3bSMartin Habets 	efx->n_extra_tx_channels = 0;
3336e173d3bSMartin Habets 	j = efx->xdp_channel_offset;
3346e173d3bSMartin Habets 	for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
3356e173d3bSMartin Habets 		if (!efx->extra_channel_type[i])
3366e173d3bSMartin Habets 			continue;
3376e173d3bSMartin Habets 		if (j <= efx->tx_channel_offset + efx->n_tx_channels) {
3386e173d3bSMartin Habets 			efx->extra_channel_type[i]->handle_no_channel(efx);
3396e173d3bSMartin Habets 		} else {
3406e173d3bSMartin Habets 			--j;
3416e173d3bSMartin Habets 			efx_get_channel(efx, j)->type =
3426e173d3bSMartin Habets 				efx->extra_channel_type[i];
3436e173d3bSMartin Habets 			if (efx_channel_has_tx_queues(efx_get_channel(efx, j)))
3446e173d3bSMartin Habets 				efx->n_extra_tx_channels++;
3456e173d3bSMartin Habets 		}
3466e173d3bSMartin Habets 	}
3476e173d3bSMartin Habets 
3486e173d3bSMartin Habets 	rss_spread = efx->n_rx_channels;
3496e173d3bSMartin Habets 	/* RSS might be usable on VFs even if it is disabled on the PF */
350dfb1cfbdSMartin Habets #ifdef CONFIG_SFC_SIENA_SRIOV
3516e173d3bSMartin Habets 	if (efx->type->sriov_wanted) {
3526e173d3bSMartin Habets 		efx->rss_spread = ((rss_spread > 1 ||
3536e173d3bSMartin Habets 				    !efx->type->sriov_wanted(efx)) ?
3546e173d3bSMartin Habets 				   rss_spread : efx_vf_size(efx));
3556e173d3bSMartin Habets 		return 0;
3566e173d3bSMartin Habets 	}
3576e173d3bSMartin Habets #endif
3586e173d3bSMartin Habets 	efx->rss_spread = rss_spread;
3596e173d3bSMartin Habets 
3606e173d3bSMartin Habets 	return 0;
3616e173d3bSMartin Habets }
3626e173d3bSMartin Habets 
3636e173d3bSMartin Habets #if defined(CONFIG_SMP)
efx_siena_set_interrupt_affinity(struct efx_nic * efx)36471ad88f6SMartin Habets void efx_siena_set_interrupt_affinity(struct efx_nic *efx)
3656e173d3bSMartin Habets {
3666e173d3bSMartin Habets 	const struct cpumask *numa_mask = cpumask_of_pcibus(efx->pci_dev->bus);
3676e173d3bSMartin Habets 	struct efx_channel *channel;
3686e173d3bSMartin Habets 	unsigned int cpu;
3696e173d3bSMartin Habets 
3706e173d3bSMartin Habets 	/* If no online CPUs in local node, fallback to any online CPU */
3716e173d3bSMartin Habets 	if (cpumask_first_and(cpu_online_mask, numa_mask) >= nr_cpu_ids)
3726e173d3bSMartin Habets 		numa_mask = cpu_online_mask;
3736e173d3bSMartin Habets 
3746e173d3bSMartin Habets 	cpu = -1;
3756e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
3766e173d3bSMartin Habets 		cpu = cpumask_next_and(cpu, cpu_online_mask, numa_mask);
3776e173d3bSMartin Habets 		if (cpu >= nr_cpu_ids)
3786e173d3bSMartin Habets 			cpu = cpumask_first_and(cpu_online_mask, numa_mask);
3796e173d3bSMartin Habets 		irq_set_affinity_hint(channel->irq, cpumask_of(cpu));
3806e173d3bSMartin Habets 	}
3816e173d3bSMartin Habets }
3826e173d3bSMartin Habets 
efx_siena_clear_interrupt_affinity(struct efx_nic * efx)38371ad88f6SMartin Habets void efx_siena_clear_interrupt_affinity(struct efx_nic *efx)
3846e173d3bSMartin Habets {
3856e173d3bSMartin Habets 	struct efx_channel *channel;
3866e173d3bSMartin Habets 
3876e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
3886e173d3bSMartin Habets 		irq_set_affinity_hint(channel->irq, NULL);
3896e173d3bSMartin Habets }
3906e173d3bSMartin Habets #else
3916e173d3bSMartin Habets void
efx_siena_set_interrupt_affinity(struct efx_nic * efx __always_unused)39271ad88f6SMartin Habets efx_siena_set_interrupt_affinity(struct efx_nic *efx __always_unused)
3936e173d3bSMartin Habets {
3946e173d3bSMartin Habets }
3956e173d3bSMartin Habets 
3966e173d3bSMartin Habets void
efx_siena_clear_interrupt_affinity(struct efx_nic * efx __always_unused)39771ad88f6SMartin Habets efx_siena_clear_interrupt_affinity(struct efx_nic *efx __always_unused)
3986e173d3bSMartin Habets {
3996e173d3bSMartin Habets }
4006e173d3bSMartin Habets #endif /* CONFIG_SMP */
4016e173d3bSMartin Habets 
efx_siena_remove_interrupts(struct efx_nic * efx)40271ad88f6SMartin Habets void efx_siena_remove_interrupts(struct efx_nic *efx)
4036e173d3bSMartin Habets {
4046e173d3bSMartin Habets 	struct efx_channel *channel;
4056e173d3bSMartin Habets 
4066e173d3bSMartin Habets 	/* Remove MSI/MSI-X interrupts */
4076e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
4086e173d3bSMartin Habets 		channel->irq = 0;
4096e173d3bSMartin Habets 	pci_disable_msi(efx->pci_dev);
4106e173d3bSMartin Habets 	pci_disable_msix(efx->pci_dev);
4116e173d3bSMartin Habets 
4126e173d3bSMartin Habets 	/* Remove legacy interrupt */
4136e173d3bSMartin Habets 	efx->legacy_irq = 0;
4146e173d3bSMartin Habets }
4156e173d3bSMartin Habets 
4166e173d3bSMartin Habets /***************
4176e173d3bSMartin Habets  * EVENT QUEUES
4186e173d3bSMartin Habets  ***************/
4196e173d3bSMartin Habets 
4206e173d3bSMartin Habets /* Create event queue
4216e173d3bSMartin Habets  * Event queue memory allocations are done only once.  If the channel
4226e173d3bSMartin Habets  * is reset, the memory buffer will be reused; this guards against
4236e173d3bSMartin Habets  * errors during channel reset and also simplifies interrupt handling.
4246e173d3bSMartin Habets  */
efx_probe_eventq(struct efx_channel * channel)42571ad88f6SMartin Habets static int efx_probe_eventq(struct efx_channel *channel)
4266e173d3bSMartin Habets {
4276e173d3bSMartin Habets 	struct efx_nic *efx = channel->efx;
4286e173d3bSMartin Habets 	unsigned long entries;
4296e173d3bSMartin Habets 
4306e173d3bSMartin Habets 	netif_dbg(efx, probe, efx->net_dev,
4316e173d3bSMartin Habets 		  "chan %d create event queue\n", channel->channel);
4326e173d3bSMartin Habets 
4336e173d3bSMartin Habets 	/* Build an event queue with room for one event per tx and rx buffer,
4346e173d3bSMartin Habets 	 * plus some extra for link state events and MCDI completions.
4356e173d3bSMartin Habets 	 */
4366e173d3bSMartin Habets 	entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128);
4376e173d3bSMartin Habets 	EFX_WARN_ON_PARANOID(entries > EFX_MAX_EVQ_SIZE);
4386e173d3bSMartin Habets 	channel->eventq_mask = max(entries, EFX_MIN_EVQ_SIZE) - 1;
4396e173d3bSMartin Habets 
4406e173d3bSMartin Habets 	return efx_nic_probe_eventq(channel);
4416e173d3bSMartin Habets }
4426e173d3bSMartin Habets 
4436e173d3bSMartin Habets /* Prepare channel's event queue */
efx_init_eventq(struct efx_channel * channel)44471ad88f6SMartin Habets static int efx_init_eventq(struct efx_channel *channel)
4456e173d3bSMartin Habets {
4466e173d3bSMartin Habets 	struct efx_nic *efx = channel->efx;
4476e173d3bSMartin Habets 	int rc;
4486e173d3bSMartin Habets 
4496e173d3bSMartin Habets 	EFX_WARN_ON_PARANOID(channel->eventq_init);
4506e173d3bSMartin Habets 
4516e173d3bSMartin Habets 	netif_dbg(efx, drv, efx->net_dev,
4526e173d3bSMartin Habets 		  "chan %d init event queue\n", channel->channel);
4536e173d3bSMartin Habets 
4546e173d3bSMartin Habets 	rc = efx_nic_init_eventq(channel);
4556e173d3bSMartin Habets 	if (rc == 0) {
4566e173d3bSMartin Habets 		efx->type->push_irq_moderation(channel);
4576e173d3bSMartin Habets 		channel->eventq_read_ptr = 0;
4586e173d3bSMartin Habets 		channel->eventq_init = true;
4596e173d3bSMartin Habets 	}
4606e173d3bSMartin Habets 	return rc;
4616e173d3bSMartin Habets }
4626e173d3bSMartin Habets 
4636e173d3bSMartin Habets /* Enable event queue processing and NAPI */
efx_siena_start_eventq(struct efx_channel * channel)46471ad88f6SMartin Habets void efx_siena_start_eventq(struct efx_channel *channel)
4656e173d3bSMartin Habets {
4666e173d3bSMartin Habets 	netif_dbg(channel->efx, ifup, channel->efx->net_dev,
4676e173d3bSMartin Habets 		  "chan %d start event queue\n", channel->channel);
4686e173d3bSMartin Habets 
4696e173d3bSMartin Habets 	/* Make sure the NAPI handler sees the enabled flag set */
4706e173d3bSMartin Habets 	channel->enabled = true;
4716e173d3bSMartin Habets 	smp_wmb();
4726e173d3bSMartin Habets 
4736e173d3bSMartin Habets 	napi_enable(&channel->napi_str);
4746e173d3bSMartin Habets 	efx_nic_eventq_read_ack(channel);
4756e173d3bSMartin Habets }
4766e173d3bSMartin Habets 
4776e173d3bSMartin Habets /* Disable event queue processing and NAPI */
efx_siena_stop_eventq(struct efx_channel * channel)47871ad88f6SMartin Habets void efx_siena_stop_eventq(struct efx_channel *channel)
4796e173d3bSMartin Habets {
4806e173d3bSMartin Habets 	if (!channel->enabled)
4816e173d3bSMartin Habets 		return;
4826e173d3bSMartin Habets 
4836e173d3bSMartin Habets 	napi_disable(&channel->napi_str);
4846e173d3bSMartin Habets 	channel->enabled = false;
4856e173d3bSMartin Habets }
4866e173d3bSMartin Habets 
efx_fini_eventq(struct efx_channel * channel)48771ad88f6SMartin Habets static void efx_fini_eventq(struct efx_channel *channel)
4886e173d3bSMartin Habets {
4896e173d3bSMartin Habets 	if (!channel->eventq_init)
4906e173d3bSMartin Habets 		return;
4916e173d3bSMartin Habets 
4926e173d3bSMartin Habets 	netif_dbg(channel->efx, drv, channel->efx->net_dev,
4936e173d3bSMartin Habets 		  "chan %d fini event queue\n", channel->channel);
4946e173d3bSMartin Habets 
4956e173d3bSMartin Habets 	efx_nic_fini_eventq(channel);
4966e173d3bSMartin Habets 	channel->eventq_init = false;
4976e173d3bSMartin Habets }
4986e173d3bSMartin Habets 
efx_remove_eventq(struct efx_channel * channel)49971ad88f6SMartin Habets static void efx_remove_eventq(struct efx_channel *channel)
5006e173d3bSMartin Habets {
5016e173d3bSMartin Habets 	netif_dbg(channel->efx, drv, channel->efx->net_dev,
5026e173d3bSMartin Habets 		  "chan %d remove event queue\n", channel->channel);
5036e173d3bSMartin Habets 
5046e173d3bSMartin Habets 	efx_nic_remove_eventq(channel);
5056e173d3bSMartin Habets }
5066e173d3bSMartin Habets 
5076e173d3bSMartin Habets /**************************************************************************
5086e173d3bSMartin Habets  *
5096e173d3bSMartin Habets  * Channel handling
5106e173d3bSMartin Habets  *
5116e173d3bSMartin Habets  *************************************************************************/
5126e173d3bSMartin Habets 
5136e173d3bSMartin Habets #ifdef CONFIG_RFS_ACCEL
efx_filter_rfs_expire(struct work_struct * data)5146e173d3bSMartin Habets static void efx_filter_rfs_expire(struct work_struct *data)
5156e173d3bSMartin Habets {
5166e173d3bSMartin Habets 	struct delayed_work *dwork = to_delayed_work(data);
5176e173d3bSMartin Habets 	struct efx_channel *channel;
5186e173d3bSMartin Habets 	unsigned int time, quota;
5196e173d3bSMartin Habets 
5206e173d3bSMartin Habets 	channel = container_of(dwork, struct efx_channel, filter_work);
5216e173d3bSMartin Habets 	time = jiffies - channel->rfs_last_expiry;
5226e173d3bSMartin Habets 	quota = channel->rfs_filter_count * time / (30 * HZ);
5237f9e4b2aSMartin Habets 	if (quota >= 20 && __efx_siena_filter_rfs_expire(channel,
5247f9e4b2aSMartin Habets 					min(channel->rfs_filter_count, quota)))
5256e173d3bSMartin Habets 		channel->rfs_last_expiry += time;
5266e173d3bSMartin Habets 	/* Ensure we do more work eventually even if NAPI poll is not happening */
5276e173d3bSMartin Habets 	schedule_delayed_work(dwork, 30 * HZ);
5286e173d3bSMartin Habets }
5296e173d3bSMartin Habets #endif
5306e173d3bSMartin Habets 
5316e173d3bSMartin Habets /* Allocate and initialise a channel structure. */
efx_alloc_channel(struct efx_nic * efx,int i)5326e173d3bSMartin Habets static struct efx_channel *efx_alloc_channel(struct efx_nic *efx, int i)
5336e173d3bSMartin Habets {
5346e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
5356e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
5366e173d3bSMartin Habets 	struct efx_channel *channel;
5376e173d3bSMartin Habets 	int j;
5386e173d3bSMartin Habets 
5396e173d3bSMartin Habets 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
5406e173d3bSMartin Habets 	if (!channel)
5416e173d3bSMartin Habets 		return NULL;
5426e173d3bSMartin Habets 
5436e173d3bSMartin Habets 	channel->efx = efx;
5446e173d3bSMartin Habets 	channel->channel = i;
5456e173d3bSMartin Habets 	channel->type = &efx_default_channel_type;
5466e173d3bSMartin Habets 
5476e173d3bSMartin Habets 	for (j = 0; j < EFX_MAX_TXQ_PER_CHANNEL; j++) {
5486e173d3bSMartin Habets 		tx_queue = &channel->tx_queue[j];
5496e173d3bSMartin Habets 		tx_queue->efx = efx;
5506e173d3bSMartin Habets 		tx_queue->queue = -1;
5516e173d3bSMartin Habets 		tx_queue->label = j;
5526e173d3bSMartin Habets 		tx_queue->channel = channel;
5536e173d3bSMartin Habets 	}
5546e173d3bSMartin Habets 
5556e173d3bSMartin Habets #ifdef CONFIG_RFS_ACCEL
5566e173d3bSMartin Habets 	INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
5576e173d3bSMartin Habets #endif
5586e173d3bSMartin Habets 
5596e173d3bSMartin Habets 	rx_queue = &channel->rx_queue;
5606e173d3bSMartin Habets 	rx_queue->efx = efx;
5617f9e4b2aSMartin Habets 	timer_setup(&rx_queue->slow_fill, efx_siena_rx_slow_fill, 0);
5626e173d3bSMartin Habets 
5636e173d3bSMartin Habets 	return channel;
5646e173d3bSMartin Habets }
5656e173d3bSMartin Habets 
efx_siena_init_channels(struct efx_nic * efx)56671ad88f6SMartin Habets int efx_siena_init_channels(struct efx_nic *efx)
5676e173d3bSMartin Habets {
5686e173d3bSMartin Habets 	unsigned int i;
5696e173d3bSMartin Habets 
5706e173d3bSMartin Habets 	for (i = 0; i < EFX_MAX_CHANNELS; i++) {
5716e173d3bSMartin Habets 		efx->channel[i] = efx_alloc_channel(efx, i);
5726e173d3bSMartin Habets 		if (!efx->channel[i])
5736e173d3bSMartin Habets 			return -ENOMEM;
5746e173d3bSMartin Habets 		efx->msi_context[i].efx = efx;
5756e173d3bSMartin Habets 		efx->msi_context[i].index = i;
5766e173d3bSMartin Habets 	}
5776e173d3bSMartin Habets 
5786e173d3bSMartin Habets 	/* Higher numbered interrupt modes are less capable! */
5796e173d3bSMartin Habets 	efx->interrupt_mode = min(efx->type->min_interrupt_mode,
58071ad88f6SMartin Habets 				  efx_siena_interrupt_mode);
5816e173d3bSMartin Habets 
5826e173d3bSMartin Habets 	efx->max_channels = EFX_MAX_CHANNELS;
5836e173d3bSMartin Habets 	efx->max_tx_channels = EFX_MAX_CHANNELS;
5846e173d3bSMartin Habets 
5856e173d3bSMartin Habets 	return 0;
5866e173d3bSMartin Habets }
5876e173d3bSMartin Habets 
efx_siena_fini_channels(struct efx_nic * efx)58871ad88f6SMartin Habets void efx_siena_fini_channels(struct efx_nic *efx)
5896e173d3bSMartin Habets {
5906e173d3bSMartin Habets 	unsigned int i;
5916e173d3bSMartin Habets 
5926e173d3bSMartin Habets 	for (i = 0; i < EFX_MAX_CHANNELS; i++)
5936e173d3bSMartin Habets 		if (efx->channel[i]) {
5946e173d3bSMartin Habets 			kfree(efx->channel[i]);
5956e173d3bSMartin Habets 			efx->channel[i] = NULL;
5966e173d3bSMartin Habets 		}
5976e173d3bSMartin Habets }
5986e173d3bSMartin Habets 
5996e173d3bSMartin Habets /* Allocate and initialise a channel structure, copying parameters
6006e173d3bSMartin Habets  * (but not resources) from an old channel structure.
6016e173d3bSMartin Habets  */
6026e173d3bSMartin Habets static
efx_copy_channel(const struct efx_channel * old_channel)6036e173d3bSMartin Habets struct efx_channel *efx_copy_channel(const struct efx_channel *old_channel)
6046e173d3bSMartin Habets {
6056e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
6066e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
6076e173d3bSMartin Habets 	struct efx_channel *channel;
6086e173d3bSMartin Habets 	int j;
6096e173d3bSMartin Habets 
6106e173d3bSMartin Habets 	channel = kmalloc(sizeof(*channel), GFP_KERNEL);
6116e173d3bSMartin Habets 	if (!channel)
6126e173d3bSMartin Habets 		return NULL;
6136e173d3bSMartin Habets 
6146e173d3bSMartin Habets 	*channel = *old_channel;
6156e173d3bSMartin Habets 
6166e173d3bSMartin Habets 	channel->napi_dev = NULL;
6176e173d3bSMartin Habets 	INIT_HLIST_NODE(&channel->napi_str.napi_hash_node);
6186e173d3bSMartin Habets 	channel->napi_str.napi_id = 0;
6196e173d3bSMartin Habets 	channel->napi_str.state = 0;
6206e173d3bSMartin Habets 	memset(&channel->eventq, 0, sizeof(channel->eventq));
6216e173d3bSMartin Habets 
6226e173d3bSMartin Habets 	for (j = 0; j < EFX_MAX_TXQ_PER_CHANNEL; j++) {
6236e173d3bSMartin Habets 		tx_queue = &channel->tx_queue[j];
6246e173d3bSMartin Habets 		if (tx_queue->channel)
6256e173d3bSMartin Habets 			tx_queue->channel = channel;
6266e173d3bSMartin Habets 		tx_queue->buffer = NULL;
6276e173d3bSMartin Habets 		tx_queue->cb_page = NULL;
6286e173d3bSMartin Habets 		memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
6296e173d3bSMartin Habets 	}
6306e173d3bSMartin Habets 
6316e173d3bSMartin Habets 	rx_queue = &channel->rx_queue;
6326e173d3bSMartin Habets 	rx_queue->buffer = NULL;
6336e173d3bSMartin Habets 	memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
6347f9e4b2aSMartin Habets 	timer_setup(&rx_queue->slow_fill, efx_siena_rx_slow_fill, 0);
6356e173d3bSMartin Habets #ifdef CONFIG_RFS_ACCEL
6366e173d3bSMartin Habets 	INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
6376e173d3bSMartin Habets #endif
6386e173d3bSMartin Habets 
6396e173d3bSMartin Habets 	return channel;
6406e173d3bSMartin Habets }
6416e173d3bSMartin Habets 
efx_probe_channel(struct efx_channel * channel)6426e173d3bSMartin Habets static int efx_probe_channel(struct efx_channel *channel)
6436e173d3bSMartin Habets {
6446e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
6456e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
6466e173d3bSMartin Habets 	int rc;
6476e173d3bSMartin Habets 
6486e173d3bSMartin Habets 	netif_dbg(channel->efx, probe, channel->efx->net_dev,
6496e173d3bSMartin Habets 		  "creating channel %d\n", channel->channel);
6506e173d3bSMartin Habets 
6516e173d3bSMartin Habets 	rc = channel->type->pre_probe(channel);
6526e173d3bSMartin Habets 	if (rc)
6536e173d3bSMartin Habets 		goto fail;
6546e173d3bSMartin Habets 
6556e173d3bSMartin Habets 	rc = efx_probe_eventq(channel);
6566e173d3bSMartin Habets 	if (rc)
6576e173d3bSMartin Habets 		goto fail;
6586e173d3bSMartin Habets 
6596e173d3bSMartin Habets 	efx_for_each_channel_tx_queue(tx_queue, channel) {
6607f9e4b2aSMartin Habets 		rc = efx_siena_probe_tx_queue(tx_queue);
6616e173d3bSMartin Habets 		if (rc)
6626e173d3bSMartin Habets 			goto fail;
6636e173d3bSMartin Habets 	}
6646e173d3bSMartin Habets 
6656e173d3bSMartin Habets 	efx_for_each_channel_rx_queue(rx_queue, channel) {
6667f9e4b2aSMartin Habets 		rc = efx_siena_probe_rx_queue(rx_queue);
6676e173d3bSMartin Habets 		if (rc)
6686e173d3bSMartin Habets 			goto fail;
6696e173d3bSMartin Habets 	}
6706e173d3bSMartin Habets 
6716e173d3bSMartin Habets 	channel->rx_list = NULL;
6726e173d3bSMartin Habets 
6736e173d3bSMartin Habets 	return 0;
6746e173d3bSMartin Habets 
6756e173d3bSMartin Habets fail:
67671ad88f6SMartin Habets 	efx_siena_remove_channel(channel);
6776e173d3bSMartin Habets 	return rc;
6786e173d3bSMartin Habets }
6796e173d3bSMartin Habets 
efx_get_channel_name(struct efx_channel * channel,char * buf,size_t len)6806e173d3bSMartin Habets static void efx_get_channel_name(struct efx_channel *channel, char *buf,
6816e173d3bSMartin Habets 				 size_t len)
6826e173d3bSMartin Habets {
6836e173d3bSMartin Habets 	struct efx_nic *efx = channel->efx;
6846e173d3bSMartin Habets 	const char *type;
6856e173d3bSMartin Habets 	int number;
6866e173d3bSMartin Habets 
6876e173d3bSMartin Habets 	number = channel->channel;
6886e173d3bSMartin Habets 
6896e173d3bSMartin Habets 	if (number >= efx->xdp_channel_offset &&
6906e173d3bSMartin Habets 	    !WARN_ON_ONCE(!efx->n_xdp_channels)) {
6916e173d3bSMartin Habets 		type = "-xdp";
6926e173d3bSMartin Habets 		number -= efx->xdp_channel_offset;
6936e173d3bSMartin Habets 	} else if (efx->tx_channel_offset == 0) {
6946e173d3bSMartin Habets 		type = "";
6956e173d3bSMartin Habets 	} else if (number < efx->tx_channel_offset) {
6966e173d3bSMartin Habets 		type = "-rx";
6976e173d3bSMartin Habets 	} else {
6986e173d3bSMartin Habets 		type = "-tx";
6996e173d3bSMartin Habets 		number -= efx->tx_channel_offset;
7006e173d3bSMartin Habets 	}
7016e173d3bSMartin Habets 	snprintf(buf, len, "%s%s-%d", efx->name, type, number);
7026e173d3bSMartin Habets }
7036e173d3bSMartin Habets 
efx_siena_set_channel_names(struct efx_nic * efx)70471ad88f6SMartin Habets void efx_siena_set_channel_names(struct efx_nic *efx)
7056e173d3bSMartin Habets {
7066e173d3bSMartin Habets 	struct efx_channel *channel;
7076e173d3bSMartin Habets 
7086e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
7096e173d3bSMartin Habets 		channel->type->get_name(channel,
7106e173d3bSMartin Habets 					efx->msi_context[channel->channel].name,
7116e173d3bSMartin Habets 					sizeof(efx->msi_context[0].name));
7126e173d3bSMartin Habets }
7136e173d3bSMartin Habets 
efx_siena_probe_channels(struct efx_nic * efx)71471ad88f6SMartin Habets int efx_siena_probe_channels(struct efx_nic *efx)
7156e173d3bSMartin Habets {
7166e173d3bSMartin Habets 	struct efx_channel *channel;
7176e173d3bSMartin Habets 	int rc;
7186e173d3bSMartin Habets 
7196e173d3bSMartin Habets 	/* Restart special buffer allocation */
7206e173d3bSMartin Habets 	efx->next_buffer_table = 0;
7216e173d3bSMartin Habets 
7226e173d3bSMartin Habets 	/* Probe channels in reverse, so that any 'extra' channels
7236e173d3bSMartin Habets 	 * use the start of the buffer table. This allows the traffic
7246e173d3bSMartin Habets 	 * channels to be resized without moving them or wasting the
7256e173d3bSMartin Habets 	 * entries before them.
7266e173d3bSMartin Habets 	 */
7276e173d3bSMartin Habets 	efx_for_each_channel_rev(channel, efx) {
7286e173d3bSMartin Habets 		rc = efx_probe_channel(channel);
7296e173d3bSMartin Habets 		if (rc) {
7306e173d3bSMartin Habets 			netif_err(efx, probe, efx->net_dev,
7316e173d3bSMartin Habets 				  "failed to create channel %d\n",
7326e173d3bSMartin Habets 				  channel->channel);
7336e173d3bSMartin Habets 			goto fail;
7346e173d3bSMartin Habets 		}
7356e173d3bSMartin Habets 	}
73671ad88f6SMartin Habets 	efx_siena_set_channel_names(efx);
7376e173d3bSMartin Habets 
7386e173d3bSMartin Habets 	return 0;
7396e173d3bSMartin Habets 
7406e173d3bSMartin Habets fail:
74171ad88f6SMartin Habets 	efx_siena_remove_channels(efx);
7426e173d3bSMartin Habets 	return rc;
7436e173d3bSMartin Habets }
7446e173d3bSMartin Habets 
efx_siena_remove_channel(struct efx_channel * channel)74571ad88f6SMartin Habets void efx_siena_remove_channel(struct efx_channel *channel)
7466e173d3bSMartin Habets {
7476e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
7486e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
7496e173d3bSMartin Habets 
7506e173d3bSMartin Habets 	netif_dbg(channel->efx, drv, channel->efx->net_dev,
7516e173d3bSMartin Habets 		  "destroy chan %d\n", channel->channel);
7526e173d3bSMartin Habets 
7536e173d3bSMartin Habets 	efx_for_each_channel_rx_queue(rx_queue, channel)
7547f9e4b2aSMartin Habets 		efx_siena_remove_rx_queue(rx_queue);
7556e173d3bSMartin Habets 	efx_for_each_channel_tx_queue(tx_queue, channel)
7567f9e4b2aSMartin Habets 		efx_siena_remove_tx_queue(tx_queue);
7576e173d3bSMartin Habets 	efx_remove_eventq(channel);
7586e173d3bSMartin Habets 	channel->type->post_remove(channel);
7596e173d3bSMartin Habets }
7606e173d3bSMartin Habets 
efx_siena_remove_channels(struct efx_nic * efx)76171ad88f6SMartin Habets void efx_siena_remove_channels(struct efx_nic *efx)
7626e173d3bSMartin Habets {
7636e173d3bSMartin Habets 	struct efx_channel *channel;
7646e173d3bSMartin Habets 
7656e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
76671ad88f6SMartin Habets 		efx_siena_remove_channel(channel);
7676e173d3bSMartin Habets 
7686e173d3bSMartin Habets 	kfree(efx->xdp_tx_queues);
7696e173d3bSMartin Habets }
7706e173d3bSMartin Habets 
efx_set_xdp_tx_queue(struct efx_nic * efx,int xdp_queue_number,struct efx_tx_queue * tx_queue)7716e173d3bSMartin Habets static int efx_set_xdp_tx_queue(struct efx_nic *efx, int xdp_queue_number,
7726e173d3bSMartin Habets 				struct efx_tx_queue *tx_queue)
7736e173d3bSMartin Habets {
7746e173d3bSMartin Habets 	if (xdp_queue_number >= efx->xdp_tx_queue_count)
7756e173d3bSMartin Habets 		return -EINVAL;
7766e173d3bSMartin Habets 
7776e173d3bSMartin Habets 	netif_dbg(efx, drv, efx->net_dev,
7786e173d3bSMartin Habets 		  "Channel %u TXQ %u is XDP %u, HW %u\n",
7796e173d3bSMartin Habets 		  tx_queue->channel->channel, tx_queue->label,
7806e173d3bSMartin Habets 		  xdp_queue_number, tx_queue->queue);
7816e173d3bSMartin Habets 	efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
7826e173d3bSMartin Habets 	return 0;
7836e173d3bSMartin Habets }
7846e173d3bSMartin Habets 
efx_set_xdp_channels(struct efx_nic * efx)7856e173d3bSMartin Habets static void efx_set_xdp_channels(struct efx_nic *efx)
7866e173d3bSMartin Habets {
7876e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
7886e173d3bSMartin Habets 	struct efx_channel *channel;
7896e173d3bSMartin Habets 	unsigned int next_queue = 0;
7906e173d3bSMartin Habets 	int xdp_queue_number = 0;
7916e173d3bSMartin Habets 	int rc;
7926e173d3bSMartin Habets 
7936e173d3bSMartin Habets 	/* We need to mark which channels really have RX and TX
7946e173d3bSMartin Habets 	 * queues, and adjust the TX queue numbers if we have separate
7956e173d3bSMartin Habets 	 * RX-only and TX-only channels.
7966e173d3bSMartin Habets 	 */
7976e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
7986e173d3bSMartin Habets 		if (channel->channel < efx->tx_channel_offset)
7996e173d3bSMartin Habets 			continue;
8006e173d3bSMartin Habets 
8016e173d3bSMartin Habets 		if (efx_channel_is_xdp_tx(channel)) {
8026e173d3bSMartin Habets 			efx_for_each_channel_tx_queue(tx_queue, channel) {
8036e173d3bSMartin Habets 				tx_queue->queue = next_queue++;
8046e173d3bSMartin Habets 				rc = efx_set_xdp_tx_queue(efx, xdp_queue_number,
8056e173d3bSMartin Habets 							  tx_queue);
8066e173d3bSMartin Habets 				if (rc == 0)
8076e173d3bSMartin Habets 					xdp_queue_number++;
8086e173d3bSMartin Habets 			}
8096e173d3bSMartin Habets 		} else {
8106e173d3bSMartin Habets 			efx_for_each_channel_tx_queue(tx_queue, channel) {
8116e173d3bSMartin Habets 				tx_queue->queue = next_queue++;
8126e173d3bSMartin Habets 				netif_dbg(efx, drv, efx->net_dev,
8136e173d3bSMartin Habets 					  "Channel %u TXQ %u is HW %u\n",
8146e173d3bSMartin Habets 					  channel->channel, tx_queue->label,
8156e173d3bSMartin Habets 					  tx_queue->queue);
8166e173d3bSMartin Habets 			}
8176e173d3bSMartin Habets 
8186e173d3bSMartin Habets 			/* If XDP is borrowing queues from net stack, it must
8196e173d3bSMartin Habets 			 * use the queue with no csum offload, which is the
8206e173d3bSMartin Habets 			 * first one of the channel
8216e173d3bSMartin Habets 			 * (note: tx_queue_by_type is not initialized yet)
8226e173d3bSMartin Habets 			 */
8236e173d3bSMartin Habets 			if (efx->xdp_txq_queues_mode ==
8246e173d3bSMartin Habets 			    EFX_XDP_TX_QUEUES_BORROWED) {
8256e173d3bSMartin Habets 				tx_queue = &channel->tx_queue[0];
8266e173d3bSMartin Habets 				rc = efx_set_xdp_tx_queue(efx, xdp_queue_number,
8276e173d3bSMartin Habets 							  tx_queue);
8286e173d3bSMartin Habets 				if (rc == 0)
8296e173d3bSMartin Habets 					xdp_queue_number++;
8306e173d3bSMartin Habets 			}
8316e173d3bSMartin Habets 		}
8326e173d3bSMartin Habets 	}
8336e173d3bSMartin Habets 	WARN_ON(efx->xdp_txq_queues_mode == EFX_XDP_TX_QUEUES_DEDICATED &&
8346e173d3bSMartin Habets 		xdp_queue_number != efx->xdp_tx_queue_count);
8356e173d3bSMartin Habets 	WARN_ON(efx->xdp_txq_queues_mode != EFX_XDP_TX_QUEUES_DEDICATED &&
8366e173d3bSMartin Habets 		xdp_queue_number > efx->xdp_tx_queue_count);
8376e173d3bSMartin Habets 
8386e173d3bSMartin Habets 	/* If we have more CPUs than assigned XDP TX queues, assign the already
8396e173d3bSMartin Habets 	 * existing queues to the exceeding CPUs
8406e173d3bSMartin Habets 	 */
8416e173d3bSMartin Habets 	next_queue = 0;
8426e173d3bSMartin Habets 	while (xdp_queue_number < efx->xdp_tx_queue_count) {
8436e173d3bSMartin Habets 		tx_queue = efx->xdp_tx_queues[next_queue++];
8446e173d3bSMartin Habets 		rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, tx_queue);
8456e173d3bSMartin Habets 		if (rc == 0)
8466e173d3bSMartin Habets 			xdp_queue_number++;
8476e173d3bSMartin Habets 	}
8486e173d3bSMartin Habets }
8496e173d3bSMartin Habets 
85071ad88f6SMartin Habets static int efx_soft_enable_interrupts(struct efx_nic *efx);
85171ad88f6SMartin Habets static void efx_soft_disable_interrupts(struct efx_nic *efx);
85271ad88f6SMartin Habets static void efx_init_napi_channel(struct efx_channel *channel);
85371ad88f6SMartin Habets static void efx_fini_napi_channel(struct efx_channel *channel);
85471ad88f6SMartin Habets 
efx_siena_realloc_channels(struct efx_nic * efx,u32 rxq_entries,u32 txq_entries)85571ad88f6SMartin Habets int efx_siena_realloc_channels(struct efx_nic *efx, u32 rxq_entries,
85671ad88f6SMartin Habets 			       u32 txq_entries)
8576e173d3bSMartin Habets {
8586e173d3bSMartin Habets 	struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
8596e173d3bSMartin Habets 	unsigned int i, next_buffer_table = 0;
8606e173d3bSMartin Habets 	u32 old_rxq_entries, old_txq_entries;
8616e173d3bSMartin Habets 	int rc, rc2;
8626e173d3bSMartin Habets 
8636e173d3bSMartin Habets 	rc = efx_check_disabled(efx);
8646e173d3bSMartin Habets 	if (rc)
8656e173d3bSMartin Habets 		return rc;
8666e173d3bSMartin Habets 
8676e173d3bSMartin Habets 	/* Not all channels should be reallocated. We must avoid
8686e173d3bSMartin Habets 	 * reallocating their buffer table entries.
8696e173d3bSMartin Habets 	 */
8706e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
8716e173d3bSMartin Habets 		struct efx_rx_queue *rx_queue;
8726e173d3bSMartin Habets 		struct efx_tx_queue *tx_queue;
8736e173d3bSMartin Habets 
8746e173d3bSMartin Habets 		if (channel->type->copy)
8756e173d3bSMartin Habets 			continue;
8766e173d3bSMartin Habets 		next_buffer_table = max(next_buffer_table,
8776e173d3bSMartin Habets 					channel->eventq.index +
8786e173d3bSMartin Habets 					channel->eventq.entries);
8796e173d3bSMartin Habets 		efx_for_each_channel_rx_queue(rx_queue, channel)
8806e173d3bSMartin Habets 			next_buffer_table = max(next_buffer_table,
8816e173d3bSMartin Habets 						rx_queue->rxd.index +
8826e173d3bSMartin Habets 						rx_queue->rxd.entries);
8836e173d3bSMartin Habets 		efx_for_each_channel_tx_queue(tx_queue, channel)
8846e173d3bSMartin Habets 			next_buffer_table = max(next_buffer_table,
8856e173d3bSMartin Habets 						tx_queue->txd.index +
8866e173d3bSMartin Habets 						tx_queue->txd.entries);
8876e173d3bSMartin Habets 	}
8886e173d3bSMartin Habets 
8896e173d3bSMartin Habets 	efx_device_detach_sync(efx);
89071ad88f6SMartin Habets 	efx_siena_stop_all(efx);
8916e173d3bSMartin Habets 	efx_soft_disable_interrupts(efx);
8926e173d3bSMartin Habets 
8936e173d3bSMartin Habets 	/* Clone channels (where possible) */
8946e173d3bSMartin Habets 	memset(other_channel, 0, sizeof(other_channel));
8956e173d3bSMartin Habets 	for (i = 0; i < efx->n_channels; i++) {
8966e173d3bSMartin Habets 		channel = efx->channel[i];
8976e173d3bSMartin Habets 		if (channel->type->copy)
8986e173d3bSMartin Habets 			channel = channel->type->copy(channel);
8996e173d3bSMartin Habets 		if (!channel) {
9006e173d3bSMartin Habets 			rc = -ENOMEM;
9016e173d3bSMartin Habets 			goto out;
9026e173d3bSMartin Habets 		}
9036e173d3bSMartin Habets 		other_channel[i] = channel;
9046e173d3bSMartin Habets 	}
9056e173d3bSMartin Habets 
9066e173d3bSMartin Habets 	/* Swap entry counts and channel pointers */
9076e173d3bSMartin Habets 	old_rxq_entries = efx->rxq_entries;
9086e173d3bSMartin Habets 	old_txq_entries = efx->txq_entries;
9096e173d3bSMartin Habets 	efx->rxq_entries = rxq_entries;
9106e173d3bSMartin Habets 	efx->txq_entries = txq_entries;
9116e173d3bSMartin Habets 	for (i = 0; i < efx->n_channels; i++)
9126e173d3bSMartin Habets 		swap(efx->channel[i], other_channel[i]);
9136e173d3bSMartin Habets 
9146e173d3bSMartin Habets 	/* Restart buffer table allocation */
9156e173d3bSMartin Habets 	efx->next_buffer_table = next_buffer_table;
9166e173d3bSMartin Habets 
9176e173d3bSMartin Habets 	for (i = 0; i < efx->n_channels; i++) {
9186e173d3bSMartin Habets 		channel = efx->channel[i];
9196e173d3bSMartin Habets 		if (!channel->type->copy)
9206e173d3bSMartin Habets 			continue;
9216e173d3bSMartin Habets 		rc = efx_probe_channel(channel);
9226e173d3bSMartin Habets 		if (rc)
9236e173d3bSMartin Habets 			goto rollback;
9246e173d3bSMartin Habets 		efx_init_napi_channel(efx->channel[i]);
9256e173d3bSMartin Habets 	}
9266e173d3bSMartin Habets 
9276e173d3bSMartin Habets 	efx_set_xdp_channels(efx);
9286e173d3bSMartin Habets out:
9296e173d3bSMartin Habets 	/* Destroy unused channel structures */
9306e173d3bSMartin Habets 	for (i = 0; i < efx->n_channels; i++) {
9316e173d3bSMartin Habets 		channel = other_channel[i];
9326e173d3bSMartin Habets 		if (channel && channel->type->copy) {
9336e173d3bSMartin Habets 			efx_fini_napi_channel(channel);
93471ad88f6SMartin Habets 			efx_siena_remove_channel(channel);
9356e173d3bSMartin Habets 			kfree(channel);
9366e173d3bSMartin Habets 		}
9376e173d3bSMartin Habets 	}
9386e173d3bSMartin Habets 
9396e173d3bSMartin Habets 	rc2 = efx_soft_enable_interrupts(efx);
9406e173d3bSMartin Habets 	if (rc2) {
9416e173d3bSMartin Habets 		rc = rc ? rc : rc2;
9426e173d3bSMartin Habets 		netif_err(efx, drv, efx->net_dev,
9436e173d3bSMartin Habets 			  "unable to restart interrupts on channel reallocation\n");
94471ad88f6SMartin Habets 		efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE);
9456e173d3bSMartin Habets 	} else {
94671ad88f6SMartin Habets 		efx_siena_start_all(efx);
9476e173d3bSMartin Habets 		efx_device_attach_if_not_resetting(efx);
9486e173d3bSMartin Habets 	}
9496e173d3bSMartin Habets 	return rc;
9506e173d3bSMartin Habets 
9516e173d3bSMartin Habets rollback:
9526e173d3bSMartin Habets 	/* Swap back */
9536e173d3bSMartin Habets 	efx->rxq_entries = old_rxq_entries;
9546e173d3bSMartin Habets 	efx->txq_entries = old_txq_entries;
9556e173d3bSMartin Habets 	for (i = 0; i < efx->n_channels; i++)
9566e173d3bSMartin Habets 		swap(efx->channel[i], other_channel[i]);
9576e173d3bSMartin Habets 	goto out;
9586e173d3bSMartin Habets }
9596e173d3bSMartin Habets 
efx_siena_set_channels(struct efx_nic * efx)96071ad88f6SMartin Habets int efx_siena_set_channels(struct efx_nic *efx)
9616e173d3bSMartin Habets {
9626e173d3bSMartin Habets 	struct efx_channel *channel;
9636e173d3bSMartin Habets 	int rc;
9646e173d3bSMartin Habets 
9656e173d3bSMartin Habets 	if (efx->xdp_tx_queue_count) {
9666e173d3bSMartin Habets 		EFX_WARN_ON_PARANOID(efx->xdp_tx_queues);
9676e173d3bSMartin Habets 
9686e173d3bSMartin Habets 		/* Allocate array for XDP TX queue lookup. */
9696e173d3bSMartin Habets 		efx->xdp_tx_queues = kcalloc(efx->xdp_tx_queue_count,
9706e173d3bSMartin Habets 					     sizeof(*efx->xdp_tx_queues),
9716e173d3bSMartin Habets 					     GFP_KERNEL);
9726e173d3bSMartin Habets 		if (!efx->xdp_tx_queues)
9736e173d3bSMartin Habets 			return -ENOMEM;
9746e173d3bSMartin Habets 	}
9756e173d3bSMartin Habets 
9766e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
9776e173d3bSMartin Habets 		if (channel->channel < efx->n_rx_channels)
9786e173d3bSMartin Habets 			channel->rx_queue.core_index = channel->channel;
9796e173d3bSMartin Habets 		else
9806e173d3bSMartin Habets 			channel->rx_queue.core_index = -1;
9816e173d3bSMartin Habets 	}
9826e173d3bSMartin Habets 
9836e173d3bSMartin Habets 	efx_set_xdp_channels(efx);
9846e173d3bSMartin Habets 
9856e173d3bSMartin Habets 	rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
9866e173d3bSMartin Habets 	if (rc)
9876e173d3bSMartin Habets 		return rc;
9886e173d3bSMartin Habets 	return netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
9896e173d3bSMartin Habets }
9906e173d3bSMartin Habets 
efx_default_channel_want_txqs(struct efx_channel * channel)9916e173d3bSMartin Habets static bool efx_default_channel_want_txqs(struct efx_channel *channel)
9926e173d3bSMartin Habets {
9936e173d3bSMartin Habets 	return channel->channel - channel->efx->tx_channel_offset <
9946e173d3bSMartin Habets 		channel->efx->n_tx_channels;
9956e173d3bSMartin Habets }
9966e173d3bSMartin Habets 
9976e173d3bSMartin Habets /*************
9986e173d3bSMartin Habets  * START/STOP
9996e173d3bSMartin Habets  *************/
10006e173d3bSMartin Habets 
efx_soft_enable_interrupts(struct efx_nic * efx)100171ad88f6SMartin Habets static int efx_soft_enable_interrupts(struct efx_nic *efx)
10026e173d3bSMartin Habets {
10036e173d3bSMartin Habets 	struct efx_channel *channel, *end_channel;
10046e173d3bSMartin Habets 	int rc;
10056e173d3bSMartin Habets 
10066e173d3bSMartin Habets 	BUG_ON(efx->state == STATE_DISABLED);
10076e173d3bSMartin Habets 
10086e173d3bSMartin Habets 	efx->irq_soft_enabled = true;
10096e173d3bSMartin Habets 	smp_wmb();
10106e173d3bSMartin Habets 
10116e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
10126e173d3bSMartin Habets 		if (!channel->type->keep_eventq) {
10136e173d3bSMartin Habets 			rc = efx_init_eventq(channel);
10146e173d3bSMartin Habets 			if (rc)
10156e173d3bSMartin Habets 				goto fail;
10166e173d3bSMartin Habets 		}
101771ad88f6SMartin Habets 		efx_siena_start_eventq(channel);
10186e173d3bSMartin Habets 	}
10196e173d3bSMartin Habets 
10204d49e5cdSMartin Habets 	efx_siena_mcdi_mode_event(efx);
10216e173d3bSMartin Habets 
10226e173d3bSMartin Habets 	return 0;
10236e173d3bSMartin Habets fail:
10246e173d3bSMartin Habets 	end_channel = channel;
10256e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
10266e173d3bSMartin Habets 		if (channel == end_channel)
10276e173d3bSMartin Habets 			break;
102871ad88f6SMartin Habets 		efx_siena_stop_eventq(channel);
10296e173d3bSMartin Habets 		if (!channel->type->keep_eventq)
10306e173d3bSMartin Habets 			efx_fini_eventq(channel);
10316e173d3bSMartin Habets 	}
10326e173d3bSMartin Habets 
10336e173d3bSMartin Habets 	return rc;
10346e173d3bSMartin Habets }
10356e173d3bSMartin Habets 
efx_soft_disable_interrupts(struct efx_nic * efx)103671ad88f6SMartin Habets static void efx_soft_disable_interrupts(struct efx_nic *efx)
10376e173d3bSMartin Habets {
10386e173d3bSMartin Habets 	struct efx_channel *channel;
10396e173d3bSMartin Habets 
10406e173d3bSMartin Habets 	if (efx->state == STATE_DISABLED)
10416e173d3bSMartin Habets 		return;
10426e173d3bSMartin Habets 
10434d49e5cdSMartin Habets 	efx_siena_mcdi_mode_poll(efx);
10446e173d3bSMartin Habets 
10456e173d3bSMartin Habets 	efx->irq_soft_enabled = false;
10466e173d3bSMartin Habets 	smp_wmb();
10476e173d3bSMartin Habets 
10486e173d3bSMartin Habets 	if (efx->legacy_irq)
10496e173d3bSMartin Habets 		synchronize_irq(efx->legacy_irq);
10506e173d3bSMartin Habets 
10516e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
10526e173d3bSMartin Habets 		if (channel->irq)
10536e173d3bSMartin Habets 			synchronize_irq(channel->irq);
10546e173d3bSMartin Habets 
105571ad88f6SMartin Habets 		efx_siena_stop_eventq(channel);
10566e173d3bSMartin Habets 		if (!channel->type->keep_eventq)
10576e173d3bSMartin Habets 			efx_fini_eventq(channel);
10586e173d3bSMartin Habets 	}
10596e173d3bSMartin Habets 
10606e173d3bSMartin Habets 	/* Flush the asynchronous MCDI request queue */
10614d49e5cdSMartin Habets 	efx_siena_mcdi_flush_async(efx);
10626e173d3bSMartin Habets }
10636e173d3bSMartin Habets 
efx_siena_enable_interrupts(struct efx_nic * efx)106471ad88f6SMartin Habets int efx_siena_enable_interrupts(struct efx_nic *efx)
10656e173d3bSMartin Habets {
10666e173d3bSMartin Habets 	struct efx_channel *channel, *end_channel;
10676e173d3bSMartin Habets 	int rc;
10686e173d3bSMartin Habets 
10696e173d3bSMartin Habets 	/* TODO: Is this really a bug? */
10706e173d3bSMartin Habets 	BUG_ON(efx->state == STATE_DISABLED);
10716e173d3bSMartin Habets 
10726e173d3bSMartin Habets 	if (efx->eeh_disabled_legacy_irq) {
10736e173d3bSMartin Habets 		enable_irq(efx->legacy_irq);
10746e173d3bSMartin Habets 		efx->eeh_disabled_legacy_irq = false;
10756e173d3bSMartin Habets 	}
10766e173d3bSMartin Habets 
10776e173d3bSMartin Habets 	efx->type->irq_enable_master(efx);
10786e173d3bSMartin Habets 
10796e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
10806e173d3bSMartin Habets 		if (channel->type->keep_eventq) {
10816e173d3bSMartin Habets 			rc = efx_init_eventq(channel);
10826e173d3bSMartin Habets 			if (rc)
10836e173d3bSMartin Habets 				goto fail;
10846e173d3bSMartin Habets 		}
10856e173d3bSMartin Habets 	}
10866e173d3bSMartin Habets 
10876e173d3bSMartin Habets 	rc = efx_soft_enable_interrupts(efx);
10886e173d3bSMartin Habets 	if (rc)
10896e173d3bSMartin Habets 		goto fail;
10906e173d3bSMartin Habets 
10916e173d3bSMartin Habets 	return 0;
10926e173d3bSMartin Habets 
10936e173d3bSMartin Habets fail:
10946e173d3bSMartin Habets 	end_channel = channel;
10956e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
10966e173d3bSMartin Habets 		if (channel == end_channel)
10976e173d3bSMartin Habets 			break;
10986e173d3bSMartin Habets 		if (channel->type->keep_eventq)
10996e173d3bSMartin Habets 			efx_fini_eventq(channel);
11006e173d3bSMartin Habets 	}
11016e173d3bSMartin Habets 
11026e173d3bSMartin Habets 	efx->type->irq_disable_non_ev(efx);
11036e173d3bSMartin Habets 
11046e173d3bSMartin Habets 	return rc;
11056e173d3bSMartin Habets }
11066e173d3bSMartin Habets 
efx_siena_disable_interrupts(struct efx_nic * efx)110771ad88f6SMartin Habets void efx_siena_disable_interrupts(struct efx_nic *efx)
11086e173d3bSMartin Habets {
11096e173d3bSMartin Habets 	struct efx_channel *channel;
11106e173d3bSMartin Habets 
11116e173d3bSMartin Habets 	efx_soft_disable_interrupts(efx);
11126e173d3bSMartin Habets 
11136e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
11146e173d3bSMartin Habets 		if (channel->type->keep_eventq)
11156e173d3bSMartin Habets 			efx_fini_eventq(channel);
11166e173d3bSMartin Habets 	}
11176e173d3bSMartin Habets 
11186e173d3bSMartin Habets 	efx->type->irq_disable_non_ev(efx);
11196e173d3bSMartin Habets }
11206e173d3bSMartin Habets 
efx_siena_start_channels(struct efx_nic * efx)112171ad88f6SMartin Habets void efx_siena_start_channels(struct efx_nic *efx)
11226e173d3bSMartin Habets {
11236e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
11246e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
11256e173d3bSMartin Habets 	struct efx_channel *channel;
11266e173d3bSMartin Habets 
11276e173d3bSMartin Habets 	efx_for_each_channel_rev(channel, efx) {
11286e173d3bSMartin Habets 		efx_for_each_channel_tx_queue(tx_queue, channel) {
11297f9e4b2aSMartin Habets 			efx_siena_init_tx_queue(tx_queue);
11306e173d3bSMartin Habets 			atomic_inc(&efx->active_queues);
11316e173d3bSMartin Habets 		}
11326e173d3bSMartin Habets 
11336e173d3bSMartin Habets 		efx_for_each_channel_rx_queue(rx_queue, channel) {
11347f9e4b2aSMartin Habets 			efx_siena_init_rx_queue(rx_queue);
11356e173d3bSMartin Habets 			atomic_inc(&efx->active_queues);
113671ad88f6SMartin Habets 			efx_siena_stop_eventq(channel);
11377f9e4b2aSMartin Habets 			efx_siena_fast_push_rx_descriptors(rx_queue, false);
113871ad88f6SMartin Habets 			efx_siena_start_eventq(channel);
11396e173d3bSMartin Habets 		}
11406e173d3bSMartin Habets 
11416e173d3bSMartin Habets 		WARN_ON(channel->rx_pkt_n_frags);
11426e173d3bSMartin Habets 	}
11436e173d3bSMartin Habets }
11446e173d3bSMartin Habets 
efx_siena_stop_channels(struct efx_nic * efx)114571ad88f6SMartin Habets void efx_siena_stop_channels(struct efx_nic *efx)
11466e173d3bSMartin Habets {
11476e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
11486e173d3bSMartin Habets 	struct efx_rx_queue *rx_queue;
11496e173d3bSMartin Habets 	struct efx_channel *channel;
11506e173d3bSMartin Habets 	int rc = 0;
11516e173d3bSMartin Habets 
11526e173d3bSMartin Habets 	/* Stop RX refill */
11536e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
11546e173d3bSMartin Habets 		efx_for_each_channel_rx_queue(rx_queue, channel)
11556e173d3bSMartin Habets 			rx_queue->refill_enabled = false;
11566e173d3bSMartin Habets 	}
11576e173d3bSMartin Habets 
11586e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
11596e173d3bSMartin Habets 		/* RX packet processing is pipelined, so wait for the
11606e173d3bSMartin Habets 		 * NAPI handler to complete.  At least event queue 0
11616e173d3bSMartin Habets 		 * might be kept active by non-data events, so don't
11626e173d3bSMartin Habets 		 * use napi_synchronize() but actually disable NAPI
11636e173d3bSMartin Habets 		 * temporarily.
11646e173d3bSMartin Habets 		 */
11656e173d3bSMartin Habets 		if (efx_channel_has_rx_queue(channel)) {
116671ad88f6SMartin Habets 			efx_siena_stop_eventq(channel);
116771ad88f6SMartin Habets 			efx_siena_start_eventq(channel);
11686e173d3bSMartin Habets 		}
11696e173d3bSMartin Habets 	}
11706e173d3bSMartin Habets 
11716e173d3bSMartin Habets 	if (efx->type->fini_dmaq)
11726e173d3bSMartin Habets 		rc = efx->type->fini_dmaq(efx);
11736e173d3bSMartin Habets 
11746e173d3bSMartin Habets 	if (rc) {
11756e173d3bSMartin Habets 		netif_err(efx, drv, efx->net_dev, "failed to flush queues\n");
11766e173d3bSMartin Habets 	} else {
11776e173d3bSMartin Habets 		netif_dbg(efx, drv, efx->net_dev,
11786e173d3bSMartin Habets 			  "successfully flushed all queues\n");
11796e173d3bSMartin Habets 	}
11806e173d3bSMartin Habets 
11816e173d3bSMartin Habets 	efx_for_each_channel(channel, efx) {
11826e173d3bSMartin Habets 		efx_for_each_channel_rx_queue(rx_queue, channel)
11837f9e4b2aSMartin Habets 			efx_siena_fini_rx_queue(rx_queue);
11846e173d3bSMartin Habets 		efx_for_each_channel_tx_queue(tx_queue, channel)
11857f9e4b2aSMartin Habets 			efx_siena_fini_tx_queue(tx_queue);
11866e173d3bSMartin Habets 	}
11876e173d3bSMartin Habets }
11886e173d3bSMartin Habets 
11896e173d3bSMartin Habets /**************************************************************************
11906e173d3bSMartin Habets  *
11916e173d3bSMartin Habets  * NAPI interface
11926e173d3bSMartin Habets  *
11936e173d3bSMartin Habets  *************************************************************************/
11946e173d3bSMartin Habets 
11956e173d3bSMartin Habets /* Process channel's event queue
11966e173d3bSMartin Habets  *
11976e173d3bSMartin Habets  * This function is responsible for processing the event queue of a
11986e173d3bSMartin Habets  * single channel.  The caller must guarantee that this function will
11996e173d3bSMartin Habets  * never be concurrently called more than once on the same channel,
12006e173d3bSMartin Habets  * though different channels may be being processed concurrently.
12016e173d3bSMartin Habets  */
efx_process_channel(struct efx_channel * channel,int budget)12026e173d3bSMartin Habets static int efx_process_channel(struct efx_channel *channel, int budget)
12036e173d3bSMartin Habets {
12046e173d3bSMartin Habets 	struct efx_tx_queue *tx_queue;
12056e173d3bSMartin Habets 	struct list_head rx_list;
12066e173d3bSMartin Habets 	int spent;
12076e173d3bSMartin Habets 
12086e173d3bSMartin Habets 	if (unlikely(!channel->enabled))
12096e173d3bSMartin Habets 		return 0;
12106e173d3bSMartin Habets 
12116e173d3bSMartin Habets 	/* Prepare the batch receive list */
12126e173d3bSMartin Habets 	EFX_WARN_ON_PARANOID(channel->rx_list != NULL);
12136e173d3bSMartin Habets 	INIT_LIST_HEAD(&rx_list);
12146e173d3bSMartin Habets 	channel->rx_list = &rx_list;
12156e173d3bSMartin Habets 
12166e173d3bSMartin Habets 	efx_for_each_channel_tx_queue(tx_queue, channel) {
12176e173d3bSMartin Habets 		tx_queue->pkts_compl = 0;
12186e173d3bSMartin Habets 		tx_queue->bytes_compl = 0;
12196e173d3bSMartin Habets 	}
12206e173d3bSMartin Habets 
12216e173d3bSMartin Habets 	spent = efx_nic_process_eventq(channel, budget);
12226e173d3bSMartin Habets 	if (spent && efx_channel_has_rx_queue(channel)) {
12236e173d3bSMartin Habets 		struct efx_rx_queue *rx_queue =
12246e173d3bSMartin Habets 			efx_channel_get_rx_queue(channel);
12256e173d3bSMartin Habets 
12266e173d3bSMartin Habets 		efx_rx_flush_packet(channel);
12277f9e4b2aSMartin Habets 		efx_siena_fast_push_rx_descriptors(rx_queue, true);
12286e173d3bSMartin Habets 	}
12296e173d3bSMartin Habets 
12306e173d3bSMartin Habets 	/* Update BQL */
12316e173d3bSMartin Habets 	efx_for_each_channel_tx_queue(tx_queue, channel) {
12326e173d3bSMartin Habets 		if (tx_queue->bytes_compl) {
12336e173d3bSMartin Habets 			netdev_tx_completed_queue(tx_queue->core_txq,
12346e173d3bSMartin Habets 						  tx_queue->pkts_compl,
12356e173d3bSMartin Habets 						  tx_queue->bytes_compl);
12366e173d3bSMartin Habets 		}
12376e173d3bSMartin Habets 	}
12386e173d3bSMartin Habets 
12396e173d3bSMartin Habets 	/* Receive any packets we queued up */
12406e173d3bSMartin Habets 	netif_receive_skb_list(channel->rx_list);
12416e173d3bSMartin Habets 	channel->rx_list = NULL;
12426e173d3bSMartin Habets 
12436e173d3bSMartin Habets 	return spent;
12446e173d3bSMartin Habets }
12456e173d3bSMartin Habets 
efx_update_irq_mod(struct efx_nic * efx,struct efx_channel * channel)12466e173d3bSMartin Habets static void efx_update_irq_mod(struct efx_nic *efx, struct efx_channel *channel)
12476e173d3bSMartin Habets {
12486e173d3bSMartin Habets 	int step = efx->irq_mod_step_us;
12496e173d3bSMartin Habets 
12506e173d3bSMartin Habets 	if (channel->irq_mod_score < irq_adapt_low_thresh) {
12516e173d3bSMartin Habets 		if (channel->irq_moderation_us > step) {
12526e173d3bSMartin Habets 			channel->irq_moderation_us -= step;
12536e173d3bSMartin Habets 			efx->type->push_irq_moderation(channel);
12546e173d3bSMartin Habets 		}
12556e173d3bSMartin Habets 	} else if (channel->irq_mod_score > irq_adapt_high_thresh) {
12566e173d3bSMartin Habets 		if (channel->irq_moderation_us <
12576e173d3bSMartin Habets 		    efx->irq_rx_moderation_us) {
12586e173d3bSMartin Habets 			channel->irq_moderation_us += step;
12596e173d3bSMartin Habets 			efx->type->push_irq_moderation(channel);
12606e173d3bSMartin Habets 		}
12616e173d3bSMartin Habets 	}
12626e173d3bSMartin Habets 
12636e173d3bSMartin Habets 	channel->irq_count = 0;
12646e173d3bSMartin Habets 	channel->irq_mod_score = 0;
12656e173d3bSMartin Habets }
12666e173d3bSMartin Habets 
12676e173d3bSMartin Habets /* NAPI poll handler
12686e173d3bSMartin Habets  *
12696e173d3bSMartin Habets  * NAPI guarantees serialisation of polls of the same device, which
12706e173d3bSMartin Habets  * provides the guarantee required by efx_process_channel().
12716e173d3bSMartin Habets  */
efx_poll(struct napi_struct * napi,int budget)12726e173d3bSMartin Habets static int efx_poll(struct napi_struct *napi, int budget)
12736e173d3bSMartin Habets {
12746e173d3bSMartin Habets 	struct efx_channel *channel =
12756e173d3bSMartin Habets 		container_of(napi, struct efx_channel, napi_str);
12766e173d3bSMartin Habets 	struct efx_nic *efx = channel->efx;
12776e173d3bSMartin Habets #ifdef CONFIG_RFS_ACCEL
12786e173d3bSMartin Habets 	unsigned int time;
12796e173d3bSMartin Habets #endif
12806e173d3bSMartin Habets 	int spent;
12816e173d3bSMartin Habets 
12826e173d3bSMartin Habets 	netif_vdbg(efx, intr, efx->net_dev,
12836e173d3bSMartin Habets 		   "channel %d NAPI poll executing on CPU %d\n",
12846e173d3bSMartin Habets 		   channel->channel, raw_smp_processor_id());
12856e173d3bSMartin Habets 
12866e173d3bSMartin Habets 	spent = efx_process_channel(channel, budget);
12876e173d3bSMartin Habets 
12886e173d3bSMartin Habets 	xdp_do_flush_map();
12896e173d3bSMartin Habets 
12906e173d3bSMartin Habets 	if (spent < budget) {
12916e173d3bSMartin Habets 		if (efx_channel_has_rx_queue(channel) &&
12926e173d3bSMartin Habets 		    efx->irq_rx_adaptive &&
12936e173d3bSMartin Habets 		    unlikely(++channel->irq_count == 1000)) {
12946e173d3bSMartin Habets 			efx_update_irq_mod(efx, channel);
12956e173d3bSMartin Habets 		}
12966e173d3bSMartin Habets 
12976e173d3bSMartin Habets #ifdef CONFIG_RFS_ACCEL
12986e173d3bSMartin Habets 		/* Perhaps expire some ARFS filters */
12996e173d3bSMartin Habets 		time = jiffies - channel->rfs_last_expiry;
13006e173d3bSMartin Habets 		/* Would our quota be >= 20? */
13016e173d3bSMartin Habets 		if (channel->rfs_filter_count * time >= 600 * HZ)
13026e173d3bSMartin Habets 			mod_delayed_work(system_wq, &channel->filter_work, 0);
13036e173d3bSMartin Habets #endif
13046e173d3bSMartin Habets 
13056e173d3bSMartin Habets 		/* There is no race here; although napi_disable() will
13066e173d3bSMartin Habets 		 * only wait for napi_complete(), this isn't a problem
13076e173d3bSMartin Habets 		 * since efx_nic_eventq_read_ack() will have no effect if
13086e173d3bSMartin Habets 		 * interrupts have already been disabled.
13096e173d3bSMartin Habets 		 */
13106e173d3bSMartin Habets 		if (napi_complete_done(napi, spent))
13116e173d3bSMartin Habets 			efx_nic_eventq_read_ack(channel);
13126e173d3bSMartin Habets 	}
13136e173d3bSMartin Habets 
13146e173d3bSMartin Habets 	return spent;
13156e173d3bSMartin Habets }
13166e173d3bSMartin Habets 
efx_init_napi_channel(struct efx_channel * channel)131771ad88f6SMartin Habets static void efx_init_napi_channel(struct efx_channel *channel)
13186e173d3bSMartin Habets {
13196e173d3bSMartin Habets 	struct efx_nic *efx = channel->efx;
13206e173d3bSMartin Habets 
13216e173d3bSMartin Habets 	channel->napi_dev = efx->net_dev;
1322b48b89f9SJakub Kicinski 	netif_napi_add(channel->napi_dev, &channel->napi_str, efx_poll);
13236e173d3bSMartin Habets }
13246e173d3bSMartin Habets 
efx_siena_init_napi(struct efx_nic * efx)132571ad88f6SMartin Habets void efx_siena_init_napi(struct efx_nic *efx)
13266e173d3bSMartin Habets {
13276e173d3bSMartin Habets 	struct efx_channel *channel;
13286e173d3bSMartin Habets 
13296e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
13306e173d3bSMartin Habets 		efx_init_napi_channel(channel);
13316e173d3bSMartin Habets }
13326e173d3bSMartin Habets 
efx_fini_napi_channel(struct efx_channel * channel)133371ad88f6SMartin Habets static void efx_fini_napi_channel(struct efx_channel *channel)
13346e173d3bSMartin Habets {
13356e173d3bSMartin Habets 	if (channel->napi_dev)
13366e173d3bSMartin Habets 		netif_napi_del(&channel->napi_str);
13376e173d3bSMartin Habets 
13386e173d3bSMartin Habets 	channel->napi_dev = NULL;
13396e173d3bSMartin Habets }
13406e173d3bSMartin Habets 
efx_siena_fini_napi(struct efx_nic * efx)134171ad88f6SMartin Habets void efx_siena_fini_napi(struct efx_nic *efx)
13426e173d3bSMartin Habets {
13436e173d3bSMartin Habets 	struct efx_channel *channel;
13446e173d3bSMartin Habets 
13456e173d3bSMartin Habets 	efx_for_each_channel(channel, efx)
13466e173d3bSMartin Habets 		efx_fini_napi_channel(channel);
13476e173d3bSMartin Habets }
13486e173d3bSMartin Habets 
13496e173d3bSMartin Habets /***************
13506e173d3bSMartin Habets  * Housekeeping
13516e173d3bSMartin Habets  ***************/
13526e173d3bSMartin Habets 
efx_channel_dummy_op_int(struct efx_channel * channel)13536e173d3bSMartin Habets static int efx_channel_dummy_op_int(struct efx_channel *channel)
13546e173d3bSMartin Habets {
13556e173d3bSMartin Habets 	return 0;
13566e173d3bSMartin Habets }
13576e173d3bSMartin Habets 
efx_siena_channel_dummy_op_void(struct efx_channel * channel)135871ad88f6SMartin Habets void efx_siena_channel_dummy_op_void(struct efx_channel *channel)
13596e173d3bSMartin Habets {
13606e173d3bSMartin Habets }
13616e173d3bSMartin Habets 
13626e173d3bSMartin Habets static const struct efx_channel_type efx_default_channel_type = {
13636e173d3bSMartin Habets 	.pre_probe		= efx_channel_dummy_op_int,
136471ad88f6SMartin Habets 	.post_remove		= efx_siena_channel_dummy_op_void,
13656e173d3bSMartin Habets 	.get_name		= efx_get_channel_name,
13666e173d3bSMartin Habets 	.copy			= efx_copy_channel,
13676e173d3bSMartin Habets 	.want_txqs		= efx_default_channel_want_txqs,
13686e173d3bSMartin Habets 	.keep_eventq		= false,
13696e173d3bSMartin Habets 	.want_pio		= true,
13706e173d3bSMartin Habets };
1371