Commit 2f5bb473 authored by Jack Morgenstein's avatar Jack Morgenstein Committed by David S. Miller

mlx4: Add ref counting to port MAC table for RoCE

The IB side of RoCE requires the MAC table index of the
MAC address used by its QPs.

To obtain the real MAC index, the IB side registers the
MAC (increasing its ref count, and also returning the
real MAC index) during the modify-qp sequence.

This protects against the ETH side deleting or modifying
that MAC table entry while the QP is active.

Note that until the modify-qp command returns success,
the MAC and VLAN information only has "candidate" status.
If the modify-qp succeeds, the "candidate" info is promoted
to the operational MAC/VLAN info for the qp. If the modify fails,
the candidate MAC/VLAN is unregistered, and the old qp info
is preserved.

The patch is a bit complex, because there are multiple qp
transitions where the primary-path information may be
modified:  INIT-to-RTR, and SQD-to-SQD.

Similarly for the alternate path information.

Therefore the code must handle cases where path information
has already been entered into the QP context by previous
qp transitions.

For the MAC address, the success logic is as follows:
1. If there was no previous MAC, simply move the candidate
   MAC information to the operational information, and reset
   the candidate MAC info.
2. If there was a previous MAC, unregister it.  Then move
   the MAC information from candidate to operational, and
   reset the candidate info (as in 1. above).

The MAC address failure logic is the same for all cases:
 - Unregister the candidate MAC, and reset the candidate MAC info.

For Vlan registration, the logic is similar.
Signed-off-by: default avatarJack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6ffaeff
...@@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr { ...@@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr {
struct mlx4_rcv_tunnel_hdr tun; struct mlx4_rcv_tunnel_hdr tun;
} __packed; } __packed;
struct mlx4_roce_smac_vlan_info {
u64 smac;
int smac_index;
int smac_port;
u64 candidate_smac;
int candidate_smac_index;
int candidate_smac_port;
u16 vid;
int vlan_index;
int vlan_port;
u16 candidate_vid;
int candidate_vlan_index;
int candidate_vlan_port;
int update_vid;
};
struct mlx4_ib_qp { struct mlx4_ib_qp {
struct ib_qp ibqp; struct ib_qp ibqp;
struct mlx4_qp mqp; struct mlx4_qp mqp;
...@@ -273,8 +289,9 @@ struct mlx4_ib_qp { ...@@ -273,8 +289,9 @@ struct mlx4_ib_qp {
struct list_head gid_list; struct list_head gid_list;
struct list_head steering_rules; struct list_head steering_rules;
struct mlx4_ib_buf *sqp_proxy_rcv; struct mlx4_ib_buf *sqp_proxy_rcv;
struct mlx4_roce_smac_vlan_info pri;
struct mlx4_roce_smac_vlan_info alt;
u64 reg_id; u64 reg_id;
}; };
struct mlx4_ib_srq { struct mlx4_ib_srq {
......
This diff is collapsed.
...@@ -52,6 +52,8 @@ ...@@ -52,6 +52,8 @@
struct mac_res { struct mac_res {
struct list_head list; struct list_head list;
u64 mac; u64 mac;
int ref_count;
u8 smac_index;
u8 port; u8 port;
}; };
...@@ -1683,11 +1685,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1683,11 +1685,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err; return err;
} }
static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
u8 smac_index, u64 *mac)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
struct list_head *mac_list =
&tracker->slave_list[slave].res_list[RES_MAC];
struct mac_res *res, *tmp;
list_for_each_entry_safe(res, tmp, mac_list, list) {
if (res->smac_index == smac_index && res->port == (u8) port) {
*mac = res->mac;
return 0;
}
}
return -ENOENT;
}
static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
struct mac_res *res; struct list_head *mac_list =
&tracker->slave_list[slave].res_list[RES_MAC];
struct mac_res *res, *tmp;
list_for_each_entry_safe(res, tmp, mac_list, list) {
if (res->mac == mac && res->port == (u8) port) {
/* mac found. update ref count */
++res->ref_count;
return 0;
}
}
if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
return -EINVAL; return -EINVAL;
...@@ -1698,6 +1728,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) ...@@ -1698,6 +1728,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
} }
res->mac = mac; res->mac = mac;
res->port = (u8) port; res->port = (u8) port;
res->smac_index = smac_index;
res->ref_count = 1;
list_add_tail(&res->list, list_add_tail(&res->list,
&tracker->slave_list[slave].res_list[RES_MAC]); &tracker->slave_list[slave].res_list[RES_MAC]);
return 0; return 0;
...@@ -1714,9 +1746,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, ...@@ -1714,9 +1746,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
list_for_each_entry_safe(res, tmp, mac_list, list) { list_for_each_entry_safe(res, tmp, mac_list, list) {
if (res->mac == mac && res->port == (u8) port) { if (res->mac == mac && res->port == (u8) port) {
list_del(&res->list); if (!--res->ref_count) {
mlx4_release_resource(dev, slave, RES_MAC, 1, port); list_del(&res->list);
kfree(res); mlx4_release_resource(dev, slave, RES_MAC, 1, port);
kfree(res);
}
break; break;
} }
} }
...@@ -1729,10 +1763,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave) ...@@ -1729,10 +1763,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
struct list_head *mac_list = struct list_head *mac_list =
&tracker->slave_list[slave].res_list[RES_MAC]; &tracker->slave_list[slave].res_list[RES_MAC];
struct mac_res *res, *tmp; struct mac_res *res, *tmp;
int i;
list_for_each_entry_safe(res, tmp, mac_list, list) { list_for_each_entry_safe(res, tmp, mac_list, list) {
list_del(&res->list); list_del(&res->list);
__mlx4_unregister_mac(dev, res->port, res->mac); /* dereference the mac the num times the slave referenced it */
for (i = 0; i < res->ref_count; i++)
__mlx4_unregister_mac(dev, res->port, res->mac);
mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
kfree(res); kfree(res);
} }
...@@ -1744,6 +1781,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1744,6 +1781,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
int err = -EINVAL; int err = -EINVAL;
int port; int port;
u64 mac; u64 mac;
u8 smac_index;
if (op != RES_OP_RESERVE_AND_MAP) if (op != RES_OP_RESERVE_AND_MAP)
return err; return err;
...@@ -1753,12 +1791,13 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, ...@@ -1753,12 +1791,13 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
err = __mlx4_register_mac(dev, port, mac); err = __mlx4_register_mac(dev, port, mac);
if (err >= 0) { if (err >= 0) {
smac_index = err;
set_param_l(out_param, err); set_param_l(out_param, err);
err = 0; err = 0;
} }
if (!err) { if (!err) {
err = mac_add_to_slave(dev, slave, mac, port); err = mac_add_to_slave(dev, slave, mac, port, smac_index);
if (err) if (err)
__mlx4_unregister_mac(dev, port, mac); __mlx4_unregister_mac(dev, port, mac);
} }
...@@ -3306,6 +3345,25 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, ...@@ -3306,6 +3345,25 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
} }
static int roce_verify_mac(struct mlx4_dev *dev, int slave,
struct mlx4_qp_context *qpc,
struct mlx4_cmd_mailbox *inbox)
{
u64 mac;
int port;
u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
u8 sched = *(u8 *)(inbox->buf + 64);
u8 smac_ix;
port = (sched >> 6 & 1) + 1;
if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
return -ENOENT;
}
return 0;
}
int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr, struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox, struct mlx4_cmd_mailbox *inbox,
...@@ -3328,6 +3386,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, ...@@ -3328,6 +3386,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
if (err) if (err)
return err; return err;
if (roce_verify_mac(dev, slave, qpc, inbox))
return -EINVAL;
update_pkey_index(dev, slave, inbox); update_pkey_index(dev, slave, inbox);
update_gid(dev, inbox, (u8)slave); update_gid(dev, inbox, (u8)slave);
adjust_proxy_tun_qkey(dev, vhcr, qpc); adjust_proxy_tun_qkey(dev, vhcr, qpc);
......
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