xref: /linux/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
24ef6cbe8SPablo Cascón /* Copyright (C) 2017-2019 Netronome Systems, Inc. */
325528d90SPablo Cascón 
425528d90SPablo Cascón #include <linux/bitfield.h>
525528d90SPablo Cascón #include <linux/errno.h>
625528d90SPablo Cascón #include <linux/etherdevice.h>
725528d90SPablo Cascón #include <linux/if_link.h>
825528d90SPablo Cascón #include <linux/if_ether.h>
925528d90SPablo Cascón 
1025528d90SPablo Cascón #include "nfpcore/nfp_cpp.h"
1125528d90SPablo Cascón #include "nfp_app.h"
1225528d90SPablo Cascón #include "nfp_main.h"
1325528d90SPablo Cascón #include "nfp_net_ctrl.h"
1425528d90SPablo Cascón #include "nfp_net.h"
1525528d90SPablo Cascón #include "nfp_net_sriov.h"
1625528d90SPablo Cascón 
1725528d90SPablo Cascón static int
nfp_net_sriov_check(struct nfp_app * app,int vf,u16 cap,const char * msg,bool warn)18*03d5005fSFei Qin nfp_net_sriov_check(struct nfp_app *app, int vf, u16 cap, const char *msg, bool warn)
1925528d90SPablo Cascón {
2025528d90SPablo Cascón 	u16 cap_vf;
2125528d90SPablo Cascón 
2225528d90SPablo Cascón 	if (!app || !app->pf->vfcfg_tbl2)
2325528d90SPablo Cascón 		return -EOPNOTSUPP;
2425528d90SPablo Cascón 
2525528d90SPablo Cascón 	cap_vf = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_CAP);
2625528d90SPablo Cascón 	if ((cap_vf & cap) != cap) {
27*03d5005fSFei Qin 		if (warn)
2825528d90SPablo Cascón 			nfp_warn(app->pf->cpp, "ndo_set_vf_%s not supported\n", msg);
2925528d90SPablo Cascón 		return -EOPNOTSUPP;
3025528d90SPablo Cascón 	}
3125528d90SPablo Cascón 
3225528d90SPablo Cascón 	if (vf < 0 || vf >= app->pf->num_vfs) {
33*03d5005fSFei Qin 		if (warn)
3425528d90SPablo Cascón 			nfp_warn(app->pf->cpp, "invalid VF id %d\n", vf);
3525528d90SPablo Cascón 		return -EINVAL;
3625528d90SPablo Cascón 	}
3725528d90SPablo Cascón 
3825528d90SPablo Cascón 	return 0;
3925528d90SPablo Cascón }
4025528d90SPablo Cascón 
4125528d90SPablo Cascón static int
nfp_net_sriov_update(struct nfp_app * app,int vf,u16 update,const char * msg)4225528d90SPablo Cascón nfp_net_sriov_update(struct nfp_app *app, int vf, u16 update, const char *msg)
4325528d90SPablo Cascón {
4425528d90SPablo Cascón 	struct nfp_net *nn;
4525528d90SPablo Cascón 	int ret;
4625528d90SPablo Cascón 
4725528d90SPablo Cascón 	/* Write update info to mailbox in VF config symbol */
4825528d90SPablo Cascón 	writeb(vf, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_VF_NUM);
4925528d90SPablo Cascón 	writew(update, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_UPD);
5025528d90SPablo Cascón 
5125528d90SPablo Cascón 	nn = list_first_entry(&app->pf->vnics, struct nfp_net, vnic_list);
5225528d90SPablo Cascón 	/* Signal VF reconfiguration */
5325528d90SPablo Cascón 	ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_VF);
5425528d90SPablo Cascón 	if (ret)
5525528d90SPablo Cascón 		return ret;
5625528d90SPablo Cascón 
5725528d90SPablo Cascón 	ret = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_RET);
5825528d90SPablo Cascón 	if (ret)
5925528d90SPablo Cascón 		nfp_warn(app->pf->cpp,
6025528d90SPablo Cascón 			 "FW refused VF %s update with errno: %d\n", msg, ret);
6125528d90SPablo Cascón 	return -ret;
6225528d90SPablo Cascón }
6325528d90SPablo Cascón 
nfp_app_set_vf_mac(struct net_device * netdev,int vf,u8 * mac)6425528d90SPablo Cascón int nfp_app_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
6525528d90SPablo Cascón {
6625528d90SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
6725528d90SPablo Cascón 	unsigned int vf_offset;
6825528d90SPablo Cascón 	int err;
6925528d90SPablo Cascón 
70*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_MAC, "mac", true);
7125528d90SPablo Cascón 	if (err)
7225528d90SPablo Cascón 		return err;
7325528d90SPablo Cascón 
7425528d90SPablo Cascón 	if (is_multicast_ether_addr(mac)) {
7525528d90SPablo Cascón 		nfp_warn(app->pf->cpp,
7625528d90SPablo Cascón 			 "invalid Ethernet address %pM for VF id %d\n",
7725528d90SPablo Cascón 			 mac, vf);
7825528d90SPablo Cascón 		return -EINVAL;
7925528d90SPablo Cascón 	}
8025528d90SPablo Cascón 
8125528d90SPablo Cascón 	/* Write MAC to VF entry in VF config symbol */
8225528d90SPablo Cascón 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
8325528d90SPablo Cascón 	writel(get_unaligned_be32(mac), app->pf->vfcfg_tbl2 + vf_offset);
8425528d90SPablo Cascón 	writew(get_unaligned_be16(mac + 4),
8525528d90SPablo Cascón 	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);
8625528d90SPablo Cascón 
87a267eaebSPablo Cascón 	err = nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_MAC, "MAC");
88a267eaebSPablo Cascón 	if (!err)
89a267eaebSPablo Cascón 		nfp_info(app->pf->cpp,
90a267eaebSPablo Cascón 			 "MAC %pM set on VF %d, reload the VF driver to make this change effective.\n",
91a267eaebSPablo Cascón 			 mac, vf);
92a267eaebSPablo Cascón 
93a267eaebSPablo Cascón 	return err;
9425528d90SPablo Cascón }
9525528d90SPablo Cascón 
nfp_app_set_vf_vlan(struct net_device * netdev,int vf,u16 vlan,u8 qos,__be16 vlan_proto)9625528d90SPablo Cascón int nfp_app_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
9725528d90SPablo Cascón 			__be16 vlan_proto)
9825528d90SPablo Cascón {
9925528d90SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
10059359597SBaowen Zheng 	u16 update = NFP_NET_VF_CFG_MB_UPD_VLAN;
10159359597SBaowen Zheng 	bool is_proto_sup = true;
10225528d90SPablo Cascón 	unsigned int vf_offset;
10359359597SBaowen Zheng 	u32 vlan_tag;
10425528d90SPablo Cascón 	int err;
10525528d90SPablo Cascón 
106*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN, "vlan", true);
10725528d90SPablo Cascón 	if (err)
10825528d90SPablo Cascón 		return err;
10925528d90SPablo Cascón 
11059359597SBaowen Zheng 	if (!eth_type_vlan(vlan_proto))
11125528d90SPablo Cascón 		return -EOPNOTSUPP;
11225528d90SPablo Cascón 
11325528d90SPablo Cascón 	if (vlan > 4095 || qos > 7) {
11425528d90SPablo Cascón 		nfp_warn(app->pf->cpp,
11525528d90SPablo Cascón 			 "invalid vlan id or qos for VF id %d\n", vf);
11625528d90SPablo Cascón 		return -EINVAL;
11725528d90SPablo Cascón 	}
11825528d90SPablo Cascón 
11959359597SBaowen Zheng 	/* Check if fw supports or not */
120*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", true);
12159359597SBaowen Zheng 	if (err)
12259359597SBaowen Zheng 		is_proto_sup = false;
12325528d90SPablo Cascón 
12459359597SBaowen Zheng 	if (vlan_proto != htons(ETH_P_8021Q)) {
12559359597SBaowen Zheng 		if (!is_proto_sup)
12659359597SBaowen Zheng 			return -EOPNOTSUPP;
12759359597SBaowen Zheng 		update |= NFP_NET_VF_CFG_MB_UPD_VLAN_PROTO;
12859359597SBaowen Zheng 	}
12959359597SBaowen Zheng 
13059359597SBaowen Zheng 	/* Write VLAN tag to VF entry in VF config symbol */
13159359597SBaowen Zheng 	vlan_tag = FIELD_PREP(NFP_NET_VF_CFG_VLAN_VID, vlan) |
13259359597SBaowen Zheng 		FIELD_PREP(NFP_NET_VF_CFG_VLAN_QOS, qos);
13359359597SBaowen Zheng 
13459359597SBaowen Zheng 	/* vlan_tag of 0 means that the configuration should be cleared and in
13559359597SBaowen Zheng 	 * such circumstances setting the TPID has no meaning when
13659359597SBaowen Zheng 	 * configuring firmware.
13759359597SBaowen Zheng 	 */
13859359597SBaowen Zheng 	if (vlan_tag && is_proto_sup)
13959359597SBaowen Zheng 		vlan_tag |= FIELD_PREP(NFP_NET_VF_CFG_VLAN_PROT, ntohs(vlan_proto));
14059359597SBaowen Zheng 
14159359597SBaowen Zheng 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
14259359597SBaowen Zheng 	writel(vlan_tag, app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);
14359359597SBaowen Zheng 
14459359597SBaowen Zheng 	return nfp_net_sriov_update(app, vf, update, "vlan");
14525528d90SPablo Cascón }
14625528d90SPablo Cascón 
nfp_app_set_vf_rate(struct net_device * netdev,int vf,int min_tx_rate,int max_tx_rate)147e0d0e1fdSBin Chen int nfp_app_set_vf_rate(struct net_device *netdev, int vf,
148e0d0e1fdSBin Chen 			int min_tx_rate, int max_tx_rate)
149e0d0e1fdSBin Chen {
150e0d0e1fdSBin Chen 	struct nfp_app *app = nfp_app_from_netdev(netdev);
151e0d0e1fdSBin Chen 	u32 vf_offset, ratevalue;
152e0d0e1fdSBin Chen 	int err;
153e0d0e1fdSBin Chen 
154*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", true);
155e0d0e1fdSBin Chen 	if (err)
156e0d0e1fdSBin Chen 		return err;
157e0d0e1fdSBin Chen 
158e0d0e1fdSBin Chen 	if (max_tx_rate >= NFP_NET_VF_RATE_MAX ||
159e0d0e1fdSBin Chen 	    min_tx_rate >= NFP_NET_VF_RATE_MAX) {
160e0d0e1fdSBin Chen 		nfp_warn(app->cpp, "tx-rate exceeds %d.\n",
161e0d0e1fdSBin Chen 			 NFP_NET_VF_RATE_MAX);
162e0d0e1fdSBin Chen 		return -EINVAL;
163e0d0e1fdSBin Chen 	}
164e0d0e1fdSBin Chen 
165e0d0e1fdSBin Chen 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
166e0d0e1fdSBin Chen 	ratevalue = FIELD_PREP(NFP_NET_VF_CFG_MAX_RATE,
167e0d0e1fdSBin Chen 			       max_tx_rate ? max_tx_rate :
168e0d0e1fdSBin Chen 			       NFP_NET_VF_RATE_MAX) |
169e0d0e1fdSBin Chen 		    FIELD_PREP(NFP_NET_VF_CFG_MIN_RATE, min_tx_rate);
170e0d0e1fdSBin Chen 
171e0d0e1fdSBin Chen 	writel(ratevalue,
172e0d0e1fdSBin Chen 	       app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_RATE);
173e0d0e1fdSBin Chen 
174e0d0e1fdSBin Chen 	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_RATE,
175e0d0e1fdSBin Chen 				    "rate");
176e0d0e1fdSBin Chen }
177e0d0e1fdSBin Chen 
nfp_app_set_vf_spoofchk(struct net_device * netdev,int vf,bool enable)17825528d90SPablo Cascón int nfp_app_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
17925528d90SPablo Cascón {
18025528d90SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
18125528d90SPablo Cascón 	unsigned int vf_offset;
18225528d90SPablo Cascón 	u8 vf_ctrl;
18325528d90SPablo Cascón 	int err;
18425528d90SPablo Cascón 
18525528d90SPablo Cascón 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_SPOOF,
186*03d5005fSFei Qin 				  "spoofchk", true);
18725528d90SPablo Cascón 	if (err)
18825528d90SPablo Cascón 		return err;
18925528d90SPablo Cascón 
19025528d90SPablo Cascón 	/* Write spoof check control bit to VF entry in VF config symbol */
19125528d90SPablo Cascón 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
19225528d90SPablo Cascón 		NFP_NET_VF_CFG_CTRL;
19325528d90SPablo Cascón 	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
19425528d90SPablo Cascón 	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_SPOOF;
19525528d90SPablo Cascón 	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_SPOOF, enable);
19625528d90SPablo Cascón 	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
19725528d90SPablo Cascón 
19825528d90SPablo Cascón 	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_SPOOF,
19925528d90SPablo Cascón 				    "spoofchk");
20025528d90SPablo Cascón }
20125528d90SPablo Cascón 
nfp_app_set_vf_trust(struct net_device * netdev,int vf,bool enable)2024ef6cbe8SPablo Cascón int nfp_app_set_vf_trust(struct net_device *netdev, int vf, bool enable)
2034ef6cbe8SPablo Cascón {
2044ef6cbe8SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
2054ef6cbe8SPablo Cascón 	unsigned int vf_offset;
2064ef6cbe8SPablo Cascón 	u8 vf_ctrl;
2074ef6cbe8SPablo Cascón 	int err;
2084ef6cbe8SPablo Cascón 
2094ef6cbe8SPablo Cascón 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_TRUST,
210*03d5005fSFei Qin 				  "trust", true);
2114ef6cbe8SPablo Cascón 	if (err)
2124ef6cbe8SPablo Cascón 		return err;
2134ef6cbe8SPablo Cascón 
2144ef6cbe8SPablo Cascón 	/* Write trust control bit to VF entry in VF config symbol */
2154ef6cbe8SPablo Cascón 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
2164ef6cbe8SPablo Cascón 		NFP_NET_VF_CFG_CTRL;
2174ef6cbe8SPablo Cascón 	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
2184ef6cbe8SPablo Cascón 	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_TRUST;
2194ef6cbe8SPablo Cascón 	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_TRUST, enable);
2204ef6cbe8SPablo Cascón 	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
2214ef6cbe8SPablo Cascón 
2224ef6cbe8SPablo Cascón 	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_TRUST,
2234ef6cbe8SPablo Cascón 				    "trust");
2244ef6cbe8SPablo Cascón }
2254ef6cbe8SPablo Cascón 
nfp_app_set_vf_link_state(struct net_device * netdev,int vf,int link_state)22625528d90SPablo Cascón int nfp_app_set_vf_link_state(struct net_device *netdev, int vf,
22725528d90SPablo Cascón 			      int link_state)
22825528d90SPablo Cascón {
22925528d90SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
23025528d90SPablo Cascón 	unsigned int vf_offset;
23125528d90SPablo Cascón 	u8 vf_ctrl;
23225528d90SPablo Cascón 	int err;
23325528d90SPablo Cascón 
23425528d90SPablo Cascón 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_LINK_STATE,
235*03d5005fSFei Qin 				  "link_state", true);
23625528d90SPablo Cascón 	if (err)
23725528d90SPablo Cascón 		return err;
23825528d90SPablo Cascón 
23925528d90SPablo Cascón 	switch (link_state) {
24025528d90SPablo Cascón 	case IFLA_VF_LINK_STATE_AUTO:
24125528d90SPablo Cascón 	case IFLA_VF_LINK_STATE_ENABLE:
24225528d90SPablo Cascón 	case IFLA_VF_LINK_STATE_DISABLE:
24325528d90SPablo Cascón 		break;
24425528d90SPablo Cascón 	default:
24525528d90SPablo Cascón 		return -EINVAL;
24625528d90SPablo Cascón 	}
24725528d90SPablo Cascón 
24825528d90SPablo Cascón 	/* Write link state to VF entry in VF config symbol */
24925528d90SPablo Cascón 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ +
25025528d90SPablo Cascón 		NFP_NET_VF_CFG_CTRL;
25125528d90SPablo Cascón 	vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset);
25225528d90SPablo Cascón 	vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_LINK_STATE;
25325528d90SPablo Cascón 	vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_LINK_STATE, link_state);
25425528d90SPablo Cascón 	writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset);
25525528d90SPablo Cascón 
25625528d90SPablo Cascón 	return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_LINK_STATE,
25725528d90SPablo Cascón 				    "link state");
25825528d90SPablo Cascón }
25925528d90SPablo Cascón 
nfp_app_get_vf_config(struct net_device * netdev,int vf,struct ifla_vf_info * ivi)26025528d90SPablo Cascón int nfp_app_get_vf_config(struct net_device *netdev, int vf,
26125528d90SPablo Cascón 			  struct ifla_vf_info *ivi)
26225528d90SPablo Cascón {
26325528d90SPablo Cascón 	struct nfp_app *app = nfp_app_from_netdev(netdev);
264e0d0e1fdSBin Chen 	u32 vf_offset, mac_hi, rate;
26559359597SBaowen Zheng 	u32 vlan_tag;
26625528d90SPablo Cascón 	u16 mac_lo;
26725528d90SPablo Cascón 	u8 flags;
26825528d90SPablo Cascón 	int err;
26925528d90SPablo Cascón 
270*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, 0, "", true);
27125528d90SPablo Cascón 	if (err)
27225528d90SPablo Cascón 		return err;
27325528d90SPablo Cascón 
27425528d90SPablo Cascón 	vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ;
27525528d90SPablo Cascón 
27625528d90SPablo Cascón 	mac_hi = readl(app->pf->vfcfg_tbl2 + vf_offset);
27725528d90SPablo Cascón 	mac_lo = readw(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO);
27825528d90SPablo Cascón 
27925528d90SPablo Cascón 	flags = readb(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_CTRL);
28059359597SBaowen Zheng 	vlan_tag = readl(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN);
28125528d90SPablo Cascón 
28225528d90SPablo Cascón 	memset(ivi, 0, sizeof(*ivi));
28325528d90SPablo Cascón 	ivi->vf = vf;
28425528d90SPablo Cascón 
28525528d90SPablo Cascón 	put_unaligned_be32(mac_hi, &ivi->mac[0]);
28625528d90SPablo Cascón 	put_unaligned_be16(mac_lo, &ivi->mac[4]);
28725528d90SPablo Cascón 
28859359597SBaowen Zheng 	ivi->vlan = FIELD_GET(NFP_NET_VF_CFG_VLAN_VID, vlan_tag);
28959359597SBaowen Zheng 	ivi->qos = FIELD_GET(NFP_NET_VF_CFG_VLAN_QOS, vlan_tag);
290*03d5005fSFei Qin 	if (!nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN_PROTO, "vlan_proto", false))
29159359597SBaowen Zheng 		ivi->vlan_proto = htons(FIELD_GET(NFP_NET_VF_CFG_VLAN_PROT, vlan_tag));
29225528d90SPablo Cascón 	ivi->spoofchk = FIELD_GET(NFP_NET_VF_CFG_CTRL_SPOOF, flags);
2934ef6cbe8SPablo Cascón 	ivi->trusted = FIELD_GET(NFP_NET_VF_CFG_CTRL_TRUST, flags);
29425528d90SPablo Cascón 	ivi->linkstate = FIELD_GET(NFP_NET_VF_CFG_CTRL_LINK_STATE, flags);
29525528d90SPablo Cascón 
296*03d5005fSFei Qin 	err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_RATE, "rate", false);
297e0d0e1fdSBin Chen 	if (!err) {
298e0d0e1fdSBin Chen 		rate = readl(app->pf->vfcfg_tbl2 + vf_offset +
299e0d0e1fdSBin Chen 			     NFP_NET_VF_CFG_RATE);
300e0d0e1fdSBin Chen 
301e0d0e1fdSBin Chen 		ivi->max_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MAX_RATE, rate);
302e0d0e1fdSBin Chen 		ivi->min_tx_rate = FIELD_GET(NFP_NET_VF_CFG_MIN_RATE, rate);
303e0d0e1fdSBin Chen 
304e0d0e1fdSBin Chen 		if (ivi->max_tx_rate == NFP_NET_VF_RATE_MAX)
305e0d0e1fdSBin Chen 			ivi->max_tx_rate = 0;
306e0d0e1fdSBin Chen 		if (ivi->min_tx_rate == NFP_NET_VF_RATE_MAX)
307e0d0e1fdSBin Chen 			ivi->min_tx_rate = 0;
308e0d0e1fdSBin Chen 	}
309e0d0e1fdSBin Chen 
31025528d90SPablo Cascón 	return 0;
31125528d90SPablo Cascón }
312