1 /* 2 * Copyright (C) 2017 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include <linux/bitfield.h> 35 #include <linux/errno.h> 36 #include <linux/etherdevice.h> 37 #include <linux/if_link.h> 38 #include <linux/if_ether.h> 39 40 #include "nfpcore/nfp_cpp.h" 41 #include "nfp_app.h" 42 #include "nfp_main.h" 43 #include "nfp_net_ctrl.h" 44 #include "nfp_net.h" 45 #include "nfp_net_sriov.h" 46 47 static int 48 nfp_net_sriov_check(struct nfp_app *app, int vf, u16 cap, const char *msg) 49 { 50 u16 cap_vf; 51 52 if (!app || !app->pf->vfcfg_tbl2) 53 return -EOPNOTSUPP; 54 55 cap_vf = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_CAP); 56 if ((cap_vf & cap) != cap) { 57 nfp_warn(app->pf->cpp, "ndo_set_vf_%s not supported\n", msg); 58 return -EOPNOTSUPP; 59 } 60 61 if (vf < 0 || vf >= app->pf->num_vfs) { 62 nfp_warn(app->pf->cpp, "invalid VF id %d\n", vf); 63 return -EINVAL; 64 } 65 66 return 0; 67 } 68 69 static int 70 nfp_net_sriov_update(struct nfp_app *app, int vf, u16 update, const char *msg) 71 { 72 struct nfp_net *nn; 73 int ret; 74 75 /* Write update info to mailbox in VF config symbol */ 76 writeb(vf, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_VF_NUM); 77 writew(update, app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_UPD); 78 79 nn = list_first_entry(&app->pf->vnics, struct nfp_net, vnic_list); 80 /* Signal VF reconfiguration */ 81 ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_VF); 82 if (ret) 83 return ret; 84 85 ret = readw(app->pf->vfcfg_tbl2 + NFP_NET_VF_CFG_MB_RET); 86 if (ret) 87 nfp_warn(app->pf->cpp, 88 "FW refused VF %s update with errno: %d\n", msg, ret); 89 return -ret; 90 } 91 92 int nfp_app_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) 93 { 94 struct nfp_app *app = nfp_app_from_netdev(netdev); 95 unsigned int vf_offset; 96 int err; 97 98 err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_MAC, "mac"); 99 if (err) 100 return err; 101 102 if (is_multicast_ether_addr(mac)) { 103 nfp_warn(app->pf->cpp, 104 "invalid Ethernet address %pM for VF id %d\n", 105 mac, vf); 106 return -EINVAL; 107 } 108 109 /* Write MAC to VF entry in VF config symbol */ 110 vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ; 111 writel(get_unaligned_be32(mac), app->pf->vfcfg_tbl2 + vf_offset); 112 writew(get_unaligned_be16(mac + 4), 113 app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO); 114 115 err = nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_MAC, "MAC"); 116 if (!err) 117 nfp_info(app->pf->cpp, 118 "MAC %pM set on VF %d, reload the VF driver to make this change effective.\n", 119 mac, vf); 120 121 return err; 122 } 123 124 int nfp_app_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos, 125 __be16 vlan_proto) 126 { 127 struct nfp_app *app = nfp_app_from_netdev(netdev); 128 unsigned int vf_offset; 129 u16 vlan_tci; 130 int err; 131 132 err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_VLAN, "vlan"); 133 if (err) 134 return err; 135 136 if (vlan_proto != htons(ETH_P_8021Q)) 137 return -EOPNOTSUPP; 138 139 if (vlan > 4095 || qos > 7) { 140 nfp_warn(app->pf->cpp, 141 "invalid vlan id or qos for VF id %d\n", vf); 142 return -EINVAL; 143 } 144 145 /* Write VLAN tag to VF entry in VF config symbol */ 146 vlan_tci = FIELD_PREP(NFP_NET_VF_CFG_VLAN_VID, vlan) | 147 FIELD_PREP(NFP_NET_VF_CFG_VLAN_QOS, qos); 148 vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ; 149 writew(vlan_tci, app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN); 150 151 return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_VLAN, 152 "vlan"); 153 } 154 155 int nfp_app_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable) 156 { 157 struct nfp_app *app = nfp_app_from_netdev(netdev); 158 unsigned int vf_offset; 159 u8 vf_ctrl; 160 int err; 161 162 err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_SPOOF, 163 "spoofchk"); 164 if (err) 165 return err; 166 167 /* Write spoof check control bit to VF entry in VF config symbol */ 168 vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ + 169 NFP_NET_VF_CFG_CTRL; 170 vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset); 171 vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_SPOOF; 172 vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_SPOOF, enable); 173 writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset); 174 175 return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_SPOOF, 176 "spoofchk"); 177 } 178 179 int nfp_app_set_vf_link_state(struct net_device *netdev, int vf, 180 int link_state) 181 { 182 struct nfp_app *app = nfp_app_from_netdev(netdev); 183 unsigned int vf_offset; 184 u8 vf_ctrl; 185 int err; 186 187 err = nfp_net_sriov_check(app, vf, NFP_NET_VF_CFG_MB_CAP_LINK_STATE, 188 "link_state"); 189 if (err) 190 return err; 191 192 switch (link_state) { 193 case IFLA_VF_LINK_STATE_AUTO: 194 case IFLA_VF_LINK_STATE_ENABLE: 195 case IFLA_VF_LINK_STATE_DISABLE: 196 break; 197 default: 198 return -EINVAL; 199 } 200 201 /* Write link state to VF entry in VF config symbol */ 202 vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ + 203 NFP_NET_VF_CFG_CTRL; 204 vf_ctrl = readb(app->pf->vfcfg_tbl2 + vf_offset); 205 vf_ctrl &= ~NFP_NET_VF_CFG_CTRL_LINK_STATE; 206 vf_ctrl |= FIELD_PREP(NFP_NET_VF_CFG_CTRL_LINK_STATE, link_state); 207 writeb(vf_ctrl, app->pf->vfcfg_tbl2 + vf_offset); 208 209 return nfp_net_sriov_update(app, vf, NFP_NET_VF_CFG_MB_UPD_LINK_STATE, 210 "link state"); 211 } 212 213 int nfp_app_get_vf_config(struct net_device *netdev, int vf, 214 struct ifla_vf_info *ivi) 215 { 216 struct nfp_app *app = nfp_app_from_netdev(netdev); 217 unsigned int vf_offset; 218 u16 vlan_tci; 219 u32 mac_hi; 220 u16 mac_lo; 221 u8 flags; 222 int err; 223 224 err = nfp_net_sriov_check(app, vf, 0, ""); 225 if (err) 226 return err; 227 228 vf_offset = NFP_NET_VF_CFG_MB_SZ + vf * NFP_NET_VF_CFG_SZ; 229 230 mac_hi = readl(app->pf->vfcfg_tbl2 + vf_offset); 231 mac_lo = readw(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_MAC_LO); 232 233 flags = readb(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_CTRL); 234 vlan_tci = readw(app->pf->vfcfg_tbl2 + vf_offset + NFP_NET_VF_CFG_VLAN); 235 236 memset(ivi, 0, sizeof(*ivi)); 237 ivi->vf = vf; 238 239 put_unaligned_be32(mac_hi, &ivi->mac[0]); 240 put_unaligned_be16(mac_lo, &ivi->mac[4]); 241 242 ivi->vlan = FIELD_GET(NFP_NET_VF_CFG_VLAN_VID, vlan_tci); 243 ivi->qos = FIELD_GET(NFP_NET_VF_CFG_VLAN_QOS, vlan_tci); 244 245 ivi->spoofchk = FIELD_GET(NFP_NET_VF_CFG_CTRL_SPOOF, flags); 246 ivi->linkstate = FIELD_GET(NFP_NET_VF_CFG_CTRL_LINK_STATE, flags); 247 248 return 0; 249 } 250