Commit fc06573d authored by Jack Morgenstein's avatar Jack Morgenstein Committed by Roland Dreier

IB/mlx4: Initialize SR-IOV IB support for slaves in master context

Allocate SR-IOV paravirtualization resources and MAD demuxing contexts
on the master.

This has two parts.  The first part is to initialize the structures to
contain the contexts.  This is done at master startup time in
mlx4_ib_init_sriov().

The second part is to actually create the tunneling resources required
on the master to support a slave.  This is performed the master
detects that a slave has started up (MLX4_DEV_EVENT_SLAVE_INIT event
generated when a slave initializes its comm channel).

For the master, there is no such startup event, so it creates its own
tunneling resources when it starts up.  In addition, the master also
creates the real special QPs.  The ib_core layer on the master causes
creation of proxy special QPs, since the master is also
paravirtualized at the ib_core layer.
Signed-off-by: default avatarJack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent e2c76824
This diff is collapsed.
...@@ -1357,11 +1357,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ...@@ -1357,11 +1357,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_ib_mad_init(ibdev)) if (mlx4_ib_mad_init(ibdev))
goto err_reg; goto err_reg;
if (mlx4_ib_init_sriov(ibdev))
goto err_mad;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE && !iboe->nb.notifier_call) { if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE && !iboe->nb.notifier_call) {
iboe->nb.notifier_call = mlx4_ib_netdev_event; iboe->nb.notifier_call = mlx4_ib_netdev_event;
err = register_netdevice_notifier(&iboe->nb); err = register_netdevice_notifier(&iboe->nb);
if (err) if (err)
goto err_reg; goto err_sriov;
} }
for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) {
...@@ -1379,6 +1382,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ...@@ -1379,6 +1382,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
pr_warn("failure unregistering notifier\n"); pr_warn("failure unregistering notifier\n");
flush_workqueue(wq); flush_workqueue(wq);
err_sriov:
mlx4_ib_close_sriov(ibdev);
err_mad:
mlx4_ib_mad_cleanup(ibdev);
err_reg: err_reg:
ib_unregister_device(&ibdev->ib_dev); ib_unregister_device(&ibdev->ib_dev);
...@@ -1407,6 +1416,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) ...@@ -1407,6 +1416,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
struct mlx4_ib_dev *ibdev = ibdev_ptr; struct mlx4_ib_dev *ibdev = ibdev_ptr;
int p; int p;
mlx4_ib_close_sriov(ibdev);
mlx4_ib_mad_cleanup(ibdev); mlx4_ib_mad_cleanup(ibdev);
ib_unregister_device(&ibdev->ib_dev); ib_unregister_device(&ibdev->ib_dev);
if (ibdev->iboe.nb.notifier_call) { if (ibdev->iboe.nb.notifier_call) {
...@@ -1428,6 +1438,51 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) ...@@ -1428,6 +1438,51 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
ib_dealloc_device(&ibdev->ib_dev); ib_dealloc_device(&ibdev->ib_dev);
} }
static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
{
struct mlx4_ib_demux_work **dm = NULL;
struct mlx4_dev *dev = ibdev->dev;
int i;
unsigned long flags;
if (!mlx4_is_master(dev))
return;
dm = kcalloc(dev->caps.num_ports, sizeof *dm, GFP_ATOMIC);
if (!dm) {
pr_err("failed to allocate memory for tunneling qp update\n");
goto out;
}
for (i = 0; i < dev->caps.num_ports; i++) {
dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
if (!dm[i]) {
pr_err("failed to allocate memory for tunneling qp update work struct\n");
for (i = 0; i < dev->caps.num_ports; i++) {
if (dm[i])
kfree(dm[i]);
}
goto out;
}
}
/* initialize or tear down tunnel QPs for the slave */
for (i = 0; i < dev->caps.num_ports; i++) {
INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
dm[i]->port = i + 1;
dm[i]->slave = slave;
dm[i]->do_init = do_init;
dm[i]->dev = ibdev;
spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
if (!ibdev->sriov.is_going_down)
queue_work(ibdev->sriov.demux[i].ud_wq, &dm[i]->work);
spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
}
out:
if (dm)
kfree(dm);
return;
}
static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
enum mlx4_dev_event event, unsigned long param) enum mlx4_dev_event event, unsigned long param)
{ {
...@@ -1435,22 +1490,23 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, ...@@ -1435,22 +1490,23 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr); struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr);
struct mlx4_eqe *eqe = NULL; struct mlx4_eqe *eqe = NULL;
struct ib_event_work *ew; struct ib_event_work *ew;
int port = 0; int p = 0;
if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE) if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE)
eqe = (struct mlx4_eqe *)param; eqe = (struct mlx4_eqe *)param;
else else
port = (u8)param; p = (int) param;
if (port > ibdev->num_ports)
return;
switch (event) { switch (event) {
case MLX4_DEV_EVENT_PORT_UP: case MLX4_DEV_EVENT_PORT_UP:
if (p > ibdev->num_ports)
return;
ibev.event = IB_EVENT_PORT_ACTIVE; ibev.event = IB_EVENT_PORT_ACTIVE;
break; break;
case MLX4_DEV_EVENT_PORT_DOWN: case MLX4_DEV_EVENT_PORT_DOWN:
if (p > ibdev->num_ports)
return;
ibev.event = IB_EVENT_PORT_ERR; ibev.event = IB_EVENT_PORT_ERR;
break; break;
...@@ -1472,12 +1528,22 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, ...@@ -1472,12 +1528,22 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
handle_port_mgmt_change_event(&ew->work); handle_port_mgmt_change_event(&ew->work);
return; return;
case MLX4_DEV_EVENT_SLAVE_INIT:
/* here, p is the slave id */
do_slave_init(ibdev, p, 1);
return;
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
/* here, p is the slave id */
do_slave_init(ibdev, p, 0);
return;
default: default:
return; return;
} }
ibev.device = ibdev_ptr; ibev.device = ibdev_ptr;
ibev.element.port_num = port; ibev.element.port_num = (u8) p;
ib_dispatch_event(&ibev); ib_dispatch_event(&ibev);
} }
......
...@@ -176,6 +176,10 @@ enum mlx4_ib_qp_type { ...@@ -176,6 +176,10 @@ enum mlx4_ib_qp_type {
MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER | \ MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER | \
MLX4_IB_QPT_TUN_SMI | MLX4_IB_QPT_TUN_GSI) MLX4_IB_QPT_TUN_SMI | MLX4_IB_QPT_TUN_GSI)
enum {
MLX4_NUM_TUNNEL_BUFS = 256,
};
struct mlx4_ib_tunnel_header { struct mlx4_ib_tunnel_header {
struct mlx4_av av; struct mlx4_av av;
__be32 remote_qpn; __be32 remote_qpn;
...@@ -263,6 +267,15 @@ struct mlx4_ib_ah { ...@@ -263,6 +267,15 @@ struct mlx4_ib_ah {
union mlx4_ext_av av; union mlx4_ext_av av;
}; };
struct mlx4_ib_demux_work {
struct work_struct work;
struct mlx4_ib_dev *dev;
int slave;
int do_init;
u8 port;
};
struct mlx4_ib_tun_tx_buf { struct mlx4_ib_tun_tx_buf {
struct mlx4_ib_buf buf; struct mlx4_ib_buf buf;
struct ib_ah *ah; struct ib_ah *ah;
...@@ -278,9 +291,17 @@ struct mlx4_ib_demux_pv_qp { ...@@ -278,9 +291,17 @@ struct mlx4_ib_demux_pv_qp {
unsigned tx_ix_tail; unsigned tx_ix_tail;
}; };
enum mlx4_ib_demux_pv_state {
DEMUX_PV_STATE_DOWN,
DEMUX_PV_STATE_STARTING,
DEMUX_PV_STATE_ACTIVE,
DEMUX_PV_STATE_DOWNING,
};
struct mlx4_ib_demux_pv_ctx { struct mlx4_ib_demux_pv_ctx {
int port; int port;
int slave; int slave;
enum mlx4_ib_demux_pv_state state;
int has_smi; int has_smi;
struct ib_device *ib_dev; struct ib_device *ib_dev;
struct ib_cq *cq; struct ib_cq *cq;
...@@ -319,6 +340,13 @@ struct mlx4_ib_iboe { ...@@ -319,6 +340,13 @@ struct mlx4_ib_iboe {
union ib_gid gid_table[MLX4_MAX_PORTS][128]; union ib_gid gid_table[MLX4_MAX_PORTS][128];
}; };
struct pkey_mgt {
u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
u16 phys_pkey_cache[MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
struct list_head pkey_port_list[MLX4_MFUNC_MAX];
struct kobject *device_parent[MLX4_MFUNC_MAX];
};
struct mlx4_ib_dev { struct mlx4_ib_dev {
struct ib_device ib_dev; struct ib_device ib_dev;
struct mlx4_dev *dev; struct mlx4_dev *dev;
...@@ -340,6 +368,7 @@ struct mlx4_ib_dev { ...@@ -340,6 +368,7 @@ struct mlx4_ib_dev {
int counters[MLX4_MAX_PORTS]; int counters[MLX4_MAX_PORTS];
int *eq_table; int *eq_table;
int eq_added; int eq_added;
struct pkey_mgt pkeys;
}; };
struct ib_event_work { struct ib_event_work {
...@@ -424,6 +453,9 @@ static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah) ...@@ -424,6 +453,9 @@ static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah)
return container_of(ibah, struct mlx4_ib_ah, ibah); return container_of(ibah, struct mlx4_ib_ah, ibah);
} }
int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev);
void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev);
int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
struct mlx4_db *db); struct mlx4_db *db);
void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db); void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db);
...@@ -515,4 +547,6 @@ int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, ...@@ -515,4 +547,6 @@ int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num,
enum ib_event_type type); enum ib_event_type type);
void mlx4_ib_tunnels_update_work(struct work_struct *work);
#endif /* MLX4_IB_H */ #endif /* MLX4_IB_H */
...@@ -1340,6 +1340,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, ...@@ -1340,6 +1340,8 @@ 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);
/* write the version in the event field */ /* write the version in the event field */
reply |= mlx4_comm_get_version(); reply |= mlx4_comm_get_version();
...@@ -1376,6 +1378,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, ...@@ -1376,6 +1378,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
goto reset_slave; goto reset_slave;
slave_state[slave].vhcr_dma |= param; slave_state[slave].vhcr_dma |= param;
slave_state[slave].active = true; slave_state[slave].active = true;
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) &&
......
...@@ -54,7 +54,8 @@ enum { ...@@ -54,7 +54,8 @@ enum {
}; };
enum { enum {
MLX4_MAX_PORTS = 2 MLX4_MAX_PORTS = 2,
MLX4_MAX_PORT_PKEYS = 128
}; };
/* base qkey for use in sriov tunnel-qp/proxy-qp communication. /* base qkey for use in sriov tunnel-qp/proxy-qp communication.
......
...@@ -45,6 +45,8 @@ enum mlx4_dev_event { ...@@ -45,6 +45,8 @@ enum mlx4_dev_event {
MLX4_DEV_EVENT_PORT_DOWN, MLX4_DEV_EVENT_PORT_DOWN,
MLX4_DEV_EVENT_PORT_REINIT, MLX4_DEV_EVENT_PORT_REINIT,
MLX4_DEV_EVENT_PORT_MGMT_CHANGE, MLX4_DEV_EVENT_PORT_MGMT_CHANGE,
MLX4_DEV_EVENT_SLAVE_INIT,
MLX4_DEV_EVENT_SLAVE_SHUTDOWN,
}; };
struct mlx4_interface { struct mlx4_interface {
......
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