162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This software is available to you under a choice of one of two 662306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 962306a36Sopenharmony_ci * OpenIB.org BSD license below: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1262306a36Sopenharmony_ci * without modification, are permitted provided that the following 1362306a36Sopenharmony_ci * conditions are met: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1662306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1762306a36Sopenharmony_ci * disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2062306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2162306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2262306a36Sopenharmony_ci * provided with the distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3162306a36Sopenharmony_ci * SOFTWARE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <linux/export.h> 3662306a36Sopenharmony_ci#include <linux/errno.h> 3762306a36Sopenharmony_ci#include <net/devlink.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "mlx4.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic DEFINE_MUTEX(intf_mutex); 4262306a36Sopenharmony_cistatic DEFINE_IDA(mlx4_adev_ida); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic bool is_eth_supported(struct mlx4_dev *dev) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci for (int port = 1; port <= dev->caps.num_ports; port++) 4762306a36Sopenharmony_ci if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 4862306a36Sopenharmony_ci return true; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic bool is_ib_supported(struct mlx4_dev *dev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci for (int port = 1; port <= dev->caps.num_ports; port++) 5662306a36Sopenharmony_ci if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB) 5762306a36Sopenharmony_ci return true; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE) 6062306a36Sopenharmony_ci return true; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return false; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct mlx4_adev_device { 6662306a36Sopenharmony_ci const char *suffix; 6762306a36Sopenharmony_ci bool (*is_supported)(struct mlx4_dev *dev); 6862306a36Sopenharmony_ci} mlx4_adev_devices[] = { 6962306a36Sopenharmony_ci { "eth", is_eth_supported }, 7062306a36Sopenharmony_ci { "ib", is_ib_supported }, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint mlx4_adev_init(struct mlx4_dev *dev) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci priv->adev_idx = ida_alloc(&mlx4_adev_ida, GFP_KERNEL); 7862306a36Sopenharmony_ci if (priv->adev_idx < 0) 7962306a36Sopenharmony_ci return priv->adev_idx; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci priv->adev = kcalloc(ARRAY_SIZE(mlx4_adev_devices), 8262306a36Sopenharmony_ci sizeof(struct mlx4_adev *), GFP_KERNEL); 8362306a36Sopenharmony_ci if (!priv->adev) { 8462306a36Sopenharmony_ci ida_free(&mlx4_adev_ida, priv->adev_idx); 8562306a36Sopenharmony_ci return -ENOMEM; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid mlx4_adev_cleanup(struct mlx4_dev *dev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci kfree(priv->adev); 9662306a36Sopenharmony_ci ida_free(&mlx4_adev_ida, priv->adev_idx); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void adev_release(struct device *dev) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct mlx4_adev *mlx4_adev = 10262306a36Sopenharmony_ci container_of(dev, struct mlx4_adev, adev.dev); 10362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(mlx4_adev->mdev); 10462306a36Sopenharmony_ci int idx = mlx4_adev->idx; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci kfree(mlx4_adev); 10762306a36Sopenharmony_ci priv->adev[idx] = NULL; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct mlx4_adev *add_adev(struct mlx4_dev *dev, int idx) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 11362306a36Sopenharmony_ci const char *suffix = mlx4_adev_devices[idx].suffix; 11462306a36Sopenharmony_ci struct auxiliary_device *adev; 11562306a36Sopenharmony_ci struct mlx4_adev *madev; 11662306a36Sopenharmony_ci int ret; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci madev = kzalloc(sizeof(*madev), GFP_KERNEL); 11962306a36Sopenharmony_ci if (!madev) 12062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci adev = &madev->adev; 12362306a36Sopenharmony_ci adev->id = priv->adev_idx; 12462306a36Sopenharmony_ci adev->name = suffix; 12562306a36Sopenharmony_ci adev->dev.parent = &dev->persist->pdev->dev; 12662306a36Sopenharmony_ci adev->dev.release = adev_release; 12762306a36Sopenharmony_ci madev->mdev = dev; 12862306a36Sopenharmony_ci madev->idx = idx; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ret = auxiliary_device_init(adev); 13162306a36Sopenharmony_ci if (ret) { 13262306a36Sopenharmony_ci kfree(madev); 13362306a36Sopenharmony_ci return ERR_PTR(ret); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci ret = auxiliary_device_add(adev); 13762306a36Sopenharmony_ci if (ret) { 13862306a36Sopenharmony_ci auxiliary_device_uninit(adev); 13962306a36Sopenharmony_ci return ERR_PTR(ret); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci return madev; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void del_adev(struct auxiliary_device *adev) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci auxiliary_device_delete(adev); 14762306a36Sopenharmony_ci auxiliary_device_uninit(adev); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciint mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci return auxiliary_driver_register(&madrv->adrv); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_register_auxiliary_driver); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_civoid mlx4_unregister_auxiliary_driver(struct mlx4_adrv *madrv) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci auxiliary_driver_unregister(&madrv->adrv); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_unregister_auxiliary_driver); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint mlx4_do_bond(struct mlx4_dev *dev, bool enable) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 16562306a36Sopenharmony_ci int i, ret; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)) 16862306a36Sopenharmony_ci return -EOPNOTSUPP; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci ret = mlx4_disable_rx_port_check(dev, enable); 17162306a36Sopenharmony_ci if (ret) { 17262306a36Sopenharmony_ci mlx4_err(dev, "Fail to %s rx port check\n", 17362306a36Sopenharmony_ci enable ? "enable" : "disable"); 17462306a36Sopenharmony_ci return ret; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci if (enable) { 17762306a36Sopenharmony_ci dev->flags |= MLX4_FLAG_BONDED; 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci ret = mlx4_virt2phy_port_map(dev, 1, 2); 18062306a36Sopenharmony_ci if (ret) { 18162306a36Sopenharmony_ci mlx4_err(dev, "Fail to reset port map\n"); 18262306a36Sopenharmony_ci return ret; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci dev->flags &= ~MLX4_FLAG_BONDED; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci mutex_lock(&intf_mutex); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) { 19062306a36Sopenharmony_ci struct mlx4_adev *madev = priv->adev[i]; 19162306a36Sopenharmony_ci struct mlx4_adrv *madrv; 19262306a36Sopenharmony_ci enum mlx4_protocol protocol; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!madev) 19562306a36Sopenharmony_ci continue; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci device_lock(&madev->adev.dev); 19862306a36Sopenharmony_ci if (!madev->adev.dev.driver) { 19962306a36Sopenharmony_ci device_unlock(&madev->adev.dev); 20062306a36Sopenharmony_ci continue; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci madrv = container_of(madev->adev.dev.driver, struct mlx4_adrv, 20462306a36Sopenharmony_ci adrv.driver); 20562306a36Sopenharmony_ci if (!(madrv->flags & MLX4_INTFF_BONDING)) { 20662306a36Sopenharmony_ci device_unlock(&madev->adev.dev); 20762306a36Sopenharmony_ci continue; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 21162306a36Sopenharmony_ci mlx4_dbg(dev, 21262306a36Sopenharmony_ci "SRIOV, disabled HA mode for intf proto %d\n", 21362306a36Sopenharmony_ci madrv->protocol); 21462306a36Sopenharmony_ci device_unlock(&madev->adev.dev); 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci protocol = madrv->protocol; 21962306a36Sopenharmony_ci device_unlock(&madev->adev.dev); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci del_adev(&madev->adev); 22262306a36Sopenharmony_ci priv->adev[i] = add_adev(dev, i); 22362306a36Sopenharmony_ci if (IS_ERR(priv->adev[i])) { 22462306a36Sopenharmony_ci mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i, 22562306a36Sopenharmony_ci mlx4_adev_devices[i].suffix); 22662306a36Sopenharmony_ci priv->adev[i] = NULL; 22762306a36Sopenharmony_ci continue; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci mlx4_dbg(dev, 23162306a36Sopenharmony_ci "Interface for protocol %d restarted with bonded mode %s\n", 23262306a36Sopenharmony_ci protocol, enable ? "enabled" : "disabled"); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci mutex_unlock(&intf_mutex); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_civoid mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, 24162306a36Sopenharmony_ci void *param) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci atomic_notifier_call_chain(&priv->event_nh, type, param); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciint mlx4_register_event_notifier(struct mlx4_dev *dev, 24962306a36Sopenharmony_ci struct notifier_block *nb) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return atomic_notifier_chain_register(&priv->event_nh, nb); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ciEXPORT_SYMBOL(mlx4_register_event_notifier); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciint mlx4_unregister_event_notifier(struct mlx4_dev *dev, 25862306a36Sopenharmony_ci struct notifier_block *nb) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return atomic_notifier_chain_unregister(&priv->event_nh, nb); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ciEXPORT_SYMBOL(mlx4_unregister_event_notifier); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int add_drivers(struct mlx4_dev *dev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 26962306a36Sopenharmony_ci int i, ret = 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) { 27262306a36Sopenharmony_ci bool is_supported = false; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (priv->adev[i]) 27562306a36Sopenharmony_ci continue; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (mlx4_adev_devices[i].is_supported) 27862306a36Sopenharmony_ci is_supported = mlx4_adev_devices[i].is_supported(dev); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!is_supported) 28162306a36Sopenharmony_ci continue; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci priv->adev[i] = add_adev(dev, i); 28462306a36Sopenharmony_ci if (IS_ERR(priv->adev[i])) { 28562306a36Sopenharmony_ci mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i, 28662306a36Sopenharmony_ci mlx4_adev_devices[i].suffix); 28762306a36Sopenharmony_ci /* We continue to rescan drivers and leave to the caller 28862306a36Sopenharmony_ci * to make decision if to release everything or 28962306a36Sopenharmony_ci * continue. */ 29062306a36Sopenharmony_ci ret = PTR_ERR(priv->adev[i]); 29162306a36Sopenharmony_ci priv->adev[i] = NULL; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void delete_drivers(struct mlx4_dev *dev) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 30062306a36Sopenharmony_ci bool delete_all; 30162306a36Sopenharmony_ci int i; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci delete_all = !(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (i = ARRAY_SIZE(mlx4_adev_devices) - 1; i >= 0; i--) { 30662306a36Sopenharmony_ci bool is_supported = false; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (!priv->adev[i]) 30962306a36Sopenharmony_ci continue; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (mlx4_adev_devices[i].is_supported && !delete_all) 31262306a36Sopenharmony_ci is_supported = mlx4_adev_devices[i].is_supported(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (is_supported) 31562306a36Sopenharmony_ci continue; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci del_adev(&priv->adev[i]->adev); 31862306a36Sopenharmony_ci priv->adev[i] = NULL; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* This function is used after mlx4_dev is reconfigured. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_cistatic int rescan_drivers_locked(struct mlx4_dev *dev) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci lockdep_assert_held(&intf_mutex); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci delete_drivers(dev); 32962306a36Sopenharmony_ci if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP)) 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return add_drivers(dev); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciint mlx4_register_device(struct mlx4_dev *dev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci mutex_lock(&intf_mutex); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = rescan_drivers_locked(dev); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci mutex_unlock(&intf_mutex); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (ret) { 34862306a36Sopenharmony_ci mlx4_unregister_device(dev); 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mlx4_start_catas_poll(dev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return ret; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_civoid mlx4_unregister_device(struct mlx4_dev *dev) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP)) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci mlx4_stop_catas_poll(dev); 36362306a36Sopenharmony_ci if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION && 36462306a36Sopenharmony_ci mlx4_is_slave(dev)) { 36562306a36Sopenharmony_ci /* In mlx4_remove_one on a VF */ 36662306a36Sopenharmony_ci u32 slave_read = 36762306a36Sopenharmony_ci swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read)); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (mlx4_comm_internal_err(slave_read)) { 37062306a36Sopenharmony_ci mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n", 37162306a36Sopenharmony_ci __func__); 37262306a36Sopenharmony_ci mlx4_enter_error_state(dev->persist); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci mutex_lock(&intf_mutex); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci rescan_drivers_locked(dev); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mutex_unlock(&intf_mutex); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistruct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return &info->devlink_port; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_devlink_port); 391