Commit 5c42b66d authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents eb660324 c138cdb8
This diff is collapsed.
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/notifier.h>
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h> #include <rdma/ib_umem.h>
...@@ -644,6 +645,7 @@ struct mlx4_ib_dev { ...@@ -644,6 +645,7 @@ struct mlx4_ib_dev {
spinlock_t reset_flow_resource_lock; spinlock_t reset_flow_resource_lock;
struct list_head qp_list; struct list_head qp_list;
struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES]; struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES];
struct notifier_block mlx_nb;
}; };
struct ib_event_work { struct ib_event_work {
......
...@@ -27,6 +27,7 @@ config MLX4_EN_DCB ...@@ -27,6 +27,7 @@ config MLX4_EN_DCB
config MLX4_CORE config MLX4_CORE
tristate tristate
depends on PCI depends on PCI
select AUXILIARY_BUS
select NET_DEVLINK select NET_DEVLINK
default n default n
......
...@@ -194,7 +194,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) ...@@ -194,7 +194,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
mutex_unlock(&persist->device_state_mutex); mutex_unlock(&persist->device_state_mutex);
/* At that step HW was already reset, now notify clients */ /* 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); mlx4_cmd_wake_completions(dev);
return; return;
......
...@@ -2113,7 +2113,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, ...@@ -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) if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
goto inform_slave_state; 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 */ /* write the version in the event field */
reply |= mlx4_comm_get_version(); reply |= mlx4_comm_get_version();
...@@ -2152,7 +2152,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, ...@@ -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)) if (mlx4_master_activate_admin_state(priv, slave))
goto reset_slave; goto reset_slave;
slave_state[slave].active = true; 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; break;
case MLX4_COMM_CMD_VHCR_POST: case MLX4_COMM_CMD_VHCR_POST:
if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
......
...@@ -183,24 +183,31 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev) ...@@ -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; struct mlx4_en_dev *mdev =
container_of(this, struct mlx4_en_dev, mlx_nb);
return endev->pndev[port]; struct mlx4_dev *dev = mdev->dev;
}
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_priv *priv; 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) { switch (event) {
case MLX4_DEV_EVENT_PORT_UP: case MLX4_DEV_EVENT_PORT_UP:
case MLX4_DEV_EVENT_PORT_DOWN: case MLX4_DEV_EVENT_PORT_DOWN:
if (!mdev->pndev[port]) if (!mdev->pndev[port])
return; return NOTIFY_DONE;
priv = netdev_priv(mdev->pndev[port]); priv = netdev_priv(mdev->pndev[port]);
/* To prevent races, we poll the link state in a separate /* To prevent races, we poll the link state in a separate
task rather than changing it here */ task rather than changing it here */
...@@ -212,23 +219,30 @@ static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, ...@@ -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"); mlx4_err(mdev, "Internal error detected, restarting device\n");
break; break;
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
case MLX4_DEV_EVENT_SLAVE_INIT: case MLX4_DEV_EVENT_SLAVE_INIT:
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN: case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
break; break;
default: default:
if (port < 1 || port > dev->caps.num_ports || if (port < 1 || port > dev->caps.num_ports ||
!mdev->pndev[port]) !mdev->pndev[port])
return; return NOTIFY_DONE;
mlx4_warn(mdev, "Unhandled event %d for port %d\n", event, mlx4_warn(mdev, "Unhandled event %d for port %d\n", (int)event,
(int) port); 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; int i;
mlx4_unregister_event_notifier(dev, &mdev->mlx_nb);
mutex_lock(&mdev->state_lock); mutex_lock(&mdev->state_lock);
mdev->device_up = false; mdev->device_up = false;
mutex_unlock(&mdev->state_lock); mutex_unlock(&mdev->state_lock);
...@@ -242,52 +256,41 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) ...@@ -242,52 +256,41 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
iounmap(mdev->uar_map); iounmap(mdev->uar_map);
mlx4_uar_free(dev, &mdev->priv_uar); mlx4_uar_free(dev, &mdev->priv_uar);
mlx4_pd_free(dev, mdev->priv_pdn); mlx4_pd_free(dev, mdev->priv_pdn);
if (mdev->nb.notifier_call) if (mdev->netdev_nb.notifier_call)
unregister_netdevice_notifier(&mdev->nb); unregister_netdevice_notifier(&mdev->netdev_nb);
kfree(mdev); kfree(mdev);
} }
static void mlx4_en_activate(struct mlx4_dev *dev, void *ctx) static int mlx4_en_probe(struct auxiliary_device *adev,
{ const struct auxiliary_device_id *id)
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)
{ {
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
struct mlx4_dev *dev = madev->mdev;
struct mlx4_en_dev *mdev; struct mlx4_en_dev *mdev;
int i; int err, i;
printk_once(KERN_INFO "%s", mlx4_en_version); printk_once(KERN_INFO "%s", mlx4_en_version);
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev) if (!mdev) {
err = -ENOMEM;
goto err_free_res; 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; 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; goto err_pd;
mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT, mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT,
PAGE_SIZE); PAGE_SIZE);
if (!mdev->uar_map) if (!mdev->uar_map) {
err = -ENOMEM;
goto err_uar; goto err_uar;
}
spin_lock_init(&mdev->uar_lock); spin_lock_init(&mdev->uar_lock);
mdev->dev = dev; mdev->dev = dev;
...@@ -299,13 +302,15 @@ static void *mlx4_en_add(struct mlx4_dev *dev) ...@@ -299,13 +302,15 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (!mdev->LSO_support) if (!mdev->LSO_support)
mlx4_warn(mdev, "LSO not supported, please upgrade to later FW version to enable LSO\n"); 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, err = mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, 0, 0,
0, 0, &mdev->mr)) { &mdev->mr);
if (err) {
mlx4_err(mdev, "Failed allocating memory region\n"); mlx4_err(mdev, "Failed allocating memory region\n");
goto err_map; 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"); mlx4_err(mdev, "Failed enabling memory region\n");
goto err_mr; goto err_mr;
} }
...@@ -325,15 +330,39 @@ static void *mlx4_en_add(struct mlx4_dev *dev) ...@@ -325,15 +330,39 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
* Note: we cannot use the shared workqueue because of deadlocks caused * Note: we cannot use the shared workqueue because of deadlocks caused
* by the rtnl lock */ * by the rtnl lock */
mdev->workqueue = create_singlethread_workqueue("mlx4_en"); mdev->workqueue = create_singlethread_workqueue("mlx4_en");
if (!mdev->workqueue) if (!mdev->workqueue) {
err = -ENOMEM;
goto err_mr; goto err_mr;
}
/* At this stage all non-port specific tasks are complete: /* At this stage all non-port specific tasks are complete:
* mark the card state as up */ * mark the card state as up */
mutex_init(&mdev->state_lock); mutex_init(&mdev->state_lock);
mdev->device_up = true; 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: err_mr:
(void) mlx4_mr_free(dev, &mdev->mr); (void) mlx4_mr_free(dev, &mdev->mr);
...@@ -347,16 +376,24 @@ static void *mlx4_en_add(struct mlx4_dev *dev) ...@@ -347,16 +376,24 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
err_free_dev: err_free_dev:
kfree(mdev); kfree(mdev);
err_free_res: err_free_res:
return NULL; return err;
} }
static struct mlx4_interface mlx4_en_interface = { static const struct auxiliary_device_id mlx4_en_id_table[] = {
.add = mlx4_en_add, { .name = MLX4_ADEV_NAME ".eth" },
.remove = mlx4_en_remove, {},
.event = mlx4_en_event, };
.get_dev = mlx4_en_get_netdev,
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, .protocol = MLX4_PROT_ETH,
.activate = mlx4_en_activate,
}; };
static void mlx4_en_verify_params(void) static void mlx4_en_verify_params(void)
...@@ -385,12 +422,12 @@ static int __init mlx4_en_init(void) ...@@ -385,12 +422,12 @@ static int __init mlx4_en_init(void)
mlx4_en_verify_params(); mlx4_en_verify_params();
mlx4_en_init_ptys2ethtool_map(); 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) 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); module_init(mlx4_en_init);
......
...@@ -2894,63 +2894,6 @@ static const struct xdp_metadata_ops mlx4_xdp_metadata_ops = { ...@@ -2894,63 +2894,6 @@ static const struct xdp_metadata_ops mlx4_xdp_metadata_ops = {
.xmo_rx_hash = mlx4_en_xdp_rx_hash, .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, int mlx4_en_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
...@@ -2960,14 +2903,13 @@ int mlx4_en_netdev_event(struct notifier_block *this, ...@@ -2960,14 +2903,13 @@ int mlx4_en_netdev_event(struct notifier_block *this,
struct mlx4_dev *dev; struct mlx4_dev *dev;
int i, num_eth_ports = 0; int i, num_eth_ports = 0;
bool do_bond = true; bool do_bond = true;
struct mlx4_en_priv *priv;
u8 v2p_port1 = 0; u8 v2p_port1 = 0;
u8 v2p_port2 = 0; u8 v2p_port2 = 0;
if (!net_eq(dev_net(ndev), &init_net)) if (!net_eq(dev_net(ndev), &init_net))
return NOTIFY_DONE; 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; dev = mdev->dev;
/* Go into this mode only when two network devices set on two ports /* 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, ...@@ -2995,7 +2937,6 @@ int mlx4_en_netdev_event(struct notifier_block *this,
if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port) if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port)
return NOTIFY_DONE; return NOTIFY_DONE;
priv = netdev_priv(ndev);
if (do_bond) { if (do_bond) {
struct netdev_notifier_bonding_info *notifier_info = ptr; struct netdev_notifier_bonding_info *notifier_info = ptr;
struct netdev_bonding_info *bonding_info = struct netdev_bonding_info *bonding_info =
...@@ -3062,8 +3003,7 @@ int mlx4_en_netdev_event(struct notifier_block *this, ...@@ -3062,8 +3003,7 @@ int mlx4_en_netdev_event(struct notifier_block *this,
} }
} }
mlx4_en_queue_bond_work(priv, do_bond, mlx4_queue_bond_work(dev, do_bond, v2p_port1, v2p_port2);
v2p_port1, v2p_port2);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
...@@ -501,7 +501,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) ...@@ -501,7 +501,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
int port; int port;
int slave = 0; int slave = 0;
int ret; int ret;
u32 flr_slave; int flr_slave;
u8 update_slave_state; u8 update_slave_state;
int i; int i;
enum slave_port_gen_event gen_event; enum slave_port_gen_event gen_event;
...@@ -606,8 +606,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) ...@@ -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; port = be32_to_cpu(eqe->event.port_change.port) >> 28;
slaves_port = mlx4_phys_to_slaves_pport(dev, port); slaves_port = mlx4_phys_to_slaves_pport(dev, port);
if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, mlx4_dispatch_event(
port); dev, MLX4_DEV_EVENT_PORT_DOWN, &port);
mlx4_priv(dev)->sense.do_sense_port[port] = 1; mlx4_priv(dev)->sense.do_sense_port[port] = 1;
if (!mlx4_is_master(dev)) if (!mlx4_is_master(dev))
break; break;
...@@ -647,7 +647,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) ...@@ -647,7 +647,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
} }
} }
} else { } 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; 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) ...@@ -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); spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN,
flr_slave); &flr_slave);
queue_work(priv->mfunc.master.comm_wq, queue_work(priv->mfunc.master.comm_wq,
&priv->mfunc.master.slave_flr_event_work); &priv->mfunc.master.slave_flr_event_work);
break; break;
...@@ -787,8 +788,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) ...@@ -787,8 +788,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
break; break;
case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT: case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT:
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, mlx4_dispatch_event(
(unsigned long) eqe); dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, eqe);
break; break;
case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT: case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT:
......
This diff is collapsed.
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io-mapping.h> #include <linux/io-mapping.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kmod.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/devlink.h> #include <net/devlink.h>
...@@ -1091,27 +1090,6 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) ...@@ -1091,27 +1090,6 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
return err; 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. * Change the port configuration of the device.
* Every user of this function must hold the port mutex. * Every user of this function must hold the port mutex.
...@@ -1147,7 +1125,6 @@ int mlx4_change_port_types(struct mlx4_dev *dev, ...@@ -1147,7 +1125,6 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
mlx4_err(dev, "Failed to register device\n"); mlx4_err(dev, "Failed to register device\n");
goto out; goto out;
} }
mlx4_request_modules(dev);
} }
out: out:
...@@ -1441,7 +1418,7 @@ static int mlx4_mf_unbond(struct mlx4_dev *dev) ...@@ -1441,7 +1418,7 @@ static int mlx4_mf_unbond(struct mlx4_dev *dev)
return ret; return ret;
} }
int mlx4_bond(struct mlx4_dev *dev) static int mlx4_bond(struct mlx4_dev *dev)
{ {
int ret = 0; int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
...@@ -1467,9 +1444,8 @@ int mlx4_bond(struct mlx4_dev *dev) ...@@ -1467,9 +1444,8 @@ int mlx4_bond(struct mlx4_dev *dev)
return ret; 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; int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
...@@ -1496,10 +1472,8 @@ int mlx4_unbond(struct mlx4_dev *dev) ...@@ -1496,10 +1472,8 @@ int mlx4_unbond(struct mlx4_dev *dev)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(mlx4_unbond);
static int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
{ {
u8 port1 = v2p->port1; u8 port1 = v2p->port1;
u8 port2 = v2p->port2; u8 port2 = v2p->port2;
...@@ -1541,7 +1515,61 @@ int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p) ...@@ -1541,7 +1515,61 @@ int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
mutex_unlock(&priv->bond_mutex); mutex_unlock(&priv->bond_mutex);
return err; 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) 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, ...@@ -3375,8 +3403,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
devl_assert_locked(devlink); devl_assert_locked(devlink);
dev = &priv->dev; dev = &priv->dev;
INIT_LIST_HEAD(&priv->ctx_list); err = mlx4_adev_init(dev);
spin_lock_init(&priv->ctx_lock); if (err)
return err;
ATOMIC_INIT_NOTIFIER_HEAD(&priv->event_nh);
mutex_init(&priv->port_mutex); mutex_init(&priv->port_mutex);
mutex_init(&priv->bond_mutex); mutex_init(&priv->bond_mutex);
...@@ -3402,10 +3433,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, ...@@ -3402,10 +3433,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
err = mlx4_get_ownership(dev); err = mlx4_get_ownership(dev);
if (err) { if (err) {
if (err < 0) if (err < 0)
return err; goto err_adev;
else { else {
mlx4_warn(dev, "Multiple PFs not yet supported - Skipping PF\n"); 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, ...@@ -3674,8 +3706,6 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
if (err) if (err)
goto err_port; goto err_port;
mlx4_request_modules(dev);
mlx4_sense_init(dev); mlx4_sense_init(dev);
mlx4_start_sense(dev); mlx4_start_sense(dev);
...@@ -3753,6 +3783,9 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, ...@@ -3753,6 +3783,9 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
mlx4_free_ownership(dev); mlx4_free_ownership(dev);
kfree(dev_cap); kfree(dev_cap);
err_adev:
mlx4_adev_cleanup(dev);
return err; return err;
} }
...@@ -4133,6 +4166,8 @@ static void mlx4_unload_one(struct pci_dev *pdev) ...@@ -4133,6 +4166,8 @@ static void mlx4_unload_one(struct pci_dev *pdev)
mlx4_slave_destroy_special_qp_cap(dev); mlx4_slave_destroy_special_qp_cap(dev);
kfree(dev->dev_vfs); kfree(dev->dev_vfs);
mlx4_adev_cleanup(dev);
mlx4_clean_dev(dev); mlx4_clean_dev(dev);
priv->pci_dev_data = pci_dev_data; priv->pci_dev_data = pci_dev_data;
priv->removed = 1; priv->removed = 1;
...@@ -4520,6 +4555,9 @@ static int __init mlx4_init(void) ...@@ -4520,6 +4555,9 @@ static int __init mlx4_init(void)
{ {
int ret; int ret;
WARN_ONCE(strcmp(MLX4_ADEV_NAME, KBUILD_MODNAME),
"mlx4_core name not in sync with kernel module name");
if (mlx4_verify_params()) if (mlx4_verify_params())
return -EINVAL; return -EINVAL;
......
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <net/devlink.h> #include <net/devlink.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/auxiliary_bus.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h> #include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h> #include <linux/mlx4/driver.h>
...@@ -862,6 +864,11 @@ struct mlx4_steer { ...@@ -862,6 +864,11 @@ struct mlx4_steer {
struct list_head steer_entries[MLX4_NUM_STEERS]; struct list_head steer_entries[MLX4_NUM_STEERS];
}; };
struct mlx4_port_map {
u8 port1;
u8 port2;
};
enum { enum {
MLX4_PCI_DEV_IS_VF = 1 << 0, MLX4_PCI_DEV_IS_VF = 1 << 0,
MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1, MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1,
...@@ -875,9 +882,9 @@ enum { ...@@ -875,9 +882,9 @@ enum {
struct mlx4_priv { struct mlx4_priv {
struct mlx4_dev dev; struct mlx4_dev dev;
struct list_head dev_list; struct mlx4_adev **adev;
struct list_head ctx_list; int adev_idx;
spinlock_t ctx_lock; struct atomic_notifier_head event_nh;
int pci_dev_data; int pci_dev_data;
int removed; int removed;
...@@ -1045,10 +1052,13 @@ void mlx4_catas_end(struct mlx4_dev *dev); ...@@ -1045,10 +1052,13 @@ void mlx4_catas_end(struct mlx4_dev *dev);
int mlx4_crdump_init(struct mlx4_dev *dev); int mlx4_crdump_init(struct mlx4_dev *dev);
void mlx4_crdump_end(struct mlx4_dev *dev); void mlx4_crdump_end(struct mlx4_dev *dev);
int mlx4_restart_one(struct pci_dev *pdev); 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); int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_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, void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
unsigned long param); void *param);
struct mlx4_dev_cap; struct mlx4_dev_cap;
struct mlx4_init_hca_param; struct mlx4_init_hca_param;
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <net/xdp.h> #include <net/xdp.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h> #include <linux/mlx4/device.h>
#include <linux/mlx4/qp.h> #include <linux/mlx4/qp.h>
...@@ -432,7 +433,8 @@ struct mlx4_en_dev { ...@@ -432,7 +433,8 @@ struct mlx4_en_dev {
unsigned long last_overflow_check; unsigned long last_overflow_check;
struct ptp_clock *ptp_clock; struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info; struct ptp_clock_info ptp_clock_info;
struct notifier_block nb; struct notifier_block netdev_nb;
struct notifier_block mlx_nb;
}; };
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#ifndef MLX4_DEVICE_H #ifndef MLX4_DEVICE_H
#define MLX4_DEVICE_H #define MLX4_DEVICE_H
#include <linux/auxiliary_bus.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/completion.h> #include <linux/completion.h>
...@@ -889,6 +890,12 @@ struct mlx4_dev { ...@@ -889,6 +890,12 @@ struct mlx4_dev {
u8 uar_page_shift; u8 uar_page_shift;
}; };
struct mlx4_adev {
struct auxiliary_device adev;
struct mlx4_dev *mdev;
int idx;
};
struct mlx4_clock_params { struct mlx4_clock_params {
u64 offset; u64 offset;
u8 bar; u8 bar;
...@@ -1087,6 +1094,19 @@ static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset) ...@@ -1087,6 +1094,19 @@ static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset)
(offset & (PAGE_SIZE - 1)); (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); int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn);
void mlx4_pd_free(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); int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn);
......
...@@ -34,8 +34,12 @@ ...@@ -34,8 +34,12 @@
#define MLX4_DRIVER_H #define MLX4_DRIVER_H
#include <net/devlink.h> #include <net/devlink.h>
#include <linux/auxiliary_bus.h>
#include <linux/notifier.h>
#include <linux/mlx4/device.h> #include <linux/mlx4/device.h>
#define MLX4_ADEV_NAME "mlx4_core"
struct mlx4_dev; struct mlx4_dev;
#define MLX4_MAC_MASK 0xffffffffffffULL #define MLX4_MAC_MASK 0xffffffffffffULL
...@@ -54,41 +58,19 @@ enum { ...@@ -54,41 +58,19 @@ enum {
MLX4_INTFF_BONDING = 1 << 0 MLX4_INTFF_BONDING = 1 << 0
}; };
struct mlx4_interface { struct mlx4_adrv {
void * (*add) (struct mlx4_dev *dev); struct auxiliary_driver adrv;
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;
enum mlx4_protocol protocol; enum mlx4_protocol protocol;
int flags; int flags;
}; };
int mlx4_register_interface(struct mlx4_interface *intf); int mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv);
void mlx4_unregister_interface(struct mlx4_interface *intf); 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); struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment