Merge branch 'mlx4-aux-bus'

Petr Pavlu says:

====================
Convert mlx4 to use auxiliary bus

This series converts the mlx4 drivers to use auxiliary bus, similarly to
how mlx5 was converted [1]. The first 6 patches are preparatory changes,
the remaining 4 are the final conversion.

Initial motivation for this change was to address a problem related to
loading mlx4_en/mlx4_ib by mlx4_core using request_module_nowait(). When
doing such a load in initrd, the operation is asynchronous to any init
control and can get unexpectedly affected/interrupted by an eventual
root switch. Using an auxiliary bus leaves these module loads to udevd
which better integrates with systemd processing. [2]

General benefit is to get rid of custom interface logic and instead use
a common facility available for this task. An obvious risk is that some
new bug is introduced by the conversion.

Leon Romanovsky was kind enough to check for me that the series passes
their verification tests.

Changes since v2 [3]:
* Use 'void *' as the event param of mlx4_dispatch_event().

Changes since v1 [4]:
* Fix a missing definition of the err variable in mlx4_en_add().
* Remove not needed comments about the event type in mlx4_en_event()
  and mlx4_ib_event().

[1] https://lore.kernel.org/netdev/20201101201542.2027568-1-leon@kernel.org/
[2] https://lore.kernel.org/netdev/0a361ac2-c6bd-2b18-4841-b1b991f0635e@suse.com/
[3] https://lore.kernel.org/netdev/20230813145127.10653-1-petr.pavlu@suse.com/
[4] https://lore.kernel.org/netdev/20230804150527.6117-1-petr.pavlu@suse.com/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2023-08-23 08:25:28 +01:00
commit 5c42b66d01
14 changed files with 620 additions and 426 deletions

View file

@ -82,6 +82,8 @@ static const char mlx4_ib_version[] =
static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init);
static enum rdma_link_layer mlx4_ib_port_link_layer(struct ib_device *device,
u32 port_num);
static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
void *param);
static struct workqueue_struct *wq;
@ -125,12 +127,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
u32 port_num)
{
struct mlx4_ib_dev *ibdev = to_mdev(device);
struct net_device *dev;
struct net_device *dev, *ret = NULL;
rcu_read_lock();
dev = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port_num);
for_each_netdev_rcu(&init_net, dev) {
if (dev->dev.parent != ibdev->ib_dev.dev.parent ||
dev->dev_port + 1 != port_num)
continue;
if (dev) {
if (mlx4_is_bonded(ibdev->dev)) {
struct net_device *upper = NULL;
@ -143,11 +147,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
dev = active;
}
}
dev_hold(dev);
ret = dev;
break;
}
dev_hold(dev);
rcu_read_unlock();
return dev;
return ret;
}
static int mlx4_ib_update_gids_v1(struct gid_entry *gids,
@ -2319,61 +2326,53 @@ static void mlx4_ib_update_qps(struct mlx4_ib_dev *ibdev,
mutex_unlock(&ibdev->qp1_proxy_lock[port - 1]);
}
static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev,
struct net_device *dev,
unsigned long event)
static void mlx4_ib_scan_netdev(struct mlx4_ib_dev *ibdev,
struct net_device *dev,
unsigned long event)
{
struct mlx4_ib_iboe *iboe;
int update_qps_port = -1;
int port;
struct mlx4_ib_iboe *iboe = &ibdev->iboe;
ASSERT_RTNL();
iboe = &ibdev->iboe;
if (dev->dev.parent != ibdev->ib_dev.dev.parent)
return;
spin_lock_bh(&iboe->lock);
mlx4_foreach_ib_transport_port(port, ibdev->dev) {
iboe->netdevs[port - 1] =
mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
iboe->netdevs[dev->dev_port] = event != NETDEV_UNREGISTER ? dev : NULL;
if (dev == iboe->netdevs[port - 1] &&
(event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
event == NETDEV_UP || event == NETDEV_CHANGE))
update_qps_port = port;
if (event == NETDEV_UP || event == NETDEV_DOWN) {
enum ib_port_state port_state;
struct ib_event ibev = { };
if (dev == iboe->netdevs[port - 1] &&
(event == NETDEV_UP || event == NETDEV_DOWN)) {
enum ib_port_state port_state;
struct ib_event ibev = { };
if (ib_get_cached_port_state(&ibdev->ib_dev, dev->dev_port + 1,
&port_state))
goto iboe_out;
if (ib_get_cached_port_state(&ibdev->ib_dev, port,
&port_state))
continue;
if (event == NETDEV_UP &&
(port_state != IB_PORT_ACTIVE ||
iboe->last_port_state[port - 1] != IB_PORT_DOWN))
continue;
if (event == NETDEV_DOWN &&
(port_state != IB_PORT_DOWN ||
iboe->last_port_state[port - 1] != IB_PORT_ACTIVE))
continue;
iboe->last_port_state[port - 1] = port_state;
ibev.device = &ibdev->ib_dev;
ibev.element.port_num = port;
ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
IB_EVENT_PORT_ERR;
ib_dispatch_event(&ibev);
}
if (event == NETDEV_UP &&
(port_state != IB_PORT_ACTIVE ||
iboe->last_port_state[dev->dev_port] != IB_PORT_DOWN))
goto iboe_out;
if (event == NETDEV_DOWN &&
(port_state != IB_PORT_DOWN ||
iboe->last_port_state[dev->dev_port] != IB_PORT_ACTIVE))
goto iboe_out;
iboe->last_port_state[dev->dev_port] = port_state;
ibev.device = &ibdev->ib_dev;
ibev.element.port_num = dev->dev_port + 1;
ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
IB_EVENT_PORT_ERR;
ib_dispatch_event(&ibev);
}
iboe_out:
spin_unlock_bh(&iboe->lock);
if (update_qps_port > 0)
mlx4_ib_update_qps(ibdev, dev, update_qps_port);
if (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
event == NETDEV_UP || event == NETDEV_CHANGE)
mlx4_ib_update_qps(ibdev, dev, dev->dev_port + 1);
}
static int mlx4_ib_netdev_event(struct notifier_block *this,
@ -2386,7 +2385,7 @@ static int mlx4_ib_netdev_event(struct notifier_block *this,
return NOTIFY_DONE;
ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
mlx4_ib_scan_netdevs(ibdev, dev, event);
mlx4_ib_scan_netdev(ibdev, dev, event);
return NOTIFY_DONE;
}
@ -2610,8 +2609,11 @@ static const struct ib_device_ops mlx4_ib_dev_fs_ops = {
.destroy_flow = mlx4_ib_destroy_flow,
};
static void *mlx4_ib_add(struct mlx4_dev *dev)
static int mlx4_ib_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
struct mlx4_dev *dev = madev->mdev;
struct mlx4_ib_dev *ibdev;
int num_ports = 0;
int i, j;
@ -2631,27 +2633,31 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
/* No point in registering a device with no ports... */
if (num_ports == 0)
return NULL;
return -ENODEV;
ibdev = ib_alloc_device(mlx4_ib_dev, ib_dev);
if (!ibdev) {
dev_err(&dev->persist->pdev->dev,
"Device struct alloc failed\n");
return NULL;
return -ENOMEM;
}
iboe = &ibdev->iboe;
if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
err = mlx4_pd_alloc(dev, &ibdev->priv_pdn);
if (err)
goto err_dealloc;
if (mlx4_uar_alloc(dev, &ibdev->priv_uar))
err = mlx4_uar_alloc(dev, &ibdev->priv_uar);
if (err)
goto err_pd;
ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT,
PAGE_SIZE);
if (!ibdev->uar_map)
if (!ibdev->uar_map) {
err = -ENOMEM;
goto err_uar;
}
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
ibdev->dev = dev;
@ -2695,7 +2701,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
spin_lock_init(&iboe->lock);
if (init_node_data(ibdev))
err = init_node_data(ibdev);
if (err)
goto err_map;
mlx4_init_sl2vl_tbl(ibdev);
@ -2727,6 +2734,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
new_counter_index = kmalloc(sizeof(*new_counter_index),
GFP_KERNEL);
if (!new_counter_index) {
err = -ENOMEM;
if (allocated)
mlx4_counter_free(ibdev->dev, counter_index);
goto err_counter;
@ -2744,8 +2752,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
new_counter_index =
kmalloc(sizeof(struct counter_index),
GFP_KERNEL);
if (!new_counter_index)
if (!new_counter_index) {
err = -ENOMEM;
goto err_counter;
}
new_counter_index->index = counter_index;
new_counter_index->allocated = 0;
list_add_tail(&new_counter_index->list,
@ -2774,8 +2784,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_uc_qpns_bitmap = bitmap_alloc(ibdev->steer_qpn_count,
GFP_KERNEL);
if (!ibdev->ib_uc_qpns_bitmap)
if (!ibdev->ib_uc_qpns_bitmap) {
err = -ENOMEM;
goto err_steer_qp_release;
}
if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) {
bitmap_zero(ibdev->ib_uc_qpns_bitmap,
@ -2795,17 +2807,21 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
atomic64_set(&iboe->mac[j - 1], ibdev->dev->caps.def_mac[j]);
if (mlx4_ib_alloc_diag_counters(ibdev))
err = mlx4_ib_alloc_diag_counters(ibdev);
if (err)
goto err_steer_free_bitmap;
if (ib_register_device(&ibdev->ib_dev, "mlx4_%d",
&dev->persist->pdev->dev))
err = ib_register_device(&ibdev->ib_dev, "mlx4_%d",
&dev->persist->pdev->dev);
if (err)
goto err_diag_counters;
if (mlx4_ib_mad_init(ibdev))
err = mlx4_ib_mad_init(ibdev);
if (err)
goto err_reg;
if (mlx4_ib_init_sriov(ibdev))
err = mlx4_ib_init_sriov(ibdev);
if (err)
goto err_mad;
if (!iboe->nb.notifier_call) {
@ -2839,7 +2855,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
do_slave_init(ibdev, j, 1);
}
}
return ibdev;
/* register mlx4 core notifier */
ibdev->mlx_nb.notifier_call = mlx4_ib_event;
err = mlx4_register_event_notifier(dev, &ibdev->mlx_nb);
WARN(err, "failed to register mlx4 event notifier (%d)", err);
auxiliary_set_drvdata(adev, ibdev);
return 0;
err_notif:
if (ibdev->iboe.nb.notifier_call) {
@ -2883,7 +2906,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
err_dealloc:
ib_dealloc_device(&ibdev->ib_dev);
return NULL;
return err;
}
int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn)
@ -2950,12 +2973,16 @@ int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
return err;
}
static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
static void mlx4_ib_remove(struct auxiliary_device *adev)
{
struct mlx4_ib_dev *ibdev = ibdev_ptr;
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
struct mlx4_dev *dev = madev->mdev;
struct mlx4_ib_dev *ibdev = auxiliary_get_drvdata(adev);
int p;
int i;
mlx4_unregister_event_notifier(dev, &ibdev->mlx_nb);
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
ibdev->ib_active = false;
@ -3176,11 +3203,13 @@ void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
}
}
static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
enum mlx4_dev_event event, unsigned long param)
static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
void *param)
{
struct mlx4_ib_dev *ibdev =
container_of(this, struct mlx4_ib_dev, mlx_nb);
struct mlx4_dev *dev = ibdev->dev;
struct ib_event ibev;
struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr);
struct mlx4_eqe *eqe = NULL;
struct ib_event_work *ew;
int p = 0;
@ -3190,22 +3219,28 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
(event == MLX4_DEV_EVENT_PORT_DOWN))) {
ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
if (!ew)
return;
return NOTIFY_DONE;
INIT_WORK(&ew->work, handle_bonded_port_state_event);
ew->ib_dev = ibdev;
queue_work(wq, &ew->work);
return;
return NOTIFY_DONE;
}
if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE)
switch (event) {
case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
break;
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
eqe = (struct mlx4_eqe *)param;
else
p = (int) param;
break;
default:
p = *(int *)param;
break;
}
switch (event) {
case MLX4_DEV_EVENT_PORT_UP:
if (p > ibdev->num_ports)
return;
return NOTIFY_DONE;
if (!mlx4_is_slave(dev) &&
rdma_port_get_link_layer(&ibdev->ib_dev, p) ==
IB_LINK_LAYER_INFINIBAND) {
@ -3220,7 +3255,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_PORT_DOWN:
if (p > ibdev->num_ports)
return;
return NOTIFY_DONE;
ibev.event = IB_EVENT_PORT_ERR;
break;
@ -3233,7 +3268,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
ew = kmalloc(sizeof *ew, GFP_ATOMIC);
if (!ew)
return;
return NOTIFY_DONE;
INIT_WORK(&ew->work, handle_port_mgmt_change_event);
memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
@ -3243,7 +3278,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
queue_work(wq, &ew->work);
else
handle_port_mgmt_change_event(&ew->work);
return;
return NOTIFY_DONE;
case MLX4_DEV_EVENT_SLAVE_INIT:
/* here, p is the slave id */
@ -3259,7 +3294,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
1);
}
}
return;
return NOTIFY_DONE;
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
if (mlx4_is_master(dev)) {
@ -3275,22 +3310,33 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
}
/* here, p is the slave id */
do_slave_init(ibdev, p, 0);
return;
return NOTIFY_DONE;
default:
return;
return NOTIFY_DONE;
}
ibev.device = ibdev_ptr;
ibev.device = &ibdev->ib_dev;
ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p;
ib_dispatch_event(&ibev);
return NOTIFY_DONE;
}
static struct mlx4_interface mlx4_ib_interface = {
.add = mlx4_ib_add,
.remove = mlx4_ib_remove,
.event = mlx4_ib_event,
static const struct auxiliary_device_id mlx4_ib_id_table[] = {
{ .name = MLX4_ADEV_NAME ".ib" },
{},
};
MODULE_DEVICE_TABLE(auxiliary, mlx4_ib_id_table);
static struct mlx4_adrv mlx4_ib_adrv = {
.adrv = {
.name = "ib",
.probe = mlx4_ib_probe,
.remove = mlx4_ib_remove,
.id_table = mlx4_ib_id_table,
},
.protocol = MLX4_PROT_IB_IPV6,
.flags = MLX4_INTFF_BONDING
};
@ -3315,7 +3361,7 @@ static int __init mlx4_ib_init(void)
if (err)
goto clean_cm;
err = mlx4_register_interface(&mlx4_ib_interface);
err = mlx4_register_auxiliary_driver(&mlx4_ib_adrv);
if (err)
goto clean_mcg;
@ -3337,7 +3383,7 @@ static int __init mlx4_ib_init(void)
static void __exit mlx4_ib_cleanup(void)
{
mlx4_unregister_interface(&mlx4_ib_interface);
mlx4_unregister_auxiliary_driver(&mlx4_ib_adrv);
mlx4_ib_mcg_destroy();
mlx4_ib_cm_destroy();
mlx4_ib_qp_event_cleanup();

View file

@ -38,6 +38,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/idr.h>
#include <linux/notifier.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h>
@ -644,6 +645,7 @@ struct mlx4_ib_dev {
spinlock_t reset_flow_resource_lock;
struct list_head qp_list;
struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES];
struct notifier_block mlx_nb;
};
struct ib_event_work {

View file

@ -27,6 +27,7 @@ config MLX4_EN_DCB
config MLX4_CORE
tristate
depends on PCI
select AUXILIARY_BUS
select NET_DEVLINK
default n

View file

@ -194,7 +194,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
mutex_unlock(&persist->device_state_mutex);
/* At that step HW was already reset, now notify clients */
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, NULL);
mlx4_cmd_wake_completions(dev);
return;

View file

@ -2113,7 +2113,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
goto inform_slave_state;
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, &slave);
/* write the version in the event field */
reply |= mlx4_comm_get_version();
@ -2152,7 +2152,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (mlx4_master_activate_admin_state(priv, slave))
goto reset_slave;
slave_state[slave].active = true;
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, &slave);
break;
case MLX4_COMM_CMD_VHCR_POST:
if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&

View file

@ -183,24 +183,31 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
}
}
static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
static int mlx4_en_event(struct notifier_block *this, unsigned long event,
void *param)
{
struct mlx4_en_dev *endev = ctx;
return endev->pndev[port];
}
static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
enum mlx4_dev_event event, unsigned long port)
{
struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr;
struct mlx4_en_dev *mdev =
container_of(this, struct mlx4_en_dev, mlx_nb);
struct mlx4_dev *dev = mdev->dev;
struct mlx4_en_priv *priv;
int port;
switch (event) {
case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
case MLX4_DEV_EVENT_SLAVE_INIT:
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
break;
default:
port = *(int *)param;
break;
}
switch (event) {
case MLX4_DEV_EVENT_PORT_UP:
case MLX4_DEV_EVENT_PORT_DOWN:
if (!mdev->pndev[port])
return;
return NOTIFY_DONE;
priv = netdev_priv(mdev->pndev[port]);
/* To prevent races, we poll the link state in a separate
task rather than changing it here */
@ -212,23 +219,30 @@ static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
mlx4_err(mdev, "Internal error detected, restarting device\n");
break;
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
case MLX4_DEV_EVENT_SLAVE_INIT:
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
break;
default:
if (port < 1 || port > dev->caps.num_ports ||
!mdev->pndev[port])
return;
mlx4_warn(mdev, "Unhandled event %d for port %d\n", event,
(int) port);
return NOTIFY_DONE;
mlx4_warn(mdev, "Unhandled event %d for port %d\n", (int)event,
port);
}
return NOTIFY_DONE;
}
static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
static void mlx4_en_remove(struct auxiliary_device *adev)
{
struct mlx4_en_dev *mdev = endev_ptr;
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
struct mlx4_dev *dev = madev->mdev;
struct mlx4_en_dev *mdev = auxiliary_get_drvdata(adev);
int i;
mlx4_unregister_event_notifier(dev, &mdev->mlx_nb);
mutex_lock(&mdev->state_lock);
mdev->device_up = false;
mutex_unlock(&mdev->state_lock);
@ -242,52 +256,41 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
iounmap(mdev->uar_map);
mlx4_uar_free(dev, &mdev->priv_uar);
mlx4_pd_free(dev, mdev->priv_pdn);
if (mdev->nb.notifier_call)
unregister_netdevice_notifier(&mdev->nb);
if (mdev->netdev_nb.notifier_call)
unregister_netdevice_notifier(&mdev->netdev_nb);
kfree(mdev);
}
static void mlx4_en_activate(struct mlx4_dev *dev, void *ctx)
{
int i;
struct mlx4_en_dev *mdev = ctx;
/* Create a netdev for each port */
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
mlx4_info(mdev, "Activating port:%d\n", i);
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
mdev->pndev[i] = NULL;
}
/* register notifier */
mdev->nb.notifier_call = mlx4_en_netdev_event;
if (register_netdevice_notifier(&mdev->nb)) {
mdev->nb.notifier_call = NULL;
mlx4_err(mdev, "Failed to create notifier\n");
}
}
static void *mlx4_en_add(struct mlx4_dev *dev)
static int mlx4_en_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
struct mlx4_dev *dev = madev->mdev;
struct mlx4_en_dev *mdev;
int i;
int err, i;
printk_once(KERN_INFO "%s", mlx4_en_version);
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
if (!mdev) {
err = -ENOMEM;
goto err_free_res;
}
if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
err = mlx4_pd_alloc(dev, &mdev->priv_pdn);
if (err)
goto err_free_dev;
if (mlx4_uar_alloc(dev, &mdev->priv_uar))
err = mlx4_uar_alloc(dev, &mdev->priv_uar);
if (err)
goto err_pd;
mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT,
PAGE_SIZE);
if (!mdev->uar_map)
if (!mdev->uar_map) {
err = -ENOMEM;
goto err_uar;
}
spin_lock_init(&mdev->uar_lock);
mdev->dev = dev;
@ -299,13 +302,15 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (!mdev->LSO_support)
mlx4_warn(mdev, "LSO not supported, please upgrade to later FW version to enable LSO\n");
if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
0, 0, &mdev->mr)) {
err = mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, 0, 0,
&mdev->mr);
if (err) {
mlx4_err(mdev, "Failed allocating memory region\n");
goto err_map;
}
if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
err = mlx4_mr_enable(mdev->dev, &mdev->mr);
if (err) {
mlx4_err(mdev, "Failed enabling memory region\n");
goto err_mr;
}
@ -325,15 +330,39 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
* Note: we cannot use the shared workqueue because of deadlocks caused
* by the rtnl lock */
mdev->workqueue = create_singlethread_workqueue("mlx4_en");
if (!mdev->workqueue)
if (!mdev->workqueue) {
err = -ENOMEM;
goto err_mr;
}
/* At this stage all non-port specific tasks are complete:
* mark the card state as up */
mutex_init(&mdev->state_lock);
mdev->device_up = true;
return mdev;
/* register mlx4 core notifier */
mdev->mlx_nb.notifier_call = mlx4_en_event;
err = mlx4_register_event_notifier(dev, &mdev->mlx_nb);
WARN(err, "failed to register mlx4 event notifier (%d)", err);
/* Setup ports */
/* Create a netdev for each port */
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
mlx4_info(mdev, "Activating port:%d\n", i);
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
mdev->pndev[i] = NULL;
}
/* register netdev notifier */
mdev->netdev_nb.notifier_call = mlx4_en_netdev_event;
if (register_netdevice_notifier(&mdev->netdev_nb)) {
mdev->netdev_nb.notifier_call = NULL;
mlx4_err(mdev, "Failed to create netdev notifier\n");
}
auxiliary_set_drvdata(adev, mdev);
return 0;
err_mr:
(void) mlx4_mr_free(dev, &mdev->mr);
@ -347,16 +376,24 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
err_free_dev:
kfree(mdev);
err_free_res:
return NULL;
return err;
}
static struct mlx4_interface mlx4_en_interface = {
.add = mlx4_en_add,
.remove = mlx4_en_remove,
.event = mlx4_en_event,
.get_dev = mlx4_en_get_netdev,
static const struct auxiliary_device_id mlx4_en_id_table[] = {
{ .name = MLX4_ADEV_NAME ".eth" },
{},
};
MODULE_DEVICE_TABLE(auxiliary, mlx4_en_id_table);
static struct mlx4_adrv mlx4_en_adrv = {
.adrv = {
.name = "eth",
.probe = mlx4_en_probe,
.remove = mlx4_en_remove,
.id_table = mlx4_en_id_table,
},
.protocol = MLX4_PROT_ETH,
.activate = mlx4_en_activate,
};
static void mlx4_en_verify_params(void)
@ -385,12 +422,12 @@ static int __init mlx4_en_init(void)
mlx4_en_verify_params();
mlx4_en_init_ptys2ethtool_map();
return mlx4_register_interface(&mlx4_en_interface);
return mlx4_register_auxiliary_driver(&mlx4_en_adrv);
}
static void __exit mlx4_en_cleanup(void)
{
mlx4_unregister_interface(&mlx4_en_interface);
mlx4_unregister_auxiliary_driver(&mlx4_en_adrv);
}
module_init(mlx4_en_init);

View file

@ -2894,63 +2894,6 @@ static const struct xdp_metadata_ops mlx4_xdp_metadata_ops = {
.xmo_rx_hash = mlx4_en_xdp_rx_hash,
};
struct mlx4_en_bond {
struct work_struct work;
struct mlx4_en_priv *priv;
int is_bonded;
struct mlx4_port_map port_map;
};
static void mlx4_en_bond_work(struct work_struct *work)
{
struct mlx4_en_bond *bond = container_of(work,
struct mlx4_en_bond,
work);
int err = 0;
struct mlx4_dev *dev = bond->priv->mdev->dev;
if (bond->is_bonded) {
if (!mlx4_is_bonded(dev)) {
err = mlx4_bond(dev);
if (err)
en_err(bond->priv, "Fail to bond device\n");
}
if (!err) {
err = mlx4_port_map_set(dev, &bond->port_map);
if (err)
en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n",
bond->port_map.port1,
bond->port_map.port2,
err);
}
} else if (mlx4_is_bonded(dev)) {
err = mlx4_unbond(dev);
if (err)
en_err(bond->priv, "Fail to unbond device\n");
}
dev_put(bond->priv->dev);
kfree(bond);
}
static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded,
u8 v2p_p1, u8 v2p_p2)
{
struct mlx4_en_bond *bond;
bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
if (!bond)
return -ENOMEM;
INIT_WORK(&bond->work, mlx4_en_bond_work);
bond->priv = priv;
bond->is_bonded = is_bonded;
bond->port_map.port1 = v2p_p1;
bond->port_map.port2 = v2p_p2;
dev_hold(priv->dev);
queue_work(priv->mdev->workqueue, &bond->work);
return 0;
}
int mlx4_en_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@ -2960,14 +2903,13 @@ int mlx4_en_netdev_event(struct notifier_block *this,
struct mlx4_dev *dev;
int i, num_eth_ports = 0;
bool do_bond = true;
struct mlx4_en_priv *priv;
u8 v2p_port1 = 0;
u8 v2p_port2 = 0;
if (!net_eq(dev_net(ndev), &init_net))
return NOTIFY_DONE;
mdev = container_of(this, struct mlx4_en_dev, nb);
mdev = container_of(this, struct mlx4_en_dev, netdev_nb);
dev = mdev->dev;
/* Go into this mode only when two network devices set on two ports
@ -2995,7 +2937,6 @@ int mlx4_en_netdev_event(struct notifier_block *this,
if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port)
return NOTIFY_DONE;
priv = netdev_priv(ndev);
if (do_bond) {
struct netdev_notifier_bonding_info *notifier_info = ptr;
struct netdev_bonding_info *bonding_info =
@ -3062,8 +3003,7 @@ int mlx4_en_netdev_event(struct notifier_block *this,
}
}
mlx4_en_queue_bond_work(priv, do_bond,
v2p_port1, v2p_port2);
mlx4_queue_bond_work(dev, do_bond, v2p_port1, v2p_port2);
return NOTIFY_DONE;
}

View file

@ -501,7 +501,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
int port;
int slave = 0;
int ret;
u32 flr_slave;
int flr_slave;
u8 update_slave_state;
int i;
enum slave_port_gen_event gen_event;
@ -606,8 +606,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
port = be32_to_cpu(eqe->event.port_change.port) >> 28;
slaves_port = mlx4_phys_to_slaves_pport(dev, port);
if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
port);
mlx4_dispatch_event(
dev, MLX4_DEV_EVENT_PORT_DOWN, &port);
mlx4_priv(dev)->sense.do_sense_port[port] = 1;
if (!mlx4_is_master(dev))
break;
@ -647,7 +647,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
}
}
} else {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP,
&port);
mlx4_priv(dev)->sense.do_sense_port[port] = 0;
@ -758,7 +759,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
}
spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN,
flr_slave);
&flr_slave);
queue_work(priv->mfunc.master.comm_wq,
&priv->mfunc.master.slave_flr_event_work);
break;
@ -787,8 +788,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
break;
case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT:
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE,
(unsigned long) eqe);
mlx4_dispatch_event(
dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, eqe);
break;
case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT:

View file

@ -38,102 +38,131 @@
#include "mlx4.h"
struct mlx4_device_context {
struct list_head list;
struct list_head bond_list;
struct mlx4_interface *intf;
void *context;
static DEFINE_MUTEX(intf_mutex);
static DEFINE_IDA(mlx4_adev_ida);
static bool is_eth_supported(struct mlx4_dev *dev)
{
for (int port = 1; port <= dev->caps.num_ports; port++)
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
return true;
return false;
}
static bool is_ib_supported(struct mlx4_dev *dev)
{
for (int port = 1; port <= dev->caps.num_ports; port++)
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)
return true;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)
return true;
return false;
}
static const struct mlx4_adev_device {
const char *suffix;
bool (*is_supported)(struct mlx4_dev *dev);
} mlx4_adev_devices[] = {
{ "eth", is_eth_supported },
{ "ib", is_ib_supported },
};
static LIST_HEAD(intf_list);
static LIST_HEAD(dev_list);
static DEFINE_MUTEX(intf_mutex);
static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
int mlx4_adev_init(struct mlx4_dev *dev)
{
struct mlx4_device_context *dev_ctx;
struct mlx4_priv *priv = mlx4_priv(dev);
dev_ctx = kmalloc(sizeof(*dev_ctx), GFP_KERNEL);
if (!dev_ctx)
return;
priv->adev_idx = ida_alloc(&mlx4_adev_ida, GFP_KERNEL);
if (priv->adev_idx < 0)
return priv->adev_idx;
dev_ctx->intf = intf;
dev_ctx->context = intf->add(&priv->dev);
if (dev_ctx->context) {
spin_lock_irq(&priv->ctx_lock);
list_add_tail(&dev_ctx->list, &priv->ctx_list);
spin_unlock_irq(&priv->ctx_lock);
if (intf->activate)
intf->activate(&priv->dev, dev_ctx->context);
} else
kfree(dev_ctx);
}
static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
{
struct mlx4_device_context *dev_ctx;
list_for_each_entry(dev_ctx, &priv->ctx_list, list)
if (dev_ctx->intf == intf) {
spin_lock_irq(&priv->ctx_lock);
list_del(&dev_ctx->list);
spin_unlock_irq(&priv->ctx_lock);
intf->remove(&priv->dev, dev_ctx->context);
kfree(dev_ctx);
return;
}
}
int mlx4_register_interface(struct mlx4_interface *intf)
{
struct mlx4_priv *priv;
if (!intf->add || !intf->remove)
return -EINVAL;
mutex_lock(&intf_mutex);
list_add_tail(&intf->list, &intf_list);
list_for_each_entry(priv, &dev_list, dev_list) {
if (mlx4_is_mfunc(&priv->dev) && (intf->flags & MLX4_INTFF_BONDING)) {
mlx4_dbg(&priv->dev,
"SRIOV, disabling HA mode for intf proto %d\n", intf->protocol);
intf->flags &= ~MLX4_INTFF_BONDING;
}
mlx4_add_device(intf, priv);
priv->adev = kcalloc(ARRAY_SIZE(mlx4_adev_devices),
sizeof(struct mlx4_adev *), GFP_KERNEL);
if (!priv->adev) {
ida_free(&mlx4_adev_ida, priv->adev_idx);
return -ENOMEM;
}
mutex_unlock(&intf_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_register_interface);
void mlx4_unregister_interface(struct mlx4_interface *intf)
void mlx4_adev_cleanup(struct mlx4_dev *dev)
{
struct mlx4_priv *priv;
struct mlx4_priv *priv = mlx4_priv(dev);
mutex_lock(&intf_mutex);
list_for_each_entry(priv, &dev_list, dev_list)
mlx4_remove_device(intf, priv);
list_del(&intf->list);
mutex_unlock(&intf_mutex);
kfree(priv->adev);
ida_free(&mlx4_adev_ida, priv->adev_idx);
}
EXPORT_SYMBOL_GPL(mlx4_unregister_interface);
static void adev_release(struct device *dev)
{
struct mlx4_adev *mlx4_adev =
container_of(dev, struct mlx4_adev, adev.dev);
struct mlx4_priv *priv = mlx4_priv(mlx4_adev->mdev);
int idx = mlx4_adev->idx;
kfree(mlx4_adev);
priv->adev[idx] = NULL;
}
static struct mlx4_adev *add_adev(struct mlx4_dev *dev, int idx)
{
struct mlx4_priv *priv = mlx4_priv(dev);
const char *suffix = mlx4_adev_devices[idx].suffix;
struct auxiliary_device *adev;
struct mlx4_adev *madev;
int ret;
madev = kzalloc(sizeof(*madev), GFP_KERNEL);
if (!madev)
return ERR_PTR(-ENOMEM);
adev = &madev->adev;
adev->id = priv->adev_idx;
adev->name = suffix;
adev->dev.parent = &dev->persist->pdev->dev;
adev->dev.release = adev_release;
madev->mdev = dev;
madev->idx = idx;
ret = auxiliary_device_init(adev);
if (ret) {
kfree(madev);
return ERR_PTR(ret);
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ERR_PTR(ret);
}
return madev;
}
static void del_adev(struct auxiliary_device *adev)
{
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
int mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv)
{
return auxiliary_driver_register(&madrv->adrv);
}
EXPORT_SYMBOL_GPL(mlx4_register_auxiliary_driver);
void mlx4_unregister_auxiliary_driver(struct mlx4_adrv *madrv)
{
auxiliary_driver_unregister(&madrv->adrv);
}
EXPORT_SYMBOL_GPL(mlx4_unregister_auxiliary_driver);
int mlx4_do_bond(struct mlx4_dev *dev, bool enable)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_device_context *dev_ctx = NULL, *temp_dev_ctx;
unsigned long flags;
int ret;
LIST_HEAD(bond_list);
int i, ret;
if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP))
return -EOPNOTSUPP;
@ -155,69 +184,178 @@ int mlx4_do_bond(struct mlx4_dev *dev, bool enable)
dev->flags &= ~MLX4_FLAG_BONDED;
}
spin_lock_irqsave(&priv->ctx_lock, flags);
list_for_each_entry_safe(dev_ctx, temp_dev_ctx, &priv->ctx_list, list) {
if (dev_ctx->intf->flags & MLX4_INTFF_BONDING) {
list_add_tail(&dev_ctx->bond_list, &bond_list);
list_del(&dev_ctx->list);
mutex_lock(&intf_mutex);
for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {
struct mlx4_adev *madev = priv->adev[i];
struct mlx4_adrv *madrv;
enum mlx4_protocol protocol;
if (!madev)
continue;
device_lock(&madev->adev.dev);
if (!madev->adev.dev.driver) {
device_unlock(&madev->adev.dev);
continue;
}
madrv = container_of(madev->adev.dev.driver, struct mlx4_adrv,
adrv.driver);
if (!(madrv->flags & MLX4_INTFF_BONDING)) {
device_unlock(&madev->adev.dev);
continue;
}
if (mlx4_is_mfunc(dev)) {
mlx4_dbg(dev,
"SRIOV, disabled HA mode for intf proto %d\n",
madrv->protocol);
device_unlock(&madev->adev.dev);
continue;
}
protocol = madrv->protocol;
device_unlock(&madev->adev.dev);
del_adev(&madev->adev);
priv->adev[i] = add_adev(dev, i);
if (IS_ERR(priv->adev[i])) {
mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,
mlx4_adev_devices[i].suffix);
priv->adev[i] = NULL;
continue;
}
mlx4_dbg(dev,
"Interface for protocol %d restarted with bonded mode %s\n",
protocol, enable ? "enabled" : "disabled");
}
spin_unlock_irqrestore(&priv->ctx_lock, flags);
list_for_each_entry(dev_ctx, &bond_list, bond_list) {
dev_ctx->intf->remove(dev, dev_ctx->context);
dev_ctx->context = dev_ctx->intf->add(dev);
mutex_unlock(&intf_mutex);
spin_lock_irqsave(&priv->ctx_lock, flags);
list_add_tail(&dev_ctx->list, &priv->ctx_list);
spin_unlock_irqrestore(&priv->ctx_lock, flags);
mlx4_dbg(dev, "Interface for protocol %d restarted with bonded mode %s\n",
dev_ctx->intf->protocol, enable ?
"enabled" : "disabled");
}
return 0;
}
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
unsigned long param)
void *param)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_device_context *dev_ctx;
unsigned long flags;
spin_lock_irqsave(&priv->ctx_lock, flags);
atomic_notifier_call_chain(&priv->event_nh, type, param);
}
list_for_each_entry(dev_ctx, &priv->ctx_list, list)
if (dev_ctx->intf->event)
dev_ctx->intf->event(dev, dev_ctx->context, type, param);
int mlx4_register_event_notifier(struct mlx4_dev *dev,
struct notifier_block *nb)
{
struct mlx4_priv *priv = mlx4_priv(dev);
spin_unlock_irqrestore(&priv->ctx_lock, flags);
return atomic_notifier_chain_register(&priv->event_nh, nb);
}
EXPORT_SYMBOL(mlx4_register_event_notifier);
int mlx4_unregister_event_notifier(struct mlx4_dev *dev,
struct notifier_block *nb)
{
struct mlx4_priv *priv = mlx4_priv(dev);
return atomic_notifier_chain_unregister(&priv->event_nh, nb);
}
EXPORT_SYMBOL(mlx4_unregister_event_notifier);
static int add_drivers(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {
bool is_supported = false;
if (priv->adev[i])
continue;
if (mlx4_adev_devices[i].is_supported)
is_supported = mlx4_adev_devices[i].is_supported(dev);
if (!is_supported)
continue;
priv->adev[i] = add_adev(dev, i);
if (IS_ERR(priv->adev[i])) {
mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,
mlx4_adev_devices[i].suffix);
/* We continue to rescan drivers and leave to the caller
* to make decision if to release everything or
* continue. */
ret = PTR_ERR(priv->adev[i]);
priv->adev[i] = NULL;
}
}
return ret;
}
static void delete_drivers(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
bool delete_all;
int i;
delete_all = !(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP);
for (i = ARRAY_SIZE(mlx4_adev_devices) - 1; i >= 0; i--) {
bool is_supported = false;
if (!priv->adev[i])
continue;
if (mlx4_adev_devices[i].is_supported && !delete_all)
is_supported = mlx4_adev_devices[i].is_supported(dev);
if (is_supported)
continue;
del_adev(&priv->adev[i]->adev);
priv->adev[i] = NULL;
}
}
/* This function is used after mlx4_dev is reconfigured.
*/
static int rescan_drivers_locked(struct mlx4_dev *dev)
{
lockdep_assert_held(&intf_mutex);
delete_drivers(dev);
if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))
return 0;
return add_drivers(dev);
}
int mlx4_register_device(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_interface *intf;
int ret;
mutex_lock(&intf_mutex);
dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP;
list_add_tail(&priv->dev_list, &dev_list);
list_for_each_entry(intf, &intf_list, list)
mlx4_add_device(intf, priv);
ret = rescan_drivers_locked(dev);
mutex_unlock(&intf_mutex);
if (ret) {
mlx4_unregister_device(dev);
return ret;
}
mlx4_start_catas_poll(dev);
return 0;
return ret;
}
void mlx4_unregister_device(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_interface *intf;
if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))
return;
@ -236,36 +374,13 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
}
mutex_lock(&intf_mutex);
list_for_each_entry(intf, &intf_list, list)
mlx4_remove_device(intf, priv);
list_del(&priv->dev_list);
dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP;
rescan_drivers_locked(dev);
mutex_unlock(&intf_mutex);
}
void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_device_context *dev_ctx;
unsigned long flags;
void *result = NULL;
spin_lock_irqsave(&priv->ctx_lock, flags);
list_for_each_entry(dev_ctx, &priv->ctx_list, list)
if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
break;
}
spin_unlock_irqrestore(&priv->ctx_lock, flags);
return result;
}
EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port)
{
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];

View file

@ -42,7 +42,6 @@
#include <linux/slab.h>
#include <linux/io-mapping.h>
#include <linux/delay.h>
#include <linux/kmod.h>
#include <linux/etherdevice.h>
#include <net/devlink.h>
@ -1091,27 +1090,6 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
return err;
}
static void mlx4_request_modules(struct mlx4_dev *dev)
{
int port;
int has_ib_port = false;
int has_eth_port = false;
#define EN_DRV_NAME "mlx4_en"
#define IB_DRV_NAME "mlx4_ib"
for (port = 1; port <= dev->caps.num_ports; port++) {
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)
has_ib_port = true;
else if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
has_eth_port = true;
}
if (has_eth_port)
request_module_nowait(EN_DRV_NAME);
if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
request_module_nowait(IB_DRV_NAME);
}
/*
* Change the port configuration of the device.
* Every user of this function must hold the port mutex.
@ -1147,7 +1125,6 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
mlx4_err(dev, "Failed to register device\n");
goto out;
}
mlx4_request_modules(dev);
}
out:
@ -1441,7 +1418,7 @@ static int mlx4_mf_unbond(struct mlx4_dev *dev)
return ret;
}
int mlx4_bond(struct mlx4_dev *dev)
static int mlx4_bond(struct mlx4_dev *dev)
{
int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev);
@ -1467,9 +1444,8 @@ int mlx4_bond(struct mlx4_dev *dev)
return ret;
}
EXPORT_SYMBOL_GPL(mlx4_bond);
int mlx4_unbond(struct mlx4_dev *dev)
static int mlx4_unbond(struct mlx4_dev *dev)
{
int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev);
@ -1496,10 +1472,8 @@ int mlx4_unbond(struct mlx4_dev *dev)
return ret;
}
EXPORT_SYMBOL_GPL(mlx4_unbond);
int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
static int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
{
u8 port1 = v2p->port1;
u8 port2 = v2p->port2;
@ -1541,7 +1515,61 @@ int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
mutex_unlock(&priv->bond_mutex);
return err;
}
EXPORT_SYMBOL_GPL(mlx4_port_map_set);
struct mlx4_bond {
struct work_struct work;
struct mlx4_dev *dev;
int is_bonded;
struct mlx4_port_map port_map;
};
static void mlx4_bond_work(struct work_struct *work)
{
struct mlx4_bond *bond = container_of(work, struct mlx4_bond, work);
int err = 0;
if (bond->is_bonded) {
if (!mlx4_is_bonded(bond->dev)) {
err = mlx4_bond(bond->dev);
if (err)
mlx4_err(bond->dev, "Fail to bond device\n");
}
if (!err) {
err = mlx4_port_map_set(bond->dev, &bond->port_map);
if (err)
mlx4_err(bond->dev,
"Fail to set port map [%d][%d]: %d\n",
bond->port_map.port1,
bond->port_map.port2, err);
}
} else if (mlx4_is_bonded(bond->dev)) {
err = mlx4_unbond(bond->dev);
if (err)
mlx4_err(bond->dev, "Fail to unbond device\n");
}
put_device(&bond->dev->persist->pdev->dev);
kfree(bond);
}
int mlx4_queue_bond_work(struct mlx4_dev *dev, int is_bonded, u8 v2p_p1,
u8 v2p_p2)
{
struct mlx4_bond *bond;
bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
if (!bond)
return -ENOMEM;
INIT_WORK(&bond->work, mlx4_bond_work);
get_device(&dev->persist->pdev->dev);
bond->dev = dev;
bond->is_bonded = is_bonded;
bond->port_map.port1 = v2p_p1;
bond->port_map.port2 = v2p_p2;
queue_work(mlx4_wq, &bond->work);
return 0;
}
EXPORT_SYMBOL(mlx4_queue_bond_work);
static int mlx4_load_fw(struct mlx4_dev *dev)
{
@ -3375,8 +3403,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
devl_assert_locked(devlink);
dev = &priv->dev;
INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock);
err = mlx4_adev_init(dev);
if (err)
return err;
ATOMIC_INIT_NOTIFIER_HEAD(&priv->event_nh);
mutex_init(&priv->port_mutex);
mutex_init(&priv->bond_mutex);
@ -3402,10 +3433,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
err = mlx4_get_ownership(dev);
if (err) {
if (err < 0)
return err;
goto err_adev;
else {
mlx4_warn(dev, "Multiple PFs not yet supported - Skipping PF\n");
return -EINVAL;
err = -EINVAL;
goto err_adev;
}
}
@ -3674,8 +3706,6 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
if (err)
goto err_port;
mlx4_request_modules(dev);
mlx4_sense_init(dev);
mlx4_start_sense(dev);
@ -3753,6 +3783,9 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
mlx4_free_ownership(dev);
kfree(dev_cap);
err_adev:
mlx4_adev_cleanup(dev);
return err;
}
@ -4133,6 +4166,8 @@ static void mlx4_unload_one(struct pci_dev *pdev)
mlx4_slave_destroy_special_qp_cap(dev);
kfree(dev->dev_vfs);
mlx4_adev_cleanup(dev);
mlx4_clean_dev(dev);
priv->pci_dev_data = pci_dev_data;
priv->removed = 1;
@ -4520,6 +4555,9 @@ static int __init mlx4_init(void)
{
int ret;
WARN_ONCE(strcmp(MLX4_ADEV_NAME, KBUILD_MODNAME),
"mlx4_core name not in sync with kernel module name");
if (mlx4_verify_params())
return -EINVAL;

View file

@ -47,6 +47,8 @@
#include <linux/spinlock.h>
#include <net/devlink.h>
#include <linux/rwsem.h>
#include <linux/auxiliary_bus.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h>
@ -862,6 +864,11 @@ struct mlx4_steer {
struct list_head steer_entries[MLX4_NUM_STEERS];
};
struct mlx4_port_map {
u8 port1;
u8 port2;
};
enum {
MLX4_PCI_DEV_IS_VF = 1 << 0,
MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1,
@ -875,9 +882,9 @@ enum {
struct mlx4_priv {
struct mlx4_dev dev;
struct list_head dev_list;
struct list_head ctx_list;
spinlock_t ctx_lock;
struct mlx4_adev **adev;
int adev_idx;
struct atomic_notifier_head event_nh;
int pci_dev_data;
int removed;
@ -1045,10 +1052,13 @@ void mlx4_catas_end(struct mlx4_dev *dev);
int mlx4_crdump_init(struct mlx4_dev *dev);
void mlx4_crdump_end(struct mlx4_dev *dev);
int mlx4_restart_one(struct pci_dev *pdev);
int mlx4_adev_init(struct mlx4_dev *dev);
void mlx4_adev_cleanup(struct mlx4_dev *dev);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
unsigned long param);
void *param);
struct mlx4_dev_cap;
struct mlx4_init_hca_param;

View file

@ -49,6 +49,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/irq.h>
#include <net/xdp.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/qp.h>
@ -432,7 +433,8 @@ struct mlx4_en_dev {
unsigned long last_overflow_check;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
struct notifier_block nb;
struct notifier_block netdev_nb;
struct notifier_block mlx_nb;
};

View file

@ -33,6 +33,7 @@
#ifndef MLX4_DEVICE_H
#define MLX4_DEVICE_H
#include <linux/auxiliary_bus.h>
#include <linux/if_ether.h>
#include <linux/pci.h>
#include <linux/completion.h>
@ -889,6 +890,12 @@ struct mlx4_dev {
u8 uar_page_shift;
};
struct mlx4_adev {
struct auxiliary_device adev;
struct mlx4_dev *mdev;
int idx;
};
struct mlx4_clock_params {
u64 offset;
u8 bar;
@ -1087,6 +1094,19 @@ static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset)
(offset & (PAGE_SIZE - 1));
}
static inline int mlx4_is_bonded(struct mlx4_dev *dev)
{
return !!(dev->flags & MLX4_FLAG_BONDED);
}
static inline int mlx4_is_mf_bonded(struct mlx4_dev *dev)
{
return (mlx4_is_bonded(dev) && mlx4_is_mfunc(dev));
}
int mlx4_queue_bond_work(struct mlx4_dev *dev, int is_bonded, u8 v2p_p1,
u8 v2p_p2);
int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn);
void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn);
int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn);

View file

@ -34,8 +34,12 @@
#define MLX4_DRIVER_H
#include <net/devlink.h>
#include <linux/auxiliary_bus.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h>
#define MLX4_ADEV_NAME "mlx4_core"
struct mlx4_dev;
#define MLX4_MAC_MASK 0xffffffffffffULL
@ -54,41 +58,19 @@ enum {
MLX4_INTFF_BONDING = 1 << 0
};
struct mlx4_interface {
void * (*add) (struct mlx4_dev *dev);
void (*remove)(struct mlx4_dev *dev, void *context);
void (*event) (struct mlx4_dev *dev, void *context,
enum mlx4_dev_event event, unsigned long param);
void * (*get_dev)(struct mlx4_dev *dev, void *context, u8 port);
void (*activate)(struct mlx4_dev *dev, void *context);
struct list_head list;
struct mlx4_adrv {
struct auxiliary_driver adrv;
enum mlx4_protocol protocol;
int flags;
};
int mlx4_register_interface(struct mlx4_interface *intf);
void mlx4_unregister_interface(struct mlx4_interface *intf);
int mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv);
void mlx4_unregister_auxiliary_driver(struct mlx4_adrv *madrv);
int mlx4_bond(struct mlx4_dev *dev);
int mlx4_unbond(struct mlx4_dev *dev);
static inline int mlx4_is_bonded(struct mlx4_dev *dev)
{
return !!(dev->flags & MLX4_FLAG_BONDED);
}
static inline int mlx4_is_mf_bonded(struct mlx4_dev *dev)
{
return (mlx4_is_bonded(dev) && mlx4_is_mfunc(dev));
}
struct mlx4_port_map {
u8 port1;
u8 port2;
};
int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p);
void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port);
int mlx4_register_event_notifier(struct mlx4_dev *dev,
struct notifier_block *nb);
int mlx4_unregister_event_notifier(struct mlx4_dev *dev,
struct notifier_block *nb);
struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port);