mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Revert "octeon_ep_vf: add octeon_ep_vf driver"
This reverts commitc902ba322c
. This reverts commit50648968b3
. This reverts commit77cef1e021
. This reverts commit8f8d322bc4
. This reverts commit6ca7b5486e
. This reverts commitdb468f92c3
. This reverts commit5f8c64c234
. This reverts commitebdc193b2c
. The driver needs more work. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
5e5401d661
commit
63c7234f50
@ -42,7 +42,6 @@ Contents:
|
||||
intel/ice
|
||||
marvell/octeontx2
|
||||
marvell/octeon_ep
|
||||
marvell/octeon_ep_vf
|
||||
mellanox/mlx5/index
|
||||
microsoft/netvsc
|
||||
neterion/s2io
|
||||
|
@ -1,24 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
=======================================================================
|
||||
Linux kernel networking driver for Marvell's Octeon PCI Endpoint NIC VF
|
||||
=======================================================================
|
||||
|
||||
Network driver for Marvell's Octeon PCI EndPoint NIC VF.
|
||||
Copyright (c) 2020 Marvell International Ltd.
|
||||
|
||||
Overview
|
||||
========
|
||||
This driver implements networking functionality of Marvell's Octeon PCI
|
||||
EndPoint NIC VF.
|
||||
|
||||
Supported Devices
|
||||
=================
|
||||
Currently, this driver support following devices:
|
||||
* Network controller: Cavium, Inc. Device b203
|
||||
* Network controller: Cavium, Inc. Device b403
|
||||
* Network controller: Cavium, Inc. Device b103
|
||||
* Network controller: Cavium, Inc. Device b903
|
||||
* Network controller: Cavium, Inc. Device ba03
|
||||
* Network controller: Cavium, Inc. Device bc03
|
||||
* Network controller: Cavium, Inc. Device bd03
|
@ -12861,15 +12861,6 @@ L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/marvell/octeon_ep
|
||||
|
||||
MARVELL OCTEON ENDPOINT VF DRIVER
|
||||
M: Veerasenareddy Burru <vburru@marvell.com>
|
||||
M: Sathesh Edara <sedara@marvell.com>
|
||||
M: Shinas Rasheed <srasheed@marvell.com>
|
||||
M: Satananda Burla <sburla@marvell.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/marvell/octeon_ep_vf
|
||||
|
||||
MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
|
||||
M: Sunil Goutham <sgoutham@marvell.com>
|
||||
M: Geetha sowjanya <gakula@marvell.com>
|
||||
|
@ -180,7 +180,6 @@ config SKY2_DEBUG
|
||||
|
||||
source "drivers/net/ethernet/marvell/octeontx2/Kconfig"
|
||||
source "drivers/net/ethernet/marvell/octeon_ep/Kconfig"
|
||||
source "drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig"
|
||||
source "drivers/net/ethernet/marvell/prestera/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_MARVELL
|
||||
|
@ -12,6 +12,5 @@ obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
|
||||
obj-$(CONFIG_SKGE) += skge.o
|
||||
obj-$(CONFIG_SKY2) += sky2.o
|
||||
obj-y += octeon_ep/
|
||||
obj-y += octeon_ep_vf/
|
||||
obj-y += octeontx2/
|
||||
obj-y += prestera/
|
||||
|
@ -1,19 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Marvell's Octeon PCI Endpoint NIC VF Driver Configuration
|
||||
#
|
||||
|
||||
config OCTEON_EP_VF
|
||||
tristate "Marvell Octeon PCI Endpoint NIC VF Driver"
|
||||
depends on 64BIT
|
||||
depends on PCI
|
||||
help
|
||||
This driver supports networking functionality of Marvell's
|
||||
Octeon PCI Endpoint NIC VF.
|
||||
|
||||
To know the list of devices supported by this driver, refer
|
||||
documentation in
|
||||
<file:Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst>.
|
||||
|
||||
To compile this drivers as a module, choose M here. Name of the
|
||||
module is octeon_ep_vf.
|
@ -1,10 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Network driver for Marvell's Octeon PCI Endpoint NIC VF
|
||||
#
|
||||
|
||||
obj-$(CONFIG_OCTEON_EP_VF) += octeon_ep_vf.o
|
||||
|
||||
octeon_ep_vf-y := octep_vf_main.o octep_vf_cn9k.o octep_vf_cnxk.o \
|
||||
octep_vf_tx.o octep_vf_rx.o octep_vf_mbox.o \
|
||||
octep_vf_ethtool.o
|
@ -1,488 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
#include "octep_vf_regs_cn9k.h"
|
||||
|
||||
/* Dump useful hardware IQ/OQ CSRs for debug purpose */
|
||||
static void cn93_vf_dump_q_regs(struct octep_vf_device *oct, int qno)
|
||||
{
|
||||
struct device *dev = &oct->pdev->dev;
|
||||
|
||||
dev_info(dev, "IQ-%d register dump\n", qno);
|
||||
dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_INSTR_DBELL(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(qno)));
|
||||
dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_CONTROL(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(qno)));
|
||||
dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_ENABLE(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_INSTR_BADDR(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno)));
|
||||
dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_CNTS(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_INT_LEVELS(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(qno)));
|
||||
dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_PKT_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(qno)));
|
||||
dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_IN_BYTE_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(qno)));
|
||||
|
||||
dev_info(dev, "OQ-%d register dump\n", qno);
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_CONTROL(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_ENABLE(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_CNTS(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CNTS(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_INT_LEVELS(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_PKT_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CN93_VF_SDP_R_OUT_BYTE_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_BYTE_CNT(qno)));
|
||||
}
|
||||
|
||||
/* Reset Hardware Tx queue */
|
||||
static int cn93_vf_reset_iq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
u64 val = 0ULL;
|
||||
|
||||
dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no);
|
||||
|
||||
/* Disable the Tx/Instruction Ring */
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(q_no), val);
|
||||
|
||||
/* clear the Instruction Ring packet/byte counts and doorbell CSRs */
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q_no), val);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(q_no), val);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(q_no), val);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(q_no), val);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(q_no), val);
|
||||
|
||||
val = 0xFFFFFFFF;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(q_no), val);
|
||||
|
||||
val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no));
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no), val & 0xFFFFFFFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset Hardware Rx queue */
|
||||
static void cn93_vf_reset_oq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
u64 val = 0ULL;
|
||||
|
||||
/* Disable Output (Rx) Ring */
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(q_no), val);
|
||||
|
||||
/* Clear count CSRs */
|
||||
val = octep_vf_read_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no));
|
||||
octep_vf_write_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no), val);
|
||||
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* Reset all hardware Tx/Rx queues */
|
||||
static void octep_vf_reset_io_queues_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
struct pci_dev *pdev = oct->pdev;
|
||||
int q;
|
||||
|
||||
dev_dbg(&pdev->dev, "Reset OCTEP_CN93 VF IO Queues\n");
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
cn93_vf_reset_iq(oct, q);
|
||||
cn93_vf_reset_oq(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize configuration limits and initial active config */
|
||||
static void octep_vf_init_config_cn93_vf(struct octep_vf_device *oct)
|
||||
{
|
||||
struct octep_vf_config *conf = oct->conf;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(0));
|
||||
conf->ring_cfg.max_io_rings = (reg_val >> CN93_VF_R_IN_CTL_RPVF_POS) &
|
||||
CN93_VF_R_IN_CTL_RPVF_MASK;
|
||||
conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings;
|
||||
|
||||
conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS;
|
||||
conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR;
|
||||
conf->iq.db_min = OCTEP_VF_DB_MIN;
|
||||
conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD;
|
||||
|
||||
conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS;
|
||||
conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE;
|
||||
conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD;
|
||||
conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD;
|
||||
conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD;
|
||||
|
||||
conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings;
|
||||
}
|
||||
|
||||
/* Setup registers for a hardware Tx Queue */
|
||||
static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
struct octep_vf_iq *iq = oct->iq[iq_no];
|
||||
u32 reset_instr_cnt;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no));
|
||||
|
||||
/* wait for IDLE to set to 1 */
|
||||
if (!(reg_val & CN93_VF_R_IN_CTL_IDLE)) {
|
||||
do {
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no));
|
||||
} while (!(reg_val & CN93_VF_R_IN_CTL_IDLE));
|
||||
}
|
||||
reg_val |= CN93_VF_R_IN_CTL_RDSIZE;
|
||||
reg_val |= CN93_VF_R_IN_CTL_IS_64B;
|
||||
reg_val |= CN93_VF_R_IN_CTL_ESR;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no), reg_val);
|
||||
|
||||
/* Write the start of the input queue's ring and its size */
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count);
|
||||
|
||||
/* Remember the doorbell & instruction count register addr for this queue */
|
||||
iq->doorbell_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no);
|
||||
iq->inst_cnt_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_CNTS(iq_no);
|
||||
iq->intr_lvl_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INT_LEVELS(iq_no);
|
||||
|
||||
/* Store the current instruction counter (used in flush_iq calculation) */
|
||||
reset_instr_cnt = readl(iq->inst_cnt_reg);
|
||||
writel(reset_instr_cnt, iq->inst_cnt_reg);
|
||||
|
||||
/* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */
|
||||
reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Setup registers for a hardware Rx Queue */
|
||||
static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
struct octep_vf_oq *oq = oct->oq[oq_no];
|
||||
u32 time_threshold = 0;
|
||||
u64 oq_ctl = 0ULL;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
|
||||
/* wait for IDLE to set to 1 */
|
||||
if (!(reg_val & CN93_VF_R_OUT_CTL_IDLE)) {
|
||||
do {
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
} while (!(reg_val & CN93_VF_R_OUT_CTL_IDLE));
|
||||
}
|
||||
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_IMODE);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_P);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_P);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_I);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_I);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_ES_I);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_D);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_D);
|
||||
reg_val &= ~(CN93_VF_R_OUT_CTL_ES_D);
|
||||
reg_val |= (CN93_VF_R_OUT_CTL_ES_P);
|
||||
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), reg_val);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count);
|
||||
|
||||
oq_ctl = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
oq_ctl &= ~0x7fffffULL; //clear the ISIZE and BSIZE (22-0)
|
||||
oq_ctl |= (oq->buffer_size & 0xffff); //populate the BSIZE (15-0)
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl);
|
||||
|
||||
/* Get the mapped address of the pkt_sent and pkts_credit regs */
|
||||
oq->pkts_sent_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_CNTS(oq_no);
|
||||
oq->pkts_credit_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no);
|
||||
|
||||
time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf);
|
||||
reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Setup registers for a VF mailbox */
|
||||
static void octep_vf_setup_mbox_regs_cn93(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
struct octep_vf_mbox *mbox = oct->mbox;
|
||||
|
||||
/* PF to VF DATA reg. VF reads from this reg */
|
||||
mbox->mbox_read_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_DATA(q_no);
|
||||
|
||||
/* VF mbox interrupt reg */
|
||||
mbox->mbox_int_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_INT(q_no);
|
||||
|
||||
/* VF to PF DATA reg. VF writes into this reg */
|
||||
mbox->mbox_write_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_VF_PF_DATA(q_no);
|
||||
}
|
||||
|
||||
/* Mailbox Interrupt handler */
|
||||
static void cn93_handle_vf_mbox_intr(struct octep_vf_device *oct)
|
||||
{
|
||||
if (oct->mbox)
|
||||
schedule_work(&oct->mbox->wk.work);
|
||||
else
|
||||
dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n");
|
||||
}
|
||||
|
||||
/* Tx/Rx queue interrupt handler */
|
||||
static irqreturn_t octep_vf_ioq_intr_handler_cn93(void *data)
|
||||
{
|
||||
struct octep_vf_ioq_vector *vector = (struct octep_vf_ioq_vector *)data;
|
||||
struct octep_vf_oq *oq = vector->oq;
|
||||
struct octep_vf_device *oct = vector->octep_vf_dev;
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
/* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */
|
||||
if (oq->q_no == 0) {
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0));
|
||||
if (reg_val & CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS) {
|
||||
cn93_handle_vf_mbox_intr(oct);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val);
|
||||
}
|
||||
}
|
||||
napi_schedule_irqoff(oq->napi);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Re-initialize Octeon hardware registers */
|
||||
static void octep_vf_reinit_regs_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
oct->hw_ops.setup_iq_regs(oct, i);
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
oct->hw_ops.setup_oq_regs(oct, i);
|
||||
|
||||
oct->hw_ops.enable_interrupts(oct);
|
||||
oct->hw_ops.enable_io_queues(oct);
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
|
||||
}
|
||||
|
||||
/* Enable all interrupts */
|
||||
static void octep_vf_enable_interrupts_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
int num_rings, q;
|
||||
u64 reg_val;
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++) {
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val);
|
||||
}
|
||||
/* Enable PF to VF mbox interrupt by setting 2nd bit*/
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0),
|
||||
CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB);
|
||||
}
|
||||
|
||||
/* Disable all interrupts */
|
||||
static void octep_vf_disable_interrupts_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
int num_rings, q;
|
||||
u64 reg_val;
|
||||
|
||||
/* Disable PF to VF mbox interrupt by setting 2nd bit*/
|
||||
if (oct->mbox)
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0);
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++) {
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q));
|
||||
reg_val &= ~(0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q));
|
||||
reg_val &= ~(0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */
|
||||
static u32 octep_vf_update_iq_read_index_cn93(struct octep_vf_iq *iq)
|
||||
{
|
||||
u32 pkt_in_done = readl(iq->inst_cnt_reg);
|
||||
u32 last_done, new_idx;
|
||||
|
||||
last_done = pkt_in_done - iq->pkt_in_done;
|
||||
iq->pkt_in_done = pkt_in_done;
|
||||
|
||||
new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count;
|
||||
|
||||
return new_idx;
|
||||
}
|
||||
|
||||
/* Enable a hardware Tx Queue */
|
||||
static void octep_vf_enable_iq_cn93(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
u64 loop = HZ;
|
||||
u64 reg_val;
|
||||
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF);
|
||||
|
||||
while (octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no)) &&
|
||||
loop--) {
|
||||
schedule_timeout_interruptible(1);
|
||||
}
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no));
|
||||
reg_val |= 0x1ULL;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Enable a hardware Rx Queue */
|
||||
static void octep_vf_enable_oq_cn93(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
||||
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no));
|
||||
reg_val |= 0x1ULL;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Enable all hardware Tx/Rx Queues assigned to VF */
|
||||
static void octep_vf_enable_io_queues_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
u8 q;
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
octep_vf_enable_iq_cn93(oct, q);
|
||||
octep_vf_enable_oq_cn93(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable a hardware Tx Queue assigned to VF */
|
||||
static void octep_vf_disable_iq_cn93(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no));
|
||||
reg_val &= ~0x1ULL;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Disable a hardware Rx Queue assigned to VF */
|
||||
static void octep_vf_disable_oq_cn93(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no));
|
||||
reg_val &= ~0x1ULL;
|
||||
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Disable all hardware Tx/Rx Queues assigned to VF */
|
||||
static void octep_vf_disable_io_queues_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
int q = 0;
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
octep_vf_disable_iq_cn93(oct, q);
|
||||
octep_vf_disable_oq_cn93(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump hardware registers (including Tx/Rx queues) for debugging. */
|
||||
static void octep_vf_dump_registers_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
u8 num_rings, q;
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++)
|
||||
cn93_vf_dump_q_regs(oct, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_device_setup_cn93() - Setup Octeon device.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*
|
||||
* - initialize hardware operations.
|
||||
* - get target side pcie port number for the device.
|
||||
* - set initial configuration and max limits.
|
||||
*/
|
||||
void octep_vf_device_setup_cn93(struct octep_vf_device *oct)
|
||||
{
|
||||
oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cn93;
|
||||
oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cn93;
|
||||
oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cn93;
|
||||
|
||||
oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cn93;
|
||||
oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cn93;
|
||||
|
||||
oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cn93;
|
||||
oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cn93;
|
||||
|
||||
oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cn93;
|
||||
|
||||
oct->hw_ops.enable_iq = octep_vf_enable_iq_cn93;
|
||||
oct->hw_ops.enable_oq = octep_vf_enable_oq_cn93;
|
||||
oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cn93;
|
||||
|
||||
oct->hw_ops.disable_iq = octep_vf_disable_iq_cn93;
|
||||
oct->hw_ops.disable_oq = octep_vf_disable_oq_cn93;
|
||||
oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cn93;
|
||||
oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cn93;
|
||||
|
||||
oct->hw_ops.dump_registers = octep_vf_dump_registers_cn93;
|
||||
octep_vf_init_config_cn93_vf(oct);
|
||||
}
|
@ -1,500 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
#include "octep_vf_regs_cnxk.h"
|
||||
|
||||
/* Dump useful hardware IQ/OQ CSRs for debug purpose */
|
||||
static void cnxk_vf_dump_q_regs(struct octep_vf_device *oct, int qno)
|
||||
{
|
||||
struct device *dev = &oct->pdev->dev;
|
||||
|
||||
dev_info(dev, "IQ-%d register dump\n", qno);
|
||||
dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno)));
|
||||
dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_CONTROL(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(qno)));
|
||||
dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_ENABLE(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno)));
|
||||
dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_CNTS(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(qno)));
|
||||
dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_INT_LEVELS(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(qno)));
|
||||
dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_PKT_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(qno)));
|
||||
dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_IN_BYTE_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(qno)));
|
||||
|
||||
dev_info(dev, "OQ-%d register dump\n", qno);
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_CONTROL(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_ENABLE(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_CNTS(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CNTS(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_PKT_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(qno)));
|
||||
dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno)));
|
||||
dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n",
|
||||
qno, CNXK_VF_SDP_R_ERR_TYPE(qno),
|
||||
octep_vf_read_csr64(oct, CNXK_VF_SDP_R_ERR_TYPE(qno)));
|
||||
}
|
||||
|
||||
/* Reset Hardware Tx queue */
|
||||
static int cnxk_vf_reset_iq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
u64 val = 0ULL;
|
||||
|
||||
dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no);
|
||||
|
||||
/* Disable the Tx/Instruction Ring */
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(q_no), val);
|
||||
|
||||
/* clear the Instruction Ring packet/byte counts and doorbell CSRs */
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q_no), val);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(q_no), val);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(q_no), val);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(q_no), val);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(q_no), val);
|
||||
|
||||
val = 0xFFFFFFFF;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(q_no), val);
|
||||
|
||||
val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no));
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no), val & 0xFFFFFFFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset Hardware Rx queue */
|
||||
static void cnxk_vf_reset_oq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
u64 val = 0ULL;
|
||||
|
||||
/* Disable Output (Rx) Ring */
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(q_no), val);
|
||||
|
||||
/* Clear count CSRs */
|
||||
val = octep_vf_read_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no));
|
||||
octep_vf_write_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no), val);
|
||||
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* Reset all hardware Tx/Rx queues */
|
||||
static void octep_vf_reset_io_queues_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
struct pci_dev *pdev = oct->pdev;
|
||||
int q;
|
||||
|
||||
dev_dbg(&pdev->dev, "Reset OCTEP_CNXK VF IO Queues\n");
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
cnxk_vf_reset_iq(oct, q);
|
||||
cnxk_vf_reset_oq(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize configuration limits and initial active config */
|
||||
static void octep_vf_init_config_cnxk_vf(struct octep_vf_device *oct)
|
||||
{
|
||||
struct octep_vf_config *conf = oct->conf;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(0));
|
||||
conf->ring_cfg.max_io_rings = (reg_val >> CNXK_VF_R_IN_CTL_RPVF_POS) &
|
||||
CNXK_VF_R_IN_CTL_RPVF_MASK;
|
||||
conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings;
|
||||
|
||||
conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS;
|
||||
conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR;
|
||||
conf->iq.db_min = OCTEP_VF_DB_MIN;
|
||||
conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD;
|
||||
|
||||
conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS;
|
||||
conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE;
|
||||
conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD;
|
||||
conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD;
|
||||
conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD;
|
||||
conf->oq.wmark = OCTEP_VF_OQ_WMARK_MIN;
|
||||
|
||||
conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings;
|
||||
}
|
||||
|
||||
/* Setup registers for a hardware Tx Queue */
|
||||
static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
struct octep_vf_iq *iq = oct->iq[iq_no];
|
||||
u32 reset_instr_cnt;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no));
|
||||
|
||||
/* wait for IDLE to set to 1 */
|
||||
if (!(reg_val & CNXK_VF_R_IN_CTL_IDLE)) {
|
||||
do {
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no));
|
||||
} while (!(reg_val & CNXK_VF_R_IN_CTL_IDLE));
|
||||
}
|
||||
reg_val |= CNXK_VF_R_IN_CTL_RDSIZE;
|
||||
reg_val |= CNXK_VF_R_IN_CTL_IS_64B;
|
||||
reg_val |= CNXK_VF_R_IN_CTL_ESR;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no), reg_val);
|
||||
|
||||
/* Write the start of the input queue's ring and its size */
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count);
|
||||
|
||||
/* Remember the doorbell & instruction count register addr for this queue */
|
||||
iq->doorbell_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no);
|
||||
iq->inst_cnt_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_CNTS(iq_no);
|
||||
iq->intr_lvl_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no);
|
||||
|
||||
/* Store the current instruction counter (used in flush_iq calculation) */
|
||||
reset_instr_cnt = readl(iq->inst_cnt_reg);
|
||||
writel(reset_instr_cnt, iq->inst_cnt_reg);
|
||||
|
||||
/* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */
|
||||
reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Setup registers for a hardware Rx Queue */
|
||||
static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
struct octep_vf_oq *oq = oct->oq[oq_no];
|
||||
u32 time_threshold = 0;
|
||||
u64 oq_ctl = 0ULL;
|
||||
u64 reg_val;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
|
||||
/* wait for IDLE to set to 1 */
|
||||
if (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)) {
|
||||
do {
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
} while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE));
|
||||
}
|
||||
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_P);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_I);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_I);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_I);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_D);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_D);
|
||||
reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_D);
|
||||
reg_val |= (CNXK_VF_R_OUT_CTL_ES_P);
|
||||
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count);
|
||||
|
||||
oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
|
||||
/* Clear the ISIZE and BSIZE (22-0) */
|
||||
oq_ctl &= ~0x7fffffULL;
|
||||
/* Populate the BSIZE (15-0) */
|
||||
oq_ctl |= (oq->buffer_size & 0xffff);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl);
|
||||
|
||||
/* Get the mapped address of the pkt_sent and pkts_credit regs */
|
||||
oq->pkts_sent_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_CNTS(oq_no);
|
||||
oq->pkts_credit_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no);
|
||||
|
||||
time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf);
|
||||
reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
||||
|
||||
/* set watermark for backpressure */
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no));
|
||||
reg_val &= ~0xFFFFFFFFULL;
|
||||
reg_val |= CFG_GET_OQ_WMARK(oct->conf);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Setup registers for a VF mailbox */
|
||||
static void octep_vf_setup_mbox_regs_cnxk(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
struct octep_vf_mbox *mbox = oct->mbox;
|
||||
|
||||
/* PF to VF DATA reg. VF reads from this reg */
|
||||
mbox->mbox_read_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_DATA(q_no);
|
||||
|
||||
/* VF mbox interrupt reg */
|
||||
mbox->mbox_int_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_INT(q_no);
|
||||
|
||||
/* VF to PF DATA reg. VF writes into this reg */
|
||||
mbox->mbox_write_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_VF_PF_DATA(q_no);
|
||||
}
|
||||
|
||||
/* Mailbox Interrupt handler */
|
||||
static void cnxk_handle_vf_mbox_intr(struct octep_vf_device *oct)
|
||||
{
|
||||
if (oct->mbox)
|
||||
schedule_work(&oct->mbox->wk.work);
|
||||
else
|
||||
dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n");
|
||||
}
|
||||
|
||||
/* Tx/Rx queue interrupt handler */
|
||||
static irqreturn_t octep_vf_ioq_intr_handler_cnxk(void *data)
|
||||
{
|
||||
struct octep_vf_ioq_vector *vector = (struct octep_vf_ioq_vector *)data;
|
||||
struct octep_vf_oq *oq = vector->oq;
|
||||
struct octep_vf_device *oct = vector->octep_vf_dev;
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
/* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */
|
||||
if (oq->q_no == 0) {
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0));
|
||||
if (reg_val & CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS) {
|
||||
cnxk_handle_vf_mbox_intr(oct);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val);
|
||||
}
|
||||
}
|
||||
napi_schedule_irqoff(oq->napi);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Re-initialize Octeon hardware registers */
|
||||
static void octep_vf_reinit_regs_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
oct->hw_ops.setup_iq_regs(oct, i);
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
oct->hw_ops.setup_oq_regs(oct, i);
|
||||
|
||||
oct->hw_ops.enable_interrupts(oct);
|
||||
oct->hw_ops.enable_io_queues(oct);
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
||||
writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
|
||||
}
|
||||
|
||||
/* Enable all interrupts */
|
||||
static void octep_vf_enable_interrupts_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
int num_rings, q;
|
||||
u64 reg_val;
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++) {
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val);
|
||||
}
|
||||
/* Enable PF to VF mbox interrupt by setting 2nd bit*/
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0),
|
||||
CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB);
|
||||
}
|
||||
|
||||
/* Disable all interrupts */
|
||||
static void octep_vf_disable_interrupts_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
int num_rings, q;
|
||||
u64 reg_val;
|
||||
|
||||
/* Disable PF to VF mbox interrupt by setting 2nd bit*/
|
||||
if (oct->mbox)
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0);
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++) {
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q));
|
||||
reg_val &= ~(0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q));
|
||||
reg_val &= ~(0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */
|
||||
static u32 octep_vf_update_iq_read_index_cnxk(struct octep_vf_iq *iq)
|
||||
{
|
||||
u32 pkt_in_done = readl(iq->inst_cnt_reg);
|
||||
u32 last_done, new_idx;
|
||||
|
||||
last_done = pkt_in_done - iq->pkt_in_done;
|
||||
iq->pkt_in_done = pkt_in_done;
|
||||
|
||||
new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count;
|
||||
|
||||
return new_idx;
|
||||
}
|
||||
|
||||
/* Enable a hardware Tx Queue */
|
||||
static void octep_vf_enable_iq_cnxk(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
u64 loop = HZ;
|
||||
u64 reg_val;
|
||||
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF);
|
||||
|
||||
while (octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no)) &&
|
||||
loop--) {
|
||||
schedule_timeout_interruptible(1);
|
||||
}
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no));
|
||||
reg_val |= 0x1ULL;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Enable a hardware Rx Queue */
|
||||
static void octep_vf_enable_oq_cnxk(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no));
|
||||
reg_val |= (0x1ULL << 62);
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
||||
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF);
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no));
|
||||
reg_val |= 0x1ULL;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Enable all hardware Tx/Rx Queues assigned to VF */
|
||||
static void octep_vf_enable_io_queues_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
u8 q;
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
octep_vf_enable_iq_cnxk(oct, q);
|
||||
octep_vf_enable_oq_cnxk(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable a hardware Tx Queue assigned to VF */
|
||||
static void octep_vf_disable_iq_cnxk(struct octep_vf_device *oct, int iq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no));
|
||||
reg_val &= ~0x1ULL;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Disable a hardware Rx Queue assigned to VF */
|
||||
static void octep_vf_disable_oq_cnxk(struct octep_vf_device *oct, int oq_no)
|
||||
{
|
||||
u64 reg_val = 0ULL;
|
||||
|
||||
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no));
|
||||
reg_val &= ~0x1ULL;
|
||||
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
||||
}
|
||||
|
||||
/* Disable all hardware Tx/Rx Queues assigned to VF */
|
||||
static void octep_vf_disable_io_queues_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
int q = 0;
|
||||
|
||||
for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
||||
octep_vf_disable_iq_cnxk(oct, q);
|
||||
octep_vf_disable_oq_cnxk(oct, q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump hardware registers (including Tx/Rx queues) for debugging. */
|
||||
static void octep_vf_dump_registers_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
u8 num_rings, q;
|
||||
|
||||
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
for (q = 0; q < num_rings; q++)
|
||||
cnxk_vf_dump_q_regs(oct, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_device_setup_cnxk() - Setup Octeon device.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*
|
||||
* - initialize hardware operations.
|
||||
* - get target side pcie port number for the device.
|
||||
* - set initial configuration and max limits.
|
||||
*/
|
||||
void octep_vf_device_setup_cnxk(struct octep_vf_device *oct)
|
||||
{
|
||||
oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cnxk;
|
||||
oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cnxk;
|
||||
oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cnxk;
|
||||
|
||||
oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cnxk;
|
||||
oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cnxk;
|
||||
|
||||
oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cnxk;
|
||||
oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cnxk;
|
||||
|
||||
oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cnxk;
|
||||
|
||||
oct->hw_ops.enable_iq = octep_vf_enable_iq_cnxk;
|
||||
oct->hw_ops.enable_oq = octep_vf_enable_oq_cnxk;
|
||||
oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cnxk;
|
||||
|
||||
oct->hw_ops.disable_iq = octep_vf_disable_iq_cnxk;
|
||||
oct->hw_ops.disable_oq = octep_vf_disable_oq_cnxk;
|
||||
oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cnxk;
|
||||
oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cnxk;
|
||||
|
||||
oct->hw_ops.dump_registers = octep_vf_dump_registers_cnxk;
|
||||
octep_vf_init_config_cnxk_vf(oct);
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OCTEP_VF_CONFIG_H_
|
||||
#define _OCTEP_VF_CONFIG_H_
|
||||
|
||||
/* Tx instruction types by length */
|
||||
#define OCTEP_VF_32BYTE_INSTR 32
|
||||
#define OCTEP_VF_64BYTE_INSTR 64
|
||||
|
||||
/* Tx Queue: maximum descriptors per ring */
|
||||
#define OCTEP_VF_IQ_MAX_DESCRIPTORS 1024
|
||||
/* Minimum input (Tx) requests to be enqueued to ring doorbell */
|
||||
#define OCTEP_VF_DB_MIN 8
|
||||
/* Packet threshold for Tx queue interrupt */
|
||||
#define OCTEP_VF_IQ_INTR_THRESHOLD 0x0
|
||||
|
||||
/* Minimum watermark for backpressure */
|
||||
#define OCTEP_VF_OQ_WMARK_MIN 256
|
||||
|
||||
/* Rx Queue: maximum descriptors per ring */
|
||||
#define OCTEP_VF_OQ_MAX_DESCRIPTORS 1024
|
||||
|
||||
/* Rx buffer size: Use page size buffers.
|
||||
* Build skb from allocated page buffer once the packet is received.
|
||||
* When a gathered packet is received, make head page as skb head and
|
||||
* page buffers in consecutive Rx descriptors as fragments.
|
||||
*/
|
||||
#define OCTEP_VF_OQ_BUF_SIZE (SKB_WITH_OVERHEAD(PAGE_SIZE))
|
||||
#define OCTEP_VF_OQ_PKTS_PER_INTR 128
|
||||
#define OCTEP_VF_OQ_REFILL_THRESHOLD (OCTEP_VF_OQ_MAX_DESCRIPTORS / 4)
|
||||
|
||||
#define OCTEP_VF_OQ_INTR_PKT_THRESHOLD 1
|
||||
#define OCTEP_VF_OQ_INTR_TIME_THRESHOLD 10
|
||||
|
||||
#define OCTEP_VF_MSIX_NAME_SIZE (IFNAMSIZ + 32)
|
||||
|
||||
/* Tx Queue wake threshold
|
||||
* wakeup a stopped Tx queue if minimum 2 descriptors are available.
|
||||
* Even a skb with fragments consume only one Tx queue descriptor entry.
|
||||
*/
|
||||
#define OCTEP_VF_WAKE_QUEUE_THRESHOLD 2
|
||||
|
||||
/* Minimum MTU supported by Octeon network interface */
|
||||
#define OCTEP_VF_MIN_MTU ETH_MIN_MTU
|
||||
/* Maximum MTU supported by Octeon interface*/
|
||||
#define OCTEP_VF_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN))
|
||||
/* Default MTU */
|
||||
#define OCTEP_VF_DEFAULT_MTU 1500
|
||||
|
||||
/* Macros to get octeon config params */
|
||||
#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq)
|
||||
#define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs)
|
||||
#define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type)
|
||||
#define CFG_GET_IQ_INSTR_SIZE(cfg) (64)
|
||||
#define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min)
|
||||
#define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold)
|
||||
|
||||
#define CFG_GET_OQ_NUM_DESC(cfg) ((cfg)->oq.num_descs)
|
||||
#define CFG_GET_OQ_BUF_SIZE(cfg) ((cfg)->oq.buf_size)
|
||||
#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold)
|
||||
#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt)
|
||||
#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time)
|
||||
#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark)
|
||||
|
||||
#define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->ring_cfg.active_io_rings)
|
||||
#define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->ring_cfg.max_io_rings)
|
||||
|
||||
#define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us)
|
||||
#define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us)
|
||||
|
||||
#define CFG_GET_IOQ_MSIX(cfg) ((cfg)->msix_cfg.ioq_msix)
|
||||
|
||||
/* Hardware Tx Queue configuration. */
|
||||
struct octep_vf_iq_config {
|
||||
/* Size of the Input queue (number of commands) */
|
||||
u16 num_descs;
|
||||
|
||||
/* Command size - 32 or 64 bytes */
|
||||
u16 instr_type;
|
||||
|
||||
/* Minimum number of commands pending to be posted to Octeon before driver
|
||||
* hits the Input queue doorbell.
|
||||
*/
|
||||
u16 db_min;
|
||||
|
||||
/* Trigger the IQ interrupt when processed cmd count reaches
|
||||
* this level.
|
||||
*/
|
||||
u32 intr_threshold;
|
||||
};
|
||||
|
||||
/* Hardware Rx Queue configuration. */
|
||||
struct octep_vf_oq_config {
|
||||
/* Size of Output queue (number of descriptors) */
|
||||
u16 num_descs;
|
||||
|
||||
/* Size of buffer in this Output queue. */
|
||||
u16 buf_size;
|
||||
|
||||
/* The number of buffers that were consumed during packet processing
|
||||
* by the driver on this Output queue before the driver attempts to
|
||||
* replenish the descriptor ring with new buffers.
|
||||
*/
|
||||
u16 refill_threshold;
|
||||
|
||||
/* Interrupt Coalescing (Packet Count). Octeon will interrupt the host
|
||||
* only if it sent as many packets as specified by this field.
|
||||
* The driver usually does not use packet count interrupt coalescing.
|
||||
*/
|
||||
u32 oq_intr_pkt;
|
||||
|
||||
/* Interrupt Coalescing (Time Interval). Octeon will interrupt the host
|
||||
* if at least one packet was sent in the time interval specified by
|
||||
* this field. The driver uses time interval interrupt coalescing by
|
||||
* default. The time is specified in microseconds.
|
||||
*/
|
||||
u32 oq_intr_time;
|
||||
|
||||
/* Water mark for backpressure.
|
||||
* Output queue sends backpressure signal to source when
|
||||
* free buffer count falls below wmark.
|
||||
*/
|
||||
u32 wmark;
|
||||
};
|
||||
|
||||
/* Tx/Rx configuration */
|
||||
struct octep_vf_ring_config {
|
||||
/* Max number of IOQs */
|
||||
u16 max_io_rings;
|
||||
|
||||
/* Number of active IOQs */
|
||||
u16 active_io_rings;
|
||||
};
|
||||
|
||||
/* Octeon MSI-x config. */
|
||||
struct octep_vf_msix_config {
|
||||
/* Number of IOQ interrupts */
|
||||
u16 ioq_msix;
|
||||
};
|
||||
|
||||
/* Data Structure to hold configuration limits and active config */
|
||||
struct octep_vf_config {
|
||||
/* Input Queue attributes. */
|
||||
struct octep_vf_iq_config iq;
|
||||
|
||||
/* Output Queue attributes. */
|
||||
struct octep_vf_oq_config oq;
|
||||
|
||||
/* MSI-X interrupt config */
|
||||
struct octep_vf_msix_config msix_cfg;
|
||||
|
||||
/* NIC VF ring Configuration */
|
||||
struct octep_vf_ring_config ring_cfg;
|
||||
};
|
||||
#endif /* _OCTEP_VF_CONFIG_H_ */
|
@ -1,307 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
|
||||
static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = {
|
||||
"rx_packets",
|
||||
"tx_packets",
|
||||
"rx_bytes",
|
||||
"tx_bytes",
|
||||
"rx_alloc_errors",
|
||||
"tx_busy_errors",
|
||||
"rx_dropped",
|
||||
"tx_dropped",
|
||||
"tx_hw_pkts",
|
||||
"tx_hw_octs",
|
||||
"tx_hw_bcast",
|
||||
"tx_hw_mcast",
|
||||
"rx_hw_pkts",
|
||||
"rx_hw_bytes",
|
||||
"rx_hw_bcast",
|
||||
"rx_hw_mcast",
|
||||
"rx_dropped_pkts_fifo_full",
|
||||
"rx_dropped_bytes_fifo_full",
|
||||
"rx_err_pkts",
|
||||
};
|
||||
|
||||
#define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN)
|
||||
|
||||
static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
|
||||
"tx_packets_posted[Q-%u]",
|
||||
"tx_packets_completed[Q-%u]",
|
||||
"tx_bytes[Q-%u]",
|
||||
"tx_busy[Q-%u]",
|
||||
};
|
||||
|
||||
#define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN)
|
||||
|
||||
static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
|
||||
"rx_packets[Q-%u]",
|
||||
"rx_bytes[Q-%u]",
|
||||
"rx_alloc_errors[Q-%u]",
|
||||
};
|
||||
|
||||
#define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN)
|
||||
|
||||
static void octep_vf_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct octep_vf_device *oct = netdev_priv(netdev);
|
||||
|
||||
strscpy(info->driver, OCTEP_VF_DRV_NAME, sizeof(info->driver));
|
||||
strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info));
|
||||
}
|
||||
|
||||
static void octep_vf_get_strings(struct net_device *netdev,
|
||||
u32 stringset, u8 *data)
|
||||
{
|
||||
struct octep_vf_device *oct = netdev_priv(netdev);
|
||||
u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
char *strings = (char *)data;
|
||||
int i, j;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) {
|
||||
snprintf(strings, ETH_GSTRING_LEN,
|
||||
octep_vf_gstrings_global_stats[i]);
|
||||
strings += ETH_GSTRING_LEN;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_queues; i++) {
|
||||
for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) {
|
||||
snprintf(strings, ETH_GSTRING_LEN,
|
||||
octep_vf_gstrings_tx_q_stats[j], i);
|
||||
strings += ETH_GSTRING_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_queues; i++) {
|
||||
for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) {
|
||||
snprintf(strings, ETH_GSTRING_LEN,
|
||||
octep_vf_gstrings_rx_q_stats[j], i);
|
||||
strings += ETH_GSTRING_LEN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int octep_vf_get_sset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
struct octep_vf_device *oct = netdev_priv(netdev);
|
||||
u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
||||
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return OCTEP_VF_GLOBAL_STATS_CNT + (num_queues *
|
||||
(OCTEP_VF_TX_Q_STATS_CNT + OCTEP_VF_RX_Q_STATS_CNT));
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void octep_vf_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct octep_vf_device *oct = netdev_priv(netdev);
|
||||
struct octep_vf_iface_tx_stats *iface_tx_stats;
|
||||
struct octep_vf_iface_rx_stats *iface_rx_stats;
|
||||
u64 rx_alloc_errors, tx_busy_errors;
|
||||
u64 rx_packets, rx_bytes;
|
||||
u64 tx_packets, tx_bytes;
|
||||
int q, i;
|
||||
|
||||
rx_packets = 0;
|
||||
rx_bytes = 0;
|
||||
tx_packets = 0;
|
||||
tx_bytes = 0;
|
||||
rx_alloc_errors = 0;
|
||||
tx_busy_errors = 0;
|
||||
tx_packets = 0;
|
||||
tx_bytes = 0;
|
||||
rx_packets = 0;
|
||||
rx_bytes = 0;
|
||||
|
||||
octep_vf_get_if_stats(oct);
|
||||
iface_tx_stats = &oct->iface_tx_stats;
|
||||
iface_rx_stats = &oct->iface_rx_stats;
|
||||
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_vf_iq *iq = oct->iq[q];
|
||||
struct octep_vf_oq *oq = oct->oq[q];
|
||||
|
||||
tx_packets += iq->stats.instr_completed;
|
||||
tx_bytes += iq->stats.bytes_sent;
|
||||
tx_busy_errors += iq->stats.tx_busy;
|
||||
|
||||
rx_packets += oq->stats.packets;
|
||||
rx_bytes += oq->stats.bytes;
|
||||
rx_alloc_errors += oq->stats.alloc_failures;
|
||||
}
|
||||
i = 0;
|
||||
data[i++] = rx_packets;
|
||||
data[i++] = tx_packets;
|
||||
data[i++] = rx_bytes;
|
||||
data[i++] = tx_bytes;
|
||||
data[i++] = rx_alloc_errors;
|
||||
data[i++] = tx_busy_errors;
|
||||
data[i++] = iface_rx_stats->dropped_pkts_fifo_full +
|
||||
iface_rx_stats->err_pkts;
|
||||
data[i++] = iface_tx_stats->dropped;
|
||||
data[i++] = iface_tx_stats->pkts;
|
||||
data[i++] = iface_tx_stats->octs;
|
||||
data[i++] = iface_tx_stats->bcst;
|
||||
data[i++] = iface_tx_stats->mcst;
|
||||
data[i++] = iface_rx_stats->pkts;
|
||||
data[i++] = iface_rx_stats->octets;
|
||||
data[i++] = iface_rx_stats->mcast_pkts;
|
||||
data[i++] = iface_rx_stats->bcast_pkts;
|
||||
data[i++] = iface_rx_stats->dropped_pkts_fifo_full;
|
||||
data[i++] = iface_rx_stats->dropped_octets_fifo_full;
|
||||
data[i++] = iface_rx_stats->err_pkts;
|
||||
|
||||
/* Per Tx Queue stats */
|
||||
for (q = 0; q < oct->num_iqs; q++) {
|
||||
struct octep_vf_iq *iq = oct->iq[q];
|
||||
|
||||
data[i++] = iq->stats.instr_posted;
|
||||
data[i++] = iq->stats.instr_completed;
|
||||
data[i++] = iq->stats.bytes_sent;
|
||||
data[i++] = iq->stats.tx_busy;
|
||||
}
|
||||
|
||||
/* Per Rx Queue stats */
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_vf_oq *oq = oct->oq[q];
|
||||
|
||||
data[i++] = oq->stats.packets;
|
||||
data[i++] = oq->stats.bytes;
|
||||
data[i++] = oq->stats.alloc_failures;
|
||||
}
|
||||
}
|
||||
|
||||
#define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \
|
||||
{ \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \
|
||||
if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \
|
||||
ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \
|
||||
}
|
||||
|
||||
static int octep_vf_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct octep_vf_device *oct = netdev_priv(netdev);
|
||||
struct octep_vf_iface_link_info *link_info;
|
||||
u32 advertised_modes, supported_modes;
|
||||
|
||||
ethtool_link_ksettings_zero_link_mode(cmd, supported);
|
||||
ethtool_link_ksettings_zero_link_mode(cmd, advertising);
|
||||
|
||||
octep_vf_get_link_info(oct);
|
||||
|
||||
advertised_modes = oct->link_info.advertised_modes;
|
||||
supported_modes = oct->link_info.supported_modes;
|
||||
link_info = &oct->link_info;
|
||||
|
||||
OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);
|
||||
OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);
|
||||
|
||||
if (link_info->autoneg) {
|
||||
if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
|
||||
if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
|
||||
cmd->base.autoneg = AUTONEG_ENABLE;
|
||||
} else {
|
||||
cmd->base.autoneg = AUTONEG_DISABLE;
|
||||
}
|
||||
} else {
|
||||
cmd->base.autoneg = AUTONEG_DISABLE;
|
||||
}
|
||||
|
||||
cmd->base.port = PORT_FIBRE;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
|
||||
|
||||
if (netif_carrier_ok(netdev)) {
|
||||
cmd->base.speed = link_info->speed;
|
||||
cmd->base.duplex = DUPLEX_FULL;
|
||||
} else {
|
||||
cmd->base.speed = SPEED_UNKNOWN;
|
||||
cmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops octep_vf_ethtool_ops = {
|
||||
.get_drvinfo = octep_vf_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_strings = octep_vf_get_strings,
|
||||
.get_sset_count = octep_vf_get_sset_count,
|
||||
.get_ethtool_stats = octep_vf_get_ethtool_stats,
|
||||
.get_link_ksettings = octep_vf_get_link_ksettings,
|
||||
};
|
||||
|
||||
void octep_vf_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
netdev->ethtool_ops = &octep_vf_ethtool_ops;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,338 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OCTEP_VF_MAIN_H_
|
||||
#define _OCTEP_VF_MAIN_H_
|
||||
|
||||
#include "octep_vf_tx.h"
|
||||
#include "octep_vf_rx.h"
|
||||
#include "octep_vf_mbox.h"
|
||||
|
||||
#define OCTEP_VF_DRV_NAME "octeon_ep_vf"
|
||||
#define OCTEP_VF_DRV_STRING "Marvell Octeon EndPoint NIC VF Driver"
|
||||
|
||||
#define OCTEP_PCI_DEVICE_ID_CN93_VF 0xB203 //93xx VF
|
||||
#define OCTEP_PCI_DEVICE_ID_CNF95N_VF 0xB403 //95N VF
|
||||
#define OCTEP_PCI_DEVICE_ID_CN98_VF 0xB103
|
||||
#define OCTEP_PCI_DEVICE_ID_CN10KA_VF 0xB903
|
||||
#define OCTEP_PCI_DEVICE_ID_CNF10KA_VF 0xBA03
|
||||
#define OCTEP_PCI_DEVICE_ID_CNF10KB_VF 0xBC03
|
||||
#define OCTEP_PCI_DEVICE_ID_CN10KB_VF 0xBD03
|
||||
|
||||
#define OCTEP_VF_MAX_QUEUES 63
|
||||
#define OCTEP_VF_MAX_IQ OCTEP_VF_MAX_QUEUES
|
||||
#define OCTEP_VF_MAX_OQ OCTEP_VF_MAX_QUEUES
|
||||
|
||||
#define OCTEP_VF_MAX_MSIX_VECTORS OCTEP_VF_MAX_OQ
|
||||
|
||||
#define OCTEP_VF_IQ_INTR_RESEND_BIT 59
|
||||
#define OCTEP_VF_OQ_INTR_RESEND_BIT 59
|
||||
|
||||
#define IQ_INSTR_PENDING(iq) ({ typeof(iq) iq__ = (iq); \
|
||||
((iq__)->host_write_index - (iq__)->flush_index) & \
|
||||
(iq__)->ring_size_mask; \
|
||||
})
|
||||
#define IQ_INSTR_SPACE(iq) ({ typeof(iq) iq_ = (iq); \
|
||||
(iq_)->max_count - IQ_INSTR_PENDING(iq_); \
|
||||
})
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX ((u64)(~((u64)0))) /* 0xFFFFFFFFFFFFFFFF */
|
||||
#endif
|
||||
|
||||
/* PCI address space mapping information.
|
||||
* Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of
|
||||
* Octeon gets mapped to different physical address spaces in
|
||||
* the kernel.
|
||||
*/
|
||||
struct octep_vf_mmio {
|
||||
/* The physical address to which the PCI address space is mapped. */
|
||||
u8 __iomem *hw_addr;
|
||||
|
||||
/* Flag indicating the mapping was successful. */
|
||||
int mapped;
|
||||
};
|
||||
|
||||
struct octep_vf_hw_ops {
|
||||
void (*setup_iq_regs)(struct octep_vf_device *oct, int q);
|
||||
void (*setup_oq_regs)(struct octep_vf_device *oct, int q);
|
||||
void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox);
|
||||
|
||||
irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector);
|
||||
irqreturn_t (*ioq_intr_handler)(void *ioq_vector);
|
||||
void (*reinit_regs)(struct octep_vf_device *oct);
|
||||
u32 (*update_iq_read_idx)(struct octep_vf_iq *iq);
|
||||
|
||||
void (*enable_interrupts)(struct octep_vf_device *oct);
|
||||
void (*disable_interrupts)(struct octep_vf_device *oct);
|
||||
|
||||
void (*enable_io_queues)(struct octep_vf_device *oct);
|
||||
void (*disable_io_queues)(struct octep_vf_device *oct);
|
||||
void (*enable_iq)(struct octep_vf_device *oct, int q);
|
||||
void (*disable_iq)(struct octep_vf_device *oct, int q);
|
||||
void (*enable_oq)(struct octep_vf_device *oct, int q);
|
||||
void (*disable_oq)(struct octep_vf_device *oct, int q);
|
||||
void (*reset_io_queues)(struct octep_vf_device *oct);
|
||||
void (*dump_registers)(struct octep_vf_device *oct);
|
||||
};
|
||||
|
||||
/* Octeon mailbox data */
|
||||
struct octep_vf_mbox_data {
|
||||
/* Holds the offset of received data via mailbox. */
|
||||
u32 data_index;
|
||||
|
||||
/* Holds the received data via mailbox. */
|
||||
u8 recv_data[OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE];
|
||||
};
|
||||
|
||||
/* wrappers around work structs */
|
||||
struct octep_vf_mbox_wk {
|
||||
struct work_struct work;
|
||||
void *ctxptr;
|
||||
};
|
||||
|
||||
/* Octeon device mailbox */
|
||||
struct octep_vf_mbox {
|
||||
/* A mutex to protect access to this q_mbox. */
|
||||
struct mutex lock;
|
||||
|
||||
u32 state;
|
||||
|
||||
/* SLI_MAC_PF_MBOX_INT for PF, SLI_PKT_MBOX_INT for VF. */
|
||||
u8 __iomem *mbox_int_reg;
|
||||
|
||||
/* SLI_PKT_PF_VF_MBOX_SIG(0) for PF,
|
||||
* SLI_PKT_PF_VF_MBOX_SIG(1) for VF.
|
||||
*/
|
||||
u8 __iomem *mbox_write_reg;
|
||||
|
||||
/* SLI_PKT_PF_VF_MBOX_SIG(1) for PF,
|
||||
* SLI_PKT_PF_VF_MBOX_SIG(0) for VF.
|
||||
*/
|
||||
u8 __iomem *mbox_read_reg;
|
||||
|
||||
/* Octeon mailbox data */
|
||||
struct octep_vf_mbox_data mbox_data;
|
||||
|
||||
/* Octeon mailbox work handler to process Mbox messages */
|
||||
struct octep_vf_mbox_wk wk;
|
||||
};
|
||||
|
||||
/* Tx/Rx queue vector per interrupt. */
|
||||
struct octep_vf_ioq_vector {
|
||||
char name[OCTEP_VF_MSIX_NAME_SIZE];
|
||||
struct napi_struct napi;
|
||||
struct octep_vf_device *octep_vf_dev;
|
||||
struct octep_vf_iq *iq;
|
||||
struct octep_vf_oq *oq;
|
||||
cpumask_t affinity_mask;
|
||||
};
|
||||
|
||||
/* Octeon hardware/firmware offload capability flags. */
|
||||
#define OCTEP_VF_CAP_TX_CHECKSUM BIT(0)
|
||||
#define OCTEP_VF_CAP_RX_CHECKSUM BIT(1)
|
||||
#define OCTEP_VF_CAP_TSO BIT(2)
|
||||
|
||||
/* Link modes */
|
||||
enum octep_vf_link_mode_bit_indices {
|
||||
OCTEP_VF_LINK_MODE_10GBASE_T = 0,
|
||||
OCTEP_VF_LINK_MODE_10GBASE_R,
|
||||
OCTEP_VF_LINK_MODE_10GBASE_CR,
|
||||
OCTEP_VF_LINK_MODE_10GBASE_KR,
|
||||
OCTEP_VF_LINK_MODE_10GBASE_LR,
|
||||
OCTEP_VF_LINK_MODE_10GBASE_SR,
|
||||
OCTEP_VF_LINK_MODE_25GBASE_CR,
|
||||
OCTEP_VF_LINK_MODE_25GBASE_KR,
|
||||
OCTEP_VF_LINK_MODE_25GBASE_SR,
|
||||
OCTEP_VF_LINK_MODE_40GBASE_CR4,
|
||||
OCTEP_VF_LINK_MODE_40GBASE_KR4,
|
||||
OCTEP_VF_LINK_MODE_40GBASE_LR4,
|
||||
OCTEP_VF_LINK_MODE_40GBASE_SR4,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_CR2,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_KR2,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_SR2,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_CR,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_KR,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_LR,
|
||||
OCTEP_VF_LINK_MODE_50GBASE_SR,
|
||||
OCTEP_VF_LINK_MODE_100GBASE_CR4,
|
||||
OCTEP_VF_LINK_MODE_100GBASE_KR4,
|
||||
OCTEP_VF_LINK_MODE_100GBASE_LR4,
|
||||
OCTEP_VF_LINK_MODE_100GBASE_SR4,
|
||||
OCTEP_VF_LINK_MODE_NBITS
|
||||
};
|
||||
|
||||
/* Hardware interface link state information. */
|
||||
struct octep_vf_iface_link_info {
|
||||
/* Bitmap of Supported link speeds/modes. */
|
||||
u64 supported_modes;
|
||||
|
||||
/* Bitmap of Advertised link speeds/modes. */
|
||||
u64 advertised_modes;
|
||||
|
||||
/* Negotiated link speed in Mbps. */
|
||||
u32 speed;
|
||||
|
||||
/* MTU */
|
||||
u16 mtu;
|
||||
|
||||
/* Autonegotiation state. */
|
||||
#define OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED BIT(0)
|
||||
#define OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED BIT(1)
|
||||
u8 autoneg;
|
||||
|
||||
/* Pause frames setting. */
|
||||
#define OCTEP_VF_LINK_MODE_PAUSE_SUPPORTED BIT(0)
|
||||
#define OCTEP_VF_LINK_MODE_PAUSE_ADVERTISED BIT(1)
|
||||
u8 pause;
|
||||
|
||||
/* Admin state of the link (ifconfig <iface> up/down */
|
||||
u8 admin_up;
|
||||
|
||||
/* Operational state of the link: physical link is up down */
|
||||
u8 oper_up;
|
||||
};
|
||||
|
||||
/* Hardware interface stats information. */
|
||||
struct octep_vf_iface_rxtx_stats {
|
||||
/* Hardware Interface Rx statistics */
|
||||
struct octep_vf_iface_rx_stats iface_rx_stats;
|
||||
|
||||
/* Hardware Interface Tx statistics */
|
||||
struct octep_vf_iface_tx_stats iface_tx_stats;
|
||||
};
|
||||
|
||||
struct octep_vf_fw_info {
|
||||
/* pkind value to be used in every Tx hardware descriptor */
|
||||
u8 pkind;
|
||||
/* front size data */
|
||||
u8 fsz;
|
||||
/* supported rx offloads OCTEP_VF_RX_OFFLOAD_* */
|
||||
u16 rx_ol_flags;
|
||||
/* supported tx offloads OCTEP_VF_TX_OFFLOAD_* */
|
||||
u16 tx_ol_flags;
|
||||
};
|
||||
|
||||
/* The Octeon device specific private data structure.
|
||||
* Each Octeon device has this structure to represent all its components.
|
||||
*/
|
||||
struct octep_vf_device {
|
||||
struct octep_vf_config *conf;
|
||||
|
||||
/* Octeon Chip type. */
|
||||
u16 chip_id;
|
||||
u16 rev_id;
|
||||
|
||||
/* Device capabilities enabled */
|
||||
u64 caps_enabled;
|
||||
/* Device capabilities supported */
|
||||
u64 caps_supported;
|
||||
|
||||
/* Pointer to basic Linux device */
|
||||
struct device *dev;
|
||||
/* Linux PCI device pointer */
|
||||
struct pci_dev *pdev;
|
||||
/* Netdev corresponding to the Octeon device */
|
||||
struct net_device *netdev;
|
||||
|
||||
/* memory mapped io range */
|
||||
struct octep_vf_mmio mmio;
|
||||
|
||||
/* MAC address */
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
/* Tx queues (IQ: Instruction Queue) */
|
||||
u16 num_iqs;
|
||||
/* Pointers to Octeon Tx queues */
|
||||
struct octep_vf_iq *iq[OCTEP_VF_MAX_IQ];
|
||||
|
||||
/* Rx queues (OQ: Output Queue) */
|
||||
u16 num_oqs;
|
||||
/* Pointers to Octeon Rx queues */
|
||||
struct octep_vf_oq *oq[OCTEP_VF_MAX_OQ];
|
||||
|
||||
/* Hardware port number of the PCIe interface */
|
||||
u16 pcie_port;
|
||||
|
||||
/* Hardware operations */
|
||||
struct octep_vf_hw_ops hw_ops;
|
||||
|
||||
/* IRQ info */
|
||||
u16 num_irqs;
|
||||
u16 num_non_ioq_irqs;
|
||||
char *non_ioq_irq_names;
|
||||
struct msix_entry *msix_entries;
|
||||
/* IOq information of it's corresponding MSI-X interrupt. */
|
||||
struct octep_vf_ioq_vector *ioq_vector[OCTEP_VF_MAX_QUEUES];
|
||||
|
||||
/* Hardware Interface Tx statistics */
|
||||
struct octep_vf_iface_tx_stats iface_tx_stats;
|
||||
/* Hardware Interface Rx statistics */
|
||||
struct octep_vf_iface_rx_stats iface_rx_stats;
|
||||
|
||||
/* Hardware Interface Link info like supported modes, aneg support */
|
||||
struct octep_vf_iface_link_info link_info;
|
||||
|
||||
/* Mailbox to talk to VFs */
|
||||
struct octep_vf_mbox *mbox;
|
||||
|
||||
/* Work entry to handle Tx timeout */
|
||||
struct work_struct tx_timeout_task;
|
||||
|
||||
/* offset for iface stats */
|
||||
u32 ctrl_mbox_ifstats_offset;
|
||||
|
||||
/* Negotiated Mbox version */
|
||||
u32 mbox_neg_ver;
|
||||
|
||||
/* firmware info */
|
||||
struct octep_vf_fw_info fw_info;
|
||||
};
|
||||
|
||||
static inline u16 OCTEP_VF_MAJOR_REV(struct octep_vf_device *oct)
|
||||
{
|
||||
u16 rev = (oct->rev_id & 0xC) >> 2;
|
||||
|
||||
return (rev == 0) ? 1 : rev;
|
||||
}
|
||||
|
||||
static inline u16 OCTEP_VF_MINOR_REV(struct octep_vf_device *oct)
|
||||
{
|
||||
return (oct->rev_id & 0x3);
|
||||
}
|
||||
|
||||
/* Octeon CSR read/write access APIs */
|
||||
#define octep_vf_write_csr(octep_vf_dev, reg_off, value) \
|
||||
writel(value, (octep_vf_dev)->mmio.hw_addr + (reg_off))
|
||||
|
||||
#define octep_vf_write_csr64(octep_vf_dev, reg_off, val64) \
|
||||
writeq(val64, (octep_vf_dev)->mmio.hw_addr + (reg_off))
|
||||
|
||||
#define octep_vf_read_csr(octep_vf_dev, reg_off) \
|
||||
readl((octep_vf_dev)->mmio.hw_addr + (reg_off))
|
||||
|
||||
#define octep_vf_read_csr64(octep_vf_dev, reg_off) \
|
||||
readq((octep_vf_dev)->mmio.hw_addr + (reg_off))
|
||||
|
||||
extern struct workqueue_struct *octep_vf_wq;
|
||||
|
||||
int octep_vf_device_setup(struct octep_vf_device *oct);
|
||||
int octep_vf_setup_iqs(struct octep_vf_device *oct);
|
||||
void octep_vf_free_iqs(struct octep_vf_device *oct);
|
||||
void octep_vf_clean_iqs(struct octep_vf_device *oct);
|
||||
int octep_vf_setup_oqs(struct octep_vf_device *oct);
|
||||
void octep_vf_free_oqs(struct octep_vf_device *oct);
|
||||
void octep_vf_oq_dbell_init(struct octep_vf_device *oct);
|
||||
void octep_vf_device_setup_cn93(struct octep_vf_device *oct);
|
||||
void octep_vf_device_setup_cnxk(struct octep_vf_device *oct);
|
||||
int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget);
|
||||
int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget);
|
||||
void octep_vf_set_ethtool_ops(struct net_device *netdev);
|
||||
int octep_vf_get_link_info(struct octep_vf_device *oct);
|
||||
int octep_vf_get_if_stats(struct octep_vf_device *oct);
|
||||
void octep_vf_mbox_work(struct work_struct *work);
|
||||
#endif /* _OCTEP_VF_MAIN_H_ */
|
@ -1,430 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
|
||||
/* When a new command is implemented, the below table should be updated
|
||||
* with new command and it's version info.
|
||||
*/
|
||||
static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = {
|
||||
[0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1,
|
||||
[OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] =
|
||||
OCTEP_PFVF_MBOX_VERSION_V2
|
||||
};
|
||||
|
||||
int octep_vf_setup_mbox(struct octep_vf_device *oct)
|
||||
{
|
||||
int ring = 0;
|
||||
|
||||
oct->mbox = vzalloc(sizeof(*oct->mbox));
|
||||
if (!oct->mbox)
|
||||
return -1;
|
||||
|
||||
mutex_init(&oct->mbox->lock);
|
||||
|
||||
oct->hw_ops.setup_mbox_regs(oct, ring);
|
||||
INIT_WORK(&oct->mbox->wk.work, octep_vf_mbox_work);
|
||||
oct->mbox->wk.ctxptr = oct;
|
||||
oct->mbox_neg_ver = OCTEP_PFVF_MBOX_VERSION_CURRENT;
|
||||
dev_info(&oct->pdev->dev, "setup vf mbox successfully\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void octep_vf_delete_mbox(struct octep_vf_device *oct)
|
||||
{
|
||||
if (oct->mbox) {
|
||||
if (work_pending(&oct->mbox->wk.work))
|
||||
cancel_work_sync(&oct->mbox->wk.work);
|
||||
|
||||
mutex_destroy(&oct->mbox->lock);
|
||||
vfree(oct->mbox);
|
||||
oct->mbox = NULL;
|
||||
dev_info(&oct->pdev->dev, "Deleted vf mbox successfully\n");
|
||||
}
|
||||
}
|
||||
|
||||
int octep_vf_mbox_version_check(struct octep_vf_device *oct)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_version.opcode = OCTEP_PFVF_MBOX_CMD_VERSION;
|
||||
cmd.s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret == OCTEP_PFVF_MBOX_CMD_STATUS_NACK) {
|
||||
dev_err(&oct->pdev->dev,
|
||||
"VF Mbox version is incompatible with PF\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
oct->mbox_neg_ver = (u32)rsp.s_version.version;
|
||||
dev_dbg(&oct->pdev->dev,
|
||||
"VF Mbox version:%u Negotiated VF version with PF:%u\n",
|
||||
(u32)cmd.s_version.version,
|
||||
(u32)rsp.s_version.version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void octep_vf_mbox_work(struct work_struct *work)
|
||||
{
|
||||
struct octep_vf_mbox_wk *wk = container_of(work, struct octep_vf_mbox_wk, work);
|
||||
struct octep_vf_iface_link_info *link_info;
|
||||
struct octep_vf_device *oct = NULL;
|
||||
struct octep_vf_mbox *mbox = NULL;
|
||||
union octep_pfvf_mbox_word *notif;
|
||||
u64 pf_vf_data;
|
||||
|
||||
oct = (struct octep_vf_device *)wk->ctxptr;
|
||||
link_info = &oct->link_info;
|
||||
mbox = oct->mbox;
|
||||
pf_vf_data = readq(mbox->mbox_read_reg);
|
||||
|
||||
notif = (union octep_pfvf_mbox_word *)&pf_vf_data;
|
||||
|
||||
switch (notif->s.opcode) {
|
||||
case OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS:
|
||||
if (notif->s_link_status.status) {
|
||||
link_info->oper_up = OCTEP_PFVF_LINK_STATUS_UP;
|
||||
netif_carrier_on(oct->netdev);
|
||||
dev_info(&oct->pdev->dev, "netif_carrier_on\n");
|
||||
} else {
|
||||
link_info->oper_up = OCTEP_PFVF_LINK_STATUS_DOWN;
|
||||
netif_carrier_off(oct->netdev);
|
||||
dev_info(&oct->pdev->dev, "netif_carrier_off\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(&oct->pdev->dev,
|
||||
"Received unsupported notif %d\n", notif->s.opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int __octep_vf_mbox_send_cmd(struct octep_vf_device *oct,
|
||||
union octep_pfvf_mbox_word cmd,
|
||||
union octep_pfvf_mbox_word *rsp)
|
||||
{
|
||||
struct octep_vf_mbox *mbox = oct->mbox;
|
||||
u64 reg_val = 0ull;
|
||||
int count = 0;
|
||||
|
||||
if (!mbox)
|
||||
return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
|
||||
|
||||
cmd.s.type = OCTEP_PFVF_MBOX_TYPE_CMD;
|
||||
writeq(cmd.u64, mbox->mbox_write_reg);
|
||||
|
||||
/* No response for notification messages */
|
||||
if (!rsp)
|
||||
return 0;
|
||||
|
||||
for (count = 0; count < OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT; count++) {
|
||||
usleep_range(1000, 1500);
|
||||
reg_val = readq(mbox->mbox_write_reg);
|
||||
if (reg_val != cmd.u64) {
|
||||
rsp->u64 = reg_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count == OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT) {
|
||||
dev_err(&oct->pdev->dev, "mbox send command timed out\n");
|
||||
return OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT;
|
||||
}
|
||||
if (rsp->s.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "mbox_send: Received NACK\n");
|
||||
return OCTEP_PFVF_MBOX_CMD_STATUS_NACK;
|
||||
}
|
||||
rsp->u64 = reg_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd,
|
||||
union octep_pfvf_mbox_word *rsp)
|
||||
{
|
||||
struct octep_vf_mbox *mbox = oct->mbox;
|
||||
int ret;
|
||||
|
||||
if (!mbox)
|
||||
return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
|
||||
mutex_lock(&mbox->lock);
|
||||
if (pfvf_cmd_versions[cmd.s.opcode] > oct->mbox_neg_ver) {
|
||||
dev_dbg(&oct->pdev->dev, "CMD:%d not supported in Version:%d\n",
|
||||
cmd.s.opcode, oct->mbox_neg_ver);
|
||||
mutex_unlock(&mbox->lock);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ret = __octep_vf_mbox_send_cmd(oct, cmd, rsp);
|
||||
mutex_unlock(&mbox->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode,
|
||||
u8 *data, int *size)
|
||||
{
|
||||
struct octep_vf_mbox *mbox = oct->mbox;
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int data_len = 0, tmp_len = 0;
|
||||
int read_cnt, i = 0, ret;
|
||||
|
||||
if (!mbox)
|
||||
return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
|
||||
|
||||
mutex_lock(&mbox->lock);
|
||||
cmd.u64 = 0;
|
||||
cmd.s_data.opcode = opcode;
|
||||
cmd.s_data.frag = 0;
|
||||
/* Send cmd to read data from PF */
|
||||
ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n");
|
||||
mutex_unlock(&mbox->lock);
|
||||
return ret;
|
||||
}
|
||||
/* PF sends the data length of requested CMD
|
||||
* in ACK
|
||||
*/
|
||||
data_len = *((int32_t *)rsp.s_data.data);
|
||||
tmp_len = data_len;
|
||||
cmd.u64 = 0;
|
||||
rsp.u64 = 0;
|
||||
cmd.s_data.opcode = opcode;
|
||||
cmd.s_data.frag = 1;
|
||||
while (data_len) {
|
||||
ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n");
|
||||
mutex_unlock(&mbox->lock);
|
||||
mbox->mbox_data.data_index = 0;
|
||||
memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE);
|
||||
return ret;
|
||||
}
|
||||
if (data_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE) {
|
||||
data_len -= OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
|
||||
read_cnt = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
|
||||
} else {
|
||||
read_cnt = data_len;
|
||||
data_len = 0;
|
||||
}
|
||||
for (i = 0; i < read_cnt; i++) {
|
||||
mbox->mbox_data.recv_data[mbox->mbox_data.data_index] =
|
||||
rsp.s_data.data[i];
|
||||
mbox->mbox_data.data_index++;
|
||||
}
|
||||
cmd.u64 = 0;
|
||||
rsp.u64 = 0;
|
||||
cmd.s_data.opcode = opcode;
|
||||
cmd.s_data.frag = 1;
|
||||
}
|
||||
memcpy(data, mbox->mbox_data.recv_data, tmp_len);
|
||||
*size = tmp_len;
|
||||
mbox->mbox_data.data_index = 0;
|
||||
memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE);
|
||||
mutex_unlock(&mbox->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu)
|
||||
{
|
||||
int frame_size = mtu + ETH_HLEN + ETH_FCS_LEN;
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret = 0;
|
||||
|
||||
if (mtu < ETH_MIN_MTU || frame_size > ETH_MAX_MTU) {
|
||||
dev_err(&oct->pdev->dev,
|
||||
"Failed to set MTU to %d MIN MTU:%d MAX MTU:%d\n",
|
||||
mtu, ETH_MIN_MTU, ETH_MAX_MTU);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_set_mtu.opcode = OCTEP_PFVF_MBOX_CMD_SET_MTU;
|
||||
cmd.s_set_mtu.mtu = mtu;
|
||||
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Mbox send failed; err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_set_mtu.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Received Mbox NACK from PF for MTU:%d\n", mtu);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int i, ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR;
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
cmd.s_set_mac.mac_addr[i] = mac_addr[i];
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Mbox send failed; err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int i, ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "get_mac: mbox send failed; err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "get_mac: received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
mac_addr[i] = rsp.s_set_mac.mac_addr[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_link_state.opcode = OCTEP_PFVF_MBOX_CMD_SET_RX_STATE;
|
||||
cmd.s_link_state.state = state;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Set Rx state via VF Mbox send failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Set Rx state received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS;
|
||||
cmd.s_link_status.status = status;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Set link status via VF Mbox send failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Set link status received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Get link status received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
*oper_up = rsp.s_link_status.status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_dev_remove(struct octep_vf_device *oct)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s.opcode = OCTEP_PFVF_MBOX_CMD_DEV_REMOVE;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_fw_info.opcode = OCTEP_PFVF_MBOX_CMD_GET_FW_INFO;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_fw_info.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Get link status received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
oct->fw_info.pkind = rsp.s_fw_info.pkind;
|
||||
oct->fw_info.fsz = rsp.s_fw_info.fsz;
|
||||
oct->fw_info.rx_ol_flags = rsp.s_fw_info.rx_ol_flags;
|
||||
oct->fw_info.tx_ol_flags = rsp.s_fw_info.tx_ol_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads,
|
||||
u16 rx_offloads)
|
||||
{
|
||||
union octep_pfvf_mbox_word cmd;
|
||||
union octep_pfvf_mbox_word rsp;
|
||||
int ret;
|
||||
|
||||
cmd.u64 = 0;
|
||||
cmd.s_offloads.opcode = OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS;
|
||||
cmd.s_offloads.rx_ol_flags = rx_offloads;
|
||||
cmd.s_offloads.tx_ol_flags = tx_offloads;
|
||||
ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
|
||||
if (ret) {
|
||||
dev_err(&oct->pdev->dev, "Set offloads via VF Mbox send failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
|
||||
dev_err(&oct->pdev->dev, "Set offloads received NACK\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
#ifndef _OCTEP_VF_MBOX_H_
|
||||
#define _OCTEP_VF_MBOX_H_
|
||||
|
||||
/* When a new command is implemented, VF Mbox version should be bumped.
|
||||
*/
|
||||
enum octep_pfvf_mbox_version {
|
||||
OCTEP_PFVF_MBOX_VERSION_V0,
|
||||
OCTEP_PFVF_MBOX_VERSION_V1,
|
||||
OCTEP_PFVF_MBOX_VERSION_V2
|
||||
};
|
||||
|
||||
#define OCTEP_PFVF_MBOX_VERSION_CURRENT OCTEP_PFVF_MBOX_VERSION_V2
|
||||
|
||||
enum octep_pfvf_mbox_opcode {
|
||||
OCTEP_PFVF_MBOX_CMD_VERSION,
|
||||
OCTEP_PFVF_MBOX_CMD_SET_MTU,
|
||||
OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_STATS,
|
||||
OCTEP_PFVF_MBOX_CMD_SET_RX_STATE,
|
||||
OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_MTU,
|
||||
OCTEP_PFVF_MBOX_CMD_DEV_REMOVE,
|
||||
OCTEP_PFVF_MBOX_CMD_GET_FW_INFO,
|
||||
OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS,
|
||||
OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS,
|
||||
OCTEP_PFVF_MBOX_CMD_MAX,
|
||||
};
|
||||
|
||||
enum octep_pfvf_mbox_word_type {
|
||||
OCTEP_PFVF_MBOX_TYPE_CMD,
|
||||
OCTEP_PFVF_MBOX_TYPE_RSP_ACK,
|
||||
OCTEP_PFVF_MBOX_TYPE_RSP_NACK,
|
||||
};
|
||||
|
||||
enum octep_pfvf_mbox_cmd_status {
|
||||
OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP = 1,
|
||||
OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT = 2,
|
||||
OCTEP_PFVF_MBOX_CMD_STATUS_NACK = 3,
|
||||
OCTEP_PFVF_MBOX_CMD_STATUS_BUSY = 4,
|
||||
OCTEP_PFVF_MBOX_CMD_STATUS_ERR = 5
|
||||
};
|
||||
|
||||
enum octep_pfvf_link_status {
|
||||
OCTEP_PFVF_LINK_STATUS_DOWN,
|
||||
OCTEP_PFVF_LINK_STATUS_UP,
|
||||
};
|
||||
|
||||
enum octep_pfvf_link_speed {
|
||||
OCTEP_PFVF_LINK_SPEED_NONE,
|
||||
OCTEP_PFVF_LINK_SPEED_1000,
|
||||
OCTEP_PFVF_LINK_SPEED_10000,
|
||||
OCTEP_PFVF_LINK_SPEED_25000,
|
||||
OCTEP_PFVF_LINK_SPEED_40000,
|
||||
OCTEP_PFVF_LINK_SPEED_50000,
|
||||
OCTEP_PFVF_LINK_SPEED_100000,
|
||||
OCTEP_PFVF_LINK_SPEED_LAST,
|
||||
};
|
||||
|
||||
enum octep_pfvf_link_duplex {
|
||||
OCTEP_PFVF_LINK_HALF_DUPLEX,
|
||||
OCTEP_PFVF_LINK_FULL_DUPLEX,
|
||||
};
|
||||
|
||||
enum octep_pfvf_link_autoneg {
|
||||
OCTEP_PFVF_LINK_AUTONEG,
|
||||
OCTEP_PFVF_LINK_FIXED,
|
||||
};
|
||||
|
||||
#define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT 8000
|
||||
#define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_UDELAY 1000
|
||||
#define OCTEP_PFVF_MBOX_MAX_RETRIES 2
|
||||
#define OCTEP_PFVF_MBOX_VERSION 0
|
||||
#define OCTEP_PFVF_MBOX_MAX_DATA_SIZE 6
|
||||
#define OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE 320
|
||||
#define OCTEP_PFVF_MBOX_MORE_FRAG_FLAG 1
|
||||
|
||||
union octep_pfvf_mbox_word {
|
||||
u64 u64;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 rsvd:6;
|
||||
u64 data:48;
|
||||
} s;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 frag:1;
|
||||
u64 rsvd:5;
|
||||
u8 data[6];
|
||||
} s_data;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 rsvd:6;
|
||||
u64 version:48;
|
||||
} s_version;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 rsvd:6;
|
||||
u8 mac_addr[6];
|
||||
} s_set_mac;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 rsvd:6;
|
||||
u64 mtu:48;
|
||||
} s_set_mtu;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 state:1;
|
||||
u64 rsvd:53;
|
||||
} s_link_state;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 status:1;
|
||||
u64 rsvd:53;
|
||||
} s_link_status;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 pkind:8;
|
||||
u64 fsz:8;
|
||||
u64 rx_ol_flags:16;
|
||||
u64 tx_ol_flags:16;
|
||||
u64 rsvd:6;
|
||||
} s_fw_info;
|
||||
struct {
|
||||
u64 opcode:8;
|
||||
u64 type:2;
|
||||
u64 rsvd:22;
|
||||
u64 rx_ol_flags:16;
|
||||
u64 tx_ol_flags:16;
|
||||
} s_offloads;
|
||||
} __packed;
|
||||
|
||||
int octep_vf_setup_mbox(struct octep_vf_device *oct);
|
||||
void octep_vf_delete_mbox(struct octep_vf_device *oct);
|
||||
int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd,
|
||||
union octep_pfvf_mbox_word *rsp);
|
||||
int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode,
|
||||
u8 *data, int *size);
|
||||
int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu);
|
||||
int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr);
|
||||
int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr);
|
||||
int octep_vf_mbox_version_check(struct octep_vf_device *oct);
|
||||
int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state);
|
||||
int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status);
|
||||
int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up);
|
||||
int octep_vf_mbox_dev_remove(struct octep_vf_device *oct);
|
||||
int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct);
|
||||
int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, u16 rx_offloads);
|
||||
|
||||
#endif
|
@ -1,154 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
#ifndef _OCTEP_VF_REGS_CN9K_H_
|
||||
#define _OCTEP_VF_REGS_CN9K_H_
|
||||
|
||||
/*############################ RST #########################*/
|
||||
#define CN93_VF_CONFIG_XPANSION_BAR 0x38
|
||||
#define CN93_VF_CONFIG_PCIE_CAP 0x70
|
||||
#define CN93_VF_CONFIG_PCIE_DEVCAP 0x74
|
||||
#define CN93_VF_CONFIG_PCIE_DEVCTL 0x78
|
||||
#define CN93_VF_CONFIG_PCIE_LINKCAP 0x7C
|
||||
#define CN93_VF_CONFIG_PCIE_LINKCTL 0x80
|
||||
#define CN93_VF_CONFIG_PCIE_SLOTCAP 0x84
|
||||
#define CN93_VF_CONFIG_PCIE_SLOTCTL 0x88
|
||||
|
||||
#define CN93_VF_RING_OFFSET BIT_ULL(17)
|
||||
|
||||
/*###################### RING IN REGISTERS #########################*/
|
||||
#define CN93_VF_SDP_R_IN_CONTROL_START 0x10000
|
||||
#define CN93_VF_SDP_R_IN_ENABLE_START 0x10010
|
||||
#define CN93_VF_SDP_R_IN_INSTR_BADDR_START 0x10020
|
||||
#define CN93_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030
|
||||
#define CN93_VF_SDP_R_IN_INSTR_DBELL_START 0x10040
|
||||
#define CN93_VF_SDP_R_IN_CNTS_START 0x10050
|
||||
#define CN93_VF_SDP_R_IN_INT_LEVELS_START 0x10060
|
||||
#define CN93_VF_SDP_R_IN_PKT_CNT_START 0x10080
|
||||
#define CN93_VF_SDP_R_IN_BYTE_CNT_START 0x10090
|
||||
|
||||
#define CN93_VF_SDP_R_IN_CONTROL(ring) \
|
||||
(CN93_VF_SDP_R_IN_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_ENABLE(ring) \
|
||||
(CN93_VF_SDP_R_IN_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_INSTR_BADDR(ring) \
|
||||
(CN93_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_INSTR_RSIZE(ring) \
|
||||
(CN93_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_INSTR_DBELL(ring) \
|
||||
(CN93_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_CNTS(ring) \
|
||||
(CN93_VF_SDP_R_IN_CNTS_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_INT_LEVELS(ring) \
|
||||
(CN93_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_PKT_CNT(ring) \
|
||||
(CN93_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_IN_BYTE_CNT(ring) \
|
||||
(CN93_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
/*------------------ R_IN Masks ----------------*/
|
||||
|
||||
/** Rings per Virtual Function **/
|
||||
#define CN93_VF_R_IN_CTL_RPVF_MASK (0xF)
|
||||
#define CN93_VF_R_IN_CTL_RPVF_POS (48)
|
||||
|
||||
/* Number of instructions to be read in one MAC read request.
|
||||
* setting to Max value(4)
|
||||
**/
|
||||
#define CN93_VF_R_IN_CTL_IDLE BIT_ULL(28)
|
||||
#define CN93_VF_R_IN_CTL_RDSIZE (0x3ULL << 25)
|
||||
#define CN93_VF_R_IN_CTL_IS_64B BIT_ULL(24)
|
||||
#define CN93_VF_R_IN_CTL_D_NSR BIT_ULL(8)
|
||||
#define CN93_VF_R_IN_CTL_D_ESR BIT_ULL(6)
|
||||
#define CN93_VF_R_IN_CTL_D_ROR BIT_ULL(5)
|
||||
#define CN93_VF_R_IN_CTL_NSR BIT_ULL(3)
|
||||
#define CN93_VF_R_IN_CTL_ESR BIT_ULL(1)
|
||||
#define CN93_VF_R_IN_CTL_ROR BIT_ULL(0)
|
||||
|
||||
#define CN93_VF_R_IN_CTL_MASK (CN93_VF_R_IN_CTL_RDSIZE | CN93_VF_R_IN_CTL_IS_64B)
|
||||
|
||||
/*###################### RING OUT REGISTERS #########################*/
|
||||
#define CN93_VF_SDP_R_OUT_CNTS_START 0x10100
|
||||
#define CN93_VF_SDP_R_OUT_INT_LEVELS_START 0x10110
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140
|
||||
#define CN93_VF_SDP_R_OUT_CONTROL_START 0x10150
|
||||
#define CN93_VF_SDP_R_OUT_ENABLE_START 0x10160
|
||||
#define CN93_VF_SDP_R_OUT_PKT_CNT_START 0x10180
|
||||
#define CN93_VF_SDP_R_OUT_BYTE_CNT_START 0x10190
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_CONTROL(ring) \
|
||||
(CN93_VF_SDP_R_OUT_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_ENABLE(ring) \
|
||||
(CN93_VF_SDP_R_OUT_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_BADDR(ring) \
|
||||
(CN93_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_RSIZE(ring) \
|
||||
(CN93_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_SLIST_DBELL(ring) \
|
||||
(CN93_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_CNTS(ring) \
|
||||
(CN93_VF_SDP_R_OUT_CNTS_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_INT_LEVELS(ring) \
|
||||
(CN93_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_PKT_CNT(ring) \
|
||||
(CN93_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_OUT_BYTE_CNT(ring) \
|
||||
(CN93_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
/*------------------ R_OUT Masks ----------------*/
|
||||
#define CN93_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63)
|
||||
#define CN93_VF_R_OUT_INT_LEVELS_TIMET (32)
|
||||
|
||||
#define CN93_VF_R_OUT_CTL_IDLE BIT_ULL(40)
|
||||
#define CN93_VF_R_OUT_CTL_ES_I BIT_ULL(34)
|
||||
#define CN93_VF_R_OUT_CTL_NSR_I BIT_ULL(33)
|
||||
#define CN93_VF_R_OUT_CTL_ROR_I BIT_ULL(32)
|
||||
#define CN93_VF_R_OUT_CTL_ES_D BIT_ULL(30)
|
||||
#define CN93_VF_R_OUT_CTL_NSR_D BIT_ULL(29)
|
||||
#define CN93_VF_R_OUT_CTL_ROR_D BIT_ULL(28)
|
||||
#define CN93_VF_R_OUT_CTL_ES_P BIT_ULL(26)
|
||||
#define CN93_VF_R_OUT_CTL_NSR_P BIT_ULL(25)
|
||||
#define CN93_VF_R_OUT_CTL_ROR_P BIT_ULL(24)
|
||||
#define CN93_VF_R_OUT_CTL_IMODE BIT_ULL(23)
|
||||
|
||||
/* ##################### Mail Box Registers ########################## */
|
||||
/* SDP PF to VF Mailbox Data Register */
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210
|
||||
/* SDP Packet PF to VF Mailbox Interrupt Register */
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220
|
||||
/* SDP VF to PF Mailbox Data Register */
|
||||
#define CN93_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230
|
||||
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1)
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0)
|
||||
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_DATA(ring) \
|
||||
(CN93_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_MBOX_PF_VF_INT(ring) \
|
||||
(CN93_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
|
||||
#define CN93_VF_SDP_R_MBOX_VF_PF_DATA(ring) \
|
||||
(CN93_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CN93_VF_RING_OFFSET))
|
||||
#endif /* _OCTEP_VF_REGS_CN9K_H_ */
|
@ -1,162 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
#ifndef _OCTEP_VF_REGS_CNXK_H_
|
||||
#define _OCTEP_VF_REGS_CNXK_H_
|
||||
|
||||
/*############################ RST #########################*/
|
||||
#define CNXK_VF_CONFIG_XPANSION_BAR 0x38
|
||||
#define CNXK_VF_CONFIG_PCIE_CAP 0x70
|
||||
#define CNXK_VF_CONFIG_PCIE_DEVCAP 0x74
|
||||
#define CNXK_VF_CONFIG_PCIE_DEVCTL 0x78
|
||||
#define CNXK_VF_CONFIG_PCIE_LINKCAP 0x7C
|
||||
#define CNXK_VF_CONFIG_PCIE_LINKCTL 0x80
|
||||
#define CNXK_VF_CONFIG_PCIE_SLOTCAP 0x84
|
||||
#define CNXK_VF_CONFIG_PCIE_SLOTCTL 0x88
|
||||
|
||||
#define CNXK_VF_RING_OFFSET (0x1ULL << 17)
|
||||
|
||||
/*###################### RING IN REGISTERS #########################*/
|
||||
#define CNXK_VF_SDP_R_IN_CONTROL_START 0x10000
|
||||
#define CNXK_VF_SDP_R_IN_ENABLE_START 0x10010
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_BADDR_START 0x10020
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_DBELL_START 0x10040
|
||||
#define CNXK_VF_SDP_R_IN_CNTS_START 0x10050
|
||||
#define CNXK_VF_SDP_R_IN_INT_LEVELS_START 0x10060
|
||||
#define CNXK_VF_SDP_R_IN_PKT_CNT_START 0x10080
|
||||
#define CNXK_VF_SDP_R_IN_BYTE_CNT_START 0x10090
|
||||
#define CNXK_VF_SDP_R_ERR_TYPE_START 0x10400
|
||||
|
||||
#define CNXK_VF_SDP_R_ERR_TYPE(ring) \
|
||||
(CNXK_VF_SDP_R_ERR_TYPE_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_CONTROL(ring) \
|
||||
(CNXK_VF_SDP_R_IN_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_ENABLE(ring) \
|
||||
(CNXK_VF_SDP_R_IN_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_BADDR(ring) \
|
||||
(CNXK_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_RSIZE(ring) \
|
||||
(CNXK_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_INSTR_DBELL(ring) \
|
||||
(CNXK_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_CNTS(ring) \
|
||||
(CNXK_VF_SDP_R_IN_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_INT_LEVELS(ring) \
|
||||
(CNXK_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_PKT_CNT(ring) \
|
||||
(CNXK_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_IN_BYTE_CNT(ring) \
|
||||
(CNXK_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
/*------------------ R_IN Masks ----------------*/
|
||||
|
||||
/** Rings per Virtual Function **/
|
||||
#define CNXK_VF_R_IN_CTL_RPVF_MASK (0xF)
|
||||
#define CNXK_VF_R_IN_CTL_RPVF_POS (48)
|
||||
|
||||
/* Number of instructions to be read in one MAC read request.
|
||||
* setting to Max value(4)
|
||||
**/
|
||||
#define CNXK_VF_R_IN_CTL_IDLE (0x1ULL << 28)
|
||||
#define CNXK_VF_R_IN_CTL_RDSIZE (0x3ULL << 25)
|
||||
#define CNXK_VF_R_IN_CTL_IS_64B (0x1ULL << 24)
|
||||
#define CNXK_VF_R_IN_CTL_D_NSR (0x1ULL << 8)
|
||||
#define CNXK_VF_R_IN_CTL_D_ESR (0x1ULL << 6)
|
||||
#define CNXK_VF_R_IN_CTL_D_ROR (0x1ULL << 5)
|
||||
#define CNXK_VF_R_IN_CTL_NSR (0x1ULL << 3)
|
||||
#define CNXK_VF_R_IN_CTL_ESR (0x1ULL << 1)
|
||||
#define CNXK_VF_R_IN_CTL_ROR (0x1ULL << 0)
|
||||
|
||||
#define CNXK_VF_R_IN_CTL_MASK (CNXK_VF_R_IN_CTL_RDSIZE | CNXK_VF_R_IN_CTL_IS_64B)
|
||||
|
||||
/*###################### RING OUT REGISTERS #########################*/
|
||||
#define CNXK_VF_SDP_R_OUT_CNTS_START 0x10100
|
||||
#define CNXK_VF_SDP_R_OUT_INT_LEVELS_START 0x10110
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140
|
||||
#define CNXK_VF_SDP_R_OUT_CONTROL_START 0x10150
|
||||
#define CNXK_VF_SDP_R_OUT_WMARK_START 0x10160
|
||||
#define CNXK_VF_SDP_R_OUT_ENABLE_START 0x10170
|
||||
#define CNXK_VF_SDP_R_OUT_PKT_CNT_START 0x10180
|
||||
#define CNXK_VF_SDP_R_OUT_BYTE_CNT_START 0x10190
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_CONTROL(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_ENABLE(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_BADDR(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_RSIZE(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_SLIST_DBELL(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_WMARK(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_WMARK_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_CNTS(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_INT_LEVELS(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_PKT_CNT(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_OUT_BYTE_CNT(ring) \
|
||||
(CNXK_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
/*------------------ R_OUT Masks ----------------*/
|
||||
#define CNXK_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63)
|
||||
#define CNXK_VF_R_OUT_INT_LEVELS_TIMET (32)
|
||||
|
||||
#define CNXK_VF_R_OUT_CTL_IDLE BIT_ULL(40)
|
||||
#define CNXK_VF_R_OUT_CTL_ES_I BIT_ULL(34)
|
||||
#define CNXK_VF_R_OUT_CTL_NSR_I BIT_ULL(33)
|
||||
#define CNXK_VF_R_OUT_CTL_ROR_I BIT_ULL(32)
|
||||
#define CNXK_VF_R_OUT_CTL_ES_D BIT_ULL(30)
|
||||
#define CNXK_VF_R_OUT_CTL_NSR_D BIT_ULL(29)
|
||||
#define CNXK_VF_R_OUT_CTL_ROR_D BIT_ULL(28)
|
||||
#define CNXK_VF_R_OUT_CTL_ES_P BIT_ULL(26)
|
||||
#define CNXK_VF_R_OUT_CTL_NSR_P BIT_ULL(25)
|
||||
#define CNXK_VF_R_OUT_CTL_ROR_P BIT_ULL(24)
|
||||
#define CNXK_VF_R_OUT_CTL_IMODE BIT_ULL(23)
|
||||
|
||||
/* ##################### Mail Box Registers ########################## */
|
||||
/* SDP PF to VF Mailbox Data Register */
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210
|
||||
/* SDP Packet PF to VF Mailbox Interrupt Register */
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220
|
||||
/* SDP VF to PF Mailbox Data Register */
|
||||
#define CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230
|
||||
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1)
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0)
|
||||
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_DATA(ring) \
|
||||
(CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_MBOX_PF_VF_INT(ring) \
|
||||
(CNXK_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
|
||||
#define CNXK_VF_SDP_R_MBOX_VF_PF_DATA(ring) \
|
||||
(CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET))
|
||||
#endif /* _OCTEP_VF_REGS_CNXK_H_ */
|
@ -1,511 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
|
||||
static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq)
|
||||
{
|
||||
oq->host_read_idx = 0;
|
||||
oq->host_refill_idx = 0;
|
||||
oq->refill_count = 0;
|
||||
oq->last_pkt_count = 0;
|
||||
oq->pkts_pending = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_fill_ring_buffers() - fill initial receive buffers for Rx ring.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*
|
||||
* Return: 0, if successfully filled receive buffers for all descriptors.
|
||||
* -1, if failed to allocate a buffer or failed to map for DMA.
|
||||
*/
|
||||
static int octep_vf_oq_fill_ring_buffers(struct octep_vf_oq *oq)
|
||||
{
|
||||
struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring;
|
||||
struct page *page;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < oq->max_count; i++) {
|
||||
page = dev_alloc_page();
|
||||
if (unlikely(!page)) {
|
||||
dev_err(oq->dev, "Rx buffer alloc failed\n");
|
||||
goto rx_buf_alloc_err;
|
||||
}
|
||||
desc_ring[i].buffer_ptr = dma_map_page(oq->dev, page, 0,
|
||||
PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(oq->dev, desc_ring[i].buffer_ptr)) {
|
||||
dev_err(oq->dev,
|
||||
"OQ-%d buffer alloc: DMA mapping error!\n",
|
||||
oq->q_no);
|
||||
put_page(page);
|
||||
goto dma_map_err;
|
||||
}
|
||||
oq->buff_info[i].page = page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dma_map_err:
|
||||
rx_buf_alloc_err:
|
||||
while (i) {
|
||||
i--;
|
||||
dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
put_page(oq->buff_info[i].page);
|
||||
oq->buff_info[i].page = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_refill() - refill buffers for used Rx ring descriptors.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*
|
||||
* Return: number of descriptors successfully refilled with receive buffers.
|
||||
*/
|
||||
static int octep_vf_oq_refill(struct octep_vf_device *oct, struct octep_vf_oq *oq)
|
||||
{
|
||||
struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring;
|
||||
struct page *page;
|
||||
u32 refill_idx, i;
|
||||
|
||||
refill_idx = oq->host_refill_idx;
|
||||
for (i = 0; i < oq->refill_count; i++) {
|
||||
page = dev_alloc_page();
|
||||
if (unlikely(!page)) {
|
||||
dev_err(oq->dev, "refill: rx buffer alloc failed\n");
|
||||
oq->stats.alloc_failures++;
|
||||
break;
|
||||
}
|
||||
|
||||
desc_ring[refill_idx].buffer_ptr = dma_map_page(oq->dev, page, 0,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(oq->dev, desc_ring[refill_idx].buffer_ptr)) {
|
||||
dev_err(oq->dev,
|
||||
"OQ-%d buffer refill: DMA mapping error!\n",
|
||||
oq->q_no);
|
||||
put_page(page);
|
||||
oq->stats.alloc_failures++;
|
||||
break;
|
||||
}
|
||||
oq->buff_info[refill_idx].page = page;
|
||||
refill_idx++;
|
||||
if (refill_idx == oq->max_count)
|
||||
refill_idx = 0;
|
||||
}
|
||||
oq->host_refill_idx = refill_idx;
|
||||
oq->refill_count -= i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_setup_oq() - Setup a Rx queue.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
* @q_no: Rx queue number to be setup.
|
||||
*
|
||||
* Allocate resources for a Rx queue.
|
||||
*/
|
||||
static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
struct octep_vf_oq *oq;
|
||||
u32 desc_ring_size;
|
||||
|
||||
oq = vzalloc(sizeof(*oq));
|
||||
if (!oq)
|
||||
goto create_oq_fail;
|
||||
oct->oq[q_no] = oq;
|
||||
|
||||
oq->octep_vf_dev = oct;
|
||||
oq->netdev = oct->netdev;
|
||||
oq->dev = &oct->pdev->dev;
|
||||
oq->q_no = q_no;
|
||||
oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf);
|
||||
oq->ring_size_mask = oq->max_count - 1;
|
||||
oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf);
|
||||
oq->max_single_buffer_size = oq->buffer_size - OCTEP_VF_OQ_RESP_HW_SIZE;
|
||||
|
||||
/* When the hardware/firmware supports additional capabilities,
|
||||
* additional header is filled-in by Octeon after length field in
|
||||
* Rx packets. this header contains additional packet information.
|
||||
*/
|
||||
if (oct->fw_info.rx_ol_flags)
|
||||
oq->max_single_buffer_size -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE;
|
||||
|
||||
oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf);
|
||||
|
||||
desc_ring_size = oq->max_count * OCTEP_VF_OQ_DESC_SIZE;
|
||||
oq->desc_ring = dma_alloc_coherent(oq->dev, desc_ring_size,
|
||||
&oq->desc_ring_dma, GFP_KERNEL);
|
||||
|
||||
if (unlikely(!oq->desc_ring)) {
|
||||
dev_err(oq->dev,
|
||||
"Failed to allocate DMA memory for OQ-%d !!\n", q_no);
|
||||
goto desc_dma_alloc_err;
|
||||
}
|
||||
|
||||
oq->buff_info = vzalloc(oq->max_count * OCTEP_VF_OQ_RECVBUF_SIZE);
|
||||
|
||||
if (unlikely(!oq->buff_info)) {
|
||||
dev_err(&oct->pdev->dev,
|
||||
"Failed to allocate buffer info for OQ-%d\n", q_no);
|
||||
goto buf_list_err;
|
||||
}
|
||||
|
||||
if (octep_vf_oq_fill_ring_buffers(oq))
|
||||
goto oq_fill_buff_err;
|
||||
|
||||
octep_vf_oq_reset_indices(oq);
|
||||
oct->hw_ops.setup_oq_regs(oct, q_no);
|
||||
oct->num_oqs++;
|
||||
|
||||
return 0;
|
||||
|
||||
oq_fill_buff_err:
|
||||
vfree(oq->buff_info);
|
||||
oq->buff_info = NULL;
|
||||
buf_list_err:
|
||||
dma_free_coherent(oq->dev, desc_ring_size,
|
||||
oq->desc_ring, oq->desc_ring_dma);
|
||||
oq->desc_ring = NULL;
|
||||
desc_dma_alloc_err:
|
||||
vfree(oq);
|
||||
oct->oq[q_no] = NULL;
|
||||
create_oq_fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_free_ring_buffers() - Free ring buffers.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*
|
||||
* Free receive buffers in unused Rx queue descriptors.
|
||||
*/
|
||||
static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq)
|
||||
{
|
||||
struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring;
|
||||
int i;
|
||||
|
||||
if (!oq->desc_ring || !oq->buff_info)
|
||||
return;
|
||||
|
||||
for (i = 0; i < oq->max_count; i++) {
|
||||
if (oq->buff_info[i].page) {
|
||||
dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
put_page(oq->buff_info[i].page);
|
||||
oq->buff_info[i].page = NULL;
|
||||
desc_ring[i].buffer_ptr = 0;
|
||||
}
|
||||
}
|
||||
octep_vf_oq_reset_indices(oq);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_free_oq() - Free Rx queue resources.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*
|
||||
* Free all resources of a Rx queue.
|
||||
*/
|
||||
static int octep_vf_free_oq(struct octep_vf_oq *oq)
|
||||
{
|
||||
struct octep_vf_device *oct = oq->octep_vf_dev;
|
||||
int q_no = oq->q_no;
|
||||
|
||||
octep_vf_oq_free_ring_buffers(oq);
|
||||
|
||||
if (oq->buff_info)
|
||||
vfree(oq->buff_info);
|
||||
|
||||
if (oq->desc_ring)
|
||||
dma_free_coherent(oq->dev,
|
||||
oq->max_count * OCTEP_VF_OQ_DESC_SIZE,
|
||||
oq->desc_ring, oq->desc_ring_dma);
|
||||
|
||||
vfree(oq);
|
||||
oct->oq[q_no] = NULL;
|
||||
oct->num_oqs--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_setup_oqs() - setup resources for all Rx queues.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*/
|
||||
int octep_vf_setup_oqs(struct octep_vf_device *oct)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
oct->num_oqs = 0;
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
||||
retval = octep_vf_setup_oq(oct, i);
|
||||
if (retval) {
|
||||
dev_err(&oct->pdev->dev,
|
||||
"Failed to setup OQ(RxQ)-%d.\n", i);
|
||||
goto oq_setup_err;
|
||||
}
|
||||
dev_dbg(&oct->pdev->dev, "Successfully setup OQ(RxQ)-%d.\n", i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oq_setup_err:
|
||||
while (i) {
|
||||
i--;
|
||||
octep_vf_free_oq(oct->oq[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_dbell_init() - Initialize Rx queue doorbell.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*
|
||||
* Write number of descriptors to Rx queue doorbell register.
|
||||
*/
|
||||
void octep_vf_oq_dbell_init(struct octep_vf_device *oct)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oct->num_oqs; i++)
|
||||
writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_free_oqs() - Free resources of all Rx queues.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*/
|
||||
void octep_vf_free_oqs(struct octep_vf_device *oct)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
||||
if (!oct->oq[i])
|
||||
continue;
|
||||
octep_vf_free_oq(oct->oq[i]);
|
||||
dev_dbg(&oct->pdev->dev,
|
||||
"Successfully freed OQ(RxQ)-%d.\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_check_hw_for_pkts() - Check for new Rx packets.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*
|
||||
* Return: packets received after previous check.
|
||||
*/
|
||||
static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
|
||||
struct octep_vf_oq *oq)
|
||||
{
|
||||
u32 pkt_count, new_pkts;
|
||||
|
||||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts = pkt_count - oq->last_pkt_count;
|
||||
|
||||
/* Clear the hardware packets counter register if the rx queue is
|
||||
* being processed continuously with-in a single interrupt and
|
||||
* reached half its max value.
|
||||
* this counter is not cleared every time read, to save write cycles.
|
||||
*/
|
||||
if (unlikely(pkt_count > 0xF0000000U)) {
|
||||
writel(pkt_count, oq->pkts_sent_reg);
|
||||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts += pkt_count;
|
||||
}
|
||||
oq->last_pkt_count = pkt_count;
|
||||
oq->pkts_pending += new_pkts;
|
||||
return new_pkts;
|
||||
}
|
||||
|
||||
/**
|
||||
* __octep_vf_oq_process_rx() - Process hardware Rx queue and push to stack.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
* @pkts_to_process: number of packets to be processed.
|
||||
*
|
||||
* Process the new packets in Rx queue.
|
||||
* Packets larger than single Rx buffer arrive in consecutive descriptors.
|
||||
* But, count returned by the API only accounts full packets, not fragments.
|
||||
*
|
||||
* Return: number of packets processed and pushed to stack.
|
||||
*/
|
||||
static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
|
||||
struct octep_vf_oq *oq, u16 pkts_to_process)
|
||||
{
|
||||
struct octep_vf_oq_resp_hw_ext *resp_hw_ext = NULL;
|
||||
netdev_features_t feat = oq->netdev->features;
|
||||
struct octep_vf_rx_buffer *buff_info;
|
||||
struct octep_vf_oq_resp_hw *resp_hw;
|
||||
u32 pkt, rx_bytes, desc_used;
|
||||
u16 data_offset, rx_ol_flags;
|
||||
struct sk_buff *skb;
|
||||
u32 read_idx;
|
||||
|
||||
read_idx = oq->host_read_idx;
|
||||
rx_bytes = 0;
|
||||
desc_used = 0;
|
||||
for (pkt = 0; pkt < pkts_to_process; pkt++) {
|
||||
buff_info = (struct octep_vf_rx_buffer *)&oq->buff_info[read_idx];
|
||||
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
resp_hw = page_address(buff_info->page);
|
||||
buff_info->page = NULL;
|
||||
|
||||
/* Swap the length field that is in Big-Endian to CPU */
|
||||
buff_info->len = be64_to_cpu(resp_hw->length);
|
||||
if (oct->fw_info.rx_ol_flags) {
|
||||
/* Extended response header is immediately after
|
||||
* response header (resp_hw)
|
||||
*/
|
||||
resp_hw_ext = (struct octep_vf_oq_resp_hw_ext *)
|
||||
(resp_hw + 1);
|
||||
buff_info->len -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE;
|
||||
/* Packet Data is immediately after
|
||||
* extended response header.
|
||||
*/
|
||||
data_offset = OCTEP_VF_OQ_RESP_HW_SIZE +
|
||||
OCTEP_VF_OQ_RESP_HW_EXT_SIZE;
|
||||
rx_ol_flags = resp_hw_ext->rx_ol_flags;
|
||||
} else {
|
||||
/* Data is immediately after
|
||||
* Hardware Rx response header.
|
||||
*/
|
||||
data_offset = OCTEP_VF_OQ_RESP_HW_SIZE;
|
||||
rx_ol_flags = 0;
|
||||
}
|
||||
rx_bytes += buff_info->len;
|
||||
|
||||
if (buff_info->len <= oq->max_single_buffer_size) {
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
skb_reserve(skb, data_offset);
|
||||
skb_put(skb, buff_info->len);
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
} else {
|
||||
struct skb_shared_info *shinfo;
|
||||
u16 data_len;
|
||||
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
skb_reserve(skb, data_offset);
|
||||
/* Head fragment includes response header(s);
|
||||
* subsequent fragments contains only data.
|
||||
*/
|
||||
skb_put(skb, oq->max_single_buffer_size);
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
|
||||
shinfo = skb_shinfo(skb);
|
||||
data_len = buff_info->len - oq->max_single_buffer_size;
|
||||
while (data_len) {
|
||||
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
buff_info = (struct octep_vf_rx_buffer *)
|
||||
&oq->buff_info[read_idx];
|
||||
if (data_len < oq->buffer_size) {
|
||||
buff_info->len = data_len;
|
||||
data_len = 0;
|
||||
} else {
|
||||
buff_info->len = oq->buffer_size;
|
||||
data_len -= oq->buffer_size;
|
||||
}
|
||||
|
||||
skb_add_rx_frag(skb, shinfo->nr_frags,
|
||||
buff_info->page, 0,
|
||||
buff_info->len,
|
||||
buff_info->len);
|
||||
buff_info->page = NULL;
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
skb->dev = oq->netdev;
|
||||
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||
if (feat & NETIF_F_RXCSUM &&
|
||||
OCTEP_VF_RX_CSUM_VERIFIED(rx_ol_flags))
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
else
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
napi_gro_receive(oq->napi, skb);
|
||||
}
|
||||
|
||||
oq->host_read_idx = read_idx;
|
||||
oq->refill_count += desc_used;
|
||||
oq->stats.packets += pkt;
|
||||
oq->stats.bytes += rx_bytes;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_oq_process_rx() - Process Rx queue.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
* @budget: max number of packets can be processed in one invocation.
|
||||
*
|
||||
* Check for newly received packets and process them.
|
||||
* Keeps checking for new packets until budget is used or no new packets seen.
|
||||
*
|
||||
* Return: number of packets processed.
|
||||
*/
|
||||
int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
|
||||
{
|
||||
u32 pkts_available, pkts_processed, total_pkts_processed;
|
||||
struct octep_vf_device *oct = oq->octep_vf_dev;
|
||||
|
||||
pkts_available = 0;
|
||||
pkts_processed = 0;
|
||||
total_pkts_processed = 0;
|
||||
while (total_pkts_processed < budget) {
|
||||
/* update pending count only when current one exhausted */
|
||||
if (oq->pkts_pending == 0)
|
||||
octep_vf_oq_check_hw_for_pkts(oct, oq);
|
||||
pkts_available = min(budget - total_pkts_processed,
|
||||
oq->pkts_pending);
|
||||
if (!pkts_available)
|
||||
break;
|
||||
|
||||
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
|
||||
pkts_available);
|
||||
oq->pkts_pending -= pkts_processed;
|
||||
total_pkts_processed += pkts_processed;
|
||||
}
|
||||
|
||||
if (oq->refill_count >= oq->refill_threshold) {
|
||||
u32 desc_refilled = octep_vf_oq_refill(oct, oq);
|
||||
|
||||
/* flush pending writes before updating credits */
|
||||
smp_wmb();
|
||||
writel(desc_refilled, oq->pkts_credit_reg);
|
||||
}
|
||||
|
||||
return total_pkts_processed;
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OCTEP_VF_RX_H_
|
||||
#define _OCTEP_VF_RX_H_
|
||||
|
||||
/* struct octep_vf_oq_desc_hw - Octeon Hardware OQ descriptor format.
|
||||
*
|
||||
* The descriptor ring is made of descriptors which have 2 64-bit values:
|
||||
*
|
||||
* @buffer_ptr: DMA address of the skb->data
|
||||
* @info_ptr: DMA address of host memory, used to update pkt count by hw.
|
||||
* This is currently unused to save pci writes.
|
||||
*/
|
||||
struct octep_vf_oq_desc_hw {
|
||||
dma_addr_t buffer_ptr;
|
||||
u64 info_ptr;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_oq_desc_hw) == 16);
|
||||
|
||||
#define OCTEP_VF_OQ_DESC_SIZE (sizeof(struct octep_vf_oq_desc_hw))
|
||||
|
||||
/* Rx offload flags */
|
||||
#define OCTEP_VF_RX_OFFLOAD_VLAN_STRIP BIT(0)
|
||||
#define OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM BIT(1)
|
||||
#define OCTEP_VF_RX_OFFLOAD_UDP_CKSUM BIT(2)
|
||||
#define OCTEP_VF_RX_OFFLOAD_TCP_CKSUM BIT(3)
|
||||
|
||||
#define OCTEP_VF_RX_OFFLOAD_CKSUM (OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \
|
||||
OCTEP_VF_RX_OFFLOAD_UDP_CKSUM | \
|
||||
OCTEP_VF_RX_OFFLOAD_TCP_CKSUM)
|
||||
|
||||
#define OCTEP_VF_RX_IP_CSUM(flags) ((flags) & \
|
||||
(OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \
|
||||
OCTEP_VF_RX_OFFLOAD_TCP_CKSUM | \
|
||||
OCTEP_VF_RX_OFFLOAD_UDP_CKSUM))
|
||||
|
||||
/* bit 0 is vlan strip */
|
||||
#define OCTEP_VF_RX_CSUM_IP_VERIFIED BIT(1)
|
||||
#define OCTEP_VF_RX_CSUM_L4_VERIFIED BIT(2)
|
||||
|
||||
#define OCTEP_VF_RX_CSUM_VERIFIED(flags) ((flags) & \
|
||||
(OCTEP_VF_RX_CSUM_L4_VERIFIED | \
|
||||
OCTEP_VF_RX_CSUM_IP_VERIFIED))
|
||||
|
||||
/* Extended Response Header in packet data received from Hardware.
|
||||
* Includes metadata like checksum status.
|
||||
* this is valid only if hardware/firmware published support for this.
|
||||
* This is at offset 0 of packet data (skb->data).
|
||||
*/
|
||||
struct octep_vf_oq_resp_hw_ext {
|
||||
/* Reserved. */
|
||||
u64 rsvd:48;
|
||||
|
||||
/* rx offload flags */
|
||||
u16 rx_ol_flags;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_oq_resp_hw_ext) == 8);
|
||||
|
||||
#define OCTEP_VF_OQ_RESP_HW_EXT_SIZE (sizeof(struct octep_vf_oq_resp_hw_ext))
|
||||
|
||||
/* Length of Rx packet DMA'ed by Octeon to Host.
|
||||
* this is in bigendian; so need to be converted to cpu endian.
|
||||
* Octeon writes this at the beginning of Rx buffer (skb->data).
|
||||
*/
|
||||
struct octep_vf_oq_resp_hw {
|
||||
/* The Length of the packet. */
|
||||
__be64 length;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_oq_resp_hw) == 8);
|
||||
|
||||
#define OCTEP_VF_OQ_RESP_HW_SIZE (sizeof(struct octep_vf_oq_resp_hw))
|
||||
|
||||
/* Pointer to data buffer.
|
||||
* Driver keeps a pointer to the data buffer that it made available to
|
||||
* the Octeon device. Since the descriptor ring keeps physical (bus)
|
||||
* addresses, this field is required for the driver to keep track of
|
||||
* the virtual address pointers. The fields are operated by
|
||||
* OS-dependent routines.
|
||||
*/
|
||||
struct octep_vf_rx_buffer {
|
||||
struct page *page;
|
||||
|
||||
/* length from rx hardware descriptor after converting to cpu endian */
|
||||
u64 len;
|
||||
};
|
||||
|
||||
#define OCTEP_VF_OQ_RECVBUF_SIZE (sizeof(struct octep_vf_rx_buffer))
|
||||
|
||||
/* Output Queue statistics. Each output queue has four stats fields. */
|
||||
struct octep_vf_oq_stats {
|
||||
/* Number of packets received from the Device. */
|
||||
u64 packets;
|
||||
|
||||
/* Number of bytes received from the Device. */
|
||||
u64 bytes;
|
||||
|
||||
/* Number of times failed to allocate buffers. */
|
||||
u64 alloc_failures;
|
||||
};
|
||||
|
||||
#define OCTEP_VF_OQ_STATS_SIZE (sizeof(struct octep_vf_oq_stats))
|
||||
|
||||
/* Hardware interface Rx statistics */
|
||||
struct octep_vf_iface_rx_stats {
|
||||
/* Received packets */
|
||||
u64 pkts;
|
||||
|
||||
/* Octets of received packets */
|
||||
u64 octets;
|
||||
|
||||
/* Received PAUSE and Control packets */
|
||||
u64 pause_pkts;
|
||||
|
||||
/* Received PAUSE and Control octets */
|
||||
u64 pause_octets;
|
||||
|
||||
/* Filtered DMAC0 packets */
|
||||
u64 dmac0_pkts;
|
||||
|
||||
/* Filtered DMAC0 octets */
|
||||
u64 dmac0_octets;
|
||||
|
||||
/* Packets dropped due to RX FIFO full */
|
||||
u64 dropped_pkts_fifo_full;
|
||||
|
||||
/* Octets dropped due to RX FIFO full */
|
||||
u64 dropped_octets_fifo_full;
|
||||
|
||||
/* Error packets */
|
||||
u64 err_pkts;
|
||||
|
||||
/* Filtered DMAC1 packets */
|
||||
u64 dmac1_pkts;
|
||||
|
||||
/* Filtered DMAC1 octets */
|
||||
u64 dmac1_octets;
|
||||
|
||||
/* NCSI-bound packets dropped */
|
||||
u64 ncsi_dropped_pkts;
|
||||
|
||||
/* NCSI-bound octets dropped */
|
||||
u64 ncsi_dropped_octets;
|
||||
|
||||
/* Multicast packets received. */
|
||||
u64 mcast_pkts;
|
||||
|
||||
/* Broadcast packets received. */
|
||||
u64 bcast_pkts;
|
||||
|
||||
};
|
||||
|
||||
/* The Descriptor Ring Output Queue structure.
|
||||
* This structure has all the information required to implement a
|
||||
* Octeon OQ.
|
||||
*/
|
||||
struct octep_vf_oq {
|
||||
u32 q_no;
|
||||
|
||||
struct octep_vf_device *octep_vf_dev;
|
||||
struct net_device *netdev;
|
||||
struct device *dev;
|
||||
|
||||
struct napi_struct *napi;
|
||||
|
||||
/* The receive buffer list. This list has the virtual addresses
|
||||
* of the buffers.
|
||||
*/
|
||||
struct octep_vf_rx_buffer *buff_info;
|
||||
|
||||
/* Pointer to the mapped packet credit register.
|
||||
* Host writes number of info/buffer ptrs available to this register
|
||||
*/
|
||||
u8 __iomem *pkts_credit_reg;
|
||||
|
||||
/* Pointer to the mapped packet sent register.
|
||||
* Octeon writes the number of packets DMA'ed to host memory
|
||||
* in this register.
|
||||
*/
|
||||
u8 __iomem *pkts_sent_reg;
|
||||
|
||||
/* Statistics for this OQ. */
|
||||
struct octep_vf_oq_stats stats;
|
||||
|
||||
/* Packets pending to be processed */
|
||||
u32 pkts_pending;
|
||||
u32 last_pkt_count;
|
||||
|
||||
/* Index in the ring where the driver should read the next packet */
|
||||
u32 host_read_idx;
|
||||
|
||||
/* Number of descriptors in this ring. */
|
||||
u32 max_count;
|
||||
u32 ring_size_mask;
|
||||
|
||||
/* The number of descriptors pending refill. */
|
||||
u32 refill_count;
|
||||
|
||||
/* Index in the ring where the driver will refill the
|
||||
* descriptor's buffer
|
||||
*/
|
||||
u32 host_refill_idx;
|
||||
u32 refill_threshold;
|
||||
|
||||
/* The size of each buffer pointed by the buffer pointer. */
|
||||
u32 buffer_size;
|
||||
u32 max_single_buffer_size;
|
||||
|
||||
/* The 8B aligned descriptor ring starts at this address. */
|
||||
struct octep_vf_oq_desc_hw *desc_ring;
|
||||
|
||||
/* DMA mapped address of the OQ descriptor ring. */
|
||||
dma_addr_t desc_ring_dma;
|
||||
};
|
||||
|
||||
#define OCTEP_VF_OQ_SIZE (sizeof(struct octep_vf_oq))
|
||||
#endif /* _OCTEP_VF_RX_H_ */
|
@ -1,331 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "octep_vf_config.h"
|
||||
#include "octep_vf_main.h"
|
||||
|
||||
/* Reset various index of Tx queue data structure. */
|
||||
static void octep_vf_iq_reset_indices(struct octep_vf_iq *iq)
|
||||
{
|
||||
iq->fill_cnt = 0;
|
||||
iq->host_write_index = 0;
|
||||
iq->octep_vf_read_index = 0;
|
||||
iq->flush_index = 0;
|
||||
iq->pkts_processed = 0;
|
||||
iq->pkt_in_done = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_iq_process_completions() - Process Tx queue completions.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
* @budget: max number of completions to be processed in one invocation.
|
||||
*/
|
||||
int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget)
|
||||
{
|
||||
u32 compl_pkts, compl_bytes, compl_sg;
|
||||
struct octep_vf_device *oct = iq->octep_vf_dev;
|
||||
struct octep_vf_tx_buffer *tx_buffer;
|
||||
struct skb_shared_info *shinfo;
|
||||
u32 fi = iq->flush_index;
|
||||
struct sk_buff *skb;
|
||||
u8 frags, i;
|
||||
|
||||
compl_pkts = 0;
|
||||
compl_sg = 0;
|
||||
compl_bytes = 0;
|
||||
iq->octep_vf_read_index = oct->hw_ops.update_iq_read_idx(iq);
|
||||
|
||||
while (likely(budget && (fi != iq->octep_vf_read_index))) {
|
||||
tx_buffer = iq->buff_info + fi;
|
||||
skb = tx_buffer->skb;
|
||||
|
||||
fi++;
|
||||
if (unlikely(fi == iq->max_count))
|
||||
fi = 0;
|
||||
compl_bytes += skb->len;
|
||||
compl_pkts++;
|
||||
budget--;
|
||||
|
||||
if (!tx_buffer->gather) {
|
||||
dma_unmap_single(iq->dev, tx_buffer->dma,
|
||||
tx_buffer->skb->len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Scatter/Gather */
|
||||
shinfo = skb_shinfo(skb);
|
||||
frags = shinfo->nr_frags;
|
||||
compl_sg++;
|
||||
|
||||
dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0],
|
||||
tx_buffer->sglist[0].len[3], DMA_TO_DEVICE);
|
||||
|
||||
i = 1; /* entry 0 is main skb, unmapped above */
|
||||
while (frags--) {
|
||||
dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3],
|
||||
tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE);
|
||||
i++;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
iq->pkts_processed += compl_pkts;
|
||||
iq->stats.instr_completed += compl_pkts;
|
||||
iq->stats.bytes_sent += compl_bytes;
|
||||
iq->stats.sgentry_sent += compl_sg;
|
||||
iq->flush_index = fi;
|
||||
|
||||
netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes);
|
||||
|
||||
if (unlikely(__netif_subqueue_stopped(iq->netdev, iq->q_no)) &&
|
||||
(IQ_INSTR_SPACE(iq) >
|
||||
OCTEP_VF_WAKE_QUEUE_THRESHOLD))
|
||||
netif_wake_subqueue(iq->netdev, iq->q_no);
|
||||
return !budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_iq_free_pending() - Free Tx buffers for pending completions.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
*/
|
||||
static void octep_vf_iq_free_pending(struct octep_vf_iq *iq)
|
||||
{
|
||||
struct octep_vf_tx_buffer *tx_buffer;
|
||||
struct skb_shared_info *shinfo;
|
||||
u32 fi = iq->flush_index;
|
||||
struct sk_buff *skb;
|
||||
u8 frags, i;
|
||||
|
||||
while (fi != iq->host_write_index) {
|
||||
tx_buffer = iq->buff_info + fi;
|
||||
skb = tx_buffer->skb;
|
||||
|
||||
fi++;
|
||||
if (unlikely(fi == iq->max_count))
|
||||
fi = 0;
|
||||
|
||||
if (!tx_buffer->gather) {
|
||||
dma_unmap_single(iq->dev, tx_buffer->dma,
|
||||
tx_buffer->skb->len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Scatter/Gather */
|
||||
shinfo = skb_shinfo(skb);
|
||||
frags = shinfo->nr_frags;
|
||||
|
||||
dma_unmap_single(iq->dev,
|
||||
tx_buffer->sglist[0].dma_ptr[0],
|
||||
tx_buffer->sglist[0].len[0],
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
i = 1; /* entry 0 is main skb, unmapped above */
|
||||
while (frags--) {
|
||||
dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3],
|
||||
tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE);
|
||||
i++;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
iq->flush_index = fi;
|
||||
netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no));
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_clean_iqs() - Clean Tx queues to shutdown the device.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*
|
||||
* Free the buffers in Tx queue descriptors pending completion and
|
||||
* reset queue indices
|
||||
*/
|
||||
void octep_vf_clean_iqs(struct octep_vf_device *oct)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oct->num_iqs; i++) {
|
||||
octep_vf_iq_free_pending(oct->iq[i]);
|
||||
octep_vf_iq_reset_indices(oct->iq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_setup_iq() - Setup a Tx queue.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
* @q_no: Tx queue number to be setup.
|
||||
*
|
||||
* Allocate resources for a Tx queue.
|
||||
*/
|
||||
static int octep_vf_setup_iq(struct octep_vf_device *oct, int q_no)
|
||||
{
|
||||
u32 desc_ring_size, buff_info_size, sglist_size;
|
||||
struct octep_vf_iq *iq;
|
||||
int i;
|
||||
|
||||
iq = vzalloc(sizeof(*iq));
|
||||
if (!iq)
|
||||
goto iq_alloc_err;
|
||||
oct->iq[q_no] = iq;
|
||||
|
||||
iq->octep_vf_dev = oct;
|
||||
iq->netdev = oct->netdev;
|
||||
iq->dev = &oct->pdev->dev;
|
||||
iq->q_no = q_no;
|
||||
iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
iq->ring_size_mask = iq->max_count - 1;
|
||||
iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf);
|
||||
iq->netdev_q = netdev_get_tx_queue(iq->netdev, q_no);
|
||||
|
||||
/* Allocate memory for hardware queue descriptors */
|
||||
desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
iq->desc_ring = dma_alloc_coherent(iq->dev, desc_ring_size,
|
||||
&iq->desc_ring_dma, GFP_KERNEL);
|
||||
if (unlikely(!iq->desc_ring)) {
|
||||
dev_err(iq->dev,
|
||||
"Failed to allocate DMA memory for IQ-%d\n", q_no);
|
||||
goto desc_dma_alloc_err;
|
||||
}
|
||||
|
||||
/* Allocate memory for hardware SGLIST descriptors */
|
||||
sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT *
|
||||
CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
iq->sglist = dma_alloc_coherent(iq->dev, sglist_size,
|
||||
&iq->sglist_dma, GFP_KERNEL);
|
||||
if (unlikely(!iq->sglist)) {
|
||||
dev_err(iq->dev,
|
||||
"Failed to allocate DMA memory for IQ-%d SGLIST\n",
|
||||
q_no);
|
||||
goto sglist_alloc_err;
|
||||
}
|
||||
|
||||
/* allocate memory to manage Tx packets pending completion */
|
||||
buff_info_size = OCTEP_VF_IQ_TXBUFF_INFO_SIZE * iq->max_count;
|
||||
iq->buff_info = vzalloc(buff_info_size);
|
||||
if (!iq->buff_info) {
|
||||
dev_err(iq->dev,
|
||||
"Failed to allocate buff info for IQ-%d\n", q_no);
|
||||
goto buff_info_err;
|
||||
}
|
||||
|
||||
/* Setup sglist addresses in tx_buffer entries */
|
||||
for (i = 0; i < CFG_GET_IQ_NUM_DESC(oct->conf); i++) {
|
||||
struct octep_vf_tx_buffer *tx_buffer;
|
||||
|
||||
tx_buffer = &iq->buff_info[i];
|
||||
tx_buffer->sglist =
|
||||
&iq->sglist[i * OCTEP_VF_SGLIST_ENTRIES_PER_PKT];
|
||||
tx_buffer->sglist_dma =
|
||||
iq->sglist_dma + (i * OCTEP_VF_SGLIST_SIZE_PER_PKT);
|
||||
}
|
||||
|
||||
octep_vf_iq_reset_indices(iq);
|
||||
oct->hw_ops.setup_iq_regs(oct, q_no);
|
||||
|
||||
oct->num_iqs++;
|
||||
return 0;
|
||||
|
||||
buff_info_err:
|
||||
dma_free_coherent(iq->dev, sglist_size, iq->sglist, iq->sglist_dma);
|
||||
sglist_alloc_err:
|
||||
dma_free_coherent(iq->dev, desc_ring_size,
|
||||
iq->desc_ring, iq->desc_ring_dma);
|
||||
desc_dma_alloc_err:
|
||||
vfree(iq);
|
||||
oct->iq[q_no] = NULL;
|
||||
iq_alloc_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_free_iq() - Free Tx queue resources.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
*
|
||||
* Free all the resources allocated for a Tx queue.
|
||||
*/
|
||||
static void octep_vf_free_iq(struct octep_vf_iq *iq)
|
||||
{
|
||||
struct octep_vf_device *oct = iq->octep_vf_dev;
|
||||
u64 desc_ring_size, sglist_size;
|
||||
int q_no = iq->q_no;
|
||||
|
||||
desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
|
||||
vfree(iq->buff_info);
|
||||
|
||||
if (iq->desc_ring)
|
||||
dma_free_coherent(iq->dev, desc_ring_size,
|
||||
iq->desc_ring, iq->desc_ring_dma);
|
||||
|
||||
sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT *
|
||||
CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
if (iq->sglist)
|
||||
dma_free_coherent(iq->dev, sglist_size,
|
||||
iq->sglist, iq->sglist_dma);
|
||||
|
||||
vfree(iq);
|
||||
oct->iq[q_no] = NULL;
|
||||
oct->num_iqs--;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_setup_iqs() - setup resources for all Tx queues.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*/
|
||||
int octep_vf_setup_iqs(struct octep_vf_device *oct)
|
||||
{
|
||||
int i;
|
||||
|
||||
oct->num_iqs = 0;
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
||||
if (octep_vf_setup_iq(oct, i)) {
|
||||
dev_err(&oct->pdev->dev,
|
||||
"Failed to setup IQ(TxQ)-%d.\n", i);
|
||||
goto iq_setup_err;
|
||||
}
|
||||
dev_dbg(&oct->pdev->dev, "Successfully setup IQ(TxQ)-%d.\n", i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
iq_setup_err:
|
||||
while (i) {
|
||||
i--;
|
||||
octep_vf_free_iq(oct->iq[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_free_iqs() - Free resources of all Tx queues.
|
||||
*
|
||||
* @oct: Octeon device private data structure.
|
||||
*/
|
||||
void octep_vf_free_iqs(struct octep_vf_device *oct)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
||||
octep_vf_free_iq(oct->iq[i]);
|
||||
dev_dbg(&oct->pdev->dev,
|
||||
"Successfully destroyed IQ(TxQ)-%d.\n", i);
|
||||
}
|
||||
oct->num_iqs = 0;
|
||||
}
|
@ -1,276 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
|
||||
*
|
||||
* Copyright (C) 2020 Marvell.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OCTEP_VF_TX_H_
|
||||
#define _OCTEP_VF_TX_H_
|
||||
|
||||
#define IQ_SEND_OK 0
|
||||
#define IQ_SEND_STOP 1
|
||||
#define IQ_SEND_FAILED -1
|
||||
|
||||
#define TX_BUFTYPE_NONE 0
|
||||
#define TX_BUFTYPE_NET 1
|
||||
#define TX_BUFTYPE_NET_SG 2
|
||||
#define NUM_TX_BUFTYPES 3
|
||||
|
||||
/* Hardware format for Scatter/Gather list
|
||||
*
|
||||
* 63 48|47 32|31 16|15 0
|
||||
* -----------------------------------------
|
||||
* | Len 0 | Len 1 | Len 2 | Len 3 |
|
||||
* -----------------------------------------
|
||||
* | Ptr 0 |
|
||||
* -----------------------------------------
|
||||
* | Ptr 1 |
|
||||
* -----------------------------------------
|
||||
* | Ptr 2 |
|
||||
* -----------------------------------------
|
||||
* | Ptr 3 |
|
||||
* -----------------------------------------
|
||||
*/
|
||||
struct octep_vf_tx_sglist_desc {
|
||||
u16 len[4];
|
||||
dma_addr_t dma_ptr[4];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_tx_sglist_desc) == 40);
|
||||
|
||||
/* Each Scatter/Gather entry sent to hardwar hold four pointers.
|
||||
* So, number of entries required is (MAX_SKB_FRAGS + 1)/4, where '+1'
|
||||
* is for main skb which also goes as a gather buffer to Octeon hardware.
|
||||
* To allocate sufficient SGLIST entries for a packet with max fragments,
|
||||
* align by adding 3 before calcuating max SGLIST entries per packet.
|
||||
*/
|
||||
#define OCTEP_VF_SGLIST_ENTRIES_PER_PKT ((MAX_SKB_FRAGS + 1 + 3) / 4)
|
||||
#define OCTEP_VF_SGLIST_SIZE_PER_PKT \
|
||||
(OCTEP_VF_SGLIST_ENTRIES_PER_PKT * sizeof(struct octep_vf_tx_sglist_desc))
|
||||
|
||||
struct octep_vf_tx_buffer {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma;
|
||||
struct octep_vf_tx_sglist_desc *sglist;
|
||||
dma_addr_t sglist_dma;
|
||||
u8 gather;
|
||||
};
|
||||
|
||||
#define OCTEP_VF_IQ_TXBUFF_INFO_SIZE (sizeof(struct octep_vf_tx_buffer))
|
||||
|
||||
/* VF Hardware interface Tx statistics */
|
||||
struct octep_vf_iface_tx_stats {
|
||||
/* Total frames sent on the interface */
|
||||
u64 pkts;
|
||||
|
||||
/* Total octets sent on the interface */
|
||||
u64 octs;
|
||||
|
||||
/* Packets sent to a broadcast DMAC */
|
||||
u64 bcst;
|
||||
|
||||
/* Packets sent to the multicast DMAC */
|
||||
u64 mcst;
|
||||
|
||||
/* Packets dropped */
|
||||
u64 dropped;
|
||||
|
||||
/* Reserved */
|
||||
u64 reserved[13];
|
||||
};
|
||||
|
||||
/* VF Input Queue statistics */
|
||||
struct octep_vf_iq_stats {
|
||||
/* Instructions posted to this queue. */
|
||||
u64 instr_posted;
|
||||
|
||||
/* Instructions copied by hardware for processing. */
|
||||
u64 instr_completed;
|
||||
|
||||
/* Instructions that could not be processed. */
|
||||
u64 instr_dropped;
|
||||
|
||||
/* Bytes sent through this queue. */
|
||||
u64 bytes_sent;
|
||||
|
||||
/* Gather entries sent through this queue. */
|
||||
u64 sgentry_sent;
|
||||
|
||||
/* Number of transmit failures due to TX_BUSY */
|
||||
u64 tx_busy;
|
||||
|
||||
/* Number of times the queue is restarted */
|
||||
u64 restart_cnt;
|
||||
};
|
||||
|
||||
/* The instruction (input) queue.
|
||||
* The input queue is used to post raw (instruction) mode data or packet
|
||||
* data to Octeon device from the host. Each input queue (up to 4) for
|
||||
* a Octeon device has one such structure to represent it.
|
||||
*/
|
||||
struct octep_vf_iq {
|
||||
u32 q_no;
|
||||
|
||||
struct octep_vf_device *octep_vf_dev;
|
||||
struct net_device *netdev;
|
||||
struct device *dev;
|
||||
struct netdev_queue *netdev_q;
|
||||
|
||||
/* Index in input ring where driver should write the next packet */
|
||||
u16 host_write_index;
|
||||
|
||||
/* Index in input ring where Octeon is expected to read next packet */
|
||||
u16 octep_vf_read_index;
|
||||
|
||||
/* This index aids in finding the window in the queue where Octeon
|
||||
* has read the commands.
|
||||
*/
|
||||
u16 flush_index;
|
||||
|
||||
/* Statistics for this input queue. */
|
||||
struct octep_vf_iq_stats stats;
|
||||
|
||||
/* Pointer to the Virtual Base addr of the input ring. */
|
||||
struct octep_vf_tx_desc_hw *desc_ring;
|
||||
|
||||
/* DMA mapped base address of the input descriptor ring. */
|
||||
dma_addr_t desc_ring_dma;
|
||||
|
||||
/* Info of Tx buffers pending completion. */
|
||||
struct octep_vf_tx_buffer *buff_info;
|
||||
|
||||
/* Base pointer to Scatter/Gather lists for all ring descriptors. */
|
||||
struct octep_vf_tx_sglist_desc *sglist;
|
||||
|
||||
/* DMA mapped addr of Scatter Gather Lists */
|
||||
dma_addr_t sglist_dma;
|
||||
|
||||
/* Octeon doorbell register for the ring. */
|
||||
u8 __iomem *doorbell_reg;
|
||||
|
||||
/* Octeon instruction count register for this ring. */
|
||||
u8 __iomem *inst_cnt_reg;
|
||||
|
||||
/* interrupt level register for this ring */
|
||||
u8 __iomem *intr_lvl_reg;
|
||||
|
||||
/* Maximum no. of instructions in this queue. */
|
||||
u32 max_count;
|
||||
u32 ring_size_mask;
|
||||
|
||||
u32 pkt_in_done;
|
||||
u32 pkts_processed;
|
||||
|
||||
u32 status;
|
||||
|
||||
/* Number of instructions pending to be posted to Octeon. */
|
||||
u32 fill_cnt;
|
||||
|
||||
/* The max. number of instructions that can be held pending by the
|
||||
* driver before ringing doorbell.
|
||||
*/
|
||||
u32 fill_threshold;
|
||||
};
|
||||
|
||||
/* Hardware Tx Instruction Header */
|
||||
struct octep_vf_instr_hdr {
|
||||
/* Data Len */
|
||||
u64 tlen:16;
|
||||
|
||||
/* Reserved */
|
||||
u64 rsvd:20;
|
||||
|
||||
/* PKIND for SDP */
|
||||
u64 pkind:6;
|
||||
|
||||
/* Front Data size */
|
||||
u64 fsz:6;
|
||||
|
||||
/* No. of entries in gather list */
|
||||
u64 gsz:14;
|
||||
|
||||
/* Gather indicator 1=gather*/
|
||||
u64 gather:1;
|
||||
|
||||
/* Reserved3 */
|
||||
u64 reserved3:1;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_instr_hdr) == 8);
|
||||
|
||||
/* Tx offload flags */
|
||||
#define OCTEP_VF_TX_OFFLOAD_VLAN_INSERT BIT(0)
|
||||
#define OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM BIT(1)
|
||||
#define OCTEP_VF_TX_OFFLOAD_UDP_CKSUM BIT(2)
|
||||
#define OCTEP_VF_TX_OFFLOAD_TCP_CKSUM BIT(3)
|
||||
#define OCTEP_VF_TX_OFFLOAD_SCTP_CKSUM BIT(4)
|
||||
#define OCTEP_VF_TX_OFFLOAD_TCP_TSO BIT(5)
|
||||
#define OCTEP_VF_TX_OFFLOAD_UDP_TSO BIT(6)
|
||||
|
||||
#define OCTEP_VF_TX_OFFLOAD_CKSUM (OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \
|
||||
OCTEP_VF_TX_OFFLOAD_UDP_CKSUM | \
|
||||
OCTEP_VF_TX_OFFLOAD_TCP_CKSUM)
|
||||
|
||||
#define OCTEP_VF_TX_OFFLOAD_TSO (OCTEP_VF_TX_OFFLOAD_TCP_TSO | \
|
||||
OCTEP_VF_TX_OFFLOAD_UDP_TSO)
|
||||
|
||||
#define OCTEP_VF_TX_IP_CSUM(flags) ((flags) & \
|
||||
(OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \
|
||||
OCTEP_VF_TX_OFFLOAD_TCP_CKSUM | \
|
||||
OCTEP_VF_TX_OFFLOAD_UDP_CKSUM))
|
||||
|
||||
#define OCTEP_VF_TX_TSO(flags) ((flags) & \
|
||||
(OCTEP_VF_TX_OFFLOAD_TCP_TSO | \
|
||||
OCTEP_VF_TX_OFFLOAD_UDP_TSO))
|
||||
|
||||
struct tx_mdata {
|
||||
/* offload flags */
|
||||
u16 ol_flags;
|
||||
|
||||
/* gso size */
|
||||
u16 gso_size;
|
||||
|
||||
/* gso flags */
|
||||
u16 gso_segs;
|
||||
|
||||
/* reserved */
|
||||
u16 rsvd1;
|
||||
|
||||
/* reserved */
|
||||
u64 rsvd2;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct tx_mdata) == 16);
|
||||
|
||||
/* 64-byte Tx instruction format.
|
||||
* Format of instruction for a 64-byte mode input queue.
|
||||
*
|
||||
* only first 16-bytes (dptr and ih) are mandatory; rest are optional
|
||||
* and filled by the driver based on firmware/hardware capabilities.
|
||||
* These optional headers together called Front Data and its size is
|
||||
* described by ih->fsz.
|
||||
*/
|
||||
struct octep_vf_tx_desc_hw {
|
||||
/* Pointer where the input data is available. */
|
||||
u64 dptr;
|
||||
|
||||
/* Instruction Header. */
|
||||
union {
|
||||
struct octep_vf_instr_hdr ih;
|
||||
u64 ih64;
|
||||
};
|
||||
|
||||
union {
|
||||
u64 txm64[2];
|
||||
struct tx_mdata txm;
|
||||
};
|
||||
|
||||
/* Additional headers available in a 64-byte instruction. */
|
||||
u64 exhdr[4];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct octep_vf_tx_desc_hw) == 64);
|
||||
|
||||
#define OCTEP_VF_IQ_DESC_SIZE (sizeof(struct octep_vf_tx_desc_hw))
|
||||
#endif /* _OCTEP_VF_TX_H_ */
|
Loading…
Reference in New Issue
Block a user