// SPDX-License-Identifier: GPL-2.0 /* Marvell CN10K MCS driver * * Copyright (C) 2022 Marvell. */ #include #include #include #include #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; }