brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · a371b97 Raw
391 lines · c
1/*2 * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.4 *5 * This software is available to you under a choice of one of two6 * licenses.  You may choose to be licensed under the terms of the GNU7 * General Public License (GPL) Version 2, available from the file8 * COPYING in the main directory of this source tree, or the9 * OpenIB.org BSD license below:10 *11 *     Redistribution and use in source and binary forms, with or12 *     without modification, are permitted provided that the following13 *     conditions are met:14 *15 *      - Redistributions of source code must retain the above16 *        copyright notice, this list of conditions and the following17 *        disclaimer.18 *19 *      - Redistributions in binary form must reproduce the above20 *        copyright notice, this list of conditions and the following21 *        disclaimer in the documentation and/or other materials22 *        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 OF26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31 * SOFTWARE.32 */33 34#include <linux/slab.h>35#include <linux/export.h>36#include <linux/errno.h>37#include <net/devlink.h>38 39#include "mlx4.h"40 41static DEFINE_MUTEX(intf_mutex);42static DEFINE_IDA(mlx4_adev_ida);43 44static bool is_eth_supported(struct mlx4_dev *dev)45{46	for (int port = 1; port <= dev->caps.num_ports; port++)47		if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)48			return true;49 50	return false;51}52 53static bool is_ib_supported(struct mlx4_dev *dev)54{55	for (int port = 1; port <= dev->caps.num_ports; port++)56		if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)57			return true;58 59	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)60		return true;61 62	return false;63}64 65static const struct mlx4_adev_device {66	const char *suffix;67	bool (*is_supported)(struct mlx4_dev *dev);68} mlx4_adev_devices[] = {69	{ "eth", is_eth_supported },70	{ "ib", is_ib_supported },71};72 73int mlx4_adev_init(struct mlx4_dev *dev)74{75	struct mlx4_priv *priv = mlx4_priv(dev);76 77	priv->adev_idx = ida_alloc(&mlx4_adev_ida, GFP_KERNEL);78	if (priv->adev_idx < 0)79		return priv->adev_idx;80 81	priv->adev = kcalloc(ARRAY_SIZE(mlx4_adev_devices),82			     sizeof(struct mlx4_adev *), GFP_KERNEL);83	if (!priv->adev) {84		ida_free(&mlx4_adev_ida, priv->adev_idx);85		return -ENOMEM;86	}87 88	return 0;89}90 91void mlx4_adev_cleanup(struct mlx4_dev *dev)92{93	struct mlx4_priv *priv = mlx4_priv(dev);94 95	kfree(priv->adev);96	ida_free(&mlx4_adev_ida, priv->adev_idx);97}98 99static void adev_release(struct device *dev)100{101	struct mlx4_adev *mlx4_adev =102		container_of(dev, struct mlx4_adev, adev.dev);103	struct mlx4_priv *priv = mlx4_priv(mlx4_adev->mdev);104	int idx = mlx4_adev->idx;105 106	kfree(mlx4_adev);107	priv->adev[idx] = NULL;108}109 110static struct mlx4_adev *add_adev(struct mlx4_dev *dev, int idx)111{112	struct mlx4_priv *priv = mlx4_priv(dev);113	const char *suffix = mlx4_adev_devices[idx].suffix;114	struct auxiliary_device *adev;115	struct mlx4_adev *madev;116	int ret;117 118	madev = kzalloc(sizeof(*madev), GFP_KERNEL);119	if (!madev)120		return ERR_PTR(-ENOMEM);121 122	adev = &madev->adev;123	adev->id = priv->adev_idx;124	adev->name = suffix;125	adev->dev.parent = &dev->persist->pdev->dev;126	adev->dev.release = adev_release;127	madev->mdev = dev;128	madev->idx = idx;129 130	ret = auxiliary_device_init(adev);131	if (ret) {132		kfree(madev);133		return ERR_PTR(ret);134	}135 136	ret = auxiliary_device_add(adev);137	if (ret) {138		auxiliary_device_uninit(adev);139		return ERR_PTR(ret);140	}141	return madev;142}143 144static void del_adev(struct auxiliary_device *adev)145{146	auxiliary_device_delete(adev);147	auxiliary_device_uninit(adev);148}149 150int mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv)151{152	return auxiliary_driver_register(&madrv->adrv);153}154EXPORT_SYMBOL_GPL(mlx4_register_auxiliary_driver);155 156void mlx4_unregister_auxiliary_driver(struct mlx4_adrv *madrv)157{158	auxiliary_driver_unregister(&madrv->adrv);159}160EXPORT_SYMBOL_GPL(mlx4_unregister_auxiliary_driver);161 162int mlx4_do_bond(struct mlx4_dev *dev, bool enable)163{164	struct mlx4_priv *priv = mlx4_priv(dev);165	int i, ret;166 167	if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP))168		return -EOPNOTSUPP;169 170	ret = mlx4_disable_rx_port_check(dev, enable);171	if (ret) {172		mlx4_err(dev, "Fail to %s rx port check\n",173			 enable ? "enable" : "disable");174		return ret;175	}176	if (enable) {177		dev->flags |= MLX4_FLAG_BONDED;178	} else {179		ret = mlx4_virt2phy_port_map(dev, 1, 2);180		if (ret) {181			mlx4_err(dev, "Fail to reset port map\n");182			return ret;183		}184		dev->flags &= ~MLX4_FLAG_BONDED;185	}186 187	mutex_lock(&intf_mutex);188 189	for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {190		struct mlx4_adev *madev = priv->adev[i];191		struct mlx4_adrv *madrv;192		enum mlx4_protocol protocol;193 194		if (!madev)195			continue;196 197		device_lock(&madev->adev.dev);198		if (!madev->adev.dev.driver) {199			device_unlock(&madev->adev.dev);200			continue;201		}202 203		madrv = container_of(madev->adev.dev.driver, struct mlx4_adrv,204				     adrv.driver);205		if (!(madrv->flags & MLX4_INTFF_BONDING)) {206			device_unlock(&madev->adev.dev);207			continue;208		}209 210		if (mlx4_is_mfunc(dev)) {211			mlx4_dbg(dev,212				 "SRIOV, disabled HA mode for intf proto %d\n",213				 madrv->protocol);214			device_unlock(&madev->adev.dev);215			continue;216		}217 218		protocol = madrv->protocol;219		device_unlock(&madev->adev.dev);220 221		del_adev(&madev->adev);222		priv->adev[i] = add_adev(dev, i);223		if (IS_ERR(priv->adev[i])) {224			mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,225				  mlx4_adev_devices[i].suffix);226			priv->adev[i] = NULL;227			continue;228		}229 230		mlx4_dbg(dev,231			 "Interface for protocol %d restarted with bonded mode %s\n",232			 protocol, enable ? "enabled" : "disabled");233	}234 235	mutex_unlock(&intf_mutex);236 237	return 0;238}239 240void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,241			 void *param)242{243	struct mlx4_priv *priv = mlx4_priv(dev);244 245	atomic_notifier_call_chain(&priv->event_nh, type, param);246}247 248int mlx4_register_event_notifier(struct mlx4_dev *dev,249				 struct notifier_block *nb)250{251	struct mlx4_priv *priv = mlx4_priv(dev);252 253	return atomic_notifier_chain_register(&priv->event_nh, nb);254}255EXPORT_SYMBOL(mlx4_register_event_notifier);256 257int mlx4_unregister_event_notifier(struct mlx4_dev *dev,258				   struct notifier_block *nb)259{260	struct mlx4_priv *priv = mlx4_priv(dev);261 262	return atomic_notifier_chain_unregister(&priv->event_nh, nb);263}264EXPORT_SYMBOL(mlx4_unregister_event_notifier);265 266static int add_drivers(struct mlx4_dev *dev)267{268	struct mlx4_priv *priv = mlx4_priv(dev);269	int i, ret = 0;270 271	for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {272		bool is_supported = false;273 274		if (priv->adev[i])275			continue;276 277		if (mlx4_adev_devices[i].is_supported)278			is_supported = mlx4_adev_devices[i].is_supported(dev);279 280		if (!is_supported)281			continue;282 283		priv->adev[i] = add_adev(dev, i);284		if (IS_ERR(priv->adev[i])) {285			mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,286				  mlx4_adev_devices[i].suffix);287			/* We continue to rescan drivers and leave to the caller288			 * to make decision if to release everything or289			 * continue. */290			ret = PTR_ERR(priv->adev[i]);291			priv->adev[i] = NULL;292		}293	}294	return ret;295}296 297static void delete_drivers(struct mlx4_dev *dev)298{299	struct mlx4_priv *priv = mlx4_priv(dev);300	bool delete_all;301	int i;302 303	delete_all = !(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP);304 305	for (i = ARRAY_SIZE(mlx4_adev_devices) - 1; i >= 0; i--) {306		bool is_supported = false;307 308		if (!priv->adev[i])309			continue;310 311		if (mlx4_adev_devices[i].is_supported && !delete_all)312			is_supported = mlx4_adev_devices[i].is_supported(dev);313 314		if (is_supported)315			continue;316 317		del_adev(&priv->adev[i]->adev);318		priv->adev[i] = NULL;319	}320}321 322/* This function is used after mlx4_dev is reconfigured.323 */324static int rescan_drivers_locked(struct mlx4_dev *dev)325{326	lockdep_assert_held(&intf_mutex);327 328	delete_drivers(dev);329	if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))330		return 0;331 332	return add_drivers(dev);333}334 335int mlx4_register_device(struct mlx4_dev *dev)336{337	int ret;338 339	mutex_lock(&intf_mutex);340 341	dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP;342 343	ret = rescan_drivers_locked(dev);344 345	mutex_unlock(&intf_mutex);346 347	if (ret) {348		mlx4_unregister_device(dev);349		return ret;350	}351 352	mlx4_start_catas_poll(dev);353 354	return ret;355}356 357void mlx4_unregister_device(struct mlx4_dev *dev)358{359	if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))360		return;361 362	mlx4_stop_catas_poll(dev);363	if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION &&364	    mlx4_is_slave(dev)) {365		/* In mlx4_remove_one on a VF */366		u32 slave_read =367			swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read));368 369		if (mlx4_comm_internal_err(slave_read)) {370			mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n",371				 __func__);372			mlx4_enter_error_state(dev->persist);373		}374	}375	mutex_lock(&intf_mutex);376 377	dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP;378 379	rescan_drivers_locked(dev);380 381	mutex_unlock(&intf_mutex);382}383 384struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port)385{386	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];387 388	return &info->devlink_port;389}390EXPORT_SYMBOL_GPL(mlx4_get_devlink_port);391