xref: /linux/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c (revision 0c7c237b1c35011ef0b8d30c1d5c20bc6ae7b69b)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell RVU Admin Function driver
3  *
4  * Copyright (C) 2021 Marvell.
5  *
6  */
7 
8 #include <linux/bitfield.h>
9 #include "rvu.h"
10 
11 static void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable)
12 {
13 	struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
14 	struct nix_hw *nix_hw;
15 
16 	nix_hw = get_nix_hw(rvu->hw, pfvf->nix_blkaddr);
17 	/* Enable LBK links with channel 63 for TX MCAM rule */
18 	rvu_nix_tx_tl2_cfg(rvu, pfvf->nix_blkaddr, pcifunc,
19 			   &nix_hw->txsch[NIX_TXSCH_LVL_TL2], enable);
20 }
21 
22 static int rvu_switch_install_rx_rule(struct rvu *rvu, u16 pcifunc,
23 				      u16 chan_mask)
24 {
25 	struct npc_install_flow_req req = { 0 };
26 	struct npc_install_flow_rsp rsp = { 0 };
27 	struct rvu_pfvf *pfvf;
28 
29 	pfvf = rvu_get_pfvf(rvu, pcifunc);
30 	/* If the pcifunc is not initialized then nothing to do.
31 	 * This same function will be called again via rvu_switch_update_rules
32 	 * after pcifunc is initialized.
33 	 */
34 	if (!test_bit(NIXLF_INITIALIZED, &pfvf->flags))
35 		return 0;
36 
37 	ether_addr_copy(req.packet.dmac, pfvf->mac_addr);
38 	eth_broadcast_addr((u8 *)&req.mask.dmac);
39 	req.hdr.pcifunc = 0; /* AF is requester */
40 	req.vf = pcifunc;
41 	req.features = BIT_ULL(NPC_DMAC);
42 	req.channel = pfvf->rx_chan_base;
43 	req.chan_mask = chan_mask;
44 	req.intf = pfvf->nix_rx_intf;
45 	req.op = NIX_RX_ACTION_DEFAULT;
46 	req.default_rule = 1;
47 
48 	return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
49 }
50 
51 static int rvu_switch_install_tx_rule(struct rvu *rvu, u16 pcifunc, u16 entry)
52 {
53 	struct npc_install_flow_req req = { 0 };
54 	struct npc_install_flow_rsp rsp = { 0 };
55 	struct rvu_pfvf *pfvf;
56 	u8 lbkid;
57 
58 	pfvf = rvu_get_pfvf(rvu, pcifunc);
59 	/* If the pcifunc is not initialized then nothing to do.
60 	 * This same function will be called again via rvu_switch_update_rules
61 	 * after pcifunc is initialized.
62 	 */
63 	if (!test_bit(NIXLF_INITIALIZED, &pfvf->flags))
64 		return 0;
65 
66 	rvu_switch_enable_lbk_link(rvu, pcifunc, true);
67 
68 	lbkid = pfvf->nix_blkaddr == BLKADDR_NIX0 ? 0 : 1;
69 	ether_addr_copy(req.packet.dmac, pfvf->mac_addr);
70 	eth_broadcast_addr((u8 *)&req.mask.dmac);
71 	req.hdr.pcifunc = 0; /* AF is requester */
72 	req.vf = pcifunc;
73 	req.entry = entry;
74 	req.features = BIT_ULL(NPC_DMAC);
75 	req.intf = pfvf->nix_tx_intf;
76 	req.op = NIX_TX_ACTIONOP_UCAST_CHAN;
77 	req.index = (lbkid << 8) | RVU_SWITCH_LBK_CHAN;
78 	req.set_cntr = 1;
79 
80 	return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
81 }
82 
83 static int rvu_switch_install_rules(struct rvu *rvu)
84 {
85 	struct rvu_switch *rswitch = &rvu->rswitch;
86 	u16 start = rswitch->start_entry;
87 	struct rvu_hwinfo *hw = rvu->hw;
88 	u16 pcifunc, entry = 0;
89 	int pf, vf, numvfs;
90 	int err;
91 
92 	for (pf = 1; pf < hw->total_pfs; pf++) {
93 		if (!is_pf_cgxmapped(rvu, pf))
94 			continue;
95 
96 		pcifunc = pf << 10;
97 		/* rvu_get_nix_blkaddr sets up the corresponding NIX block
98 		 * address and NIX RX and TX interfaces for a pcifunc.
99 		 * Generally it is called during attach call of a pcifunc but it
100 		 * is called here since we are pre-installing rules before
101 		 * nixlfs are attached
102 		 */
103 		rvu_get_nix_blkaddr(rvu, pcifunc);
104 
105 		/* MCAM RX rule for a PF/VF already exists as default unicast
106 		 * rules installed by AF. Hence change the channel in those
107 		 * rules to ignore channel so that packets with the required
108 		 * DMAC received from LBK(by other PF/VFs in system) or from
109 		 * external world (from wire) are accepted.
110 		 */
111 		err = rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
112 		if (err) {
113 			dev_err(rvu->dev, "RX rule for PF%d failed(%d)\n",
114 				pf, err);
115 			return err;
116 		}
117 
118 		err = rvu_switch_install_tx_rule(rvu, pcifunc, start + entry);
119 		if (err) {
120 			dev_err(rvu->dev, "TX rule for PF%d failed(%d)\n",
121 				pf, err);
122 			return err;
123 		}
124 
125 		rswitch->entry2pcifunc[entry++] = pcifunc;
126 
127 		rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
128 		for (vf = 0; vf < numvfs; vf++) {
129 			pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
130 			rvu_get_nix_blkaddr(rvu, pcifunc);
131 
132 			err = rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
133 			if (err) {
134 				dev_err(rvu->dev,
135 					"RX rule for PF%dVF%d failed(%d)\n",
136 					pf, vf, err);
137 				return err;
138 			}
139 
140 			err = rvu_switch_install_tx_rule(rvu, pcifunc,
141 							 start + entry);
142 			if (err) {
143 				dev_err(rvu->dev,
144 					"TX rule for PF%dVF%d failed(%d)\n",
145 					pf, vf, err);
146 				return err;
147 			}
148 
149 			rswitch->entry2pcifunc[entry++] = pcifunc;
150 		}
151 	}
152 
153 	return 0;
154 }
155 
156 void rvu_switch_enable(struct rvu *rvu)
157 {
158 	struct npc_mcam_alloc_entry_req alloc_req = { 0 };
159 	struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
160 	struct npc_delete_flow_req uninstall_req = { 0 };
161 	struct npc_mcam_free_entry_req free_req = { 0 };
162 	struct rvu_switch *rswitch = &rvu->rswitch;
163 	struct msg_rsp rsp;
164 	int ret;
165 
166 	alloc_req.contig = true;
167 	alloc_req.count = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs;
168 	ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &alloc_req,
169 						    &alloc_rsp);
170 	if (ret) {
171 		dev_err(rvu->dev,
172 			"Unable to allocate MCAM entries\n");
173 		goto exit;
174 	}
175 
176 	if (alloc_rsp.count != alloc_req.count) {
177 		dev_err(rvu->dev,
178 			"Unable to allocate %d MCAM entries, got %d\n",
179 			alloc_req.count, alloc_rsp.count);
180 		goto free_entries;
181 	}
182 
183 	rswitch->entry2pcifunc = kcalloc(alloc_req.count, sizeof(u16),
184 					 GFP_KERNEL);
185 	if (!rswitch->entry2pcifunc)
186 		goto free_entries;
187 
188 	rswitch->used_entries = alloc_rsp.count;
189 	rswitch->start_entry = alloc_rsp.entry;
190 
191 	ret = rvu_switch_install_rules(rvu);
192 	if (ret)
193 		goto uninstall_rules;
194 
195 	return;
196 
197 uninstall_rules:
198 	uninstall_req.start = rswitch->start_entry;
199 	uninstall_req.end =  rswitch->start_entry + rswitch->used_entries - 1;
200 	rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
201 	kfree(rswitch->entry2pcifunc);
202 free_entries:
203 	free_req.all = 1;
204 	rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
205 exit:
206 	return;
207 }
208 
209 void rvu_switch_disable(struct rvu *rvu)
210 {
211 	struct npc_delete_flow_req uninstall_req = { 0 };
212 	struct npc_mcam_free_entry_req free_req = { 0 };
213 	struct rvu_switch *rswitch = &rvu->rswitch;
214 	struct rvu_hwinfo *hw = rvu->hw;
215 	int pf, vf, numvfs;
216 	struct msg_rsp rsp;
217 	u16 pcifunc;
218 	int err;
219 
220 	if (!rswitch->used_entries)
221 		return;
222 
223 	for (pf = 1; pf < hw->total_pfs; pf++) {
224 		if (!is_pf_cgxmapped(rvu, pf))
225 			continue;
226 
227 		pcifunc = pf << 10;
228 		err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
229 		if (err)
230 			dev_err(rvu->dev,
231 				"Reverting RX rule for PF%d failed(%d)\n",
232 				pf, err);
233 
234 		/* Disable LBK link */
235 		rvu_switch_enable_lbk_link(rvu, pcifunc, false);
236 
237 		rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
238 		for (vf = 0; vf < numvfs; vf++) {
239 			pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
240 			err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
241 			if (err)
242 				dev_err(rvu->dev,
243 					"Reverting RX rule for PF%dVF%d failed(%d)\n",
244 					pf, vf, err);
245 
246 			rvu_switch_enable_lbk_link(rvu, pcifunc, false);
247 		}
248 	}
249 
250 	uninstall_req.start = rswitch->start_entry;
251 	uninstall_req.end =  rswitch->start_entry + rswitch->used_entries - 1;
252 	free_req.all = 1;
253 	rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
254 	rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
255 	rswitch->used_entries = 0;
256 	kfree(rswitch->entry2pcifunc);
257 }
258 
259 void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc)
260 {
261 	struct rvu_switch *rswitch = &rvu->rswitch;
262 	u32 max = rswitch->used_entries;
263 	u16 entry;
264 
265 	if (!rswitch->used_entries)
266 		return;
267 
268 	for (entry = 0; entry < max; entry++) {
269 		if (rswitch->entry2pcifunc[entry] == pcifunc)
270 			break;
271 	}
272 
273 	if (entry >= max)
274 		return;
275 
276 	rvu_switch_install_tx_rule(rvu, pcifunc, rswitch->start_entry + entry);
277 	rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
278 }
279