mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Add common wx_configure_vf and wx_set_mac_vf for ngbevf and txgbevf. Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com> Link: https://patch.msgid.link/20250704094923.652-4-mengyuanlou@net-swift.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
280 lines
7.1 KiB
C
280 lines
7.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
|
|
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/pci.h>
|
|
|
|
#include "wx_type.h"
|
|
#include "wx_hw.h"
|
|
#include "wx_lib.h"
|
|
#include "wx_vf.h"
|
|
#include "wx_vf_lib.h"
|
|
|
|
static void wx_write_eitr_vf(struct wx_q_vector *q_vector)
|
|
{
|
|
struct wx *wx = q_vector->wx;
|
|
int v_idx = q_vector->v_idx;
|
|
u32 itr_reg;
|
|
|
|
itr_reg = q_vector->itr & WX_VXITR_MASK;
|
|
|
|
/* set the WDIS bit to not clear the timer bits and cause an
|
|
* immediate assertion of the interrupt
|
|
*/
|
|
itr_reg |= WX_VXITR_CNT_WDIS;
|
|
|
|
wr32(wx, WX_VXITR(v_idx), itr_reg);
|
|
}
|
|
|
|
static void wx_set_ivar_vf(struct wx *wx, s8 direction, u8 queue,
|
|
u8 msix_vector)
|
|
{
|
|
u32 ivar, index;
|
|
|
|
if (direction == -1) {
|
|
/* other causes */
|
|
msix_vector |= WX_PX_IVAR_ALLOC_VAL;
|
|
ivar = rd32(wx, WX_VXIVAR_MISC);
|
|
ivar &= ~0xFF;
|
|
ivar |= msix_vector;
|
|
wr32(wx, WX_VXIVAR_MISC, ivar);
|
|
} else {
|
|
/* tx or rx causes */
|
|
msix_vector |= WX_PX_IVAR_ALLOC_VAL;
|
|
index = ((16 * (queue & 1)) + (8 * direction));
|
|
ivar = rd32(wx, WX_VXIVAR(queue >> 1));
|
|
ivar &= ~(0xFF << index);
|
|
ivar |= (msix_vector << index);
|
|
wr32(wx, WX_VXIVAR(queue >> 1), ivar);
|
|
}
|
|
}
|
|
|
|
void wx_configure_msix_vf(struct wx *wx)
|
|
{
|
|
int v_idx;
|
|
|
|
wx->eims_enable_mask = 0;
|
|
for (v_idx = 0; v_idx < wx->num_q_vectors; v_idx++) {
|
|
struct wx_q_vector *q_vector = wx->q_vector[v_idx];
|
|
struct wx_ring *ring;
|
|
|
|
wx_for_each_ring(ring, q_vector->rx)
|
|
wx_set_ivar_vf(wx, 0, ring->reg_idx, v_idx);
|
|
|
|
wx_for_each_ring(ring, q_vector->tx)
|
|
wx_set_ivar_vf(wx, 1, ring->reg_idx, v_idx);
|
|
|
|
/* add q_vector eims value to global eims_enable_mask */
|
|
wx->eims_enable_mask |= BIT(v_idx);
|
|
wx_write_eitr_vf(q_vector);
|
|
}
|
|
|
|
wx_set_ivar_vf(wx, -1, 1, v_idx);
|
|
|
|
/* setup eims_other and add value to global eims_enable_mask */
|
|
wx->eims_other = BIT(v_idx);
|
|
wx->eims_enable_mask |= wx->eims_other;
|
|
}
|
|
|
|
int wx_write_uc_addr_list_vf(struct net_device *netdev)
|
|
{
|
|
struct wx *wx = netdev_priv(netdev);
|
|
int count = 0;
|
|
|
|
if (!netdev_uc_empty(netdev)) {
|
|
struct netdev_hw_addr *ha;
|
|
|
|
netdev_for_each_uc_addr(ha, netdev)
|
|
wx_set_uc_addr_vf(wx, ++count, ha->addr);
|
|
} else {
|
|
/*
|
|
* If the list is empty then send message to PF driver to
|
|
* clear all macvlans on this VF.
|
|
*/
|
|
wx_set_uc_addr_vf(wx, 0, NULL);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* wx_configure_tx_ring_vf - Configure Tx ring after Reset
|
|
* @wx: board private structure
|
|
* @ring: structure containing ring specific data
|
|
*
|
|
* Configure the Tx descriptor ring after a reset.
|
|
**/
|
|
static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
|
|
{
|
|
u8 reg_idx = ring->reg_idx;
|
|
u64 tdba = ring->dma;
|
|
u32 txdctl = 0;
|
|
int ret;
|
|
|
|
/* disable queue to avoid issues while updating state */
|
|
wr32(wx, WX_VXTXDCTL(reg_idx), WX_VXTXDCTL_FLUSH);
|
|
wr32(wx, WX_VXTDBAL(reg_idx), tdba & DMA_BIT_MASK(32));
|
|
wr32(wx, WX_VXTDBAH(reg_idx), tdba >> 32);
|
|
|
|
/* enable relaxed ordering */
|
|
pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
|
|
0, PCI_EXP_DEVCTL_RELAX_EN);
|
|
|
|
/* reset head and tail pointers */
|
|
wr32(wx, WX_VXTDH(reg_idx), 0);
|
|
wr32(wx, WX_VXTDT(reg_idx), 0);
|
|
ring->tail = wx->hw_addr + WX_VXTDT(reg_idx);
|
|
|
|
/* reset ntu and ntc to place SW in sync with hardwdare */
|
|
ring->next_to_clean = 0;
|
|
ring->next_to_use = 0;
|
|
|
|
txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
|
|
txdctl |= WX_VXTXDCTL_ENABLE;
|
|
|
|
/* reinitialize tx_buffer_info */
|
|
memset(ring->tx_buffer_info, 0,
|
|
sizeof(struct wx_tx_buffer) * ring->count);
|
|
|
|
wr32(wx, WX_VXTXDCTL(reg_idx), txdctl);
|
|
/* poll to verify queue is enabled */
|
|
ret = read_poll_timeout(rd32, txdctl, txdctl & WX_VXTXDCTL_ENABLE,
|
|
1000, 10000, true, wx, WX_VXTXDCTL(reg_idx));
|
|
if (ret == -ETIMEDOUT)
|
|
wx_err(wx, "Could not enable Tx Queue %d\n", reg_idx);
|
|
}
|
|
|
|
/**
|
|
* wx_configure_tx_vf - Configure Transmit Unit after Reset
|
|
* @wx: board private structure
|
|
*
|
|
* Configure the Tx unit of the MAC after a reset.
|
|
**/
|
|
void wx_configure_tx_vf(struct wx *wx)
|
|
{
|
|
u32 i;
|
|
|
|
/* Setup the HW Tx Head and Tail descriptor pointers */
|
|
for (i = 0; i < wx->num_tx_queues; i++)
|
|
wx_configure_tx_ring_vf(wx, wx->tx_ring[i]);
|
|
}
|
|
|
|
static void wx_configure_srrctl_vf(struct wx *wx, struct wx_ring *ring,
|
|
int index)
|
|
{
|
|
u32 srrctl;
|
|
|
|
srrctl = rd32m(wx, WX_VXRXDCTL(index),
|
|
(u32)~(WX_VXRXDCTL_HDRSZ_MASK | WX_VXRXDCTL_BUFSZ_MASK));
|
|
srrctl |= WX_VXRXDCTL_DROP;
|
|
srrctl |= WX_VXRXDCTL_HDRSZ(wx_hdr_sz(WX_RX_HDR_SIZE));
|
|
srrctl |= WX_VXRXDCTL_BUFSZ(wx_buf_sz(WX_RX_BUF_SIZE));
|
|
|
|
wr32(wx, WX_VXRXDCTL(index), srrctl);
|
|
}
|
|
|
|
void wx_setup_psrtype_vf(struct wx *wx)
|
|
{
|
|
/* PSRTYPE must be initialized */
|
|
u32 psrtype = WX_VXMRQC_PSR_L2HDR |
|
|
WX_VXMRQC_PSR_L3HDR |
|
|
WX_VXMRQC_PSR_L4HDR |
|
|
WX_VXMRQC_PSR_TUNHDR |
|
|
WX_VXMRQC_PSR_TUNMAC;
|
|
|
|
wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
|
|
}
|
|
|
|
void wx_setup_vfmrqc_vf(struct wx *wx)
|
|
{
|
|
u16 rss_i = wx->num_rx_queues;
|
|
u32 vfmrqc = 0, vfreta = 0;
|
|
u8 i, j;
|
|
|
|
/* Fill out hash function seeds */
|
|
netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key));
|
|
for (i = 0; i < WX_RSS_KEY_SIZE / 4; i++)
|
|
wr32(wx, WX_VXRSSRK(i), wx->rss_key[i]);
|
|
|
|
for (i = 0, j = 0; i < WX_MAX_RETA_ENTRIES; i++, j++) {
|
|
if (j == rss_i)
|
|
j = 0;
|
|
|
|
wx->rss_indir_tbl[i] = j;
|
|
|
|
vfreta |= j << (i & 0x3) * 8;
|
|
if ((i & 3) == 3) {
|
|
wr32(wx, WX_VXRETA(i >> 2), vfreta);
|
|
vfreta = 0;
|
|
}
|
|
}
|
|
|
|
/* Perform hash on these packet types */
|
|
vfmrqc |= WX_VXMRQC_RSS_ALG_IPV4 |
|
|
WX_VXMRQC_RSS_ALG_IPV4_TCP |
|
|
WX_VXMRQC_RSS_ALG_IPV6 |
|
|
WX_VXMRQC_RSS_ALG_IPV6_TCP;
|
|
|
|
vfmrqc |= WX_VXMRQC_RSS_EN;
|
|
|
|
if (wx->num_rx_queues > 3)
|
|
vfmrqc |= WX_VXMRQC_RSS_HASH(2);
|
|
else if (wx->num_rx_queues > 1)
|
|
vfmrqc |= WX_VXMRQC_RSS_HASH(1);
|
|
wr32m(wx, WX_VXMRQC, WX_VXMRQC_RSS_MASK, WX_VXMRQC_RSS(vfmrqc));
|
|
}
|
|
|
|
void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring)
|
|
{
|
|
u8 reg_idx = ring->reg_idx;
|
|
union wx_rx_desc *rx_desc;
|
|
u64 rdba = ring->dma;
|
|
u32 rxdctl;
|
|
|
|
/* disable queue to avoid issues while updating state */
|
|
rxdctl = rd32(wx, WX_VXRXDCTL(reg_idx));
|
|
wx_disable_rx_queue(wx, ring);
|
|
|
|
wr32(wx, WX_VXRDBAL(reg_idx), rdba & DMA_BIT_MASK(32));
|
|
wr32(wx, WX_VXRDBAH(reg_idx), rdba >> 32);
|
|
|
|
/* enable relaxed ordering */
|
|
pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
|
|
0, PCI_EXP_DEVCTL_RELAX_EN);
|
|
|
|
/* reset head and tail pointers */
|
|
wr32(wx, WX_VXRDH(reg_idx), 0);
|
|
wr32(wx, WX_VXRDT(reg_idx), 0);
|
|
ring->tail = wx->hw_addr + WX_VXRDT(reg_idx);
|
|
|
|
/* initialize rx_buffer_info */
|
|
memset(ring->rx_buffer_info, 0,
|
|
sizeof(struct wx_rx_buffer) * ring->count);
|
|
|
|
/* initialize Rx descriptor 0 */
|
|
rx_desc = WX_RX_DESC(ring, 0);
|
|
rx_desc->wb.upper.length = 0;
|
|
|
|
/* reset ntu and ntc to place SW in sync with hardwdare */
|
|
ring->next_to_clean = 0;
|
|
ring->next_to_use = 0;
|
|
ring->next_to_alloc = 0;
|
|
|
|
wx_configure_srrctl_vf(wx, ring, reg_idx);
|
|
|
|
/* allow any size packet since we can handle overflow */
|
|
rxdctl &= ~WX_VXRXDCTL_BUFLEN_MASK;
|
|
rxdctl |= WX_VXRXDCTL_BUFLEN(wx_buf_len(ring->count));
|
|
rxdctl |= WX_VXRXDCTL_ENABLE | WX_VXRXDCTL_VLAN;
|
|
|
|
/* enable RSC */
|
|
rxdctl &= ~WX_VXRXDCTL_RSCMAX_MASK;
|
|
rxdctl |= WX_VXRXDCTL_RSCMAX(0);
|
|
rxdctl |= WX_VXRXDCTL_RSCEN;
|
|
|
|
wr32(wx, WX_VXRXDCTL(reg_idx), rxdctl);
|
|
|
|
/* pf/vf reuse */
|
|
wx_enable_rx_queue(wx, ring);
|
|
wx_alloc_rx_buffers(ring, wx_desc_unused(ring));
|
|
}
|