2021-05-26 19:09:36 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Marvell RPM CN10K driver
|
|
|
|
*
|
|
|
|
* Copyright (C) 2020 Marvell.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/bitfield.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include "rvu.h"
|
|
|
|
#include "cgx.h"
|
|
|
|
#include "rvu_reg.h"
|
|
|
|
|
2021-07-22 16:18:54 +00:00
|
|
|
/* RVU LMTST */
|
|
|
|
#define LMT_TBL_OP_READ 0
|
|
|
|
#define LMT_TBL_OP_WRITE 1
|
|
|
|
#define LMT_MAP_TABLE_SIZE (128 * 1024)
|
|
|
|
#define LMT_MAPTBL_ENTRY_SIZE 16
|
|
|
|
|
|
|
|
/* Function to perform operations (read/write) on lmtst map table */
|
|
|
|
static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val,
|
|
|
|
int lmt_tbl_op)
|
|
|
|
{
|
|
|
|
void __iomem *lmt_map_base;
|
|
|
|
u64 tbl_base;
|
|
|
|
|
|
|
|
tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE);
|
|
|
|
|
|
|
|
lmt_map_base = ioremap_wc(tbl_base, LMT_MAP_TABLE_SIZE);
|
|
|
|
if (!lmt_map_base) {
|
|
|
|
dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lmt_tbl_op == LMT_TBL_OP_READ) {
|
|
|
|
*val = readq(lmt_map_base + index);
|
|
|
|
} else {
|
|
|
|
writeq((*val), (lmt_map_base + index));
|
|
|
|
/* Flushing the AP interceptor cache to make APR_LMT_MAP_ENTRY_S
|
|
|
|
* changes effective. Write 1 for flush and read is being used as a
|
|
|
|
* barrier and sets up a data dependency. Write to 0 after a write
|
|
|
|
* to 1 to complete the flush.
|
|
|
|
*/
|
|
|
|
rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, BIT_ULL(0));
|
|
|
|
rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CTL);
|
|
|
|
rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, 0x00);
|
|
|
|
}
|
|
|
|
|
|
|
|
iounmap(lmt_map_base);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 rvu_get_lmtst_tbl_index(struct rvu *rvu, u16 pcifunc)
|
|
|
|
{
|
|
|
|
return ((rvu_get_pf(pcifunc) * rvu->hw->total_vfs) +
|
|
|
|
(pcifunc & RVU_PFVF_FUNC_MASK)) * LMT_MAPTBL_ENTRY_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc,
|
|
|
|
u64 iova, u64 *lmt_addr)
|
|
|
|
{
|
|
|
|
u64 pa, val, pf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!iova) {
|
|
|
|
dev_err(rvu->dev, "%s Requested Null address for transulation\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova);
|
|
|
|
pf = rvu_get_pf(pcifunc) & 0x1F;
|
|
|
|
val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 |
|
|
|
|
((pcifunc & RVU_PFVF_FUNC_MASK) & 0xFF);
|
|
|
|
rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TXN_REQ, val);
|
|
|
|
|
|
|
|
err = rvu_poll_reg(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS, BIT_ULL(0), false);
|
|
|
|
if (err) {
|
|
|
|
dev_err(rvu->dev, "%s LMTLINE iova transulation failed\n", __func__);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
val = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS);
|
|
|
|
if (val & ~0x1ULL) {
|
|
|
|
dev_err(rvu->dev, "%s LMTLINE iova transulation failed err:%llx\n", __func__, val);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
/* PA[51:12] = RVU_AF_SMMU_TLN_FLIT1[60:21]
|
|
|
|
* PA[11:0] = IOVA[11:0]
|
|
|
|
*/
|
|
|
|
pa = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TLN_FLIT1) >> 21;
|
|
|
|
pa &= GENMASK_ULL(39, 0);
|
|
|
|
*lmt_addr = (pa << 12) | (iova & 0xFFF);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rvu_update_lmtaddr(struct rvu *rvu, u16 pcifunc, u64 lmt_addr)
|
|
|
|
{
|
|
|
|
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
|
|
|
|
u32 tbl_idx;
|
|
|
|
int err = 0;
|
|
|
|
u64 val;
|
|
|
|
|
|
|
|
/* Read the current lmt addr of pcifunc */
|
|
|
|
tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc);
|
|
|
|
err = lmtst_map_table_ops(rvu, tbl_idx, &val, LMT_TBL_OP_READ);
|
|
|
|
if (err) {
|
|
|
|
dev_err(rvu->dev,
|
|
|
|
"Failed to read LMT map table: index 0x%x err %d\n",
|
|
|
|
tbl_idx, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Storing the seondary's lmt base address as this needs to be
|
|
|
|
* reverted in FLR. Also making sure this default value doesn't
|
|
|
|
* get overwritten on multiple calls to this mailbox.
|
|
|
|
*/
|
|
|
|
if (!pfvf->lmt_base_addr)
|
|
|
|
pfvf->lmt_base_addr = val;
|
|
|
|
|
|
|
|
/* Update the LMT table with new addr */
|
|
|
|
err = lmtst_map_table_ops(rvu, tbl_idx, &lmt_addr, LMT_TBL_OP_WRITE);
|
|
|
|
if (err) {
|
|
|
|
dev_err(rvu->dev,
|
|
|
|
"Failed to update LMT map table: index 0x%x err %d\n",
|
|
|
|
tbl_idx, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu,
|
|
|
|
struct lmtst_tbl_setup_req *req,
|
|
|
|
struct msg_rsp *rsp)
|
|
|
|
{
|
|
|
|
u64 lmt_addr, val;
|
|
|
|
u32 pri_tbl_idx;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/* Check if PF_FUNC wants to use it's own local memory as LMTLINE
|
|
|
|
* region, if so, convert that IOVA to physical address and
|
|
|
|
* populate LMT table with that address
|
|
|
|
*/
|
|
|
|
if (req->use_local_lmt_region) {
|
|
|
|
err = rvu_get_lmtaddr(rvu, req->hdr.pcifunc,
|
|
|
|
req->lmt_iova, &lmt_addr);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* Update the lmt addr for this PFFUNC in the LMT table */
|
|
|
|
err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, lmt_addr);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reconfiguring lmtst map table in lmt region shared mode i.e. make
|
|
|
|
* multiple PF_FUNCs to share an LMTLINE region, so primary/base
|
|
|
|
* pcifunc (which is passed as an argument to mailbox) is the one
|
|
|
|
* whose lmt base address will be shared among other secondary
|
|
|
|
* pcifunc (will be the one who is calling this mailbox).
|
|
|
|
*/
|
|
|
|
if (req->base_pcifunc) {
|
|
|
|
/* Calculating the LMT table index equivalent to primary
|
|
|
|
* pcifunc.
|
|
|
|
*/
|
|
|
|
pri_tbl_idx = rvu_get_lmtst_tbl_index(rvu, req->base_pcifunc);
|
|
|
|
|
|
|
|
/* Read the base lmt addr of the primary pcifunc */
|
|
|
|
err = lmtst_map_table_ops(rvu, pri_tbl_idx, &val,
|
|
|
|
LMT_TBL_OP_READ);
|
|
|
|
if (err) {
|
|
|
|
dev_err(rvu->dev,
|
|
|
|
"Failed to read LMT map table: index 0x%x err %d\n",
|
|
|
|
pri_tbl_idx, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the base lmt addr of secondary with primary's base
|
|
|
|
* lmt addr.
|
|
|
|
*/
|
|
|
|
err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, val);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resetting the lmtst map table to original base addresses */
|
|
|
|
void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc)
|
|
|
|
{
|
|
|
|
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
|
|
|
|
u32 tbl_idx;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (is_rvu_otx2(rvu))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pfvf->lmt_base_addr) {
|
|
|
|
/* This corresponds to lmt map table index */
|
|
|
|
tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc);
|
|
|
|
/* Reverting back original lmt base addr for respective
|
|
|
|
* pcifunc.
|
|
|
|
*/
|
|
|
|
err = lmtst_map_table_ops(rvu, tbl_idx, &pfvf->lmt_base_addr,
|
|
|
|
LMT_TBL_OP_WRITE);
|
|
|
|
if (err)
|
|
|
|
dev_err(rvu->dev,
|
|
|
|
"Failed to update LMT map table: index 0x%x err %d\n",
|
|
|
|
tbl_idx, err);
|
|
|
|
pfvf->lmt_base_addr = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-26 19:09:36 +00:00
|
|
|
int rvu_set_channels_base(struct rvu *rvu)
|
|
|
|
{
|
|
|
|
struct rvu_hwinfo *hw = rvu->hw;
|
|
|
|
u16 cpt_chan_base;
|
|
|
|
u64 nix_const;
|
|
|
|
int blkaddr;
|
|
|
|
|
|
|
|
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
|
|
|
|
if (blkaddr < 0)
|
|
|
|
return blkaddr;
|
|
|
|
|
|
|
|
nix_const = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
|
|
|
|
|
|
|
|
hw->cgx = (nix_const >> 12) & 0xFULL;
|
|
|
|
hw->lmac_per_cgx = (nix_const >> 8) & 0xFULL;
|
|
|
|
hw->cgx_links = hw->cgx * hw->lmac_per_cgx;
|
|
|
|
hw->lbk_links = (nix_const >> 24) & 0xFULL;
|
|
|
|
hw->cpt_links = (nix_const >> 44) & 0xFULL;
|
|
|
|
hw->sdp_links = 1;
|
|
|
|
|
|
|
|
hw->cgx_chan_base = NIX_CHAN_CGX_LMAC_CHX(0, 0, 0);
|
|
|
|
hw->lbk_chan_base = NIX_CHAN_LBK_CHX(0, 0);
|
|
|
|
hw->sdp_chan_base = NIX_CHAN_SDP_CH_START;
|
|
|
|
|
|
|
|
/* No Programmable channels */
|
|
|
|
if (!(nix_const & BIT_ULL(60)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
hw->cap.programmable_chans = true;
|
|
|
|
|
|
|
|
/* If programmable channels are present then configure
|
|
|
|
* channels such that all channel numbers are contiguous
|
|
|
|
* leaving no holes. This way the new CPT channels can be
|
|
|
|
* accomodated. The order of channel numbers assigned is
|
|
|
|
* LBK, SDP, CGX and CPT.
|
|
|
|
*/
|
|
|
|
hw->sdp_chan_base = hw->lbk_chan_base + hw->lbk_links *
|
|
|
|
((nix_const >> 16) & 0xFFULL);
|
|
|
|
hw->cgx_chan_base = hw->sdp_chan_base + hw->sdp_links * SDP_CHANNELS;
|
|
|
|
|
|
|
|
cpt_chan_base = hw->cgx_chan_base + hw->cgx_links *
|
|
|
|
(nix_const & 0xFFULL);
|
|
|
|
|
|
|
|
/* Out of 4096 channels start CPT from 2048 so
|
|
|
|
* that MSB for CPT channels is always set
|
|
|
|
*/
|
|
|
|
if (cpt_chan_base <= 0x800) {
|
|
|
|
hw->cpt_chan_base = 0x800;
|
|
|
|
} else {
|
|
|
|
dev_err(rvu->dev,
|
|
|
|
"CPT channels could not fit in the range 2048-4095\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define LBK_CONNECT_NIXX(a) (0x0 + (a))
|
|
|
|
|
|
|
|
static void __rvu_lbk_set_chans(struct rvu *rvu, void __iomem *base,
|
|
|
|
u64 offset, int lbkid, u16 chans)
|
|
|
|
{
|
|
|
|
struct rvu_hwinfo *hw = rvu->hw;
|
|
|
|
u64 cfg;
|
|
|
|
|
|
|
|
cfg = readq(base + offset);
|
|
|
|
cfg &= ~(LBK_LINK_CFG_RANGE_MASK |
|
|
|
|
LBK_LINK_CFG_ID_MASK | LBK_LINK_CFG_BASE_MASK);
|
|
|
|
cfg |= FIELD_PREP(LBK_LINK_CFG_RANGE_MASK, ilog2(chans));
|
|
|
|
cfg |= FIELD_PREP(LBK_LINK_CFG_ID_MASK, lbkid);
|
|
|
|
cfg |= FIELD_PREP(LBK_LINK_CFG_BASE_MASK, hw->lbk_chan_base);
|
|
|
|
|
|
|
|
writeq(cfg, base + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rvu_lbk_set_channels(struct rvu *rvu)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = NULL;
|
|
|
|
void __iomem *base;
|
|
|
|
u64 lbk_const;
|
|
|
|
u8 src, dst;
|
|
|
|
u16 chans;
|
|
|
|
|
|
|
|
/* To loopback packets between multiple NIX blocks
|
|
|
|
* mutliple LBK blocks are needed. With two NIX blocks,
|
|
|
|
* four LBK blocks are needed and each LBK block
|
|
|
|
* source and destination are as follows:
|
|
|
|
* LBK0 - source NIX0 and destination NIX1
|
|
|
|
* LBK1 - source NIX0 and destination NIX1
|
|
|
|
* LBK2 - source NIX1 and destination NIX0
|
|
|
|
* LBK3 - source NIX1 and destination NIX1
|
|
|
|
* As per the HRM channel numbers should be programmed as:
|
|
|
|
* P2X and X2P of LBK0 as same
|
|
|
|
* P2X and X2P of LBK3 as same
|
|
|
|
* P2X of LBK1 and X2P of LBK2 as same
|
|
|
|
* P2X of LBK2 and X2P of LBK1 as same
|
|
|
|
*/
|
|
|
|
while (true) {
|
|
|
|
pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
|
|
|
|
PCI_DEVID_OCTEONTX2_LBK, pdev);
|
|
|
|
if (!pdev)
|
|
|
|
return;
|
|
|
|
|
|
|
|
base = pci_ioremap_bar(pdev, 0);
|
|
|
|
if (!base)
|
|
|
|
goto err_put;
|
|
|
|
|
|
|
|
lbk_const = readq(base + LBK_CONST);
|
|
|
|
chans = FIELD_GET(LBK_CONST_CHANS, lbk_const);
|
|
|
|
dst = FIELD_GET(LBK_CONST_DST, lbk_const);
|
|
|
|
src = FIELD_GET(LBK_CONST_SRC, lbk_const);
|
|
|
|
|
|
|
|
if (src == dst) {
|
|
|
|
if (src == LBK_CONNECT_NIXX(0)) { /* LBK0 */
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_X2P,
|
|
|
|
0, chans);
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_P2X,
|
|
|
|
0, chans);
|
|
|
|
} else if (src == LBK_CONNECT_NIXX(1)) { /* LBK3 */
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_X2P,
|
|
|
|
1, chans);
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_P2X,
|
|
|
|
1, chans);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (src == LBK_CONNECT_NIXX(0)) { /* LBK1 */
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_X2P,
|
|
|
|
0, chans);
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_P2X,
|
|
|
|
1, chans);
|
|
|
|
} else if (src == LBK_CONNECT_NIXX(1)) { /* LBK2 */
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_X2P,
|
|
|
|
1, chans);
|
|
|
|
__rvu_lbk_set_chans(rvu, base, LBK_LINK_CFG_P2X,
|
|
|
|
0, chans);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iounmap(base);
|
|
|
|
}
|
|
|
|
err_put:
|
|
|
|
pci_dev_put(pdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __rvu_nix_set_channels(struct rvu *rvu, int blkaddr)
|
|
|
|
{
|
|
|
|
u64 nix_const = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
|
|
|
|
u16 cgx_chans, lbk_chans, sdp_chans, cpt_chans;
|
|
|
|
struct rvu_hwinfo *hw = rvu->hw;
|
|
|
|
int link, nix_link = 0;
|
|
|
|
u16 start;
|
|
|
|
u64 cfg;
|
|
|
|
|
|
|
|
cgx_chans = nix_const & 0xFFULL;
|
|
|
|
lbk_chans = (nix_const >> 16) & 0xFFULL;
|
|
|
|
sdp_chans = SDP_CHANNELS;
|
|
|
|
cpt_chans = (nix_const >> 32) & 0xFFFULL;
|
|
|
|
|
|
|
|
start = hw->cgx_chan_base;
|
|
|
|
for (link = 0; link < hw->cgx_links; link++, nix_link++) {
|
|
|
|
cfg = rvu_read64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link));
|
|
|
|
cfg &= ~(NIX_AF_LINKX_BASE_MASK | NIX_AF_LINKX_RANGE_MASK);
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_RANGE_MASK, ilog2(cgx_chans));
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_BASE_MASK, start);
|
|
|
|
rvu_write64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link), cfg);
|
|
|
|
start += cgx_chans;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = hw->lbk_chan_base;
|
|
|
|
for (link = 0; link < hw->lbk_links; link++, nix_link++) {
|
|
|
|
cfg = rvu_read64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link));
|
|
|
|
cfg &= ~(NIX_AF_LINKX_BASE_MASK | NIX_AF_LINKX_RANGE_MASK);
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_RANGE_MASK, ilog2(lbk_chans));
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_BASE_MASK, start);
|
|
|
|
rvu_write64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link), cfg);
|
|
|
|
start += lbk_chans;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = hw->sdp_chan_base;
|
|
|
|
for (link = 0; link < hw->sdp_links; link++, nix_link++) {
|
|
|
|
cfg = rvu_read64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link));
|
|
|
|
cfg &= ~(NIX_AF_LINKX_BASE_MASK | NIX_AF_LINKX_RANGE_MASK);
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_RANGE_MASK, ilog2(sdp_chans));
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_BASE_MASK, start);
|
|
|
|
rvu_write64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link), cfg);
|
|
|
|
start += sdp_chans;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = hw->cpt_chan_base;
|
|
|
|
for (link = 0; link < hw->cpt_links; link++, nix_link++) {
|
|
|
|
cfg = rvu_read64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link));
|
|
|
|
cfg &= ~(NIX_AF_LINKX_BASE_MASK | NIX_AF_LINKX_RANGE_MASK);
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_RANGE_MASK, ilog2(cpt_chans));
|
|
|
|
cfg |= FIELD_PREP(NIX_AF_LINKX_BASE_MASK, start);
|
|
|
|
rvu_write64(rvu, blkaddr, NIX_AF_LINKX_CFG(nix_link), cfg);
|
|
|
|
start += cpt_chans;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rvu_nix_set_channels(struct rvu *rvu)
|
|
|
|
{
|
|
|
|
int blkaddr = 0;
|
|
|
|
|
|
|
|
blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
|
|
|
|
while (blkaddr) {
|
|
|
|
__rvu_nix_set_channels(rvu, blkaddr);
|
|
|
|
blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __rvu_rpm_set_channels(int cgxid, int lmacid, u16 base)
|
|
|
|
{
|
|
|
|
u64 cfg;
|
|
|
|
|
|
|
|
cfg = cgx_lmac_read(cgxid, lmacid, RPMX_CMRX_LINK_CFG);
|
|
|
|
cfg &= ~(RPMX_CMRX_LINK_BASE_MASK | RPMX_CMRX_LINK_RANGE_MASK);
|
|
|
|
|
|
|
|
/* There is no read-only constant register to read
|
|
|
|
* the number of channels for LMAC and it is always 16.
|
|
|
|
*/
|
|
|
|
cfg |= FIELD_PREP(RPMX_CMRX_LINK_RANGE_MASK, ilog2(16));
|
|
|
|
cfg |= FIELD_PREP(RPMX_CMRX_LINK_BASE_MASK, base);
|
|
|
|
cgx_lmac_write(cgxid, lmacid, RPMX_CMRX_LINK_CFG, cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rvu_rpm_set_channels(struct rvu *rvu)
|
|
|
|
{
|
|
|
|
struct rvu_hwinfo *hw = rvu->hw;
|
|
|
|
u16 base = hw->cgx_chan_base;
|
|
|
|
int cgx, lmac;
|
|
|
|
|
|
|
|
for (cgx = 0; cgx < rvu->cgx_cnt_max; cgx++) {
|
|
|
|
for (lmac = 0; lmac < hw->lmac_per_cgx; lmac++) {
|
|
|
|
__rvu_rpm_set_channels(cgx, lmac, base);
|
|
|
|
base += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rvu_program_channels(struct rvu *rvu)
|
|
|
|
{
|
|
|
|
struct rvu_hwinfo *hw = rvu->hw;
|
|
|
|
|
|
|
|
if (!hw->cap.programmable_chans)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rvu_nix_set_channels(rvu);
|
|
|
|
rvu_lbk_set_channels(rvu);
|
|
|
|
rvu_rpm_set_channels(rvu);
|
|
|
|
}
|