1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2019 Netronome Systems, Inc. */
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>
10 #include "nfpcore/nfp_cpp.h"
13 #include "nfp_net_ctrl.h"
15 #include "nfp_net_sriov.h"
18 nfp_net_sriov_check(struct nfp_app
*app
, int vf
, u16 cap
, const char *msg
)
22 if (!app
|| !app
->pf
->vfcfg_tbl2
)
25 cap_vf
= readw(app
->pf
->vfcfg_tbl2
+ NFP_NET_VF_CFG_MB_CAP
);
26 if ((cap_vf
& cap
) != cap
) {
27 nfp_warn(app
->pf
->cpp
, "ndo_set_vf_%s not supported\n", msg
);
31 if (vf
< 0 || vf
>= app
->pf
->num_vfs
) {
32 nfp_warn(app
->pf
->cpp
, "invalid VF id %d\n", vf
);
40 nfp_net_sriov_update(struct nfp_app
*app
, int vf
, u16 update
, const char *msg
)
45 /* Write update info to mailbox in VF config symbol */
46 writeb(vf
, app
->pf
->vfcfg_tbl2
+ NFP_NET_VF_CFG_MB_VF_NUM
);
47 writew(update
, app
->pf
->vfcfg_tbl2
+ NFP_NET_VF_CFG_MB_UPD
);
49 nn
= list_first_entry(&app
->pf
->vnics
, struct nfp_net
, vnic_list
);
50 /* Signal VF reconfiguration */
51 ret
= nfp_net_reconfig(nn
, NFP_NET_CFG_UPDATE_VF
);
55 ret
= readw(app
->pf
->vfcfg_tbl2
+ NFP_NET_VF_CFG_MB_RET
);
57 nfp_warn(app
->pf
->cpp
,
58 "FW refused VF %s update with errno: %d\n", msg
, ret
);
62 int nfp_app_set_vf_mac(struct net_device
*netdev
, int vf
, u8
*mac
)
64 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
65 unsigned int vf_offset
;
68 err
= nfp_net_sriov_check(app
, vf
, NFP_NET_VF_CFG_MB_CAP_MAC
, "mac");
72 if (is_multicast_ether_addr(mac
)) {
73 nfp_warn(app
->pf
->cpp
,
74 "invalid Ethernet address %pM for VF id %d\n",
79 /* Write MAC to VF entry in VF config symbol */
80 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
;
81 writel(get_unaligned_be32(mac
), app
->pf
->vfcfg_tbl2
+ vf_offset
);
82 writew(get_unaligned_be16(mac
+ 4),
83 app
->pf
->vfcfg_tbl2
+ vf_offset
+ NFP_NET_VF_CFG_MAC_LO
);
85 err
= nfp_net_sriov_update(app
, vf
, NFP_NET_VF_CFG_MB_UPD_MAC
, "MAC");
87 nfp_info(app
->pf
->cpp
,
88 "MAC %pM set on VF %d, reload the VF driver to make this change effective.\n",
94 int nfp_app_set_vf_vlan(struct net_device
*netdev
, int vf
, u16 vlan
, u8 qos
,
97 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
98 unsigned int vf_offset
;
102 err
= nfp_net_sriov_check(app
, vf
, NFP_NET_VF_CFG_MB_CAP_VLAN
, "vlan");
106 if (vlan_proto
!= htons(ETH_P_8021Q
))
109 if (vlan
> 4095 || qos
> 7) {
110 nfp_warn(app
->pf
->cpp
,
111 "invalid vlan id or qos for VF id %d\n", vf
);
115 /* Write VLAN tag to VF entry in VF config symbol */
116 vlan_tci
= FIELD_PREP(NFP_NET_VF_CFG_VLAN_VID
, vlan
) |
117 FIELD_PREP(NFP_NET_VF_CFG_VLAN_QOS
, qos
);
118 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
;
119 writew(vlan_tci
, app
->pf
->vfcfg_tbl2
+ vf_offset
+ NFP_NET_VF_CFG_VLAN
);
121 return nfp_net_sriov_update(app
, vf
, NFP_NET_VF_CFG_MB_UPD_VLAN
,
125 int nfp_app_set_vf_spoofchk(struct net_device
*netdev
, int vf
, bool enable
)
127 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
128 unsigned int vf_offset
;
132 err
= nfp_net_sriov_check(app
, vf
, NFP_NET_VF_CFG_MB_CAP_SPOOF
,
137 /* Write spoof check control bit to VF entry in VF config symbol */
138 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
+
140 vf_ctrl
= readb(app
->pf
->vfcfg_tbl2
+ vf_offset
);
141 vf_ctrl
&= ~NFP_NET_VF_CFG_CTRL_SPOOF
;
142 vf_ctrl
|= FIELD_PREP(NFP_NET_VF_CFG_CTRL_SPOOF
, enable
);
143 writeb(vf_ctrl
, app
->pf
->vfcfg_tbl2
+ vf_offset
);
145 return nfp_net_sriov_update(app
, vf
, NFP_NET_VF_CFG_MB_UPD_SPOOF
,
149 int nfp_app_set_vf_trust(struct net_device
*netdev
, int vf
, bool enable
)
151 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
152 unsigned int vf_offset
;
156 err
= nfp_net_sriov_check(app
, vf
, NFP_NET_VF_CFG_MB_CAP_TRUST
,
161 /* Write trust control bit to VF entry in VF config symbol */
162 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
+
164 vf_ctrl
= readb(app
->pf
->vfcfg_tbl2
+ vf_offset
);
165 vf_ctrl
&= ~NFP_NET_VF_CFG_CTRL_TRUST
;
166 vf_ctrl
|= FIELD_PREP(NFP_NET_VF_CFG_CTRL_TRUST
, enable
);
167 writeb(vf_ctrl
, app
->pf
->vfcfg_tbl2
+ vf_offset
);
169 return nfp_net_sriov_update(app
, vf
, NFP_NET_VF_CFG_MB_UPD_TRUST
,
173 int nfp_app_set_vf_link_state(struct net_device
*netdev
, int vf
,
176 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
177 unsigned int vf_offset
;
181 err
= nfp_net_sriov_check(app
, vf
, NFP_NET_VF_CFG_MB_CAP_LINK_STATE
,
186 switch (link_state
) {
187 case IFLA_VF_LINK_STATE_AUTO
:
188 case IFLA_VF_LINK_STATE_ENABLE
:
189 case IFLA_VF_LINK_STATE_DISABLE
:
195 /* Write link state to VF entry in VF config symbol */
196 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
+
198 vf_ctrl
= readb(app
->pf
->vfcfg_tbl2
+ vf_offset
);
199 vf_ctrl
&= ~NFP_NET_VF_CFG_CTRL_LINK_STATE
;
200 vf_ctrl
|= FIELD_PREP(NFP_NET_VF_CFG_CTRL_LINK_STATE
, link_state
);
201 writeb(vf_ctrl
, app
->pf
->vfcfg_tbl2
+ vf_offset
);
203 return nfp_net_sriov_update(app
, vf
, NFP_NET_VF_CFG_MB_UPD_LINK_STATE
,
207 int nfp_app_get_vf_config(struct net_device
*netdev
, int vf
,
208 struct ifla_vf_info
*ivi
)
210 struct nfp_app
*app
= nfp_app_from_netdev(netdev
);
211 unsigned int vf_offset
;
218 err
= nfp_net_sriov_check(app
, vf
, 0, "");
222 vf_offset
= NFP_NET_VF_CFG_MB_SZ
+ vf
* NFP_NET_VF_CFG_SZ
;
224 mac_hi
= readl(app
->pf
->vfcfg_tbl2
+ vf_offset
);
225 mac_lo
= readw(app
->pf
->vfcfg_tbl2
+ vf_offset
+ NFP_NET_VF_CFG_MAC_LO
);
227 flags
= readb(app
->pf
->vfcfg_tbl2
+ vf_offset
+ NFP_NET_VF_CFG_CTRL
);
228 vlan_tci
= readw(app
->pf
->vfcfg_tbl2
+ vf_offset
+ NFP_NET_VF_CFG_VLAN
);
230 memset(ivi
, 0, sizeof(*ivi
));
233 put_unaligned_be32(mac_hi
, &ivi
->mac
[0]);
234 put_unaligned_be16(mac_lo
, &ivi
->mac
[4]);
236 ivi
->vlan
= FIELD_GET(NFP_NET_VF_CFG_VLAN_VID
, vlan_tci
);
237 ivi
->qos
= FIELD_GET(NFP_NET_VF_CFG_VLAN_QOS
, vlan_tci
);
239 ivi
->spoofchk
= FIELD_GET(NFP_NET_VF_CFG_CTRL_SPOOF
, flags
);
240 ivi
->trusted
= FIELD_GET(NFP_NET_VF_CFG_CTRL_TRUST
, flags
);
241 ivi
->linkstate
= FIELD_GET(NFP_NET_VF_CFG_CTRL_LINK_STATE
, flags
);