123109f8dSSubbaraya Sundeep // SPDX-License-Identifier: GPL-2.0
2c7cd6c5aSSunil Goutham /* Marvell RVU Admin Function driver
323109f8dSSubbaraya Sundeep *
423109f8dSSubbaraya Sundeep * Copyright (C) 2021 Marvell.
5c7cd6c5aSSunil Goutham *
623109f8dSSubbaraya Sundeep */
723109f8dSSubbaraya Sundeep
823109f8dSSubbaraya Sundeep #include <linux/bitfield.h>
923109f8dSSubbaraya Sundeep #include "rvu.h"
1023109f8dSSubbaraya Sundeep
rvu_switch_enable_lbk_link(struct rvu * rvu,u16 pcifunc,bool enable)11b6a072a1SSubbaraya Sundeep static void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable)
12b6a072a1SSubbaraya Sundeep {
13b6a072a1SSubbaraya Sundeep struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
14b6a072a1SSubbaraya Sundeep struct nix_hw *nix_hw;
15b6a072a1SSubbaraya Sundeep
16b6a072a1SSubbaraya Sundeep nix_hw = get_nix_hw(rvu->hw, pfvf->nix_blkaddr);
17b6a072a1SSubbaraya Sundeep /* Enable LBK links with channel 63 for TX MCAM rule */
18b6a072a1SSubbaraya Sundeep rvu_nix_tx_tl2_cfg(rvu, pfvf->nix_blkaddr, pcifunc,
19b6a072a1SSubbaraya Sundeep &nix_hw->txsch[NIX_TXSCH_LVL_TL2], enable);
20b6a072a1SSubbaraya Sundeep }
21b6a072a1SSubbaraya Sundeep
rvu_switch_install_rx_rule(struct rvu * rvu,u16 pcifunc,u16 chan_mask)2223109f8dSSubbaraya Sundeep static int rvu_switch_install_rx_rule(struct rvu *rvu, u16 pcifunc,
2323109f8dSSubbaraya Sundeep u16 chan_mask)
2423109f8dSSubbaraya Sundeep {
2523109f8dSSubbaraya Sundeep struct npc_install_flow_req req = { 0 };
2623109f8dSSubbaraya Sundeep struct npc_install_flow_rsp rsp = { 0 };
2723109f8dSSubbaraya Sundeep struct rvu_pfvf *pfvf;
2823109f8dSSubbaraya Sundeep
2923109f8dSSubbaraya Sundeep pfvf = rvu_get_pfvf(rvu, pcifunc);
3023109f8dSSubbaraya Sundeep /* If the pcifunc is not initialized then nothing to do.
3123109f8dSSubbaraya Sundeep * This same function will be called again via rvu_switch_update_rules
3223109f8dSSubbaraya Sundeep * after pcifunc is initialized.
3323109f8dSSubbaraya Sundeep */
3423109f8dSSubbaraya Sundeep if (!test_bit(NIXLF_INITIALIZED, &pfvf->flags))
3523109f8dSSubbaraya Sundeep return 0;
3623109f8dSSubbaraya Sundeep
3723109f8dSSubbaraya Sundeep ether_addr_copy(req.packet.dmac, pfvf->mac_addr);
3823109f8dSSubbaraya Sundeep eth_broadcast_addr((u8 *)&req.mask.dmac);
3923109f8dSSubbaraya Sundeep req.hdr.pcifunc = 0; /* AF is requester */
4023109f8dSSubbaraya Sundeep req.vf = pcifunc;
4123109f8dSSubbaraya Sundeep req.features = BIT_ULL(NPC_DMAC);
4223109f8dSSubbaraya Sundeep req.channel = pfvf->rx_chan_base;
4323109f8dSSubbaraya Sundeep req.chan_mask = chan_mask;
4423109f8dSSubbaraya Sundeep req.intf = pfvf->nix_rx_intf;
4523109f8dSSubbaraya Sundeep req.op = NIX_RX_ACTION_DEFAULT;
4623109f8dSSubbaraya Sundeep req.default_rule = 1;
4723109f8dSSubbaraya Sundeep
4823109f8dSSubbaraya Sundeep return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
4923109f8dSSubbaraya Sundeep }
5023109f8dSSubbaraya Sundeep
rvu_switch_install_tx_rule(struct rvu * rvu,u16 pcifunc,u16 entry)5123109f8dSSubbaraya Sundeep static int rvu_switch_install_tx_rule(struct rvu *rvu, u16 pcifunc, u16 entry)
5223109f8dSSubbaraya Sundeep {
5323109f8dSSubbaraya Sundeep struct npc_install_flow_req req = { 0 };
5423109f8dSSubbaraya Sundeep struct npc_install_flow_rsp rsp = { 0 };
5523109f8dSSubbaraya Sundeep struct rvu_pfvf *pfvf;
5623109f8dSSubbaraya Sundeep u8 lbkid;
5723109f8dSSubbaraya Sundeep
5823109f8dSSubbaraya Sundeep pfvf = rvu_get_pfvf(rvu, pcifunc);
5923109f8dSSubbaraya Sundeep /* If the pcifunc is not initialized then nothing to do.
6023109f8dSSubbaraya Sundeep * This same function will be called again via rvu_switch_update_rules
6123109f8dSSubbaraya Sundeep * after pcifunc is initialized.
6223109f8dSSubbaraya Sundeep */
6323109f8dSSubbaraya Sundeep if (!test_bit(NIXLF_INITIALIZED, &pfvf->flags))
6423109f8dSSubbaraya Sundeep return 0;
6523109f8dSSubbaraya Sundeep
66b6a072a1SSubbaraya Sundeep rvu_switch_enable_lbk_link(rvu, pcifunc, true);
67b6a072a1SSubbaraya Sundeep
6823109f8dSSubbaraya Sundeep lbkid = pfvf->nix_blkaddr == BLKADDR_NIX0 ? 0 : 1;
6923109f8dSSubbaraya Sundeep ether_addr_copy(req.packet.dmac, pfvf->mac_addr);
7023109f8dSSubbaraya Sundeep eth_broadcast_addr((u8 *)&req.mask.dmac);
7123109f8dSSubbaraya Sundeep req.hdr.pcifunc = 0; /* AF is requester */
7223109f8dSSubbaraya Sundeep req.vf = pcifunc;
7323109f8dSSubbaraya Sundeep req.entry = entry;
7423109f8dSSubbaraya Sundeep req.features = BIT_ULL(NPC_DMAC);
7523109f8dSSubbaraya Sundeep req.intf = pfvf->nix_tx_intf;
7623109f8dSSubbaraya Sundeep req.op = NIX_TX_ACTIONOP_UCAST_CHAN;
7723109f8dSSubbaraya Sundeep req.index = (lbkid << 8) | RVU_SWITCH_LBK_CHAN;
7823109f8dSSubbaraya Sundeep req.set_cntr = 1;
7923109f8dSSubbaraya Sundeep
8023109f8dSSubbaraya Sundeep return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
8123109f8dSSubbaraya Sundeep }
8223109f8dSSubbaraya Sundeep
rvu_switch_install_rules(struct rvu * rvu)8323109f8dSSubbaraya Sundeep static int rvu_switch_install_rules(struct rvu *rvu)
8423109f8dSSubbaraya Sundeep {
8523109f8dSSubbaraya Sundeep struct rvu_switch *rswitch = &rvu->rswitch;
8623109f8dSSubbaraya Sundeep u16 start = rswitch->start_entry;
8723109f8dSSubbaraya Sundeep struct rvu_hwinfo *hw = rvu->hw;
8823109f8dSSubbaraya Sundeep u16 pcifunc, entry = 0;
899986066dSSubbaraya Sundeep int pf, vf, numvfs;
9023109f8dSSubbaraya Sundeep int err;
9123109f8dSSubbaraya Sundeep
9223109f8dSSubbaraya Sundeep for (pf = 1; pf < hw->total_pfs; pf++) {
9323109f8dSSubbaraya Sundeep if (!is_pf_cgxmapped(rvu, pf))
9423109f8dSSubbaraya Sundeep continue;
9523109f8dSSubbaraya Sundeep
9623109f8dSSubbaraya Sundeep pcifunc = pf << 10;
9723109f8dSSubbaraya Sundeep /* rvu_get_nix_blkaddr sets up the corresponding NIX block
9823109f8dSSubbaraya Sundeep * address and NIX RX and TX interfaces for a pcifunc.
9923109f8dSSubbaraya Sundeep * Generally it is called during attach call of a pcifunc but it
10023109f8dSSubbaraya Sundeep * is called here since we are pre-installing rules before
10123109f8dSSubbaraya Sundeep * nixlfs are attached
10223109f8dSSubbaraya Sundeep */
10323109f8dSSubbaraya Sundeep rvu_get_nix_blkaddr(rvu, pcifunc);
10423109f8dSSubbaraya Sundeep
10523109f8dSSubbaraya Sundeep /* MCAM RX rule for a PF/VF already exists as default unicast
10623109f8dSSubbaraya Sundeep * rules installed by AF. Hence change the channel in those
10723109f8dSSubbaraya Sundeep * rules to ignore channel so that packets with the required
10823109f8dSSubbaraya Sundeep * DMAC received from LBK(by other PF/VFs in system) or from
10923109f8dSSubbaraya Sundeep * external world (from wire) are accepted.
11023109f8dSSubbaraya Sundeep */
11123109f8dSSubbaraya Sundeep err = rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
11223109f8dSSubbaraya Sundeep if (err) {
11323109f8dSSubbaraya Sundeep dev_err(rvu->dev, "RX rule for PF%d failed(%d)\n",
11423109f8dSSubbaraya Sundeep pf, err);
11523109f8dSSubbaraya Sundeep return err;
11623109f8dSSubbaraya Sundeep }
11723109f8dSSubbaraya Sundeep
11823109f8dSSubbaraya Sundeep err = rvu_switch_install_tx_rule(rvu, pcifunc, start + entry);
11923109f8dSSubbaraya Sundeep if (err) {
12023109f8dSSubbaraya Sundeep dev_err(rvu->dev, "TX rule for PF%d failed(%d)\n",
12123109f8dSSubbaraya Sundeep pf, err);
12223109f8dSSubbaraya Sundeep return err;
12323109f8dSSubbaraya Sundeep }
12423109f8dSSubbaraya Sundeep
12523109f8dSSubbaraya Sundeep rswitch->entry2pcifunc[entry++] = pcifunc;
12623109f8dSSubbaraya Sundeep
1279986066dSSubbaraya Sundeep rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
1289986066dSSubbaraya Sundeep for (vf = 0; vf < numvfs; vf++) {
12923109f8dSSubbaraya Sundeep pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
13023109f8dSSubbaraya Sundeep rvu_get_nix_blkaddr(rvu, pcifunc);
13123109f8dSSubbaraya Sundeep
13223109f8dSSubbaraya Sundeep err = rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
13323109f8dSSubbaraya Sundeep if (err) {
13423109f8dSSubbaraya Sundeep dev_err(rvu->dev,
13523109f8dSSubbaraya Sundeep "RX rule for PF%dVF%d failed(%d)\n",
13623109f8dSSubbaraya Sundeep pf, vf, err);
13723109f8dSSubbaraya Sundeep return err;
13823109f8dSSubbaraya Sundeep }
13923109f8dSSubbaraya Sundeep
14023109f8dSSubbaraya Sundeep err = rvu_switch_install_tx_rule(rvu, pcifunc,
14123109f8dSSubbaraya Sundeep start + entry);
14223109f8dSSubbaraya Sundeep if (err) {
14323109f8dSSubbaraya Sundeep dev_err(rvu->dev,
14423109f8dSSubbaraya Sundeep "TX rule for PF%dVF%d failed(%d)\n",
14523109f8dSSubbaraya Sundeep pf, vf, err);
14623109f8dSSubbaraya Sundeep return err;
14723109f8dSSubbaraya Sundeep }
14823109f8dSSubbaraya Sundeep
14923109f8dSSubbaraya Sundeep rswitch->entry2pcifunc[entry++] = pcifunc;
15023109f8dSSubbaraya Sundeep }
15123109f8dSSubbaraya Sundeep }
15223109f8dSSubbaraya Sundeep
15323109f8dSSubbaraya Sundeep return 0;
15423109f8dSSubbaraya Sundeep }
15523109f8dSSubbaraya Sundeep
rvu_switch_enable(struct rvu * rvu)15623109f8dSSubbaraya Sundeep void rvu_switch_enable(struct rvu *rvu)
15723109f8dSSubbaraya Sundeep {
15823109f8dSSubbaraya Sundeep struct npc_mcam_alloc_entry_req alloc_req = { 0 };
15923109f8dSSubbaraya Sundeep struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
16023109f8dSSubbaraya Sundeep struct npc_delete_flow_req uninstall_req = { 0 };
161*ec87f054SSuman Ghosh struct npc_delete_flow_rsp uninstall_rsp = { 0 };
16223109f8dSSubbaraya Sundeep struct npc_mcam_free_entry_req free_req = { 0 };
16323109f8dSSubbaraya Sundeep struct rvu_switch *rswitch = &rvu->rswitch;
16423109f8dSSubbaraya Sundeep struct msg_rsp rsp;
16523109f8dSSubbaraya Sundeep int ret;
16623109f8dSSubbaraya Sundeep
16723109f8dSSubbaraya Sundeep alloc_req.contig = true;
16823109f8dSSubbaraya Sundeep alloc_req.count = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs;
16923109f8dSSubbaraya Sundeep ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &alloc_req,
17023109f8dSSubbaraya Sundeep &alloc_rsp);
17123109f8dSSubbaraya Sundeep if (ret) {
17223109f8dSSubbaraya Sundeep dev_err(rvu->dev,
17323109f8dSSubbaraya Sundeep "Unable to allocate MCAM entries\n");
17423109f8dSSubbaraya Sundeep goto exit;
17523109f8dSSubbaraya Sundeep }
17623109f8dSSubbaraya Sundeep
17723109f8dSSubbaraya Sundeep if (alloc_rsp.count != alloc_req.count) {
17823109f8dSSubbaraya Sundeep dev_err(rvu->dev,
17923109f8dSSubbaraya Sundeep "Unable to allocate %d MCAM entries, got %d\n",
18023109f8dSSubbaraya Sundeep alloc_req.count, alloc_rsp.count);
18123109f8dSSubbaraya Sundeep goto free_entries;
18223109f8dSSubbaraya Sundeep }
18323109f8dSSubbaraya Sundeep
18423109f8dSSubbaraya Sundeep rswitch->entry2pcifunc = kcalloc(alloc_req.count, sizeof(u16),
18523109f8dSSubbaraya Sundeep GFP_KERNEL);
18623109f8dSSubbaraya Sundeep if (!rswitch->entry2pcifunc)
18723109f8dSSubbaraya Sundeep goto free_entries;
18823109f8dSSubbaraya Sundeep
18923109f8dSSubbaraya Sundeep rswitch->used_entries = alloc_rsp.count;
19023109f8dSSubbaraya Sundeep rswitch->start_entry = alloc_rsp.entry;
19123109f8dSSubbaraya Sundeep
19223109f8dSSubbaraya Sundeep ret = rvu_switch_install_rules(rvu);
19323109f8dSSubbaraya Sundeep if (ret)
19423109f8dSSubbaraya Sundeep goto uninstall_rules;
19523109f8dSSubbaraya Sundeep
19623109f8dSSubbaraya Sundeep return;
19723109f8dSSubbaraya Sundeep
19823109f8dSSubbaraya Sundeep uninstall_rules:
19923109f8dSSubbaraya Sundeep uninstall_req.start = rswitch->start_entry;
20023109f8dSSubbaraya Sundeep uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
201*ec87f054SSuman Ghosh rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
20223109f8dSSubbaraya Sundeep kfree(rswitch->entry2pcifunc);
20323109f8dSSubbaraya Sundeep free_entries:
20423109f8dSSubbaraya Sundeep free_req.all = 1;
20523109f8dSSubbaraya Sundeep rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
20623109f8dSSubbaraya Sundeep exit:
20723109f8dSSubbaraya Sundeep return;
20823109f8dSSubbaraya Sundeep }
20923109f8dSSubbaraya Sundeep
rvu_switch_disable(struct rvu * rvu)21023109f8dSSubbaraya Sundeep void rvu_switch_disable(struct rvu *rvu)
21123109f8dSSubbaraya Sundeep {
21223109f8dSSubbaraya Sundeep struct npc_delete_flow_req uninstall_req = { 0 };
213*ec87f054SSuman Ghosh struct npc_delete_flow_rsp uninstall_rsp = { 0 };
21423109f8dSSubbaraya Sundeep struct npc_mcam_free_entry_req free_req = { 0 };
21523109f8dSSubbaraya Sundeep struct rvu_switch *rswitch = &rvu->rswitch;
21623109f8dSSubbaraya Sundeep struct rvu_hwinfo *hw = rvu->hw;
2179986066dSSubbaraya Sundeep int pf, vf, numvfs;
21823109f8dSSubbaraya Sundeep struct msg_rsp rsp;
21923109f8dSSubbaraya Sundeep u16 pcifunc;
22023109f8dSSubbaraya Sundeep int err;
22123109f8dSSubbaraya Sundeep
22223109f8dSSubbaraya Sundeep if (!rswitch->used_entries)
22323109f8dSSubbaraya Sundeep return;
22423109f8dSSubbaraya Sundeep
22523109f8dSSubbaraya Sundeep for (pf = 1; pf < hw->total_pfs; pf++) {
22623109f8dSSubbaraya Sundeep if (!is_pf_cgxmapped(rvu, pf))
22723109f8dSSubbaraya Sundeep continue;
22823109f8dSSubbaraya Sundeep
22923109f8dSSubbaraya Sundeep pcifunc = pf << 10;
23023109f8dSSubbaraya Sundeep err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
23123109f8dSSubbaraya Sundeep if (err)
23223109f8dSSubbaraya Sundeep dev_err(rvu->dev,
23323109f8dSSubbaraya Sundeep "Reverting RX rule for PF%d failed(%d)\n",
23423109f8dSSubbaraya Sundeep pf, err);
23523109f8dSSubbaraya Sundeep
236b6a072a1SSubbaraya Sundeep /* Disable LBK link */
237b6a072a1SSubbaraya Sundeep rvu_switch_enable_lbk_link(rvu, pcifunc, false);
238b6a072a1SSubbaraya Sundeep
2399986066dSSubbaraya Sundeep rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
2409986066dSSubbaraya Sundeep for (vf = 0; vf < numvfs; vf++) {
24123109f8dSSubbaraya Sundeep pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
24223109f8dSSubbaraya Sundeep err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
24323109f8dSSubbaraya Sundeep if (err)
24423109f8dSSubbaraya Sundeep dev_err(rvu->dev,
24523109f8dSSubbaraya Sundeep "Reverting RX rule for PF%dVF%d failed(%d)\n",
24623109f8dSSubbaraya Sundeep pf, vf, err);
247b6a072a1SSubbaraya Sundeep
248b6a072a1SSubbaraya Sundeep rvu_switch_enable_lbk_link(rvu, pcifunc, false);
24923109f8dSSubbaraya Sundeep }
25023109f8dSSubbaraya Sundeep }
25123109f8dSSubbaraya Sundeep
25223109f8dSSubbaraya Sundeep uninstall_req.start = rswitch->start_entry;
25323109f8dSSubbaraya Sundeep uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
25423109f8dSSubbaraya Sundeep free_req.all = 1;
255*ec87f054SSuman Ghosh rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
25623109f8dSSubbaraya Sundeep rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
25723109f8dSSubbaraya Sundeep rswitch->used_entries = 0;
25823109f8dSSubbaraya Sundeep kfree(rswitch->entry2pcifunc);
25923109f8dSSubbaraya Sundeep }
26023109f8dSSubbaraya Sundeep
rvu_switch_update_rules(struct rvu * rvu,u16 pcifunc)26123109f8dSSubbaraya Sundeep void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc)
26223109f8dSSubbaraya Sundeep {
26323109f8dSSubbaraya Sundeep struct rvu_switch *rswitch = &rvu->rswitch;
26423109f8dSSubbaraya Sundeep u32 max = rswitch->used_entries;
26523109f8dSSubbaraya Sundeep u16 entry;
26623109f8dSSubbaraya Sundeep
26723109f8dSSubbaraya Sundeep if (!rswitch->used_entries)
26823109f8dSSubbaraya Sundeep return;
26923109f8dSSubbaraya Sundeep
27023109f8dSSubbaraya Sundeep for (entry = 0; entry < max; entry++) {
27123109f8dSSubbaraya Sundeep if (rswitch->entry2pcifunc[entry] == pcifunc)
27223109f8dSSubbaraya Sundeep break;
27323109f8dSSubbaraya Sundeep }
27423109f8dSSubbaraya Sundeep
27523109f8dSSubbaraya Sundeep if (entry >= max)
27623109f8dSSubbaraya Sundeep return;
27723109f8dSSubbaraya Sundeep
27823109f8dSSubbaraya Sundeep rvu_switch_install_tx_rule(rvu, pcifunc, rswitch->start_entry + entry);
27923109f8dSSubbaraya Sundeep rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
28023109f8dSSubbaraya Sundeep }
281