From dfa267ec54ac9740895786f838b41cb54a735213 Mon Sep 17 00:00:00 2001 From: Sunil Kumar Kori Date: Tue, 6 Apr 2021 20:11:23 +0530 Subject: [PATCH] common/cnxk: support NIX LSO and misc utils 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 Acked-by: Nithin Dabilpuram --- drivers/common/cnxk/meson.build | 1 + drivers/common/cnxk/roc_nix.h | 28 ++ drivers/common/cnxk/roc_nix_debug.c | 16 + drivers/common/cnxk/roc_nix_ops.c | 438 ++++++++++++++++++++++++++++ drivers/common/cnxk/roc_nix_priv.h | 2 + drivers/common/cnxk/version.map | 5 + 6 files changed, 490 insertions(+) create mode 100644 drivers/common/cnxk/roc_nix_ops.c diff --git a/drivers/common/cnxk/meson.build b/drivers/common/cnxk/meson.build index 33eeb8c1be..d8514b39bc 100644 --- a/drivers/common/cnxk/meson.build +++ b/drivers/common/cnxk/meson.build @@ -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', diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h index 2158f8cecd..ce8c252bb2 100644 --- a/drivers/common/cnxk/roc_nix.h +++ b/drivers/common/cnxk/roc_nix.h @@ -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); diff --git a/drivers/common/cnxk/roc_nix_debug.c b/drivers/common/cnxk/roc_nix_debug.c index 00712d5501..a0cf98e842 100644 --- a/drivers/common/cnxk/roc_nix_debug.c +++ b/drivers/common/cnxk/roc_nix_debug.c @@ -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 index 0000000000..eeb85a54f9 --- /dev/null +++ b/drivers/common/cnxk/roc_nix_ops.c @@ -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; +} diff --git a/drivers/common/cnxk/roc_nix_priv.h b/drivers/common/cnxk/roc_nix_priv.h index c54f45ad9a..115ee34dbe 100644 --- a/drivers/common/cnxk/roc_nix_priv.h +++ b/drivers/common/cnxk/roc_nix_priv.h @@ -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; diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map index 48182a081a..299fd90e91 100644 --- a/drivers/common/cnxk/version.map +++ b/drivers/common/cnxk/version.map @@ -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;