common/cnxk: support NIX LSO and misc utils
authorSunil Kumar Kori <skori@marvell.com>
Tue, 6 Apr 2021 14:41:23 +0000 (20:11 +0530)
committerJerin Jacob <jerinj@marvell.com>
Fri, 9 Apr 2021 06:32:24 +0000 (08:32 +0200)
Add support to create LSO formats for TCP segmentation offload
for IPv4/IPv6, tunnel and non-tunnel protocols. Tunnel protocol
support is for GRE and UDP based tunnel protocols.

This patch also adds other helper API to retrieve eeprom info
and configure Rx for different switch headers.

Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Acked-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
drivers/common/cnxk/meson.build
drivers/common/cnxk/roc_nix.h
drivers/common/cnxk/roc_nix_debug.c
drivers/common/cnxk/roc_nix_ops.c [new file with mode: 0644]
drivers/common/cnxk/roc_nix_priv.h
drivers/common/cnxk/version.map

index 33eeb8c..d8514b3 100644 (file)
@@ -22,6 +22,7 @@ sources = files('roc_dev.c',
                'roc_nix_mac.c',
                'roc_nix_mcast.c',
                'roc_nix_npc.c',
+               'roc_nix_ops.c',
                'roc_nix_ptp.c',
                'roc_nix_queue.c',
                'roc_nix_rss.c',
index 2158f8c..ce8c252 100644 (file)
@@ -59,6 +59,12 @@ struct roc_nix_fc_cfg {
        };
 };
 
+struct roc_nix_eeprom_info {
+#define ROC_NIX_EEPROM_SIZE 256
+       uint16_t sff_id;
+       uint8_t buf[ROC_NIX_EEPROM_SIZE];
+};
+
 /* Range to adjust PTP frequency. Valid range is
  * (-ROC_NIX_PTP_FREQ_ADJUST, ROC_NIX_PTP_FREQ_ADJUST)
  */
@@ -246,6 +252,14 @@ struct roc_nix {
        uint8_t reserved[ROC_NIX_MEM_SZ] __plt_cache_aligned;
 } __plt_cache_aligned;
 
+enum roc_nix_lso_tun_type {
+       ROC_NIX_LSO_TUN_V4V4,
+       ROC_NIX_LSO_TUN_V4V6,
+       ROC_NIX_LSO_TUN_V6V4,
+       ROC_NIX_LSO_TUN_V6V6,
+       ROC_NIX_LSO_TUN_MAX,
+};
+
 /* Dev */
 int __roc_api roc_nix_dev_init(struct roc_nix *roc_nix);
 int __roc_api roc_nix_dev_fini(struct roc_nix *roc_nix);
@@ -315,6 +329,20 @@ int __roc_api roc_nix_mac_link_cb_register(struct roc_nix *roc_nix,
                                           link_status_t link_update);
 void __roc_api roc_nix_mac_link_cb_unregister(struct roc_nix *roc_nix);
 
+/* Ops */
+int __roc_api roc_nix_switch_hdr_set(struct roc_nix *roc_nix,
+                                    uint64_t switch_header_type);
+int __roc_api roc_nix_lso_fmt_setup(struct roc_nix *roc_nix);
+int __roc_api roc_nix_lso_fmt_get(struct roc_nix *roc_nix,
+                                 uint8_t udp_tun[ROC_NIX_LSO_TUN_MAX],
+                                 uint8_t tun[ROC_NIX_LSO_TUN_MAX]);
+int __roc_api roc_nix_lso_custom_fmt_setup(struct roc_nix *roc_nix,
+                                          struct nix_lso_format *fields,
+                                          uint16_t nb_fields);
+
+int __roc_api roc_nix_eeprom_info_get(struct roc_nix *roc_nix,
+                                     struct roc_nix_eeprom_info *info);
+
 /* Flow control */
 int __roc_api roc_nix_fc_config_set(struct roc_nix *roc_nix,
                                    struct roc_nix_fc_cfg *fc_cfg);
index 00712d5..a0cf98e 100644 (file)
@@ -786,6 +786,22 @@ roc_nix_dump(struct roc_nix *roc_nix)
        nix_dump("  \tnb_tx_queues = %d", nix->nb_tx_queues);
        nix_dump("  \tlso_tsov6_idx = %d", nix->lso_tsov6_idx);
        nix_dump("  \tlso_tsov4_idx = %d", nix->lso_tsov4_idx);
+       nix_dump("  \tlso_udp_tun_v4v4 = %d",
+                nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V4V4]);
+       nix_dump("  \tlso_udp_tun_v4v6 = %d",
+                nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V4V6]);
+       nix_dump("  \tlso_udp_tun_v6v4 = %d",
+                nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V6V4]);
+       nix_dump("  \tlso_udp_tun_v6v6 = %d",
+                nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V6V6]);
+       nix_dump("  \tlso_tun_v4v4 = %d",
+                nix->lso_tun_idx[ROC_NIX_LSO_TUN_V4V4]);
+       nix_dump("  \tlso_tun_v4v6 = %d",
+                nix->lso_tun_idx[ROC_NIX_LSO_TUN_V4V6]);
+       nix_dump("  \tlso_tun_v6v4 = %d",
+                nix->lso_tun_idx[ROC_NIX_LSO_TUN_V6V4]);
+       nix_dump("  \tlso_tun_v6v6 = %d",
+                nix->lso_tun_idx[ROC_NIX_LSO_TUN_V6V6]);
        nix_dump("  \tlf_rx_stats = %d", nix->lf_rx_stats);
        nix_dump("  \tlf_tx_stats = %d", nix->lf_tx_stats);
        nix_dump("  \trx_chan_cnt = %d", nix->rx_chan_cnt);
diff --git a/drivers/common/cnxk/roc_nix_ops.c b/drivers/common/cnxk/roc_nix_ops.c
new file mode 100644 (file)
index 0000000..eeb85a5
--- /dev/null
@@ -0,0 +1,438 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+static inline struct mbox *
+get_mbox(struct roc_nix *roc_nix)
+{
+       struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+       struct dev *dev = &nix->dev;
+
+       return dev->mbox;
+}
+
+static void
+nix_lso_tcp(struct nix_lso_format_cfg *req, bool v4)
+{
+       __io struct nix_lso_format *field;
+
+       /* Format works only with TCP packet marked by OL3/OL4 */
+       field = (__io struct nix_lso_format *)&req->fields[0];
+       req->field_mask = NIX_LSO_FIELD_MASK;
+       /* Outer IPv4/IPv6 */
+       field->layer = NIX_TXLAYER_OL3;
+       field->offset = v4 ? 2 : 4;
+       field->sizem1 = 1; /* 2B */
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+       if (v4) {
+               /* IPID field */
+               field->layer = NIX_TXLAYER_OL3;
+               field->offset = 4;
+               field->sizem1 = 1;
+               /* Incremented linearly per segment */
+               field->alg = NIX_LSOALG_ADD_SEGNUM;
+               field++;
+       }
+
+       /* TCP sequence number update */
+       field->layer = NIX_TXLAYER_OL4;
+       field->offset = 4;
+       field->sizem1 = 3; /* 4 bytes */
+       field->alg = NIX_LSOALG_ADD_OFFSET;
+       field++;
+       /* TCP flags field */
+       field->layer = NIX_TXLAYER_OL4;
+       field->offset = 12;
+       field->sizem1 = 1;
+       field->alg = NIX_LSOALG_TCP_FLAGS;
+       field++;
+}
+
+static void
+nix_lso_udp_tun_tcp(struct nix_lso_format_cfg *req, bool outer_v4,
+                   bool inner_v4)
+{
+       __io struct nix_lso_format *field;
+
+       field = (__io struct nix_lso_format *)&req->fields[0];
+       req->field_mask = NIX_LSO_FIELD_MASK;
+       /* Outer IPv4/IPv6 len */
+       field->layer = NIX_TXLAYER_OL3;
+       field->offset = outer_v4 ? 2 : 4;
+       field->sizem1 = 1; /* 2B */
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+       if (outer_v4) {
+               /* IPID */
+               field->layer = NIX_TXLAYER_OL3;
+               field->offset = 4;
+               field->sizem1 = 1;
+               /* Incremented linearly per segment */
+               field->alg = NIX_LSOALG_ADD_SEGNUM;
+               field++;
+       }
+
+       /* Outer UDP length */
+       field->layer = NIX_TXLAYER_OL4;
+       field->offset = 4;
+       field->sizem1 = 1;
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+
+       /* Inner IPv4/IPv6 */
+       field->layer = NIX_TXLAYER_IL3;
+       field->offset = inner_v4 ? 2 : 4;
+       field->sizem1 = 1; /* 2B */
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+       if (inner_v4) {
+               /* IPID field */
+               field->layer = NIX_TXLAYER_IL3;
+               field->offset = 4;
+               field->sizem1 = 1;
+               /* Incremented linearly per segment */
+               field->alg = NIX_LSOALG_ADD_SEGNUM;
+               field++;
+       }
+
+       /* TCP sequence number update */
+       field->layer = NIX_TXLAYER_IL4;
+       field->offset = 4;
+       field->sizem1 = 3; /* 4 bytes */
+       field->alg = NIX_LSOALG_ADD_OFFSET;
+       field++;
+
+       /* TCP flags field */
+       field->layer = NIX_TXLAYER_IL4;
+       field->offset = 12;
+       field->sizem1 = 1;
+       field->alg = NIX_LSOALG_TCP_FLAGS;
+       field++;
+}
+
+static void
+nix_lso_tun_tcp(struct nix_lso_format_cfg *req, bool outer_v4, bool inner_v4)
+{
+       __io struct nix_lso_format *field;
+
+       field = (__io struct nix_lso_format *)&req->fields[0];
+       req->field_mask = NIX_LSO_FIELD_MASK;
+       /* Outer IPv4/IPv6 len */
+       field->layer = NIX_TXLAYER_OL3;
+       field->offset = outer_v4 ? 2 : 4;
+       field->sizem1 = 1; /* 2B */
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+       if (outer_v4) {
+               /* IPID */
+               field->layer = NIX_TXLAYER_OL3;
+               field->offset = 4;
+               field->sizem1 = 1;
+               /* Incremented linearly per segment */
+               field->alg = NIX_LSOALG_ADD_SEGNUM;
+               field++;
+       }
+
+       /* Inner IPv4/IPv6 */
+       field->layer = NIX_TXLAYER_IL3;
+       field->offset = inner_v4 ? 2 : 4;
+       field->sizem1 = 1; /* 2B */
+       field->alg = NIX_LSOALG_ADD_PAYLEN;
+       field++;
+       if (inner_v4) {
+               /* IPID field */
+               field->layer = NIX_TXLAYER_IL3;
+               field->offset = 4;
+               field->sizem1 = 1;
+               /* Incremented linearly per segment */
+               field->alg = NIX_LSOALG_ADD_SEGNUM;
+               field++;
+       }
+
+       /* TCP sequence number update */
+       field->layer = NIX_TXLAYER_IL4;
+       field->offset = 4;
+       field->sizem1 = 3; /* 4 bytes */
+       field->alg = NIX_LSOALG_ADD_OFFSET;
+       field++;
+
+       /* TCP flags field */
+       field->layer = NIX_TXLAYER_IL4;
+       field->offset = 12;
+       field->sizem1 = 1;
+       field->alg = NIX_LSOALG_TCP_FLAGS;
+       field++;
+}
+
+int
+roc_nix_lso_custom_fmt_setup(struct roc_nix *roc_nix,
+                            struct nix_lso_format *fields, uint16_t nb_fields)
+{
+       struct mbox *mbox = get_mbox(roc_nix);
+       struct nix_lso_format_cfg_rsp *rsp;
+       struct nix_lso_format_cfg *req;
+       int rc = -ENOSPC;
+
+       if (nb_fields > NIX_LSO_FIELD_MAX)
+               return -EINVAL;
+
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return rc;
+
+       req->field_mask = NIX_LSO_FIELD_MASK;
+       mbox_memcpy(req->fields, fields,
+                   sizeof(struct nix_lso_format) * nb_fields);
+
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       plt_nix_dbg("Setup custom format %u", rsp->lso_format_idx);
+       return rsp->lso_format_idx;
+}
+
+int
+roc_nix_lso_fmt_setup(struct roc_nix *roc_nix)
+{
+       struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+       struct mbox *mbox = get_mbox(roc_nix);
+       struct nix_lso_format_cfg_rsp *rsp;
+       struct nix_lso_format_cfg *req;
+       int rc = -ENOSPC;
+
+       /*
+        * IPv4/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return rc;
+       nix_lso_tcp(req, true);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       if (rsp->lso_format_idx != NIX_LSO_FORMAT_IDX_TSOV4)
+               return NIX_ERR_INTERNAL;
+
+       plt_nix_dbg("tcpv4 lso fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv6/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_tcp(req, false);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       if (rsp->lso_format_idx != NIX_LSO_FORMAT_IDX_TSOV6)
+               return NIX_ERR_INTERNAL;
+
+       plt_nix_dbg("tcpv6 lso fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv4/UDP/TUN HDR/IPv4/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_udp_tun_tcp(req, true, true);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V4V4] = rsp->lso_format_idx;
+       plt_nix_dbg("udp tun v4v4 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv4/UDP/TUN HDR/IPv6/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_udp_tun_tcp(req, true, false);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V4V6] = rsp->lso_format_idx;
+       plt_nix_dbg("udp tun v4v6 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv6/UDP/TUN HDR/IPv4/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_udp_tun_tcp(req, false, true);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V6V4] = rsp->lso_format_idx;
+       plt_nix_dbg("udp tun v6v4 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv6/UDP/TUN HDR/IPv6/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_udp_tun_tcp(req, false, false);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_udp_tun_idx[ROC_NIX_LSO_TUN_V6V6] = rsp->lso_format_idx;
+       plt_nix_dbg("udp tun v6v6 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv4/TUN HDR/IPv4/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_tun_tcp(req, true, true);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_tun_idx[ROC_NIX_LSO_TUN_V4V4] = rsp->lso_format_idx;
+       plt_nix_dbg("tun v4v4 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv4/TUN HDR/IPv6/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_tun_tcp(req, true, false);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_tun_idx[ROC_NIX_LSO_TUN_V4V6] = rsp->lso_format_idx;
+       plt_nix_dbg("tun v4v6 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv6/TUN HDR/IPv4/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_tun_tcp(req, false, true);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_tun_idx[ROC_NIX_LSO_TUN_V6V4] = rsp->lso_format_idx;
+       plt_nix_dbg("tun v6v4 fmt=%u\n", rsp->lso_format_idx);
+
+       /*
+        * IPv6/TUN HDR/IPv6/TCP LSO
+        */
+       req = mbox_alloc_msg_nix_lso_format_cfg(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       nix_lso_tun_tcp(req, false, false);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       nix->lso_tun_idx[ROC_NIX_LSO_TUN_V6V6] = rsp->lso_format_idx;
+       plt_nix_dbg("tun v6v6 fmt=%u\n", rsp->lso_format_idx);
+       return 0;
+}
+
+int
+roc_nix_lso_fmt_get(struct roc_nix *roc_nix,
+                   uint8_t udp_tun[ROC_NIX_LSO_TUN_MAX],
+                   uint8_t tun[ROC_NIX_LSO_TUN_MAX])
+{
+       struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+
+       memcpy(udp_tun, nix->lso_udp_tun_idx, ROC_NIX_LSO_TUN_MAX);
+       memcpy(tun, nix->lso_tun_idx, ROC_NIX_LSO_TUN_MAX);
+       return 0;
+}
+
+int
+roc_nix_switch_hdr_set(struct roc_nix *roc_nix, uint64_t switch_header_type)
+{
+       struct mbox *mbox = get_mbox(roc_nix);
+       struct npc_set_pkind *req;
+       struct msg_resp *rsp;
+       int rc = -ENOSPC;
+
+       if (switch_header_type == 0)
+               switch_header_type = ROC_PRIV_FLAGS_DEFAULT;
+
+       if (switch_header_type != ROC_PRIV_FLAGS_DEFAULT &&
+           switch_header_type != ROC_PRIV_FLAGS_EDSA &&
+           switch_header_type != ROC_PRIV_FLAGS_HIGIG &&
+           switch_header_type != ROC_PRIV_FLAGS_LEN_90B &&
+           switch_header_type != ROC_PRIV_FLAGS_CUSTOM) {
+               plt_err("switch header type is not supported");
+               return NIX_ERR_PARAM;
+       }
+
+       if (switch_header_type == ROC_PRIV_FLAGS_LEN_90B &&
+           !roc_nix_is_sdp(roc_nix)) {
+               plt_err("chlen90b is not supported on non-SDP device");
+               return NIX_ERR_PARAM;
+       }
+
+       if (switch_header_type == ROC_PRIV_FLAGS_HIGIG &&
+           roc_nix_is_vf_or_sdp(roc_nix)) {
+               plt_err("higig2 is supported on PF devices only");
+               return NIX_ERR_PARAM;
+       }
+
+       req = mbox_alloc_msg_npc_set_pkind(mbox);
+       if (req == NULL)
+               return rc;
+       req->mode = switch_header_type;
+       req->dir = PKIND_RX;
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       req = mbox_alloc_msg_npc_set_pkind(mbox);
+       if (req == NULL)
+               return -ENOSPC;
+       req->mode = switch_header_type;
+       req->dir = PKIND_TX;
+       return mbox_process_msg(mbox, (void *)&rsp);
+}
+
+int
+roc_nix_eeprom_info_get(struct roc_nix *roc_nix,
+                       struct roc_nix_eeprom_info *info)
+{
+       struct mbox *mbox = get_mbox(roc_nix);
+       struct cgx_fw_data *rsp = NULL;
+       int rc;
+
+       if (!info) {
+               plt_err("Input buffer is NULL");
+               return NIX_ERR_PARAM;
+       }
+
+       mbox_alloc_msg_cgx_get_aux_link_info(mbox);
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc) {
+               plt_err("Failed to get fw data: %d", rc);
+               return rc;
+       }
+
+       info->sff_id = rsp->fwdata.sfp_eeprom.sff_id;
+       mbox_memcpy(info->buf, rsp->fwdata.sfp_eeprom.buf, SFP_EEPROM_SIZE);
+       return 0;
+}
index c54f45a..115ee34 100644 (file)
@@ -45,6 +45,8 @@ struct nix {
        uint16_t nb_tx_queues;
        uint8_t lso_tsov6_idx;
        uint8_t lso_tsov4_idx;
+       uint8_t lso_udp_tun_idx[ROC_NIX_LSO_TUN_MAX];
+       uint8_t lso_tun_idx[ROC_NIX_LSO_TUN_MAX];
        uint8_t lf_rx_stats;
        uint8_t lf_tx_stats;
        uint8_t rx_chan_cnt;
index 48182a0..299fd90 100644 (file)
@@ -39,6 +39,9 @@ INTERNAL {
        roc_nix_lf_free;
        roc_nix_lf_get_reg_count;
        roc_nix_lf_reg_dump;
+       roc_nix_lso_custom_fmt_setup;
+       roc_nix_lso_fmt_get;
+       roc_nix_lso_fmt_setup;
        roc_nix_mac_addr_add;
        roc_nix_mac_addr_del;
        roc_nix_mac_addr_set;
@@ -98,6 +101,8 @@ INTERNAL {
        roc_nix_num_xstats_get;
        roc_nix_xstats_get;
        roc_nix_xstats_names_get;
+       roc_nix_switch_hdr_set;
+       roc_nix_eeprom_info_get;
        roc_nix_unregister_cq_irqs;
        roc_nix_unregister_queue_irqs;
        roc_nix_vlan_insert_ena_dis;