FILE
dev.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/dev.c
1/* 2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/mlx5/driver.h> 34#include <linux/mlx5/eswitch.h> 35#include <linux/mlx5/mlx5_ifc_vdpa.h> 36#include <linux/mlx5/vport.h> 37#include "mlx5_core.h" 38#include "devlink.h" 39#include "lag/lag.h" 40 41static DEFINE_IDA(mlx5_adev_ida); 42 43static bool is_eth_rep_supported(struct mlx5_core_dev *dev) 44{ 45 if (!IS_ENABLED(CONFIG_MLX5_ESWITCH)) 46 return false; 47 48 if (!MLX5_ESWITCH_MANAGER(dev)) 49 return false; 50 51 if (!is_mdev_switchdev_mode(dev)) 52 return false; 53 54 return true; 55} 56 57bool mlx5_eth_supported(struct mlx5_core_dev *dev) 58{ 59 if (!IS_ENABLED(CONFIG_MLX5_CORE_EN)) 60 return false; 61 62 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 63 return false; 64 65 if (!MLX5_CAP_GEN(dev, eth_net_offloads)) { 66 mlx5_core_warn(dev, "Missing eth_net_offloads capability\n"); 67 return false; 68 } 69 70 if (!MLX5_CAP_GEN(dev, nic_flow_table)) { 71 mlx5_core_warn(dev, "Missing nic_flow_table capability\n"); 72 return false; 73 } 74 75 if (!MLX5_CAP_ETH(dev, csum_cap)) { 76 mlx5_core_warn(dev, "Missing csum_cap capability\n"); 77 return false; 78 } 79 80 if (!MLX5_CAP_ETH(dev, max_lso_cap)) { 81 mlx5_core_warn(dev, "Missing max_lso_cap capability\n"); 82 return false; 83 } 84 85 if (!MLX5_CAP_ETH(dev, vlan_cap)) { 86 mlx5_core_warn(dev, "Missing vlan_cap capability\n"); 87 return false; 88 } 89 90 if (!MLX5_CAP_ETH(dev, rss_ind_tbl_cap)) { 91 mlx5_core_warn(dev, "Missing rss_ind_tbl_cap capability\n"); 92 return false; 93 } 94 95 if (MLX5_CAP_FLOWTABLE(dev, 96 flow_table_properties_nic_receive.max_ft_level) < 3) { 97 mlx5_core_warn(dev, "max_ft_level < 3\n"); 98 return false; 99 } 100 101 if (!MLX5_CAP_ETH(dev, self_lb_en_modifiable)) 102 mlx5_core_warn(dev, "Self loop back prevention is not supported\n"); 103 if (!MLX5_CAP_GEN(dev, cq_moderation)) 104 mlx5_core_warn(dev, "CQ moderation is not supported\n"); 105 106 return true; 107} 108 109bool mlx5_vnet_supported(struct mlx5_core_dev *dev) 110{ 111 if (!IS_ENABLED(CONFIG_MLX5_VDPA_NET)) 112 return false; 113 114 if (mlx5_core_is_pf(dev)) 115 return false; 116 117 if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & 118 MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q)) 119 return false; 120 121 if (!(MLX5_CAP_DEV_VDPA_EMULATION(dev, event_mode) & 122 MLX5_VIRTIO_Q_EVENT_MODE_QP_MODE)) 123 return false; 124 125 if (!MLX5_CAP_DEV_VDPA_EMULATION(dev, eth_frame_offload_type)) 126 return false; 127 128 return true; 129} 130 131static bool is_vnet_enabled(struct mlx5_core_dev *dev) 132{ 133 union devlink_param_value val; 134 int err; 135 136 err = devl_param_driverinit_value_get(priv_to_devlink(dev), 137 DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET, 138 &val); 139 return err ? false : val.vbool; 140} 141 142static bool is_ib_rep_supported(struct mlx5_core_dev *dev) 143{ 144 if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) 145 return false; 146 147 if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) 148 return false; 149 150 if (!is_eth_rep_supported(dev)) 151 return false; 152 153 if (mlx5_core_mp_enabled(dev)) 154 return false; 155 156 return true; 157} 158 159static bool is_mp_supported(struct mlx5_core_dev *dev) 160{ 161 if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) 162 return false; 163 164 if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) 165 return false; 166 167 if (is_ib_rep_supported(dev)) 168 return false; 169 170 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 171 return false; 172 173 if (!mlx5_core_is_mp_slave(dev)) 174 return false; 175 176 return true; 177} 178 179bool mlx5_rdma_supported(struct mlx5_core_dev *dev) 180{ 181 if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) 182 return false; 183 184 if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) 185 return false; 186 187 if (is_ib_rep_supported(dev)) 188 return false; 189 190 if (is_mp_supported(dev)) 191 return false; 192 193 return true; 194} 195 196static bool is_ib_enabled(struct mlx5_core_dev *dev) 197{ 198 union devlink_param_value val; 199 int err; 200 201 err = devl_param_driverinit_value_get(priv_to_devlink(dev), 202 DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA, 203 &val); 204 return err ? false : val.vbool; 205} 206 207static bool is_dpll_supported(struct mlx5_core_dev *dev) 208{ 209 if (!IS_ENABLED(CONFIG_MLX5_DPLL)) 210 return false; 211 212 if (!MLX5_CAP_MCAM_REG2(dev, synce_registers)) { 213 mlx5_core_dbg(dev, "Missing SyncE capability\n"); 214 return false; 215 } 216 217 return true; 218} 219 220enum { 221 MLX5_INTERFACE_PROTOCOL_ETH, 222 MLX5_INTERFACE_PROTOCOL_ETH_REP, 223 224 MLX5_INTERFACE_PROTOCOL_IB, 225 MLX5_INTERFACE_PROTOCOL_IB_REP, 226 MLX5_INTERFACE_PROTOCOL_MPIB, 227 228 MLX5_INTERFACE_PROTOCOL_VNET, 229 230 MLX5_INTERFACE_PROTOCOL_DPLL, 231 MLX5_INTERFACE_PROTOCOL_FWCTL, 232}; 233 234static bool is_fwctl_supported(struct mlx5_core_dev *dev) 235{ 236 /* fwctl is most useful on PFs, prevent fwctl on SFs for now */ 237 return MLX5_CAP_GEN(dev, uctx_cap) && !mlx5_core_is_sf(dev); 238} 239 240static const struct mlx5_adev_device { 241 const char *suffix; 242 bool (*is_supported)(struct mlx5_core_dev *dev); 243 bool (*is_enabled)(struct mlx5_core_dev *dev); 244} mlx5_adev_devices[] = { 245 [MLX5_INTERFACE_PROTOCOL_VNET] = { .suffix = "vnet", 246 .is_supported = &mlx5_vnet_supported, 247 .is_enabled = &is_vnet_enabled }, 248 [MLX5_INTERFACE_PROTOCOL_IB] = { .suffix = "rdma", 249 .is_supported = &mlx5_rdma_supported, 250 .is_enabled = &is_ib_enabled }, 251 [MLX5_INTERFACE_PROTOCOL_ETH] = { .suffix = "eth", 252 .is_supported = &mlx5_eth_supported, 253 .is_enabled = &mlx5_core_is_eth_enabled }, 254 [MLX5_INTERFACE_PROTOCOL_ETH_REP] = { .suffix = "eth-rep", 255 .is_supported = &is_eth_rep_supported }, 256 [MLX5_INTERFACE_PROTOCOL_IB_REP] = { .suffix = "rdma-rep", 257 .is_supported = &is_ib_rep_supported }, 258 [MLX5_INTERFACE_PROTOCOL_MPIB] = { .suffix = "multiport", 259 .is_supported = &is_mp_supported }, 260 [MLX5_INTERFACE_PROTOCOL_DPLL] = { .suffix = "dpll", 261 .is_supported = &is_dpll_supported }, 262 [MLX5_INTERFACE_PROTOCOL_FWCTL] = { .suffix = "fwctl", 263 .is_supported = &is_fwctl_supported }, 264}; 265 266int mlx5_adev_idx_alloc(void) 267{ 268 return ida_alloc(&mlx5_adev_ida, GFP_KERNEL); 269} 270 271void mlx5_adev_idx_free(int idx) 272{ 273 ida_free(&mlx5_adev_ida, idx); 274} 275 276int mlx5_adev_init(struct mlx5_core_dev *dev) 277{ 278 struct mlx5_priv *priv = &dev->priv; 279 280 priv->adev = kcalloc(ARRAY_SIZE(mlx5_adev_devices), 281 sizeof(struct mlx5_adev *), GFP_KERNEL); 282 if (!priv->adev) 283 return -ENOMEM; 284 285 return 0; 286} 287 288void mlx5_adev_cleanup(struct mlx5_core_dev *dev) 289{ 290 struct mlx5_priv *priv = &dev->priv; 291 292 kfree(priv->adev); 293} 294 295static void adev_release(struct device *dev) 296{ 297 struct mlx5_adev *mlx5_adev = 298 container_of(dev, struct mlx5_adev, adev.dev); 299 struct mlx5_priv *priv = &mlx5_adev->mdev->priv; 300 int idx = mlx5_adev->idx; 301 302 kfree(mlx5_adev); 303 priv->adev[idx] = NULL; 304} 305 306static struct mlx5_adev *add_adev(struct mlx5_core_dev *dev, int idx) 307{ 308 const char *suffix = mlx5_adev_devices[idx].suffix; 309 struct auxiliary_device *adev; 310 struct mlx5_adev *madev; 311 int ret; 312 313 madev = kzalloc(sizeof(*madev), GFP_KERNEL); 314 if (!madev) 315 return ERR_PTR(-ENOMEM); 316 317 adev = &madev->adev; 318 adev->id = dev->priv.adev_idx; 319 adev->name = suffix; 320 adev->dev.parent = dev->device; 321 adev->dev.release = adev_release; 322 madev->mdev = dev; 323 madev->idx = idx; 324 325 ret = auxiliary_device_init(adev); 326 if (ret) { 327 kfree(madev); 328 return ERR_PTR(ret); 329 } 330 331 ret = auxiliary_device_add(adev); 332 if (ret) { 333 auxiliary_device_uninit(adev); 334 return ERR_PTR(ret); 335 } 336 return madev; 337} 338 339static void del_adev(struct auxiliary_device *adev) 340{ 341 auxiliary_device_delete(adev); 342 auxiliary_device_uninit(adev); 343} 344 345void mlx5_dev_set_lightweight(struct mlx5_core_dev *dev) 346{ 347 mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp); 348 dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; 349 mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp); 350} 351 352bool mlx5_dev_is_lightweight(struct mlx5_core_dev *dev) 353{ 354 return dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; 355} 356 357int mlx5_attach_device(struct mlx5_core_dev *dev) 358{ 359 struct mlx5_priv *priv = &dev->priv; 360 struct auxiliary_device *adev; 361 const struct auxiliary_driver *adrv; 362 int ret = 0, i; 363 364 devl_assert_locked(priv_to_devlink(dev)); 365 mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp); 366 priv->flags &= ~MLX5_PRIV_FLAGS_DETACH; 367 for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) { 368 if (!priv->adev[i]) { 369 bool is_supported = false; 370 371 if (mlx5_adev_devices[i].is_enabled) { 372 bool enabled; 373 374 enabled = mlx5_adev_devices[i].is_enabled(dev); 375 if (!enabled) 376 continue; 377 } 378 379 if (mlx5_adev_devices[i].is_supported) 380 is_supported = mlx5_adev_devices[i].is_supported(dev); 381 382 if (!is_supported) 383 continue; 384 385 priv->adev[i] = add_adev(dev, i); 386 if (IS_ERR(priv->adev[i])) { 387 ret = PTR_ERR(priv->adev[i]); 388 priv->adev[i] = NULL; 389 } 390 } else { 391 adev = &priv->adev[i]->adev; 392 393 /* Pay attention that this is not PCI driver that 394 * mlx5_core_dev is connected, but auxiliary driver. 395 */ 396 if (!adev->dev.driver) 397 continue; 398 adrv = to_auxiliary_drv(adev->dev.driver); 399 400 if (adrv->resume) 401 ret = adrv->resume(adev); 402 } 403 if (ret) { 404 mlx5_core_warn(dev, "Device[%d] (%s) failed to load\n", 405 i, mlx5_adev_devices[i].suffix); 406 407 break; 408 } 409 } 410 mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp); 411 return ret; 412} 413 414void mlx5_detach_device(struct mlx5_core_dev *dev, bool suspend) 415{ 416 struct mlx5_priv *priv = &dev->priv; 417 struct auxiliary_device *adev; 418 const struct auxiliary_driver *adrv; 419 pm_message_t pm = {}; 420 int i; 421 422 devl_assert_locked(priv_to_devlink(dev)); 423 mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp); 424 for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) { 425 if (!priv->adev[i]) 426 continue; 427 428 if (mlx5_adev_devices[i].is_enabled) { 429 bool enabled; 430 431 enabled = mlx5_adev_devices[i].is_enabled(dev); 432 if (!enabled) 433 goto skip_suspend; 434 } 435 436 adev = &priv->adev[i]->adev; 437 /* Auxiliary driver was unbind manually through sysfs */ 438 if (!adev->dev.driver) 439 goto skip_suspend; 440 441 adrv = to_auxiliary_drv(adev->dev.driver); 442 443 if (adrv->suspend && suspend) { 444 adrv->suspend(adev, pm); 445 continue; 446 } 447 448skip_suspend: 449 del_adev(&priv->adev[i]->adev); 450 priv->adev[i] = NULL; 451 } 452 priv->flags |= MLX5_PRIV_FLAGS_DETACH; 453 mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp); 454} 455 456int mlx5_register_device(struct mlx5_core_dev *dev) 457{ 458 int ret; 459 460 devl_assert_locked(priv_to_devlink(dev)); 461 mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp); 462 dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; 463 ret = mlx5_rescan_drivers_locked(dev); 464 mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp); 465 if (ret) 466 mlx5_unregister_device(dev); 467 468 return ret; 469} 470 471void mlx5_unregister_device(struct mlx5_core_dev *dev) 472{ 473 devl_assert_locked(priv_to_devlink(dev)); 474 mlx5_devcom_comp_lock(dev->priv.hca_devcom_comp); 475 dev->priv.flags = MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; 476 mlx5_rescan_drivers_locked(dev); 477 mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp); 478} 479 480static int add_drivers(struct mlx5_core_dev *dev) 481{ 482 struct mlx5_priv *priv = &dev->priv; 483 int i, ret = 0; 484 485 for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) { 486 bool is_supported = false; 487 488 if (priv->adev[i]) 489 continue; 490 491 if (mlx5_adev_devices[i].is_enabled && 492 !(mlx5_adev_devices[i].is_enabled(dev))) 493 continue; 494 495 if (mlx5_adev_devices[i].is_supported) 496 is_supported = mlx5_adev_devices[i].is_supported(dev); 497 498 if (!is_supported) 499 continue; 500 501 priv->adev[i] = add_adev(dev, i); 502 if (IS_ERR(priv->adev[i])) { 503 mlx5_core_warn(dev, "Device[%d] (%s) failed to load\n", 504 i, mlx5_adev_devices[i].suffix); 505 /* We continue to rescan drivers and leave to the caller 506 * to make decision if to release everything or continue. 507 */ 508 ret = PTR_ERR(priv->adev[i]); 509 priv->adev[i] = NULL; 510 } 511 } 512 return ret; 513} 514 515static void delete_drivers(struct mlx5_core_dev *dev) 516{ 517 struct mlx5_priv *priv = &dev->priv; 518 bool delete_all; 519 int i; 520 521 delete_all = priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; 522 523 for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) { 524 bool is_supported = false; 525 526 if (!priv->adev[i]) 527 continue; 528 529 if (mlx5_adev_devices[i].is_enabled) { 530 bool enabled; 531 532 enabled = mlx5_adev_devices[i].is_enabled(dev); 533 if (!enabled) 534 goto del_adev; 535 } 536 537 if (mlx5_adev_devices[i].is_supported && !delete_all) 538 is_supported = mlx5_adev_devices[i].is_supported(dev); 539 540 if (is_supported) 541 continue; 542 543del_adev: 544 del_adev(&priv->adev[i]->adev); 545 priv->adev[i] = NULL; 546 } 547} 548 549/* This function is used after mlx5_core_dev is reconfigured. 550 */ 551int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev) 552{ 553 struct mlx5_priv *priv = &dev->priv; 554 555 if (priv->flags & MLX5_PRIV_FLAGS_DETACH) 556 return 0; 557 558 delete_drivers(dev); 559 if (priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV) 560 return 0; 561 562 return add_drivers(dev); 563} 564 565bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev) 566{ 567 u8 fsystem_guid[MLX5_SW_IMAGE_GUID_MAX_BYTES]; 568 u8 psystem_guid[MLX5_SW_IMAGE_GUID_MAX_BYTES]; 569 u8 flen; 570 u8 plen; 571 572 mlx5_query_nic_sw_system_image_guid(dev, fsystem_guid, &flen); 573 mlx5_query_nic_sw_system_image_guid(peer_dev, psystem_guid, &plen); 574 575 return plen && flen && flen == plen && 576 !memcmp(fsystem_guid, psystem_guid, flen); 577} 578 579void mlx5_core_reps_aux_devs_remove(struct mlx5_core_dev *dev) 580{ 581 struct mlx5_priv *priv = &dev->priv; 582 583 if (priv->adev[MLX5_INTERFACE_PROTOCOL_ETH]) 584 device_lock_assert(&priv->adev[MLX5_INTERFACE_PROTOCOL_ETH]->adev.dev); 585 else 586 mlx5_core_err(dev, "ETH driver already removed\n"); 587 if (priv->adev[MLX5_INTERFACE_PROTOCOL_IB_REP]) 588 del_adev(&priv->adev[MLX5_INTERFACE_PROTOCOL_IB_REP]->adev); 589 if (priv->adev[MLX5_INTERFACE_PROTOCOL_ETH_REP]) 590 del_adev(&priv->adev[MLX5_INTERFACE_PROTOCOL_ETH_REP]->adev); 591}
~/
Read-only file preview.