1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2017-2019 Netronome Systems, Inc. */
3
4#include <linux/bitfield.h>
5#include <linux/errno.h>
6#include <linux/etherdevice.h>
7#include <linux/if_link.h>
8#include <linux/if_ether.h>
9
10#include "nfpcore/nfp_cpp.h"
11#include "nfp_app.h"
12#include "nfp_main.h"
13#include "nfp_net_ctrl.h"
14#include "nfp_net.h"
15#include "nfp_net_sriov.h"
16
17static int
18nfp_net_sriov_check(struct nfp_app *app, int vf, u16 cap, const char *msg, bool warn)
19{
20	u16 cap_vf;
21
22	if (!app || !app->pf->vfcfg_tbl2)
23		return -EOPNOTSUPP;
24
25	cap_vf = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_CAP);
26	if ((cap_vf & cap) != cap) {
27		if (warn)
28			nfp_warn(app->pf->cpp, "ndo_set_vf_%s not supported\n", msg);
29		return -EOPNOTSUPP;
30	}
31
32	if (vf < 0 || vf >= app->pf->num_vfs) {
33		if (warn)
34			nfp_warn(app->pf->cpp, "invalid VF id %d\n", vf);
35		return -EINVAL;
36	}
37
38	return 0;
39}
40
41static int
42nfp_net_sriov_update(struct nfp_app *app, int vf, u16 update, const char *msg)
43{
44	struct nfp_net *nn;
45	int ret;
46
47	/* Write update info to mailbox in VF config symbol */
48	writeb(vf, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_VF_NUM);
49	writew(update, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_UPD);
50
51	nn = list_first_entry(&app->pf->vnics, struct nfp_net, vnic_list);
52	/* Signal VF reconfiguration */
53	ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_VF);
54	if (ret)
55		return ret;
56
57	ret = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_RET);
58	if (ret)
59		nfp_warn(app->pf->cpp,
60			 "FW refused VF %s update with errno: %d\n", msg, ret);
61	return -ret;
62}
63
64int nfp_app_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
65{
66	struct nfp_app *app = nfp_app_from_netdev(netdev);
67	unsigned int vf_offset;
68	int err;
69
70	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_MAC, "mac", true);
71	if (err)
72		return err;
73
74	if (is_multicast_ether_addr(mac)) {
75		nfp_warn(app->pf->cpp,
76			 "invalid Ethernet address %pM for VF id %d\n",
77			 mac, vf);
78		return -EINVAL;
79	}
80
81	/* Write MAC to VF entry in VF config symbol */
82	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
83	writel(get_unaligned_be32(mac), app->pf->vfcfg_tbl2 + vf_offset);
84	writew(get_unaligned_be16(mac + 4),
85	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);
86
87	err = nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_MAC, "MAC");
88	if (!err)
89		nfp_info(app->pf->cpp,
90			 "MAC %pM set on VF %d, reload the VF driver to make this change effective.\n",
91			 mac, vf);
92
93	return err;
94}
95
96int nfp_app_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
97			__be16 vlan_proto)
98{
99	struct nfp_app *app = nfp_app_from_netdev(netdev);
100	u16 update = NFP_NET_VF_CFG_MB_UPD_VLAN;
101	bool is_proto_sup = true;
102	unsigned int vf_offset;
103	u32 vlan_tag;
104	int err;
105
106	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN, "vlan", true);
107	if (err)
108		return err;
109
110	if (!eth_type_vlan(vlan_proto))
111		return -EOPNOTSUPP;
112
113	if (vlan > 4095 || qos > 7) {
114		nfp_warn(app->pf->cpp,
115			 "invalid vlan id or qos for VF id %d\n", vf);
116		return -EINVAL;
117	}
118
119	/* Check if fw supports or not */
120	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", true);
121	if (err)
122		is_proto_sup = false;
123
124	if (vlan_proto != htons(ETH_P_8021Q)) {
125		if (!is_proto_sup)
126			return -EOPNOTSUPP;
127		update |= NFP_NET_VF_CFG_MB_UPD_VLAN_PROTO;
128	}
129
130	/* Write VLAN tag to VF entry in VF config symbol */
131	vlan_tag = FIELD_PREP(NFP_NET_VF_CFG_VLAN_VID, vlan) |
132		FIELD_PREP(NFP_NET_VF_CFG_VLAN_QOS, qos);
133
134	/* vlan_tag of 0 means that the configuration should be cleared and in
135	 * such circumstances setting the TPID has no meaning when
136	 * configuring firmware.
137	 */
138	if (vlan_tag && is_proto_sup)
139		vlan_tag |= FIELD_PREP(NFP_NET_VF_CFG_VLAN_PROT, ntohs(vlan_proto));
140
141	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
142	writel(vlan_tag, app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);
143
144	return nfp_net_sriov_update(app, vf, update, "vlan");
145}
146
147int nfp_app_set_vf_rate(struct net_device *netdev, int vf,
148			int min_tx_rate, int max_tx_rate)
149{
150	struct nfp_app *app = nfp_app_from_netdev(netdev);
151	u32 vf_offset, ratevalue;
152	int err;
153
154	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", true);
155	if (err)
156		return err;
157
158	if (max_tx_rate >= NFP_NET_VF_RATE_MAX ||
159	    min_tx_rate >= NFP_NET_VF_RATE_MAX) {
160		nfp_warn(app->cpp, "tx-rate exceeds %d.\n",
161			 NFP_NET_VF_RATE_MAX);
162		return -EINVAL;
163	}
164
165	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
166	ratevalue = FIELD_PREP(NFP_NET_VF_CFG_MAX_RATE,
167			       max_tx_rate ? max_tx_rate :
168			       NFP_NET_VF_RATE_MAX) |
169		    FIELD_PREP(NFP_NET_VF_CFG_MIN_RATE, min_tx_rate);
170
171	writel(ratevalue,
172	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_RATE);
173
174	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_RATE,
175				    "rate");
176}
177
178int nfp_app_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
179{
180	struct nfp_app *app = nfp_app_from_netdev(netdev);
181	unsigned int vf_offset;
182	u8 vf_ctrl;
183	int err;
184
185	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_SPOOF,
186				  "spoofchk", true);
187	if (err)
188		return err;
189
190	/* Write spoof check control bit to VF entry in VF config symbol */
191	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
192		NFP_NET_VF_CFG_CTRL;
193	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
194	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_SPOOF;
195	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_SPOOF, enable);
196	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
197
198	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_SPOOF,
199				    "spoofchk");
200}
201
202int nfp_app_set_vf_trust(struct net_device *netdev, int vf, bool enable)
203{
204	struct nfp_app *app = nfp_app_from_netdev(netdev);
205	unsigned int vf_offset;
206	u8 vf_ctrl;
207	int err;
208
209	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_TRUST,
210				  "trust", true);
211	if (err)
212		return err;
213
214	/* Write trust control bit to VF entry in VF config symbol */
215	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
216		NFP_NET_VF_CFG_CTRL;
217	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
218	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_TRUST;
219	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_TRUST, enable);
220	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
221
222	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_TRUST,
223				    "trust");
224}
225
226int nfp_app_set_vf_link_state(struct net_device *netdev, int vf,
227			      int link_state)
228{
229	struct nfp_app *app = nfp_app_from_netdev(netdev);
230	unsigned int vf_offset;
231	u8 vf_ctrl;
232	int err;
233
234	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_LINK_STATE,
235				  "link_state", true);
236	if (err)
237		return err;
238
239	switch (link_state) {
240	case IFLA_VF_LINK_STATE_AUTO:
241	case IFLA_VF_LINK_STATE_ENABLE:
242	case IFLA_VF_LINK_STATE_DISABLE:
243		break;
244	default:
245		return -EINVAL;
246	}
247
248	/* Write link state to VF entry in VF config symbol */
249	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
250		NFP_NET_VF_CFG_CTRL;
251	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
252	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_LINK_STATE;
253	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_LINK_STATE, link_state);
254	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
255
256	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_LINK_STATE,
257				    "link state");
258}
259
260int nfp_app_get_vf_config(struct net_device *netdev, int vf,
261			  struct ifla_vf_info *ivi)
262{
263	struct nfp_app *app = nfp_app_from_netdev(netdev);
264	u32 vf_offset, mac_hi, rate;
265	u32 vlan_tag;
266	u16 mac_lo;
267	u8 flags;
268	int err;
269
270	err = nfp_net_sriov_check(app, vf, 0, "", true);
271	if (err)
272		return err;
273
274	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
275
276	mac_hi = readl(app->pf->vfcfg_tbl2 + vf_offset);
277	mac_lo = readw(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);
278
279	flags = readb(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_CTRL);
280	vlan_tag = readl(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);
281
282	memset(ivi, 0, sizeof(*ivi));
283	ivi->vf = vf;
284
285	put_unaligned_be32(mac_hi, &ivi->mac[0]);
286	put_unaligned_be16(mac_lo, &ivi->mac[4]);
287
288	ivi->vlan = FIELD_GET(NFP_NET_VF_CFG_VLAN_VID, vlan_tag);
289	ivi->qos = FIELD_GET(NFP_NET_VF_CFG_VLAN_QOS, vlan_tag);
290	if (!nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", false))
291		ivi->vlan_proto = htons(FIELD_GET(NFP_NET_VF_CFG_VLAN_PROT, vlan_tag));
292	ivi->spoofchk = FIELD_GET(NFP_NET_VF_CFG_CTRL_SPOOF, flags);
293	ivi->trusted = FIELD_GET(NFP_NET_VF_CFG_CTRL_TRUST, flags);
294	ivi->linkstate = FIELD_GET(NFP_NET_VF_CFG_CTRL_LINK_STATE, flags);
295
296	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", false);
297	if (!err) {
298		rate = readl(app->pf->vfcfg_tbl2 + vf_offset +
299			     NFP_NET_VF_CFG_RATE);
300
301		ivi->max_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MAX_RATE, rate);
302		ivi->min_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MIN_RATE, rate);
303
304		if (ivi->max_tx_rate == NFP_NET_VF_RATE_MAX)
305			ivi->max_tx_rate = 0;
306		if (ivi->min_tx_rate == NFP_NET_VF_RATE_MAX)
307			ivi->min_tx_rate = 0;
308	}
309
310	return 0;
311}
312