mirror of https://github.com/F-Stack/f-stack.git
473 lines
9.9 KiB
C
473 lines
9.9 KiB
C
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||
|
* Copyright(C) 2021 Marvell.
|
||
|
*/
|
||
|
|
||
|
#include "roc_api.h"
|
||
|
#include "roc_priv.h"
|
||
|
|
||
|
bool
|
||
|
roc_nix_is_lbk(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return nix->lbk_link;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_get_base_chan(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return nix->rx_chan_base;
|
||
|
}
|
||
|
|
||
|
uint16_t
|
||
|
roc_nix_get_vwqe_interval(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return nix->vwqe_interval;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
roc_nix_is_sdp(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return nix->sdp_link;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
roc_nix_is_pf(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return !dev_is_vf(&nix->dev);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_get_pf(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct dev *dev = &nix->dev;
|
||
|
|
||
|
return dev_get_pf(dev->pf_func);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_get_vf(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct dev *dev = &nix->dev;
|
||
|
|
||
|
return dev_get_vf(dev->pf_func);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
roc_nix_is_vf_or_sdp(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
return (dev_is_vf(&nix->dev) != 0) || roc_nix_is_sdp(roc_nix);
|
||
|
}
|
||
|
|
||
|
uint16_t
|
||
|
roc_nix_get_pf_func(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct dev *dev = &nix->dev;
|
||
|
|
||
|
return dev->pf_func;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_lf_inl_ipsec_cfg(struct roc_nix *roc_nix, struct roc_nix_ipsec_cfg *cfg,
|
||
|
bool enb)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct nix_inline_ipsec_lf_cfg *lf_cfg;
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
|
||
|
lf_cfg = mbox_alloc_msg_nix_inline_ipsec_lf_cfg(mbox);
|
||
|
if (lf_cfg == NULL)
|
||
|
return -ENOSPC;
|
||
|
|
||
|
if (enb) {
|
||
|
lf_cfg->enable = 1;
|
||
|
lf_cfg->sa_base_addr = cfg->iova;
|
||
|
lf_cfg->ipsec_cfg1.sa_idx_w = plt_log2_u32(cfg->max_sa);
|
||
|
lf_cfg->ipsec_cfg0.lenm1_max = roc_nix_max_pkt_len(roc_nix) - 1;
|
||
|
lf_cfg->ipsec_cfg1.sa_idx_max = cfg->max_sa - 1;
|
||
|
lf_cfg->ipsec_cfg0.sa_pow2_size = plt_log2_u32(cfg->sa_size);
|
||
|
lf_cfg->ipsec_cfg0.tag_const = cfg->tag_const;
|
||
|
lf_cfg->ipsec_cfg0.tt = cfg->tt;
|
||
|
} else {
|
||
|
lf_cfg->enable = 0;
|
||
|
}
|
||
|
|
||
|
return mbox_process(mbox);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_cpt_ctx_cache_sync(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
struct msg_req *req;
|
||
|
|
||
|
req = mbox_alloc_msg_cpt_ctx_cache_sync(mbox);
|
||
|
if (req == NULL)
|
||
|
return -ENOSPC;
|
||
|
|
||
|
return mbox_process(mbox);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_max_pkt_len(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
|
||
|
if (roc_nix_is_sdp(roc_nix))
|
||
|
return NIX_SDP_MAX_HW_FRS;
|
||
|
|
||
|
if (roc_model_is_cn9k())
|
||
|
return NIX_CN9K_MAX_HW_FRS;
|
||
|
|
||
|
if (nix->lbk_link)
|
||
|
return NIX_LBK_MAX_HW_FRS;
|
||
|
|
||
|
return NIX_RPM_MAX_HW_FRS;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_lf_alloc(struct roc_nix *roc_nix, uint32_t nb_rxq, uint32_t nb_txq,
|
||
|
uint64_t rx_cfg)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
struct nix_lf_alloc_req *req;
|
||
|
struct nix_lf_alloc_rsp *rsp;
|
||
|
int rc = -ENOSPC;
|
||
|
|
||
|
req = mbox_alloc_msg_nix_lf_alloc(mbox);
|
||
|
if (req == NULL)
|
||
|
return rc;
|
||
|
req->rq_cnt = nb_rxq;
|
||
|
req->sq_cnt = nb_txq;
|
||
|
req->cq_cnt = nb_rxq;
|
||
|
/* XQESZ can be W64 or W16 */
|
||
|
req->xqe_sz = NIX_XQESZ_W16;
|
||
|
req->rss_sz = nix->reta_sz;
|
||
|
req->rss_grps = ROC_NIX_RSS_GRPS;
|
||
|
req->npa_func = idev_npa_pffunc_get();
|
||
|
req->sso_func = idev_sso_pffunc_get();
|
||
|
req->rx_cfg = rx_cfg;
|
||
|
if (roc_nix_is_lbk(roc_nix) && roc_nix->enable_loop &&
|
||
|
roc_model_is_cn98xx())
|
||
|
req->flags = NIX_LF_LBK_BLK_SEL;
|
||
|
|
||
|
if (!roc_nix->rss_tag_as_xor)
|
||
|
req->flags |= NIX_LF_RSS_TAG_LSB_AS_ADDER;
|
||
|
|
||
|
rc = mbox_process_msg(mbox, (void *)&rsp);
|
||
|
if (rc)
|
||
|
goto fail;
|
||
|
|
||
|
nix->rx_cfg = rx_cfg;
|
||
|
nix->sqb_size = rsp->sqb_size;
|
||
|
nix->tx_chan_base = rsp->tx_chan_base;
|
||
|
nix->rx_chan_base = rsp->rx_chan_base;
|
||
|
if (roc_nix_is_lbk(roc_nix) && roc_nix->enable_loop)
|
||
|
nix->tx_chan_base = rsp->rx_chan_base;
|
||
|
nix->rx_chan_cnt = rsp->rx_chan_cnt;
|
||
|
nix->tx_chan_cnt = rsp->tx_chan_cnt;
|
||
|
nix->lso_tsov4_idx = rsp->lso_tsov4_idx;
|
||
|
nix->lso_tsov6_idx = rsp->lso_tsov6_idx;
|
||
|
nix->lf_tx_stats = rsp->lf_tx_stats;
|
||
|
nix->lf_rx_stats = rsp->lf_rx_stats;
|
||
|
nix->cints = rsp->cints;
|
||
|
roc_nix->cints = rsp->cints;
|
||
|
nix->qints = rsp->qints;
|
||
|
nix->ptp_en = rsp->hw_rx_tstamp_en;
|
||
|
roc_nix->rx_ptp_ena = rsp->hw_rx_tstamp_en;
|
||
|
nix->cgx_links = rsp->cgx_links;
|
||
|
nix->lbk_links = rsp->lbk_links;
|
||
|
nix->sdp_links = rsp->sdp_links;
|
||
|
nix->tx_link = rsp->tx_link;
|
||
|
nix->nb_rx_queues = nb_rxq;
|
||
|
nix->nb_tx_queues = nb_txq;
|
||
|
nix->sqs = plt_zmalloc(sizeof(struct roc_nix_sq *) * nb_txq, 0);
|
||
|
if (!nix->sqs)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
nix_tel_node_add(roc_nix);
|
||
|
fail:
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_lf_free(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
struct nix_lf_free_req *req;
|
||
|
struct ndc_sync_op *ndc_req;
|
||
|
int rc = -ENOSPC;
|
||
|
|
||
|
plt_free(nix->sqs);
|
||
|
nix->sqs = NULL;
|
||
|
|
||
|
/* Sync NDC-NIX for LF */
|
||
|
ndc_req = mbox_alloc_msg_ndc_sync_op(mbox);
|
||
|
if (ndc_req == NULL)
|
||
|
return rc;
|
||
|
ndc_req->nix_lf_tx_sync = 1;
|
||
|
ndc_req->nix_lf_rx_sync = 1;
|
||
|
rc = mbox_process(mbox);
|
||
|
if (rc)
|
||
|
plt_err("Error on NDC-NIX-[TX, RX] LF sync, rc %d", rc);
|
||
|
|
||
|
req = mbox_alloc_msg_nix_lf_free(mbox);
|
||
|
if (req == NULL)
|
||
|
return -ENOSPC;
|
||
|
/* Let AF driver free all this nix lf's
|
||
|
* NPC entries allocated using NPC MBOX.
|
||
|
*/
|
||
|
req->flags = 0;
|
||
|
|
||
|
return mbox_process(mbox);
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
nix_lf_attach(struct dev *dev)
|
||
|
{
|
||
|
struct mbox *mbox = dev->mbox;
|
||
|
struct rsrc_attach_req *req;
|
||
|
int rc = -ENOSPC;
|
||
|
|
||
|
/* Attach NIX(lf) */
|
||
|
req = mbox_alloc_msg_attach_resources(mbox);
|
||
|
if (req == NULL)
|
||
|
return rc;
|
||
|
req->modify = true;
|
||
|
req->nixlf = true;
|
||
|
|
||
|
return mbox_process(mbox);
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
nix_lf_get_msix_offset(struct dev *dev, struct nix *nix)
|
||
|
{
|
||
|
struct msix_offset_rsp *msix_rsp;
|
||
|
struct mbox *mbox = dev->mbox;
|
||
|
int rc;
|
||
|
|
||
|
/* Get MSIX vector offsets */
|
||
|
mbox_alloc_msg_msix_offset(mbox);
|
||
|
rc = mbox_process_msg(mbox, (void *)&msix_rsp);
|
||
|
if (rc == 0)
|
||
|
nix->msixoff = msix_rsp->nix_msixoff;
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
nix_lf_detach(struct nix *nix)
|
||
|
{
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
struct rsrc_detach_req *req;
|
||
|
int rc = -ENOSPC;
|
||
|
|
||
|
req = mbox_alloc_msg_detach_resources(mbox);
|
||
|
if (req == NULL)
|
||
|
return rc;
|
||
|
req->partial = true;
|
||
|
req->nixlf = true;
|
||
|
|
||
|
return mbox_process(mbox);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
roc_nix_get_hw_info(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
struct mbox *mbox = (&nix->dev)->mbox;
|
||
|
struct nix_hw_info *hw_info;
|
||
|
int rc;
|
||
|
|
||
|
mbox_alloc_msg_nix_get_hw_info(mbox);
|
||
|
rc = mbox_process_msg(mbox, (void *)&hw_info);
|
||
|
if (rc == 0)
|
||
|
nix->vwqe_interval = hw_info->vwqe_delay;
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
sdp_lbk_id_update(struct plt_pci_device *pci_dev, struct nix *nix)
|
||
|
{
|
||
|
nix->sdp_link = false;
|
||
|
nix->lbk_link = false;
|
||
|
|
||
|
/* Update SDP/LBK link based on PCI device id */
|
||
|
switch (pci_dev->id.device_id) {
|
||
|
case PCI_DEVID_CNXK_RVU_SDP_PF:
|
||
|
case PCI_DEVID_CNXK_RVU_SDP_VF:
|
||
|
nix->sdp_link = true;
|
||
|
break;
|
||
|
case PCI_DEVID_CNXK_RVU_AF_VF:
|
||
|
nix->lbk_link = true;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint64_t
|
||
|
nix_get_blkaddr(struct dev *dev)
|
||
|
{
|
||
|
uint64_t reg;
|
||
|
|
||
|
/* Reading the discovery register to know which NIX is the LF
|
||
|
* attached to.
|
||
|
*/
|
||
|
reg = plt_read64(dev->bar2 +
|
||
|
RVU_PF_BLOCK_ADDRX_DISC(RVU_BLOCK_ADDR_NIX0));
|
||
|
|
||
|
return reg & 0x1FFULL ? RVU_BLOCK_ADDR_NIX0 : RVU_BLOCK_ADDR_NIX1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_dev_init(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
enum roc_nix_rss_reta_sz reta_sz;
|
||
|
struct plt_pci_device *pci_dev;
|
||
|
uint16_t max_sqb_count;
|
||
|
uint64_t blkaddr;
|
||
|
struct dev *dev;
|
||
|
struct nix *nix;
|
||
|
int rc;
|
||
|
|
||
|
if (roc_nix == NULL || roc_nix->pci_dev == NULL)
|
||
|
return NIX_ERR_PARAM;
|
||
|
|
||
|
reta_sz = roc_nix->reta_sz;
|
||
|
if (reta_sz != 0 && reta_sz != 64 && reta_sz != 128 && reta_sz != 256)
|
||
|
return NIX_ERR_PARAM;
|
||
|
|
||
|
if (reta_sz == 0)
|
||
|
reta_sz = ROC_NIX_RSS_RETA_SZ_64;
|
||
|
|
||
|
max_sqb_count = roc_nix->max_sqb_count;
|
||
|
max_sqb_count = PLT_MIN(max_sqb_count, NIX_MAX_SQB);
|
||
|
max_sqb_count = PLT_MAX(max_sqb_count, NIX_MIN_SQB);
|
||
|
roc_nix->max_sqb_count = max_sqb_count;
|
||
|
|
||
|
PLT_STATIC_ASSERT(sizeof(struct nix) <= ROC_NIX_MEM_SZ);
|
||
|
nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
pci_dev = roc_nix->pci_dev;
|
||
|
dev = &nix->dev;
|
||
|
|
||
|
if (nix->dev.drv_inited)
|
||
|
return 0;
|
||
|
|
||
|
if (dev->mbox_active)
|
||
|
goto skip_dev_init;
|
||
|
|
||
|
memset(nix, 0, sizeof(*nix));
|
||
|
/* Initialize device */
|
||
|
rc = dev_init(dev, pci_dev);
|
||
|
if (rc) {
|
||
|
plt_err("Failed to init roc device");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
skip_dev_init:
|
||
|
dev->roc_nix = roc_nix;
|
||
|
|
||
|
nix->lmt_base = dev->lmt_base;
|
||
|
/* Expose base LMT line address for
|
||
|
* "Per Core LMT line" mode.
|
||
|
*/
|
||
|
roc_nix->lmt_base = dev->lmt_base;
|
||
|
|
||
|
/* Attach NIX LF */
|
||
|
rc = nix_lf_attach(dev);
|
||
|
if (rc)
|
||
|
goto dev_fini;
|
||
|
|
||
|
blkaddr = nix_get_blkaddr(dev);
|
||
|
nix->is_nix1 = (blkaddr == RVU_BLOCK_ADDR_NIX1);
|
||
|
|
||
|
/* Calculating base address based on which NIX block LF
|
||
|
* is attached to.
|
||
|
*/
|
||
|
nix->base = dev->bar2 + (blkaddr << 20);
|
||
|
|
||
|
/* Get NIX MSIX offset */
|
||
|
rc = nix_lf_get_msix_offset(dev, nix);
|
||
|
if (rc)
|
||
|
goto lf_detach;
|
||
|
|
||
|
/* Update nix context */
|
||
|
sdp_lbk_id_update(pci_dev, nix);
|
||
|
nix->pci_dev = pci_dev;
|
||
|
nix->reta_sz = reta_sz;
|
||
|
nix->mtu = ROC_NIX_DEFAULT_HW_FRS;
|
||
|
|
||
|
/* Always start with full FC for LBK */
|
||
|
if (nix->lbk_link) {
|
||
|
nix->rx_pause = 1;
|
||
|
nix->tx_pause = 1;
|
||
|
} else if (!roc_nix_is_vf_or_sdp(roc_nix)) {
|
||
|
/* Get the current state of flow control */
|
||
|
roc_nix_fc_mode_get(roc_nix);
|
||
|
}
|
||
|
|
||
|
/* Register error and ras interrupts */
|
||
|
rc = nix_register_irqs(nix);
|
||
|
if (rc)
|
||
|
goto lf_detach;
|
||
|
|
||
|
rc = nix_tm_conf_init(roc_nix);
|
||
|
if (rc)
|
||
|
goto unregister_irqs;
|
||
|
|
||
|
/* Get NIX HW info */
|
||
|
roc_nix_get_hw_info(roc_nix);
|
||
|
nix->dev.drv_inited = true;
|
||
|
|
||
|
return 0;
|
||
|
unregister_irqs:
|
||
|
nix_unregister_irqs(nix);
|
||
|
lf_detach:
|
||
|
nix_lf_detach(nix);
|
||
|
dev_fini:
|
||
|
rc |= dev_fini(dev, pci_dev);
|
||
|
fail:
|
||
|
nix_tel_node_del(roc_nix);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
roc_nix_dev_fini(struct roc_nix *roc_nix)
|
||
|
{
|
||
|
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
|
||
|
int rc = 0;
|
||
|
|
||
|
if (nix == NULL)
|
||
|
return NIX_ERR_PARAM;
|
||
|
|
||
|
if (!nix->dev.drv_inited)
|
||
|
goto fini;
|
||
|
|
||
|
nix_tm_conf_fini(roc_nix);
|
||
|
nix_unregister_irqs(nix);
|
||
|
|
||
|
rc = nix_lf_detach(nix);
|
||
|
nix->dev.drv_inited = false;
|
||
|
fini:
|
||
|
rc |= dev_fini(&nix->dev, nix->pci_dev);
|
||
|
return rc;
|
||
|
}
|