mlx4: Add infrastructure for selecting VFs to enable QP0 via MLX proxy QPs
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / fw.c
index 7e2995e..01e6dd6 100644 (file)
@@ -178,8 +178,8 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                                struct mlx4_cmd_info *cmd)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       u8      field;
-       u32     size;
+       u8      field, port;
+       u32     size, proxy_qp, qkey;
        int     err = 0;
 
 #define QUERY_FUNC_CAP_FLAGS_OFFSET            0x0
@@ -209,6 +209,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
 
 /* when opcode modifier = 1 */
 #define QUERY_FUNC_CAP_PHYS_PORT_OFFSET                0x3
+#define QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET     0x4
 #define QUERY_FUNC_CAP_FLAGS0_OFFSET           0x8
 #define QUERY_FUNC_CAP_FLAGS1_OFFSET           0xc
 
@@ -221,40 +222,64 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
 #define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC                0x40
 #define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN       0x80
 #define QUERY_FUNC_CAP_FLAGS1_NIC_INFO                 0x10
+#define QUERY_FUNC_CAP_VF_ENABLE_QP0           0x08
 
 #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
 
        if (vhcr->op_modifier == 1) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, slave);
+               int converted_port = mlx4_slave_convert_port(
+                               dev, slave, vhcr->in_modifier);
+
+               if (converted_port < 0)
+                       return -EINVAL;
+
+               vhcr->in_modifier = converted_port;
+               /* phys-port = logical-port */
+               field = vhcr->in_modifier -
+                       find_first_bit(actv_ports.ports, dev->caps.num_ports);
+               MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
+
+               port = vhcr->in_modifier;
+               proxy_qp = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1;
+
                /* Set nic_info bit to mark new fields support */
                field  = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
-               MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
 
-               field = vhcr->in_modifier; /* phys-port = logical-port */
-               MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
+               if (mlx4_vf_smi_enabled(dev, slave, port) &&
+                   !mlx4_get_parav_qkey(dev, proxy_qp, &qkey)) {
+                       field |= QUERY_FUNC_CAP_VF_ENABLE_QP0;
+                       MLX4_PUT(outbox->buf, qkey,
+                                QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
+               }
+               MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
 
                /* size is now the QP number */
-               size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + field - 1;
+               size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1;
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
 
                size += 2;
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL);
 
-               size = dev->phys_caps.base_proxy_sqpn + 8 * slave + field - 1;
-               MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_PROXY);
-
-               size += 2;
-               MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY);
+               MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP0_PROXY);
+               proxy_qp += 2;
+               MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP1_PROXY);
 
                MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier],
                         QUERY_FUNC_CAP_PHYS_PORT_ID);
 
        } else if (vhcr->op_modifier == 0) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, slave);
                /* enable rdma and ethernet interfaces, and new quota locations */
                field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
                         QUERY_FUNC_CAP_FLAG_QUOTAS);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
 
-               field = dev->caps.num_ports;
+               field = min(
+                       bitmap_weight(actv_ports.ports, dev->caps.num_ports),
+                       dev->caps.num_ports);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
 
                size = dev->caps.function_caps; /* set PF behaviours */
@@ -310,7 +335,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
        struct mlx4_cmd_mailbox *mailbox;
        u32                     *outbox;
        u8                      field, op_modifier;
-       u32                     size;
+       u32                     size, qkey;
        int                     err = 0, quotas = 0;
 
        op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
@@ -398,7 +423,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
 
        MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
        if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) {
-               if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_OFFSET) {
+               if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN) {
                        mlx4_err(dev, "VLAN is enforced on this port\n");
                        err = -EPROTONOSUPPORT;
                        goto out;
@@ -426,6 +451,13 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
                goto out;
        }
 
+       if (func_cap->flags1 & QUERY_FUNC_CAP_VF_ENABLE_QP0) {
+               MLX4_GET(qkey, outbox, QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
+               func_cap->qp0_qkey = qkey;
+       } else {
+               func_cap->qp0_qkey = 0;
+       }
+
        MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL);
        func_cap->qp0_tunnel_qpn = size & 0xFFFFFF;
 
@@ -840,6 +872,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        int     err = 0;
        u8      field;
        u32     bmme_flags;
+       int     real_port;
+       int     slave_port;
+       int     first_port;
+       struct mlx4_active_ports actv_ports;
 
        err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
                           MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
@@ -852,8 +888,26 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
        flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV;
        flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
+       actv_ports = mlx4_get_active_ports(dev, slave);
+       first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+       for (slave_port = 0, real_port = first_port;
+            real_port < first_port +
+            bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+            ++real_port, ++slave_port) {
+               if (flags & (MLX4_DEV_CAP_FLAG_WOL_PORT1 << real_port))
+                       flags |= MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port;
+               else
+                       flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
+       }
+       for (; slave_port < dev->caps.num_ports; ++slave_port)
+               flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
        MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
 
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET);
+       field &= ~0x0F;
+       field |= bitmap_weight(actv_ports.ports, dev->caps.num_ports) & 0x0F;
+       MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VL_PORT_OFFSET);
+
        /* For guests, disable timestamp */
        MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
        field &= 0x7f;
@@ -903,12 +957,20 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
        u16 short_field;
        int err;
        int admin_link_state;
+       int port = mlx4_slave_convert_port(dev, slave,
+                                          vhcr->in_modifier & 0xFF);
 
 #define MLX4_VF_PORT_NO_LINK_SENSE_MASK        0xE0
 #define MLX4_PORT_LINK_UP_MASK         0x80
 #define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c
 #define QUERY_PORT_CUR_MAX_GID_OFFSET  0x0e
 
+       if (port < 0)
+               return -EINVAL;
+
+       vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
+                           (port & 0xFF);
+
        err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0,
                           MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
                           MLX4_CMD_NATIVE);
@@ -935,7 +997,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                MLX4_PUT(outbox->buf, port_type,
                         QUERY_PORT_SUPPORTED_TYPE_OFFSET);
 
-               short_field = 1; /* slave max gids */
+               if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
+                       short_field = mlx4_get_slave_num_gids(dev, slave, port);
+               else
+                       short_field = 1; /* slave max gids */
                MLX4_PUT(outbox->buf, short_field,
                         QUERY_PORT_CUR_MAX_GID_OFFSET);
 
@@ -1585,9 +1650,12 @@ int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave,
                           struct mlx4_cmd_info *cmd)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int port = vhcr->in_modifier;
+       int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
        int err;
 
+       if (port < 0)
+               return -EINVAL;
+
        if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port))
                return 0;
 
@@ -1677,9 +1745,12 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
                            struct mlx4_cmd_info *cmd)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int port = vhcr->in_modifier;
+       int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
        int err;
 
+       if (port < 0)
+               return -EINVAL;
+
        if (!(priv->mfunc.master.slave_state[slave].init_port_mask &
            (1 << port)))
                return 0;
@@ -1724,6 +1795,46 @@ int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
                        MLX4_CMD_NATIVE);
 }
 
+struct mlx4_config_dev {
+       __be32  update_flags;
+       __be32  rsdv1[3];
+       __be16  vxlan_udp_dport;
+       __be16  rsvd2;
+};
+
+#define MLX4_VXLAN_UDP_DPORT (1 << 0)
+
+static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+{
+       int err;
+       struct mlx4_cmd_mailbox *mailbox;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       memcpy(mailbox->buf, config_dev, sizeof(*config_dev));
+
+       err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_CONFIG_DEV,
+                      MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
+{
+       struct mlx4_config_dev config_dev;
+
+       memset(&config_dev, 0, sizeof(config_dev));
+       config_dev.update_flags    = cpu_to_be32(MLX4_VXLAN_UDP_DPORT);
+       config_dev.vxlan_udp_dport = udp_port;
+
+       return mlx4_CONFIG_DEV(dev, &config_dev);
+}
+EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
+
+
 int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
 {
        int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
@@ -1891,7 +2002,8 @@ void mlx4_opreq_action(struct work_struct *work)
                        err = EINVAL;
                        break;
                }
-               err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
+               err = mlx4_cmd(dev, 0, ((u32) err |
+                                       (__force u32)cpu_to_be32(token) << 16),
                               1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
                               MLX4_CMD_NATIVE);
                if (err) {