312 lines · c
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 int18nfp_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 int42nfp_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 in135 * such circumstances setting the TPID has no meaning when136 * 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