--- /dev/null
+/* 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;
+}