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