diff options
author | Jack Morgenstein <jackm@dev.mellanox.co.il> | 2013-06-27 12:05:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-01 16:10:22 -0400 |
commit | b01978cacfd7e3a4ca703b0e48f2e18de8865df5 (patch) | |
tree | 73beae91335dbcf4a4129b3970be68f1082aff0b /drivers/net/ethernet/mellanox/mlx4/cmd.c | |
parent | 4e144d3a807d6d2aa03d2cb234d88ef1a140e8c3 (diff) |
net/mlx4_core: Dynamic VST to VST vlan/qos changes
Within VST mode, enable modifying the vlan and/or qos
for a VF without requiring unbind/rebind.
This requires firmware which supports the UPDATE_QP command.
(If the command is not available, we fall back to requiring
unbind/bind to activate these changes).
To avoid race conditions with modify-qp on QPs that are affected
by update-qp, this operation is performed on the comm_wq.
If the update operation succeeds for all the necessary QPs, a
vlan_unregister is performed for the abandoned vlan id.
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4/cmd.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 122 |
1 files changed, 117 insertions, 5 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index df04c8206ebe..7b927891dc35 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -112,6 +112,14 @@ enum { | |||
112 | GO_BIT_TIMEOUT_MSECS = 10000 | 112 | GO_BIT_TIMEOUT_MSECS = 10000 |
113 | }; | 113 | }; |
114 | 114 | ||
115 | enum mlx4_vlan_transition { | ||
116 | MLX4_VLAN_TRANSITION_VST_VST = 0, | ||
117 | MLX4_VLAN_TRANSITION_VST_VGT = 1, | ||
118 | MLX4_VLAN_TRANSITION_VGT_VST = 2, | ||
119 | MLX4_VLAN_TRANSITION_VGT_VGT = 3, | ||
120 | }; | ||
121 | |||
122 | |||
115 | struct mlx4_cmd_context { | 123 | struct mlx4_cmd_context { |
116 | struct completion done; | 124 | struct completion done; |
117 | int result; | 125 | int result; |
@@ -792,6 +800,15 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, | |||
792 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); | 800 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); |
793 | } | 801 | } |
794 | 802 | ||
803 | int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, | ||
804 | struct mlx4_vhcr *vhcr, | ||
805 | struct mlx4_cmd_mailbox *inbox, | ||
806 | struct mlx4_cmd_mailbox *outbox, | ||
807 | struct mlx4_cmd_info *cmd) | ||
808 | { | ||
809 | return -EPERM; | ||
810 | } | ||
811 | |||
795 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, | 812 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, |
796 | struct mlx4_vhcr *vhcr, | 813 | struct mlx4_vhcr *vhcr, |
797 | struct mlx4_cmd_mailbox *inbox, | 814 | struct mlx4_cmd_mailbox *inbox, |
@@ -1226,6 +1243,15 @@ static struct mlx4_cmd_info cmd_info[] = { | |||
1226 | .wrapper = mlx4_GEN_QP_wrapper | 1243 | .wrapper = mlx4_GEN_QP_wrapper |
1227 | }, | 1244 | }, |
1228 | { | 1245 | { |
1246 | .opcode = MLX4_CMD_UPDATE_QP, | ||
1247 | .has_inbox = false, | ||
1248 | .has_outbox = false, | ||
1249 | .out_is_imm = false, | ||
1250 | .encode_slave_id = false, | ||
1251 | .verify = NULL, | ||
1252 | .wrapper = MLX4_CMD_UPDATE_QP_wrapper | ||
1253 | }, | ||
1254 | { | ||
1229 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, | 1255 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, |
1230 | .has_inbox = false, | 1256 | .has_inbox = false, |
1231 | .has_outbox = false, | 1257 | .has_outbox = false, |
@@ -1495,6 +1521,72 @@ out: | |||
1495 | return ret; | 1521 | return ret; |
1496 | } | 1522 | } |
1497 | 1523 | ||
1524 | |||
1525 | int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, | ||
1526 | int slave, int port) | ||
1527 | { | ||
1528 | struct mlx4_vport_oper_state *vp_oper; | ||
1529 | struct mlx4_vport_state *vp_admin; | ||
1530 | struct mlx4_vf_immed_vlan_work *work; | ||
1531 | int err; | ||
1532 | int admin_vlan_ix = NO_INDX; | ||
1533 | |||
1534 | vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
1535 | vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; | ||
1536 | |||
1537 | if (vp_oper->state.default_vlan == vp_admin->default_vlan && | ||
1538 | vp_oper->state.default_qos == vp_admin->default_qos) | ||
1539 | return 0; | ||
1540 | |||
1541 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
1542 | if (!work) | ||
1543 | return -ENOMEM; | ||
1544 | |||
1545 | if (vp_oper->state.default_vlan != vp_admin->default_vlan) { | ||
1546 | err = __mlx4_register_vlan(&priv->dev, port, | ||
1547 | vp_admin->default_vlan, | ||
1548 | &admin_vlan_ix); | ||
1549 | if (err) { | ||
1550 | mlx4_warn((&priv->dev), | ||
1551 | "No vlan resources slave %d, port %d\n", | ||
1552 | slave, port); | ||
1553 | return err; | ||
1554 | } | ||
1555 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; | ||
1556 | mlx4_dbg((&(priv->dev)), | ||
1557 | "alloc vlan %d idx %d slave %d port %d\n", | ||
1558 | (int)(vp_admin->default_vlan), | ||
1559 | admin_vlan_ix, slave, port); | ||
1560 | } | ||
1561 | |||
1562 | /* save original vlan ix and vlan id */ | ||
1563 | work->orig_vlan_id = vp_oper->state.default_vlan; | ||
1564 | work->orig_vlan_ix = vp_oper->vlan_idx; | ||
1565 | |||
1566 | /* handle new qos */ | ||
1567 | if (vp_oper->state.default_qos != vp_admin->default_qos) | ||
1568 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; | ||
1569 | |||
1570 | if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) | ||
1571 | vp_oper->vlan_idx = admin_vlan_ix; | ||
1572 | |||
1573 | vp_oper->state.default_vlan = vp_admin->default_vlan; | ||
1574 | vp_oper->state.default_qos = vp_admin->default_qos; | ||
1575 | |||
1576 | /* iterate over QPs owned by this slave, using UPDATE_QP */ | ||
1577 | work->port = port; | ||
1578 | work->slave = slave; | ||
1579 | work->qos = vp_oper->state.default_qos; | ||
1580 | work->vlan_id = vp_oper->state.default_vlan; | ||
1581 | work->vlan_ix = vp_oper->vlan_idx; | ||
1582 | work->priv = priv; | ||
1583 | INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); | ||
1584 | queue_work(priv->mfunc.master.comm_wq, &work->work); | ||
1585 | |||
1586 | return 0; | ||
1587 | } | ||
1588 | |||
1589 | |||
1498 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) | 1590 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) |
1499 | { | 1591 | { |
1500 | int port, err; | 1592 | int port, err; |
@@ -2109,11 +2201,18 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac) | |||
2109 | } | 2201 | } |
2110 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); | 2202 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); |
2111 | 2203 | ||
2204 | static int calculate_transition(u16 oper_vlan, u16 admin_vlan) | ||
2205 | { | ||
2206 | return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT)); | ||
2207 | } | ||
2208 | |||
2112 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | 2209 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) |
2113 | { | 2210 | { |
2114 | struct mlx4_priv *priv = mlx4_priv(dev); | 2211 | struct mlx4_priv *priv = mlx4_priv(dev); |
2115 | struct mlx4_vport_state *s_info; | 2212 | struct mlx4_vport_oper_state *vf_oper; |
2213 | struct mlx4_vport_state *vf_admin; | ||
2116 | int slave; | 2214 | int slave; |
2215 | enum mlx4_vlan_transition vlan_trans; | ||
2117 | 2216 | ||
2118 | if ((!mlx4_is_master(dev)) || | 2217 | if ((!mlx4_is_master(dev)) || |
2119 | !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) | 2218 | !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) |
@@ -2126,12 +2225,25 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | |||
2126 | if (slave < 0) | 2225 | if (slave < 0) |
2127 | return -EINVAL; | 2226 | return -EINVAL; |
2128 | 2227 | ||
2129 | s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; | 2228 | vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; |
2229 | vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
2230 | |||
2130 | if ((0 == vlan) && (0 == qos)) | 2231 | if ((0 == vlan) && (0 == qos)) |
2131 | s_info->default_vlan = MLX4_VGT; | 2232 | vf_admin->default_vlan = MLX4_VGT; |
2132 | else | 2233 | else |
2133 | s_info->default_vlan = vlan; | 2234 | vf_admin->default_vlan = vlan; |
2134 | s_info->default_qos = qos; | 2235 | vf_admin->default_qos = qos; |
2236 | |||
2237 | vlan_trans = calculate_transition(vf_oper->state.default_vlan, | ||
2238 | vf_admin->default_vlan); | ||
2239 | |||
2240 | if (priv->mfunc.master.slave_state[slave].active && | ||
2241 | dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP && | ||
2242 | vlan_trans == MLX4_VLAN_TRANSITION_VST_VST) { | ||
2243 | mlx4_info(dev, "updating vf %d port %d config params immediately\n", | ||
2244 | vf, port); | ||
2245 | mlx4_master_immediate_activate_vlan_qos(priv, slave, port); | ||
2246 | } | ||
2135 | return 0; | 2247 | return 0; |
2136 | } | 2248 | } |
2137 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); | 2249 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); |