162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "ixgbe.h"
562306a36Sopenharmony_ci#include "ixgbe_sriov.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB
862306a36Sopenharmony_ci/**
962306a36Sopenharmony_ci * ixgbe_cache_ring_dcb_sriov - Descriptor ring to register mapping for SR-IOV
1062306a36Sopenharmony_ci * @adapter: board private structure to initialize
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Cache the descriptor ring offsets for SR-IOV to the assigned rings.  It
1362306a36Sopenharmony_ci * will also try to cache the proper offsets if RSS/FCoE are enabled along
1462306a36Sopenharmony_ci * with VMDq.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci **/
1762306a36Sopenharmony_cistatic bool ixgbe_cache_ring_dcb_sriov(struct ixgbe_adapter *adapter)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci#ifdef IXGBE_FCOE
2062306a36Sopenharmony_ci	struct ixgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE];
2162306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
2262306a36Sopenharmony_ci	struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
2362306a36Sopenharmony_ci	int i;
2462306a36Sopenharmony_ci	u16 reg_idx, pool;
2562306a36Sopenharmony_ci	u8 tcs = adapter->hw_tcs;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	/* verify we have DCB queueing enabled before proceeding */
2862306a36Sopenharmony_ci	if (tcs <= 1)
2962306a36Sopenharmony_ci		return false;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/* verify we have VMDq enabled before proceeding */
3262306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
3362306a36Sopenharmony_ci		return false;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* start at VMDq register offset for SR-IOV enabled setups */
3662306a36Sopenharmony_ci	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
3762306a36Sopenharmony_ci	for (i = 0, pool = 0; i < adapter->num_rx_queues; i++, reg_idx++) {
3862306a36Sopenharmony_ci		/* If we are greater than indices move to next pool */
3962306a36Sopenharmony_ci		if ((reg_idx & ~vmdq->mask) >= tcs) {
4062306a36Sopenharmony_ci			pool++;
4162306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
4262306a36Sopenharmony_ci		}
4362306a36Sopenharmony_ci		adapter->rx_ring[i]->reg_idx = reg_idx;
4462306a36Sopenharmony_ci		adapter->rx_ring[i]->netdev = pool ? NULL : adapter->netdev;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
4862306a36Sopenharmony_ci	for (i = 0; i < adapter->num_tx_queues; i++, reg_idx++) {
4962306a36Sopenharmony_ci		/* If we are greater than indices move to next pool */
5062306a36Sopenharmony_ci		if ((reg_idx & ~vmdq->mask) >= tcs)
5162306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
5262306a36Sopenharmony_ci		adapter->tx_ring[i]->reg_idx = reg_idx;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
5662306a36Sopenharmony_ci	/* nothing to do if FCoE is disabled */
5762306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
5862306a36Sopenharmony_ci		return true;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* The work is already done if the FCoE ring is shared */
6162306a36Sopenharmony_ci	if (fcoe->offset < tcs)
6262306a36Sopenharmony_ci		return true;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* The FCoE rings exist separately, we need to move their reg_idx */
6562306a36Sopenharmony_ci	if (fcoe->indices) {
6662306a36Sopenharmony_ci		u16 queues_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
6762306a36Sopenharmony_ci		u8 fcoe_tc = ixgbe_fcoe_get_tc(adapter);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		reg_idx = (vmdq->offset + vmdq->indices) * queues_per_pool;
7062306a36Sopenharmony_ci		for (i = fcoe->offset; i < adapter->num_rx_queues; i++) {
7162306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask) + fcoe_tc;
7262306a36Sopenharmony_ci			adapter->rx_ring[i]->reg_idx = reg_idx;
7362306a36Sopenharmony_ci			adapter->rx_ring[i]->netdev = adapter->netdev;
7462306a36Sopenharmony_ci			reg_idx++;
7562306a36Sopenharmony_ci		}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci		reg_idx = (vmdq->offset + vmdq->indices) * queues_per_pool;
7862306a36Sopenharmony_ci		for (i = fcoe->offset; i < adapter->num_tx_queues; i++) {
7962306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask) + fcoe_tc;
8062306a36Sopenharmony_ci			adapter->tx_ring[i]->reg_idx = reg_idx;
8162306a36Sopenharmony_ci			reg_idx++;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
8662306a36Sopenharmony_ci	return true;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* ixgbe_get_first_reg_idx - Return first register index associated with ring */
9062306a36Sopenharmony_cistatic void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
9162306a36Sopenharmony_ci				    unsigned int *tx, unsigned int *rx)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
9462306a36Sopenharmony_ci	u8 num_tcs = adapter->hw_tcs;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	*tx = 0;
9762306a36Sopenharmony_ci	*rx = 0;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	switch (hw->mac.type) {
10062306a36Sopenharmony_ci	case ixgbe_mac_82598EB:
10162306a36Sopenharmony_ci		/* TxQs/TC: 4	RxQs/TC: 8 */
10262306a36Sopenharmony_ci		*tx = tc << 2; /* 0, 4,  8, 12, 16, 20, 24, 28 */
10362306a36Sopenharmony_ci		*rx = tc << 3; /* 0, 8, 16, 24, 32, 40, 48, 56 */
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci	case ixgbe_mac_82599EB:
10662306a36Sopenharmony_ci	case ixgbe_mac_X540:
10762306a36Sopenharmony_ci	case ixgbe_mac_X550:
10862306a36Sopenharmony_ci	case ixgbe_mac_X550EM_x:
10962306a36Sopenharmony_ci	case ixgbe_mac_x550em_a:
11062306a36Sopenharmony_ci		if (num_tcs > 4) {
11162306a36Sopenharmony_ci			/*
11262306a36Sopenharmony_ci			 * TCs    : TC0/1 TC2/3 TC4-7
11362306a36Sopenharmony_ci			 * TxQs/TC:    32    16     8
11462306a36Sopenharmony_ci			 * RxQs/TC:    16    16    16
11562306a36Sopenharmony_ci			 */
11662306a36Sopenharmony_ci			*rx = tc << 4;
11762306a36Sopenharmony_ci			if (tc < 3)
11862306a36Sopenharmony_ci				*tx = tc << 5;		/*   0,  32,  64 */
11962306a36Sopenharmony_ci			else if (tc < 5)
12062306a36Sopenharmony_ci				*tx = (tc + 2) << 4;	/*  80,  96 */
12162306a36Sopenharmony_ci			else
12262306a36Sopenharmony_ci				*tx = (tc + 8) << 3;	/* 104, 112, 120 */
12362306a36Sopenharmony_ci		} else {
12462306a36Sopenharmony_ci			/*
12562306a36Sopenharmony_ci			 * TCs    : TC0 TC1 TC2/3
12662306a36Sopenharmony_ci			 * TxQs/TC:  64  32    16
12762306a36Sopenharmony_ci			 * RxQs/TC:  32  32    32
12862306a36Sopenharmony_ci			 */
12962306a36Sopenharmony_ci			*rx = tc << 5;
13062306a36Sopenharmony_ci			if (tc < 2)
13162306a36Sopenharmony_ci				*tx = tc << 6;		/*  0,  64 */
13262306a36Sopenharmony_ci			else
13362306a36Sopenharmony_ci				*tx = (tc + 4) << 4;	/* 96, 112 */
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	default:
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/**
14262306a36Sopenharmony_ci * ixgbe_cache_ring_dcb - Descriptor ring to register mapping for DCB
14362306a36Sopenharmony_ci * @adapter: board private structure to initialize
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * Cache the descriptor ring offsets for DCB to the assigned rings.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci **/
14862306a36Sopenharmony_cistatic bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	u8 num_tcs = adapter->hw_tcs;
15162306a36Sopenharmony_ci	unsigned int tx_idx, rx_idx;
15262306a36Sopenharmony_ci	int tc, offset, rss_i, i;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* verify we have DCB queueing enabled before proceeding */
15562306a36Sopenharmony_ci	if (num_tcs <= 1)
15662306a36Sopenharmony_ci		return false;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	rss_i = adapter->ring_feature[RING_F_RSS].indices;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (tc = 0, offset = 0; tc < num_tcs; tc++, offset += rss_i) {
16162306a36Sopenharmony_ci		ixgbe_get_first_reg_idx(adapter, tc, &tx_idx, &rx_idx);
16262306a36Sopenharmony_ci		for (i = 0; i < rss_i; i++, tx_idx++, rx_idx++) {
16362306a36Sopenharmony_ci			adapter->tx_ring[offset + i]->reg_idx = tx_idx;
16462306a36Sopenharmony_ci			adapter->rx_ring[offset + i]->reg_idx = rx_idx;
16562306a36Sopenharmony_ci			adapter->rx_ring[offset + i]->netdev = adapter->netdev;
16662306a36Sopenharmony_ci			adapter->tx_ring[offset + i]->dcb_tc = tc;
16762306a36Sopenharmony_ci			adapter->rx_ring[offset + i]->dcb_tc = tc;
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return true;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#endif
17562306a36Sopenharmony_ci/**
17662306a36Sopenharmony_ci * ixgbe_cache_ring_sriov - Descriptor ring to register mapping for sriov
17762306a36Sopenharmony_ci * @adapter: board private structure to initialize
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * SR-IOV doesn't use any descriptor rings but changes the default if
18062306a36Sopenharmony_ci * no other mapping is used.
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
18662306a36Sopenharmony_ci	struct ixgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE];
18762306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
18862306a36Sopenharmony_ci	struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
18962306a36Sopenharmony_ci	struct ixgbe_ring_feature *rss = &adapter->ring_feature[RING_F_RSS];
19062306a36Sopenharmony_ci	u16 reg_idx, pool;
19162306a36Sopenharmony_ci	int i;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* only proceed if VMDq is enabled */
19462306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_VMDQ_ENABLED))
19562306a36Sopenharmony_ci		return false;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* start at VMDq register offset for SR-IOV enabled setups */
19862306a36Sopenharmony_ci	pool = 0;
19962306a36Sopenharmony_ci	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
20062306a36Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++, reg_idx++) {
20162306a36Sopenharmony_ci#ifdef IXGBE_FCOE
20262306a36Sopenharmony_ci		/* Allow first FCoE queue to be mapped as RSS */
20362306a36Sopenharmony_ci		if (fcoe->offset && (i > fcoe->offset))
20462306a36Sopenharmony_ci			break;
20562306a36Sopenharmony_ci#endif
20662306a36Sopenharmony_ci		/* If we are greater than indices move to next pool */
20762306a36Sopenharmony_ci		if ((reg_idx & ~vmdq->mask) >= rss->indices) {
20862306a36Sopenharmony_ci			pool++;
20962306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci		adapter->rx_ring[i]->reg_idx = reg_idx;
21262306a36Sopenharmony_ci		adapter->rx_ring[i]->netdev = pool ? NULL : adapter->netdev;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
21662306a36Sopenharmony_ci	/* FCoE uses a linear block of queues so just assigning 1:1 */
21762306a36Sopenharmony_ci	for (; i < adapter->num_rx_queues; i++, reg_idx++) {
21862306a36Sopenharmony_ci		adapter->rx_ring[i]->reg_idx = reg_idx;
21962306a36Sopenharmony_ci		adapter->rx_ring[i]->netdev = adapter->netdev;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#endif
22362306a36Sopenharmony_ci	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
22462306a36Sopenharmony_ci	for (i = 0; i < adapter->num_tx_queues; i++, reg_idx++) {
22562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
22662306a36Sopenharmony_ci		/* Allow first FCoE queue to be mapped as RSS */
22762306a36Sopenharmony_ci		if (fcoe->offset && (i > fcoe->offset))
22862306a36Sopenharmony_ci			break;
22962306a36Sopenharmony_ci#endif
23062306a36Sopenharmony_ci		/* If we are greater than indices move to next pool */
23162306a36Sopenharmony_ci		if ((reg_idx & rss->mask) >= rss->indices)
23262306a36Sopenharmony_ci			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
23362306a36Sopenharmony_ci		adapter->tx_ring[i]->reg_idx = reg_idx;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci#ifdef IXGBE_FCOE
23762306a36Sopenharmony_ci	/* FCoE uses a linear block of queues so just assigning 1:1 */
23862306a36Sopenharmony_ci	for (; i < adapter->num_tx_queues; i++, reg_idx++)
23962306a36Sopenharmony_ci		adapter->tx_ring[i]->reg_idx = reg_idx;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#endif
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return true;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/**
24762306a36Sopenharmony_ci * ixgbe_cache_ring_rss - Descriptor ring to register mapping for RSS
24862306a36Sopenharmony_ci * @adapter: board private structure to initialize
24962306a36Sopenharmony_ci *
25062306a36Sopenharmony_ci * Cache the descriptor ring offsets for RSS to the assigned rings.
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci **/
25362306a36Sopenharmony_cistatic bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	int i, reg_idx;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
25862306a36Sopenharmony_ci		adapter->rx_ring[i]->reg_idx = i;
25962306a36Sopenharmony_ci		adapter->rx_ring[i]->netdev = adapter->netdev;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	for (i = 0, reg_idx = 0; i < adapter->num_tx_queues; i++, reg_idx++)
26262306a36Sopenharmony_ci		adapter->tx_ring[i]->reg_idx = reg_idx;
26362306a36Sopenharmony_ci	for (i = 0; i < adapter->num_xdp_queues; i++, reg_idx++)
26462306a36Sopenharmony_ci		adapter->xdp_ring[i]->reg_idx = reg_idx;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return true;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/**
27062306a36Sopenharmony_ci * ixgbe_cache_ring_register - Descriptor ring to register mapping
27162306a36Sopenharmony_ci * @adapter: board private structure to initialize
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * Once we know the feature-set enabled for the device, we'll cache
27462306a36Sopenharmony_ci * the register offset the descriptor ring is assigned to.
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * Note, the order the various feature calls is important.  It must start with
27762306a36Sopenharmony_ci * the "most" features enabled at the same time, then trickle down to the
27862306a36Sopenharmony_ci * least amount of features turned on at once.
27962306a36Sopenharmony_ci **/
28062306a36Sopenharmony_cistatic void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	/* start with default case */
28362306a36Sopenharmony_ci	adapter->rx_ring[0]->reg_idx = 0;
28462306a36Sopenharmony_ci	adapter->tx_ring[0]->reg_idx = 0;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB
28762306a36Sopenharmony_ci	if (ixgbe_cache_ring_dcb_sriov(adapter))
28862306a36Sopenharmony_ci		return;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (ixgbe_cache_ring_dcb(adapter))
29162306a36Sopenharmony_ci		return;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci#endif
29462306a36Sopenharmony_ci	if (ixgbe_cache_ring_sriov(adapter))
29562306a36Sopenharmony_ci		return;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	ixgbe_cache_ring_rss(adapter);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int ixgbe_xdp_queues(struct ixgbe_adapter *adapter)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	int queues;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	queues = min_t(int, IXGBE_MAX_XDP_QS, nr_cpu_ids);
30562306a36Sopenharmony_ci	return adapter->xdp_prog ? queues : 0;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci#define IXGBE_RSS_64Q_MASK	0x3F
30962306a36Sopenharmony_ci#define IXGBE_RSS_16Q_MASK	0xF
31062306a36Sopenharmony_ci#define IXGBE_RSS_8Q_MASK	0x7
31162306a36Sopenharmony_ci#define IXGBE_RSS_4Q_MASK	0x3
31262306a36Sopenharmony_ci#define IXGBE_RSS_2Q_MASK	0x1
31362306a36Sopenharmony_ci#define IXGBE_RSS_DISABLED_MASK	0x0
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * ixgbe_set_dcb_sriov_queues: Allocate queues for SR-IOV devices w/ DCB
31862306a36Sopenharmony_ci * @adapter: board private structure to initialize
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * When SR-IOV (Single Root IO Virtualiztion) is enabled, allocate queues
32162306a36Sopenharmony_ci * and VM pools where appropriate.  Also assign queues based on DCB
32262306a36Sopenharmony_ci * priorities and map accordingly..
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci **/
32562306a36Sopenharmony_cistatic bool ixgbe_set_dcb_sriov_queues(struct ixgbe_adapter *adapter)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	int i;
32862306a36Sopenharmony_ci	u16 vmdq_i = adapter->ring_feature[RING_F_VMDQ].limit;
32962306a36Sopenharmony_ci	u16 vmdq_m = 0;
33062306a36Sopenharmony_ci#ifdef IXGBE_FCOE
33162306a36Sopenharmony_ci	u16 fcoe_i = 0;
33262306a36Sopenharmony_ci#endif
33362306a36Sopenharmony_ci	u8 tcs = adapter->hw_tcs;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* verify we have DCB queueing enabled before proceeding */
33662306a36Sopenharmony_ci	if (tcs <= 1)
33762306a36Sopenharmony_ci		return false;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* verify we have VMDq enabled before proceeding */
34062306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
34162306a36Sopenharmony_ci		return false;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* limit VMDq instances on the PF by number of Tx queues */
34462306a36Sopenharmony_ci	vmdq_i = min_t(u16, vmdq_i, MAX_TX_QUEUES / tcs);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* Add starting offset to total pool count */
34762306a36Sopenharmony_ci	vmdq_i += adapter->ring_feature[RING_F_VMDQ].offset;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* 16 pools w/ 8 TC per pool */
35062306a36Sopenharmony_ci	if (tcs > 4) {
35162306a36Sopenharmony_ci		vmdq_i = min_t(u16, vmdq_i, 16);
35262306a36Sopenharmony_ci		vmdq_m = IXGBE_82599_VMDQ_8Q_MASK;
35362306a36Sopenharmony_ci	/* 32 pools w/ 4 TC per pool */
35462306a36Sopenharmony_ci	} else {
35562306a36Sopenharmony_ci		vmdq_i = min_t(u16, vmdq_i, 32);
35662306a36Sopenharmony_ci		vmdq_m = IXGBE_82599_VMDQ_4Q_MASK;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci#ifdef IXGBE_FCOE
36062306a36Sopenharmony_ci	/* queues in the remaining pools are available for FCoE */
36162306a36Sopenharmony_ci	fcoe_i = (128 / __ALIGN_MASK(1, ~vmdq_m)) - vmdq_i;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci#endif
36462306a36Sopenharmony_ci	/* remove the starting offset from the pool count */
36562306a36Sopenharmony_ci	vmdq_i -= adapter->ring_feature[RING_F_VMDQ].offset;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* save features for later use */
36862306a36Sopenharmony_ci	adapter->ring_feature[RING_F_VMDQ].indices = vmdq_i;
36962306a36Sopenharmony_ci	adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * We do not support DCB, VMDq, and RSS all simultaneously
37362306a36Sopenharmony_ci	 * so we will disable RSS since it is the lowest priority
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].indices = 1;
37662306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].mask = IXGBE_RSS_DISABLED_MASK;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* disable ATR as it is not supported when VMDq is enabled */
37962306a36Sopenharmony_ci	adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	adapter->num_rx_pools = vmdq_i;
38262306a36Sopenharmony_ci	adapter->num_rx_queues_per_pool = tcs;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	adapter->num_tx_queues = vmdq_i * tcs;
38562306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
38662306a36Sopenharmony_ci	adapter->num_rx_queues = vmdq_i * tcs;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci#ifdef IXGBE_FCOE
38962306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
39062306a36Sopenharmony_ci		struct ixgbe_ring_feature *fcoe;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci		fcoe = &adapter->ring_feature[RING_F_FCOE];
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		/* limit ourselves based on feature limits */
39562306a36Sopenharmony_ci		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		if (fcoe_i) {
39862306a36Sopenharmony_ci			/* alloc queues for FCoE separately */
39962306a36Sopenharmony_ci			fcoe->indices = fcoe_i;
40062306a36Sopenharmony_ci			fcoe->offset = vmdq_i * tcs;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci			/* add queues to adapter */
40362306a36Sopenharmony_ci			adapter->num_tx_queues += fcoe_i;
40462306a36Sopenharmony_ci			adapter->num_rx_queues += fcoe_i;
40562306a36Sopenharmony_ci		} else if (tcs > 1) {
40662306a36Sopenharmony_ci			/* use queue belonging to FcoE TC */
40762306a36Sopenharmony_ci			fcoe->indices = 1;
40862306a36Sopenharmony_ci			fcoe->offset = ixgbe_fcoe_get_tc(adapter);
40962306a36Sopenharmony_ci		} else {
41062306a36Sopenharmony_ci			adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci			fcoe->indices = 0;
41362306a36Sopenharmony_ci			fcoe->offset = 0;
41462306a36Sopenharmony_ci		}
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
41862306a36Sopenharmony_ci	/* configure TC to queue mapping */
41962306a36Sopenharmony_ci	for (i = 0; i < tcs; i++)
42062306a36Sopenharmony_ci		netdev_set_tc_queue(adapter->netdev, i, 1, i);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return true;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct net_device *dev = adapter->netdev;
42862306a36Sopenharmony_ci	struct ixgbe_ring_feature *f;
42962306a36Sopenharmony_ci	int rss_i, rss_m, i;
43062306a36Sopenharmony_ci	int tcs;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* Map queue offset and counts onto allocated tx queues */
43362306a36Sopenharmony_ci	tcs = adapter->hw_tcs;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* verify we have DCB queueing enabled before proceeding */
43662306a36Sopenharmony_ci	if (tcs <= 1)
43762306a36Sopenharmony_ci		return false;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* determine the upper limit for our current DCB mode */
44062306a36Sopenharmony_ci	rss_i = dev->num_tx_queues / tcs;
44162306a36Sopenharmony_ci	if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
44262306a36Sopenharmony_ci		/* 8 TC w/ 4 queues per TC */
44362306a36Sopenharmony_ci		rss_i = min_t(u16, rss_i, 4);
44462306a36Sopenharmony_ci		rss_m = IXGBE_RSS_4Q_MASK;
44562306a36Sopenharmony_ci	} else if (tcs > 4) {
44662306a36Sopenharmony_ci		/* 8 TC w/ 8 queues per TC */
44762306a36Sopenharmony_ci		rss_i = min_t(u16, rss_i, 8);
44862306a36Sopenharmony_ci		rss_m = IXGBE_RSS_8Q_MASK;
44962306a36Sopenharmony_ci	} else {
45062306a36Sopenharmony_ci		/* 4 TC w/ 16 queues per TC */
45162306a36Sopenharmony_ci		rss_i = min_t(u16, rss_i, 16);
45262306a36Sopenharmony_ci		rss_m = IXGBE_RSS_16Q_MASK;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* set RSS mask and indices */
45662306a36Sopenharmony_ci	f = &adapter->ring_feature[RING_F_RSS];
45762306a36Sopenharmony_ci	rss_i = min_t(int, rss_i, f->limit);
45862306a36Sopenharmony_ci	f->indices = rss_i;
45962306a36Sopenharmony_ci	f->mask = rss_m;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* disable ATR as it is not supported when multiple TCs are enabled */
46262306a36Sopenharmony_ci	adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#ifdef IXGBE_FCOE
46562306a36Sopenharmony_ci	/* FCoE enabled queues require special configuration indexed
46662306a36Sopenharmony_ci	 * by feature specific indices and offset. Here we map FCoE
46762306a36Sopenharmony_ci	 * indices onto the DCB queue pairs allowing FCoE to own
46862306a36Sopenharmony_ci	 * configuration later.
46962306a36Sopenharmony_ci	 */
47062306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
47162306a36Sopenharmony_ci		u8 tc = ixgbe_fcoe_get_tc(adapter);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		f = &adapter->ring_feature[RING_F_FCOE];
47462306a36Sopenharmony_ci		f->indices = min_t(u16, rss_i, f->limit);
47562306a36Sopenharmony_ci		f->offset = rss_i * tc;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
47962306a36Sopenharmony_ci	for (i = 0; i < tcs; i++)
48062306a36Sopenharmony_ci		netdev_set_tc_queue(dev, i, rss_i, rss_i * i);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	adapter->num_tx_queues = rss_i * tcs;
48362306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
48462306a36Sopenharmony_ci	adapter->num_rx_queues = rss_i * tcs;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return true;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci#endif
49062306a36Sopenharmony_ci/**
49162306a36Sopenharmony_ci * ixgbe_set_sriov_queues - Allocate queues for SR-IOV devices
49262306a36Sopenharmony_ci * @adapter: board private structure to initialize
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * When SR-IOV (Single Root IO Virtualiztion) is enabled, allocate queues
49562306a36Sopenharmony_ci * and VM pools where appropriate.  If RSS is available, then also try and
49662306a36Sopenharmony_ci * enable RSS and map accordingly.
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci **/
49962306a36Sopenharmony_cistatic bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	u16 vmdq_i = adapter->ring_feature[RING_F_VMDQ].limit;
50262306a36Sopenharmony_ci	u16 vmdq_m = 0;
50362306a36Sopenharmony_ci	u16 rss_i = adapter->ring_feature[RING_F_RSS].limit;
50462306a36Sopenharmony_ci	u16 rss_m = IXGBE_RSS_DISABLED_MASK;
50562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
50662306a36Sopenharmony_ci	u16 fcoe_i = 0;
50762306a36Sopenharmony_ci#endif
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* only proceed if SR-IOV is enabled */
51062306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
51162306a36Sopenharmony_ci		return false;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* limit l2fwd RSS based on total Tx queue limit */
51462306a36Sopenharmony_ci	rss_i = min_t(u16, rss_i, MAX_TX_QUEUES / vmdq_i);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Add starting offset to total pool count */
51762306a36Sopenharmony_ci	vmdq_i += adapter->ring_feature[RING_F_VMDQ].offset;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* double check we are limited to maximum pools */
52062306a36Sopenharmony_ci	vmdq_i = min_t(u16, IXGBE_MAX_VMDQ_INDICES, vmdq_i);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	/* 64 pool mode with 2 queues per pool */
52362306a36Sopenharmony_ci	if (vmdq_i > 32) {
52462306a36Sopenharmony_ci		vmdq_m = IXGBE_82599_VMDQ_2Q_MASK;
52562306a36Sopenharmony_ci		rss_m = IXGBE_RSS_2Q_MASK;
52662306a36Sopenharmony_ci		rss_i = min_t(u16, rss_i, 2);
52762306a36Sopenharmony_ci	/* 32 pool mode with up to 4 queues per pool */
52862306a36Sopenharmony_ci	} else {
52962306a36Sopenharmony_ci		vmdq_m = IXGBE_82599_VMDQ_4Q_MASK;
53062306a36Sopenharmony_ci		rss_m = IXGBE_RSS_4Q_MASK;
53162306a36Sopenharmony_ci		/* We can support 4, 2, or 1 queues */
53262306a36Sopenharmony_ci		rss_i = (rss_i > 3) ? 4 : (rss_i > 1) ? 2 : 1;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci#ifdef IXGBE_FCOE
53662306a36Sopenharmony_ci	/* queues in the remaining pools are available for FCoE */
53762306a36Sopenharmony_ci	fcoe_i = 128 - (vmdq_i * __ALIGN_MASK(1, ~vmdq_m));
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci#endif
54062306a36Sopenharmony_ci	/* remove the starting offset from the pool count */
54162306a36Sopenharmony_ci	vmdq_i -= adapter->ring_feature[RING_F_VMDQ].offset;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* save features for later use */
54462306a36Sopenharmony_ci	adapter->ring_feature[RING_F_VMDQ].indices = vmdq_i;
54562306a36Sopenharmony_ci	adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* limit RSS based on user input and save for later use */
54862306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].indices = rss_i;
54962306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].mask = rss_m;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	adapter->num_rx_pools = vmdq_i;
55262306a36Sopenharmony_ci	adapter->num_rx_queues_per_pool = rss_i;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	adapter->num_rx_queues = vmdq_i * rss_i;
55562306a36Sopenharmony_ci	adapter->num_tx_queues = vmdq_i * rss_i;
55662306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* disable ATR as it is not supported when VMDq is enabled */
55962306a36Sopenharmony_ci	adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci#ifdef IXGBE_FCOE
56262306a36Sopenharmony_ci	/*
56362306a36Sopenharmony_ci	 * FCoE can use rings from adjacent buffers to allow RSS
56462306a36Sopenharmony_ci	 * like behavior.  To account for this we need to add the
56562306a36Sopenharmony_ci	 * FCoE indices to the total ring count.
56662306a36Sopenharmony_ci	 */
56762306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
56862306a36Sopenharmony_ci		struct ixgbe_ring_feature *fcoe;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		fcoe = &adapter->ring_feature[RING_F_FCOE];
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci		/* limit ourselves based on feature limits */
57362306a36Sopenharmony_ci		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		if (vmdq_i > 1 && fcoe_i) {
57662306a36Sopenharmony_ci			/* alloc queues for FCoE separately */
57762306a36Sopenharmony_ci			fcoe->indices = fcoe_i;
57862306a36Sopenharmony_ci			fcoe->offset = vmdq_i * rss_i;
57962306a36Sopenharmony_ci		} else {
58062306a36Sopenharmony_ci			/* merge FCoE queues with RSS queues */
58162306a36Sopenharmony_ci			fcoe_i = min_t(u16, fcoe_i + rss_i, num_online_cpus());
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci			/* limit indices to rss_i if MSI-X is disabled */
58462306a36Sopenharmony_ci			if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
58562306a36Sopenharmony_ci				fcoe_i = rss_i;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			/* attempt to reserve some queues for just FCoE */
58862306a36Sopenharmony_ci			fcoe->indices = min_t(u16, fcoe_i, fcoe->limit);
58962306a36Sopenharmony_ci			fcoe->offset = fcoe_i - fcoe->indices;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci			fcoe_i -= rss_i;
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		/* add queues to adapter */
59562306a36Sopenharmony_ci		adapter->num_tx_queues += fcoe_i;
59662306a36Sopenharmony_ci		adapter->num_rx_queues += fcoe_i;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci#endif
60062306a36Sopenharmony_ci	/* To support macvlan offload we have to use num_tc to
60162306a36Sopenharmony_ci	 * restrict the queues that can be used by the device.
60262306a36Sopenharmony_ci	 * By doing this we can avoid reporting a false number of
60362306a36Sopenharmony_ci	 * queues.
60462306a36Sopenharmony_ci	 */
60562306a36Sopenharmony_ci	if (vmdq_i > 1)
60662306a36Sopenharmony_ci		netdev_set_num_tc(adapter->netdev, 1);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* populate TC0 for use by pool 0 */
60962306a36Sopenharmony_ci	netdev_set_tc_queue(adapter->netdev, 0,
61062306a36Sopenharmony_ci			    adapter->num_rx_queues_per_pool, 0);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return true;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/**
61662306a36Sopenharmony_ci * ixgbe_set_rss_queues - Allocate queues for RSS
61762306a36Sopenharmony_ci * @adapter: board private structure to initialize
61862306a36Sopenharmony_ci *
61962306a36Sopenharmony_ci * This is our "base" multiqueue mode.  RSS (Receive Side Scaling) will try
62062306a36Sopenharmony_ci * to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
62162306a36Sopenharmony_ci *
62262306a36Sopenharmony_ci **/
62362306a36Sopenharmony_cistatic bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
62662306a36Sopenharmony_ci	struct ixgbe_ring_feature *f;
62762306a36Sopenharmony_ci	u16 rss_i;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/* set mask for 16 queue limit of RSS */
63062306a36Sopenharmony_ci	f = &adapter->ring_feature[RING_F_RSS];
63162306a36Sopenharmony_ci	rss_i = f->limit;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	f->indices = rss_i;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (hw->mac.type < ixgbe_mac_X550)
63662306a36Sopenharmony_ci		f->mask = IXGBE_RSS_16Q_MASK;
63762306a36Sopenharmony_ci	else
63862306a36Sopenharmony_ci		f->mask = IXGBE_RSS_64Q_MASK;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* disable ATR by default, it will be configured below */
64162306a36Sopenharmony_ci	adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/*
64462306a36Sopenharmony_ci	 * Use Flow Director in addition to RSS to ensure the best
64562306a36Sopenharmony_ci	 * distribution of flows across cores, even when an FDIR flow
64662306a36Sopenharmony_ci	 * isn't matched.
64762306a36Sopenharmony_ci	 */
64862306a36Sopenharmony_ci	if (rss_i > 1 && adapter->atr_sample_rate) {
64962306a36Sopenharmony_ci		f = &adapter->ring_feature[RING_F_FDIR];
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		rss_i = f->indices = f->limit;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
65462306a36Sopenharmony_ci			adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci#ifdef IXGBE_FCOE
65862306a36Sopenharmony_ci	/*
65962306a36Sopenharmony_ci	 * FCoE can exist on the same rings as standard network traffic
66062306a36Sopenharmony_ci	 * however it is preferred to avoid that if possible.  In order
66162306a36Sopenharmony_ci	 * to get the best performance we allocate as many FCoE queues
66262306a36Sopenharmony_ci	 * as we can and we place them at the end of the ring array to
66362306a36Sopenharmony_ci	 * avoid sharing queues with standard RSS on systems with 24 or
66462306a36Sopenharmony_ci	 * more CPUs.
66562306a36Sopenharmony_ci	 */
66662306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
66762306a36Sopenharmony_ci		struct net_device *dev = adapter->netdev;
66862306a36Sopenharmony_ci		u16 fcoe_i;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		f = &adapter->ring_feature[RING_F_FCOE];
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		/* merge FCoE queues with RSS queues */
67362306a36Sopenharmony_ci		fcoe_i = min_t(u16, f->limit + rss_i, num_online_cpus());
67462306a36Sopenharmony_ci		fcoe_i = min_t(u16, fcoe_i, dev->num_tx_queues);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		/* limit indices to rss_i if MSI-X is disabled */
67762306a36Sopenharmony_ci		if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
67862306a36Sopenharmony_ci			fcoe_i = rss_i;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		/* attempt to reserve some queues for just FCoE */
68162306a36Sopenharmony_ci		f->indices = min_t(u16, fcoe_i, f->limit);
68262306a36Sopenharmony_ci		f->offset = fcoe_i - f->indices;
68362306a36Sopenharmony_ci		rss_i = max_t(u16, fcoe_i, rss_i);
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
68762306a36Sopenharmony_ci	adapter->num_rx_queues = rss_i;
68862306a36Sopenharmony_ci	adapter->num_tx_queues = rss_i;
68962306a36Sopenharmony_ci	adapter->num_xdp_queues = ixgbe_xdp_queues(adapter);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return true;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/**
69562306a36Sopenharmony_ci * ixgbe_set_num_queues - Allocate queues for device, feature dependent
69662306a36Sopenharmony_ci * @adapter: board private structure to initialize
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * This is the top level queue allocation routine.  The order here is very
69962306a36Sopenharmony_ci * important, starting with the "most" number of features turned on at once,
70062306a36Sopenharmony_ci * and ending with the smallest set of features.  This way large combinations
70162306a36Sopenharmony_ci * can be allocated if they're turned on, and smaller combinations are the
70262306a36Sopenharmony_ci * fallthrough conditions.
70362306a36Sopenharmony_ci *
70462306a36Sopenharmony_ci **/
70562306a36Sopenharmony_cistatic void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	/* Start with base case */
70862306a36Sopenharmony_ci	adapter->num_rx_queues = 1;
70962306a36Sopenharmony_ci	adapter->num_tx_queues = 1;
71062306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
71162306a36Sopenharmony_ci	adapter->num_rx_pools = 1;
71262306a36Sopenharmony_ci	adapter->num_rx_queues_per_pool = 1;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB
71562306a36Sopenharmony_ci	if (ixgbe_set_dcb_sriov_queues(adapter))
71662306a36Sopenharmony_ci		return;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (ixgbe_set_dcb_queues(adapter))
71962306a36Sopenharmony_ci		return;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci#endif
72262306a36Sopenharmony_ci	if (ixgbe_set_sriov_queues(adapter))
72362306a36Sopenharmony_ci		return;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ixgbe_set_rss_queues(adapter);
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/**
72962306a36Sopenharmony_ci * ixgbe_acquire_msix_vectors - acquire MSI-X vectors
73062306a36Sopenharmony_ci * @adapter: board private structure
73162306a36Sopenharmony_ci *
73262306a36Sopenharmony_ci * Attempts to acquire a suitable range of MSI-X vector interrupts. Will
73362306a36Sopenharmony_ci * return a negative error code if unable to acquire MSI-X vectors for any
73462306a36Sopenharmony_ci * reason.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic int ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct ixgbe_hw *hw = &adapter->hw;
73962306a36Sopenharmony_ci	int i, vectors, vector_threshold;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* We start by asking for one vector per queue pair with XDP queues
74262306a36Sopenharmony_ci	 * being stacked with TX queues.
74362306a36Sopenharmony_ci	 */
74462306a36Sopenharmony_ci	vectors = max(adapter->num_rx_queues, adapter->num_tx_queues);
74562306a36Sopenharmony_ci	vectors = max(vectors, adapter->num_xdp_queues);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* It is easy to be greedy for MSI-X vectors. However, it really
74862306a36Sopenharmony_ci	 * doesn't do much good if we have a lot more vectors than CPUs. We'll
74962306a36Sopenharmony_ci	 * be somewhat conservative and only ask for (roughly) the same number
75062306a36Sopenharmony_ci	 * of vectors as there are CPUs.
75162306a36Sopenharmony_ci	 */
75262306a36Sopenharmony_ci	vectors = min_t(int, vectors, num_online_cpus());
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	/* Some vectors are necessary for non-queue interrupts */
75562306a36Sopenharmony_ci	vectors += NON_Q_VECTORS;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Hardware can only support a maximum of hw.mac->max_msix_vectors.
75862306a36Sopenharmony_ci	 * With features such as RSS and VMDq, we can easily surpass the
75962306a36Sopenharmony_ci	 * number of Rx and Tx descriptor queues supported by our device.
76062306a36Sopenharmony_ci	 * Thus, we cap the maximum in the rare cases where the CPU count also
76162306a36Sopenharmony_ci	 * exceeds our vector limit
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	vectors = min_t(int, vectors, hw->mac.max_msix_vectors);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/* We want a minimum of two MSI-X vectors for (1) a TxQ[0] + RxQ[0]
76662306a36Sopenharmony_ci	 * handler, and (2) an Other (Link Status Change, etc.) handler.
76762306a36Sopenharmony_ci	 */
76862306a36Sopenharmony_ci	vector_threshold = MIN_MSIX_COUNT;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	adapter->msix_entries = kcalloc(vectors,
77162306a36Sopenharmony_ci					sizeof(struct msix_entry),
77262306a36Sopenharmony_ci					GFP_KERNEL);
77362306a36Sopenharmony_ci	if (!adapter->msix_entries)
77462306a36Sopenharmony_ci		return -ENOMEM;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	for (i = 0; i < vectors; i++)
77762306a36Sopenharmony_ci		adapter->msix_entries[i].entry = i;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
78062306a36Sopenharmony_ci					vector_threshold, vectors);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (vectors < 0) {
78362306a36Sopenharmony_ci		/* A negative count of allocated vectors indicates an error in
78462306a36Sopenharmony_ci		 * acquiring within the specified range of MSI-X vectors
78562306a36Sopenharmony_ci		 */
78662306a36Sopenharmony_ci		e_dev_warn("Failed to allocate MSI-X interrupts. Err: %d\n",
78762306a36Sopenharmony_ci			   vectors);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
79062306a36Sopenharmony_ci		kfree(adapter->msix_entries);
79162306a36Sopenharmony_ci		adapter->msix_entries = NULL;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		return vectors;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* we successfully allocated some number of vectors within our
79762306a36Sopenharmony_ci	 * requested range.
79862306a36Sopenharmony_ci	 */
79962306a36Sopenharmony_ci	adapter->flags |= IXGBE_FLAG_MSIX_ENABLED;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/* Adjust for only the vectors we'll use, which is minimum
80262306a36Sopenharmony_ci	 * of max_q_vectors, or the number of vectors we were allocated.
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	vectors -= NON_Q_VECTORS;
80562306a36Sopenharmony_ci	adapter->num_q_vectors = min_t(int, vectors, adapter->max_q_vectors);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic void ixgbe_add_ring(struct ixgbe_ring *ring,
81162306a36Sopenharmony_ci			   struct ixgbe_ring_container *head)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	ring->next = head->ring;
81462306a36Sopenharmony_ci	head->ring = ring;
81562306a36Sopenharmony_ci	head->count++;
81662306a36Sopenharmony_ci	head->next_update = jiffies + 1;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/**
82062306a36Sopenharmony_ci * ixgbe_alloc_q_vector - Allocate memory for a single interrupt vector
82162306a36Sopenharmony_ci * @adapter: board private structure to initialize
82262306a36Sopenharmony_ci * @v_count: q_vectors allocated on adapter, used for ring interleaving
82362306a36Sopenharmony_ci * @v_idx: index of vector in adapter struct
82462306a36Sopenharmony_ci * @txr_count: total number of Tx rings to allocate
82562306a36Sopenharmony_ci * @txr_idx: index of first Tx ring to allocate
82662306a36Sopenharmony_ci * @xdp_count: total number of XDP rings to allocate
82762306a36Sopenharmony_ci * @xdp_idx: index of first XDP ring to allocate
82862306a36Sopenharmony_ci * @rxr_count: total number of Rx rings to allocate
82962306a36Sopenharmony_ci * @rxr_idx: index of first Rx ring to allocate
83062306a36Sopenharmony_ci *
83162306a36Sopenharmony_ci * We allocate one q_vector.  If allocation fails we return -ENOMEM.
83262306a36Sopenharmony_ci **/
83362306a36Sopenharmony_cistatic int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
83462306a36Sopenharmony_ci				int v_count, int v_idx,
83562306a36Sopenharmony_ci				int txr_count, int txr_idx,
83662306a36Sopenharmony_ci				int xdp_count, int xdp_idx,
83762306a36Sopenharmony_ci				int rxr_count, int rxr_idx)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	int node = dev_to_node(&adapter->pdev->dev);
84062306a36Sopenharmony_ci	struct ixgbe_q_vector *q_vector;
84162306a36Sopenharmony_ci	struct ixgbe_ring *ring;
84262306a36Sopenharmony_ci	int cpu = -1;
84362306a36Sopenharmony_ci	int ring_count;
84462306a36Sopenharmony_ci	u8 tcs = adapter->hw_tcs;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	ring_count = txr_count + rxr_count + xdp_count;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* customize cpu for Flow Director mapping */
84962306a36Sopenharmony_ci	if ((tcs <= 1) && !(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) {
85062306a36Sopenharmony_ci		u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
85162306a36Sopenharmony_ci		if (rss_i > 1 && adapter->atr_sample_rate) {
85262306a36Sopenharmony_ci			cpu = cpumask_local_spread(v_idx, node);
85362306a36Sopenharmony_ci			node = cpu_to_node(cpu);
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	/* allocate q_vector and rings */
85862306a36Sopenharmony_ci	q_vector = kzalloc_node(struct_size(q_vector, ring, ring_count),
85962306a36Sopenharmony_ci				GFP_KERNEL, node);
86062306a36Sopenharmony_ci	if (!q_vector)
86162306a36Sopenharmony_ci		q_vector = kzalloc(struct_size(q_vector, ring, ring_count),
86262306a36Sopenharmony_ci				   GFP_KERNEL);
86362306a36Sopenharmony_ci	if (!q_vector)
86462306a36Sopenharmony_ci		return -ENOMEM;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* setup affinity mask and node */
86762306a36Sopenharmony_ci	if (cpu != -1)
86862306a36Sopenharmony_ci		cpumask_set_cpu(cpu, &q_vector->affinity_mask);
86962306a36Sopenharmony_ci	q_vector->numa_node = node;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCA
87262306a36Sopenharmony_ci	/* initialize CPU for DCA */
87362306a36Sopenharmony_ci	q_vector->cpu = -1;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci#endif
87662306a36Sopenharmony_ci	/* initialize NAPI */
87762306a36Sopenharmony_ci	netif_napi_add(adapter->netdev, &q_vector->napi, ixgbe_poll);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* tie q_vector and adapter together */
88062306a36Sopenharmony_ci	adapter->q_vector[v_idx] = q_vector;
88162306a36Sopenharmony_ci	q_vector->adapter = adapter;
88262306a36Sopenharmony_ci	q_vector->v_idx = v_idx;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* initialize work limits */
88562306a36Sopenharmony_ci	q_vector->tx.work_limit = adapter->tx_work_limit;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Initialize setting for adaptive ITR */
88862306a36Sopenharmony_ci	q_vector->tx.itr = IXGBE_ITR_ADAPTIVE_MAX_USECS |
88962306a36Sopenharmony_ci			   IXGBE_ITR_ADAPTIVE_LATENCY;
89062306a36Sopenharmony_ci	q_vector->rx.itr = IXGBE_ITR_ADAPTIVE_MAX_USECS |
89162306a36Sopenharmony_ci			   IXGBE_ITR_ADAPTIVE_LATENCY;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* intialize ITR */
89462306a36Sopenharmony_ci	if (txr_count && !rxr_count) {
89562306a36Sopenharmony_ci		/* tx only vector */
89662306a36Sopenharmony_ci		if (adapter->tx_itr_setting == 1)
89762306a36Sopenharmony_ci			q_vector->itr = IXGBE_12K_ITR;
89862306a36Sopenharmony_ci		else
89962306a36Sopenharmony_ci			q_vector->itr = adapter->tx_itr_setting;
90062306a36Sopenharmony_ci	} else {
90162306a36Sopenharmony_ci		/* rx or rx/tx vector */
90262306a36Sopenharmony_ci		if (adapter->rx_itr_setting == 1)
90362306a36Sopenharmony_ci			q_vector->itr = IXGBE_20K_ITR;
90462306a36Sopenharmony_ci		else
90562306a36Sopenharmony_ci			q_vector->itr = adapter->rx_itr_setting;
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* initialize pointer to rings */
90962306a36Sopenharmony_ci	ring = q_vector->ring;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	while (txr_count) {
91262306a36Sopenharmony_ci		/* assign generic ring traits */
91362306a36Sopenharmony_ci		ring->dev = &adapter->pdev->dev;
91462306a36Sopenharmony_ci		ring->netdev = adapter->netdev;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		/* configure backlink on ring */
91762306a36Sopenharmony_ci		ring->q_vector = q_vector;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		/* update q_vector Tx values */
92062306a36Sopenharmony_ci		ixgbe_add_ring(ring, &q_vector->tx);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci		/* apply Tx specific ring traits */
92362306a36Sopenharmony_ci		ring->count = adapter->tx_ring_count;
92462306a36Sopenharmony_ci		ring->queue_index = txr_idx;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		/* assign ring to adapter */
92762306a36Sopenharmony_ci		WRITE_ONCE(adapter->tx_ring[txr_idx], ring);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		/* update count and index */
93062306a36Sopenharmony_ci		txr_count--;
93162306a36Sopenharmony_ci		txr_idx += v_count;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		/* push pointer to next ring */
93462306a36Sopenharmony_ci		ring++;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	while (xdp_count) {
93862306a36Sopenharmony_ci		/* assign generic ring traits */
93962306a36Sopenharmony_ci		ring->dev = &adapter->pdev->dev;
94062306a36Sopenharmony_ci		ring->netdev = adapter->netdev;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		/* configure backlink on ring */
94362306a36Sopenharmony_ci		ring->q_vector = q_vector;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		/* update q_vector Tx values */
94662306a36Sopenharmony_ci		ixgbe_add_ring(ring, &q_vector->tx);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		/* apply Tx specific ring traits */
94962306a36Sopenharmony_ci		ring->count = adapter->tx_ring_count;
95062306a36Sopenharmony_ci		ring->queue_index = xdp_idx;
95162306a36Sopenharmony_ci		set_ring_xdp(ring);
95262306a36Sopenharmony_ci		spin_lock_init(&ring->tx_lock);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci		/* assign ring to adapter */
95562306a36Sopenharmony_ci		WRITE_ONCE(adapter->xdp_ring[xdp_idx], ring);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		/* update count and index */
95862306a36Sopenharmony_ci		xdp_count--;
95962306a36Sopenharmony_ci		xdp_idx++;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		/* push pointer to next ring */
96262306a36Sopenharmony_ci		ring++;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	while (rxr_count) {
96662306a36Sopenharmony_ci		/* assign generic ring traits */
96762306a36Sopenharmony_ci		ring->dev = &adapter->pdev->dev;
96862306a36Sopenharmony_ci		ring->netdev = adapter->netdev;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci		/* configure backlink on ring */
97162306a36Sopenharmony_ci		ring->q_vector = q_vector;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		/* update q_vector Rx values */
97462306a36Sopenharmony_ci		ixgbe_add_ring(ring, &q_vector->rx);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		/*
97762306a36Sopenharmony_ci		 * 82599 errata, UDP frames with a 0 checksum
97862306a36Sopenharmony_ci		 * can be marked as checksum errors.
97962306a36Sopenharmony_ci		 */
98062306a36Sopenharmony_ci		if (adapter->hw.mac.type == ixgbe_mac_82599EB)
98162306a36Sopenharmony_ci			set_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, &ring->state);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci#ifdef IXGBE_FCOE
98462306a36Sopenharmony_ci		if (adapter->netdev->features & NETIF_F_FCOE_MTU) {
98562306a36Sopenharmony_ci			struct ixgbe_ring_feature *f;
98662306a36Sopenharmony_ci			f = &adapter->ring_feature[RING_F_FCOE];
98762306a36Sopenharmony_ci			if ((rxr_idx >= f->offset) &&
98862306a36Sopenharmony_ci			    (rxr_idx < f->offset + f->indices))
98962306a36Sopenharmony_ci				set_bit(__IXGBE_RX_FCOE, &ring->state);
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci#endif /* IXGBE_FCOE */
99362306a36Sopenharmony_ci		/* apply Rx specific ring traits */
99462306a36Sopenharmony_ci		ring->count = adapter->rx_ring_count;
99562306a36Sopenharmony_ci		ring->queue_index = rxr_idx;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		/* assign ring to adapter */
99862306a36Sopenharmony_ci		WRITE_ONCE(adapter->rx_ring[rxr_idx], ring);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		/* update count and index */
100162306a36Sopenharmony_ci		rxr_count--;
100262306a36Sopenharmony_ci		rxr_idx += v_count;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		/* push pointer to next ring */
100562306a36Sopenharmony_ci		ring++;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	return 0;
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci/**
101262306a36Sopenharmony_ci * ixgbe_free_q_vector - Free memory allocated for specific interrupt vector
101362306a36Sopenharmony_ci * @adapter: board private structure to initialize
101462306a36Sopenharmony_ci * @v_idx: Index of vector to be freed
101562306a36Sopenharmony_ci *
101662306a36Sopenharmony_ci * This function frees the memory allocated to the q_vector.  In addition if
101762306a36Sopenharmony_ci * NAPI is enabled it will delete any references to the NAPI struct prior
101862306a36Sopenharmony_ci * to freeing the q_vector.
101962306a36Sopenharmony_ci **/
102062306a36Sopenharmony_cistatic void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct ixgbe_q_vector *q_vector = adapter->q_vector[v_idx];
102362306a36Sopenharmony_ci	struct ixgbe_ring *ring;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	ixgbe_for_each_ring(ring, q_vector->tx) {
102662306a36Sopenharmony_ci		if (ring_is_xdp(ring))
102762306a36Sopenharmony_ci			WRITE_ONCE(adapter->xdp_ring[ring->queue_index], NULL);
102862306a36Sopenharmony_ci		else
102962306a36Sopenharmony_ci			WRITE_ONCE(adapter->tx_ring[ring->queue_index], NULL);
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	ixgbe_for_each_ring(ring, q_vector->rx)
103362306a36Sopenharmony_ci		WRITE_ONCE(adapter->rx_ring[ring->queue_index], NULL);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	adapter->q_vector[v_idx] = NULL;
103662306a36Sopenharmony_ci	__netif_napi_del(&q_vector->napi);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	/*
103962306a36Sopenharmony_ci	 * after a call to __netif_napi_del() napi may still be used and
104062306a36Sopenharmony_ci	 * ixgbe_get_stats64() might access the rings on this vector,
104162306a36Sopenharmony_ci	 * we must wait a grace period before freeing it.
104262306a36Sopenharmony_ci	 */
104362306a36Sopenharmony_ci	kfree_rcu(q_vector, rcu);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci/**
104762306a36Sopenharmony_ci * ixgbe_alloc_q_vectors - Allocate memory for interrupt vectors
104862306a36Sopenharmony_ci * @adapter: board private structure to initialize
104962306a36Sopenharmony_ci *
105062306a36Sopenharmony_ci * We allocate one q_vector per queue interrupt.  If allocation fails we
105162306a36Sopenharmony_ci * return -ENOMEM.
105262306a36Sopenharmony_ci **/
105362306a36Sopenharmony_cistatic int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	int q_vectors = adapter->num_q_vectors;
105662306a36Sopenharmony_ci	int rxr_remaining = adapter->num_rx_queues;
105762306a36Sopenharmony_ci	int txr_remaining = adapter->num_tx_queues;
105862306a36Sopenharmony_ci	int xdp_remaining = adapter->num_xdp_queues;
105962306a36Sopenharmony_ci	int rxr_idx = 0, txr_idx = 0, xdp_idx = 0, v_idx = 0;
106062306a36Sopenharmony_ci	int err, i;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* only one q_vector if MSI-X is disabled. */
106362306a36Sopenharmony_ci	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
106462306a36Sopenharmony_ci		q_vectors = 1;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (q_vectors >= (rxr_remaining + txr_remaining + xdp_remaining)) {
106762306a36Sopenharmony_ci		for (; rxr_remaining; v_idx++) {
106862306a36Sopenharmony_ci			err = ixgbe_alloc_q_vector(adapter, q_vectors, v_idx,
106962306a36Sopenharmony_ci						   0, 0, 0, 0, 1, rxr_idx);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci			if (err)
107262306a36Sopenharmony_ci				goto err_out;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci			/* update counts and index */
107562306a36Sopenharmony_ci			rxr_remaining--;
107662306a36Sopenharmony_ci			rxr_idx++;
107762306a36Sopenharmony_ci		}
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	for (; v_idx < q_vectors; v_idx++) {
108162306a36Sopenharmony_ci		int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
108262306a36Sopenharmony_ci		int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
108362306a36Sopenharmony_ci		int xqpv = DIV_ROUND_UP(xdp_remaining, q_vectors - v_idx);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		err = ixgbe_alloc_q_vector(adapter, q_vectors, v_idx,
108662306a36Sopenharmony_ci					   tqpv, txr_idx,
108762306a36Sopenharmony_ci					   xqpv, xdp_idx,
108862306a36Sopenharmony_ci					   rqpv, rxr_idx);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		if (err)
109162306a36Sopenharmony_ci			goto err_out;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		/* update counts and index */
109462306a36Sopenharmony_ci		rxr_remaining -= rqpv;
109562306a36Sopenharmony_ci		txr_remaining -= tqpv;
109662306a36Sopenharmony_ci		xdp_remaining -= xqpv;
109762306a36Sopenharmony_ci		rxr_idx++;
109862306a36Sopenharmony_ci		txr_idx++;
109962306a36Sopenharmony_ci		xdp_idx += xqpv;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_rx_queues; i++) {
110362306a36Sopenharmony_ci		if (adapter->rx_ring[i])
110462306a36Sopenharmony_ci			adapter->rx_ring[i]->ring_idx = i;
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	for (i = 0; i < adapter->num_tx_queues; i++) {
110862306a36Sopenharmony_ci		if (adapter->tx_ring[i])
110962306a36Sopenharmony_ci			adapter->tx_ring[i]->ring_idx = i;
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_xdp_queues; i++) {
111362306a36Sopenharmony_ci		if (adapter->xdp_ring[i])
111462306a36Sopenharmony_ci			adapter->xdp_ring[i]->ring_idx = i;
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	return 0;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cierr_out:
112062306a36Sopenharmony_ci	adapter->num_tx_queues = 0;
112162306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
112262306a36Sopenharmony_ci	adapter->num_rx_queues = 0;
112362306a36Sopenharmony_ci	adapter->num_q_vectors = 0;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	while (v_idx--)
112662306a36Sopenharmony_ci		ixgbe_free_q_vector(adapter, v_idx);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	return -ENOMEM;
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci/**
113262306a36Sopenharmony_ci * ixgbe_free_q_vectors - Free memory allocated for interrupt vectors
113362306a36Sopenharmony_ci * @adapter: board private structure to initialize
113462306a36Sopenharmony_ci *
113562306a36Sopenharmony_ci * This function frees the memory allocated to the q_vectors.  In addition if
113662306a36Sopenharmony_ci * NAPI is enabled it will delete any references to the NAPI struct prior
113762306a36Sopenharmony_ci * to freeing the q_vector.
113862306a36Sopenharmony_ci **/
113962306a36Sopenharmony_cistatic void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	int v_idx = adapter->num_q_vectors;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	adapter->num_tx_queues = 0;
114462306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
114562306a36Sopenharmony_ci	adapter->num_rx_queues = 0;
114662306a36Sopenharmony_ci	adapter->num_q_vectors = 0;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	while (v_idx--)
114962306a36Sopenharmony_ci		ixgbe_free_q_vector(adapter, v_idx);
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
115562306a36Sopenharmony_ci		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
115662306a36Sopenharmony_ci		pci_disable_msix(adapter->pdev);
115762306a36Sopenharmony_ci		kfree(adapter->msix_entries);
115862306a36Sopenharmony_ci		adapter->msix_entries = NULL;
115962306a36Sopenharmony_ci	} else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
116062306a36Sopenharmony_ci		adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
116162306a36Sopenharmony_ci		pci_disable_msi(adapter->pdev);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci/**
116662306a36Sopenharmony_ci * ixgbe_set_interrupt_capability - set MSI-X or MSI if supported
116762306a36Sopenharmony_ci * @adapter: board private structure to initialize
116862306a36Sopenharmony_ci *
116962306a36Sopenharmony_ci * Attempt to configure the interrupts using the best available
117062306a36Sopenharmony_ci * capabilities of the hardware and the kernel.
117162306a36Sopenharmony_ci **/
117262306a36Sopenharmony_cistatic void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	int err;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	/* We will try to get MSI-X interrupts first */
117762306a36Sopenharmony_ci	if (!ixgbe_acquire_msix_vectors(adapter))
117862306a36Sopenharmony_ci		return;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* At this point, we do not have MSI-X capabilities. We need to
118162306a36Sopenharmony_ci	 * reconfigure or disable various features which require MSI-X
118262306a36Sopenharmony_ci	 * capability.
118362306a36Sopenharmony_ci	 */
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/* Disable DCB unless we only have a single traffic class */
118662306a36Sopenharmony_ci	if (adapter->hw_tcs > 1) {
118762306a36Sopenharmony_ci		e_dev_warn("Number of DCB TCs exceeds number of available queues. Disabling DCB support.\n");
118862306a36Sopenharmony_ci		netdev_reset_tc(adapter->netdev);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		if (adapter->hw.mac.type == ixgbe_mac_82598EB)
119162306a36Sopenharmony_ci			adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
119462306a36Sopenharmony_ci		adapter->temp_dcb_cfg.pfc_mode_enable = false;
119562306a36Sopenharmony_ci		adapter->dcb_cfg.pfc_mode_enable = false;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	adapter->hw_tcs = 0;
119962306a36Sopenharmony_ci	adapter->dcb_cfg.num_tcs.pg_tcs = 1;
120062306a36Sopenharmony_ci	adapter->dcb_cfg.num_tcs.pfc_tcs = 1;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* Disable SR-IOV support */
120362306a36Sopenharmony_ci	e_dev_warn("Disabling SR-IOV support\n");
120462306a36Sopenharmony_ci	ixgbe_disable_sriov(adapter);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/* Disable RSS */
120762306a36Sopenharmony_ci	e_dev_warn("Disabling RSS support\n");
120862306a36Sopenharmony_ci	adapter->ring_feature[RING_F_RSS].limit = 1;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	/* recalculate number of queues now that many features have been
121162306a36Sopenharmony_ci	 * changed or disabled.
121262306a36Sopenharmony_ci	 */
121362306a36Sopenharmony_ci	ixgbe_set_num_queues(adapter);
121462306a36Sopenharmony_ci	adapter->num_q_vectors = 1;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	err = pci_enable_msi(adapter->pdev);
121762306a36Sopenharmony_ci	if (err)
121862306a36Sopenharmony_ci		e_dev_warn("Failed to allocate MSI interrupt, falling back to legacy. Error: %d\n",
121962306a36Sopenharmony_ci			   err);
122062306a36Sopenharmony_ci	else
122162306a36Sopenharmony_ci		adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci/**
122562306a36Sopenharmony_ci * ixgbe_init_interrupt_scheme - Determine proper interrupt scheme
122662306a36Sopenharmony_ci * @adapter: board private structure to initialize
122762306a36Sopenharmony_ci *
122862306a36Sopenharmony_ci * We determine which interrupt scheme to use based on...
122962306a36Sopenharmony_ci * - Kernel support (MSI, MSI-X)
123062306a36Sopenharmony_ci *   - which can be user-defined (via MODULE_PARAM)
123162306a36Sopenharmony_ci * - Hardware queue count (num_*_queues)
123262306a36Sopenharmony_ci *   - defined by miscellaneous hardware support/features (RSS, etc.)
123362306a36Sopenharmony_ci **/
123462306a36Sopenharmony_ciint ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	int err;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	/* Number of supported queues */
123962306a36Sopenharmony_ci	ixgbe_set_num_queues(adapter);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* Set interrupt mode */
124262306a36Sopenharmony_ci	ixgbe_set_interrupt_capability(adapter);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	err = ixgbe_alloc_q_vectors(adapter);
124562306a36Sopenharmony_ci	if (err) {
124662306a36Sopenharmony_ci		e_dev_err("Unable to allocate memory for queue vectors\n");
124762306a36Sopenharmony_ci		goto err_alloc_q_vectors;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	ixgbe_cache_ring_register(adapter);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	e_dev_info("Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u XDP Queue count = %u\n",
125362306a36Sopenharmony_ci		   (adapter->num_rx_queues > 1) ? "Enabled" : "Disabled",
125462306a36Sopenharmony_ci		   adapter->num_rx_queues, adapter->num_tx_queues,
125562306a36Sopenharmony_ci		   adapter->num_xdp_queues);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	set_bit(__IXGBE_DOWN, &adapter->state);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cierr_alloc_q_vectors:
126262306a36Sopenharmony_ci	ixgbe_reset_interrupt_capability(adapter);
126362306a36Sopenharmony_ci	return err;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci/**
126762306a36Sopenharmony_ci * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
126862306a36Sopenharmony_ci * @adapter: board private structure to clear interrupt scheme on
126962306a36Sopenharmony_ci *
127062306a36Sopenharmony_ci * We go through and clear interrupt specific resources and reset the structure
127162306a36Sopenharmony_ci * to pre-load conditions
127262306a36Sopenharmony_ci **/
127362306a36Sopenharmony_civoid ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	adapter->num_tx_queues = 0;
127662306a36Sopenharmony_ci	adapter->num_xdp_queues = 0;
127762306a36Sopenharmony_ci	adapter->num_rx_queues = 0;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	ixgbe_free_q_vectors(adapter);
128062306a36Sopenharmony_ci	ixgbe_reset_interrupt_capability(adapter);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_civoid ixgbe_tx_ctxtdesc(struct ixgbe_ring *tx_ring, u32 vlan_macip_lens,
128462306a36Sopenharmony_ci		       u32 fceof_saidx, u32 type_tucmd, u32 mss_l4len_idx)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct ixgbe_adv_tx_context_desc *context_desc;
128762306a36Sopenharmony_ci	u16 i = tx_ring->next_to_use;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	context_desc = IXGBE_TX_CTXTDESC(tx_ring, i);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	i++;
129262306a36Sopenharmony_ci	tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	/* set bits to identify this as an advanced context descriptor */
129562306a36Sopenharmony_ci	type_tucmd |= IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	context_desc->vlan_macip_lens	= cpu_to_le32(vlan_macip_lens);
129862306a36Sopenharmony_ci	context_desc->fceof_saidx	= cpu_to_le32(fceof_saidx);
129962306a36Sopenharmony_ci	context_desc->type_tucmd_mlhl	= cpu_to_le32(type_tucmd);
130062306a36Sopenharmony_ci	context_desc->mss_l4len_idx	= cpu_to_le32(mss_l4len_idx);
130162306a36Sopenharmony_ci}
130262306a36Sopenharmony_ci
1303