2026-01-29 22:25:33 +08:00

984 lines
28 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
#include "rnpgbe.h"
#include "rnpgbe_sriov.h"
#include "rnpgbe_common.h"
/**
* rnpgbe_cache_ring_dcb - Descriptor ring to register mapping for DCB
* @adapter: board private structure to initialize
*
* Cache the descriptor ring offsets for DCB to the assigned rings.
*
**/
static bool rnpgbe_cache_ring_dcb(struct rnpgbe_adapter *adapter)
{
struct net_device *dev = adapter->netdev;
unsigned int tx_idx, rx_idx;
int tc, offset, rss_i, i, step;
u8 num_tcs = netdev_get_num_tc(dev);
struct rnpgbe_ring *ring;
struct rnpgbe_hw *hw = &adapter->hw;
struct rnpgbe_dma_info *dma = &hw->dma;
/* verify we have DCB queueing enabled before proceeding */
if (num_tcs <= 1)
return false;
rss_i = adapter->ring_feature[RING_F_RSS].indices;
step = 4;
for (tc = 0, offset = 0; tc < num_tcs; tc++, offset += rss_i) {
tx_idx = tc;
rx_idx = tc;
for (i = 0; i < rss_i; i++, tx_idx += step, rx_idx += step) {
ring = adapter->tx_ring[offset + i];
ring->ring_addr =
dma->dma_ring_addr + RING_OFFSET(tx_idx);
ring->rnpgbe_queue_idx = tx_idx;
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
ring = adapter->rx_ring[offset + i];
ring->ring_addr =
dma->dma_ring_addr + RING_OFFSET(rx_idx);
ring->rnpgbe_queue_idx = rx_idx;
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
}
}
return true;
}
/**
* rnpgbe_cache_ring_sriov - Descriptor ring to register mapping for sriov
* @adapter: board private structure to initialize
*
* SR-IOV doesn't use any descriptor rings but changes the default if
* no other mapping is used.
*
*/
static bool rnpgbe_cache_ring_sriov(struct rnpgbe_adapter *adapter)
{
/* only proceed if VMDq is enabled */
if (!(adapter->flags & RNP_FLAG_VMDQ_ENABLED))
return false;
return true;
}
/**
* rnpgbe_cache_ring_rss - Descriptor ring to register mapping for RSS
* @adapter: board private structure to initialize
*
* Cache the descriptor ring offsets for RSS to the assigned rings.
*
**/
static bool rnpgbe_cache_ring_rss(struct rnpgbe_adapter *adapter)
{
int i;
int ring_step = 1;
struct rnpgbe_ring *ring;
struct rnpgbe_hw *hw = &adapter->hw;
struct rnpgbe_dma_info *dma = &hw->dma;
/* some ring alloc rules can be added here */
for (i = 0; i < adapter->num_rx_queues; i++) {
ring = adapter->tx_ring[i];
ring->rnpgbe_queue_idx = i * ring_step;
ring->ring_addr = dma->dma_ring_addr +
RING_OFFSET(ring->rnpgbe_queue_idx);
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
}
for (i = 0; i < adapter->num_tx_queues; i++) {
ring = adapter->rx_ring[i];
ring->rnpgbe_queue_idx = i * ring_step;
ring->ring_addr = dma->dma_ring_addr +
RING_OFFSET(ring->rnpgbe_queue_idx);
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
}
return true;
}
/**
* rnpgbe_cache_ring_register - Descriptor ring to register mapping
* @adapter: board private structure to initialize
*
* Once we know the feature-set enabled for the device, we'll cache
* the register offset the descriptor ring is assigned to.
*
* Note, the order the various feature calls is important. It must start with
* the "most" features enabled at the same time, then trickle down to the
* least amount of features turned on at once.
**/
static void rnpgbe_cache_ring_register(struct rnpgbe_adapter *adapter)
{
/* start with default case */
if (rnpgbe_cache_ring_dcb(adapter))
return;
/* sriov ring alloc is added before, this maybe no use */
if (rnpgbe_cache_ring_sriov(adapter))
return;
rnpgbe_cache_ring_rss(adapter);
}
#define RNP_RSS_128Q_MASK 0x7F
#define RNP_RSS_64Q_MASK 0x3F
#define RNP_RSS_16Q_MASK 0xF
#define RNP_RSS_32Q_MASK 0x1F
#define RNP_RSS_8Q_MASK 0x7
#define RNP_RSS_4Q_MASK 0x3
#define RNP_RSS_2Q_MASK 0x1
#define RNP_RSS_DISABLED_MASK 0x0
static bool rnpgbe_set_dcb_queues(struct rnpgbe_adapter *adapter)
{
struct net_device *dev = adapter->netdev;
struct rnpgbe_ring_feature *f;
int rss_i, rss_m, i;
int tcs;
/* Map queue offset and counts onto allocated tx queues */
tcs = netdev_get_num_tc(dev);
/* verify we have DCB queueing enabled before proceeding */
if (tcs <= 1)
return false;
/* determine the upper limit for our current DCB mode */
rss_i = dev->num_tx_queues / tcs;
rss_i = min_t(u16, rss_i, 32);
rss_m = RNP_RSS_32Q_MASK;
/* set RSS mask and indices */
/* f->limit is relative with cpu_vector */
f = &adapter->ring_feature[RING_F_RSS];
/* use f->limit to change rss */
rss_i = min_t(int, rss_i, f->limit);
f->indices = rss_i;
f->mask = rss_m;
/* disable ATR as it is not supported when multiple TCs are enabled */
adapter->flags &= ~RNP_FLAG_FDIR_HASH_CAPABLE;
/* setup queue tc num */
for (i = 0; i < tcs; i++)
netdev_set_tc_queue(dev, i, rss_i, rss_i * i);
adapter->num_tx_queues = rss_i * tcs;
adapter->num_rx_queues = rss_i * tcs;
return true;
}
/**
* rnpgbe_set_sriov_queues - Allocate queues for SR-IOV devices
* @adapter: board private structure to initialize
*
* When SR-IOV (Single Root IO Virtualiztion) is enabled, allocate queues
* and VM pools where appropriate. If RSS is available, then also try and
* enable RSS and map accordingly.
*
**/
static bool rnpgbe_set_sriov_queues(struct rnpgbe_adapter *adapter)
{
u16 vmdq_m = 0;
u16 rss_i = adapter->ring_feature[RING_F_RSS].limit;
u16 rss_m = RNP_RSS_DISABLED_MASK;
struct rnpgbe_hw *hw = &adapter->hw;
/* only proceed if SR-IOV is enabled */
if (!(adapter->flags & RNP_FLAG_SRIOV_ENABLED))
return false;
/* save features for later use */
adapter->ring_feature[RING_F_VMDQ].indices =
adapter->max_ring_pair_counts - 1;
adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
/* limit RSS based on user input and save for later use */
adapter->ring_feature[RING_F_RSS].indices = rss_i;
adapter->ring_feature[RING_F_RSS].mask = rss_m;
adapter->num_rx_queues = hw->sriov_ring_limit;
adapter->num_tx_queues = hw->sriov_ring_limit;
/* disable ATR as it is not supported when VMDq is enabled */
adapter->flags &= ~RNP_FLAG_FDIR_HASH_CAPABLE;
return true;
}
u32 rnpgbe_rss_indir_tbl_entries(struct rnpgbe_adapter *adapter)
{
if (adapter->hw.rss_type == rnpgbe_rss_uv3p)
return 8;
else if (adapter->hw.rss_type == rnpgbe_rss_uv440)
return 128;
else if (adapter->hw.rss_type == rnpgbe_rss_n10)
return 128;
else
return 128;
}
/**
* rnpgbe_set_rss_queues - Allocate queues for RSS
* @adapter: board private structure to initialize
*
* This is our "base" multiqueue mode. RSS (Receive Side Scaling) will try
* to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
*
**/
static bool rnpgbe_set_rss_queues(struct rnpgbe_adapter *adapter)
{
struct rnpgbe_ring_feature *f;
u16 rss_i;
f = &adapter->ring_feature[RING_F_RSS];
/* use thid to change ring num */
rss_i = f->limit;
/* set limit -> indices */
f->indices = rss_i;
/* should init rss mask */
switch (adapter->hw.rss_type) {
case rnpgbe_rss_uv3p:
f->mask = RNP_RSS_8Q_MASK;
break;
case rnpgbe_rss_uv440:
f->mask = RNP_RSS_64Q_MASK;
break;
case rnpgbe_rss_n10:
f->mask = RNP_RSS_128Q_MASK;
break;
case rnpgbe_rss_n500:
f->mask = RNP_RSS_8Q_MASK;
break;
default:
f->mask = 0;
break;
}
/* should not more than irq */
adapter->num_tx_queues =
min_t(int, rss_i, adapter->max_ring_pair_counts);
adapter->num_rx_queues = adapter->num_tx_queues;
rnpgbe_dbg("[%s] limit:%d indices:%d queues:%d\n", adapter->name,
f->limit, f->indices, adapter->num_tx_queues);
return true;
}
/**
* rnpgbe_set_num_queues - Allocate queues for device, feature dependent
* @adapter: board private structure to initialize
*
* This is the top level queue allocation routine. The order here is very
* important, starting with the "most" number of features turned on at once,
* and ending with the smallest set of features. This way large combinations
* can be allocated if they're turned on, and smaller combinations are the
* fallthrough conditions.
*
**/
static void rnpgbe_set_num_queues(struct rnpgbe_adapter *adapter)
{
/* Start with base case */
adapter->num_tx_queues = 1;
adapter->num_rx_queues = 1;
if (rnpgbe_set_dcb_queues(adapter))
return;
if (rnpgbe_set_sriov_queues(adapter))
return;
/* at last we support rss */
rnpgbe_set_rss_queues(adapter);
}
static int rnpgbe_acquire_msix_vectors(struct rnpgbe_adapter *adapter, int vectors)
{
int err;
err = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
vectors, vectors);
if (err < 0) {
rnpgbe_err("pci_enable_msix failed: req:%d err:%d\n", vectors,
err);
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
return -EINVAL;
}
/* Adjust for only the vectors we'll use, which is minimum
* of max_msix_q_vectors + NON_Q_VECTORS, or the number of
* vectors we were allocated.
*/
vectors -= adapter->num_other_vectors;
adapter->num_q_vectors = min(vectors, adapter->max_q_vectors);
if (adapter->flags & RNP_FLAG_DCB_ENABLED)
adapter->num_q_vectors = min(32, adapter->num_q_vectors);
return 0;
}
static void rnpgbe_add_ring(struct rnpgbe_ring *ring,
struct rnpgbe_ring_container *head)
{
ring->next = head->ring;
head->ring = ring;
head->count++;
}
/**
* rnpgbe_alloc_q_vector - Allocate memory for a single interrupt vector
* @adapter: board private structure to initialize
* @eth_queue_idx: eth queue idx
* @v_idx: index of vector in adapter struct
* @r_idx: index of first Tx ring to allocate
* @r_count: total number of Rx rings to allocate
* @step: ring step
*
* We allocate one q_vector. If allocation fails we return -ENOMEM.
**/
static int rnpgbe_alloc_q_vector(struct rnpgbe_adapter *adapter,
int eth_queue_idx, int v_idx, int r_idx,
int r_count, int step)
{
struct rnpgbe_q_vector *q_vector;
struct rnpgbe_ring *ring;
struct rnpgbe_hw *hw = &adapter->hw;
struct rnpgbe_dma_info *dma = &hw->dma;
int node = NUMA_NO_NODE;
int cpu = -1;
int ring_count, size;
int txr_count, rxr_count, idx;
int rxr_idx = r_idx, txr_idx = r_idx;
int cpu_offset = 0;
rxr_count = r_count;
txr_count = rxr_count;
ring_count = txr_count + rxr_count;
size = sizeof(struct rnpgbe_q_vector) +
(sizeof(struct rnpgbe_ring) * ring_count);
/* should minis adapter->q_vector_off */
if (cpu_online(cpu_offset + v_idx - adapter->q_vector_off)) {
/* cpu 1 - 7 */
cpu = cpu_offset + v_idx - adapter->q_vector_off;
node = cpu_to_node(cpu);
}
/* allocate q_vector and rings */
q_vector = kzalloc_node(size, GFP_KERNEL, node);
if (!q_vector)
q_vector = kzalloc(size, GFP_KERNEL);
if (!q_vector)
return -ENOMEM;
/* setup affinity mask and node */
if (cpu != -1)
cpumask_set_cpu(cpu, &q_vector->affinity_mask);
q_vector->numa_node = node;
netif_napi_add_weight(adapter->netdev, &q_vector->napi, rnpgbe_poll,
adapter->napi_budge);
/* tie q_vector and adapter together */
adapter->q_vector[v_idx - adapter->q_vector_off] = q_vector;
q_vector->adapter = adapter;
q_vector->v_idx = v_idx;
/* initialize work limits */
q_vector->tx.work_limit = adapter->tx_work_limit;
/* initialize pointer to rings */
ring = q_vector->ring;
for (idx = 0; idx < txr_count; idx++) {
/* assign generic ring traits */
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
/* configure backlink on ring */
ring->q_vector = q_vector;
/* update q_vector Tx values */
rnpgbe_add_ring(ring, &q_vector->tx);
/* apply Tx specific ring traits */
ring->count = adapter->tx_ring_item_count;
if (adapter->flags & RNP_FLAG_DCB_ENABLED) {
int rss_i;
rss_i = adapter->ring_feature[RING_F_RSS].indices;
/* in dcb mode should assign rss */
ring->queue_index = eth_queue_idx + idx * rss_i;
} else {
ring->queue_index = eth_queue_idx + idx;
}
/* rnpgbe_queue_idx can be changed after */
/* it is used to location hw reg */
ring->rnpgbe_queue_idx = txr_idx;
ring->ring_addr = dma->dma_ring_addr + RING_OFFSET(txr_idx);
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
ring->device_id = adapter->pdev->device;
ring->pfvfnum = hw->pfvfnum;
/* assign ring to adapter */
adapter->tx_ring[ring->queue_index] = ring;
/* update count and index */
txr_idx += step;
rnpgbe_dbg("\t\t%s:vector[%d] <--RNP TxRing:%d, eth_queue:%d\n",
adapter->name, v_idx, ring->rnpgbe_queue_idx,
ring->queue_index);
/* push pointer to next ring */
ring++;
}
for (idx = 0; idx < rxr_count; idx++) {
/* assign generic ring traits */
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
/* configure backlink on ring */
ring->q_vector = q_vector;
/* update q_vector Rx values */
rnpgbe_add_ring(ring, &q_vector->rx);
/* apply Rx specific ring traits */
ring->count = adapter->rx_ring_item_count;
/* rnpgbe_queue_idx can be changed after */
/* it is used to location hw reg */
if (adapter->flags & RNP_FLAG_DCB_ENABLED) {
int rss_i;
rss_i = adapter->ring_feature[RING_F_RSS].indices;
/* in dcb mode should assign rss */
ring->queue_index = eth_queue_idx + idx * rss_i;
} else {
ring->queue_index = eth_queue_idx + idx;
}
ring->rnpgbe_queue_idx = rxr_idx;
ring->ring_addr = dma->dma_ring_addr + RING_OFFSET(rxr_idx);
ring->dma_int_stat = ring->ring_addr + RNP_DMA_INT_STAT;
ring->dma_int_mask = ring->ring_addr + RNP_DMA_INT_MASK;
ring->dma_int_clr = ring->ring_addr + RNP_DMA_INT_CLR;
ring->device_id = adapter->pdev->device;
ring->pfvfnum = hw->pfvfnum;
/* assign ring to adapter */
adapter->rx_ring[ring->queue_index] = ring;
rnpgbe_dbg("\t\t%s:vector[%d] <--RNP RxRing:%d, eth_queue:%d\n",
adapter->name, v_idx, ring->rnpgbe_queue_idx,
ring->queue_index);
/* update count and index */
rxr_idx += step;
/* push pointer to next ring */
ring++;
}
q_vector->new_rx_count = adapter->rx_frames;
q_vector->old_rx_count = adapter->rx_frames;
q_vector->itr_rx = adapter->rx_usecs;
q_vector->rx.itr = adapter->rx_usecs;
return 0;
}
/**
* rnpgbe_free_q_vector - Free memory allocated for specific interrupt vector
* @adapter: board private structure to initialize
* @v_idx: Index of vector to be freed
*
* This function frees the memory allocated to the q_vector. In addition if
* NAPI is enabled it will delete any references to the NAPI struct prior
* to freeing the q_vector.
**/
static void rnpgbe_free_q_vector(struct rnpgbe_adapter *adapter, int v_idx)
{
struct rnpgbe_q_vector *q_vector = adapter->q_vector[v_idx];
struct rnpgbe_ring *ring;
rnpgbe_dbg("v_idx:%d\n", v_idx);
rnpgbe_for_each_ring(ring, q_vector->tx)
adapter->tx_ring[ring->queue_index] = NULL;
rnpgbe_for_each_ring(ring, q_vector->rx)
adapter->rx_ring[ring->queue_index] = NULL;
adapter->q_vector[v_idx] = NULL;
netif_napi_del(&q_vector->napi);
/* rnpgbe_get_stats64() might access the rings on this vector,
* we must wait a grace period before freeing it.
*/
kfree_rcu(q_vector, rcu);
}
/**
* rnpgbe_alloc_q_vectors - Allocate memory for interrupt vectors
* @adapter: board private structure to initialize
*
* We allocate one q_vector per queue interrupt. If allocation fails we
* return -ENOMEM.
**/
static int rnpgbe_alloc_q_vectors(struct rnpgbe_adapter *adapter)
{
int v_idx = adapter->q_vector_off;
int ring_idx = 0;
int r_remaing =
min_t(int, adapter->num_tx_queues, adapter->num_rx_queues);
int ring_step = 1;
int err, ring_cnt, v_remaing = adapter->num_q_vectors;
int q_vector_nums = 0;
struct rnpgbe_hw *hw = &adapter->hw;
if (adapter->flags & RNP_FLAG_SRIOV_ENABLED) {
ring_idx = 0;
/* only 2 rings when sriov enabled */
/* from back */
ring_idx = adapter->max_ring_pair_counts -
ring_step * hw->sriov_ring_limit;
r_remaing = hw->sriov_ring_limit;
}
adapter->eth_queue_idx = 0;
BUG_ON(adapter->num_q_vectors == 0);
if (adapter->flags & RNP_FLAG_DCB_ENABLED) {
rnpgbe_dbg("in dcb mode r_remaing %d, num_q_vectors %d\n",
r_remaing, v_remaing);
}
rnpgbe_dbg("r_remaing:%d, ring_step:%d num_q_vectors:%d\n", r_remaing,
ring_step, v_remaing);
/* can support muti rings in one q_vector */
for (; r_remaing > 0 && v_remaing > 0; v_remaing--) {
ring_cnt = DIV_ROUND_UP(r_remaing, v_remaing);
if (adapter->flags & RNP_FLAG_DCB_ENABLED)
BUG_ON(ring_cnt != adapter->num_tc);
err = rnpgbe_alloc_q_vector(adapter, adapter->eth_queue_idx,
v_idx, ring_idx, ring_cnt,
ring_step);
if (err)
goto err_out;
ring_idx += ring_step * ring_cnt;
r_remaing -= ring_cnt;
v_idx++;
q_vector_nums++;
/* dcb mode only add 1 */
if (adapter->flags & RNP_FLAG_DCB_ENABLED)
adapter->eth_queue_idx += 1;
else
adapter->eth_queue_idx += ring_cnt;
}
/* should fix the real used q_vectors_nums */
adapter->num_q_vectors = q_vector_nums;
return 0;
err_out:
adapter->num_tx_queues = 0;
adapter->num_rx_queues = 0;
adapter->num_q_vectors = 0;
while (v_idx--)
rnpgbe_free_q_vector(adapter, v_idx);
return -ENOMEM;
}
/**
* rnpgbe_free_q_vectors - Free memory allocated for interrupt vectors
* @adapter: board private structure to initialize
*
* This function frees the memory allocated to the q_vectors. In addition if
* NAPI is enabled it will delete any references to the NAPI struct prior
* to freeing the q_vector.
**/
static void rnpgbe_free_q_vectors(struct rnpgbe_adapter *adapter)
{
int v_idx = adapter->num_q_vectors;
adapter->num_rx_queues = 0;
adapter->num_tx_queues = 0;
adapter->num_q_vectors = 0;
while (v_idx--)
rnpgbe_free_q_vector(adapter, v_idx);
}
void rnpgbe_reset_interrupt_capability(struct rnpgbe_adapter *adapter)
{
if (adapter->flags & RNP_FLAG_MSIX_ENABLED)
pci_disable_msix(adapter->pdev);
else if (adapter->flags & RNP_FLAG_MSI_CAPABLE)
pci_disable_msi(adapter->pdev);
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
adapter->q_vector_off = 0;
/* frist clean msix flags */
adapter->flags &= (~RNP_FLAG_MSIX_ENABLED);
adapter->flags &= (~RNP_FLAG_MSI_ENABLED);
}
/**
* rnpgbe_set_interrupt_capability - set MSI-X or MSI if supported
* @adapter: board private structure to initialize
*
* Attempt to configure the interrupts using the best available
* capabilities of the hardware and the kernel.
**/
int rnpgbe_set_interrupt_capability(struct rnpgbe_adapter *adapter)
{
struct rnpgbe_hw *hw = &adapter->hw;
int vector, v_budget, err = 0;
int irq_mode_back = adapter->irq_mode;
v_budget = min_t(int, adapter->num_tx_queues, adapter->num_rx_queues);
/* in one ring mode should reset v_budget */
v_budget = min_t(int, v_budget, num_online_cpus());
v_budget += adapter->num_other_vectors;
v_budget = min_t(int, v_budget, hw->mac.max_msix_vectors);
if (adapter->irq_mode == irq_mode_msix) {
adapter->msix_entries = kcalloc(v_budget,
sizeof(struct msix_entry), GFP_KERNEL);
if (!adapter->msix_entries) {
rnpgbe_err("alloc msix_entries failed!\n");
return -EINVAL;
}
dbg("[%s] adapter:%p msix_entry:%p\n", __func__, adapter,
adapter->msix_entries);
for (vector = 0; vector < v_budget; vector++)
adapter->msix_entries[vector].entry = vector;
err = rnpgbe_acquire_msix_vectors(adapter, v_budget);
if (!err) {
if (adapter->num_other_vectors)
adapter->q_vector_off = 1;
rnpgbe_dbg("adapter%d alloc vectors: cnt:%d [%d~%d] num_q_vectors:%d\n",
adapter->bd_number, v_budget,
adapter->q_vector_off,
adapter->q_vector_off + v_budget - 1,
adapter->num_q_vectors);
adapter->flags |= RNP_FLAG_MSIX_ENABLED;
goto out;
}
/* if has msi capability try it */
if (adapter->flags & RNP_FLAG_MSI_CAPABLE)
adapter->irq_mode = irq_mode_msi;
kfree(adapter->msix_entries);
pr_info("acquire msix failed, try to use msi\n");
} else {
rnpgbe_dbg("adapter%d not in msix mode\n", adapter->bd_number);
}
/* if has msi capability or set irq_mode */
if (adapter->irq_mode == irq_mode_msi) {
err = pci_enable_msi(adapter->pdev);
/* msi mode use only 1 irq */
if (err)
pr_info("Failed to allocate MSI interrupt, falling back to legacy. Error");
else
adapter->flags |= RNP_FLAG_MSI_ENABLED;
}
/* write back origin irq_mode */
adapter->irq_mode = irq_mode_back;
/* legacy and msi only 1 vectors */
adapter->num_q_vectors = 1;
err = 0;
out:
return err;
}
static void update_ring_count(struct rnpgbe_adapter *adapter)
{
if (adapter->flags2 & RNP_FLAG2_INSMOD)
return;
adapter->flags2 |= RNP_FLAG2_INSMOD;
/* limit ring count if in msi or legacy mode */
if (!(adapter->flags & RNP_FLAG_MSIX_ENABLED)) {
adapter->num_tx_queues = 1;
adapter->num_rx_queues = 1;
adapter->ring_feature[RING_F_RSS].limit = 1;
adapter->ring_feature[RING_F_FDIR].limit = 1;
adapter->ring_feature[RING_F_RSS].indices = 1;
}
}
/**
* rnpgbe_init_interrupt_scheme - Determine proper interrupt scheme
* @adapter: board private structure to initialize
*
* We determine which interrupt scheme to use based on...
* - Hardware queue count (num_*_queues)
* - defined by miscellaneous hardware support/features (RSS, etc.)
**/
int rnpgbe_init_interrupt_scheme(struct rnpgbe_adapter *adapter)
{
int err;
/* Number of supported queues */
rnpgbe_set_num_queues(adapter);
/* Set interrupt mode */
err = rnpgbe_set_interrupt_capability(adapter);
if (err) {
e_dev_err("Unable to get interrupt\n");
goto err_set_interrupt;
}
/* update ring num only init */
update_ring_count(adapter);
err = rnpgbe_alloc_q_vectors(adapter);
if (err) {
e_dev_err("Unable to allocate memory for queue vectors\n");
goto err_alloc_q_vectors;
}
rnpgbe_cache_ring_register(adapter);
/* printk now qvctor ring setup */
DPRINTK(PROBE, INFO,
"Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u\n\n",
(adapter->num_rx_queues > 1) ? "Enabled" : "Disabled",
adapter->num_rx_queues, adapter->num_tx_queues);
set_bit(__RNP_DOWN, &adapter->state);
return 0;
err_alloc_q_vectors:
rnpgbe_reset_interrupt_capability(adapter);
err_set_interrupt:;
return err;
}
/**
* rnpgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
* @adapter: board private structure to clear interrupt scheme on
*
* We go through and clear interrupt specific resources and reset the structure
* to pre-load conditions
**/
void rnpgbe_clear_interrupt_scheme(struct rnpgbe_adapter *adapter)
{
adapter->num_tx_queues = 0;
adapter->num_rx_queues = 0;
rnpgbe_free_q_vectors(adapter);
rnpgbe_reset_interrupt_capability(adapter);
}
/**
* rnpgbe_tx_ctxtdesc - Send a control desc to hw
* @tx_ring: target ring of this control desc
* @mss_len_vf_num: mss length
* @inner_vlan_tunnel_len: inner vlan tunnel length
* @ignore_vlan: ignore vlan flag
* @crc_pad: padding flag
*
**/
void rnpgbe_tx_ctxtdesc(struct rnpgbe_ring *tx_ring, u32 mss_len_vf_num,
u32 inner_vlan_tunnel_len, int ignore_vlan,
bool crc_pad)
{
struct rnpgbe_tx_ctx_desc *context_desc;
u16 i = tx_ring->next_to_use;
struct rnpgbe_adapter *adapter = RING2ADAPT(tx_ring);
u32 type_tucmd = 0;
context_desc = RNP_TX_CTXTDESC(tx_ring, i);
i++;
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
/* set bits to identify this as an advanced context descriptor */
type_tucmd |= RNP_TXD_CTX_CTRL_DESC;
/* set mac padding status if set priv_flags */
if (adapter->priv_flags & RNP_PRIV_FLAG_TX_PADDING) {
if (!crc_pad)
type_tucmd |= RNP_TXD_MTI_CRC_PAD_CTRL;
}
#define VLAN_MASK (0x0000ffff)
#define VLAN_INSERT (0x00800000)
if (inner_vlan_tunnel_len & VLAN_MASK)
type_tucmd |= VLAN_INSERT;
context_desc->mss_len_vf_num = cpu_to_le32(mss_len_vf_num);
context_desc->inner_vlan_tunnel_len =
cpu_to_le32(inner_vlan_tunnel_len);
context_desc->resv_cmd = cpu_to_le32(type_tucmd);
context_desc->resv = 0;
if (tx_ring->q_vector->adapter->flags & RNP_FLAG_SRIOV_ENABLED) {
if (ignore_vlan) {
context_desc->inner_vlan_tunnel_len |=
VF_VEB_IGNORE_VLAN;
}
}
buf_dump_line("ctx ", __LINE__, context_desc, sizeof(*context_desc));
}
void rnpgbe_maybe_tx_ctxtdesc(struct rnpgbe_ring *tx_ring,
struct rnpgbe_tx_buffer *first, u32 ignore_vlan)
{
if (first->ctx_flag) {
rnpgbe_tx_ctxtdesc(tx_ring, first->mss_len_vf_num,
first->inner_vlan_tunnel_len, ignore_vlan,
first->gso_need_padding);
}
}
void rnpgbe_store_reta(struct rnpgbe_adapter *adapter)
{
u32 i, reta_entries = rnpgbe_rss_indir_tbl_entries(adapter);
struct rnpgbe_hw *hw = &adapter->hw;
u32 reta = 0;
struct rnpgbe_ring *rx_ring;
/* Write redirection table to HW */
for (i = 0; i < reta_entries; i++) {
if (adapter->flags & RNP_FLAG_SRIOV_ENABLED) {
reta = adapter->rss_indir_tbl[i];
} else {
rx_ring = adapter->rx_ring[adapter->rss_indir_tbl[i]];
reta = rx_ring->rnpgbe_queue_idx;
}
hw->rss_indir_tbl[i] = reta;
}
hw->ops.set_rss_table(hw);
}
void rnpgbe_store_key(struct rnpgbe_adapter *adapter)
{
struct rnpgbe_hw *hw = &adapter->hw;
bool sriov_flag = !!(adapter->flags & RNP_FLAG_SRIOV_ENABLED);
hw->ops.set_rss_key(hw, sriov_flag);
}
int rnpgbe_init_rss_key(struct rnpgbe_adapter *adapter)
{
struct rnpgbe_hw *hw = &adapter->hw;
bool sriov_flag = !!(adapter->flags & RNP_FLAG_SRIOV_ENABLED);
/* only init rss key once */
/* no change rss key if user input one */
if (!adapter->rss_key_setup_flag) {
netdev_rss_key_fill(adapter->rss_key, RNP_RSS_KEY_SIZE);
adapter->rss_key_setup_flag = 1;
}
hw->ops.set_rss_key(hw, sriov_flag);
return 0;
}
int rnpgbe_init_rss_table(struct rnpgbe_adapter *adapter)
{
int rx_nums = adapter->num_rx_queues;
int i, j;
struct rnpgbe_hw *hw = &adapter->hw;
struct rnpgbe_ring *rx_ring;
u32 reta = 0;
u32 reta_entries = rnpgbe_rss_indir_tbl_entries(adapter);
if (adapter->flags & RNP_FLAG_DCB_ENABLED) {
rx_nums = rx_nums / adapter->num_tc;
for (i = 0, j = 0; i < 8; i++) {
adapter->rss_tc_tbl[i] = j;
hw->rss_tc_tbl[i] = j;
j = (j + 1) % adapter->num_tc;
}
} else {
for (i = 0, j = 0; i < 8; i++) {
hw->rss_tc_tbl[i] = 0;
adapter->rss_tc_tbl[i] = 0;
}
}
/* adapter->num_q_vectors is not correct */
for (i = 0, j = 0; i < reta_entries; i++) {
/* init with default value */
if (!adapter->rss_tbl_setup_flag)
adapter->rss_indir_tbl[i] = j;
if (adapter->flags & RNP_FLAG_SRIOV_ENABLED) {
/* in sriov mode reta in [0, rx_nums] */
reta = j;
} else {
/* in no sriov, reta is real ring number */
rx_ring = adapter->rx_ring[adapter->rss_indir_tbl[i]];
reta = rx_ring->rnpgbe_queue_idx;
}
/* store rss_indir_tbl */
hw->rss_indir_tbl[i] = reta;
j = (j + 1) % rx_nums;
}
/* tbl only init once */
adapter->rss_tbl_setup_flag = 1;
hw->ops.set_rss_table(hw);
return 0;
}
/* setup to the hw */
s32 rnpgbe_fdir_write_perfect_filter(int fdir_mode, struct rnpgbe_hw *hw,
union rnpgbe_atr_input *filter, u16 hw_id,
u8 queue, bool prio_flag)
{
if (filter->formatted.flow_type == RNP_ATR_FLOW_TYPE_ETHER) {
hw->ops.set_layer2_remapping(hw, filter, hw_id, queue,
prio_flag);
} else {
hw->ops.set_tuple5_remapping(hw, filter, hw_id, queue,
prio_flag);
}
return 0;
}
s32 rnpgbe_fdir_erase_perfect_filter(int fdir_mode, struct rnpgbe_hw *hw,
union rnpgbe_atr_input *input, u16 pri_id)
{
/* just disable filter */
if (input->formatted.flow_type == RNP_ATR_FLOW_TYPE_ETHER) {
hw->ops.clr_layer2_remapping(hw, pri_id);
dbg("disable layer2 %d\n", pri_id);
} else {
hw->ops.clr_tuple5_remapping(hw, pri_id);
dbg("disable tuple5 %d\n", pri_id);
}
return 0;
}