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
11static 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
22static 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
51static 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
83static 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
156void 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_delete_flow_rsp uninstall_rsp = { 0 };
162	struct npc_mcam_free_entry_req free_req = { 0 };
163	struct rvu_switch *rswitch = &rvu->rswitch;
164	struct msg_rsp rsp;
165	int ret;
166
167	alloc_req.contig = true;
168	alloc_req.count = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs;
169	ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &alloc_req,
170						    &alloc_rsp);
171	if (ret) {
172		dev_err(rvu->dev,
173			"Unable to allocate MCAM entries\n");
174		goto exit;
175	}
176
177	if (alloc_rsp.count != alloc_req.count) {
178		dev_err(rvu->dev,
179			"Unable to allocate %d MCAM entries, got %d\n",
180			alloc_req.count, alloc_rsp.count);
181		goto free_entries;
182	}
183
184	rswitch->entry2pcifunc = kcalloc(alloc_req.count, sizeof(u16),
185					 GFP_KERNEL);
186	if (!rswitch->entry2pcifunc)
187		goto free_entries;
188
189	rswitch->used_entries = alloc_rsp.count;
190	rswitch->start_entry = alloc_rsp.entry;
191
192	ret = rvu_switch_install_rules(rvu);
193	if (ret)
194		goto uninstall_rules;
195
196	return;
197
198uninstall_rules:
199	uninstall_req.start = rswitch->start_entry;
200	uninstall_req.end =  rswitch->start_entry + rswitch->used_entries - 1;
201	rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
202	kfree(rswitch->entry2pcifunc);
203free_entries:
204	free_req.all = 1;
205	rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
206exit:
207	return;
208}
209
210void rvu_switch_disable(struct rvu *rvu)
211{
212	struct npc_delete_flow_req uninstall_req = { 0 };
213	struct npc_delete_flow_rsp uninstall_rsp = { 0 };
214	struct npc_mcam_free_entry_req free_req = { 0 };
215	struct rvu_switch *rswitch = &rvu->rswitch;
216	struct rvu_hwinfo *hw = rvu->hw;
217	int pf, vf, numvfs;
218	struct msg_rsp rsp;
219	u16 pcifunc;
220	int err;
221
222	if (!rswitch->used_entries)
223		return;
224
225	for (pf = 1; pf < hw->total_pfs; pf++) {
226		if (!is_pf_cgxmapped(rvu, pf))
227			continue;
228
229		pcifunc = pf << 10;
230		err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
231		if (err)
232			dev_err(rvu->dev,
233				"Reverting RX rule for PF%d failed(%d)\n",
234				pf, err);
235
236		/* Disable LBK link */
237		rvu_switch_enable_lbk_link(rvu, pcifunc, false);
238
239		rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
240		for (vf = 0; vf < numvfs; vf++) {
241			pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
242			err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
243			if (err)
244				dev_err(rvu->dev,
245					"Reverting RX rule for PF%dVF%d failed(%d)\n",
246					pf, vf, err);
247
248			rvu_switch_enable_lbk_link(rvu, pcifunc, false);
249		}
250	}
251
252	uninstall_req.start = rswitch->start_entry;
253	uninstall_req.end =  rswitch->start_entry + rswitch->used_entries - 1;
254	free_req.all = 1;
255	rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
256	rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
257	rswitch->used_entries = 0;
258	kfree(rswitch->entry2pcifunc);
259}
260
261void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc)
262{
263	struct rvu_switch *rswitch = &rvu->rswitch;
264	u32 max = rswitch->used_entries;
265	u16 entry;
266
267	if (!rswitch->used_entries)
268		return;
269
270	for (entry = 0; entry < max; entry++) {
271		if (rswitch->entry2pcifunc[entry] == pcifunc)
272			break;
273	}
274
275	if (entry >= max)
276		return;
277
278	rvu_switch_install_tx_rule(rvu, pcifunc, rswitch->start_entry + entry);
279	rvu_switch_install_rx_rule(rvu, pcifunc, 0x0);
280}
281