1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 /* 3 * Copyright (C) 2018 Netronome Systems, Inc. 4 * 5 * This software is dual licensed under the GNU General License Version 2, 6 * June 1991 as shown in the file COPYING in the top-level directory of this 7 * source tree or the BSD 2-Clause License provided below. You have the 8 * option to license this software under the complete terms of either license. 9 * 10 * The BSD 2-Clause License: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * 1. Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 35 #include <linux/bitfield.h> 36 #include <linux/etherdevice.h> 37 #include <linux/lockdep.h> 38 #include <linux/netdevice.h> 39 #include <linux/rcupdate.h> 40 #include <linux/slab.h> 41 42 #include "../nfpcore/nfp.h" 43 #include "../nfpcore/nfp_cpp.h" 44 #include "../nfpcore/nfp_nsp.h" 45 #include "../nfp_app.h" 46 #include "../nfp_main.h" 47 #include "../nfp_net.h" 48 #include "../nfp_net_repr.h" 49 #include "../nfp_port.h" 50 #include "main.h" 51 52 static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id) 53 { 54 return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) | 55 FIELD_PREP(NFP_ABM_PORTID_ID, id); 56 } 57 58 static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id) 59 { 60 enum nfp_repr_type rtype; 61 struct nfp_reprs *reprs; 62 u8 port; 63 64 rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id); 65 port = FIELD_GET(NFP_ABM_PORTID_ID, port_id); 66 67 reprs = rcu_dereference(app->reprs[rtype]); 68 if (!reprs) 69 return NULL; 70 71 if (port >= reprs->num_reprs) 72 return NULL; 73 74 return rcu_dereference(reprs->reprs[port]); 75 } 76 77 static int 78 nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink, 79 enum nfp_port_type ptype) 80 { 81 struct net_device *netdev; 82 enum nfp_repr_type rtype; 83 struct nfp_reprs *reprs; 84 struct nfp_repr *repr; 85 struct nfp_port *port; 86 int err; 87 88 if (ptype == NFP_PORT_PHYS_PORT) 89 rtype = NFP_REPR_TYPE_PHYS_PORT; 90 else 91 rtype = NFP_REPR_TYPE_PF; 92 93 netdev = nfp_repr_alloc(app); 94 if (!netdev) 95 return -ENOMEM; 96 repr = netdev_priv(netdev); 97 repr->app_priv = alink; 98 99 port = nfp_port_alloc(app, ptype, netdev); 100 if (IS_ERR(port)) { 101 err = PTR_ERR(port); 102 goto err_free_repr; 103 } 104 105 if (ptype == NFP_PORT_PHYS_PORT) { 106 port->eth_forced = true; 107 err = nfp_port_init_phy_port(app->pf, app, port, alink->id); 108 if (err) 109 goto err_free_port; 110 } else { 111 port->pf_id = alink->abm->pf_id; 112 port->pf_split = app->pf->max_data_vnics > 1; 113 port->pf_split_id = alink->id; 114 port->vnic = alink->vnic->dp.ctrl_bar; 115 } 116 117 SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev); 118 eth_hw_addr_random(netdev); 119 120 err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id), 121 port, alink->vnic->dp.netdev); 122 if (err) 123 goto err_free_port; 124 125 reprs = nfp_reprs_get_locked(app, rtype); 126 WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr"); 127 rcu_assign_pointer(reprs->reprs[alink->id], netdev); 128 129 nfp_info(app->cpp, "%s Port %d Representor(%s) created\n", 130 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys", 131 alink->id, netdev->name); 132 133 return 0; 134 135 err_free_port: 136 nfp_port_free(port); 137 err_free_repr: 138 nfp_repr_free(netdev); 139 return err; 140 } 141 142 static void 143 nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink, 144 enum nfp_repr_type rtype) 145 { 146 struct net_device *netdev; 147 struct nfp_reprs *reprs; 148 149 reprs = nfp_reprs_get_locked(app, rtype); 150 netdev = nfp_repr_get_locked(app, reprs, alink->id); 151 if (!netdev) 152 return; 153 rcu_assign_pointer(reprs->reprs[alink->id], NULL); 154 synchronize_rcu(); 155 /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */ 156 nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev)); 157 } 158 159 static void 160 nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink) 161 { 162 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF); 163 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT); 164 } 165 166 static void nfp_abm_kill_reprs_all(struct nfp_abm *abm) 167 { 168 struct nfp_pf *pf = abm->app->pf; 169 struct nfp_net *nn; 170 171 list_for_each_entry(nn, &pf->vnics, vnic_list) 172 nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv); 173 } 174 175 static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app) 176 { 177 struct nfp_abm *abm = app->priv; 178 179 return abm->eswitch_mode; 180 } 181 182 static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm) 183 { 184 nfp_abm_kill_reprs_all(abm); 185 186 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 187 return 0; 188 } 189 190 static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm) 191 { 192 if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY) 193 WARN_ON(nfp_abm_eswitch_set_legacy(abm)); 194 } 195 196 static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm) 197 { 198 struct nfp_app *app = abm->app; 199 struct nfp_pf *pf = app->pf; 200 struct nfp_net *nn; 201 int err; 202 203 list_for_each_entry(nn, &pf->vnics, vnic_list) { 204 struct nfp_abm_link *alink = nn->app_priv; 205 206 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT); 207 if (err) 208 goto err_kill_all_reprs; 209 210 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT); 211 if (err) 212 goto err_kill_all_reprs; 213 } 214 215 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 216 return 0; 217 218 err_kill_all_reprs: 219 nfp_abm_kill_reprs_all(abm); 220 return err; 221 } 222 223 static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode) 224 { 225 struct nfp_abm *abm = app->priv; 226 227 if (abm->eswitch_mode == mode) 228 return 0; 229 230 switch (mode) { 231 case DEVLINK_ESWITCH_MODE_LEGACY: 232 return nfp_abm_eswitch_set_legacy(abm); 233 case DEVLINK_ESWITCH_MODE_SWITCHDEV: 234 return nfp_abm_eswitch_set_switchdev(abm); 235 default: 236 return -EINVAL; 237 } 238 } 239 240 static void 241 nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn, 242 unsigned int id) 243 { 244 struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id]; 245 u8 mac_addr[ETH_ALEN]; 246 const char *mac_str; 247 char name[32]; 248 249 if (id > pf->eth_tbl->count) { 250 nfp_warn(pf->cpp, "No entry for persistent MAC address\n"); 251 eth_hw_addr_random(nn->dp.netdev); 252 return; 253 } 254 255 snprintf(name, sizeof(name), "eth%u.mac.pf%u", 256 eth_port->eth_index, abm->pf_id); 257 258 mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); 259 if (!mac_str) { 260 nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n", 261 name); 262 eth_hw_addr_random(nn->dp.netdev); 263 return; 264 } 265 266 if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 267 &mac_addr[0], &mac_addr[1], &mac_addr[2], 268 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { 269 nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n", 270 mac_str); 271 eth_hw_addr_random(nn->dp.netdev); 272 return; 273 } 274 275 ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr); 276 ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr); 277 } 278 279 static int 280 nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id) 281 { 282 struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id]; 283 struct nfp_abm *abm = app->priv; 284 struct nfp_abm_link *alink; 285 int err; 286 287 alink = kzalloc(sizeof(*alink), GFP_KERNEL); 288 if (!alink) 289 return -ENOMEM; 290 nn->app_priv = alink; 291 alink->abm = abm; 292 alink->vnic = nn; 293 alink->id = id; 294 295 /* This is a multi-host app, make sure MAC/PHY is up, but don't 296 * make the MAC/PHY state follow the state of any of the ports. 297 */ 298 err = nfp_eth_set_configured(app->cpp, eth_port->index, true); 299 if (err < 0) 300 goto err_free_alink; 301 302 netif_keep_dst(nn->dp.netdev); 303 304 nfp_abm_vnic_set_mac(app->pf, abm, nn, id); 305 nfp_abm_ctrl_read_params(alink); 306 307 return 0; 308 309 err_free_alink: 310 kfree(alink); 311 return err; 312 } 313 314 static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn) 315 { 316 struct nfp_abm_link *alink = nn->app_priv; 317 318 nfp_abm_kill_reprs(alink->abm, alink); 319 kfree(alink); 320 } 321 322 static int nfp_abm_init(struct nfp_app *app) 323 { 324 struct nfp_pf *pf = app->pf; 325 struct nfp_reprs *reprs; 326 struct nfp_abm *abm; 327 int err; 328 329 if (!pf->eth_tbl) { 330 nfp_err(pf->cpp, "ABM NIC requires ETH table\n"); 331 return -EINVAL; 332 } 333 if (pf->max_data_vnics != pf->eth_tbl->count) { 334 nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", 335 pf->max_data_vnics, pf->eth_tbl->count); 336 return -EINVAL; 337 } 338 if (!pf->mac_stats_bar) { 339 nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n"); 340 return -EINVAL; 341 } 342 343 abm = kzalloc(sizeof(*abm), GFP_KERNEL); 344 if (!abm) 345 return -ENOMEM; 346 app->priv = abm; 347 abm->app = app; 348 349 err = nfp_abm_ctrl_find_addrs(abm); 350 if (err) 351 goto err_free_abm; 352 353 err = -ENOMEM; 354 reprs = nfp_reprs_alloc(pf->max_data_vnics); 355 if (!reprs) 356 goto err_free_abm; 357 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs); 358 359 reprs = nfp_reprs_alloc(pf->max_data_vnics); 360 if (!reprs) 361 goto err_free_phys; 362 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs); 363 364 return 0; 365 366 err_free_phys: 367 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 368 err_free_abm: 369 kfree(abm); 370 app->priv = NULL; 371 return err; 372 } 373 374 static void nfp_abm_clean(struct nfp_app *app) 375 { 376 struct nfp_abm *abm = app->priv; 377 378 nfp_abm_eswitch_clean_up(abm); 379 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); 380 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 381 kfree(abm); 382 app->priv = NULL; 383 } 384 385 const struct nfp_app_type app_abm = { 386 .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC, 387 .name = "abm", 388 389 .init = nfp_abm_init, 390 .clean = nfp_abm_clean, 391 392 .vnic_alloc = nfp_abm_vnic_alloc, 393 .vnic_free = nfp_abm_vnic_free, 394 395 .eswitch_mode_get = nfp_abm_eswitch_mode_get, 396 .eswitch_mode_set = nfp_abm_eswitch_mode_set, 397 398 .repr_get = nfp_abm_repr_get, 399 }; 400