1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c
Subbaraya Sundeep a88e0f936b octeontx2: Detect the mbox up or down message via register
A single line of interrupt is used to receive up notifications
and down reply messages from AF to PF (similarly from PF to its VF).
PF acts as bridge and forwards VF messages to AF and sends respsones
back from AF to VF. When an async event like link event is received
by up message when PF is in middle of forwarding VF message then
mailbox errors occur because PF state machine is corrupted.
Since VF is a separate driver or VF driver can be in a VM it is
not possible to serialize from the start of communication at VF.
Hence to differentiate between type of messages at PF this patch makes
sender to set mbox data register with distinct values for up and down
messages. Sender also checks whether previous interrupt is received
before triggering current interrupt by waiting for mailbox data register
to become zero.

Fixes: 5a6d7c9dae ("octeontx2-pf: Mailbox communication with AF")
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-03-20 10:49:07 +00:00

931 lines
21 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Marvell CN10K MCS driver
*
* Copyright (C) 2022 Marvell.
*/
#include <linux/types.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "mcs.h"
#include "rvu.h"
#include "mcs_reg.h"
#include "lmac_common.h"
#define M(_name, _id, _fn_name, _req_type, _rsp_type) \
static struct _req_type __maybe_unused \
*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid) \
{ \
struct _req_type *req; \
\
req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \
&rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \
sizeof(struct _rsp_type)); \
if (!req) \
return NULL; \
req->hdr.sig = OTX2_MBOX_REQ_SIG; \
req->hdr.id = _id; \
return req; \
}
MBOX_UP_MCS_MESSAGES
#undef M
void rvu_mcs_ptp_cfg(struct rvu *rvu, u8 rpm_id, u8 lmac_id, bool ena)
{
struct mcs *mcs;
u64 cfg;
u8 port;
if (!rvu->mcs_blk_cnt)
return;
/* When ptp is enabled, RPM appends 8B header for all
* RX packets. MCS PEX need to configure to skip 8B
* during packet parsing.
*/
/* CNF10K-B */
if (rvu->mcs_blk_cnt > 1) {
mcs = mcs_get_pdata(rpm_id);
cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION);
if (ena)
cfg |= BIT_ULL(lmac_id);
else
cfg &= ~BIT_ULL(lmac_id);
mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION, cfg);
return;
}
/* CN10KB */
mcs = mcs_get_pdata(0);
port = (rpm_id * rvu->hw->lmac_per_cgx) + lmac_id;
cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port));
if (ena)
cfg |= BIT_ULL(0);
else
cfg &= ~BIT_ULL(0);
mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port), cfg);
}
int rvu_mbox_handler_mcs_set_lmac_mode(struct rvu *rvu,
struct mcs_set_lmac_mode *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (BIT_ULL(req->lmac_id) & mcs->hw->lmac_bmap)
mcs_set_lmac_mode(mcs, req->lmac_id, req->mode);
return 0;
}
int mcs_add_intr_wq_entry(struct mcs *mcs, struct mcs_intr_event *event)
{
struct mcs_intrq_entry *qentry;
u16 pcifunc = event->pcifunc;
struct rvu *rvu = mcs->rvu;
struct mcs_pfvf *pfvf;
/* Check if it is PF or VF */
if (pcifunc & RVU_PFVF_FUNC_MASK)
pfvf = &mcs->vf[rvu_get_hwvf(rvu, pcifunc)];
else
pfvf = &mcs->pf[rvu_get_pf(pcifunc)];
event->intr_mask &= pfvf->intr_mask;
/* Check PF/VF interrupt notification is enabled */
if (!(pfvf->intr_mask && event->intr_mask))
return 0;
qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC);
if (!qentry)
return -ENOMEM;
qentry->intr_event = *event;
spin_lock(&rvu->mcs_intrq_lock);
list_add_tail(&qentry->node, &rvu->mcs_intrq_head);
spin_unlock(&rvu->mcs_intrq_lock);
queue_work(rvu->mcs_intr_wq, &rvu->mcs_intr_work);
return 0;
}
static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu)
{
struct mcs_intr_info *req;
int pf;
pf = rvu_get_pf(event->pcifunc);
mutex_lock(&rvu->mbox_lock);
req = otx2_mbox_alloc_msg_mcs_intr_notify(rvu, pf);
if (!req) {
mutex_unlock(&rvu->mbox_lock);
return -ENOMEM;
}
req->mcs_id = event->mcs_id;
req->intr_mask = event->intr_mask;
req->sa_id = event->sa_id;
req->hdr.pcifunc = event->pcifunc;
req->lmac_id = event->lmac_id;
otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);
mutex_unlock(&rvu->mbox_lock);
return 0;
}
static void mcs_intr_handler_task(struct work_struct *work)
{
struct rvu *rvu = container_of(work, struct rvu, mcs_intr_work);
struct mcs_intrq_entry *qentry;
struct mcs_intr_event *event;
unsigned long flags;
do {
spin_lock_irqsave(&rvu->mcs_intrq_lock, flags);
qentry = list_first_entry_or_null(&rvu->mcs_intrq_head,
struct mcs_intrq_entry,
node);
if (qentry)
list_del(&qentry->node);
spin_unlock_irqrestore(&rvu->mcs_intrq_lock, flags);
if (!qentry)
break; /* nothing more to process */
event = &qentry->intr_event;
mcs_notify_pfvf(event, rvu);
kfree(qentry);
} while (1);
}
int rvu_mbox_handler_mcs_intr_cfg(struct rvu *rvu,
struct mcs_intr_cfg *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct mcs_pfvf *pfvf;
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
/* Check if it is PF or VF */
if (pcifunc & RVU_PFVF_FUNC_MASK)
pfvf = &mcs->vf[rvu_get_hwvf(rvu, pcifunc)];
else
pfvf = &mcs->pf[rvu_get_pf(pcifunc)];
mcs->pf_map[0] = pcifunc;
pfvf->intr_mask = req->intr_mask;
return 0;
}
int rvu_mbox_handler_mcs_get_hw_info(struct rvu *rvu,
struct msg_req *req,
struct mcs_hw_info *rsp)
{
struct mcs *mcs;
if (!rvu->mcs_blk_cnt)
return MCS_AF_ERR_NOT_MAPPED;
/* MCS resources are same across all blocks */
mcs = mcs_get_pdata(0);
rsp->num_mcs_blks = rvu->mcs_blk_cnt;
rsp->tcam_entries = mcs->hw->tcam_entries;
rsp->secy_entries = mcs->hw->secy_entries;
rsp->sc_entries = mcs->hw->sc_entries;
rsp->sa_entries = mcs->hw->sa_entries;
return 0;
}
int rvu_mbox_handler_mcs_port_reset(struct rvu *rvu, struct mcs_port_reset_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_reset_port(mcs, req->port_id, req->reset);
return 0;
}
int rvu_mbox_handler_mcs_clear_stats(struct rvu *rvu,
struct mcs_clear_stats *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mutex_lock(&mcs->stats_lock);
if (req->all)
mcs_clear_all_stats(mcs, pcifunc, req->dir);
else
mcs_clear_stats(mcs, req->type, req->id, req->dir);
mutex_unlock(&mcs->stats_lock);
return 0;
}
int rvu_mbox_handler_mcs_get_flowid_stats(struct rvu *rvu,
struct mcs_stats_req *req,
struct mcs_flowid_stats *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
/* In CNF10K-B, before reading the statistics,
* MCSX_MIL_GLOBAL.FORCE_CLK_EN_IP needs to be set
* to get accurate statistics
*/
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, true);
mutex_lock(&mcs->stats_lock);
mcs_get_flowid_stats(mcs, rsp, req->id, req->dir);
mutex_unlock(&mcs->stats_lock);
/* Clear MCSX_MIL_GLOBAL.FORCE_CLK_EN_IP after reading
* the statistics
*/
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, false);
return 0;
}
int rvu_mbox_handler_mcs_get_secy_stats(struct rvu *rvu,
struct mcs_stats_req *req,
struct mcs_secy_stats *rsp)
{ struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, true);
mutex_lock(&mcs->stats_lock);
if (req->dir == MCS_RX)
mcs_get_rx_secy_stats(mcs, rsp, req->id);
else
mcs_get_tx_secy_stats(mcs, rsp, req->id);
mutex_unlock(&mcs->stats_lock);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, false);
return 0;
}
int rvu_mbox_handler_mcs_get_sc_stats(struct rvu *rvu,
struct mcs_stats_req *req,
struct mcs_sc_stats *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, true);
mutex_lock(&mcs->stats_lock);
mcs_get_sc_stats(mcs, rsp, req->id, req->dir);
mutex_unlock(&mcs->stats_lock);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, false);
return 0;
}
int rvu_mbox_handler_mcs_get_sa_stats(struct rvu *rvu,
struct mcs_stats_req *req,
struct mcs_sa_stats *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, true);
mutex_lock(&mcs->stats_lock);
mcs_get_sa_stats(mcs, rsp, req->id, req->dir);
mutex_unlock(&mcs->stats_lock);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, false);
return 0;
}
int rvu_mbox_handler_mcs_get_port_stats(struct rvu *rvu,
struct mcs_stats_req *req,
struct mcs_port_stats *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, true);
mutex_lock(&mcs->stats_lock);
mcs_get_port_stats(mcs, rsp, req->id, req->dir);
mutex_unlock(&mcs->stats_lock);
if (mcs->hw->mcs_blks > 1)
mcs_set_force_clk_en(mcs, false);
return 0;
}
int rvu_mbox_handler_mcs_set_active_lmac(struct rvu *rvu,
struct mcs_set_active_lmac *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (!mcs)
return MCS_AF_ERR_NOT_MAPPED;
mcs->hw->lmac_bmap = req->lmac_bmap;
mcs_set_lmac_channels(req->mcs_id, req->chan_base);
return 0;
}
int rvu_mbox_handler_mcs_port_cfg_set(struct rvu *rvu, struct mcs_port_cfg_set_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->lmac_cnt <= req->port_id || !(mcs->hw->lmac_bmap & BIT_ULL(req->port_id)))
return -EINVAL;
mcs_set_port_cfg(mcs, req);
return 0;
}
int rvu_mbox_handler_mcs_port_cfg_get(struct rvu *rvu, struct mcs_port_cfg_get_req *req,
struct mcs_port_cfg_get_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (mcs->hw->lmac_cnt <= req->port_id || !(mcs->hw->lmac_bmap & BIT_ULL(req->port_id)))
return -EINVAL;
mcs_get_port_cfg(mcs, req, rsp);
return 0;
}
int rvu_mbox_handler_mcs_custom_tag_cfg_get(struct rvu *rvu, struct mcs_custom_tag_cfg_get_req *req,
struct mcs_custom_tag_cfg_get_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_get_custom_tag_cfg(mcs, req, rsp);
return 0;
}
int rvu_mcs_flr_handler(struct rvu *rvu, u16 pcifunc)
{
struct mcs *mcs;
int mcs_id;
/* CNF10K-B mcs0-6 are mapped to RPM2-8*/
if (rvu->mcs_blk_cnt > 1) {
for (mcs_id = 0; mcs_id < rvu->mcs_blk_cnt; mcs_id++) {
mcs = mcs_get_pdata(mcs_id);
mcs_free_all_rsrc(mcs, MCS_RX, pcifunc);
mcs_free_all_rsrc(mcs, MCS_TX, pcifunc);
}
} else {
/* CN10K-B has only one mcs block */
mcs = mcs_get_pdata(0);
mcs_free_all_rsrc(mcs, MCS_RX, pcifunc);
mcs_free_all_rsrc(mcs, MCS_TX, pcifunc);
}
return 0;
}
int rvu_mbox_handler_mcs_flowid_ena_entry(struct rvu *rvu,
struct mcs_flowid_ena_dis_entry *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_ena_dis_flowid_entry(mcs, req->flow_id, req->dir, req->ena);
return 0;
}
int rvu_mbox_handler_mcs_pn_table_write(struct rvu *rvu,
struct mcs_pn_table_write_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_pn_table_write(mcs, req->pn_id, req->next_pn, req->dir);
return 0;
}
int rvu_mbox_handler_mcs_set_pn_threshold(struct rvu *rvu,
struct mcs_set_pn_threshold *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_pn_threshold_set(mcs, req);
return 0;
}
int rvu_mbox_handler_mcs_rx_sc_sa_map_write(struct rvu *rvu,
struct mcs_rx_sc_sa_map *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs->mcs_ops->mcs_rx_sa_mem_map_write(mcs, req);
return 0;
}
int rvu_mbox_handler_mcs_tx_sc_sa_map_write(struct rvu *rvu,
struct mcs_tx_sc_sa_map *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs->mcs_ops->mcs_tx_sa_mem_map_write(mcs, req);
mcs->tx_sa_active[req->sc_id] = req->tx_sa_active;
return 0;
}
int rvu_mbox_handler_mcs_sa_plcy_write(struct rvu *rvu,
struct mcs_sa_plcy_write_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
int i;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
for (i = 0; i < req->sa_cnt; i++)
mcs_sa_plcy_write(mcs, &req->plcy[i][0],
req->sa_index[i], req->dir);
return 0;
}
int rvu_mbox_handler_mcs_rx_sc_cam_write(struct rvu *rvu,
struct mcs_rx_sc_cam_write_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_rx_sc_cam_write(mcs, req->sci, req->secy_id, req->sc_id);
return 0;
}
int rvu_mbox_handler_mcs_secy_plcy_write(struct rvu *rvu,
struct mcs_secy_plcy_write_req *req,
struct msg_rsp *rsp)
{ struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mcs_secy_plcy_write(mcs, req->plcy,
req->secy_id, req->dir);
return 0;
}
int rvu_mbox_handler_mcs_flowid_entry_write(struct rvu *rvu,
struct mcs_flowid_entry_write_req *req,
struct msg_rsp *rsp)
{
struct secy_mem_map map;
struct mcs *mcs;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
/* TODO validate the flowid */
mcs_flowid_entry_write(mcs, req->data, req->mask,
req->flow_id, req->dir);
map.secy = req->secy_id;
map.sc = req->sc_id;
map.ctrl_pkt = req->ctrl_pkt;
map.flow_id = req->flow_id;
map.sci = req->sci;
mcs->mcs_ops->mcs_flowid_secy_map(mcs, &map, req->dir);
if (req->ena)
mcs_ena_dis_flowid_entry(mcs, req->flow_id,
req->dir, true);
return 0;
}
int rvu_mbox_handler_mcs_free_resources(struct rvu *rvu,
struct mcs_free_rsrc_req *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct mcs_rsrc_map *map;
struct mcs *mcs;
int rc = 0;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (req->dir == MCS_RX)
map = &mcs->rx;
else
map = &mcs->tx;
mutex_lock(&rvu->rsrc_lock);
/* Free all the cam resources mapped to PF/VF */
if (req->all) {
rc = mcs_free_all_rsrc(mcs, req->dir, pcifunc);
goto exit;
}
switch (req->rsrc_type) {
case MCS_RSRC_TYPE_FLOWID:
rc = mcs_free_rsrc(&map->flow_ids, map->flowid2pf_map, req->rsrc_id, pcifunc);
mcs_ena_dis_flowid_entry(mcs, req->rsrc_id, req->dir, false);
break;
case MCS_RSRC_TYPE_SECY:
rc = mcs_free_rsrc(&map->secy, map->secy2pf_map, req->rsrc_id, pcifunc);
mcs_clear_secy_plcy(mcs, req->rsrc_id, req->dir);
break;
case MCS_RSRC_TYPE_SC:
rc = mcs_free_rsrc(&map->sc, map->sc2pf_map, req->rsrc_id, pcifunc);
/* Disable SC CAM only on RX side */
if (req->dir == MCS_RX)
mcs_ena_dis_sc_cam_entry(mcs, req->rsrc_id, false);
break;
case MCS_RSRC_TYPE_SA:
rc = mcs_free_rsrc(&map->sa, map->sa2pf_map, req->rsrc_id, pcifunc);
break;
}
exit:
mutex_unlock(&rvu->rsrc_lock);
return rc;
}
int rvu_mbox_handler_mcs_alloc_resources(struct rvu *rvu,
struct mcs_alloc_rsrc_req *req,
struct mcs_alloc_rsrc_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct mcs_rsrc_map *map;
struct mcs *mcs;
int rsrc_id, i;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
if (req->dir == MCS_RX)
map = &mcs->rx;
else
map = &mcs->tx;
mutex_lock(&rvu->rsrc_lock);
if (req->all) {
rsrc_id = mcs_alloc_all_rsrc(mcs, &rsp->flow_ids[0],
&rsp->secy_ids[0],
&rsp->sc_ids[0],
&rsp->sa_ids[0],
&rsp->sa_ids[1],
pcifunc, req->dir);
goto exit;
}
switch (req->rsrc_type) {
case MCS_RSRC_TYPE_FLOWID:
for (i = 0; i < req->rsrc_cnt; i++) {
rsrc_id = mcs_alloc_rsrc(&map->flow_ids, map->flowid2pf_map, pcifunc);
if (rsrc_id < 0)
goto exit;
rsp->flow_ids[i] = rsrc_id;
rsp->rsrc_cnt++;
}
break;
case MCS_RSRC_TYPE_SECY:
for (i = 0; i < req->rsrc_cnt; i++) {
rsrc_id = mcs_alloc_rsrc(&map->secy, map->secy2pf_map, pcifunc);
if (rsrc_id < 0)
goto exit;
rsp->secy_ids[i] = rsrc_id;
rsp->rsrc_cnt++;
}
break;
case MCS_RSRC_TYPE_SC:
for (i = 0; i < req->rsrc_cnt; i++) {
rsrc_id = mcs_alloc_rsrc(&map->sc, map->sc2pf_map, pcifunc);
if (rsrc_id < 0)
goto exit;
rsp->sc_ids[i] = rsrc_id;
rsp->rsrc_cnt++;
}
break;
case MCS_RSRC_TYPE_SA:
for (i = 0; i < req->rsrc_cnt; i++) {
rsrc_id = mcs_alloc_rsrc(&map->sa, map->sa2pf_map, pcifunc);
if (rsrc_id < 0)
goto exit;
rsp->sa_ids[i] = rsrc_id;
rsp->rsrc_cnt++;
}
break;
}
rsp->rsrc_type = req->rsrc_type;
rsp->dir = req->dir;
rsp->mcs_id = req->mcs_id;
rsp->all = req->all;
exit:
if (rsrc_id < 0)
dev_err(rvu->dev, "Failed to allocate the mcs resources for PCIFUNC:%d\n", pcifunc);
mutex_unlock(&rvu->rsrc_lock);
return 0;
}
int rvu_mbox_handler_mcs_alloc_ctrl_pkt_rule(struct rvu *rvu,
struct mcs_alloc_ctrl_pkt_rule_req *req,
struct mcs_alloc_ctrl_pkt_rule_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct mcs_rsrc_map *map;
struct mcs *mcs;
int rsrc_id;
u16 offset;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
map = (req->dir == MCS_RX) ? &mcs->rx : &mcs->tx;
mutex_lock(&rvu->rsrc_lock);
switch (req->rule_type) {
case MCS_CTRL_PKT_RULE_TYPE_ETH:
offset = MCS_CTRLPKT_ETYPE_RULE_OFFSET;
break;
case MCS_CTRL_PKT_RULE_TYPE_DA:
offset = MCS_CTRLPKT_DA_RULE_OFFSET;
break;
case MCS_CTRL_PKT_RULE_TYPE_RANGE:
offset = MCS_CTRLPKT_DA_RANGE_RULE_OFFSET;
break;
case MCS_CTRL_PKT_RULE_TYPE_COMBO:
offset = MCS_CTRLPKT_COMBO_RULE_OFFSET;
break;
case MCS_CTRL_PKT_RULE_TYPE_MAC:
offset = MCS_CTRLPKT_MAC_EN_RULE_OFFSET;
break;
}
rsrc_id = mcs_alloc_ctrlpktrule(&map->ctrlpktrule, map->ctrlpktrule2pf_map, offset,
pcifunc);
if (rsrc_id < 0)
goto exit;
rsp->rule_idx = rsrc_id;
rsp->rule_type = req->rule_type;
rsp->dir = req->dir;
rsp->mcs_id = req->mcs_id;
mutex_unlock(&rvu->rsrc_lock);
return 0;
exit:
if (rsrc_id < 0)
dev_err(rvu->dev, "Failed to allocate the mcs ctrl pkt rule for PCIFUNC:%d\n",
pcifunc);
mutex_unlock(&rvu->rsrc_lock);
return rsrc_id;
}
int rvu_mbox_handler_mcs_free_ctrl_pkt_rule(struct rvu *rvu,
struct mcs_free_ctrl_pkt_rule_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
int rc;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
mutex_lock(&rvu->rsrc_lock);
rc = mcs_free_ctrlpktrule(mcs, req);
mutex_unlock(&rvu->rsrc_lock);
return rc;
}
int rvu_mbox_handler_mcs_ctrl_pkt_rule_write(struct rvu *rvu,
struct mcs_ctrl_pkt_rule_write_req *req,
struct msg_rsp *rsp)
{
struct mcs *mcs;
int rc;
if (req->mcs_id >= rvu->mcs_blk_cnt)
return MCS_AF_ERR_INVALID_MCSID;
mcs = mcs_get_pdata(req->mcs_id);
rc = mcs_ctrlpktrule_write(mcs, req);
return rc;
}
static void rvu_mcs_set_lmac_bmap(struct rvu *rvu)
{
struct mcs *mcs = mcs_get_pdata(0);
unsigned long lmac_bmap;
int cgx, lmac, port;
for (port = 0; port < mcs->hw->lmac_cnt; port++) {
cgx = port / rvu->hw->lmac_per_cgx;
lmac = port % rvu->hw->lmac_per_cgx;
if (!is_lmac_valid(rvu_cgx_pdata(cgx, rvu), lmac))
continue;
set_bit(port, &lmac_bmap);
}
mcs->hw->lmac_bmap = lmac_bmap;
}
int rvu_mcs_init(struct rvu *rvu)
{
struct rvu_hwinfo *hw = rvu->hw;
int lmac, err = 0, mcs_id;
struct mcs *mcs;
rvu->mcs_blk_cnt = mcs_get_blkcnt();
if (!rvu->mcs_blk_cnt)
return 0;
/* Needed only for CN10K-B */
if (rvu->mcs_blk_cnt == 1) {
err = mcs_set_lmac_channels(0, hw->cgx_chan_base);
if (err)
return err;
/* Set active lmacs */
rvu_mcs_set_lmac_bmap(rvu);
}
/* Install default tcam bypass entry and set port to operational mode */
for (mcs_id = 0; mcs_id < rvu->mcs_blk_cnt; mcs_id++) {
mcs = mcs_get_pdata(mcs_id);
mcs_install_flowid_bypass_entry(mcs);
for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++)
mcs_set_lmac_mode(mcs, lmac, 0);
mcs->rvu = rvu;
/* Allocated memory for PFVF data */
mcs->pf = devm_kcalloc(mcs->dev, hw->total_pfs,
sizeof(struct mcs_pfvf), GFP_KERNEL);
if (!mcs->pf)
return -ENOMEM;
mcs->vf = devm_kcalloc(mcs->dev, hw->total_vfs,
sizeof(struct mcs_pfvf), GFP_KERNEL);
if (!mcs->vf)
return -ENOMEM;
}
/* Initialize the wq for handling mcs interrupts */
INIT_LIST_HEAD(&rvu->mcs_intrq_head);
INIT_WORK(&rvu->mcs_intr_work, mcs_intr_handler_task);
rvu->mcs_intr_wq = alloc_workqueue("mcs_intr_wq", 0, 0);
if (!rvu->mcs_intr_wq) {
dev_err(rvu->dev, "mcs alloc workqueue failed\n");
return -ENOMEM;
}
return err;
}
void rvu_mcs_exit(struct rvu *rvu)
{
if (!rvu->mcs_intr_wq)
return;
flush_workqueue(rvu->mcs_intr_wq);
destroy_workqueue(rvu->mcs_intr_wq);
rvu->mcs_intr_wq = NULL;
}