diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4/cmd.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 196 |
1 files changed, 191 insertions, 5 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 0e572a527154..299d0184f983 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/errno.h> | 39 | #include <linux/errno.h> |
40 | 40 | ||
41 | #include <linux/mlx4/cmd.h> | 41 | #include <linux/mlx4/cmd.h> |
42 | #include <linux/mlx4/device.h> | ||
42 | #include <linux/semaphore.h> | 43 | #include <linux/semaphore.h> |
43 | #include <rdma/ib_smi.h> | 44 | #include <rdma/ib_smi.h> |
44 | 45 | ||
@@ -111,6 +112,14 @@ enum { | |||
111 | GO_BIT_TIMEOUT_MSECS = 10000 | 112 | GO_BIT_TIMEOUT_MSECS = 10000 |
112 | }; | 113 | }; |
113 | 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 | |||
114 | struct mlx4_cmd_context { | 123 | struct mlx4_cmd_context { |
115 | struct completion done; | 124 | struct completion done; |
116 | int result; | 125 | int result; |
@@ -256,6 +265,8 @@ static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, | |||
256 | 265 | ||
257 | if (!wait_for_completion_timeout(&context->done, | 266 | if (!wait_for_completion_timeout(&context->done, |
258 | msecs_to_jiffies(timeout))) { | 267 | msecs_to_jiffies(timeout))) { |
268 | mlx4_warn(dev, "communication channel command 0x%x timed out\n", | ||
269 | op); | ||
259 | err = -EBUSY; | 270 | err = -EBUSY; |
260 | goto out; | 271 | goto out; |
261 | } | 272 | } |
@@ -485,6 +496,8 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
485 | } | 496 | } |
486 | 497 | ||
487 | if (cmd_pending(dev)) { | 498 | if (cmd_pending(dev)) { |
499 | mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", | ||
500 | op); | ||
488 | err = -ETIMEDOUT; | 501 | err = -ETIMEDOUT; |
489 | goto out; | 502 | goto out; |
490 | } | 503 | } |
@@ -548,6 +561,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
548 | 561 | ||
549 | if (!wait_for_completion_timeout(&context->done, | 562 | if (!wait_for_completion_timeout(&context->done, |
550 | msecs_to_jiffies(timeout))) { | 563 | msecs_to_jiffies(timeout))) { |
564 | mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", | ||
565 | op); | ||
551 | err = -EBUSY; | 566 | err = -EBUSY; |
552 | goto out; | 567 | goto out; |
553 | } | 568 | } |
@@ -785,6 +800,15 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, | |||
785 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); | 800 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); |
786 | } | 801 | } |
787 | 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 | |||
788 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, | 812 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, |
789 | struct mlx4_vhcr *vhcr, | 813 | struct mlx4_vhcr *vhcr, |
790 | struct mlx4_cmd_mailbox *inbox, | 814 | struct mlx4_cmd_mailbox *inbox, |
@@ -1219,6 +1243,15 @@ static struct mlx4_cmd_info cmd_info[] = { | |||
1219 | .wrapper = mlx4_GEN_QP_wrapper | 1243 | .wrapper = mlx4_GEN_QP_wrapper |
1220 | }, | 1244 | }, |
1221 | { | 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 | { | ||
1222 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, | 1255 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, |
1223 | .has_inbox = false, | 1256 | .has_inbox = false, |
1224 | .has_outbox = false, | 1257 | .has_outbox = false, |
@@ -1488,6 +1521,102 @@ out: | |||
1488 | return ret; | 1521 | return ret; |
1489 | } | 1522 | } |
1490 | 1523 | ||
1524 | static int calculate_transition(u16 oper_vlan, u16 admin_vlan) | ||
1525 | { | ||
1526 | return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT)); | ||
1527 | } | ||
1528 | |||
1529 | int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, | ||
1530 | int slave, int port) | ||
1531 | { | ||
1532 | struct mlx4_vport_oper_state *vp_oper; | ||
1533 | struct mlx4_vport_state *vp_admin; | ||
1534 | struct mlx4_vf_immed_vlan_work *work; | ||
1535 | struct mlx4_dev *dev = &(priv->dev); | ||
1536 | int err; | ||
1537 | int admin_vlan_ix = NO_INDX; | ||
1538 | enum mlx4_vlan_transition vlan_trans; | ||
1539 | |||
1540 | vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
1541 | vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; | ||
1542 | |||
1543 | if (vp_oper->state.default_vlan == vp_admin->default_vlan && | ||
1544 | vp_oper->state.default_qos == vp_admin->default_qos && | ||
1545 | vp_oper->state.link_state == vp_admin->link_state) | ||
1546 | return 0; | ||
1547 | |||
1548 | vlan_trans = calculate_transition(vp_oper->state.default_vlan, | ||
1549 | vp_admin->default_vlan); | ||
1550 | |||
1551 | if (!(priv->mfunc.master.slave_state[slave].active && | ||
1552 | dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP && | ||
1553 | vlan_trans == MLX4_VLAN_TRANSITION_VST_VST)) { | ||
1554 | /* even if the UPDATE_QP command isn't supported, we still want | ||
1555 | * to set this VF link according to the admin directive | ||
1556 | */ | ||
1557 | vp_oper->state.link_state = vp_admin->link_state; | ||
1558 | return -1; | ||
1559 | } | ||
1560 | |||
1561 | mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n", | ||
1562 | slave, port); | ||
1563 | mlx4_dbg(dev, "vlan %d QoS %d link down %d\n", vp_admin->default_vlan, | ||
1564 | vp_admin->default_qos, vp_admin->link_state); | ||
1565 | |||
1566 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
1567 | if (!work) | ||
1568 | return -ENOMEM; | ||
1569 | |||
1570 | if (vp_oper->state.default_vlan != vp_admin->default_vlan) { | ||
1571 | err = __mlx4_register_vlan(&priv->dev, port, | ||
1572 | vp_admin->default_vlan, | ||
1573 | &admin_vlan_ix); | ||
1574 | if (err) { | ||
1575 | kfree(work); | ||
1576 | mlx4_warn((&priv->dev), | ||
1577 | "No vlan resources slave %d, port %d\n", | ||
1578 | slave, port); | ||
1579 | return err; | ||
1580 | } | ||
1581 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; | ||
1582 | mlx4_dbg((&(priv->dev)), | ||
1583 | "alloc vlan %d idx %d slave %d port %d\n", | ||
1584 | (int)(vp_admin->default_vlan), | ||
1585 | admin_vlan_ix, slave, port); | ||
1586 | } | ||
1587 | |||
1588 | /* save original vlan ix and vlan id */ | ||
1589 | work->orig_vlan_id = vp_oper->state.default_vlan; | ||
1590 | work->orig_vlan_ix = vp_oper->vlan_idx; | ||
1591 | |||
1592 | /* handle new qos */ | ||
1593 | if (vp_oper->state.default_qos != vp_admin->default_qos) | ||
1594 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; | ||
1595 | |||
1596 | if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) | ||
1597 | vp_oper->vlan_idx = admin_vlan_ix; | ||
1598 | |||
1599 | vp_oper->state.default_vlan = vp_admin->default_vlan; | ||
1600 | vp_oper->state.default_qos = vp_admin->default_qos; | ||
1601 | vp_oper->state.link_state = vp_admin->link_state; | ||
1602 | |||
1603 | if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE) | ||
1604 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE; | ||
1605 | |||
1606 | /* iterate over QPs owned by this slave, using UPDATE_QP */ | ||
1607 | work->port = port; | ||
1608 | work->slave = slave; | ||
1609 | work->qos = vp_oper->state.default_qos; | ||
1610 | work->vlan_id = vp_oper->state.default_vlan; | ||
1611 | work->vlan_ix = vp_oper->vlan_idx; | ||
1612 | work->priv = priv; | ||
1613 | INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); | ||
1614 | queue_work(priv->mfunc.master.comm_wq, &work->work); | ||
1615 | |||
1616 | return 0; | ||
1617 | } | ||
1618 | |||
1619 | |||
1491 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) | 1620 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) |
1492 | { | 1621 | { |
1493 | int port, err; | 1622 | int port, err; |
@@ -2102,10 +2231,12 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac) | |||
2102 | } | 2231 | } |
2103 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); | 2232 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); |
2104 | 2233 | ||
2234 | |||
2105 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | 2235 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) |
2106 | { | 2236 | { |
2107 | struct mlx4_priv *priv = mlx4_priv(dev); | 2237 | struct mlx4_priv *priv = mlx4_priv(dev); |
2108 | struct mlx4_vport_state *s_info; | 2238 | struct mlx4_vport_oper_state *vf_oper; |
2239 | struct mlx4_vport_state *vf_admin; | ||
2109 | int slave; | 2240 | int slave; |
2110 | 2241 | ||
2111 | if ((!mlx4_is_master(dev)) || | 2242 | if ((!mlx4_is_master(dev)) || |
@@ -2119,12 +2250,19 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | |||
2119 | if (slave < 0) | 2250 | if (slave < 0) |
2120 | return -EINVAL; | 2251 | return -EINVAL; |
2121 | 2252 | ||
2122 | s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; | 2253 | vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; |
2254 | vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
2255 | |||
2123 | if ((0 == vlan) && (0 == qos)) | 2256 | if ((0 == vlan) && (0 == qos)) |
2124 | s_info->default_vlan = MLX4_VGT; | 2257 | vf_admin->default_vlan = MLX4_VGT; |
2125 | else | 2258 | else |
2126 | s_info->default_vlan = vlan; | 2259 | vf_admin->default_vlan = vlan; |
2127 | s_info->default_qos = qos; | 2260 | vf_admin->default_qos = qos; |
2261 | |||
2262 | if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) | ||
2263 | mlx4_info(dev, | ||
2264 | "updating vf %d port %d config will take effect on next VF restart\n", | ||
2265 | vf, port); | ||
2128 | return 0; | 2266 | return 0; |
2129 | } | 2267 | } |
2130 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); | 2268 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); |
@@ -2178,7 +2316,55 @@ int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_in | |||
2178 | ivf->qos = s_info->default_qos; | 2316 | ivf->qos = s_info->default_qos; |
2179 | ivf->tx_rate = s_info->tx_rate; | 2317 | ivf->tx_rate = s_info->tx_rate; |
2180 | ivf->spoofchk = s_info->spoofchk; | 2318 | ivf->spoofchk = s_info->spoofchk; |
2319 | ivf->linkstate = s_info->link_state; | ||
2181 | 2320 | ||
2182 | return 0; | 2321 | return 0; |
2183 | } | 2322 | } |
2184 | EXPORT_SYMBOL_GPL(mlx4_get_vf_config); | 2323 | EXPORT_SYMBOL_GPL(mlx4_get_vf_config); |
2324 | |||
2325 | int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state) | ||
2326 | { | ||
2327 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
2328 | struct mlx4_vport_state *s_info; | ||
2329 | int slave; | ||
2330 | u8 link_stat_event; | ||
2331 | |||
2332 | slave = mlx4_get_slave_indx(dev, vf); | ||
2333 | if (slave < 0) | ||
2334 | return -EINVAL; | ||
2335 | |||
2336 | switch (link_state) { | ||
2337 | case IFLA_VF_LINK_STATE_AUTO: | ||
2338 | /* get current link state */ | ||
2339 | if (!priv->sense.do_sense_port[port]) | ||
2340 | link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; | ||
2341 | else | ||
2342 | link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; | ||
2343 | break; | ||
2344 | |||
2345 | case IFLA_VF_LINK_STATE_ENABLE: | ||
2346 | link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; | ||
2347 | break; | ||
2348 | |||
2349 | case IFLA_VF_LINK_STATE_DISABLE: | ||
2350 | link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; | ||
2351 | break; | ||
2352 | |||
2353 | default: | ||
2354 | mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", | ||
2355 | link_state, slave, port); | ||
2356 | return -EINVAL; | ||
2357 | }; | ||
2358 | s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; | ||
2359 | s_info->link_state = link_state; | ||
2360 | |||
2361 | /* send event */ | ||
2362 | mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event); | ||
2363 | |||
2364 | if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) | ||
2365 | mlx4_dbg(dev, | ||
2366 | "updating vf %d port %d no link state HW enforcment\n", | ||
2367 | vf, port); | ||
2368 | return 0; | ||
2369 | } | ||
2370 | EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); | ||