diff options
| author | Yevgeny Petrilin <yevgenyp@mellanox.com> | 2013-07-28 11:54:21 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-07-29 04:12:40 -0400 |
| commit | fe6f700d6cbb7e8a61711e325f53d9c9e0a42a4c (patch) | |
| tree | 1a3d5b95434519950cb10ed9e51b50c2583e53fd | |
| parent | 2d4b646613d6b12175b017aca18113945af1faf3 (diff) | |
net/mlx4_core: Respond to operation request by firmware
This commit adds new firmware command and new firmware event. The firmware
raises the MLX4_EVENT_TYPE_OP_REQUIRED event in order to signal the driver it
needs to perform an administrative operation throughout the MLX4_CMD_GET_OP_REQ
command. At the moment the supported operation is adding/removing multicast
entries which are used by the firmware for handling NCSI traffic in B0
steering mode.
Also, had to swap the order of mlx4_init_mcg_table() and
mlx4_init_eq_table() to make sure that driver will get events only after
resources are initialized to handle it.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.com>
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 18 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/eq.c | 9 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/fw.c | 104 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/fw.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/main.c | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mcg.c | 11 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4.h | 13 | ||||
| -rw-r--r-- | include/linux/mlx4/cmd.h | 1 | ||||
| -rw-r--r-- | include/linux/mlx4/device.h | 1 |
9 files changed, 166 insertions, 27 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 299d0184f983..141322c31ae9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
| @@ -809,6 +809,15 @@ int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, | |||
| 809 | return -EPERM; | 809 | return -EPERM; |
| 810 | } | 810 | } |
| 811 | 811 | ||
| 812 | int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave, | ||
| 813 | struct mlx4_vhcr *vhcr, | ||
| 814 | struct mlx4_cmd_mailbox *inbox, | ||
| 815 | struct mlx4_cmd_mailbox *outbox, | ||
| 816 | struct mlx4_cmd_info *cmd) | ||
| 817 | { | ||
| 818 | return -EPERM; | ||
| 819 | } | ||
| 820 | |||
| 812 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, | 821 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, |
| 813 | struct mlx4_vhcr *vhcr, | 822 | struct mlx4_vhcr *vhcr, |
| 814 | struct mlx4_cmd_mailbox *inbox, | 823 | struct mlx4_cmd_mailbox *inbox, |
| @@ -1252,6 +1261,15 @@ static struct mlx4_cmd_info cmd_info[] = { | |||
| 1252 | .wrapper = MLX4_CMD_UPDATE_QP_wrapper | 1261 | .wrapper = MLX4_CMD_UPDATE_QP_wrapper |
| 1253 | }, | 1262 | }, |
| 1254 | { | 1263 | { |
| 1264 | .opcode = MLX4_CMD_GET_OP_REQ, | ||
| 1265 | .has_inbox = false, | ||
| 1266 | .has_outbox = false, | ||
| 1267 | .out_is_imm = false, | ||
| 1268 | .encode_slave_id = false, | ||
| 1269 | .verify = NULL, | ||
| 1270 | .wrapper = MLX4_CMD_GET_OP_REQ_wrapper, | ||
| 1271 | }, | ||
| 1272 | { | ||
| 1255 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, | 1273 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, |
| 1256 | .has_inbox = false, | 1274 | .has_inbox = false, |
| 1257 | .has_outbox = false, | 1275 | .has_outbox = false, |
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 7e042869ef0c..0416c5b3b35c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c | |||
| @@ -79,6 +79,7 @@ enum { | |||
| 79 | (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ | 79 | (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ |
| 80 | (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ | 80 | (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ |
| 81 | (1ull << MLX4_EVENT_TYPE_CMD) | \ | 81 | (1ull << MLX4_EVENT_TYPE_CMD) | \ |
| 82 | (1ull << MLX4_EVENT_TYPE_OP_REQUIRED) | \ | ||
| 82 | (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ | 83 | (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ |
| 83 | (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ | 84 | (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ |
| 84 | (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) | 85 | (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) |
| @@ -629,6 +630,14 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) | |||
| 629 | mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); | 630 | mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); |
| 630 | break; | 631 | break; |
| 631 | 632 | ||
| 633 | case MLX4_EVENT_TYPE_OP_REQUIRED: | ||
| 634 | atomic_inc(&priv->opreq_count); | ||
| 635 | /* FW commands can't be executed from interrupt context | ||
| 636 | * working in deferred task | ||
| 637 | */ | ||
| 638 | queue_work(mlx4_wq, &priv->opreq_task); | ||
| 639 | break; | ||
| 640 | |||
| 632 | case MLX4_EVENT_TYPE_COMM_CHANNEL: | 641 | case MLX4_EVENT_TYPE_COMM_CHANNEL: |
| 633 | if (!mlx4_is_master(dev)) { | 642 | if (!mlx4_is_master(dev)) { |
| 634 | mlx4_warn(dev, "Received comm channel event " | 643 | mlx4_warn(dev, "Received comm channel event " |
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 8873d6802c80..aec6f5802da5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c | |||
| @@ -1705,3 +1705,107 @@ int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) | |||
| 1705 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); | 1705 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); |
| 1706 | } | 1706 | } |
| 1707 | EXPORT_SYMBOL_GPL(mlx4_wol_write); | 1707 | EXPORT_SYMBOL_GPL(mlx4_wol_write); |
| 1708 | |||
| 1709 | enum { | ||
| 1710 | ADD_TO_MCG = 0x26, | ||
| 1711 | }; | ||
| 1712 | |||
| 1713 | |||
| 1714 | void mlx4_opreq_action(struct work_struct *work) | ||
| 1715 | { | ||
| 1716 | struct mlx4_priv *priv = container_of(work, struct mlx4_priv, | ||
| 1717 | opreq_task); | ||
| 1718 | struct mlx4_dev *dev = &priv->dev; | ||
| 1719 | int num_tasks = atomic_read(&priv->opreq_count); | ||
| 1720 | struct mlx4_cmd_mailbox *mailbox; | ||
| 1721 | struct mlx4_mgm *mgm; | ||
| 1722 | u32 *outbox; | ||
| 1723 | u32 modifier; | ||
| 1724 | u16 token; | ||
| 1725 | u16 type_m; | ||
| 1726 | u16 type; | ||
| 1727 | int err; | ||
| 1728 | u32 num_qps; | ||
| 1729 | struct mlx4_qp qp; | ||
| 1730 | int i; | ||
| 1731 | u8 rem_mcg; | ||
| 1732 | u8 prot; | ||
| 1733 | |||
| 1734 | #define GET_OP_REQ_MODIFIER_OFFSET 0x08 | ||
| 1735 | #define GET_OP_REQ_TOKEN_OFFSET 0x14 | ||
| 1736 | #define GET_OP_REQ_TYPE_OFFSET 0x1a | ||
| 1737 | #define GET_OP_REQ_DATA_OFFSET 0x20 | ||
| 1738 | |||
| 1739 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
| 1740 | if (IS_ERR(mailbox)) { | ||
| 1741 | mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n"); | ||
| 1742 | return; | ||
| 1743 | } | ||
| 1744 | outbox = mailbox->buf; | ||
| 1745 | |||
| 1746 | while (num_tasks) { | ||
| 1747 | err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, | ||
| 1748 | MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, | ||
| 1749 | MLX4_CMD_NATIVE); | ||
| 1750 | if (err) { | ||
| 1751 | mlx4_err(dev, "Failed to retreive required operation: %d\n", | ||
| 1752 | err); | ||
| 1753 | return; | ||
| 1754 | } | ||
| 1755 | MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET); | ||
| 1756 | MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET); | ||
| 1757 | MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET); | ||
| 1758 | type_m = type >> 12; | ||
| 1759 | type &= 0xfff; | ||
| 1760 | |||
| 1761 | switch (type) { | ||
| 1762 | case ADD_TO_MCG: | ||
| 1763 | if (dev->caps.steering_mode == | ||
| 1764 | MLX4_STEERING_MODE_DEVICE_MANAGED) { | ||
| 1765 | mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n"); | ||
| 1766 | err = EPERM; | ||
| 1767 | break; | ||
| 1768 | } | ||
| 1769 | mgm = (struct mlx4_mgm *)((u8 *)(outbox) + | ||
| 1770 | GET_OP_REQ_DATA_OFFSET); | ||
| 1771 | num_qps = be32_to_cpu(mgm->members_count) & | ||
| 1772 | MGM_QPN_MASK; | ||
| 1773 | rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1; | ||
| 1774 | prot = ((u8 *)(&mgm->members_count))[0] >> 6; | ||
| 1775 | |||
| 1776 | for (i = 0; i < num_qps; i++) { | ||
| 1777 | qp.qpn = be32_to_cpu(mgm->qp[i]); | ||
| 1778 | if (rem_mcg) | ||
| 1779 | err = mlx4_multicast_detach(dev, &qp, | ||
| 1780 | mgm->gid, | ||
| 1781 | prot, 0); | ||
| 1782 | else | ||
| 1783 | err = mlx4_multicast_attach(dev, &qp, | ||
| 1784 | mgm->gid, | ||
| 1785 | mgm->gid[5] | ||
| 1786 | , 0, prot, | ||
| 1787 | NULL); | ||
| 1788 | if (err) | ||
| 1789 | break; | ||
| 1790 | } | ||
| 1791 | break; | ||
| 1792 | default: | ||
| 1793 | mlx4_warn(dev, "Bad type for required operation\n"); | ||
| 1794 | err = EINVAL; | ||
| 1795 | break; | ||
| 1796 | } | ||
