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