
On 26.08.20 14:37, Stefan Roese wrote:
From: Suneel Garapati sgarapati@marvell.com
Adds support for Network Interface controllers found on OcteonTX SoC platforms.
Signed-off-by: Suneel Garapati sgarapati@marvell.com Signed-off-by: Stefan Roese sr@denx.de Cc: Joe Hershberger joe.hershberger@ni.com
Series-changes: 3
- Add SoB from Stefan
- Remove spdx.org line from comment
- Remove inclusion of common.h header
- Order header file inclusion
- Misc minor checkpatch fixes
Series-changes: 1
- Change patch subject
- Rebased on latest TOT
- Removed inclusion of common.h
Applied to u-boot-marvell/master
Thanks, Stefan
drivers/net/Kconfig | 14 + drivers/net/Makefile | 2 + drivers/net/octeontx/Makefile | 7 + drivers/net/octeontx/bgx.c | 1565 +++++++++++++++++++++++++++ drivers/net/octeontx/bgx.h | 259 +++++ drivers/net/octeontx/nic.h | 508 +++++++++ drivers/net/octeontx/nic_main.c | 778 +++++++++++++ drivers/net/octeontx/nic_reg.h | 250 +++++ drivers/net/octeontx/nicvf_main.c | 581 ++++++++++ drivers/net/octeontx/nicvf_queues.c | 1140 +++++++++++++++++++ drivers/net/octeontx/nicvf_queues.h | 353 ++++++ drivers/net/octeontx/q_struct.h | 695 ++++++++++++ drivers/net/octeontx/smi.c | 380 +++++++ drivers/net/octeontx/xcv.c | 124 +++ 14 files changed, 6656 insertions(+) create mode 100644 drivers/net/octeontx/Makefile create mode 100644 drivers/net/octeontx/bgx.c create mode 100644 drivers/net/octeontx/bgx.h create mode 100644 drivers/net/octeontx/nic.h create mode 100644 drivers/net/octeontx/nic_main.c create mode 100644 drivers/net/octeontx/nic_reg.h create mode 100644 drivers/net/octeontx/nicvf_main.c create mode 100644 drivers/net/octeontx/nicvf_queues.c create mode 100644 drivers/net/octeontx/nicvf_queues.h create mode 100644 drivers/net/octeontx/q_struct.h create mode 100644 drivers/net/octeontx/smi.c create mode 100644 drivers/net/octeontx/xcv.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 039f9fb058..26ea53d346 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -407,6 +407,20 @@ config MT7628_ETH The MediaTek MT7628 ethernet interface is used on MT7628 and MT7688 based boards.
+config NET_OCTEONTX
- bool "OcteonTX Ethernet support"
- depends on ARCH_OCTEONTX
- depends on PCI_SRIOV
- help
You must select Y to enable network device support for
OcteonTX SoCs. If unsure, say n
+config OCTEONTX_SMI
- bool "OcteonTX SMI Device support"
- depends on ARCH_OCTEONTX || ARCH_OCTEONTX2
- help
You must select Y to enable SMI controller support for
OcteonTX or OcteonTX2 SoCs. If unsure, say n
- config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1ecdc40b8f..bee9680f76 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -65,6 +65,8 @@ obj-$(CONFIG_RENESAS_RAVB) += ravb.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o +obj-$(CONFIG_NET_OCTEONTX) += octeontx/ +obj-$(CONFIG_OCTEONTX_SMI) += octeontx/smi.o obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o obj-$(CONFIG_ULI526X) += uli526x.o obj-$(CONFIG_VSC7385_ENET) += vsc7385.o diff --git a/drivers/net/octeontx/Makefile b/drivers/net/octeontx/Makefile new file mode 100644 index 0000000000..d4adb7cdba --- /dev/null +++ b/drivers/net/octeontx/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2018 Marvell International Ltd. +#
+obj-$(CONFIG_NET_OCTEONTX) += bgx.o nic_main.o nicvf_queues.o nicvf_main.o \
xcv.o
diff --git a/drivers/net/octeontx/bgx.c b/drivers/net/octeontx/bgx.c new file mode 100644 index 0000000000..fbe2e2c073 --- /dev/null +++ b/drivers/net/octeontx/bgx.c @@ -0,0 +1,1565 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdt_support.h> +#include <malloc.h> +#include <miiphy.h> +#include <misc.h> +#include <net.h> +#include <netdev.h> +#include <pci.h> +#include <pci_ids.h> +#include <asm/io.h> +#include <asm/arch/board.h> +#include <linux/delay.h> +#include <linux/libfdt.h>
+#include "nic_reg.h" +#include "nic.h" +#include "bgx.h"
+static const phy_interface_t if_mode[] = {
- [QLM_MODE_SGMII] = PHY_INTERFACE_MODE_SGMII,
- [QLM_MODE_RGMII] = PHY_INTERFACE_MODE_RGMII,
- [QLM_MODE_QSGMII] = PHY_INTERFACE_MODE_QSGMII,
- [QLM_MODE_XAUI] = PHY_INTERFACE_MODE_XAUI,
- [QLM_MODE_RXAUI] = PHY_INTERFACE_MODE_RXAUI,
+};
+struct lmac {
- struct bgx *bgx;
- int dmac;
- u8 mac[6];
- bool link_up;
- bool init_pend;
- int lmacid; /* ID within BGX */
- int phy_addr; /* ID on board */
- struct udevice *dev;
- struct mii_dev *mii_bus;
- struct phy_device *phydev;
- unsigned int last_duplex;
- unsigned int last_link;
- unsigned int last_speed;
- int lane_to_sds;
- int use_training;
- int lmac_type;
- u8 qlm_mode;
- int qlm;
- bool is_1gx;
+};
+struct bgx {
- u8 bgx_id;
- int node;
- struct lmac lmac[MAX_LMAC_PER_BGX];
- int lmac_count;
- u8 max_lmac;
- void __iomem *reg_base;
- struct pci_dev *pdev;
- bool is_rgx;
+};
+struct bgx_board_info bgx_board_info[MAX_BGX_PER_NODE];
+struct bgx *bgx_vnic[MAX_BGX_PER_NODE];
+/* APIs to read/write BGXX CSRs */ +static u64 bgx_reg_read(struct bgx *bgx, uint8_t lmac, u64 offset) +{
- u64 addr = (uintptr_t)bgx->reg_base +
((uint32_t)lmac << 20) + offset;
- return readq((void *)addr);
+}
+static void bgx_reg_write(struct bgx *bgx, uint8_t lmac,
u64 offset, u64 val)
+{
- u64 addr = (uintptr_t)bgx->reg_base +
((uint32_t)lmac << 20) + offset;
- writeq(val, (void *)addr);
+}
+static void bgx_reg_modify(struct bgx *bgx, uint8_t lmac,
u64 offset, u64 val)
+{
- u64 addr = (uintptr_t)bgx->reg_base +
((uint32_t)lmac << 20) + offset;
- writeq(val | bgx_reg_read(bgx, lmac, offset), (void *)addr);
+}
+static int bgx_poll_reg(struct bgx *bgx, uint8_t lmac,
u64 reg, u64 mask, bool zero)
+{
- int timeout = 200;
- u64 reg_val;
- while (timeout) {
reg_val = bgx_reg_read(bgx, lmac, reg);
if (zero && !(reg_val & mask))
return 0;
if (!zero && (reg_val & mask))
return 0;
mdelay(1);
timeout--;
- }
- return 1;
+}
+static int gser_poll_reg(u64 reg, int bit, u64 mask, u64 expected_val,
int timeout)
+{
- u64 reg_val;
- debug("%s reg = %#llx, mask = %#llx,", __func__, reg, mask);
- debug(" expected_val = %#llx, bit = %d\n", expected_val, bit);
- while (timeout) {
reg_val = readq(reg) >> bit;
if ((reg_val & mask) == (expected_val))
return 0;
mdelay(1);
timeout--;
- }
- return 1;
+}
+static bool is_bgx_port_valid(int bgx, int lmac) +{
- debug("%s bgx %d lmac %d valid %d\n", __func__, bgx, lmac,
bgx_board_info[bgx].lmac_reg[lmac]);
- if (bgx_board_info[bgx].lmac_reg[lmac])
return 1;
- else
return 0;
+}
+struct lmac *bgx_get_lmac(int node, int bgx_idx, int lmacid) +{
- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- if (bgx)
return &bgx->lmac[lmacid];
- return NULL;
+}
+const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid) +{
- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- if (bgx)
return bgx->lmac[lmacid].mac;
- return NULL;
+}
+void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac) +{
- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- if (!bgx)
return;
- memcpy(bgx->lmac[lmacid].mac, mac, 6);
+}
+/* Return number of BGX present in HW */ +void bgx_get_count(int node, int *bgx_count) +{
- int i;
- struct bgx *bgx;
- *bgx_count = 0;
- for (i = 0; i < MAX_BGX_PER_NODE; i++) {
bgx = bgx_vnic[node * MAX_BGX_PER_NODE + i];
debug("bgx_vnic[%u]: %p\n", node * MAX_BGX_PER_NODE + i,
bgx);
if (bgx)
*bgx_count |= (1 << i);
- }
+}
+/* Return number of LMAC configured for this BGX */ +int bgx_get_lmac_count(int node, int bgx_idx) +{
- struct bgx *bgx;
- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- if (bgx)
return bgx->lmac_count;
- return 0;
+}
+void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) +{
- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- u64 cfg;
- if (!bgx)
return;
- cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
- if (enable)
cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN;
- else
cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
- bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+}
+static void bgx_flush_dmac_addrs(struct bgx *bgx, u64 lmac) +{
- u64 dmac = 0x00;
- u64 offset, addr;
- while (bgx->lmac[lmac].dmac > 0) {
offset = ((bgx->lmac[lmac].dmac - 1) * sizeof(dmac)) +
(lmac * MAX_DMAC_PER_LMAC * sizeof(dmac));
addr = (uintptr_t)bgx->reg_base +
BGX_CMR_RX_DMACX_CAM + offset;
writeq(dmac, (void *)addr);
bgx->lmac[lmac].dmac--;
- }
+}
+/* Configure BGX LMAC in internal loopback mode */ +void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable)
+{
- struct bgx *bgx;
- struct lmac *lmac;
- u64 cfg;
- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
- if (!bgx)
return;
- lmac = &bgx->lmac[lmac_idx];
- if (lmac->qlm_mode == QLM_MODE_SGMII) {
cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL);
if (enable)
cfg |= PCS_MRX_CTL_LOOPBACK1;
else
cfg &= ~PCS_MRX_CTL_LOOPBACK1;
bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg);
- } else {
cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1);
if (enable)
cfg |= SPU_CTL_LOOPBACK;
else
cfg &= ~SPU_CTL_LOOPBACK;
bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg);
- }
+}
+/* Return the DLM used for the BGX */ +static int get_qlm_for_bgx(int node, int bgx_id, int index) +{
- int qlm = 0;
- u64 cfg;
- if (otx_is_soc(CN81XX)) {
qlm = (bgx_id) ? 2 : 0;
qlm += (index >= 2) ? 1 : 0;
- } else if (otx_is_soc(CN83XX)) {
switch (bgx_id) {
case 0:
qlm = 2;
break;
case 1:
qlm = 3;
break;
case 2:
if (index >= 2)
qlm = 6;
else
qlm = 5;
break;
case 3:
qlm = 4;
break;
}
- }
- cfg = readq(GSERX_CFG(qlm)) & GSERX_CFG_BGX;
- debug("%s:qlm%d: cfg = %lld\n", __func__, qlm, cfg);
- /* Check if DLM is configured as BGX# */
- if (cfg) {
if (readq(GSERX_PHY_CTL(qlm)))
return -1;
return qlm;
- }
- return -1;
+}
+static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid) +{
- u64 cfg;
- struct lmac *lmac;
- lmac = &bgx->lmac[lmacid];
- debug("%s:bgx_id = %d, lmacid = %d\n", __func__, bgx->bgx_id, lmacid);
- bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_THRESH, 0x30);
- /* max packet size */
- bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_RXX_JABBER, MAX_FRAME_SIZE);
- /* Disable frame alignment if using preamble */
- cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
- if (cfg & 1)
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SGMII_CTL, 0);
- /* Enable lmac */
- bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
- /* PCS reset */
- bgx_reg_modify(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_RESET);
- if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_CTL,
PCS_MRX_CTL_RESET, true)) {
printf("BGX PCS reset not completed\n");
return -1;
- }
- /* power down, reset autoneg, autoneg enable */
- cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
- cfg &= ~PCS_MRX_CTL_PWR_DN;
- if (bgx_board_info[bgx->bgx_id].phy_info[lmacid].autoneg_dis)
cfg |= (PCS_MRX_CTL_RST_AN);
- else
cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN);
- bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
- /* Disable disparity for QSGMII mode, to prevent propogation across
* ports.
*/
- if (lmac->qlm_mode == QLM_MODE_QSGMII) {
cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL);
cfg &= ~PCS_MISCX_CTL_DISP_EN;
bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, cfg);
return 0; /* Skip checking AN_CPT */
- }
- if (lmac->is_1gx) {
cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL);
cfg |= PCS_MISC_CTL_MODE;
bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, cfg);
- }
- if (lmac->qlm_mode == QLM_MODE_SGMII) {
if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
PCS_MRX_STATUS_AN_CPT, false)) {
printf("BGX AN_CPT not completed\n");
return -1;
}
- }
- return 0;
+}
+static int bgx_lmac_sgmii_set_link_speed(struct lmac *lmac) +{
- u64 prtx_cfg;
- u64 pcs_miscx_ctl;
- u64 cfg;
- struct bgx *bgx = lmac->bgx;
- unsigned int lmacid = lmac->lmacid;
- debug("%s: lmacid %d\n", __func__, lmac->lmacid);
- /* Disable LMAC before setting up speed */
- cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
- cfg &= ~CMR_EN;
- bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
- /* Read GMX CFG */
- prtx_cfg = bgx_reg_read(bgx, lmacid,
BGX_GMP_GMI_PRTX_CFG);
- /* Read PCS MISCS CTL */
- pcs_miscx_ctl = bgx_reg_read(bgx, lmacid,
BGX_GMP_PCS_MISCX_CTL);
- /* Use GMXENO to force the link down*/
- if (lmac->link_up) {
pcs_miscx_ctl &= ~PCS_MISC_CTL_GMX_ENO;
/* change the duplex setting if the link is up */
prtx_cfg |= GMI_PORT_CFG_DUPLEX;
- } else {
pcs_miscx_ctl |= PCS_MISC_CTL_GMX_ENO;
- }
- /* speed based setting for GMX */
- switch (lmac->last_speed) {
- case 10:
prtx_cfg &= ~GMI_PORT_CFG_SPEED;
prtx_cfg |= GMI_PORT_CFG_SPEED_MSB;
prtx_cfg &= ~GMI_PORT_CFG_SLOT_TIME;
pcs_miscx_ctl |= 50; /* sampling point */
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x40);
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
break;
- case 100:
prtx_cfg &= ~GMI_PORT_CFG_SPEED;
prtx_cfg &= ~GMI_PORT_CFG_SPEED_MSB;
prtx_cfg &= ~GMI_PORT_CFG_SLOT_TIME;
pcs_miscx_ctl |= 0x5; /* sampling point */
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x40);
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
break;
- case 1000:
prtx_cfg |= GMI_PORT_CFG_SPEED;
prtx_cfg &= ~GMI_PORT_CFG_SPEED_MSB;
prtx_cfg |= GMI_PORT_CFG_SLOT_TIME;
pcs_miscx_ctl |= 0x1; /* sampling point */
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x200);
if (lmac->last_duplex)
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
else /* half duplex */
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST,
0x2000);
break;
- default:
break;
- }
- /* write back the new PCS misc and GMX settings */
- bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, pcs_miscx_ctl);
- bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_PRTX_CFG, prtx_cfg);
- /* read back GMX CFG again to check config completion */
- bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_PRTX_CFG);
- /* enable BGX back */
- cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
- cfg |= CMR_EN;
- bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
- return 0;
+}
+static int bgx_lmac_xaui_init(struct bgx *bgx, int lmacid, int lmac_type) +{
- u64 cfg;
- struct lmac *lmac;
- lmac = &bgx->lmac[lmacid];
- /* Reset SPU */
- bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET);
- if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
printf("BGX SPU reset not completed\n");
return -1;
- }
- /* Disable LMAC */
- cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
- cfg &= ~CMR_EN;
- bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
- bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
- /* Set interleaved running disparity for RXAUI */
- if (lmac->qlm_mode != QLM_MODE_RXAUI)
bgx_reg_modify(bgx, lmacid,
BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
- else
bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL,
SPU_MISC_CTL_RX_DIS | SPU_MISC_CTL_INTLV_RDISP);
- /* clear all interrupts */
- cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_INT);
- bgx_reg_write(bgx, lmacid, BGX_SMUX_RX_INT, cfg);
- cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_INT);
- bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_INT, cfg);
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
- bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
- if (lmac->use_training) {
bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LP_CUP, 0x00);
bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_CUP, 0x00);
bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_REP, 0x00);
/* training enable */
bgx_reg_modify(bgx, lmacid,
BGX_SPUX_BR_PMD_CRTL, SPU_PMD_CRTL_TRAIN_EN);
- }
- /* Append FCS to each packet */
- bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, SMU_TX_APPEND_FCS_D);
- /* Disable forward error correction */
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_FEC_CONTROL);
- cfg &= ~SPU_FEC_CTL_FEC_EN;
- bgx_reg_write(bgx, lmacid, BGX_SPUX_FEC_CONTROL, cfg);
- /* Disable autoneg */
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
- cfg = cfg & ~(SPU_AN_CTL_XNP_EN);
- if (lmac->use_training)
cfg = cfg | (SPU_AN_CTL_AN_EN);
- else
cfg = cfg & ~(SPU_AN_CTL_AN_EN);
- bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_CONTROL, cfg);
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_ADV);
- /* Clear all KR bits, configure according to the mode */
- cfg &= ~((0xfULL << 22) | (1ULL << 12));
- if (lmac->qlm_mode == QLM_MODE_10G_KR)
cfg |= (1 << 23);
- else if (lmac->qlm_mode == QLM_MODE_40G_KR4)
cfg |= (1 << 24);
- bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_ADV, cfg);
- cfg = bgx_reg_read(bgx, 0, BGX_SPU_DBG_CONTROL);
- if (lmac->use_training)
cfg |= SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
- else
cfg &= ~SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
- bgx_reg_write(bgx, 0, BGX_SPU_DBG_CONTROL, cfg);
- /* Enable lmac */
- bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_CONTROL1);
- cfg &= ~SPU_CTL_LOW_POWER;
- bgx_reg_write(bgx, lmacid, BGX_SPUX_CONTROL1, cfg);
- cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_CTL);
- cfg &= ~SMU_TX_CTL_UNI_EN;
- cfg |= SMU_TX_CTL_DIC_EN;
- bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
- /* take lmac_count into account */
- bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
- /* max packet size */
- bgx_reg_modify(bgx, lmacid, BGX_SMUX_RX_JABBER, MAX_FRAME_SIZE);
- debug("xaui_init: lmacid = %d, qlm = %d, qlm_mode = %d\n",
lmacid, lmac->qlm, lmac->qlm_mode);
- /* RXAUI with Marvell PHY requires some tweaking */
- if (lmac->qlm_mode == QLM_MODE_RXAUI) {
char mii_name[20];
struct phy_info *phy;
phy = &bgx_board_info[bgx->bgx_id].phy_info[lmacid];
snprintf(mii_name, sizeof(mii_name), "smi%d", phy->mdio_bus);
debug("mii_name: %s\n", mii_name);
lmac->mii_bus = miiphy_get_dev_by_name(mii_name);
lmac->phy_addr = phy->phy_addr;
rxaui_phy_xs_init(lmac->mii_bus, lmac->phy_addr);
- }
- return 0;
+}
+/* Get max number of lanes present in a given QLM/DLM */ +static int get_qlm_lanes(int qlm) +{
- if (otx_is_soc(CN81XX))
return 2;
- else if (otx_is_soc(CN83XX))
return (qlm >= 5) ? 2 : 4;
- else
return -1;
+}
+int __rx_equalization(int qlm, int lane) +{
- int max_lanes = get_qlm_lanes(qlm);
- int l;
- int fail = 0;
- /* Before completing Rx equalization wait for
* GSERx_RX_EIE_DETSTS[CDRLOCK] to be set
* This ensures the rx data is valid
*/
- if (lane == -1) {
if (gser_poll_reg(GSER_RX_EIE_DETSTS(qlm), GSER_CDRLOCK, 0xf,
(1 << max_lanes) - 1, 100)) {
debug("ERROR: CDR Lock not detected");
debug(" on DLM%d for 2 lanes\n", qlm);
return -1;
}
- } else {
if (gser_poll_reg(GSER_RX_EIE_DETSTS(qlm), GSER_CDRLOCK,
(0xf & (1 << lane)), (1 << lane), 100)) {
debug("ERROR: DLM%d: CDR Lock not detected", qlm);
debug(" on %d lane\n", lane);
return -1;
}
- }
- for (l = 0; l < max_lanes; l++) {
u64 rctl, reer;
if (lane != -1 && lane != l)
continue;
/* Enable software control */
rctl = readq(GSER_BR_RXX_CTL(qlm, l));
rctl |= GSER_BR_RXX_CTL_RXT_SWM;
writeq(rctl, GSER_BR_RXX_CTL(qlm, l));
/* Clear the completion flag and initiate a new request */
reer = readq(GSER_BR_RXX_EER(qlm, l));
reer &= ~GSER_BR_RXX_EER_RXT_ESV;
reer |= GSER_BR_RXX_EER_RXT_EER;
writeq(reer, GSER_BR_RXX_EER(qlm, l));
- }
- /* Wait for RX equalization to complete */
- for (l = 0; l < max_lanes; l++) {
u64 rctl, reer;
if (lane != -1 && lane != l)
continue;
gser_poll_reg(GSER_BR_RXX_EER(qlm, l), EER_RXT_ESV, 1, 1, 200);
reer = readq(GSER_BR_RXX_EER(qlm, l));
/* Switch back to hardware control */
rctl = readq(GSER_BR_RXX_CTL(qlm, l));
rctl &= ~GSER_BR_RXX_CTL_RXT_SWM;
writeq(rctl, GSER_BR_RXX_CTL(qlm, l));
if (reer & GSER_BR_RXX_EER_RXT_ESV) {
debug("Rx equalization completed on DLM%d", qlm);
debug(" QLM%d rxt_esm = 0x%llx\n", l, (reer & 0x3fff));
} else {
debug("Rx equalization timedout on DLM%d", qlm);
debug(" lane %d\n", l);
fail = 1;
}
- }
- return (fail) ? -1 : 0;
+}
+static int bgx_xaui_check_link(struct lmac *lmac) +{
- struct bgx *bgx = lmac->bgx;
- int lmacid = lmac->lmacid;
- int lmac_type = lmac->lmac_type;
- u64 cfg;
- bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
- /* check if auto negotiation is complete */
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
- if (cfg & SPU_AN_CTL_AN_EN) {
cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_STATUS);
if (!(cfg & SPU_AN_STS_AN_COMPLETE)) {
/* Restart autonegotiation */
debug("restarting auto-neg\n");
bgx_reg_modify(bgx, lmacid, BGX_SPUX_AN_CONTROL,
SPU_AN_CTL_AN_RESTART);
return -1;
}
- }
- debug("%s link use_training %d\n", __func__, lmac->use_training);
- if (lmac->use_training) {
cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
if (!(cfg & (1ull << 13))) {
debug("waiting for link training\n");
/* Clear the training interrupts (W1C) */
cfg = (1ull << 13) | (1ull << 14);
bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
udelay(2000);
/* Restart training */
cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL);
cfg |= (1ull << 0);
bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL, cfg);
return -1;
}
- }
- /* Perform RX Equalization. Applies to non-KR interfaces for speeds
* >= 6.25Gbps.
*/
- if (!lmac->use_training) {
int qlm;
bool use_dlm = 0;
if (otx_is_soc(CN81XX) || (otx_is_soc(CN83XX) &&
bgx->bgx_id == 2))
use_dlm = 1;
switch (lmac->lmac_type) {
default:
case BGX_MODE_SGMII:
case BGX_MODE_RGMII:
case BGX_MODE_XAUI:
/* Nothing to do */
break;
case BGX_MODE_XLAUI:
if (use_dlm) {
if (__rx_equalization(lmac->qlm, -1) ||
__rx_equalization(lmac->qlm + 1, -1)) {
printf("BGX%d:%d", bgx->bgx_id, lmacid);
printf(" Waiting for RX Equalization");
printf(" on DLM%d/DLM%d\n",
lmac->qlm, lmac->qlm + 1);
return -1;
}
} else {
if (__rx_equalization(lmac->qlm, -1)) {
printf("BGX%d:%d", bgx->bgx_id, lmacid);
printf(" Waiting for RX Equalization");
printf(" on QLM%d\n", lmac->qlm);
return -1;
}
}
break;
case BGX_MODE_RXAUI:
/* RXAUI0 uses LMAC0:QLM0/QLM2 and RXAUI1 uses
* LMAC1:QLM1/QLM3 RXAUI requires 2 lanes
* for each interface
*/
qlm = lmac->qlm;
if (__rx_equalization(qlm, 0)) {
printf("BGX%d:%d", bgx->bgx_id, lmacid);
printf(" Waiting for RX Equalization");
printf(" on QLM%d, Lane0\n", qlm);
return -1;
}
if (__rx_equalization(qlm, 1)) {
printf("BGX%d:%d", bgx->bgx_id, lmacid);
printf(" Waiting for RX Equalization");
printf(" on QLM%d, Lane1\n", qlm);
return -1;
}
break;
case BGX_MODE_XFI:
{
int lid;
bool altpkg = otx_is_altpkg();
if (bgx->bgx_id == 0 && altpkg && lmacid)
lid = 0;
else if ((lmacid >= 2) && use_dlm)
lid = lmacid - 2;
else
lid = lmacid;
if (__rx_equalization(lmac->qlm, lid)) {
printf("BGX%d:%d", bgx->bgx_id, lid);
printf(" Waiting for RX Equalization");
printf(" on QLM%d\n", lmac->qlm);
}
}
break;
}
- }
- /* wait for PCS to come out of reset */
- if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
printf("BGX SPU reset not completed\n");
return -1;
- }
- if (lmac_type == 3 || lmac_type == 4) {
if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BR_STATUS1,
SPU_BR_STATUS_BLK_LOCK, false)) {
printf("SPU_BR_STATUS_BLK_LOCK not completed\n");
return -1;
}
- } else {
if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BX_STATUS,
SPU_BX_STATUS_RX_ALIGN, false)) {
printf("SPU_BX_STATUS_RX_ALIGN not completed\n");
return -1;
}
- }
- /* Clear rcvflt bit (latching high) and read it back */
- bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
- if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
printf("Receive fault, retry training\n");
if (lmac->use_training) {
cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
if (!(cfg & (1ull << 13))) {
cfg = (1ull << 13) | (1ull << 14);
bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
cfg = bgx_reg_read(bgx, lmacid,
BGX_SPUX_BR_PMD_CRTL);
cfg |= (1ull << 0);
bgx_reg_write(bgx, lmacid,
BGX_SPUX_BR_PMD_CRTL, cfg);
return -1;
}
}
return -1;
- }
- /* Wait for MAC RX to be ready */
- if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
SMU_RX_CTL_STATUS, true)) {
printf("SMU RX link not okay\n");
return -1;
- }
- /* Wait for BGX RX to be idle */
- if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_RX_IDLE, false)) {
printf("SMU RX not idle\n");
return -1;
- }
- /* Wait for BGX TX to be idle */
- if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_TX_IDLE, false)) {
printf("SMU TX not idle\n");
return -1;
- }
- if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
printf("Receive fault\n");
return -1;
- }
- /* Receive link is latching low. Force it high and verify it */
- if (!(bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS1) &
SPU_STATUS1_RCV_LNK))
bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1,
SPU_STATUS1_RCV_LNK);
- if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
SPU_STATUS1_RCV_LNK, false)) {
printf("SPU receive link down\n");
return -1;
- }
- cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
- cfg &= ~SPU_MISC_CTL_RX_DIS;
- bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
- return 0;
+}
+static int bgx_lmac_enable(struct bgx *bgx, int8_t lmacid) +{
- struct lmac *lmac;
- u64 cfg;
- lmac = &bgx->lmac[lmacid];
- debug("%s: lmac: %p, lmacid = %d\n", __func__, lmac, lmacid);
- if (lmac->qlm_mode == QLM_MODE_SGMII ||
lmac->qlm_mode == QLM_MODE_RGMII ||
lmac->qlm_mode == QLM_MODE_QSGMII) {
if (bgx_lmac_sgmii_init(bgx, lmacid)) {
debug("bgx_lmac_sgmii_init failed\n");
return -1;
}
cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND, cfg);
bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_MIN_PKT, 60 - 1);
- } else {
if (bgx_lmac_xaui_init(bgx, lmacid, lmac->lmac_type))
return -1;
cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_APPEND);
cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, cfg);
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_MIN_PKT, 60 + 4);
- }
- /* Enable lmac */
- bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
- return 0;
+}
+int bgx_poll_for_link(int node, int bgx_idx, int lmacid) +{
- int ret;
- struct lmac *lmac = bgx_get_lmac(node, bgx_idx, lmacid);
- char mii_name[10];
- struct phy_info *phy;
- if (!lmac) {
printf("LMAC %d/%d/%d is disabled or doesn't exist\n",
node, bgx_idx, lmacid);
return 0;
- }
- debug("%s: %d, lmac: %d/%d/%d %p\n",
__FILE__, __LINE__,
node, bgx_idx, lmacid, lmac);
- if (lmac->init_pend) {
ret = bgx_lmac_enable(lmac->bgx, lmacid);
if (ret < 0) {
printf("BGX%d LMAC%d lmac_enable failed\n", bgx_idx,
lmacid);
return ret;
}
lmac->init_pend = 0;
mdelay(100);
- }
- if (lmac->qlm_mode == QLM_MODE_SGMII ||
lmac->qlm_mode == QLM_MODE_RGMII ||
lmac->qlm_mode == QLM_MODE_QSGMII) {
if (bgx_board_info[bgx_idx].phy_info[lmacid].phy_addr == -1) {
lmac->link_up = 1;
lmac->last_speed = 1000;
lmac->last_duplex = 1;
printf("BGX%d:LMAC %u link up\n", bgx_idx, lmacid);
return lmac->link_up;
}
snprintf(mii_name, sizeof(mii_name), "smi%d",
bgx_board_info[bgx_idx].phy_info[lmacid].mdio_bus);
debug("mii_name: %s\n", mii_name);
lmac->mii_bus = miiphy_get_dev_by_name(mii_name);
phy = &bgx_board_info[bgx_idx].phy_info[lmacid];
lmac->phy_addr = phy->phy_addr;
debug("lmac->mii_bus: %p\n", lmac->mii_bus);
if (!lmac->mii_bus) {
printf("MDIO device %s not found\n", mii_name);
ret = -ENODEV;
return ret;
}
lmac->phydev = phy_connect(lmac->mii_bus, lmac->phy_addr,
lmac->dev,
if_mode[lmac->qlm_mode]);
if (!lmac->phydev) {
printf("%s: No PHY device\n", __func__);
return -1;
}
ret = phy_config(lmac->phydev);
if (ret) {
printf("%s: Could not initialize PHY %s\n",
__func__, lmac->phydev->dev->name);
return ret;
}
ret = phy_startup(lmac->phydev);
debug("%s: %d\n", __FILE__, __LINE__);
if (ret) {
printf("%s: Could not initialize PHY %s\n",
__func__, lmac->phydev->dev->name);
}
+#ifdef OCTEONTX_XCV
if (lmac->qlm_mode == QLM_MODE_RGMII)
xcv_setup_link(lmac->phydev->link, lmac->phydev->speed);
+#endif
lmac->link_up = lmac->phydev->link;
lmac->last_speed = lmac->phydev->speed;
lmac->last_duplex = lmac->phydev->duplex;
debug("%s qlm_mode %d phy link status 0x%x,last speed 0x%x,",
__func__, lmac->qlm_mode, lmac->link_up,
lmac->last_speed);
debug(" duplex 0x%x\n", lmac->last_duplex);
if (lmac->qlm_mode != QLM_MODE_RGMII)
bgx_lmac_sgmii_set_link_speed(lmac);
- } else {
u64 status1;
u64 tx_ctl;
u64 rx_ctl;
status1 = bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_SPUX_STATUS1);
tx_ctl = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_TX_CTL);
rx_ctl = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_RX_CTL);
debug("BGX%d LMAC%d BGX_SPUX_STATUS2: %lx\n", bgx_idx, lmacid,
(unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_SPUX_STATUS2));
debug("BGX%d LMAC%d BGX_SPUX_STATUS1: %lx\n", bgx_idx, lmacid,
(unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_SPUX_STATUS1));
debug("BGX%d LMAC%d BGX_SMUX_RX_CTL: %lx\n", bgx_idx, lmacid,
(unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_SMUX_RX_CTL));
debug("BGX%d LMAC%d BGX_SMUX_TX_CTL: %lx\n", bgx_idx, lmacid,
(unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
BGX_SMUX_TX_CTL));
if ((status1 & SPU_STATUS1_RCV_LNK) &&
((tx_ctl & SMU_TX_CTL_LNK_STATUS) == 0) &&
((rx_ctl & SMU_RX_CTL_STATUS) == 0)) {
lmac->link_up = 1;
if (lmac->lmac_type == 4)
lmac->last_speed = 40000;
else
lmac->last_speed = 10000;
lmac->last_duplex = 1;
} else {
lmac->link_up = 0;
lmac->last_speed = 0;
lmac->last_duplex = 0;
return bgx_xaui_check_link(lmac);
}
lmac->last_link = lmac->link_up;
- }
- printf("BGX%d:LMAC %u link %s\n", bgx_idx, lmacid,
(lmac->link_up) ? "up" : "down");
- return lmac->link_up;
+}
+void bgx_lmac_disable(struct bgx *bgx, uint8_t lmacid) +{
- struct lmac *lmac;
- u64 cmrx_cfg;
- lmac = &bgx->lmac[lmacid];
- cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
- cmrx_cfg &= ~(1 << 15);
- bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
- bgx_flush_dmac_addrs(bgx, lmacid);
- if (lmac->phydev)
phy_shutdown(lmac->phydev);
- lmac->phydev = NULL;
+}
+/* Program BGXX_CMRX_CONFIG.{lmac_type,lane_to_sds} for each interface.
- And the number of LMACs used by this interface. Each lmac can be in
- programmed in a different mode, so parse each lmac one at a time.
- */
+static void bgx_init_hw(struct bgx *bgx) +{
- struct lmac *lmac;
- int i, lmacid, count = 0, inc = 0;
- char buf[40];
- static int qsgmii_configured;
- for (lmacid = 0; lmacid < MAX_LMAC_PER_BGX; lmacid++) {
struct lmac *tlmac;
lmac = &bgx->lmac[lmacid];
debug("%s: lmacid = %d, qlm = %d, mode = %d\n",
__func__, lmacid, lmac->qlm, lmac->qlm_mode);
/* If QLM is not programmed, skip */
if (lmac->qlm == -1)
continue;
switch (lmac->qlm_mode) {
case QLM_MODE_SGMII:
{
/* EBB8000 (alternative pkg) has only lane0 present on
* DLM0 and DLM1, skip configuring other lanes
*/
if (bgx->bgx_id == 0 && otx_is_altpkg()) {
if (lmacid % 2)
continue;
}
lmac->lane_to_sds = lmacid;
lmac->lmac_type = 0;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: %s\n",
bgx->bgx_id, lmac->qlm, lmacid,
lmac->is_1gx ? "1000Base-X" : "SGMII");
break;
}
case QLM_MODE_XAUI:
if (lmacid != 0)
continue;
lmac->lmac_type = 1;
lmac->lane_to_sds = 0xE4;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: XAUI\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_RXAUI:
if (lmacid == 0) {
lmac->lmac_type = 2;
lmac->lane_to_sds = 0x4;
} else if (lmacid == 1) {
struct lmac *tlmac;
tlmac = &bgx->lmac[2];
if (tlmac->qlm_mode == QLM_MODE_RXAUI) {
lmac->lmac_type = 2;
lmac->lane_to_sds = 0xe;
lmac->qlm = tlmac->qlm;
}
} else {
continue;
}
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: RXAUI\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_XFI:
/* EBB8000 (alternative pkg) has only lane0 present on
* DLM0 and DLM1, skip configuring other lanes
*/
if (bgx->bgx_id == 0 && otx_is_altpkg()) {
if (lmacid % 2)
continue;
}
lmac->lane_to_sds = lmacid;
lmac->lmac_type = 3;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: XFI\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_XLAUI:
if (lmacid != 0)
continue;
lmac->lmac_type = 4;
lmac->lane_to_sds = 0xE4;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: XLAUI\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_10G_KR:
/* EBB8000 (alternative pkg) has only lane0 present on
* DLM0 and DLM1, skip configuring other lanes
*/
if (bgx->bgx_id == 0 && otx_is_altpkg()) {
if (lmacid % 2)
continue;
}
lmac->lane_to_sds = lmacid;
lmac->lmac_type = 3;
lmac->use_training = 1;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: 10G-KR\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_40G_KR4:
if (lmacid != 0)
continue;
lmac->lmac_type = 4;
lmac->lane_to_sds = 0xE4;
lmac->use_training = 1;
snprintf(buf, sizeof(buf),
"BGX%d QLM%d LMAC%d mode: 40G-KR4\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case QLM_MODE_RGMII:
if (lmacid != 0)
continue;
lmac->lmac_type = 5;
lmac->lane_to_sds = 0xE4;
snprintf(buf, sizeof(buf),
"BGX%d LMAC%d mode: RGMII\n",
bgx->bgx_id, lmacid);
break;
case QLM_MODE_QSGMII:
if (qsgmii_configured)
continue;
if (lmacid == 0 || lmacid == 2) {
count = 4;
printf("BGX%d QLM%d LMAC%d mode: QSGMII\n",
bgx->bgx_id, lmac->qlm, lmacid);
for (i = 0; i < count; i++) {
struct lmac *l;
int type;
l = &bgx->lmac[i];
l->lmac_type = 6;
type = l->lmac_type;
l->qlm_mode = QLM_MODE_QSGMII;
l->lane_to_sds = lmacid + i;
if (is_bgx_port_valid(bgx->bgx_id, i))
bgx_reg_write(bgx, i,
BGX_CMRX_CFG,
(type << 8) |
l->lane_to_sds);
}
qsgmii_configured = 1;
}
continue;
default:
continue;
}
/* Reset lmac to the unused slot */
if (is_bgx_port_valid(bgx->bgx_id, count) &&
lmac->qlm_mode != QLM_MODE_QSGMII) {
int lmac_en = 0;
int tmp, idx;
tlmac = &bgx->lmac[count];
tlmac->lmac_type = lmac->lmac_type;
idx = bgx->bgx_id;
tmp = count + inc;
/* Adjust lane_to_sds based on BGX-ENABLE */
for (; tmp < MAX_LMAC_PER_BGX; inc++) {
lmac_en = bgx_board_info[idx].lmac_enable[tmp];
if (lmac_en)
break;
tmp = count + inc;
}
if (inc != 0 && inc < MAX_LMAC_PER_BGX &&
lmac_en && inc != count)
tlmac->lane_to_sds =
lmac->lane_to_sds + abs(inc - count);
else
tlmac->lane_to_sds = lmac->lane_to_sds;
tlmac->qlm = lmac->qlm;
tlmac->qlm_mode = lmac->qlm_mode;
printf("%s", buf);
/* Initialize lmac_type and lane_to_sds */
bgx_reg_write(bgx, count, BGX_CMRX_CFG,
(tlmac->lmac_type << 8) |
tlmac->lane_to_sds);
if (tlmac->lmac_type == BGX_MODE_SGMII) {
if (tlmac->is_1gx) {
/* This is actually 1000BASE-X, so
* mark the LMAC as such.
*/
bgx_reg_modify(bgx, count,
BGX_GMP_PCS_MISCX_CTL,
PCS_MISC_CTL_MODE);
}
if (!bgx_board_info[bgx->bgx_id].phy_info[lmacid].autoneg_dis) {
/* The Linux DTS does not disable
* autoneg for this LMAC (in SGMII or
* 1000BASE-X mode), so that means
* enable autoneg.
*/
bgx_reg_modify(bgx, count,
BGX_GMP_PCS_MRX_CTL,
PCS_MRX_CTL_AN_EN);
}
}
count += 1;
}
- }
- /* Done probing all 4 lmacs, now clear qsgmii_configured */
- qsgmii_configured = 0;
- printf("BGX%d LMACs: %d\n", bgx->bgx_id, count);
- bgx->lmac_count = count;
- bgx_reg_write(bgx, 0, BGX_CMR_RX_LMACS, count);
- bgx_reg_write(bgx, 0, BGX_CMR_TX_LMACS, count);
- bgx_reg_modify(bgx, 0, BGX_CMR_GLOBAL_CFG, CMR_GLOBAL_CFG_FCS_STRIP);
- if (bgx_reg_read(bgx, 0, BGX_CMR_BIST_STATUS))
printf("BGX%d BIST failed\n", bgx->bgx_id);
- /* Set the backpressure AND mask */
- for (i = 0; i < bgx->lmac_count; i++)
bgx_reg_modify(bgx, 0, BGX_CMR_CHAN_MSK_AND,
((1ULL << MAX_BGX_CHANS_PER_LMAC) - 1) <<
(i * MAX_BGX_CHANS_PER_LMAC));
- /* Disable all MAC filtering */
- for (i = 0; i < RX_DMAC_COUNT; i++)
bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + (i * 8), 0x00);
- /* Disable MAC steering (NCSI traffic) */
- for (i = 0; i < RX_TRAFFIC_STEER_RULE_COUNT; i++)
bgx_reg_write(bgx, 0, BGX_CMR_RX_STREERING + (i * 8), 0x00);
+}
+static void bgx_get_qlm_mode(struct bgx *bgx) +{
- struct lmac *lmac;
- int lmacid;
- /* Read LMACx type to figure out QLM mode
* This is configured by low level firmware
*/
- for (lmacid = 0; lmacid < MAX_LMAC_PER_BGX; lmacid++) {
int lmac_type;
int train_en;
int index = 0;
if (otx_is_soc(CN81XX) || (otx_is_soc(CN83XX) &&
bgx->bgx_id == 2))
index = (lmacid < 2) ? 0 : 2;
lmac = &bgx->lmac[lmacid];
/* check if QLM is programmed, if not, skip */
if (lmac->qlm == -1)
continue;
lmac_type = bgx_reg_read(bgx, index, BGX_CMRX_CFG);
lmac->lmac_type = (lmac_type >> 8) & 0x07;
debug("%s:%d:%d: lmac_type = %d, altpkg = %d\n", __func__,
bgx->bgx_id, lmacid, lmac->lmac_type, otx_is_altpkg());
train_en = (readq(GSERX_SCRATCH(lmac->qlm))) & 0xf;
lmac->is_1gx = bgx_reg_read(bgx, index, BGX_GMP_PCS_MISCX_CTL)
& (PCS_MISC_CTL_MODE) ? true : false;
switch (lmac->lmac_type) {
case BGX_MODE_SGMII:
if (bgx->is_rgx) {
if (lmacid == 0) {
lmac->qlm_mode = QLM_MODE_RGMII;
debug("BGX%d LMAC%d mode: RGMII\n",
bgx->bgx_id, lmacid);
}
continue;
} else {
if (bgx->bgx_id == 0 && otx_is_altpkg()) {
if (lmacid % 2)
continue;
}
lmac->qlm_mode = QLM_MODE_SGMII;
debug("BGX%d QLM%d LMAC%d mode: %s\n",
bgx->bgx_id, lmac->qlm, lmacid,
lmac->is_1gx ? "1000Base-X" : "SGMII");
}
break;
case BGX_MODE_XAUI:
if (bgx->bgx_id == 0 && otx_is_altpkg())
continue;
lmac->qlm_mode = QLM_MODE_XAUI;
if (lmacid != 0)
continue;
debug("BGX%d QLM%d LMAC%d mode: XAUI\n",
bgx->bgx_id, lmac->qlm, lmacid);
break;
case BGX_MODE_RXAUI:
if (bgx->bgx_id == 0 && otx_is_altpkg())
continue;
lmac->qlm_mode = QLM_MODE_RXAUI;
if (index == lmacid) {
debug("BGX%d QLM%d LMAC%d mode: RXAUI\n",
bgx->bgx_id, lmac->qlm, (index ? 1 : 0));
}
break;
case BGX_MODE_XFI:
if (bgx->bgx_id == 0 && otx_is_altpkg()) {
if (lmacid % 2)
continue;
}
if ((lmacid < 2 && (train_en & (1 << lmacid))) ||
(train_en & (1 << (lmacid - 2)))) {
lmac->qlm_mode = QLM_MODE_10G_KR;
debug("BGX%d QLM%d LMAC%d mode: 10G_KR\n",
bgx->bgx_id, lmac->qlm, lmacid);
} else {
lmac->qlm_mode = QLM_MODE_XFI;
debug("BGX%d QLM%d LMAC%d mode: XFI\n",
bgx->bgx_id, lmac->qlm, lmacid);
}
break;
case BGX_MODE_XLAUI:
if (bgx->bgx_id == 0 && otx_is_altpkg())
continue;
if (train_en) {
lmac->qlm_mode = QLM_MODE_40G_KR4;
if (lmacid != 0)
break;
debug("BGX%d QLM%d LMAC%d mode: 40G_KR4\n",
bgx->bgx_id, lmac->qlm, lmacid);
} else {
lmac->qlm_mode = QLM_MODE_XLAUI;
if (lmacid != 0)
break;
debug("BGX%d QLM%d LMAC%d mode: XLAUI\n",
bgx->bgx_id, lmac->qlm, lmacid);
}
break;
case BGX_MODE_QSGMII:
/* If QLM is configured as QSGMII, use lmac0 */
if (otx_is_soc(CN83XX) && lmacid == 2 &&
bgx->bgx_id != 2) {
//lmac->qlm_mode = QLM_MODE_DISABLED;
continue;
}
if (lmacid == 0 || lmacid == 2) {
lmac->qlm_mode = QLM_MODE_QSGMII;
debug("BGX%d QLM%d LMAC%d mode: QSGMII\n",
bgx->bgx_id, lmac->qlm, lmacid);
}
break;
default:
break;
}
- }
+}
+void bgx_set_board_info(int bgx_id, int *mdio_bus,
int *phy_addr, bool *autoneg_dis, bool *lmac_reg,
bool *lmac_enable)
+{
- unsigned int i;
- for (i = 0; i < MAX_LMAC_PER_BGX; i++) {
bgx_board_info[bgx_id].phy_info[i].phy_addr = phy_addr[i];
bgx_board_info[bgx_id].phy_info[i].mdio_bus = mdio_bus[i];
bgx_board_info[bgx_id].phy_info[i].autoneg_dis = autoneg_dis[i];
bgx_board_info[bgx_id].lmac_reg[i] = lmac_reg[i];
bgx_board_info[bgx_id].lmac_enable[i] = lmac_enable[i];
debug("%s bgx_id %d lmac %d\n", __func__, bgx_id, i);
debug("phy addr %x mdio bus %d autoneg_dis %d lmac_reg %d\n",
bgx_board_info[bgx_id].phy_info[i].phy_addr,
bgx_board_info[bgx_id].phy_info[i].mdio_bus,
bgx_board_info[bgx_id].phy_info[i].autoneg_dis,
bgx_board_info[bgx_id].lmac_reg[i]);
debug("lmac_enable = %x\n",
bgx_board_info[bgx_id].lmac_enable[i]);
- }
+}
+int octeontx_bgx_remove(struct udevice *dev) +{
- int lmacid;
- u64 cfg;
- int count = MAX_LMAC_PER_BGX;
- struct bgx *bgx = dev_get_priv(dev);
- if (!bgx->reg_base)
return 0;
- if (bgx->is_rgx)
count = 1;
- for (lmacid = 0; lmacid < count; lmacid++) {
struct lmac *lmac;
lmac = &bgx->lmac[lmacid];
cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
/* Disable PCS for 1G interface */
if (lmac->lmac_type == BGX_MODE_SGMII ||
lmac->lmac_type == BGX_MODE_QSGMII) {
cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
cfg |= PCS_MRX_CTL_PWR_DN;
bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
}
debug("%s disabling bgx%d lmacid%d\n", __func__, bgx->bgx_id,
lmacid);
bgx_lmac_disable(bgx, lmacid);
- }
- return 0;
+}
+int octeontx_bgx_probe(struct udevice *dev) +{
- struct bgx *bgx = dev_get_priv(dev);
- u8 lmac = 0;
- int qlm[4] = {-1, -1, -1, -1};
- int bgx_idx, node;
- int inc = 1;
- bgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
- if (!bgx->reg_base) {
debug("No PCI region found\n");
return 0;
- }
+#ifdef OCTEONTX_XCV
- /* Use FAKE BGX2 for RGX interface */
- if ((((uintptr_t)bgx->reg_base >> 24) & 0xf) == 0x8) {
bgx->bgx_id = 2;
bgx->is_rgx = true;
for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac++) {
if (lmac == 0) {
bgx->lmac[lmac].lmacid = 0;
bgx->lmac[lmac].qlm = 0;
} else {
bgx->lmac[lmac].qlm = -1;
}
}
xcv_init_hw();
goto skip_qlm_config;
- }
+#endif
- node = node_id(bgx->reg_base);
- bgx_idx = ((uintptr_t)bgx->reg_base >> 24) & 3;
- bgx->bgx_id = (node * MAX_BGX_PER_NODE) + bgx_idx;
- if (otx_is_soc(CN81XX))
inc = 2;
- else if (otx_is_soc(CN83XX) && (bgx_idx == 2))
inc = 2;
- for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac += inc) {
/* BGX3 (DLM4), has only 2 lanes */
if (otx_is_soc(CN83XX) && bgx_idx == 3 && lmac >= 2)
continue;
qlm[lmac + 0] = get_qlm_for_bgx(node, bgx_idx, lmac);
/* Each DLM has 2 lanes, configure both lanes with
* same qlm configuration
*/
if (inc == 2)
qlm[lmac + 1] = qlm[lmac];
debug("qlm[%d] = %d\n", lmac, qlm[lmac]);
- }
- /* A BGX can take 1 or 2 DLMs, if both the DLMs are not configured
* as BGX, then return, nothing to initialize
*/
- if (otx_is_soc(CN81XX))
if ((qlm[0] == -1) && (qlm[2] == -1))
return -ENODEV;
- /* MAP configuration registers */
- for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac++) {
bgx->lmac[lmac].qlm = qlm[lmac];
bgx->lmac[lmac].lmacid = lmac;
- }
+#ifdef OCTEONTX_XCV +skip_qlm_config: +#endif
- bgx_vnic[bgx->bgx_id] = bgx;
- bgx_get_qlm_mode(bgx);
- debug("bgx_vnic[%u]: %p\n", bgx->bgx_id, bgx);
- bgx_init_hw(bgx);
- /* Init LMACs */
- for (lmac = 0; lmac < bgx->lmac_count; lmac++) {
struct lmac *tlmac = &bgx->lmac[lmac];
tlmac->dev = dev;
tlmac->init_pend = 1;
tlmac->bgx = bgx;
- }
- return 0;
+}
+U_BOOT_DRIVER(octeontx_bgx) = {
- .name = "octeontx_bgx",
- .id = UCLASS_MISC,
- .probe = octeontx_bgx_probe,
- .remove = octeontx_bgx_remove,
- .priv_auto_alloc_size = sizeof(struct bgx),
- .flags = DM_FLAG_OS_PREPARE,
+};
+static struct pci_device_id octeontx_bgx_supported[] = {
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_BGX) },
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_RGX) },
- {}
+};
+U_BOOT_PCI_DEVICE(octeontx_bgx, octeontx_bgx_supported); diff --git a/drivers/net/octeontx/bgx.h b/drivers/net/octeontx/bgx.h new file mode 100644 index 0000000000..8402630bf5 --- /dev/null +++ b/drivers/net/octeontx/bgx.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2018 Marvell International Ltd.
- */
+#ifndef BGX_H +#define BGX_H
+#include <asm/arch/board.h>
+/* PCI device IDs */ +#define PCI_DEVICE_ID_OCTEONTX_BGX 0xA026 +#define PCI_DEVICE_ID_OCTEONTX_RGX 0xA054
+#define MAX_LMAC_PER_BGX 4 +#define MAX_BGX_CHANS_PER_LMAC 16 +#define MAX_DMAC_PER_LMAC 8 +#define MAX_FRAME_SIZE 9216
+#define MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE 2
+#define MAX_LMAC (MAX_BGX_PER_NODE * MAX_LMAC_PER_BGX)
+#define NODE_ID_MASK 0x300000000000 +#define NODE_ID(x) (((x) & NODE_ID_MASK) >> 44)
+/* Registers */ +#define GSERX_CFG(x) (0x87E090000080ull + (x) * 0x1000000ull) +#define GSERX_SCRATCH(x) (0x87E090000020ull + (x) * 0x1000000ull) +#define GSERX_PHY_CTL(x) (0x87E090000000ull + (x) * 0x1000000ull) +#define GSERX_CFG_BGX BIT(2) +#define GSER_RX_EIE_DETSTS(x) (0x87E090000150ull + (x) * 0x1000000ull) +#define GSER_CDRLOCK (8) +#define GSER_BR_RXX_CTL(x, y) (0x87E090000400ull + (x) * 0x1000000ull + \
(y) * 0x80)
+#define GSER_BR_RXX_CTL_RXT_SWM BIT(2) +#define GSER_BR_RXX_EER(x, y) (0x87E090000418ull + (x) * 0x1000000ull + \
(y) * 0x80)
+#define GSER_BR_RXX_EER_RXT_ESV BIT(14) +#define GSER_BR_RXX_EER_RXT_EER BIT(15) +#define EER_RXT_ESV (14)
+#define BGX_CMRX_CFG 0x00 +#define CMR_PKT_TX_EN BIT_ULL(13) +#define CMR_PKT_RX_EN BIT_ULL(14) +#define CMR_EN BIT_ULL(15) +#define BGX_CMR_GLOBAL_CFG 0x08 +#define CMR_GLOBAL_CFG_FCS_STRIP BIT_ULL(6) +#define BGX_CMRX_RX_ID_MAP 0x60 +#define BGX_CMRX_RX_STAT0 0x70 +#define BGX_CMRX_RX_STAT1 0x78 +#define BGX_CMRX_RX_STAT2 0x80 +#define BGX_CMRX_RX_STAT3 0x88 +#define BGX_CMRX_RX_STAT4 0x90 +#define BGX_CMRX_RX_STAT5 0x98 +#define BGX_CMRX_RX_STAT6 0xA0 +#define BGX_CMRX_RX_STAT7 0xA8 +#define BGX_CMRX_RX_STAT8 0xB0 +#define BGX_CMRX_RX_STAT9 0xB8 +#define BGX_CMRX_RX_STAT10 0xC0 +#define BGX_CMRX_RX_BP_DROP 0xC8 +#define BGX_CMRX_RX_DMAC_CTL 0x0E8 +#define BGX_CMR_RX_DMACX_CAM 0x200 +#define RX_DMACX_CAM_EN BIT_ULL(48) +#define RX_DMACX_CAM_LMACID(x) ((x) << 49) +#define RX_DMAC_COUNT 32 +#define BGX_CMR_RX_STREERING 0x300 +#define RX_TRAFFIC_STEER_RULE_COUNT 8 +#define BGX_CMR_CHAN_MSK_AND 0x450 +#define BGX_CMR_BIST_STATUS 0x460 +#define BGX_CMR_RX_LMACS 0x468 +#define BGX_CMRX_TX_STAT0 0x600 +#define BGX_CMRX_TX_STAT1 0x608 +#define BGX_CMRX_TX_STAT2 0x610 +#define BGX_CMRX_TX_STAT3 0x618 +#define BGX_CMRX_TX_STAT4 0x620 +#define BGX_CMRX_TX_STAT5 0x628 +#define BGX_CMRX_TX_STAT6 0x630 +#define BGX_CMRX_TX_STAT7 0x638 +#define BGX_CMRX_TX_STAT8 0x640 +#define BGX_CMRX_TX_STAT9 0x648 +#define BGX_CMRX_TX_STAT10 0x650 +#define BGX_CMRX_TX_STAT11 0x658 +#define BGX_CMRX_TX_STAT12 0x660 +#define BGX_CMRX_TX_STAT13 0x668 +#define BGX_CMRX_TX_STAT14 0x670 +#define BGX_CMRX_TX_STAT15 0x678 +#define BGX_CMRX_TX_STAT16 0x680 +#define BGX_CMRX_TX_STAT17 0x688 +#define BGX_CMR_TX_LMACS 0x1000
+#define BGX_SPUX_CONTROL1 0x10000 +#define SPU_CTL_LOW_POWER BIT_ULL(11) +#define SPU_CTL_LOOPBACK BIT_ULL(14) +#define SPU_CTL_RESET BIT_ULL(15) +#define BGX_SPUX_STATUS1 0x10008 +#define SPU_STATUS1_RCV_LNK BIT_ULL(2) +#define BGX_SPUX_STATUS2 0x10020 +#define SPU_STATUS2_RCVFLT BIT_ULL(10) +#define BGX_SPUX_BX_STATUS 0x10028 +#define SPU_BX_STATUS_RX_ALIGN BIT_ULL(12) +#define BGX_SPUX_BR_STATUS1 0x10030 +#define SPU_BR_STATUS_BLK_LOCK BIT_ULL(0) +#define SPU_BR_STATUS_RCV_LNK BIT_ULL(12) +#define BGX_SPUX_BR_PMD_CRTL 0x10068 +#define SPU_PMD_CRTL_TRAIN_EN BIT_ULL(1) +#define BGX_SPUX_BR_PMD_LP_CUP 0x10078 +#define BGX_SPUX_BR_PMD_LD_CUP 0x10088 +#define BGX_SPUX_BR_PMD_LD_REP 0x10090 +#define BGX_SPUX_FEC_CONTROL 0x100A0 +#define SPU_FEC_CTL_FEC_EN BIT_ULL(0) +#define SPU_FEC_CTL_ERR_EN BIT_ULL(1) +#define BGX_SPUX_AN_CONTROL 0x100C8 +#define SPU_AN_CTL_AN_EN BIT_ULL(12) +#define SPU_AN_CTL_XNP_EN BIT_ULL(13) +#define SPU_AN_CTL_AN_RESTART BIT_ULL(15) +#define BGX_SPUX_AN_STATUS 0x100D0 +#define SPU_AN_STS_AN_COMPLETE BIT_ULL(5) +#define BGX_SPUX_AN_ADV 0x100D8 +#define BGX_SPUX_MISC_CONTROL 0x10218 +#define SPU_MISC_CTL_INTLV_RDISP BIT_ULL(10) +#define SPU_MISC_CTL_RX_DIS BIT_ULL(12) +#define BGX_SPUX_INT 0x10220 /* +(0..3) << 20 */ +#define BGX_SPUX_INT_W1S 0x10228 +#define BGX_SPUX_INT_ENA_W1C 0x10230 +#define BGX_SPUX_INT_ENA_W1S 0x10238 +#define BGX_SPU_DBG_CONTROL 0x10300 +#define SPU_DBG_CTL_AN_ARB_LINK_CHK_EN BIT_ULL(18) +#define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29)
+#define BGX_SMUX_RX_INT 0x20000 +#define BGX_SMUX_RX_JABBER 0x20030 +#define BGX_SMUX_RX_CTL 0x20048 +#define SMU_RX_CTL_STATUS (3ull << 0) +#define BGX_SMUX_TX_APPEND 0x20100 +#define SMU_TX_APPEND_FCS_D BIT_ULL(2) +#define BGX_SMUX_TX_MIN_PKT 0x20118 +#define BGX_SMUX_TX_INT 0x20140 +#define BGX_SMUX_TX_CTL 0x20178 +#define SMU_TX_CTL_DIC_EN BIT_ULL(0) +#define SMU_TX_CTL_UNI_EN BIT_ULL(1) +#define SMU_TX_CTL_LNK_STATUS (3ull << 4) +#define BGX_SMUX_TX_THRESH 0x20180 +#define BGX_SMUX_CTL 0x20200 +#define SMU_CTL_RX_IDLE BIT_ULL(0) +#define SMU_CTL_TX_IDLE BIT_ULL(1)
+#define BGX_GMP_PCS_MRX_CTL 0x30000 +#define PCS_MRX_CTL_RST_AN BIT_ULL(9) +#define PCS_MRX_CTL_PWR_DN BIT_ULL(11) +#define PCS_MRX_CTL_AN_EN BIT_ULL(12) +#define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14) +#define PCS_MRX_CTL_RESET BIT_ULL(15) +#define BGX_GMP_PCS_MRX_STATUS 0x30008 +#define PCS_MRX_STATUS_AN_CPT BIT_ULL(5) +#define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020 +#define BGX_GMP_PCS_SGM_AN_ADV 0x30068 +#define BGX_GMP_PCS_MISCX_CTL 0x30078 +#define PCS_MISCX_CTL_DISP_EN BIT_ULL(13) +#define PCS_MISC_CTL_GMX_ENO BIT_ULL(11) +#define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full +#define PCS_MISC_CTL_MODE BIT_ULL(8) +#define BGX_GMP_GMI_PRTX_CFG 0x38020 +#define GMI_PORT_CFG_SPEED BIT_ULL(1) +#define GMI_PORT_CFG_DUPLEX BIT_ULL(2) +#define GMI_PORT_CFG_SLOT_TIME BIT_ULL(3) +#define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8) +#define BGX_GMP_GMI_RXX_JABBER 0x38038 +#define BGX_GMP_GMI_TXX_THRESH 0x38210 +#define BGX_GMP_GMI_TXX_APPEND 0x38218 +#define BGX_GMP_GMI_TXX_SLOT 0x38220 +#define BGX_GMP_GMI_TXX_BURST 0x38228 +#define BGX_GMP_GMI_TXX_MIN_PKT 0x38240 +#define BGX_GMP_GMI_TXX_SGMII_CTL 0x38300
+#define BGX_MSIX_VEC_0_29_ADDR 0x400000 /* +(0..29) << 4 */ +#define BGX_MSIX_VEC_0_29_CTL 0x400008 +#define BGX_MSIX_PBA_0 0x4F0000
+/* MSI-X interrupts */ +#define BGX_MSIX_VECTORS 30 +#define BGX_LMAC_VEC_OFFSET 7 +#define BGX_MSIX_VEC_SHIFT 4
+#define CMRX_INT 0 +#define SPUX_INT 1 +#define SMUX_RX_INT 2 +#define SMUX_TX_INT 3 +#define GMPX_PCS_INT 4 +#define GMPX_GMI_RX_INT 5 +#define GMPX_GMI_TX_INT 6 +#define CMR_MEM_INT 28 +#define SPU_MEM_INT 29
+#define LMAC_INTR_LINK_UP BIT(0) +#define LMAC_INTR_LINK_DOWN BIT(1)
+/* RX_DMAC_CTL configuration*/ +enum MCAST_MODE {
MCAST_MODE_REJECT,
MCAST_MODE_ACCEPT,
MCAST_MODE_CAM_FILTER,
RSVD
+};
+#define BCAST_ACCEPT 1 +#define CAM_ACCEPT 1
+int octeontx_bgx_initialize(unsigned int bgx_idx, unsigned int node); +void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac); +void bgx_get_count(int node, int *bgx_count); +int bgx_get_lmac_count(int node, int bgx); +void bgx_print_stats(int bgx_idx, int lmac); +void xcv_init_hw(void); +void xcv_setup_link(bool link_up, int link_speed);
+#undef LINK_INTR_ENABLE
+enum qlm_mode {
- QLM_MODE_SGMII, /* SGMII, each lane independent */
- QLM_MODE_XAUI, /* 1 XAUI or DXAUI, 4 lanes */
- QLM_MODE_RXAUI, /* 2 RXAUI, 2 lanes each */
- QLM_MODE_XFI, /* 4 XFI, 1 lane each */
- QLM_MODE_XLAUI, /* 1 XLAUI, 4 lanes each */
- QLM_MODE_10G_KR, /* 4 10GBASE-KR, 1 lane each */
- QLM_MODE_40G_KR4, /* 1 40GBASE-KR4, 4 lanes each */
- QLM_MODE_QSGMII, /* 4 QSGMII, each lane independent */
- QLM_MODE_RGMII, /* 1 RGX */
+};
+struct phy_info {
- int mdio_bus;
- int phy_addr;
- bool autoneg_dis;
+};
+struct bgx_board_info {
- struct phy_info phy_info[MAX_LMAC_PER_BGX];
- bool lmac_reg[MAX_LMAC_PER_BGX];
- bool lmac_enable[MAX_LMAC_PER_BGX];
+};
+enum LMAC_TYPE {
- BGX_MODE_SGMII = 0, /* 1 lane, 1.250 Gbaud */
- BGX_MODE_XAUI = 1, /* 4 lanes, 3.125 Gbaud */
- BGX_MODE_DXAUI = 1, /* 4 lanes, 6.250 Gbaud */
- BGX_MODE_RXAUI = 2, /* 2 lanes, 6.250 Gbaud */
- BGX_MODE_XFI = 3, /* 1 lane, 10.3125 Gbaud */
- BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */
- BGX_MODE_10G_KR = 3,/* 1 lane, 10.3125 Gbaud */
- BGX_MODE_40G_KR = 4,/* 4 lanes, 10.3125 Gbaud */
- BGX_MODE_RGMII = 5,
- BGX_MODE_QSGMII = 6,
- BGX_MODE_INVALID = 7,
+};
+int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr);
+#endif /* BGX_H */ diff --git a/drivers/net/octeontx/nic.h b/drivers/net/octeontx/nic.h new file mode 100644 index 0000000000..af3576cfbb --- /dev/null +++ b/drivers/net/octeontx/nic.h @@ -0,0 +1,508 @@ +/* SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2018 Marvell International Ltd.
- */
+#ifndef NIC_H +#define NIC_H
+#include <linux/netdevice.h> +#include "bgx.h"
+#define PCI_DEVICE_ID_CAVIUM_NICVF_1 0x0011
+/* Subsystem device IDs */ +#define PCI_SUBSYS_DEVID_88XX_NIC_PF 0xA11E +#define PCI_SUBSYS_DEVID_81XX_NIC_PF 0xA21E +#define PCI_SUBSYS_DEVID_83XX_NIC_PF 0xA31E
+#define PCI_SUBSYS_DEVID_88XX_PASS1_NIC_VF 0xA11E +#define PCI_SUBSYS_DEVID_88XX_NIC_VF 0xA134 +#define PCI_SUBSYS_DEVID_81XX_NIC_VF 0xA234 +#define PCI_SUBSYS_DEVID_83XX_NIC_VF 0xA334
+#define NIC_INTF_COUNT 2 /* Interfaces btw VNIC and TNS/BGX */ +#define NIC_CHANS_PER_INF 128 +#define NIC_MAX_CHANS (NIC_INTF_COUNT * NIC_CHANS_PER_INF)
+/* PCI BAR nos */ +#define PCI_CFG_REG_BAR_NUM 0 +#define PCI_MSIX_REG_BAR_NUM 4
+/* NIC SRIOV VF count */ +#define MAX_NUM_VFS_SUPPORTED 128 +#define DEFAULT_NUM_VF_ENABLED 8
+#define NIC_TNS_BYPASS_MODE 0 +#define NIC_TNS_MODE 1
+/* NIC priv flags */ +#define NIC_SRIOV_ENABLED BIT(0) +#define NIC_TNS_ENABLED BIT(1)
+/* VNIC HW optimiation features */ +#define VNIC_RX_CSUM_OFFLOAD_SUPPORT +#undef VNIC_TX_CSUM_OFFLOAD_SUPPORT +#undef VNIC_SG_SUPPORT +#undef VNIC_TSO_SUPPORT +#undef VNIC_LRO_SUPPORT +#undef VNIC_RSS_SUPPORT
+/* TSO not supported in Thunder pass1 */ +#ifdef VNIC_TSO_SUPPORT +#define VNIC_SW_TSO_SUPPORT +#undef VNIC_HW_TSO_SUPPORT +#endif
+/* ETHTOOL enable or disable, undef this to disable */ +#define NICVF_ETHTOOL_ENABLE
+/* Min/Max packet size */ +#define NIC_HW_MIN_FRS 64 +#define NIC_HW_MAX_FRS 9200 /* 9216 max packet including FCS */
+/* Max pkinds */ +#define NIC_MAX_PKIND 16
+/* Max when CPI_ALG is IP diffserv */ +#define NIC_MAX_CPI_PER_LMAC 64
+/* NIC VF Interrupts */ +#define NICVF_INTR_CQ 0 +#define NICVF_INTR_SQ 1 +#define NICVF_INTR_RBDR 2 +#define NICVF_INTR_PKT_DROP 3 +#define NICVF_INTR_TCP_TIMER 4 +#define NICVF_INTR_MBOX 5 +#define NICVF_INTR_QS_ERR 6
+#define NICVF_INTR_CQ_SHIFT 0 +#define NICVF_INTR_SQ_SHIFT 8 +#define NICVF_INTR_RBDR_SHIFT 16 +#define NICVF_INTR_PKT_DROP_SHIFT 20 +#define NICVF_INTR_TCP_TIMER_SHIFT 21 +#define NICVF_INTR_MBOX_SHIFT 22 +#define NICVF_INTR_QS_ERR_SHIFT 23
+#define NICVF_INTR_CQ_MASK (0xFF << NICVF_INTR_CQ_SHIFT) +#define NICVF_INTR_SQ_MASK (0xFF << NICVF_INTR_SQ_SHIFT) +#define NICVF_INTR_RBDR_MASK (0x03 << NICVF_INTR_RBDR_SHIFT) +#define NICVF_INTR_PKT_DROP_MASK BIT(NICVF_INTR_PKT_DROP_SHIFT) +#define NICVF_INTR_TCP_TIMER_MASK BIT(NICVF_INTR_TCP_TIMER_SHIFT) +#define NICVF_INTR_MBOX_MASK BIT(NICVF_INTR_MBOX_SHIFT) +#define NICVF_INTR_QS_ERR_MASK BIT(NICVF_INTR_QS_ERR_SHIFT)
+/* MSI-X interrupts */ +#define NIC_PF_MSIX_VECTORS 10 +#define NIC_VF_MSIX_VECTORS 20
+#define NIC_PF_INTR_ID_ECC0_SBE 0 +#define NIC_PF_INTR_ID_ECC0_DBE 1 +#define NIC_PF_INTR_ID_ECC1_SBE 2 +#define NIC_PF_INTR_ID_ECC1_DBE 3 +#define NIC_PF_INTR_ID_ECC2_SBE 4 +#define NIC_PF_INTR_ID_ECC2_DBE 5 +#define NIC_PF_INTR_ID_ECC3_SBE 6 +#define NIC_PF_INTR_ID_ECC3_DBE 7 +#define NIC_PF_INTR_ID_MBOX0 8 +#define NIC_PF_INTR_ID_MBOX1 9
+/* Global timer for CQ timer thresh interrupts
- Calculated for SCLK of 700Mhz
- value written should be a 1/16thof what is expected
- 1 tick per ms
- */
+#define NICPF_CLK_PER_INT_TICK 43750
+struct nicvf_cq_poll {
- u8 cq_idx; /* Completion queue index */
+};
+#define NIC_MAX_RSS_HASH_BITS 8 +#define NIC_MAX_RSS_IDR_TBL_SIZE BIT(NIC_MAX_RSS_HASH_BITS) +#define RSS_HASH_KEY_SIZE 5 /* 320 bit key */
+#ifdef VNIC_RSS_SUPPORT +struct nicvf_rss_info {
- bool enable;
+#define RSS_L2_EXTENDED_HASH_ENA BIT(0) +#define RSS_IP_HASH_ENA BIT(1) +#define RSS_TCP_HASH_ENA BIT(2) +#define RSS_TCP_SYN_DIS BIT(3) +#define RSS_UDP_HASH_ENA BIT(4) +#define RSS_L4_EXTENDED_HASH_ENA BIT(5) +#define RSS_ROCE_ENA BIT(6) +#define RSS_L3_BI_DIRECTION_ENA BIT(7) +#define RSS_L4_BI_DIRECTION_ENA BIT(8)
- u64 cfg;
- u8 hash_bits;
- u16 rss_size;
- u8 ind_tbl[NIC_MAX_RSS_IDR_TBL_SIZE];
- u64 key[RSS_HASH_KEY_SIZE];
+}; +#endif
+enum rx_stats_reg_offset {
- RX_OCTS = 0x0,
- RX_UCAST = 0x1,
- RX_BCAST = 0x2,
- RX_MCAST = 0x3,
- RX_RED = 0x4,
- RX_RED_OCTS = 0x5,
- RX_ORUN = 0x6,
- RX_ORUN_OCTS = 0x7,
- RX_FCS = 0x8,
- RX_L2ERR = 0x9,
- RX_DRP_BCAST = 0xa,
- RX_DRP_MCAST = 0xb,
- RX_DRP_L3BCAST = 0xc,
- RX_DRP_L3MCAST = 0xd,
- RX_STATS_ENUM_LAST,
+};
+enum tx_stats_reg_offset {
- TX_OCTS = 0x0,
- TX_UCAST = 0x1,
- TX_BCAST = 0x2,
- TX_MCAST = 0x3,
- TX_DROP = 0x4,
- TX_STATS_ENUM_LAST,
+};
+struct nicvf_hw_stats {
- u64 rx_bytes_ok;
- u64 rx_ucast_frames_ok;
- u64 rx_bcast_frames_ok;
- u64 rx_mcast_frames_ok;
- u64 rx_fcs_errors;
- u64 rx_l2_errors;
- u64 rx_drop_red;
- u64 rx_drop_red_bytes;
- u64 rx_drop_overrun;
- u64 rx_drop_overrun_bytes;
- u64 rx_drop_bcast;
- u64 rx_drop_mcast;
- u64 rx_drop_l3_bcast;
- u64 rx_drop_l3_mcast;
- u64 tx_bytes_ok;
- u64 tx_ucast_frames_ok;
- u64 tx_bcast_frames_ok;
- u64 tx_mcast_frames_ok;
- u64 tx_drops;
+};
+struct nicvf_drv_stats {
- /* Rx */
- u64 rx_frames_ok;
- u64 rx_frames_64;
- u64 rx_frames_127;
- u64 rx_frames_255;
- u64 rx_frames_511;
- u64 rx_frames_1023;
- u64 rx_frames_1518;
- u64 rx_frames_jumbo;
- u64 rx_drops;
- /* Tx */
- u64 tx_frames_ok;
- u64 tx_drops;
- u64 tx_busy;
- u64 tx_tso;
+};
+struct hw_info {
- u8 bgx_cnt;
- u8 chans_per_lmac;
- u8 chans_per_bgx; /* Rx/Tx chans */
- u8 chans_per_rgx;
- u8 chans_per_lbk;
- u16 cpi_cnt;
- u16 rssi_cnt;
- u16 rss_ind_tbl_size;
- u16 tl4_cnt;
- u16 tl3_cnt;
- u8 tl2_cnt;
- u8 tl1_cnt;
- bool tl1_per_bgx; /* TL1 per BGX or per LMAC */
- u8 model_id;
+};
+struct nicvf {
- struct udevice *dev;
- u8 vf_id;
- bool sqs_mode:1;
- bool loopback_supported:1;
- u8 tns_mode;
- u8 node;
- u16 mtu;
- struct queue_set *qs;
+#define MAX_SQS_PER_VF_SINGLE_NODE 5 +#define MAX_SQS_PER_VF 11
- u8 num_qs;
- void *addnl_qs;
- u16 vf_mtu;
- void __iomem *reg_base;
+#define MAX_QUEUES_PER_QSET 8
- struct nicvf_cq_poll *napi[8];
- u8 cpi_alg;
- struct nicvf_hw_stats stats;
- struct nicvf_drv_stats drv_stats;
- struct nicpf *nicpf;
- /* VF <-> PF mailbox communication */
- bool pf_acked;
- bool pf_nacked;
- bool set_mac_pending;
- bool link_up;
- u8 duplex;
- u32 speed;
- u8 rev_id;
- u8 rx_queues;
- u8 tx_queues;
- bool open;
- bool rb_alloc_fail;
- void *rcv_buf;
- bool hw_tso;
+};
+static inline int node_id(void *addr) +{
- return ((uintptr_t)addr >> 44) & 0x3;
+}
+struct nicpf {
- struct udevice *udev;
- struct hw_info *hw;
- u8 node;
- unsigned int flags;
- u16 total_vf_cnt; /* Total num of VF supported */
- u16 num_vf_en; /* No of VF enabled */
- void __iomem *reg_base; /* Register start address */
- u16 rss_ind_tbl_size;
- u8 num_sqs_en; /* Secondary qsets enabled */
- u64 nicvf[MAX_NUM_VFS_SUPPORTED];
- u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF];
- u8 pqs_vf[MAX_NUM_VFS_SUPPORTED];
- bool sqs_used[MAX_NUM_VFS_SUPPORTED];
- struct pkind_cfg pkind;
- u8 bgx_cnt;
- u8 rev_id;
+#define NIC_SET_VF_LMAC_MAP(bgx, lmac) ((((bgx) & 0xF) << 4) | ((lmac) & 0xF)) +#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) (((map) >> 4) & 0xF) +#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) ((map) & 0xF)
- u8 vf_lmac_map[MAX_LMAC];
- u16 cpi_base[MAX_NUM_VFS_SUPPORTED];
- u64 mac[MAX_NUM_VFS_SUPPORTED];
- bool mbx_lock[MAX_NUM_VFS_SUPPORTED];
- u8 link[MAX_LMAC];
- u8 duplex[MAX_LMAC];
- u32 speed[MAX_LMAC];
- bool vf_enabled[MAX_NUM_VFS_SUPPORTED];
- u16 rssi_base[MAX_NUM_VFS_SUPPORTED];
- u8 lmac_cnt;
+};
+/* PF <--> VF Mailbox communication
- Eight 64bit registers are shared between PF and VF.
- Separate set for each VF.
- Writing '1' into last register mbx7 means end of message.
- */
+/* PF <--> VF mailbox communication */ +#define NIC_PF_VF_MAILBOX_SIZE 2 +#define NIC_PF_VF_MBX_TIMEOUT 2000 /* ms */
+/* Mailbox message types */ +#define NIC_MBOX_MSG_READY 0x01 /* Is PF ready to rcv msgs */ +#define NIC_MBOX_MSG_ACK 0x02 /* ACK the message received */ +#define NIC_MBOX_MSG_NACK 0x03 /* NACK the message received */ +#define NIC_MBOX_MSG_QS_CFG 0x04 /* Configure Qset */ +#define NIC_MBOX_MSG_RQ_CFG 0x05 /* Configure receive queue */ +#define NIC_MBOX_MSG_SQ_CFG 0x06 /* Configure Send queue */ +#define NIC_MBOX_MSG_RQ_DROP_CFG 0x07 /* Configure receive queue */ +#define NIC_MBOX_MSG_SET_MAC 0x08 /* Add MAC ID to DMAC filter */ +#define NIC_MBOX_MSG_SET_MAX_FRS 0x09 /* Set max frame size */ +#define NIC_MBOX_MSG_CPI_CFG 0x0A /* Config CPI, RSSI */ +#define NIC_MBOX_MSG_RSS_SIZE 0x0B /* Get RSS indir_tbl size */ +#define NIC_MBOX_MSG_RSS_CFG 0x0C /* Config RSS table */ +#define NIC_MBOX_MSG_RSS_CFG_CONT 0x0D /* RSS config continuation */ +#define NIC_MBOX_MSG_RQ_BP_CFG 0x0E /* RQ backpressure config */ +#define NIC_MBOX_MSG_RQ_SW_SYNC 0x0F /* Flush inflight pkts to RQ */ +#define NIC_MBOX_MSG_BGX_STATS 0x10 /* Get stats from BGX */ +#define NIC_MBOX_MSG_BGX_LINK_CHANGE 0x11 /* BGX:LMAC link status */ +#define NIC_MBOX_MSG_ALLOC_SQS 0x12 /* Allocate secondary Qset */ +#define NIC_MBOX_MSG_NICVF_PTR 0x13 /* Send nicvf ptr to PF */ +#define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */ +#define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */ +#define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ +#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ +#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
+struct nic_cfg_msg {
- u8 msg;
- u8 vf_id;
- u8 node_id;
- bool tns_mode:1;
- bool sqs_mode:1;
- bool loopback_supported:1;
- u8 mac_addr[6];
+};
+/* Qset configuration */ +struct qs_cfg_msg {
- u8 msg;
- u8 num;
- u8 sqs_count;
- u64 cfg;
+};
+/* Receive queue configuration */ +struct rq_cfg_msg {
- u8 msg;
- u8 qs_num;
- u8 rq_num;
- u64 cfg;
+};
+/* Send queue configuration */ +struct sq_cfg_msg {
- u8 msg;
- u8 qs_num;
- u8 sq_num;
- bool sqs_mode;
- u64 cfg;
+};
+/* Set VF's MAC address */ +struct set_mac_msg {
- u8 msg;
- u8 vf_id;
- u8 mac_addr[6];
+};
+/* Set Maximum frame size */ +struct set_frs_msg {
- u8 msg;
- u8 vf_id;
- u16 max_frs;
+};
+/* Set CPI algorithm type */ +struct cpi_cfg_msg {
- u8 msg;
- u8 vf_id;
- u8 rq_cnt;
- u8 cpi_alg;
+};
+/* Get RSS table size */ +struct rss_sz_msg {
- u8 msg;
- u8 vf_id;
- u16 ind_tbl_size;
+};
+/* Set RSS configuration */ +struct rss_cfg_msg {
- u8 msg;
- u8 vf_id;
- u8 hash_bits;
- u8 tbl_len;
- u8 tbl_offset;
+#define RSS_IND_TBL_LEN_PER_MBX_MSG 8
- u8 ind_tbl[RSS_IND_TBL_LEN_PER_MBX_MSG];
+};
+struct bgx_stats_msg {
- u8 msg;
- u8 vf_id;
- u8 rx;
- u8 idx;
- u64 stats;
+};
+/* Physical interface link status */ +struct bgx_link_status {
- u8 msg;
- u8 link_up;
- u8 duplex;
- u32 speed;
+};
+#ifdef VNIC_MULTI_QSET_SUPPORT +/* Get Extra Qset IDs */ +struct sqs_alloc {
- u8 msg;
- u8 vf_id;
- u8 qs_count;
+};
+struct nicvf_ptr {
- u8 msg;
- u8 vf_id;
- bool sqs_mode;
- u8 sqs_id;
- u64 nicvf;
+}; +#endif
+/* Set interface in loopback mode */ +struct set_loopback {
- u8 msg;
- u8 vf_id;
- bool enable;
+};
+/* 128 bit shared memory between PF and each VF */ +union nic_mbx {
- struct { u8 msg; } msg;
- struct nic_cfg_msg nic_cfg;
- struct qs_cfg_msg qs;
- struct rq_cfg_msg rq;
- struct sq_cfg_msg sq;
- struct set_mac_msg mac;
- struct set_frs_msg frs;
- struct cpi_cfg_msg cpi_cfg;
- struct rss_sz_msg rss_size;
- struct rss_cfg_msg rss_cfg;
- struct bgx_stats_msg bgx_stats;
- struct bgx_link_status link_status;
+#ifdef VNIC_MULTI_QSET_SUPPORT
- struct sqs_alloc sqs_alloc;
- struct nicvf_ptr nicvf;
+#endif
- struct set_loopback lbk;
+};
+int nicvf_set_real_num_queues(struct udevice *dev,
int tx_queues, int rx_queues);
+int nicvf_open(struct udevice *dev); +void nicvf_stop(struct udevice *dev); +int nicvf_send_msg_to_pf(struct nicvf *vf, union nic_mbx *mbx); +void nicvf_update_stats(struct nicvf *nic);
+void nic_handle_mbx_intr(struct nicpf *nic, int vf);
+int bgx_poll_for_link(int node, int bgx_idx, int lmacid); +const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid); +void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac); +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable); +void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable);
+static inline bool pass1_silicon(unsigned int revision, int model_id) +{
- return ((revision < 8) && (model_id == 0x88));
+}
+static inline bool pass2_silicon(unsigned int revision, int model_id) +{
- return ((revision >= 8) && (model_id == 0x88));
+}
+#endif /* NIC_H */ diff --git a/drivers/net/octeontx/nic_main.c b/drivers/net/octeontx/nic_main.c new file mode 100644 index 0000000000..1a805f7a46 --- /dev/null +++ b/drivers/net/octeontx/nic_main.c @@ -0,0 +1,778 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <config.h> +#include <net.h> +#include <netdev.h> +#include <malloc.h> +#include <miiphy.h> +#include <dm.h> +#include <misc.h> +#include <pci.h> +#include <pci_ids.h> +#include <asm/io.h> +#include <linux/delay.h>
+#include "nic_reg.h" +#include "nic.h" +#include "q_struct.h"
+unsigned long rounddown_pow_of_two(unsigned long n) +{
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- n |= n >> 32;
- return(n + 1);
+}
+static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg); +static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
struct sq_cfg_msg *sq);
+static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf); +static int nic_rcv_queue_sw_sync(struct nicpf *nic);
+/* Register read/write APIs */ +static void nic_reg_write(struct nicpf *nic, u64 offset, u64 val) +{
- writeq(val, nic->reg_base + offset);
+}
+static u64 nic_reg_read(struct nicpf *nic, u64 offset) +{
- return readq(nic->reg_base + offset);
+}
+static u64 nic_get_mbx_addr(int vf) +{
- return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT);
+}
+static void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) +{
- void __iomem *mbx_addr = (void *)(nic->reg_base + nic_get_mbx_addr(vf));
- u64 *msg = (u64 *)mbx;
- /* In first revision HW, mbox interrupt is triggerred
* when PF writes to MBOX(1), in next revisions when
* PF writes to MBOX(0)
*/
- if (pass1_silicon(nic->rev_id, nic->hw->model_id)) {
/* see the comment for nic_reg_write()/nic_reg_read()
* functions above
*/
writeq(msg[0], mbx_addr);
writeq(msg[1], mbx_addr + 8);
- } else {
writeq(msg[1], mbx_addr + 8);
writeq(msg[0], mbx_addr);
- }
+}
+static void nic_mbx_send_ready(struct nicpf *nic, int vf) +{
- union nic_mbx mbx = {};
- int bgx_idx, lmac, timeout = 5, link = -1;
- const u8 *mac;
- mbx.nic_cfg.msg = NIC_MBOX_MSG_READY;
- mbx.nic_cfg.vf_id = vf;
- if (nic->flags & NIC_TNS_ENABLED)
mbx.nic_cfg.tns_mode = NIC_TNS_MODE;
- else
mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
- if (vf < nic->num_vf_en) {
bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac);
if (mac)
memcpy((u8 *)&mbx.nic_cfg.mac_addr, mac, 6);
while (timeout-- && (link <= 0)) {
link = bgx_poll_for_link(nic->node, bgx_idx, lmac);
debug("Link status: %d\n", link);
if (link <= 0)
mdelay(2000);
}
- }
+#ifdef VNIC_MULTI_QSET_SUPPORT
- mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false;
+#endif
- mbx.nic_cfg.node_id = nic->node;
- mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en;
- nic_send_msg_to_vf(nic, vf, &mbx);
+}
+/* ACKs VF's mailbox message
- @vf: VF to which ACK to be sent
- */
+static void nic_mbx_send_ack(struct nicpf *nic, int vf) +{
- union nic_mbx mbx = {};
- mbx.msg.msg = NIC_MBOX_MSG_ACK;
- nic_send_msg_to_vf(nic, vf, &mbx);
+}
+/* NACKs VF's mailbox message that PF is not able to
- complete the action
- @vf: VF to which ACK to be sent
- */
+static void nic_mbx_send_nack(struct nicpf *nic, int vf) +{
- union nic_mbx mbx = {};
- mbx.msg.msg = NIC_MBOX_MSG_NACK;
- nic_send_msg_to_vf(nic, vf, &mbx);
+}
+static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) +{
- int bgx_idx, lmac_idx;
- if (lbk->vf_id > nic->num_vf_en)
return -1;
- bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
- lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
- bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
- return 0;
+}
+/* Interrupt handler to handle mailbox messages from VFs */ +void nic_handle_mbx_intr(struct nicpf *nic, int vf) +{
- union nic_mbx mbx = {};
- u64 *mbx_data;
- u64 mbx_addr;
- u64 reg_addr;
- u64 cfg;
- int bgx, lmac;
- int i;
- int ret = 0;
- nic->mbx_lock[vf] = true;
- mbx_addr = nic_get_mbx_addr(vf);
- mbx_data = (u64 *)&mbx;
- for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
*mbx_data = nic_reg_read(nic, mbx_addr);
mbx_data++;
mbx_addr += sizeof(u64);
- }
- debug("%s: Mailbox msg %d from VF%d\n", __func__, mbx.msg.msg, vf);
- switch (mbx.msg.msg) {
- case NIC_MBOX_MSG_READY:
nic_mbx_send_ready(nic, vf);
if (vf < nic->num_vf_en) {
nic->link[vf] = 0;
nic->duplex[vf] = 0;
nic->speed[vf] = 0;
}
ret = 1;
break;
- case NIC_MBOX_MSG_QS_CFG:
reg_addr = NIC_PF_QSET_0_127_CFG |
(mbx.qs.num << NIC_QS_ID_SHIFT);
cfg = mbx.qs.cfg;
+#ifdef VNIC_MULTI_QSET_SUPPORT
/* Check if its a secondary Qset */
if (vf >= nic->num_vf_en) {
cfg = cfg & (~0x7FULL);
/* Assign this Qset to primary Qset's VF */
cfg |= nic->pqs_vf[vf];
}
+#endif
nic_reg_write(nic, reg_addr, cfg);
break;
- case NIC_MBOX_MSG_RQ_CFG:
reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG |
(mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
(mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
nic_reg_write(nic, reg_addr, mbx.rq.cfg);
/* Enable CQE_RX2_S extension in CQE_RX descriptor.
* This gets appended by default on 81xx/83xx chips,
* for consistency enabling the same on 88xx pass2
* where this is introduced.
*/
if (pass2_silicon(nic->rev_id, nic->hw->model_id))
nic_reg_write(nic, NIC_PF_RX_CFG, 0x01);
break;
- case NIC_MBOX_MSG_RQ_BP_CFG:
reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
(mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
(mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
nic_reg_write(nic, reg_addr, mbx.rq.cfg);
break;
- case NIC_MBOX_MSG_RQ_SW_SYNC:
ret = nic_rcv_queue_sw_sync(nic);
break;
- case NIC_MBOX_MSG_RQ_DROP_CFG:
reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG |
(mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
(mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
nic_reg_write(nic, reg_addr, mbx.rq.cfg);
break;
- case NIC_MBOX_MSG_SQ_CFG:
reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG |
(mbx.sq.qs_num << NIC_QS_ID_SHIFT) |
(mbx.sq.sq_num << NIC_Q_NUM_SHIFT);
nic_reg_write(nic, reg_addr, mbx.sq.cfg);
nic_tx_channel_cfg(nic, mbx.qs.num,
(struct sq_cfg_msg *)&mbx.sq);
break;
- case NIC_MBOX_MSG_SET_MAC:
+#ifdef VNIC_MULTI_QSET_SUPPORT
if (vf >= nic->num_vf_en)
break;
+#endif
lmac = mbx.mac.vf_id;
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr);
break;
- case NIC_MBOX_MSG_SET_MAX_FRS:
ret = nic_update_hw_frs(nic, mbx.frs.max_frs,
mbx.frs.vf_id);
break;
- case NIC_MBOX_MSG_CPI_CFG:
nic_config_cpi(nic, &mbx.cpi_cfg);
break;
+#ifdef VNIC_RSS_SUPPORT
- case NIC_MBOX_MSG_RSS_SIZE:
nic_send_rss_size(nic, vf);
goto unlock;
- case NIC_MBOX_MSG_RSS_CFG:
- case NIC_MBOX_MSG_RSS_CFG_CONT:
nic_config_rss(nic, &mbx.rss_cfg);
break;
+#endif
- case NIC_MBOX_MSG_CFG_DONE:
/* Last message of VF config msg sequence */
nic->vf_enabled[vf] = true;
if (vf >= nic->lmac_cnt)
goto unlock;
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, true);
goto unlock;
- case NIC_MBOX_MSG_SHUTDOWN:
/* First msg in VF teardown sequence */
nic->vf_enabled[vf] = false;
+#ifdef VNIC_MULTI_QSET_SUPPORT
if (vf >= nic->num_vf_en)
nic->sqs_used[vf - nic->num_vf_en] = false;
nic->pqs_vf[vf] = 0;
+#endif
if (vf >= nic->lmac_cnt)
break;
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, false);
break;
+#ifdef VNIC_MULTI_QSET_SUPPORT
- case NIC_MBOX_MSG_ALLOC_SQS:
nic_alloc_sqs(nic, &mbx.sqs_alloc);
goto unlock;
- case NIC_MBOX_MSG_NICVF_PTR:
nic->nicvf[vf] = mbx.nicvf.nicvf;
break;
- case NIC_MBOX_MSG_PNICVF_PTR:
nic_send_pnicvf(nic, vf);
goto unlock;
- case NIC_MBOX_MSG_SNICVF_PTR:
nic_send_snicvf(nic, &mbx.nicvf);
goto unlock;
+#endif
- case NIC_MBOX_MSG_LOOPBACK:
ret = nic_config_loopback(nic, &mbx.lbk);
break;
- default:
printf("Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
break;
- }
- if (!ret)
nic_mbx_send_ack(nic, vf);
- else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
nic_mbx_send_nack(nic, vf);
+unlock:
- nic->mbx_lock[vf] = false;
+}
+static int nic_rcv_queue_sw_sync(struct nicpf *nic) +{
- int timeout = 20;
- nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01);
- while (timeout) {
if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1)
break;
udelay(2000);
timeout--;
- }
- nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00);
- if (!timeout) {
printf("Recevie queue software sync failed");
return 1;
- }
- return 0;
+}
+static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) +{
- u64 *pkind = (u64 *)&nic->pkind;
- if (new_frs > NIC_HW_MAX_FRS || new_frs < NIC_HW_MIN_FRS) {
printf("Invalid MTU setting from VF%d rejected,", vf);
printf(" should be between %d and %d\n", NIC_HW_MIN_FRS,
NIC_HW_MAX_FRS);
return 1;
- }
- new_frs += ETH_HLEN;
- if (new_frs <= nic->pkind.maxlen)
return 0;
- nic->pkind.maxlen = new_frs;
- nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *pkind);
- return 0;
+}
+/* Set minimum transmit packet size */ +static void nic_set_tx_pkt_pad(struct nicpf *nic, int size) +{
- int lmac;
- u64 lmac_cfg;
- struct hw_info *hw = nic->hw;
- int max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX;
- /* Max value that can be set is 60 */
- if (size > 52)
size = 52;
- /* CN81XX has RGX configured as FAKE BGX, adjust mac_lmac accordingly */
- if (hw->chans_per_rgx)
max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1;
- for (lmac = 0; lmac < max_lmac; lmac++) {
lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
lmac_cfg &= ~(0xF << 2);
lmac_cfg |= ((size / 4) << 2);
nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg);
- }
+}
+/* Function to check number of LMACs present and set VF to LMAC mapping.
- Mapping will be used while initializing channels.
- */
+static void nic_set_lmac_vf_mapping(struct nicpf *nic) +{
- int bgx, bgx_count, next_bgx_lmac = 0;
- int lmac, lmac_cnt = 0;
- u64 lmac_credit;
- nic->num_vf_en = 0;
- if (nic->flags & NIC_TNS_ENABLED) {
nic->num_vf_en = DEFAULT_NUM_VF_ENABLED;
return;
- }
- bgx_get_count(nic->node, &bgx_count);
- debug("bgx_count: %d\n", bgx_count);
- for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) {
if (!(bgx_count & (1 << bgx)))
continue;
nic->bgx_cnt++;
lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
debug("lmac_cnt: %d for BGX%d\n", lmac_cnt, bgx);
for (lmac = 0; lmac < lmac_cnt; lmac++)
nic->vf_lmac_map[next_bgx_lmac++] =
NIC_SET_VF_LMAC_MAP(bgx, lmac);
nic->num_vf_en += lmac_cnt;
/* Program LMAC credits */
lmac_credit = (1ull << 1); /* chennel credit enable */
lmac_credit |= (0x1ff << 2);
lmac_credit |= (((((48 * 1024) / lmac_cnt) -
NIC_HW_MAX_FRS) / 16) << 12);
lmac = bgx * MAX_LMAC_PER_BGX;
for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++)
nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
lmac_credit);
- }
+}
+static void nic_get_hw_info(struct nicpf *nic) +{
- u16 sdevid;
- struct hw_info *hw = nic->hw;
- dm_pci_read_config16(nic->udev, PCI_SUBSYSTEM_ID, &sdevid);
- switch (sdevid) {
- case PCI_SUBSYS_DEVID_88XX_NIC_PF:
hw->bgx_cnt = MAX_BGX_PER_NODE;
hw->chans_per_lmac = 16;
hw->chans_per_bgx = 128;
hw->cpi_cnt = 2048;
hw->rssi_cnt = 4096;
hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
hw->tl3_cnt = 256;
hw->tl2_cnt = 64;
hw->tl1_cnt = 2;
hw->tl1_per_bgx = true;
hw->model_id = 0x88;
break;
- case PCI_SUBSYS_DEVID_81XX_NIC_PF:
hw->bgx_cnt = MAX_BGX_PER_NODE;
hw->chans_per_lmac = 8;
hw->chans_per_bgx = 32;
hw->chans_per_rgx = 8;
hw->chans_per_lbk = 24;
hw->cpi_cnt = 512;
hw->rssi_cnt = 256;
hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */
hw->tl3_cnt = 64;
hw->tl2_cnt = 16;
hw->tl1_cnt = 10;
hw->tl1_per_bgx = false;
hw->model_id = 0x81;
break;
- case PCI_SUBSYS_DEVID_83XX_NIC_PF:
hw->bgx_cnt = MAX_BGX_PER_NODE;
hw->chans_per_lmac = 8;
hw->chans_per_bgx = 32;
hw->chans_per_lbk = 64;
hw->cpi_cnt = 2048;
hw->rssi_cnt = 1024;
hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */
hw->tl3_cnt = 256;
hw->tl2_cnt = 64;
hw->tl1_cnt = 18;
hw->tl1_per_bgx = false;
hw->model_id = 0x83;
break;
- }
- hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->udev);
+}
+static void nic_init_hw(struct nicpf *nic) +{
- int i;
- u64 reg;
- u64 *pkind = (u64 *)&nic->pkind;
- /* Get HW capability info */
- nic_get_hw_info(nic);
- /* Enable NIC HW block */
- nic_reg_write(nic, NIC_PF_CFG, 0x3);
- /* Enable backpressure */
- nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03);
- nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, (1ULL << 63) | 0x08);
- nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
(1ULL << 63) | 0x09);
- for (i = 0; i < NIC_MAX_CHANS; i++)
nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (i << 3), 1);
- if (nic->flags & NIC_TNS_ENABLED) {
reg = NIC_TNS_MODE << 7;
reg |= 0x06;
nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, reg);
reg &= ~0xFull;
reg |= 0x07;
nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), reg);
- } else {
/* Disable TNS mode on both interfaces */
reg = NIC_TNS_BYPASS_MODE << 7;
reg |= 0x08; /* Block identifier */
nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, reg);
reg &= ~0xFull;
reg |= 0x09;
nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), reg);
- }
- /* PKIND configuration */
- nic->pkind.minlen = 0;
- nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN;
- nic->pkind.lenerr_en = 1;
- nic->pkind.rx_hdr = 0;
- nic->pkind.hdr_sl = 0;
- for (i = 0; i < NIC_MAX_PKIND; i++)
nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), *pkind);
- nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS);
- /* Timer config */
- nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
+}
+/* Channel parse index configuration */ +static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) +{
- struct hw_info *hw = nic->hw;
- u32 vnic, bgx, lmac, chan;
- u32 padd, cpi_count = 0;
- u64 cpi_base, cpi, rssi_base, rssi;
- u8 qset, rq_idx = 0;
- vnic = cfg->vf_id;
- bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
- lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
- chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
- cpi_base = vnic * NIC_MAX_CPI_PER_LMAC;
- rssi_base = vnic * hw->rss_ind_tbl_size;
- /* Rx channel configuration */
- nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
(1ull << 63) | (vnic << 0));
- nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3),
((u64)cfg->cpi_alg << 62) | (cpi_base << 48));
- if (cfg->cpi_alg == CPI_ALG_NONE)
cpi_count = 1;
- else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */
cpi_count = 8;
- else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */
cpi_count = 16;
- else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */
cpi_count = NIC_MAX_CPI_PER_LMAC;
- /* RSS Qset, Qidx mapping */
- qset = cfg->vf_id;
- rssi = rssi_base;
- for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) {
nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
(qset << 3) | rq_idx);
rq_idx++;
- }
- rssi = 0;
- cpi = cpi_base;
- for (; cpi < (cpi_base + cpi_count); cpi++) {
/* Determine port to channel adder */
if (cfg->cpi_alg != CPI_ALG_DIFF)
padd = cpi % cpi_count;
else
padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
/* Leave RSS_SIZE as '0' to disable RSS */
if (pass1_silicon(nic->rev_id, nic->hw->model_id)) {
nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
(vnic << 24) | (padd << 16) |
(rssi_base + rssi));
} else {
/* Set MPI_ALG to '0' to disable MCAM parsing */
nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
(padd << 16));
/* MPI index is same as CPI if MPI_ALG is not enabled */
nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3),
(vnic << 24) | (rssi_base + rssi));
}
if ((rssi + 1) >= cfg->rq_cnt)
continue;
if (cfg->cpi_alg == CPI_ALG_VLAN)
rssi++;
else if (cfg->cpi_alg == CPI_ALG_VLAN16)
rssi = ((cpi - cpi_base) & 0xe) >> 1;
else if (cfg->cpi_alg == CPI_ALG_DIFF)
rssi = ((cpi - cpi_base) & 0x38) >> 3;
- }
- nic->cpi_base[cfg->vf_id] = cpi_base;
- nic->rssi_base[cfg->vf_id] = rssi_base;
+}
+/* Transmit channel configuration (TL4 -> TL3 -> Chan)
- VNIC0-SQ0 -> TL4(0) -> TL4A(0) -> TL3[0] -> BGX0/LMAC0/Chan0
- VNIC1-SQ0 -> TL4(8) -> TL4A(2) -> TL3[2] -> BGX0/LMAC1/Chan0
- VNIC2-SQ0 -> TL4(16) -> TL4A(4) -> TL3[4] -> BGX0/LMAC2/Chan0
- VNIC3-SQ0 -> TL4(32) -> TL4A(6) -> TL3[6] -> BGX0/LMAC3/Chan0
- VNIC4-SQ0 -> TL4(512) -> TL4A(128) -> TL3[128] -> BGX1/LMAC0/Chan0
- VNIC5-SQ0 -> TL4(520) -> TL4A(130) -> TL3[130] -> BGX1/LMAC1/Chan0
- VNIC6-SQ0 -> TL4(528) -> TL4A(132) -> TL3[132] -> BGX1/LMAC2/Chan0
- VNIC7-SQ0 -> TL4(536) -> TL4A(134) -> TL3[134] -> BGX1/LMAC3/Chan0
- */
+static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
struct sq_cfg_msg *sq)
+{
- struct hw_info *hw = nic->hw;
- u32 bgx, lmac, chan;
- u32 tl2, tl3, tl4;
- u32 rr_quantum;
- u8 sq_idx = sq->sq_num;
- u8 pqs_vnic = vnic;
- int svf;
- u16 sdevid;
- dm_pci_read_config16(nic->udev, PCI_SUBSYSTEM_ID, &sdevid);
- bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
- lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
- /* 24 bytes for FCS, IPG and preamble */
- rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
- /* For 88xx 0-511 TL4 transmits via BGX0 and
* 512-1023 TL4s transmit via BGX1.
*/
- if (hw->tl1_per_bgx) {
tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt);
if (!sq->sqs_mode) {
tl4 += (lmac * MAX_QUEUES_PER_QSET);
} else {
for (svf = 0; svf < MAX_SQS_PER_VF_SINGLE_NODE; svf++) {
if (nic->vf_sqs[pqs_vnic][svf] == vnic)
break;
}
tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET);
tl4 += (lmac * MAX_QUEUES_PER_QSET *
MAX_SQS_PER_VF_SINGLE_NODE);
tl4 += (svf * MAX_QUEUES_PER_QSET);
}
- } else {
tl4 = (vnic * MAX_QUEUES_PER_QSET);
- }
- tl4 += sq_idx;
- tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt);
- nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
((u64)vnic << NIC_QS_ID_SHIFT) |
((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4);
- nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3),
((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum);
- nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
- /* On 88xx 0-127 channels are for BGX0 and
* 127-255 channels for BGX1.
*
* On 81xx/83xx TL3_CHAN reg should be configured with channel
* within LMAC i.e 0-7 and not the actual channel number like on 88xx
*/
- chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
- if (hw->tl1_per_bgx)
nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
- else
nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0);
- /* Enable backpressure on the channel */
- nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
- tl2 = tl3 >> 2;
- nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2);
- nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
- /* No priorities as of now */
- nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
- /* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1'
* on 81xx/83xx TL2 needs to be configured to transmit to one of the
* possible LMACs.
*
* This register doesn't exist on 88xx.
*/
- if (!hw->tl1_per_bgx)
nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3),
lmac + (bgx * MAX_LMAC_PER_BGX));
+}
+int nic_initialize(struct udevice *dev) +{
- struct nicpf *nic = dev_get_priv(dev);
- nic->udev = dev;
- nic->hw = calloc(1, sizeof(struct hw_info));
- if (!nic->hw)
return -ENOMEM;
- /* MAP PF's configuration registers */
- nic->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
- if (!nic->reg_base) {
printf("Cannot map config register space, aborting\n");
goto exit;
- }
- nic->node = node_id(nic->reg_base);
- dm_pci_read_config8(dev, PCI_REVISION_ID, &nic->rev_id);
- /* By default set NIC in TNS bypass mode */
- nic->flags &= ~NIC_TNS_ENABLED;
- /* Initialize hardware */
- nic_init_hw(nic);
- nic_set_lmac_vf_mapping(nic);
- /* Set RSS TBL size for each VF */
- nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
- nic->rss_ind_tbl_size = rounddown_pow_of_two(nic->rss_ind_tbl_size);
- return 0;
+exit:
- free(nic->hw);
- return -ENODEV;
+}
+int octeontx_nic_probe(struct udevice *dev) +{
- int ret = 0;
- struct nicpf *nicpf = dev_get_priv(dev);
- nicpf->udev = dev;
- ret = nic_initialize(dev);
- if (ret < 0) {
printf("couldn't initialize NIC PF\n");
return ret;
- }
- ret = pci_sriov_init(dev, nicpf->num_vf_en);
- if (ret < 0)
printf("enabling SRIOV failed for num VFs %d\n",
nicpf->num_vf_en);
- return ret;
+}
+U_BOOT_DRIVER(octeontx_nic) = {
- .name = "octeontx_nic",
- .id = UCLASS_MISC,
- .probe = octeontx_nic_probe,
- .priv_auto_alloc_size = sizeof(struct nicpf),
+};
+static struct pci_device_id octeontx_nic_supported[] = {
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NIC) },
- {}
+};
+U_BOOT_PCI_DEVICE(octeontx_nic, octeontx_nic_supported);
diff --git a/drivers/net/octeontx/nic_reg.h b/drivers/net/octeontx/nic_reg.h new file mode 100644 index 0000000000..c214ebb679 --- /dev/null +++ b/drivers/net/octeontx/nic_reg.h @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2018 Marvell International Ltd.
- */
+#ifndef NIC_REG_H +#define NIC_REG_H
+#define NIC_PF_REG_COUNT 29573 +#define NIC_VF_REG_COUNT 249
+/* Physical function register offsets */ +#define NIC_PF_CFG (0x0000) +#define NIC_PF_STATUS (0x0010)
+#define NIC_PF_INTR_TIMER_CFG (0x0030) +#define NIC_PF_BIST_STATUS (0x0040) +#define NIC_PF_SOFT_RESET (0x0050)
+#define NIC_PF_TCP_TIMER (0x0060) +#define NIC_PF_BP_CFG (0x0080) +#define NIC_PF_RRM_CFG (0x0088) +#define NIC_PF_CQM_CF (0x00A0) +#define NIC_PF_CNM_CF (0x00A8) +#define NIC_PF_CNM_STATUS (0x00B0) +#define NIC_PF_CQ_AVG_CFG (0x00C0) +#define NIC_PF_RRM_AVG_CFG (0x00C8)
+#define NIC_PF_INTF_0_1_SEND_CFG (0x0200) +#define NIC_PF_INTF_0_1_BP_CFG (0x0208) +#define NIC_PF_INTF_0_1_BP_DIS_0_1 (0x0210) +#define NIC_PF_INTF_0_1_BP_SW_0_1 (0x0220) +#define NIC_PF_RBDR_BP_STATE_0_3 (0x0240)
+#define NIC_PF_MAILBOX_INT (0x0410) +#define NIC_PF_MAILBOX_INT_W1S (0x0430) +#define NIC_PF_MAILBOX_ENA_W1C (0x0450) +#define NIC_PF_MAILBOX_ENA_W1S (0x0470)
+#define NIC_PF_RX_ETYPE_0_7 (0x0500) +#define NIC_PF_RX_CFG (0x05D0) +#define NIC_PF_PKIND_0_15_CFG (0x0600)
+#define NIC_PF_ECC0_FLIP0 (0x1000) +#define NIC_PF_ECC1_FLIP0 (0x1008) +#define NIC_PF_ECC2_FLIP0 (0x1010) +#define NIC_PF_ECC3_FLIP0 (0x1018) +#define NIC_PF_ECC0_FLIP1 (0x1080) +#define NIC_PF_ECC1_FLIP1 (0x1088) +#define NIC_PF_ECC2_FLIP1 (0x1090) +#define NIC_PF_ECC3_FLIP1 (0x1098) +#define NIC_PF_ECC0_CDIS (0x1100) +#define NIC_PF_ECC1_CDIS (0x1108) +#define NIC_PF_ECC2_CDIS (0x1110) +#define NIC_PF_ECC3_CDIS (0x1118) +#define NIC_PF_BIST0_STATUS (0x1280) +#define NIC_PF_BIST1_STATUS (0x1288) +#define NIC_PF_BIST2_STATUS (0x1290) +#define NIC_PF_BIST3_STATUS (0x1298)
+#define NIC_PF_ECC0_SBE_INT (0x2000) +#define NIC_PF_ECC0_SBE_INT_W1S (0x2008) +#define NIC_PF_ECC0_SBE_ENA_W1C (0x2010) +#define NIC_PF_ECC0_SBE_ENA_W1S (0x2018) +#define NIC_PF_ECC0_DBE_INT (0x2100) +#define NIC_PF_ECC0_DBE_INT_W1S (0x2108) +#define NIC_PF_ECC0_DBE_ENA_W1C (0x2110) +#define NIC_PF_ECC0_DBE_ENA_W1S (0x2118)
+#define NIC_PF_ECC1_SBE_INT (0x2200) +#define NIC_PF_ECC1_SBE_INT_W1S (0x2208) +#define NIC_PF_ECC1_SBE_ENA_W1C (0x2210) +#define NIC_PF_ECC1_SBE_ENA_W1S (0x2218) +#define NIC_PF_ECC1_DBE_INT (0x2300) +#define NIC_PF_ECC1_DBE_INT_W1S (0x2308) +#define NIC_PF_ECC1_DBE_ENA_W1C (0x2310) +#define NIC_PF_ECC1_DBE_ENA_W1S (0x2318)
+#define NIC_PF_ECC2_SBE_INT (0x2400) +#define NIC_PF_ECC2_SBE_INT_W1S (0x2408) +#define NIC_PF_ECC2_SBE_ENA_W1C (0x2410) +#define NIC_PF_ECC2_SBE_ENA_W1S (0x2418) +#define NIC_PF_ECC2_DBE_INT (0x2500) +#define NIC_PF_ECC2_DBE_INT_W1S (0x2508) +#define NIC_PF_ECC2_DBE_ENA_W1C (0x2510) +#define NIC_PF_ECC2_DBE_ENA_W1S (0x2518)
+#define NIC_PF_ECC3_SBE_INT (0x2600) +#define NIC_PF_ECC3_SBE_INT_W1S (0x2608) +#define NIC_PF_ECC3_SBE_ENA_W1C (0x2610) +#define NIC_PF_ECC3_SBE_ENA_W1S (0x2618) +#define NIC_PF_ECC3_DBE_INT (0x2700) +#define NIC_PF_ECC3_DBE_INT_W1S (0x2708) +#define NIC_PF_ECC3_DBE_ENA_W1C (0x2710) +#define NIC_PF_ECC3_DBE_ENA_W1S (0x2718)
+#define NIC_PF_CPI_0_2047_CFG (0x200000) +#define NIC_PF_MPI_0_2047_CFG (0x210000) +#define NIC_PF_RSSI_0_4097_RQ (0x220000) +#define NIC_PF_LMAC_0_7_CFG (0x240000) +#define NIC_PF_LMAC_0_7_SW_XOFF (0x242000) +#define NIC_PF_LMAC_0_7_CREDIT (0x244000) +#define NIC_PF_CHAN_0_255_TX_CFG (0x400000) +#define NIC_PF_CHAN_0_255_RX_CFG (0x420000) +#define NIC_PF_CHAN_0_255_SW_XOFF (0x440000) +#define NIC_PF_CHAN_0_255_CREDIT (0x460000) +#define NIC_PF_CHAN_0_255_RX_BP_CFG (0x480000)
+#define NIC_PF_SW_SYNC_RX (0x490000)
+#define NIC_PF_SW_SYNC_RX_DONE (0x490008) +#define NIC_PF_TL2_0_63_CFG (0x500000) +#define NIC_PF_TL2_0_63_PRI (0x520000) +#define NIC_PF_TL2_LMAC (0x540000) +#define NIC_PF_TL2_0_63_SH_STATUS (0x580000) +#define NIC_PF_TL3A_0_63_CFG (0x5F0000) +#define NIC_PF_TL3_0_255_CFG (0x600000) +#define NIC_PF_TL3_0_255_CHAN (0x620000) +#define NIC_PF_TL3_0_255_PIR (0x640000) +#define NIC_PF_TL3_0_255_SW_XOFF (0x660000) +#define NIC_PF_TL3_0_255_CNM_RATE (0x680000) +#define NIC_PF_TL3_0_255_SH_STATUS (0x6A0000) +#define NIC_PF_TL4A_0_255_CFG (0x6F0000) +#define NIC_PF_TL4_0_1023_CFG (0x800000) +#define NIC_PF_TL4_0_1023_SW_XOFF (0x820000) +#define NIC_PF_TL4_0_1023_SH_STATUS (0x840000) +#define NIC_PF_TL4A_0_1023_CNM_RATE (0x880000) +#define NIC_PF_TL4A_0_1023_CNM_STATUS (0x8A0000)
+#define NIC_PF_VF_0_127_MAILBOX_0_1 (0x20002030) +#define NIC_PF_VNIC_0_127_TX_STAT_0_4 (0x20004000) +#define NIC_PF_VNIC_0_127_RX_STAT_0_13 (0x20004100) +#define NIC_PF_QSET_0_127_LOCK_0_15 (0x20006000) +#define NIC_PF_QSET_0_127_CFG (0x20010000) +#define NIC_PF_QSET_0_127_RQ_0_7_CFG (0x20010400) +#define NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG (0x20010420) +#define NIC_PF_QSET_0_127_RQ_0_7_BP_CFG (0x20010500) +#define NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1 (0x20010600) +#define NIC_PF_QSET_0_127_SQ_0_7_CFG (0x20010C00) +#define NIC_PF_QSET_0_127_SQ_0_7_CFG2 (0x20010C08) +#define NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1 (0x20010D00)
+#define NIC_PF_MSIX_VEC_0_18_ADDR (0x000000) +#define NIC_PF_MSIX_VEC_0_CTL (0x000008) +#define NIC_PF_MSIX_PBA_0 (0x0F0000)
+/* Virtual function register offsets */ +#define NIC_VNIC_CFG (0x000020) +#define NIC_VF_PF_MAILBOX_0_1 (0x000130) +#define NIC_VF_INT (0x000200) +#define NIC_VF_INT_W1S (0x000220) +#define NIC_VF_ENA_W1C (0x000240) +#define NIC_VF_ENA_W1S (0x000260)
+#define NIC_VNIC_RSS_CFG (0x0020E0) +#define NIC_VNIC_RSS_KEY_0_4 (0x002200) +#define NIC_VNIC_TX_STAT_0_4 (0x004000) +#define NIC_VNIC_RX_STAT_0_13 (0x004100) +#define NIC_QSET_RQ_GEN_CFG (0x010010)
+#define NIC_QSET_CQ_0_7_CFG (0x010400) +#define NIC_QSET_CQ_0_7_CFG2 (0x010408) +#define NIC_QSET_CQ_0_7_THRESH (0x010410) +#define NIC_QSET_CQ_0_7_BASE (0x010420) +#define NIC_QSET_CQ_0_7_HEAD (0x010428) +#define NIC_QSET_CQ_0_7_TAIL (0x010430) +#define NIC_QSET_CQ_0_7_DOOR (0x010438) +#define NIC_QSET_CQ_0_7_STATUS (0x010440) +#define NIC_QSET_CQ_0_7_STATUS2 (0x010448) +#define NIC_QSET_CQ_0_7_DEBUG (0x010450)
+#define NIC_QSET_RQ_0_7_CFG (0x010600) +#define NIC_QSET_RQ_0_7_STAT_0_1 (0x010700)
+#define NIC_QSET_SQ_0_7_CFG (0x010800) +#define NIC_QSET_SQ_0_7_THRESH (0x010810) +#define NIC_QSET_SQ_0_7_BASE (0x010820) +#define NIC_QSET_SQ_0_7_HEAD (0x010828) +#define NIC_QSET_SQ_0_7_TAIL (0x010830) +#define NIC_QSET_SQ_0_7_DOOR (0x010838) +#define NIC_QSET_SQ_0_7_STATUS (0x010840) +#define NIC_QSET_SQ_0_7_DEBUG (0x010848) +#define NIC_QSET_SQ_0_7_CNM_CHG (0x010860) +#define NIC_QSET_SQ_0_7_STAT_0_1 (0x010900)
+#define NIC_QSET_RBDR_0_1_CFG (0x010C00) +#define NIC_QSET_RBDR_0_1_THRESH (0x010C10) +#define NIC_QSET_RBDR_0_1_BASE (0x010C20) +#define NIC_QSET_RBDR_0_1_HEAD (0x010C28) +#define NIC_QSET_RBDR_0_1_TAIL (0x010C30) +#define NIC_QSET_RBDR_0_1_DOOR (0x010C38) +#define NIC_QSET_RBDR_0_1_STATUS0 (0x010C40) +#define NIC_QSET_RBDR_0_1_STATUS1 (0x010C48) +#define NIC_QSET_RBDR_0_1_PREFETCH_STATUS (0x010C50)
+#define NIC_VF_MSIX_VECTOR_0_19_ADDR (0x000000) +#define NIC_VF_MSIX_VECTOR_0_19_CTL (0x000008) +#define NIC_VF_MSIX_PBA (0x0F0000)
+/* Offsets within registers */ +#define NIC_MSIX_VEC_SHIFT 4 +#define NIC_Q_NUM_SHIFT 18 +#define NIC_QS_ID_SHIFT 21 +#define NIC_VF_NUM_SHIFT 21
+/* Port kind configuration register */ +struct pkind_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- uint64_t reserved_42_63:22;
- uint64_t hdr_sl:5; /* Header skip length */
- uint64_t rx_hdr:3; /* TNS Receive header present */
- uint64_t lenerr_en:1; /* L2 length error check enable */
- uint64_t reserved_32_32:1;
- uint64_t maxlen:16; /* Max frame size */
- uint64_t minlen:16; /* Min frame size */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- uint64_t minlen:16;
- uint64_t maxlen:16;
- uint64_t reserved_32_32:1;
- uint64_t lenerr_en:1;
- uint64_t rx_hdr:3;
- uint64_t hdr_sl:5;
- uint64_t reserved_42_63:22;
+#endif +};
+static inline uint64_t BGXX_PF_BAR0(unsigned long param1)
__attribute__ ((pure, always_inline));
+static inline uint64_t BGXX_PF_BAR0(unsigned long param1) +{
- assert(param1 <= 1);
- return 0x87E0E0000000 + (param1 << 24);
+}
+#define BGXX_PF_BAR0_SIZE 0x400000 +#define NIC_PF_BAR0 0x843000000000 +#define NIC_PF_BAR0_SIZE 0x40000000
+static inline uint64_t NIC_VFX_BAR0(unsigned long param1)
__attribute__ ((pure, always_inline));
+static inline uint64_t NIC_VFX_BAR0(unsigned long param1) +{
- assert(param1 <= 127);
- return 0x8430A0000000 + (param1 << 21);
+}
+#define NIC_VFX_BAR0_SIZE 0x200000
+#endif /* NIC_REG_H */ diff --git a/drivers/net/octeontx/nicvf_main.c b/drivers/net/octeontx/nicvf_main.c new file mode 100644 index 0000000000..e13c8b9556 --- /dev/null +++ b/drivers/net/octeontx/nicvf_main.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <dm.h> +#include <malloc.h> +#include <misc.h> +#include <net.h> +#include <pci.h> +#include <pci_ids.h> +#include <phy.h> +#include <asm/io.h> +#include <linux/delay.h>
+#include "nic_reg.h" +#include "nic.h" +#include "nicvf_queues.h"
+/* Register read/write APIs */ +void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val) +{
- writeq(val, nic->reg_base + offset);
+}
+u64 nicvf_reg_read(struct nicvf *nic, u64 offset) +{
- return readq(nic->reg_base + offset);
+}
+void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
u64 qidx, u64 val)
+{
- void *addr = nic->reg_base + offset;
- writeq(val, (void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
+}
+u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx) +{
- void *addr = nic->reg_base + offset;
- return readq((void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
+}
+static void nicvf_handle_mbx_intr(struct nicvf *nic);
+/* VF -> PF mailbox communication */ +static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx) +{
- u64 *msg = (u64 *)mbx;
- nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 0, msg[0]);
- nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]);
+}
+int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) +{
- int timeout = NIC_PF_VF_MBX_TIMEOUT;
- int sleep = 10;
- nic->pf_acked = false;
- nic->pf_nacked = false;
- nicvf_write_to_mbx(nic, mbx);
- nic_handle_mbx_intr(nic->nicpf, nic->vf_id);
- /* Wait for previous message to be acked, timeout 2sec */
- while (!nic->pf_acked) {
if (nic->pf_nacked)
return -1;
mdelay(sleep);
nicvf_handle_mbx_intr(nic);
if (nic->pf_acked)
break;
timeout -= sleep;
if (!timeout) {
printf("PF didn't ack to mbox msg %d from VF%d\n",
(mbx->msg.msg & 0xFF), nic->vf_id);
return -1;
}
- }
- return 0;
+}
+/* Checks if VF is able to comminicate with PF
- and also gets the VNIC number this VF is associated to.
- */
+static int nicvf_check_pf_ready(struct nicvf *nic) +{
- union nic_mbx mbx = {};
- mbx.msg.msg = NIC_MBOX_MSG_READY;
- if (nicvf_send_msg_to_pf(nic, &mbx)) {
printf("PF didn't respond to READY msg\n");
return 0;
- }
- return 1;
+}
+static void nicvf_handle_mbx_intr(struct nicvf *nic) +{
- union nic_mbx mbx = {};
- struct eth_pdata *pdata = dev_get_platdata(nic->dev);
- u64 *mbx_data;
- u64 mbx_addr;
- int i;
- mbx_addr = NIC_VF_PF_MAILBOX_0_1;
- mbx_data = (u64 *)&mbx;
- for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
*mbx_data = nicvf_reg_read(nic, mbx_addr);
mbx_data++;
mbx_addr += sizeof(u64);
- }
- debug("Mbox message: msg: 0x%x\n", mbx.msg.msg);
- switch (mbx.msg.msg) {
- case NIC_MBOX_MSG_READY:
nic->pf_acked = true;
nic->vf_id = mbx.nic_cfg.vf_id & 0x7F;
nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F;
nic->node = mbx.nic_cfg.node_id;
if (!nic->set_mac_pending)
memcpy(pdata->enetaddr,
mbx.nic_cfg.mac_addr, 6);
nic->loopback_supported = mbx.nic_cfg.loopback_supported;
nic->link_up = false;
nic->duplex = 0;
nic->speed = 0;
break;
- case NIC_MBOX_MSG_ACK:
nic->pf_acked = true;
break;
- case NIC_MBOX_MSG_NACK:
nic->pf_nacked = true;
break;
- case NIC_MBOX_MSG_BGX_LINK_CHANGE:
nic->pf_acked = true;
nic->link_up = mbx.link_status.link_up;
nic->duplex = mbx.link_status.duplex;
nic->speed = mbx.link_status.speed;
if (nic->link_up) {
printf("%s: Link is Up %d Mbps %s\n",
nic->dev->name, nic->speed,
nic->duplex == 1 ?
"Full duplex" : "Half duplex");
} else {
printf("%s: Link is Down\n", nic->dev->name);
}
break;
- default:
printf("Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
break;
- }
- nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0);
+}
+static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct udevice *dev) +{
- union nic_mbx mbx = {};
- struct eth_pdata *pdata = dev_get_platdata(dev);
- mbx.mac.msg = NIC_MBOX_MSG_SET_MAC;
- mbx.mac.vf_id = nic->vf_id;
- memcpy(mbx.mac.mac_addr, pdata->enetaddr, 6);
- return nicvf_send_msg_to_pf(nic, &mbx);
+}
+static void nicvf_config_cpi(struct nicvf *nic) +{
- union nic_mbx mbx = {};
- mbx.cpi_cfg.msg = NIC_MBOX_MSG_CPI_CFG;
- mbx.cpi_cfg.vf_id = nic->vf_id;
- mbx.cpi_cfg.cpi_alg = nic->cpi_alg;
- mbx.cpi_cfg.rq_cnt = nic->qs->rq_cnt;
- nicvf_send_msg_to_pf(nic, &mbx);
+}
+static int nicvf_init_resources(struct nicvf *nic) +{
- int err;
- nic->num_qs = 1;
- /* Enable Qset */
- nicvf_qset_config(nic, true);
- /* Initialize queues and HW for data transfer */
- err = nicvf_config_data_transfer(nic, true);
- if (err) {
printf("Failed to alloc/config VF's QSet resources\n");
return err;
- }
- return 0;
+}
+static void nicvf_snd_pkt_handler(struct nicvf *nic,
struct cmp_queue *cq,
void *cq_desc, int cqe_type)
+{
- struct cqe_send_t *cqe_tx;
- struct snd_queue *sq;
- struct sq_hdr_subdesc *hdr;
- cqe_tx = (struct cqe_send_t *)cq_desc;
- sq = &nic->qs->sq[cqe_tx->sq_idx];
- hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
- if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
return;
- nicvf_check_cqe_tx_errs(nic, cq, cq_desc);
- nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
+}
+static int nicvf_rcv_pkt_handler(struct nicvf *nic,
struct cmp_queue *cq, void *cq_desc,
void **ppkt, int cqe_type)
+{
- void *pkt;
- size_t pkt_len;
- struct cqe_rx_t *cqe_rx = (struct cqe_rx_t *)cq_desc;
- int err = 0;
- /* Check for errors */
- err = nicvf_check_cqe_rx_errs(nic, cq, cq_desc);
- if (err && !cqe_rx->rb_cnt)
return -1;
- pkt = nicvf_get_rcv_pkt(nic, cq_desc, &pkt_len);
- if (!pkt) {
debug("Packet not received\n");
return -1;
- }
- if (pkt)
*ppkt = pkt;
- return pkt_len;
+}
+int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len) +{
- int cq_qnum = 0;
- int processed_sq_cqe = 0;
- int processed_rq_cqe = 0;
- int processed_cqe = 0;
- unsigned long cqe_count, cqe_head;
- struct queue_set *qs = nic->qs;
- struct cmp_queue *cq = &qs->cq[cq_qnum];
- struct cqe_rx_t *cq_desc;
- /* Get num of valid CQ entries expect next one to be SQ completion */
- cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_qnum);
- cqe_count &= 0xFFFF;
- if (!cqe_count)
return 0;
- /* Get head of the valid CQ entries */
- cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_qnum);
- cqe_head >>= 9;
- cqe_head &= 0xFFFF;
- if (cqe_count) {
/* Get the CQ descriptor */
cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
cqe_head++;
cqe_head &= (cq->dmem.q_len - 1);
/* Initiate prefetch for next descriptor */
prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head));
switch (cq_desc->cqe_type) {
case CQE_TYPE_RX:
debug("%s: Got Rx CQE\n", nic->dev->name);
*pkt_len = nicvf_rcv_pkt_handler(nic, cq, cq_desc,
ppkt, CQE_TYPE_RX);
processed_rq_cqe++;
break;
case CQE_TYPE_SEND:
debug("%s: Got Tx CQE\n", nic->dev->name);
nicvf_snd_pkt_handler(nic, cq, cq_desc, CQE_TYPE_SEND);
processed_sq_cqe++;
break;
default:
debug("%s: Got CQ type %u\n", nic->dev->name,
cq_desc->cqe_type);
break;
}
processed_cqe++;
- }
- /* Dequeue CQE */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
cq_qnum, processed_cqe);
- asm volatile ("dsb sy");
- return (processed_sq_cqe | processed_rq_cqe);
+}
+/* Qset error interrupt handler
- As of now only CQ errors are handled
- */
+void nicvf_handle_qs_err(struct nicvf *nic) +{
- struct queue_set *qs = nic->qs;
- int qidx;
- u64 status;
- /* Check if it is CQ err */
- for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS,
qidx);
if (!(status & CQ_ERR_MASK))
continue;
/* Process already queued CQEs and reconfig CQ */
nicvf_sq_disable(nic, qidx);
nicvf_cmp_queue_config(nic, qs, qidx, true);
nicvf_sq_free_used_descs(nic->dev, &qs->sq[qidx], qidx);
nicvf_sq_enable(nic, &qs->sq[qidx], qidx);
- }
+}
+static int nicvf_free_pkt(struct udevice *dev, uchar *pkt, int pkt_len) +{
- struct nicvf *nic = dev_get_priv(dev);
- if (pkt && pkt_len)
free(pkt);
- nicvf_refill_rbdr(nic);
- return 0;
+}
+static int nicvf_xmit(struct udevice *dev, void *pkt, int pkt_len) +{
- struct nicvf *nic = dev_get_priv(dev);
- int ret = 0;
- int rcv_len = 0;
- unsigned int timeout = 5000;
- void *rpkt = NULL;
- if (!nicvf_sq_append_pkt(nic, pkt, pkt_len)) {
printf("VF%d: TX ring full\n", nic->vf_id);
return -1;
- }
- /* check and update CQ for pkt sent */
- while (!ret && timeout--) {
ret = nicvf_cq_handler(nic, &rpkt, &rcv_len);
if (!ret) {
debug("%s: %d, Not sent\n", __func__, __LINE__);
udelay(10);
}
- }
- return 0;
+}
+static int nicvf_recv(struct udevice *dev, int flags, uchar **packetp) +{
- struct nicvf *nic = dev_get_priv(dev);
- void *pkt;
- int pkt_len = 0;
+#ifdef DEBUG
- u8 *dpkt;
- int i, j;
+#endif
- nicvf_cq_handler(nic, &pkt, &pkt_len);
- if (pkt_len) {
+#ifdef DEBUG
dpkt = pkt;
printf("RX packet contents:\n");
for (i = 0; i < 8; i++) {
puts("\t");
for (j = 0; j < 10; j++)
printf("%02x ", dpkt[i * 10 + j]);
puts("\n");
}
+#endif
*packetp = pkt;
- }
- return pkt_len;
+}
+void nicvf_stop(struct udevice *dev) +{
- struct nicvf *nic = dev_get_priv(dev);
- if (!nic->open)
return;
- /* Free resources */
- nicvf_config_data_transfer(nic, false);
- /* Disable HW Qset */
- nicvf_qset_config(nic, false);
- nic->open = false;
+}
+int nicvf_open(struct udevice *dev) +{
- int err;
- struct nicvf *nic = dev_get_priv(dev);
- nicvf_hw_set_mac_addr(nic, dev);
- /* Configure CPI alorithm */
- nic->cpi_alg = CPI_ALG_NONE;
- nicvf_config_cpi(nic);
- /* Initialize the queues */
- err = nicvf_init_resources(nic);
- if (err)
return -1;
- if (!nicvf_check_pf_ready(nic))
return -1;
- nic->open = true;
- /* Make sure queue initialization is written */
- asm volatile("dsb sy");
- return 0;
+}
+int nicvf_write_hwaddr(struct udevice *dev) +{
- unsigned char ethaddr[ARP_HLEN];
- struct eth_pdata *pdata = dev_get_platdata(dev);
- struct nicvf *nic = dev_get_priv(dev);
- /* If lower level firmware fails to set proper MAC
* u-boot framework updates MAC to random address.
* Use this hook to update mac address in environment.
*/
- if (!eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr)) {
eth_env_set_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
- }
- eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr);
- if (memcmp(ethaddr, pdata->enetaddr, ARP_HLEN)) {
debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
nicvf_hw_set_mac_addr(nic, dev);
- }
- return 0;
+}
+static void nicvf_probe_mdio_devices(void) +{
- struct udevice *pdev;
- int err;
- static int probed;
- if (probed)
return;
- err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
PCI_DEVICE_ID_CAVIUM_SMI, 0,
&pdev);
- if (err)
debug("%s couldn't find SMI device\n", __func__);
- probed = 1;
+}
+int nicvf_initialize(struct udevice *dev) +{
- struct nicvf *nicvf = dev_get_priv(dev);
- struct eth_pdata *pdata = dev_get_platdata(dev);
- int ret = 0, bgx, lmac;
- char name[16];
- unsigned char ethaddr[ARP_HLEN];
- struct udevice *pfdev;
- struct nicpf *pf;
- static int vfid;
- if (dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
PCI_DEVICE_ID_CAVIUM_NIC, 0, &pfdev)) {
printf("%s NIC PF device not found..VF probe failed\n",
__func__);
return -1;
- }
- pf = dev_get_priv(pfdev);
- nicvf->vf_id = vfid++;
- nicvf->dev = dev;
- nicvf->nicpf = pf;
- nicvf_probe_mdio_devices();
- /* Enable TSO support */
- nicvf->hw_tso = true;
- nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
- debug("nicvf->reg_base: %p\n", nicvf->reg_base);
- if (!nicvf->reg_base) {
printf("Cannot map config register space, aborting\n");
ret = -1;
goto fail;
- }
- ret = nicvf_set_qset_resources(nicvf);
- if (ret)
return -1;
- sprintf(name, "vnic%u", nicvf->vf_id);
- debug("%s name %s\n", __func__, name);
- device_set_name(dev, name);
- bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
- lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
- debug("%s VF %d BGX %d LMAC %d\n", __func__, nicvf->vf_id, bgx, lmac);
- debug("%s PF %p pfdev %p VF %p vfdev %p vf->pdata %p\n",
__func__, nicvf->nicpf, nicvf->nicpf->udev, nicvf, nicvf->dev,
pdata);
- fdt_board_get_ethaddr(bgx, lmac, ethaddr);
- debug("%s bgx %d lmac %d ethaddr %pM\n", __func__, bgx, lmac, ethaddr);
- if (is_valid_ethaddr(ethaddr)) {
memcpy(pdata->enetaddr, ethaddr, ARP_HLEN);
eth_env_set_enetaddr_by_index("eth", dev->seq, ethaddr);
- }
- debug("%s enetaddr %pM ethaddr %pM\n", __func__,
pdata->enetaddr, ethaddr);
+fail:
- return ret;
+}
+int octeontx_vnic_probe(struct udevice *dev) +{
- return nicvf_initialize(dev);
+}
+static const struct eth_ops octeontx_vnic_ops = {
- .start = nicvf_open,
- .stop = nicvf_stop,
- .send = nicvf_xmit,
- .recv = nicvf_recv,
- .free_pkt = nicvf_free_pkt,
- .write_hwaddr = nicvf_write_hwaddr,
+};
+U_BOOT_DRIVER(octeontx_vnic) = {
- .name = "vnic",
- .id = UCLASS_ETH,
- .probe = octeontx_vnic_probe,
- .ops = &octeontx_vnic_ops,
- .priv_auto_alloc_size = sizeof(struct nicvf),
- .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+static struct pci_device_id octeontx_vnic_supported[] = {
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF) },
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF_1) },
- {}
+};
+U_BOOT_PCI_DEVICE(octeontx_vnic, octeontx_vnic_supported); diff --git a/drivers/net/octeontx/nicvf_queues.c b/drivers/net/octeontx/nicvf_queues.c new file mode 100644 index 0000000000..c7f262f440 --- /dev/null +++ b/drivers/net/octeontx/nicvf_queues.c @@ -0,0 +1,1140 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <cpu_func.h> +#include <dm/device.h> +#include <malloc.h> +#include <net.h> +#include <phy.h> +#include <linux/delay.h>
+#include "nic_reg.h" +#include "nic.h" +#include "q_struct.h" +#include "nicvf_queues.h"
+static int nicvf_poll_reg(struct nicvf *nic, int qidx,
u64 reg, int bit_pos, int bits, int val)
+{
- u64 bit_mask;
- u64 reg_val;
- int timeout = 10;
- bit_mask = (1ULL << bits) - 1;
- bit_mask = (bit_mask << bit_pos);
- while (timeout) {
reg_val = nicvf_queue_reg_read(nic, reg, qidx);
if (((reg_val & bit_mask) >> bit_pos) == val)
return 0;
udelay(2000);
timeout--;
- }
- printf("Poll on reg 0x%llx failed\n", reg);
- return 1;
+}
+static int nicvf_alloc_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem,
int q_len, int desc_size, int align_bytes)
+{
- dmem->q_len = q_len;
- dmem->size = (desc_size * q_len) + align_bytes;
- /* Save address, need it while freeing */
- dmem->unalign_base = calloc(1, dmem->size);
- dmem->dma = (uintptr_t)dmem->unalign_base;
- if (!dmem->unalign_base)
return -1;
- /* Align memory address for 'align_bytes' */
- dmem->phys_base = NICVF_ALIGNED_ADDR((u64)dmem->dma, align_bytes);
- dmem->base = dmem->unalign_base + (dmem->phys_base - dmem->dma);
- return 0;
+}
+static void nicvf_free_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem) +{
- if (!dmem)
return;
- free(dmem->unalign_base);
- dmem->unalign_base = NULL;
- dmem->base = NULL;
+}
+static void *nicvf_rb_ptr_to_pkt(struct nicvf *nic, uintptr_t rb_ptr) +{
- return (void *)rb_ptr;
+}
+static int nicvf_init_rbdr(struct nicvf *nic, struct rbdr *rbdr,
int ring_len, int buf_size)
+{
- int idx;
- uintptr_t rbuf;
- struct rbdr_entry_t *desc;
- if (nicvf_alloc_q_desc_mem(nic, &rbdr->dmem, ring_len,
sizeof(struct rbdr_entry_t),
NICVF_RCV_BUF_ALIGN_BYTES)) {
printf("Unable to allocate memory for rcv buffer ring\n");
return -1;
- }
- rbdr->desc = rbdr->dmem.base;
- /* Buffer size has to be in multiples of 128 bytes */
- rbdr->dma_size = buf_size;
- rbdr->enable = true;
- rbdr->thresh = RBDR_THRESH;
- debug("%s: %d: allocating %lld bytes for rcv buffers\n",
__func__, __LINE__,
ring_len * buf_size + NICVF_RCV_BUF_ALIGN_BYTES);
- rbdr->buf_mem = (uintptr_t)calloc(1, ring_len * buf_size
+ NICVF_RCV_BUF_ALIGN_BYTES);
- if (!rbdr->buf_mem) {
printf("Unable to allocate memory for rcv buffers\n");
return -1;
- }
- rbdr->buffers = NICVF_ALIGNED_ADDR(rbdr->buf_mem,
NICVF_RCV_BUF_ALIGN_BYTES);
- debug("%s: %d: rbdr->buf_mem: %lx, rbdr->buffers: %lx\n",
__func__, __LINE__, rbdr->buf_mem, rbdr->buffers);
- for (idx = 0; idx < ring_len; idx++) {
rbuf = rbdr->buffers + DMA_BUFFER_LEN * idx;
desc = GET_RBDR_DESC(rbdr, idx);
desc->buf_addr = rbuf >> NICVF_RCV_BUF_ALIGN;
flush_dcache_range((uintptr_t)desc,
(uintptr_t)desc + sizeof(desc));
- }
- return 0;
+}
+static void nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr) +{
- if (!rbdr)
return;
- rbdr->enable = false;
- if (!rbdr->dmem.base)
return;
- debug("%s: %d: rbdr->buf_mem: %p\n", __func__,
__LINE__, (void *)rbdr->buf_mem);
- free((void *)rbdr->buf_mem);
- /* Free RBDR ring */
- nicvf_free_q_desc_mem(nic, &rbdr->dmem);
+}
+/* Refill receive buffer descriptors with new buffers.
- This runs in softirq context .
- */
+void nicvf_refill_rbdr(struct nicvf *nic) +{
- struct queue_set *qs = nic->qs;
- int rbdr_idx = qs->rbdr_cnt;
- unsigned long qcount, head, tail, rb_cnt;
- struct rbdr *rbdr;
- if (!rbdr_idx)
return;
- rbdr_idx--;
- rbdr = &qs->rbdr[rbdr_idx];
- /* Check if it's enabled */
- if (!rbdr->enable) {
printf("Receive queue %d is disabled\n", rbdr_idx);
return;
- }
- /* check if valid descs reached or crossed threshold level */
- qcount = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, rbdr_idx);
- head = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, rbdr_idx);
- tail = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, rbdr_idx);
- qcount &= 0x7FFFF;
- rb_cnt = qs->rbdr_len - qcount - 1;
- debug("%s: %d: qcount: %lu, head: %lx, tail: %lx, rb_cnt: %lu\n",
__func__, __LINE__, qcount, head, tail, rb_cnt);
- /* Notify HW */
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR, rbdr_idx, rb_cnt);
- asm volatile ("dsb sy");
+}
+/* TBD: how to handle full packets received in CQ
- i.e conversion of buffers into SKBs
- */
+static int nicvf_init_cmp_queue(struct nicvf *nic,
struct cmp_queue *cq, int q_len)
+{
- if (nicvf_alloc_q_desc_mem(nic, &cq->dmem, q_len,
CMP_QUEUE_DESC_SIZE,
NICVF_CQ_BASE_ALIGN_BYTES)) {
printf("Unable to allocate memory for completion queue\n");
return -1;
- }
- cq->desc = cq->dmem.base;
- if (!pass1_silicon(nic->rev_id, nic->nicpf->hw->model_id))
cq->thresh = CMP_QUEUE_CQE_THRESH;
- else
cq->thresh = 0;
- cq->intr_timer_thresh = CMP_QUEUE_TIMER_THRESH;
- return 0;
+}
+static void nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq) +{
- if (!cq)
return;
- if (!cq->dmem.base)
return;
- nicvf_free_q_desc_mem(nic, &cq->dmem);
+}
+static int nicvf_init_snd_queue(struct nicvf *nic,
struct snd_queue *sq, int q_len)
+{
- if (nicvf_alloc_q_desc_mem(nic, &sq->dmem, q_len,
SND_QUEUE_DESC_SIZE,
NICVF_SQ_BASE_ALIGN_BYTES)) {
printf("Unable to allocate memory for send queue\n");
return -1;
- }
- sq->desc = sq->dmem.base;
- sq->skbuff = calloc(q_len, sizeof(u64));
- sq->head = 0;
- sq->tail = 0;
- sq->free_cnt = q_len - 1;
- sq->thresh = SND_QUEUE_THRESH;
- return 0;
+}
+static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq) +{
- if (!sq)
return;
- if (!sq->dmem.base)
return;
- debug("%s: %d\n", __func__, __LINE__);
- free(sq->skbuff);
- nicvf_free_q_desc_mem(nic, &sq->dmem);
+}
+static void nicvf_reclaim_snd_queue(struct nicvf *nic,
struct queue_set *qs, int qidx)
+{
- /* Disable send queue */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, 0);
- /* Check if SQ is stopped */
- if (nicvf_poll_reg(nic, qidx, NIC_QSET_SQ_0_7_STATUS, 21, 1, 0x01))
return;
- /* Reset send queue */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
+}
+static void nicvf_reclaim_rcv_queue(struct nicvf *nic,
struct queue_set *qs, int qidx)
+{
- union nic_mbx mbx = {};
- /* Make sure all packets in the pipeline are written back into mem */
- mbx.msg.msg = NIC_MBOX_MSG_RQ_SW_SYNC;
- nicvf_send_msg_to_pf(nic, &mbx);
+}
+static void nicvf_reclaim_cmp_queue(struct nicvf *nic,
struct queue_set *qs, int qidx)
+{
- /* Disable timer threshold (doesn't get reset upon CQ reset */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx, 0);
- /* Disable completion queue */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, 0);
- /* Reset completion queue */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
+}
+static void nicvf_reclaim_rbdr(struct nicvf *nic,
struct rbdr *rbdr, int qidx)
+{
- u64 tmp, fifo_state;
- int timeout = 10;
- /* Save head and tail pointers for feeing up buffers */
- rbdr->head = nicvf_queue_reg_read(nic,
NIC_QSET_RBDR_0_1_HEAD,
qidx) >> 3;
- rbdr->tail = nicvf_queue_reg_read(nic,
NIC_QSET_RBDR_0_1_TAIL,
qidx) >> 3;
- /* If RBDR FIFO is in 'FAIL' state then do a reset first
* before relaiming.
*/
- fifo_state = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, qidx);
- if (((fifo_state >> 62) & 0x03) == 0x3)
nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
qidx, NICVF_RBDR_RESET);
- /* Disable RBDR */
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0);
- if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
return;
- while (1) {
tmp = nicvf_queue_reg_read(nic,
NIC_QSET_RBDR_0_1_PREFETCH_STATUS,
qidx);
if ((tmp & 0xFFFFFFFF) == ((tmp >> 32) & 0xFFFFFFFF))
break;
mdelay(2000);
timeout--;
if (!timeout) {
printf("Failed polling on prefetch status\n");
return;
}
- }
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
qidx, NICVF_RBDR_RESET);
- if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x02))
return;
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0x00);
- if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
return;
+}
+/* Configures receive queue */ +static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable)
+{
- union nic_mbx mbx = {};
- struct rcv_queue *rq;
- union {
struct rq_cfg s;
u64 u;
- } rq_cfg;
- rq = &qs->rq[qidx];
- rq->enable = enable;
- /* Disable receive queue */
- nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, 0);
- if (!rq->enable) {
nicvf_reclaim_rcv_queue(nic, qs, qidx);
return;
- }
- rq->cq_qs = qs->vnic_id;
- rq->cq_idx = qidx;
- rq->start_rbdr_qs = qs->vnic_id;
- rq->start_qs_rbdr_idx = qs->rbdr_cnt - 1;
- rq->cont_rbdr_qs = qs->vnic_id;
- rq->cont_qs_rbdr_idx = qs->rbdr_cnt - 1;
- /* all writes of RBDR data to be loaded into L2 Cache as well*/
- rq->caching = 1;
- /* Send a mailbox msg to PF to config RQ */
- mbx.rq.msg = NIC_MBOX_MSG_RQ_CFG;
- mbx.rq.qs_num = qs->vnic_id;
- mbx.rq.rq_num = qidx;
- mbx.rq.cfg = (rq->caching << 26) | (rq->cq_qs << 19) |
(rq->cq_idx << 16) | (rq->cont_rbdr_qs << 9) |
(rq->cont_qs_rbdr_idx << 8) |
(rq->start_rbdr_qs << 1) | (rq->start_qs_rbdr_idx);
- nicvf_send_msg_to_pf(nic, &mbx);
- mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG;
- mbx.rq.cfg = (1ULL << 63) | (1ULL << 62) | (qs->vnic_id << 0);
- nicvf_send_msg_to_pf(nic, &mbx);
- /* RQ drop config
* Enable CQ drop to reserve sufficient CQEs for all tx packets
*/
- mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG;
- mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
- nicvf_send_msg_to_pf(nic, &mbx);
- nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00);
- /* Enable Receive queue */
- rq_cfg.s.ena = 1;
- rq_cfg.s.tcp_ena = 0;
- nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, rq_cfg.u);
+}
+void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable)
+{
- struct cmp_queue *cq;
- union {
u64 u;
struct cq_cfg s;
- } cq_cfg;
- cq = &qs->cq[qidx];
- cq->enable = enable;
- if (!cq->enable) {
nicvf_reclaim_cmp_queue(nic, qs, qidx);
return;
- }
- /* Reset completion queue */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
- if (!cq->enable)
return;
- /* Set completion queue base address */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_BASE,
qidx, (u64)(cq->dmem.phys_base));
- /* Enable Completion queue */
- cq_cfg.s.ena = 1;
- cq_cfg.s.reset = 0;
- cq_cfg.s.caching = 0;
- cq_cfg.s.qsize = CMP_QSIZE;
- cq_cfg.s.avg_con = 0;
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, cq_cfg.u);
- /* Set threshold value for interrupt generation */
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh);
- nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx,
cq->intr_timer_thresh);
+}
+/* Configures transmit queue */ +static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable)
+{
- union nic_mbx mbx = {};
- struct snd_queue *sq;
- union {
struct sq_cfg s;
u64 u;
- } sq_cfg;
- sq = &qs->sq[qidx];
- sq->enable = enable;
- if (!sq->enable) {
nicvf_reclaim_snd_queue(nic, qs, qidx);
return;
- }
- /* Reset send queue */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
- sq->cq_qs = qs->vnic_id;
- sq->cq_idx = qidx;
- /* Send a mailbox msg to PF to config SQ */
- mbx.sq.msg = NIC_MBOX_MSG_SQ_CFG;
- mbx.sq.qs_num = qs->vnic_id;
- mbx.sq.sq_num = qidx;
- mbx.sq.sqs_mode = nic->sqs_mode;
- mbx.sq.cfg = (sq->cq_qs << 3) | sq->cq_idx;
- nicvf_send_msg_to_pf(nic, &mbx);
- /* Set queue base address */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_BASE,
qidx, (u64)(sq->dmem.phys_base));
- /* Enable send queue & set queue size */
- sq_cfg.s.ena = 1;
- sq_cfg.s.reset = 0;
- sq_cfg.s.ldwb = 0;
- sq_cfg.s.qsize = SND_QSIZE;
- sq_cfg.s.tstmp_bgx_intf = 0;
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg.u);
- /* Set threshold value for interrupt generation */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_THRESH, qidx, sq->thresh);
+}
+/* Configures receive buffer descriptor ring */ +static void nicvf_rbdr_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable)
+{
- struct rbdr *rbdr;
- union {
struct rbdr_cfg s;
u64 u;
- } rbdr_cfg;
- rbdr = &qs->rbdr[qidx];
- nicvf_reclaim_rbdr(nic, rbdr, qidx);
- if (!enable)
return;
- /* Set descriptor base address */
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_BASE,
qidx, (u64)(rbdr->dmem.phys_base));
- /* Enable RBDR & set queue size */
- /* Buffer size should be in multiples of 128 bytes */
- rbdr_cfg.s.ena = 1;
- rbdr_cfg.s.reset = 0;
- rbdr_cfg.s.ldwb = 0;
- rbdr_cfg.s.qsize = RBDR_SIZE;
- rbdr_cfg.s.avg_con = 0;
- rbdr_cfg.s.lines = rbdr->dma_size / 128;
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
qidx, rbdr_cfg.u);
- /* Notify HW */
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR,
qidx, qs->rbdr_len - 1);
- /* Set threshold value for interrupt generation */
- nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_THRESH,
qidx, rbdr->thresh - 1);
+}
+/* Requests PF to assign and enable Qset */ +void nicvf_qset_config(struct nicvf *nic, bool enable) +{
- union nic_mbx mbx = {};
- struct queue_set *qs = nic->qs;
- struct qs_cfg *qs_cfg;
- if (!qs) {
printf("Qset is still not allocated, don't init queues\n");
return;
- }
- qs->enable = enable;
- qs->vnic_id = nic->vf_id;
- /* Send a mailbox msg to PF to config Qset */
- mbx.qs.msg = NIC_MBOX_MSG_QS_CFG;
- mbx.qs.num = qs->vnic_id;
+#ifdef VNIC_MULTI_QSET_SUPPORT
- mbx.qs.sqs_count = nic->sqs_count;
+#endif
- mbx.qs.cfg = 0;
- qs_cfg = (struct qs_cfg *)&mbx.qs.cfg;
- if (qs->enable) {
qs_cfg->ena = 1;
+#ifdef __BIG_ENDIAN
qs_cfg->be = 1;
+#endif
qs_cfg->vnic = qs->vnic_id;
- }
- nicvf_send_msg_to_pf(nic, &mbx);
+}
+static void nicvf_free_resources(struct nicvf *nic) +{
- int qidx;
- struct queue_set *qs = nic->qs;
- /* Free receive buffer descriptor ring */
- for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
nicvf_free_rbdr(nic, &qs->rbdr[qidx]);
- /* Free completion queue */
- for (qidx = 0; qidx < qs->cq_cnt; qidx++)
nicvf_free_cmp_queue(nic, &qs->cq[qidx]);
- /* Free send queue */
- for (qidx = 0; qidx < qs->sq_cnt; qidx++)
nicvf_free_snd_queue(nic, &qs->sq[qidx]);
+}
+static int nicvf_alloc_resources(struct nicvf *nic) +{
- int qidx;
- struct queue_set *qs = nic->qs;
- /* Alloc receive buffer descriptor ring */
- for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
if (nicvf_init_rbdr(nic, &qs->rbdr[qidx], qs->rbdr_len,
DMA_BUFFER_LEN))
goto alloc_fail;
- }
- /* Alloc send queue */
- for (qidx = 0; qidx < qs->sq_cnt; qidx++) {
if (nicvf_init_snd_queue(nic, &qs->sq[qidx], qs->sq_len))
goto alloc_fail;
- }
- /* Alloc completion queue */
- for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
if (nicvf_init_cmp_queue(nic, &qs->cq[qidx], qs->cq_len))
goto alloc_fail;
- }
- return 0;
+alloc_fail:
- nicvf_free_resources(nic);
- return -1;
+}
+int nicvf_set_qset_resources(struct nicvf *nic) +{
- struct queue_set *qs;
- qs = calloc(1, sizeof(struct queue_set));
- if (!qs)
return -1;
- nic->qs = qs;
- /* Set count of each queue */
- qs->rbdr_cnt = RBDR_CNT;
- qs->rq_cnt = 1;
- qs->sq_cnt = SND_QUEUE_CNT;
- qs->cq_cnt = CMP_QUEUE_CNT;
- /* Set queue lengths */
- qs->rbdr_len = RCV_BUF_COUNT;
- qs->sq_len = SND_QUEUE_LEN;
- qs->cq_len = CMP_QUEUE_LEN;
- nic->rx_queues = qs->rq_cnt;
- nic->tx_queues = qs->sq_cnt;
- return 0;
+}
+int nicvf_config_data_transfer(struct nicvf *nic, bool enable) +{
- bool disable = false;
- struct queue_set *qs = nic->qs;
- int qidx;
- if (!qs)
return 0;
- if (enable) {
if (nicvf_alloc_resources(nic))
return -1;
for (qidx = 0; qidx < qs->sq_cnt; qidx++)
nicvf_snd_queue_config(nic, qs, qidx, enable);
for (qidx = 0; qidx < qs->cq_cnt; qidx++)
nicvf_cmp_queue_config(nic, qs, qidx, enable);
for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
nicvf_rbdr_config(nic, qs, qidx, enable);
for (qidx = 0; qidx < qs->rq_cnt; qidx++)
nicvf_rcv_queue_config(nic, qs, qidx, enable);
- } else {
for (qidx = 0; qidx < qs->rq_cnt; qidx++)
nicvf_rcv_queue_config(nic, qs, qidx, disable);
for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
nicvf_rbdr_config(nic, qs, qidx, disable);
for (qidx = 0; qidx < qs->sq_cnt; qidx++)
nicvf_snd_queue_config(nic, qs, qidx, disable);
for (qidx = 0; qidx < qs->cq_cnt; qidx++)
nicvf_cmp_queue_config(nic, qs, qidx, disable);
nicvf_free_resources(nic);
- }
- return 0;
+}
+/* Get a free desc from SQ
- returns descriptor ponter & descriptor number
- */
+static int nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt) +{
- int qentry;
- qentry = sq->tail;
- sq->free_cnt -= desc_cnt;
- sq->tail += desc_cnt;
- sq->tail &= (sq->dmem.q_len - 1);
- return qentry;
+}
+/* Free descriptor back to SQ for future use */ +void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt) +{
- sq->free_cnt += desc_cnt;
- sq->head += desc_cnt;
- sq->head &= (sq->dmem.q_len - 1);
+}
+static int nicvf_get_nxt_sqentry(struct snd_queue *sq, int qentry) +{
- qentry++;
- qentry &= (sq->dmem.q_len - 1);
- return qentry;
+}
+void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx) +{
- u64 sq_cfg;
- sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
- sq_cfg |= NICVF_SQ_EN;
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
- /* Ring doorbell so that H/W restarts processing SQEs */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR, qidx, 0);
+}
+void nicvf_sq_disable(struct nicvf *nic, int qidx) +{
- u64 sq_cfg;
- sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
- sq_cfg &= ~NICVF_SQ_EN;
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
+}
+void nicvf_sq_free_used_descs(struct udevice *dev, struct snd_queue *sq,
int qidx)
+{
- u64 head;
- struct nicvf *nic = dev_get_priv(dev);
- struct sq_hdr_subdesc *hdr;
- head = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, qidx) >> 4;
- while (sq->head != head) {
hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, sq->head);
if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) {
nicvf_put_sq_desc(sq, 1);
continue;
}
nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
- }
+}
+/* Get the number of SQ descriptors needed to xmit this skb */ +static int nicvf_sq_subdesc_required(struct nicvf *nic) +{
- int subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
- return subdesc_cnt;
+}
+/* Add SQ HEADER subdescriptor.
- First subdescriptor for every send descriptor.
- */
+static inline void +nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
int subdesc_cnt, void *pkt, size_t pkt_len)
+{
- struct sq_hdr_subdesc *hdr;
- hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
- sq->skbuff[qentry] = (uintptr_t)pkt;
- memset(hdr, 0, SND_QUEUE_DESC_SIZE);
- hdr->subdesc_type = SQ_DESC_TYPE_HEADER;
- /* Enable notification via CQE after processing SQE */
- hdr->post_cqe = 1;
- /* No of subdescriptors following this */
- hdr->subdesc_cnt = subdesc_cnt;
- hdr->tot_len = pkt_len;
- flush_dcache_range((uintptr_t)hdr,
(uintptr_t)hdr + sizeof(struct sq_hdr_subdesc));
+}
+/* SQ GATHER subdescriptor
- Must follow HDR descriptor
- */
+static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
size_t size, uintptr_t data)
+{
- struct sq_gather_subdesc *gather;
- qentry &= (sq->dmem.q_len - 1);
- gather = (struct sq_gather_subdesc *)GET_SQ_DESC(sq, qentry);
- memset(gather, 0, SND_QUEUE_DESC_SIZE);
- gather->subdesc_type = SQ_DESC_TYPE_GATHER;
- gather->ld_type = NIC_SEND_LD_TYPE_E_LDD;
- gather->size = size;
- gather->addr = data;
- flush_dcache_range((uintptr_t)gather,
(uintptr_t)gather + sizeof(struct sq_hdr_subdesc));
+}
+/* Append an skb to a SQ for packet transfer. */ +int nicvf_sq_append_pkt(struct nicvf *nic, void *pkt, size_t pkt_size) +{
- int subdesc_cnt;
- int sq_num = 0, qentry;
- struct queue_set *qs;
- struct snd_queue *sq;
- qs = nic->qs;
- sq = &qs->sq[sq_num];
- subdesc_cnt = nicvf_sq_subdesc_required(nic);
- if (subdesc_cnt > sq->free_cnt)
goto append_fail;
- qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
- /* Add SQ header subdesc */
- nicvf_sq_add_hdr_subdesc(nic, sq, qentry, subdesc_cnt - 1,
pkt, pkt_size);
- /* Add SQ gather subdescs */
- qentry = nicvf_get_nxt_sqentry(sq, qentry);
- nicvf_sq_add_gather_subdesc(sq, qentry, pkt_size, (uintptr_t)(pkt));
- flush_dcache_range((uintptr_t)pkt,
(uintptr_t)pkt + pkt_size);
- /* make sure all memory stores are done before ringing doorbell */
- asm volatile ("dsb sy");
- /* Inform HW to xmit new packet */
- nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
sq_num, subdesc_cnt);
- return 1;
+append_fail:
- printf("Not enough SQ descriptors to xmit pkt\n");
- return 0;
+}
+static unsigned int frag_num(unsigned int i) +{ +#ifdef __BIG_ENDIAN
- return (i & ~3) + 3 - (i & 3);
+#else
- return i;
+#endif +}
+void *nicvf_get_rcv_pkt(struct nicvf *nic, void *cq_desc, size_t *pkt_len) +{
- int frag;
- int payload_len = 0, tot_len;
- void *pkt = NULL, *pkt_buf = NULL, *buffer;
- struct cqe_rx_t *cqe_rx;
- struct rbdr *rbdr;
- struct rcv_queue *rq;
- struct queue_set *qs = nic->qs;
- u16 *rb_lens = NULL;
- u64 *rb_ptrs = NULL;
- cqe_rx = (struct cqe_rx_t *)cq_desc;
- rq = &qs->rq[cqe_rx->rq_idx];
- rbdr = &qs->rbdr[rq->start_qs_rbdr_idx];
- rb_lens = cq_desc + (3 * sizeof(u64)); /* Use offsetof */
- /* Except 88xx pass1 on all other chips CQE_RX2_S is added to
* CQE_RX at word6, hence buffer pointers move by word
*
* Use existing 'hw_tso' flag which will be set for all chips
* except 88xx pass1 instead of a additional cache line
* access (or miss) by using pci dev's revision.
*/
- if (!nic->hw_tso)
rb_ptrs = (void *)cqe_rx + (6 * sizeof(u64));
- else
rb_ptrs = (void *)cqe_rx + (7 * sizeof(u64));
- /*
* Figure out packet length to create packet buffer
*/
- for (frag = 0; frag < cqe_rx->rb_cnt; frag++)
payload_len += rb_lens[frag_num(frag)];
- *pkt_len = payload_len;
- /* round up size to 8 byte multiple */
- tot_len = (payload_len & (~0x7)) + 8;
- buffer = calloc(1, tot_len);
- if (!buffer) {
printf("%s - Failed to allocate packet buffer\n", __func__);
return NULL;
- }
- pkt_buf = buffer;
- debug("total pkt buf %p len %ld tot_len %d\n", pkt_buf, *pkt_len,
tot_len);
- for (frag = 0; frag < cqe_rx->rb_cnt; frag++) {
payload_len = rb_lens[frag_num(frag)];
invalidate_dcache_range((uintptr_t)(*rb_ptrs),
(uintptr_t)(*rb_ptrs) + rbdr->dma_size);
/* First fragment */
*rb_ptrs = *rb_ptrs - cqe_rx->align_pad;
pkt = nicvf_rb_ptr_to_pkt(nic, *rb_ptrs);
invalidate_dcache_range((uintptr_t)pkt,
(uintptr_t)pkt + payload_len);
if (cqe_rx->align_pad)
pkt += cqe_rx->align_pad;
debug("pkt_buf %p, pkt %p payload_len %d\n", pkt_buf, pkt,
payload_len);
memcpy(buffer, pkt, payload_len);
buffer += payload_len;
/* Next buffer pointer */
rb_ptrs++;
- }
- return pkt_buf;
+}
+/* Clear interrupt */ +void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx) +{
- u64 reg_val = 0;
- switch (int_type) {
- case NICVF_INTR_CQ:
reg_val = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
- break;
- case NICVF_INTR_SQ:
reg_val = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
- break;
- case NICVF_INTR_RBDR:
reg_val = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
- break;
- case NICVF_INTR_PKT_DROP:
reg_val = (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
- break;
- case NICVF_INTR_TCP_TIMER:
reg_val = (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
- break;
- case NICVF_INTR_MBOX:
reg_val = (1ULL << NICVF_INTR_MBOX_SHIFT);
- break;
- case NICVF_INTR_QS_ERR:
reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
- break;
- default:
printf("Failed to clear interrupt: unknown type\n");
- break;
- }
- nicvf_reg_write(nic, NIC_VF_INT, reg_val);
+}
+void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx) +{
- struct rcv_queue *rq;
+#define GET_RQ_STATS(reg) \
- nicvf_reg_read(nic, NIC_QSET_RQ_0_7_STAT_0_1 |\
(rq_idx << NIC_Q_NUM_SHIFT) | ((reg) << 3))
- rq = &nic->qs->rq[rq_idx];
- rq->stats.bytes = GET_RQ_STATS(RQ_SQ_STATS_OCTS);
- rq->stats.pkts = GET_RQ_STATS(RQ_SQ_STATS_PKTS);
+}
+void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx) +{
- struct snd_queue *sq;
+#define GET_SQ_STATS(reg) \
- nicvf_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1 |\
(sq_idx << NIC_Q_NUM_SHIFT) | ((reg) << 3))
- sq = &nic->qs->sq[sq_idx];
- sq->stats.bytes = GET_SQ_STATS(RQ_SQ_STATS_OCTS);
- sq->stats.pkts = GET_SQ_STATS(RQ_SQ_STATS_PKTS);
+}
+/* Check for errors in the receive cmp.queue entry */ +int nicvf_check_cqe_rx_errs(struct nicvf *nic,
struct cmp_queue *cq, void *cq_desc)
+{
- struct cqe_rx_t *cqe_rx;
- struct cmp_queue_stats *stats = &cq->stats;
- cqe_rx = (struct cqe_rx_t *)cq_desc;
- if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
stats->rx.errop.good++;
return 0;
- }
- switch (cqe_rx->err_level) {
- case CQ_ERRLVL_MAC:
stats->rx.errlvl.mac_errs++;
- break;
- case CQ_ERRLVL_L2:
stats->rx.errlvl.l2_errs++;
- break;
- case CQ_ERRLVL_L3:
stats->rx.errlvl.l3_errs++;
- break;
- case CQ_ERRLVL_L4:
stats->rx.errlvl.l4_errs++;
- break;
- }
- switch (cqe_rx->err_opcode) {
- case CQ_RX_ERROP_RE_PARTIAL:
stats->rx.errop.partial_pkts++;
- break;
- case CQ_RX_ERROP_RE_JABBER:
stats->rx.errop.jabber_errs++;
- break;
- case CQ_RX_ERROP_RE_FCS:
stats->rx.errop.fcs_errs++;
- break;
- case CQ_RX_ERROP_RE_TERMINATE:
stats->rx.errop.terminate_errs++;
- break;
- case CQ_RX_ERROP_RE_RX_CTL:
stats->rx.errop.bgx_rx_errs++;
- break;
- case CQ_RX_ERROP_PREL2_ERR:
stats->rx.errop.prel2_errs++;
- break;
- case CQ_RX_ERROP_L2_FRAGMENT:
stats->rx.errop.l2_frags++;
- break;
- case CQ_RX_ERROP_L2_OVERRUN:
stats->rx.errop.l2_overruns++;
- break;
- case CQ_RX_ERROP_L2_PFCS:
stats->rx.errop.l2_pfcs++;
- break;
- case CQ_RX_ERROP_L2_PUNY:
stats->rx.errop.l2_puny++;
- break;
- case CQ_RX_ERROP_L2_MAL:
stats->rx.errop.l2_hdr_malformed++;
- break;
- case CQ_RX_ERROP_L2_OVERSIZE:
stats->rx.errop.l2_oversize++;
- break;
- case CQ_RX_ERROP_L2_UNDERSIZE:
stats->rx.errop.l2_undersize++;
- break;
- case CQ_RX_ERROP_L2_LENMISM:
stats->rx.errop.l2_len_mismatch++;
- break;
- case CQ_RX_ERROP_L2_PCLP:
stats->rx.errop.l2_pclp++;
- break;
- case CQ_RX_ERROP_IP_NOT:
stats->rx.errop.non_ip++;
- break;
- case CQ_RX_ERROP_IP_CSUM_ERR:
stats->rx.errop.ip_csum_err++;
- break;
- case CQ_RX_ERROP_IP_MAL:
stats->rx.errop.ip_hdr_malformed++;
- break;
- case CQ_RX_ERROP_IP_MALD:
stats->rx.errop.ip_payload_malformed++;
- break;
- case CQ_RX_ERROP_IP_HOP:
stats->rx.errop.ip_hop_errs++;
- break;
- case CQ_RX_ERROP_L3_ICRC:
stats->rx.errop.l3_icrc_errs++;
- break;
- case CQ_RX_ERROP_L3_PCLP:
stats->rx.errop.l3_pclp++;
- break;
- case CQ_RX_ERROP_L4_MAL:
stats->rx.errop.l4_malformed++;
- break;
- case CQ_RX_ERROP_L4_CHK:
stats->rx.errop.l4_csum_errs++;
- break;
- case CQ_RX_ERROP_UDP_LEN:
stats->rx.errop.udp_len_err++;
- break;
- case CQ_RX_ERROP_L4_PORT:
stats->rx.errop.bad_l4_port++;
- break;
- case CQ_RX_ERROP_TCP_FLAG:
stats->rx.errop.bad_tcp_flag++;
- break;
- case CQ_RX_ERROP_TCP_OFFSET:
stats->rx.errop.tcp_offset_errs++;
- break;
- case CQ_RX_ERROP_L4_PCLP:
stats->rx.errop.l4_pclp++;
- break;
- case CQ_RX_ERROP_RBDR_TRUNC:
stats->rx.errop.pkt_truncated++;
- break;
- }
- return 1;
+}
+/* Check for errors in the send cmp.queue entry */ +int nicvf_check_cqe_tx_errs(struct nicvf *nic,
struct cmp_queue *cq, void *cq_desc)
+{
- struct cqe_send_t *cqe_tx;
- struct cmp_queue_stats *stats = &cq->stats;
- cqe_tx = (struct cqe_send_t *)cq_desc;
- switch (cqe_tx->send_status) {
- case CQ_TX_ERROP_GOOD:
stats->tx.good++;
return 0;
- break;
- case CQ_TX_ERROP_DESC_FAULT:
stats->tx.desc_fault++;
- break;
- case CQ_TX_ERROP_HDR_CONS_ERR:
stats->tx.hdr_cons_err++;
- break;
- case CQ_TX_ERROP_SUBDC_ERR:
stats->tx.subdesc_err++;
- break;
- case CQ_TX_ERROP_IMM_SIZE_OFLOW:
stats->tx.imm_size_oflow++;
- break;
- case CQ_TX_ERROP_DATA_SEQUENCE_ERR:
stats->tx.data_seq_err++;
- break;
- case CQ_TX_ERROP_MEM_SEQUENCE_ERR:
stats->tx.mem_seq_err++;
- break;
- case CQ_TX_ERROP_LOCK_VIOL:
stats->tx.lock_viol++;
- break;
- case CQ_TX_ERROP_DATA_FAULT:
stats->tx.data_fault++;
- break;
- case CQ_TX_ERROP_TSTMP_CONFLICT:
stats->tx.tstmp_conflict++;
- break;
- case CQ_TX_ERROP_TSTMP_TIMEOUT:
stats->tx.tstmp_timeout++;
- break;
- case CQ_TX_ERROP_MEM_FAULT:
stats->tx.mem_fault++;
- break;
- case CQ_TX_ERROP_CK_OVERLAP:
stats->tx.csum_overlap++;
- break;
- case CQ_TX_ERROP_CK_OFLOW:
stats->tx.csum_overflow++;
- break;
- }
- return 1;
+} diff --git a/drivers/net/octeontx/nicvf_queues.h b/drivers/net/octeontx/nicvf_queues.h new file mode 100644 index 0000000000..833b2a1dd4 --- /dev/null +++ b/drivers/net/octeontx/nicvf_queues.h @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2018 Marvell International Ltd.
- */
+#ifndef NICVF_QUEUES_H +#define NICVF_QUEUES_H
+#include "q_struct.h"
+#define MAX_QUEUE_SET 128 +#define MAX_RCV_QUEUES_PER_QS 8 +#define MAX_RCV_BUF_DESC_RINGS_PER_QS 2 +#define MAX_SND_QUEUES_PER_QS 8 +#define MAX_CMP_QUEUES_PER_QS 8
+/* VF's queue interrupt ranges */ +#define NICVF_INTR_ID_CQ 0 +#define NICVF_INTR_ID_SQ 8 +#define NICVF_INTR_ID_RBDR 16 +#define NICVF_INTR_ID_MISC 18 +#define NICVF_INTR_ID_QS_ERR 19
+#define RBDR_SIZE0 0ULL /* 8K entries */ +#define RBDR_SIZE1 1ULL /* 16K entries */ +#define RBDR_SIZE2 2ULL /* 32K entries */ +#define RBDR_SIZE3 3ULL /* 64K entries */ +#define RBDR_SIZE4 4ULL /* 126K entries */ +#define RBDR_SIZE5 5ULL /* 256K entries */ +#define RBDR_SIZE6 6ULL /* 512K entries */
+#define SND_QUEUE_SIZE0 0ULL /* 1K entries */ +#define SND_QUEUE_SIZE1 1ULL /* 2K entries */ +#define SND_QUEUE_SIZE2 2ULL /* 4K entries */ +#define SND_QUEUE_SIZE3 3ULL /* 8K entries */ +#define SND_QUEUE_SIZE4 4ULL /* 16K entries */ +#define SND_QUEUE_SIZE5 5ULL /* 32K entries */ +#define SND_QUEUE_SIZE6 6ULL /* 64K entries */
+#define CMP_QUEUE_SIZE0 0ULL /* 1K entries */ +#define CMP_QUEUE_SIZE1 1ULL /* 2K entries */ +#define CMP_QUEUE_SIZE2 2ULL /* 4K entries */ +#define CMP_QUEUE_SIZE3 3ULL /* 8K entries */ +#define CMP_QUEUE_SIZE4 4ULL /* 16K entries */ +#define CMP_QUEUE_SIZE5 5ULL /* 32K entries */ +#define CMP_QUEUE_SIZE6 6ULL /* 64K entries */
+/* Default queue count per QS, its lengths and threshold values */ +#define RBDR_CNT 1 +#define RCV_QUEUE_CNT 1 +#define SND_QUEUE_CNT 1 +#define CMP_QUEUE_CNT 1 /* Max of RCV and SND qcount */
+#define SND_QSIZE SND_QUEUE_SIZE0 +#define SND_QUEUE_LEN BIT_ULL((SND_QSIZE + 10)) +#define SND_QUEUE_THRESH 2ULL +#define MIN_SQ_DESC_PER_PKT_XMIT 2 +#define MAX_CQE_PER_PKT_XMIT 2
+#define CMP_QSIZE CMP_QUEUE_SIZE0 +#define CMP_QUEUE_LEN BIT_ULL((CMP_QSIZE + 10)) +#define CMP_QUEUE_CQE_THRESH 0 +#define CMP_QUEUE_TIMER_THRESH 1 /* 1 ms */
+#define RBDR_SIZE RBDR_SIZE0 +#define RCV_BUF_COUNT BIT_ULL((RBDR_SIZE + 13)) +#define RBDR_THRESH (RCV_BUF_COUNT / 2) +#define DMA_BUFFER_LEN 2048 /* In multiples of 128bytes */ +#define RCV_FRAG_LEN DMA_BUFFER_LEN
+#define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) *\
MAX_CQE_PER_PKT_XMIT)
+#define RQ_CQ_DROP ((CMP_QUEUE_LEN - MAX_CQES_FOR_TX) / 256)
+/* Descriptor size */ +#define SND_QUEUE_DESC_SIZE 16 /* 128 bits */ +#define CMP_QUEUE_DESC_SIZE 512
+/* Buffer / descriptor alignments */ +#define NICVF_RCV_BUF_ALIGN 7 +#define NICVF_RCV_BUF_ALIGN_BYTES BIT_ULL(NICVF_RCV_BUF_ALIGN) +#define NICVF_CQ_BASE_ALIGN_BYTES 512 /* 9 bits */ +#define NICVF_SQ_BASE_ALIGN_BYTES 128 /* 7 bits */
+#define NICVF_ALIGNED_ADDR(ADDR, ALIGN_BYTES) ALIGN(ADDR, ALIGN_BYTES)
+/* Queue enable/disable */ +#define NICVF_SQ_EN BIT_ULL(19)
+/* Queue reset */ +#define NICVF_CQ_RESET BIT_ULL(41) +#define NICVF_SQ_RESET BIT_ULL(17) +#define NICVF_RBDR_RESET BIT_ULL(43)
+enum CQ_RX_ERRLVL_E {
- CQ_ERRLVL_MAC,
- CQ_ERRLVL_L2,
- CQ_ERRLVL_L3,
- CQ_ERRLVL_L4,
+};
+enum CQ_RX_ERROP_E {
- CQ_RX_ERROP_RE_NONE = 0x0,
- CQ_RX_ERROP_RE_PARTIAL = 0x1,
- CQ_RX_ERROP_RE_JABBER = 0x2,
- CQ_RX_ERROP_RE_FCS = 0x7,
- CQ_RX_ERROP_RE_TERMINATE = 0x9,
- CQ_RX_ERROP_RE_RX_CTL = 0xb,
- CQ_RX_ERROP_PREL2_ERR = 0x1f,
- CQ_RX_ERROP_L2_FRAGMENT = 0x20,
- CQ_RX_ERROP_L2_OVERRUN = 0x21,
- CQ_RX_ERROP_L2_PFCS = 0x22,
- CQ_RX_ERROP_L2_PUNY = 0x23,
- CQ_RX_ERROP_L2_MAL = 0x24,
- CQ_RX_ERROP_L2_OVERSIZE = 0x25,
- CQ_RX_ERROP_L2_UNDERSIZE = 0x26,
- CQ_RX_ERROP_L2_LENMISM = 0x27,
- CQ_RX_ERROP_L2_PCLP = 0x28,
- CQ_RX_ERROP_IP_NOT = 0x41,
- CQ_RX_ERROP_IP_CSUM_ERR = 0x42,
- CQ_RX_ERROP_IP_MAL = 0x43,
- CQ_RX_ERROP_IP_MALD = 0x44,
- CQ_RX_ERROP_IP_HOP = 0x45,
- CQ_RX_ERROP_L3_ICRC = 0x46,
- CQ_RX_ERROP_L3_PCLP = 0x47,
- CQ_RX_ERROP_L4_MAL = 0x61,
- CQ_RX_ERROP_L4_CHK = 0x62,
- CQ_RX_ERROP_UDP_LEN = 0x63,
- CQ_RX_ERROP_L4_PORT = 0x64,
- CQ_RX_ERROP_TCP_FLAG = 0x65,
- CQ_RX_ERROP_TCP_OFFSET = 0x66,
- CQ_RX_ERROP_L4_PCLP = 0x67,
- CQ_RX_ERROP_RBDR_TRUNC = 0x70,
+};
+enum CQ_TX_ERROP_E {
- CQ_TX_ERROP_GOOD = 0x0,
- CQ_TX_ERROP_DESC_FAULT = 0x10,
- CQ_TX_ERROP_HDR_CONS_ERR = 0x11,
- CQ_TX_ERROP_SUBDC_ERR = 0x12,
- CQ_TX_ERROP_IMM_SIZE_OFLOW = 0x80,
- CQ_TX_ERROP_DATA_SEQUENCE_ERR = 0x81,
- CQ_TX_ERROP_MEM_SEQUENCE_ERR = 0x82,
- CQ_TX_ERROP_LOCK_VIOL = 0x83,
- CQ_TX_ERROP_DATA_FAULT = 0x84,
- CQ_TX_ERROP_TSTMP_CONFLICT = 0x85,
- CQ_TX_ERROP_TSTMP_TIMEOUT = 0x86,
- CQ_TX_ERROP_MEM_FAULT = 0x87,
- CQ_TX_ERROP_CK_OVERLAP = 0x88,
- CQ_TX_ERROP_CK_OFLOW = 0x89,
- CQ_TX_ERROP_ENUM_LAST = 0x8a,
+};
+struct cmp_queue_stats {
- struct rx_stats {
struct {
u64 mac_errs;
u64 l2_errs;
u64 l3_errs;
u64 l4_errs;
} errlvl;
struct {
u64 good;
u64 partial_pkts;
u64 jabber_errs;
u64 fcs_errs;
u64 terminate_errs;
u64 bgx_rx_errs;
u64 prel2_errs;
u64 l2_frags;
u64 l2_overruns;
u64 l2_pfcs;
u64 l2_puny;
u64 l2_hdr_malformed;
u64 l2_oversize;
u64 l2_undersize;
u64 l2_len_mismatch;
u64 l2_pclp;
u64 non_ip;
u64 ip_csum_err;
u64 ip_hdr_malformed;
u64 ip_payload_malformed;
u64 ip_hop_errs;
u64 l3_icrc_errs;
u64 l3_pclp;
u64 l4_malformed;
u64 l4_csum_errs;
u64 udp_len_err;
u64 bad_l4_port;
u64 bad_tcp_flag;
u64 tcp_offset_errs;
u64 l4_pclp;
u64 pkt_truncated;
} errop;
- } rx;
- struct tx_stats {
u64 good;
u64 desc_fault;
u64 hdr_cons_err;
u64 subdesc_err;
u64 imm_size_oflow;
u64 data_seq_err;
u64 mem_seq_err;
u64 lock_viol;
u64 data_fault;
u64 tstmp_conflict;
u64 tstmp_timeout;
u64 mem_fault;
u64 csum_overlap;
u64 csum_overflow;
- } tx;
+};
+enum RQ_SQ_STATS {
- RQ_SQ_STATS_OCTS,
- RQ_SQ_STATS_PKTS,
+};
+struct rx_tx_queue_stats {
- u64 bytes;
- u64 pkts;
+};
+struct q_desc_mem {
- uintptr_t dma;
- u64 size;
- u16 q_len;
- uintptr_t phys_base;
- void *base;
- void *unalign_base;
- bool allocated;
+};
+struct rbdr {
- bool enable;
- u32 dma_size;
- u32 thresh; /* Threshold level for interrupt */
- void *desc;
- u32 head;
- u32 tail;
- struct q_desc_mem dmem;
- uintptr_t buf_mem;
- uintptr_t buffers;
+};
+struct rcv_queue {
- bool enable;
- struct rbdr *rbdr_start;
- struct rbdr *rbdr_cont;
- bool en_tcp_reassembly;
- u8 cq_qs; /* CQ's QS to which this RQ is assigned */
- u8 cq_idx; /* CQ index (0 to 7) in the QS */
- u8 cont_rbdr_qs; /* Continue buffer ptrs - QS num */
- u8 cont_qs_rbdr_idx; /* RBDR idx in the cont QS */
- u8 start_rbdr_qs; /* First buffer ptrs - QS num */
- u8 start_qs_rbdr_idx; /* RBDR idx in the above QS */
- u8 caching;
- struct rx_tx_queue_stats stats;
+};
+struct cmp_queue {
- bool enable;
- u16 intr_timer_thresh;
- u16 thresh;
- void *desc;
- struct q_desc_mem dmem;
- struct cmp_queue_stats stats;
+};
+struct snd_queue {
- bool enable;
- u8 cq_qs; /* CQ's QS to which this SQ is pointing */
- u8 cq_idx; /* CQ index (0 to 7) in the above QS */
- u16 thresh;
- u32 free_cnt;
- u32 head;
- u32 tail;
- u64 *skbuff;
- void *desc;
- struct q_desc_mem dmem;
- struct rx_tx_queue_stats stats;
+};
+struct queue_set {
- bool enable;
- bool be_en;
- u8 vnic_id;
- u8 rq_cnt;
- u8 cq_cnt;
- u64 cq_len;
- u8 sq_cnt;
- u64 sq_len;
- u8 rbdr_cnt;
- u64 rbdr_len;
- struct rcv_queue rq[MAX_RCV_QUEUES_PER_QS];
- struct cmp_queue cq[MAX_CMP_QUEUES_PER_QS];
- struct snd_queue sq[MAX_SND_QUEUES_PER_QS];
- struct rbdr rbdr[MAX_RCV_BUF_DESC_RINGS_PER_QS];
+};
+#define GET_RBDR_DESC(RING, idx)\
(&(((struct rbdr_entry_t *)((RING)->desc))[idx]))
+#define GET_SQ_DESC(RING, idx)\
(&(((struct sq_hdr_subdesc *)((RING)->desc))[idx]))
+#define GET_CQ_DESC(RING, idx)\
(&(((union cq_desc_t *)((RING)->desc))[idx]))
+/* CQ status bits */ +#define CQ_WR_FULL BIT(26) +#define CQ_WR_DISABLE BIT(25) +#define CQ_WR_FAULT BIT(24) +#define CQ_CQE_COUNT (0xFFFF << 0)
+#define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
+int nicvf_set_qset_resources(struct nicvf *nic); +int nicvf_config_data_transfer(struct nicvf *nic, bool enable); +void nicvf_qset_config(struct nicvf *nic, bool enable); +void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable);
+void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx); +void nicvf_sq_disable(struct nicvf *nic, int qidx); +void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt); +void nicvf_sq_free_used_descs(struct udevice *dev,
struct snd_queue *sq, int qidx);
+int nicvf_sq_append_pkt(struct nicvf *nic, void *pkt, size_t pkt_len);
+void *nicvf_get_rcv_pkt(struct nicvf *nic, void *cq_desc, size_t *pkt_len); +void nicvf_refill_rbdr(struct nicvf *nic);
+void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx); +void nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx); +void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx); +int nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx);
+/* Register access APIs */ +void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val); +u64 nicvf_reg_read(struct nicvf *nic, u64 offset); +void nicvf_qset_reg_write(struct nicvf *nic, u64 offset, u64 val); +u64 nicvf_qset_reg_read(struct nicvf *nic, u64 offset); +void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
u64 qidx, u64 val);
+u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx);
+/* Stats */ +void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx); +void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx); +int nicvf_check_cqe_rx_errs(struct nicvf *nic,
struct cmp_queue *cq, void *cq_desc);
+int nicvf_check_cqe_tx_errs(struct nicvf *nic,
struct cmp_queue *cq, void *cq_desc);
+#endif /* NICVF_QUEUES_H */ diff --git a/drivers/net/octeontx/q_struct.h b/drivers/net/octeontx/q_struct.h new file mode 100644 index 0000000000..87abb132f5 --- /dev/null +++ b/drivers/net/octeontx/q_struct.h @@ -0,0 +1,695 @@ +/* SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2018 Marvell International Ltd.
- */
+#ifndef Q_STRUCT_H +#define Q_STRUCT_H
+/* Load transaction types for reading segment bytes specified by
- NIC_SEND_GATHER_S[LD_TYPE].
- */
+enum nic_send_ld_type_e {
- NIC_SEND_LD_TYPE_E_LDD = 0x0,
- NIC_SEND_LD_TYPE_E_LDT = 0x1,
- NIC_SEND_LD_TYPE_E_LDWB = 0x2,
- NIC_SEND_LD_TYPE_E_ENUM_LAST = 0x3,
+};
+enum ether_type_algorithm {
- ETYPE_ALG_NONE = 0x0,
- ETYPE_ALG_SKIP = 0x1,
- ETYPE_ALG_ENDPARSE = 0x2,
- ETYPE_ALG_VLAN = 0x3,
- ETYPE_ALG_VLAN_STRIP = 0x4,
+};
+enum layer3_type {
- L3TYPE_NONE = 0x00,
- L3TYPE_GRH = 0x01,
- L3TYPE_IPV4 = 0x04,
- L3TYPE_IPV4_OPTIONS = 0x05,
- L3TYPE_IPV6 = 0x06,
- L3TYPE_IPV6_OPTIONS = 0x07,
- L3TYPE_ET_STOP = 0x0D,
- L3TYPE_OTHER = 0x0E,
+};
+enum layer4_type {
- L4TYPE_NONE = 0x00,
- L4TYPE_IPSEC_ESP = 0x01,
- L4TYPE_IPFRAG = 0x02,
- L4TYPE_IPCOMP = 0x03,
- L4TYPE_TCP = 0x04,
- L4TYPE_UDP = 0x05,
- L4TYPE_SCTP = 0x06,
- L4TYPE_GRE = 0x07,
- L4TYPE_ROCE_BTH = 0x08,
- L4TYPE_OTHER = 0x0E,
+};
+/* CPI and RSSI configuration */ +enum cpi_algorithm_type {
- CPI_ALG_NONE = 0x0,
- CPI_ALG_VLAN = 0x1,
- CPI_ALG_VLAN16 = 0x2,
- CPI_ALG_DIFF = 0x3,
+};
+enum rss_algorithm_type {
- RSS_ALG_NONE = 0x00,
- RSS_ALG_PORT = 0x01,
- RSS_ALG_IP = 0x02,
- RSS_ALG_TCP_IP = 0x03,
- RSS_ALG_UDP_IP = 0x04,
- RSS_ALG_SCTP_IP = 0x05,
- RSS_ALG_GRE_IP = 0x06,
- RSS_ALG_ROCE = 0x07,
+};
+enum rss_hash_cfg {
- RSS_HASH_L2ETC = 0x00,
- RSS_HASH_IP = 0x01,
- RSS_HASH_TCP = 0x02,
- RSS_TCP_SYN_DIS = 0x03,
- RSS_HASH_UDP = 0x04,
- RSS_HASH_L4ETC = 0x05,
- RSS_HASH_ROCE = 0x06,
- RSS_L3_BIDI = 0x07,
- RSS_L4_BIDI = 0x08,
+};
+/* Completion queue entry types */ +enum cqe_type {
- CQE_TYPE_INVALID = 0x0,
- CQE_TYPE_RX = 0x2,
- CQE_TYPE_RX_SPLIT = 0x3,
- CQE_TYPE_RX_TCP = 0x4,
- CQE_TYPE_SEND = 0x8,
- CQE_TYPE_SEND_PTP = 0x9,
+};
+enum cqe_rx_tcp_status {
- CQE_RX_STATUS_VALID_TCP_CNXT = 0x00,
- CQE_RX_STATUS_INVALID_TCP_CNXT = 0x0F,
+};
+enum cqe_send_status {
- CQE_SEND_STATUS_GOOD = 0x00,
- CQE_SEND_STATUS_DESC_FAULT = 0x01,
- CQE_SEND_STATUS_HDR_CONS_ERR = 0x11,
- CQE_SEND_STATUS_SUBDESC_ERR = 0x12,
- CQE_SEND_STATUS_IMM_SIZE_OFLOW = 0x80,
- CQE_SEND_STATUS_CRC_SEQ_ERR = 0x81,
- CQE_SEND_STATUS_DATA_SEQ_ERR = 0x82,
- CQE_SEND_STATUS_MEM_SEQ_ERR = 0x83,
- CQE_SEND_STATUS_LOCK_VIOL = 0x84,
- CQE_SEND_STATUS_LOCK_UFLOW = 0x85,
- CQE_SEND_STATUS_DATA_FAULT = 0x86,
- CQE_SEND_STATUS_TSTMP_CONFLICT = 0x87,
- CQE_SEND_STATUS_TSTMP_TIMEOUT = 0x88,
- CQE_SEND_STATUS_MEM_FAULT = 0x89,
- CQE_SEND_STATUS_CSUM_OVERLAP = 0x8A,
- CQE_SEND_STATUS_CSUM_OVERFLOW = 0x8B,
+};
+enum cqe_rx_tcp_end_reason {
- CQE_RX_TCP_END_FIN_FLAG_DET = 0,
- CQE_RX_TCP_END_INVALID_FLAG = 1,
- CQE_RX_TCP_END_TIMEOUT = 2,
- CQE_RX_TCP_END_OUT_OF_SEQ = 3,
- CQE_RX_TCP_END_PKT_ERR = 4,
- CQE_RX_TCP_END_QS_DISABLED = 0x0F,
+};
+/* Packet protocol level error enumeration */ +enum cqe_rx_err_level {
- CQE_RX_ERRLVL_RE = 0x0,
- CQE_RX_ERRLVL_L2 = 0x1,
- CQE_RX_ERRLVL_L3 = 0x2,
- CQE_RX_ERRLVL_L4 = 0x3,
+};
+/* Packet protocol level error type enumeration */ +enum cqe_rx_err_opcode {
- CQE_RX_ERR_RE_NONE = 0x0,
- CQE_RX_ERR_RE_PARTIAL = 0x1,
- CQE_RX_ERR_RE_JABBER = 0x2,
- CQE_RX_ERR_RE_FCS = 0x7,
- CQE_RX_ERR_RE_TERMINATE = 0x9,
- CQE_RX_ERR_RE_RX_CTL = 0xb,
- CQE_RX_ERR_PREL2_ERR = 0x1f,
- CQE_RX_ERR_L2_FRAGMENT = 0x20,
- CQE_RX_ERR_L2_OVERRUN = 0x21,
- CQE_RX_ERR_L2_PFCS = 0x22,
- CQE_RX_ERR_L2_PUNY = 0x23,
- CQE_RX_ERR_L2_MAL = 0x24,
- CQE_RX_ERR_L2_OVERSIZE = 0x25,
- CQE_RX_ERR_L2_UNDERSIZE = 0x26,
- CQE_RX_ERR_L2_LENMISM = 0x27,
- CQE_RX_ERR_L2_PCLP = 0x28,
- CQE_RX_ERR_IP_NOT = 0x41,
- CQE_RX_ERR_IP_CHK = 0x42,
- CQE_RX_ERR_IP_MAL = 0x43,
- CQE_RX_ERR_IP_MALD = 0x44,
- CQE_RX_ERR_IP_HOP = 0x45,
- CQE_RX_ERR_L3_ICRC = 0x46,
- CQE_RX_ERR_L3_PCLP = 0x47,
- CQE_RX_ERR_L4_MAL = 0x61,
- CQE_RX_ERR_L4_CHK = 0x62,
- CQE_RX_ERR_UDP_LEN = 0x63,
- CQE_RX_ERR_L4_PORT = 0x64,
- CQE_RX_ERR_TCP_FLAG = 0x65,
- CQE_RX_ERR_TCP_OFFSET = 0x66,
- CQE_RX_ERR_L4_PCLP = 0x67,
- CQE_RX_ERR_RBDR_TRUNC = 0x70,
+};
+struct cqe_rx_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 cqe_type:4; /* W0 */
- u64 stdn_fault:1;
- u64 rsvd0:1;
- u64 rq_qs:7;
- u64 rq_idx:3;
- u64 rsvd1:12;
- u64 rss_alg:4;
- u64 rsvd2:4;
- u64 rb_cnt:4;
- u64 vlan_found:1;
- u64 vlan_stripped:1;
- u64 vlan2_found:1;
- u64 vlan2_stripped:1;
- u64 l4_type:4;
- u64 l3_type:4;
- u64 l2_present:1;
- u64 err_level:3;
- u64 err_opcode:8;
- u64 pkt_len:16; /* W1 */
- u64 l2_ptr:8;
- u64 l3_ptr:8;
- u64 l4_ptr:8;
- u64 cq_pkt_len:8;
- u64 align_pad:3;
- u64 rsvd3:1;
- u64 chan:12;
- u64 rss_tag:32; /* W2 */
- u64 vlan_tci:16;
- u64 vlan_ptr:8;
- u64 vlan2_ptr:8;
- u64 rb3_sz:16; /* W3 */
- u64 rb2_sz:16;
- u64 rb1_sz:16;
- u64 rb0_sz:16;
- u64 rb7_sz:16; /* W4 */
- u64 rb6_sz:16;
- u64 rb5_sz:16;
- u64 rb4_sz:16;
- u64 rb11_sz:16; /* W5 */
- u64 rb10_sz:16;
- u64 rb9_sz:16;
- u64 rb8_sz:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 err_opcode:8;
- u64 err_level:3;
- u64 l2_present:1;
- u64 l3_type:4;
- u64 l4_type:4;
- u64 vlan2_stripped:1;
- u64 vlan2_found:1;
- u64 vlan_stripped:1;
- u64 vlan_found:1;
- u64 rb_cnt:4;
- u64 rsvd2:4;
- u64 rss_alg:4;
- u64 rsvd1:12;
- u64 rq_idx:3;
- u64 rq_qs:7;
- u64 rsvd0:1;
- u64 stdn_fault:1;
- u64 cqe_type:4; /* W0 */
- u64 chan:12;
- u64 rsvd3:1;
- u64 align_pad:3;
- u64 cq_pkt_len:8;
- u64 l4_ptr:8;
- u64 l3_ptr:8;
- u64 l2_ptr:8;
- u64 pkt_len:16; /* W1 */
- u64 vlan2_ptr:8;
- u64 vlan_ptr:8;
- u64 vlan_tci:16;
- u64 rss_tag:32; /* W2 */
- u64 rb0_sz:16;
- u64 rb1_sz:16;
- u64 rb2_sz:16;
- u64 rb3_sz:16; /* W3 */
- u64 rb4_sz:16;
- u64 rb5_sz:16;
- u64 rb6_sz:16;
- u64 rb7_sz:16; /* W4 */
- u64 rb8_sz:16;
- u64 rb9_sz:16;
- u64 rb10_sz:16;
- u64 rb11_sz:16; /* W5 */
+#endif
- u64 rb0_ptr:64;
- u64 rb1_ptr:64;
- u64 rb2_ptr:64;
- u64 rb3_ptr:64;
- u64 rb4_ptr:64;
- u64 rb5_ptr:64;
- u64 rb6_ptr:64;
- u64 rb7_ptr:64;
- u64 rb8_ptr:64;
- u64 rb9_ptr:64;
- u64 rb10_ptr:64;
- u64 rb11_ptr:64;
+};
+struct cqe_rx_tcp_err_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 cqe_type:4; /* W0 */
- u64 rsvd0:60;
- u64 rsvd1:4; /* W1 */
- u64 partial_first:1;
- u64 rsvd2:27;
- u64 rbdr_bytes:8;
- u64 rsvd3:24;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 rsvd0:60;
- u64 cqe_type:4;
- u64 rsvd3:24;
- u64 rbdr_bytes:8;
- u64 rsvd2:27;
- u64 partial_first:1;
- u64 rsvd1:4;
+#endif +};
+struct cqe_rx_tcp_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 cqe_type:4; /* W0 */
- u64 rsvd0:52;
- u64 cq_tcp_status:8;
- u64 rsvd1:32; /* W1 */
- u64 tcp_cntx_bytes:8;
- u64 rsvd2:8;
- u64 tcp_err_bytes:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 cq_tcp_status:8;
- u64 rsvd0:52;
- u64 cqe_type:4; /* W0 */
- u64 tcp_err_bytes:16;
- u64 rsvd2:8;
- u64 tcp_cntx_bytes:8;
- u64 rsvd1:32; /* W1 */
+#endif +};
+struct cqe_send_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 cqe_type:4; /* W0 */
- u64 rsvd0:4;
- u64 sqe_ptr:16;
- u64 rsvd1:4;
- u64 rsvd2:10;
- u64 sq_qs:7;
- u64 sq_idx:3;
- u64 rsvd3:8;
- u64 send_status:8;
- u64 ptp_timestamp:64; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 send_status:8;
- u64 rsvd3:8;
- u64 sq_idx:3;
- u64 sq_qs:7;
- u64 rsvd2:10;
- u64 rsvd1:4;
- u64 sqe_ptr:16;
- u64 rsvd0:4;
- u64 cqe_type:4; /* W0 */
- u64 ptp_timestamp:64; /* W1 */
+#endif +};
+union cq_desc_t {
- u64 u[64];
- struct cqe_send_t snd_hdr;
- struct cqe_rx_t rx_hdr;
- struct cqe_rx_tcp_t rx_tcp_hdr;
- struct cqe_rx_tcp_err_t rx_tcp_err_hdr;
+};
+struct rbdr_entry_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 rsvd0:15;
- u64 buf_addr:42;
- u64 cache_align:7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 cache_align:7;
- u64 buf_addr:42;
- u64 rsvd0:15;
+#endif +};
+/* TCP reassembly context */ +struct rbe_tcp_cnxt_t { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 tcp_pkt_cnt:12;
- u64 rsvd1:4;
- u64 align_hdr_bytes:4;
- u64 align_ptr_bytes:4;
- u64 ptr_bytes:16;
- u64 rsvd2:24;
- u64 cqe_type:4;
- u64 rsvd0:54;
- u64 tcp_end_reason:2;
- u64 tcp_status:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 tcp_status:4;
- u64 tcp_end_reason:2;
- u64 rsvd0:54;
- u64 cqe_type:4;
- u64 rsvd2:24;
- u64 ptr_bytes:16;
- u64 align_ptr_bytes:4;
- u64 align_hdr_bytes:4;
- u64 rsvd1:4;
- u64 tcp_pkt_cnt:12;
+#endif +};
+/* Always Big endian */ +struct rx_hdr_t {
- u64 opaque:32;
- u64 rss_flow:8;
- u64 skip_length:6;
- u64 disable_rss:1;
- u64 disable_tcp_reassembly:1;
- u64 nodrop:1;
- u64 dest_alg:2;
- u64 rsvd0:2;
- u64 dest_rq:11;
+};
+enum send_l4_csum_type {
- SEND_L4_CSUM_DISABLE = 0x00,
- SEND_L4_CSUM_UDP = 0x01,
- SEND_L4_CSUM_TCP = 0x02,
- SEND_L4_CSUM_SCTP = 0x03,
+};
+enum send_crc_alg {
- SEND_CRCALG_CRC32 = 0x00,
- SEND_CRCALG_CRC32C = 0x01,
- SEND_CRCALG_ICRC = 0x02,
+};
+enum send_load_type {
- SEND_LD_TYPE_LDD = 0x00,
- SEND_LD_TYPE_LDT = 0x01,
- SEND_LD_TYPE_LDWB = 0x02,
+};
+enum send_mem_alg_type {
- SEND_MEMALG_SET = 0x00,
- SEND_MEMALG_ADD = 0x08,
- SEND_MEMALG_SUB = 0x09,
- SEND_MEMALG_ADDLEN = 0x0A,
- SEND_MEMALG_SUBLEN = 0x0B,
+};
+enum send_mem_dsz_type {
- SEND_MEMDSZ_B64 = 0x00,
- SEND_MEMDSZ_B32 = 0x01,
- SEND_MEMDSZ_B8 = 0x03,
+};
+enum sq_subdesc_type {
- SQ_DESC_TYPE_INVALID = 0x00,
- SQ_DESC_TYPE_HEADER = 0x01,
- SQ_DESC_TYPE_CRC = 0x02,
- SQ_DESC_TYPE_IMMEDIATE = 0x03,
- SQ_DESC_TYPE_GATHER = 0x04,
- SQ_DESC_TYPE_MEMORY = 0x05,
+};
+struct sq_crc_subdesc { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 rsvd1:32;
- u64 crc_ival:32;
- u64 subdesc_type:4;
- u64 crc_alg:2;
- u64 rsvd0:10;
- u64 crc_insert_pos:16;
- u64 hdr_start:16;
- u64 crc_len:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 crc_len:16;
- u64 hdr_start:16;
- u64 crc_insert_pos:16;
- u64 rsvd0:10;
- u64 crc_alg:2;
- u64 subdesc_type:4;
- u64 crc_ival:32;
- u64 rsvd1:32;
+#endif +};
+struct sq_gather_subdesc { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 subdesc_type:4; /* W0 */
- u64 ld_type:2;
- u64 rsvd0:42;
- u64 size:16;
- u64 rsvd1:15; /* W1 */
- u64 addr:49;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 size:16;
- u64 rsvd0:42;
- u64 ld_type:2;
- u64 subdesc_type:4; /* W0 */
- u64 addr:49;
- u64 rsvd1:15; /* W1 */
+#endif +};
+/* SQ immediate subdescriptor */ +struct sq_imm_subdesc { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 subdesc_type:4; /* W0 */
- u64 rsvd0:46;
- u64 len:14;
- u64 data:64; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 len:14;
- u64 rsvd0:46;
- u64 subdesc_type:4; /* W0 */
- u64 data:64; /* W1 */
+#endif +};
+struct sq_mem_subdesc { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 subdesc_type:4; /* W0 */
- u64 mem_alg:4;
- u64 mem_dsz:2;
- u64 wmem:1;
- u64 rsvd0:21;
- u64 offset:32;
- u64 rsvd1:15; /* W1 */
- u64 addr:49;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 offset:32;
- u64 rsvd0:21;
- u64 wmem:1;
- u64 mem_dsz:2;
- u64 mem_alg:4;
- u64 subdesc_type:4; /* W0 */
- u64 addr:49;
- u64 rsvd1:15; /* W1 */
+#endif +};
+struct sq_hdr_subdesc { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 subdesc_type:4;
- u64 tso:1;
- u64 post_cqe:1; /* Post CQE on no error also */
- u64 dont_send:1;
- u64 tstmp:1;
- u64 subdesc_cnt:8;
- u64 csum_l4:2;
- u64 csum_l3:1;
- u64 rsvd0:5;
- u64 l4_offset:8;
- u64 l3_offset:8;
- u64 rsvd1:4;
- u64 tot_len:20; /* W0 */
- u64 tso_sdc_cont:8;
- u64 tso_sdc_first:8;
- u64 tso_l4_offset:8;
- u64 tso_flags_last:12;
- u64 tso_flags_first:12;
- u64 rsvd2:2;
- u64 tso_max_paysize:14; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 tot_len:20;
- u64 rsvd1:4;
- u64 l3_offset:8;
- u64 l4_offset:8;
- u64 rsvd0:5;
- u64 csum_l3:1;
- u64 csum_l4:2;
- u64 subdesc_cnt:8;
- u64 tstmp:1;
- u64 dont_send:1;
- u64 post_cqe:1; /* Post CQE on no error also */
- u64 tso:1;
- u64 subdesc_type:4; /* W0 */
- u64 tso_max_paysize:14;
- u64 rsvd2:2;
- u64 tso_flags_first:12;
- u64 tso_flags_last:12;
- u64 tso_l4_offset:8;
- u64 tso_sdc_first:8;
- u64 tso_sdc_cont:8; /* W1 */
+#endif +};
+/* Queue config register formats */ +struct rq_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 reserved_2_63:62;
- u64 ena:1;
- u64 tcp_ena:1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 tcp_ena:1;
- u64 ena:1;
- u64 reserved_2_63:62;
+#endif +};
+struct cq_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 reserved_43_63:21;
- u64 ena:1;
- u64 reset:1;
- u64 caching:1;
- u64 reserved_35_39:5;
- u64 qsize:3;
- u64 reserved_25_31:7;
- u64 avg_con:9;
- u64 reserved_0_15:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 reserved_0_15:16;
- u64 avg_con:9;
- u64 reserved_25_31:7;
- u64 qsize:3;
- u64 reserved_35_39:5;
- u64 caching:1;
- u64 reset:1;
- u64 ena:1;
- u64 reserved_43_63:21;
+#endif +};
+struct sq_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 reserved_20_63:44;
- u64 ena:1;
- u64 reserved_18_18:1;
- u64 reset:1;
- u64 ldwb:1;
- u64 reserved_11_15:5;
- u64 qsize:3;
- u64 reserved_3_7:5;
- u64 tstmp_bgx_intf:3;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 tstmp_bgx_intf:3;
- u64 reserved_3_7:5;
- u64 qsize:3;
- u64 reserved_11_15:5;
- u64 ldwb:1;
- u64 reset:1;
- u64 reserved_18_18:1;
- u64 ena:1;
- u64 reserved_20_63:44;
+#endif +};
+struct rbdr_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 reserved_45_63:19;
- u64 ena:1;
- u64 reset:1;
- u64 ldwb:1;
- u64 reserved_36_41:6;
- u64 qsize:4;
- u64 reserved_25_31:7;
- u64 avg_con:9;
- u64 reserved_12_15:4;
- u64 lines:12;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 lines:12;
- u64 reserved_12_15:4;
- u64 avg_con:9;
- u64 reserved_25_31:7;
- u64 qsize:4;
- u64 reserved_36_41:6;
- u64 ldwb:1;
- u64 reset:1;
- u64 ena: 1;
- u64 reserved_45_63:19;
+#endif +};
+struct qs_cfg { +#if defined(__BIG_ENDIAN_BITFIELD)
- u64 reserved_32_63:32;
- u64 ena:1;
- u64 reserved_27_30:4;
- u64 sq_ins_ena:1;
- u64 sq_ins_pos:6;
- u64 lock_ena:1;
- u64 lock_viol_cqe_ena:1;
- u64 send_tstmp_ena:1;
- u64 be:1;
- u64 reserved_7_15:9;
- u64 vnic:7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u64 vnic:7;
- u64 reserved_7_15:9;
- u64 be:1;
- u64 send_tstmp_ena:1;
- u64 lock_viol_cqe_ena:1;
- u64 lock_ena:1;
- u64 sq_ins_pos:6;
- u64 sq_ins_ena:1;
- u64 reserved_27_30:4;
- u64 ena:1;
- u64 reserved_32_63:32;
+#endif +};
+#endif /* Q_STRUCT_H */ diff --git a/drivers/net/octeontx/smi.c b/drivers/net/octeontx/smi.c new file mode 100644 index 0000000000..8e2c3ca5a3 --- /dev/null +++ b/drivers/net/octeontx/smi.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <dm.h> +#include <malloc.h> +#include <miiphy.h> +#include <misc.h> +#include <pci.h> +#include <pci_ids.h> +#include <phy.h> +#include <asm/io.h> +#include <linux/ctype.h> +#include <linux/delay.h>
+#define PCI_DEVICE_ID_OCTEONTX_SMI 0xA02B
+DECLARE_GLOBAL_DATA_PTR;
+enum octeontx_smi_mode {
- CLAUSE22 = 0,
- CLAUSE45 = 1,
+};
+enum {
- SMI_OP_C22_WRITE = 0,
- SMI_OP_C22_READ = 1,
- SMI_OP_C45_ADDR = 0,
- SMI_OP_C45_WRITE = 1,
- SMI_OP_C45_PRIA = 2,
- SMI_OP_C45_READ = 3,
+};
+union smi_x_clk {
- u64 u;
- struct smi_x_clk_s {
int phase:8;
int sample:4;
int preamble:1;
int clk_idle:1;
int reserved_14_14:1;
int sample_mode:1;
int sample_hi:5;
int reserved_21_23:3;
int mode:1;
- } s;
+};
+union smi_x_cmd {
- u64 u;
- struct smi_x_cmd_s {
int reg_adr:5;
int reserved_5_7:3;
int phy_adr:5;
int reserved_13_15:3;
int phy_op:2;
- } s;
+};
+union smi_x_wr_dat {
- u64 u;
- struct smi_x_wr_dat_s {
unsigned int dat:16;
int val:1;
int pending:1;
- } s;
+};
+union smi_x_rd_dat {
- u64 u;
- struct smi_x_rd_dat_s {
unsigned int dat:16;
int val:1;
int pending:1;
- } s;
+};
+union smi_x_en {
- u64 u;
- struct smi_x_en_s {
int en:1;
- } s;
+};
+#define SMI_X_RD_DAT 0x10ull +#define SMI_X_WR_DAT 0x08ull +#define SMI_X_CMD 0x00ull +#define SMI_X_CLK 0x18ull +#define SMI_X_EN 0x20ull
+struct octeontx_smi_priv {
- void __iomem *baseaddr;
- enum octeontx_smi_mode mode;
+};
+#define MDIO_TIMEOUT 10000
+void octeontx_smi_setmode(struct mii_dev *bus, enum octeontx_smi_mode mode) +{
- struct octeontx_smi_priv *priv = bus->priv;
- union smi_x_clk smix_clk;
- smix_clk.u = readq(priv->baseaddr + SMI_X_CLK);
- smix_clk.s.mode = mode;
- smix_clk.s.preamble = mode == CLAUSE45;
- writeq(smix_clk.u, priv->baseaddr + SMI_X_CLK);
- priv->mode = mode;
+}
+int octeontx_c45_addr(struct mii_dev *bus, int addr, int devad, int regnum) +{
- struct octeontx_smi_priv *priv = bus->priv;
- union smi_x_cmd smix_cmd;
- union smi_x_wr_dat smix_wr_dat;
- unsigned long timeout = MDIO_TIMEOUT;
- smix_wr_dat.u = 0;
- smix_wr_dat.s.dat = regnum;
- writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
- smix_cmd.u = 0;
- smix_cmd.s.phy_op = SMI_OP_C45_ADDR;
- smix_cmd.s.phy_adr = addr;
- smix_cmd.s.reg_adr = devad;
- writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
- do {
smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
udelay(100);
timeout--;
- } while (smix_wr_dat.s.pending && timeout);
- return timeout == 0;
+}
+int octeontx_phy_read(struct mii_dev *bus, int addr, int devad, int regnum) +{
- struct octeontx_smi_priv *priv = bus->priv;
- union smi_x_cmd smix_cmd;
- union smi_x_rd_dat smix_rd_dat;
- unsigned long timeout = MDIO_TIMEOUT;
- int ret;
- enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
- debug("RD: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
mode, priv->baseaddr, addr, devad, regnum);
- octeontx_smi_setmode(bus, mode);
- if (mode == CLAUSE45) {
ret = octeontx_c45_addr(bus, addr, devad, regnum);
debug("RD: ret: %u\n", ret);
if (ret)
return 0;
- }
- smix_cmd.u = 0;
- smix_cmd.s.phy_adr = addr;
- if (mode == CLAUSE45) {
smix_cmd.s.reg_adr = devad;
smix_cmd.s.phy_op = SMI_OP_C45_READ;
- } else {
smix_cmd.s.reg_adr = regnum;
smix_cmd.s.phy_op = SMI_OP_C22_READ;
- }
- writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
- do {
smix_rd_dat.u = readq(priv->baseaddr + SMI_X_RD_DAT);
udelay(10);
timeout--;
- } while (smix_rd_dat.s.pending && timeout);
- debug("SMIX_RD_DAT: %lx\n", (unsigned long)smix_rd_dat.u);
- return smix_rd_dat.s.dat;
+}
+int octeontx_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
u16 value)
+{
- struct octeontx_smi_priv *priv = bus->priv;
- union smi_x_cmd smix_cmd;
- union smi_x_wr_dat smix_wr_dat;
- unsigned long timeout = MDIO_TIMEOUT;
- int ret;
- enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
- debug("WR: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
mode, priv->baseaddr, addr, devad, regnum);
- if (mode == CLAUSE45) {
ret = octeontx_c45_addr(bus, addr, devad, regnum);
debug("WR: ret: %u\n", ret);
if (ret)
return ret;
- }
- smix_wr_dat.u = 0;
- smix_wr_dat.s.dat = value;
- writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
- smix_cmd.u = 0;
- smix_cmd.s.phy_adr = addr;
- if (mode == CLAUSE45) {
smix_cmd.s.reg_adr = devad;
smix_cmd.s.phy_op = SMI_OP_C45_WRITE;
- } else {
smix_cmd.s.reg_adr = regnum;
smix_cmd.s.phy_op = SMI_OP_C22_WRITE;
- }
- writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
- do {
smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
udelay(10);
timeout--;
- } while (smix_wr_dat.s.pending && timeout);
- debug("SMIX_WR_DAT: %lx\n", (unsigned long)smix_wr_dat.u);
- return timeout == 0;
+}
+int octeontx_smi_reset(struct mii_dev *bus) +{
- struct octeontx_smi_priv *priv = bus->priv;
- union smi_x_en smi_en;
- smi_en.s.en = 0;
- writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
- smi_en.s.en = 1;
- writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
- octeontx_smi_setmode(bus, CLAUSE22);
- return 0;
+}
+/* PHY XS initialization, primarily for RXAUI
- */
+int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr) +{
- int reg;
- ulong start_time;
- int phy_id1, phy_id2;
- int oui, model_number;
- phy_id1 = octeontx_phy_read(bus, phy_addr, 1, 0x2);
- phy_id2 = octeontx_phy_read(bus, phy_addr, 1, 0x3);
- model_number = (phy_id2 >> 4) & 0x3F;
- debug("%s model %x\n", __func__, model_number);
- oui = phy_id1;
- oui <<= 6;
- oui |= (phy_id2 >> 10) & 0x3F;
- debug("%s oui %x\n", __func__, oui);
- switch (oui) {
- case 0x5016:
if (model_number == 9) {
debug("%s +\n", __func__);
/* Perform hardware reset in XGXS control */
reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
if ((reg & 0xffff) < 0)
goto read_error;
reg |= 0x8000;
octeontx_phy_write(bus, phy_addr, 4, 0x0, reg);
start_time = get_timer(0);
do {
reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
if ((reg & 0xffff) < 0)
goto read_error;
} while ((reg & 0x8000) && get_timer(start_time) < 500);
if (reg & 0x8000) {
printf("HW reset for M88X3120 PHY failed");
printf("MII_BMCR: 0x%x\n", reg);
return -1;
}
/* program 4.49155 with 0x5 */
octeontx_phy_write(bus, phy_addr, 4, 0xc003, 0x5);
}
break;
- default:
break;
- }
- return 0;
+read_error:
- debug("M88X3120 PHY config read failed\n");
- return -1;
+}
+int octeontx_smi_probe(struct udevice *dev) +{
- int ret, subnode, cnt = 0, node = dev->node.of_offset;
- struct mii_dev *bus;
- struct octeontx_smi_priv *priv;
- pci_dev_t bdf = dm_pci_get_bdf(dev);
- debug("SMI PCI device: %x\n", bdf);
- dev->req_seq = PCI_FUNC(bdf);
- if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM)) {
printf("Failed to map PCI region for bdf %x\n", bdf);
return -1;
- }
- fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
ret = fdt_node_check_compatible(gd->fdt_blob, subnode,
"cavium,thunder-8890-mdio");
if (ret)
continue;
bus = mdio_alloc();
priv = malloc(sizeof(*priv));
if (!bus || !priv) {
printf("Failed to allocate OcteonTX MDIO bus # %u\n",
dev->seq);
return -1;
}
bus->read = octeontx_phy_read;
bus->write = octeontx_phy_write;
bus->reset = octeontx_smi_reset;
bus->priv = priv;
priv->mode = CLAUSE22;
priv->baseaddr = (void __iomem *)fdtdec_get_addr(gd->fdt_blob,
subnode,
"reg");
debug("mdio base addr %p\n", priv->baseaddr);
/* use given name or generate its own unique name */
snprintf(bus->name, MDIO_NAME_LEN, "smi%d", cnt++);
ret = mdio_register(bus);
if (ret)
return ret;
- }
- return 0;
+}
+static const struct udevice_id octeontx_smi_ids[] = {
- { .compatible = "cavium,thunder-8890-mdio-nexus" },
- {}
+};
+U_BOOT_DRIVER(octeontx_smi) = {
- .name = "octeontx_smi",
- .id = UCLASS_MISC,
- .probe = octeontx_smi_probe,
- .of_match = octeontx_smi_ids,
+};
+static struct pci_device_id octeontx_smi_supported[] = {
- { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_SMI) },
- {}
+};
+U_BOOT_PCI_DEVICE(octeontx_smi, octeontx_smi_supported); diff --git a/drivers/net/octeontx/xcv.c b/drivers/net/octeontx/xcv.c new file mode 100644 index 0000000000..8dd558b1bf --- /dev/null +++ b/drivers/net/octeontx/xcv.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2018 Marvell International Ltd.
- */
+#include <config.h> +#include <dm.h> +#include <errno.h> +#include <fdt_support.h> +#include <pci.h> +#include <malloc.h> +#include <miiphy.h> +#include <misc.h> +#include <net.h> +#include <netdev.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/libfdt.h>
+#include <asm/arch/csrs/csrs-xcv.h>
+#define XCVX_BASE 0x87E0DB000000ULL
+/* Initialize XCV block */ +void xcv_init_hw(void) +{
- union xcvx_reset reset;
- union xcvx_dll_ctl xcv_dll_ctl;
- /* Take the DLL out of reset */
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- reset.s.dllrst = 0;
- writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
- /* Take the clock tree out of reset */
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- reset.s.clkrst = 0;
- writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
- /* Once the 125MHz ref clock is stable, wait 10us for DLL to lock */
- udelay(10);
- /* Optionally, bypass the DLL setting */
- xcv_dll_ctl.u = readq(XCVX_BASE + XCVX_DLL_CTL(0));
- xcv_dll_ctl.s.clkrx_set = 0;
- xcv_dll_ctl.s.clkrx_byp = 1;
- xcv_dll_ctl.s.clktx_byp = 0;
- writeq(xcv_dll_ctl.u, XCVX_BASE + XCVX_DLL_CTL(0));
- /* Enable the compensation controller */
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- reset.s.comp = 1;
- writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- /* Wait for 1040 reference clock cycles for the compensation state
* machine lock.
*/
- udelay(100);
- /* Enable the XCV block */
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- reset.s.enable = 1;
- writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
- /* set XCV(0)_RESET[CLKRST] to 1 */
- reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- reset.s.clkrst = 1;
- writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
+}
+/*
- Configure XCV link based on the speed
- link_up : Set to 1 when link is up otherwise 0
- link_speed: The speed of the link.
- */
+void xcv_setup_link(bool link_up, int link_speed) +{
- union xcvx_ctl xcv_ctl;
- union xcvx_reset reset;
- union xcvx_batch_crd_ret xcv_crd_ret;
- int speed = 2;
- /* Check RGMII link */
- if (link_speed == 100)
speed = 1;
- else if (link_speed == 10)
speed = 0;
- if (link_up) {
/* Set operating speed */
xcv_ctl.u = readq(XCVX_BASE + XCVX_CTL(0));
xcv_ctl.s.speed = speed;
writeq(xcv_ctl.u, XCVX_BASE + XCVX_CTL(0));
/* Datapaths come out of reset
* - The datapath resets will disengage BGX from the
* RGMII interface
* - XCV will continue to return TX credits for each tick
* that is sent on the TX data path
*/
reset.u = readq(XCVX_BASE + XCVX_RESET(0));
reset.s.tx_dat_rst_n = 1;
reset.s.rx_dat_rst_n = 1;
writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
/* Enable packet flow */
reset.u = readq(XCVX_BASE + XCVX_RESET(0));
reset.s.tx_pkt_rst_n = 1;
reset.s.rx_pkt_rst_n = 1;
writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
xcv_crd_ret.u = readq(XCVX_BASE + XCVX_BATCH_CRD_RET(0));
xcv_crd_ret.s.crd_ret = 1;
writeq(xcv_crd_ret.u, XCVX_BASE + XCVX_BATCH_CRD_RET(0));
- } else {
/* Enable packet flow */
reset.u = readq(XCVX_BASE + XCVX_RESET(0));
reset.s.tx_pkt_rst_n = 0;
reset.s.rx_pkt_rst_n = 0;
writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
reset.u = readq(XCVX_BASE + XCVX_RESET(0));
- }
+}
Viele Grüße, Stefan