]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/mellanox/mlx4/fw.c
net/mlx4: Add support for A0 steering
[karo-tx-linux.git] / drivers / net / ethernet / mellanox / mlx4 / fw.c
index 2e88a235e26b47b5fc85ad2a6c5ea4a494997e14..ef3b95bac2adc46a7bf976bda2a3f51988aa2ab5 100644 (file)
@@ -139,7 +139,13 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [10] = "TCP/IP offloads/flow-steering for VXLAN support",
                [11] = "MAD DEMUX (Secure-Host) support",
                [12] = "Large cache line (>64B) CQE stride support",
-               [13] = "Large cache line (>64B) EQE stride support"
+               [13] = "Large cache line (>64B) EQE stride support",
+               [14] = "Ethernet protocol control support",
+               [15] = "Ethernet Backplane autoneg support",
+               [16] = "CONFIG DEV support",
+               [17] = "Asymmetric EQs support",
+               [18] = "More than 80 VFs support",
+               [19] = "Performance optimized for limited rule configuration flow steering support"
        };
        int i;
 
@@ -174,6 +180,61 @@ int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
        return err;
 }
 
+int mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       u8 in_modifier;
+       u8 field;
+       u16 field16;
+       int err;
+
+#define QUERY_FUNC_BUS_OFFSET                  0x00
+#define QUERY_FUNC_DEVICE_OFFSET               0x01
+#define QUERY_FUNC_FUNCTION_OFFSET             0x01
+#define QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET    0x03
+#define QUERY_FUNC_RSVD_EQS_OFFSET             0x04
+#define QUERY_FUNC_MAX_EQ_OFFSET               0x06
+#define QUERY_FUNC_RSVD_UARS_OFFSET            0x0b
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       in_modifier = slave;
+
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, 0,
+                          MLX4_CMD_QUERY_FUNC,
+                          MLX4_CMD_TIME_CLASS_A,
+                          MLX4_CMD_NATIVE);
+       if (err)
+               goto out;
+
+       MLX4_GET(field, outbox, QUERY_FUNC_BUS_OFFSET);
+       func->bus = field & 0xf;
+       MLX4_GET(field, outbox, QUERY_FUNC_DEVICE_OFFSET);
+       func->device = field & 0xf1;
+       MLX4_GET(field, outbox, QUERY_FUNC_FUNCTION_OFFSET);
+       func->function = field & 0x7;
+       MLX4_GET(field, outbox, QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET);
+       func->physical_function = field & 0xf;
+       MLX4_GET(field16, outbox, QUERY_FUNC_RSVD_EQS_OFFSET);
+       func->rsvd_eqs = field16 & 0xffff;
+       MLX4_GET(field16, outbox, QUERY_FUNC_MAX_EQ_OFFSET);
+       func->max_eq = field16 & 0xffff;
+       MLX4_GET(field, outbox, QUERY_FUNC_RSVD_UARS_OFFSET);
+       func->rsvd_uars = field & 0x0f;
+
+       mlx4_dbg(dev, "Bus: %d, Device: %d, Function: %d, Physical function: %d, Max EQs: %d, Reserved EQs: %d, Reserved UARs: %d\n",
+                func->bus, func->device, func->function, func->physical_function,
+                func->max_eq, func->rsvd_eqs, func->rsvd_uars);
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
 int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                                struct mlx4_vhcr *vhcr,
                                struct mlx4_cmd_mailbox *inbox,
@@ -184,6 +245,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
        u8      field, port;
        u32     size, proxy_qp, qkey;
        int     err = 0;
+       struct mlx4_func func;
 
 #define QUERY_FUNC_CAP_FLAGS_OFFSET            0x0
 #define QUERY_FUNC_CAP_NUM_PORTS_OFFSET                0x1
@@ -205,10 +267,16 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
 #define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET                0x64
 #define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET                0x68
 
+#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET      0x6c
+
 #define QUERY_FUNC_CAP_FMR_FLAG                        0x80
 #define QUERY_FUNC_CAP_FLAG_RDMA               0x40
 #define QUERY_FUNC_CAP_FLAG_ETH                        0x80
 #define QUERY_FUNC_CAP_FLAG_QUOTAS             0x10
+#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX      0x04
+
+#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG    (1UL << 31)
+#define QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG    (1UL << 30)
 
 /* when opcode modifier = 1 */
 #define QUERY_FUNC_CAP_PHYS_PORT_OFFSET                0x3
@@ -228,6 +296,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
 #define QUERY_FUNC_CAP_VF_ENABLE_QP0           0x08
 
 #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
+#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31)
 
        if (vhcr->op_modifier == 1) {
                struct mlx4_active_ports actv_ports =
@@ -277,7 +346,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                        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);
+                        QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
 
                field = min(
@@ -306,11 +375,24 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                size = dev->caps.num_cqs;
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
 
-               size = dev->caps.num_eqs;
-               MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
-
-               size = dev->caps.reserved_eqs;
-               MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+               if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) ||
+                   mlx4_QUERY_FUNC(dev, &func, slave)) {
+                       size = vhcr->in_modifier &
+                               QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
+                               dev->caps.num_eqs :
+                               rounddown_pow_of_two(dev->caps.num_eqs);
+                       MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
+                       size = dev->caps.reserved_eqs;
+                       MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+               } else {
+                       size = vhcr->in_modifier &
+                               QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
+                               func.max_eq :
+                               rounddown_pow_of_two(func.max_eq);
+                       MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
+                       size = func.rsvd_eqs;
+                       MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+               }
 
                size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave];
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
@@ -326,13 +408,16 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
 
+               size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG |
+                       QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG;
+               MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
        } else
                err = -EINVAL;
 
        return err;
 }
 
-int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
+int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
                        struct mlx4_func_cap *func_cap)
 {
        struct mlx4_cmd_mailbox *mailbox;
@@ -340,14 +425,17 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
        u8                      field, op_modifier;
        u32                     size, qkey;
        int                     err = 0, quotas = 0;
+       u32                     in_modifier;
 
        op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
+       in_modifier = op_modifier ? gen_or_port :
+               QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS;
 
        mailbox = mlx4_alloc_cmd_mailbox(dev);
        if (IS_ERR(mailbox))
                return PTR_ERR(mailbox);
 
-       err = mlx4_cmd_box(dev, 0, mailbox->dma, gen_or_port, op_modifier,
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, op_modifier,
                           MLX4_CMD_QUERY_FUNC_CAP,
                           MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
        if (err)
@@ -415,6 +503,19 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
                MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
                func_cap->reserved_eq = size & 0xFFFFFF;
 
+               func_cap->extra_flags = 0;
+
+               /* Mailbox data from 0x6c and onward should only be treated if
+                * QUERY_FUNC_CAP_FLAG_VALID_MAILBOX is set in func_cap->flags
+                */
+               if (func_cap->flags & QUERY_FUNC_CAP_FLAG_VALID_MAILBOX) {
+                       MLX4_GET(size, outbox, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
+                       if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG)
+                               func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_BF_RES_QP;
+                       if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG)
+                               func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_A0_RES_QP;
+               }
+
                goto out;
        }
 
@@ -519,6 +620,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET                0x21
 #define QUERY_DEV_CAP_RSVD_MRW_OFFSET          0x22
 #define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET       0x23
+#define QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET                0x26
 #define QUERY_DEV_CAP_MAX_AV_OFFSET            0x27
 #define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET                0x29
 #define QUERY_DEV_CAP_MAX_RES_QP_OFFSET                0x2b
@@ -560,6 +662,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET    0x76
 #define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET      0x77
 #define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE  0x7a
+#define QUERY_DEV_CAP_ETH_PROT_CTRL_OFFSET     0x7a
 #define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET   0x80
 #define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET      0x82
 #define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET      0x84
@@ -571,11 +674,15 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET      0x90
 #define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET    0x92
 #define QUERY_DEV_CAP_BMME_FLAGS_OFFSET                0x94
+#define QUERY_DEV_CAP_CONFIG_DEV_OFFSET                0x94
 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET         0x98
 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET                0xa0
+#define QUERY_DEV_CAP_ETH_BACKPL_OFFSET                0x9c
 #define QUERY_DEV_CAP_FW_REASSIGN_MAC          0x9d
 #define QUERY_DEV_CAP_VXLAN                    0x9e
 #define QUERY_DEV_CAP_MAD_DEMUX_OFFSET         0xb0
+#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET   0xa8
+#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET  0xac
 
        dev_cap->flags2 = 0;
        mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -605,7 +712,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
        dev_cap->max_mpts = 1 << (field & 0x3f);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
-       dev_cap->reserved_eqs = field & 0xf;
+       dev_cap->reserved_eqs = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
        dev_cap->max_eqs = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
@@ -616,6 +723,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev_cap->reserved_mrws = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
        dev_cap->max_mtt_seg = 1 << (field & 0x3f);
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET);
+       dev_cap->num_sys_eqs = size & 0xfff;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
        dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
@@ -737,15 +846,22 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
        dev_cap->max_rq_desc_sz = size;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
+       if (field & (1 << 5))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL;
        if (field & (1 << 6))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CQE_STRIDE;
        if (field & (1 << 7))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE;
-
        MLX4_GET(dev_cap->bmme_flags, outbox,
                 QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
+       if (field & 0x20)
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV;
        MLX4_GET(dev_cap->reserved_lkey, outbox,
                 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
+       MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET);
+       if (field32 & (1 << 0))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
        if (field & 1<<6)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
@@ -763,6 +879,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        if (field32 & (1 << 0))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_MAD_DEMUX;
 
+       MLX4_GET(dev_cap->dmfs_high_rate_qpn_base, outbox,
+                QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET);
+       dev_cap->dmfs_high_rate_qpn_base &= MGM_QPN_MASK;
+       MLX4_GET(dev_cap->dmfs_high_rate_qpn_range, outbox,
+                QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET);
+       dev_cap->dmfs_high_rate_qpn_range &= MGM_QPN_MASK;
+
        MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
        if (field32 & (1 << 16))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
@@ -770,62 +893,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
        if (field32 & (1 << 20))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
+       if (field32 & (1 << 21))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS;
 
-       if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
-               for (i = 1; i <= dev_cap->num_ports; ++i) {
-                       MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
-                       dev_cap->max_vl[i]         = field >> 4;
-                       MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
-                       dev_cap->ib_mtu[i]         = field >> 4;
-                       dev_cap->max_port_width[i] = field & 0xf;
-                       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
-                       dev_cap->max_gids[i]       = 1 << (field & 0xf);
-                       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
-                       dev_cap->max_pkeys[i]      = 1 << (field & 0xf);
-               }
-       } else {
-#define QUERY_PORT_SUPPORTED_TYPE_OFFSET       0x00
-#define QUERY_PORT_MTU_OFFSET                  0x01
-#define QUERY_PORT_ETH_MTU_OFFSET              0x02
-#define QUERY_PORT_WIDTH_OFFSET                        0x06
-#define QUERY_PORT_MAX_GID_PKEY_OFFSET         0x07
-#define QUERY_PORT_MAX_MACVLAN_OFFSET          0x0a
-#define QUERY_PORT_MAX_VL_OFFSET               0x0b
-#define QUERY_PORT_MAC_OFFSET                  0x10
-#define QUERY_PORT_TRANS_VENDOR_OFFSET         0x18
-#define QUERY_PORT_WAVELENGTH_OFFSET           0x1c
-#define QUERY_PORT_TRANS_CODE_OFFSET           0x20
-
-               for (i = 1; i <= dev_cap->num_ports; ++i) {
-                       err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
-                                          MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
-                       if (err)
-                               goto out;
-
-                       MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
-                       dev_cap->supported_port_types[i] = field & 3;
-                       dev_cap->suggested_type[i] = (field >> 3) & 1;
-                       dev_cap->default_sense[i] = (field >> 4) & 1;
-                       MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
-                       dev_cap->ib_mtu[i]         = field & 0xf;
-                       MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
-                       dev_cap->max_port_width[i] = field & 0xf;
-                       MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
-                       dev_cap->max_gids[i]       = 1 << (field >> 4);
-                       dev_cap->max_pkeys[i]      = 1 << (field & 0xf);
-                       MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
-                       dev_cap->max_vl[i]         = field & 0xf;
-                       MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
-                       dev_cap->log_max_macs[i]  = field & 0xf;
-                       dev_cap->log_max_vlans[i] = field >> 4;
-                       MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
-                       MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
-                       MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
-                       dev_cap->trans_type[i] = field32 >> 24;
-                       dev_cap->vendor_oui[i] = field32 & 0xffffff;
-                       MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
-                       MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
-               }
+       for (i = 1; i <= dev_cap->num_ports; i++) {
+               err = mlx4_QUERY_PORT(dev, i, dev_cap->port_cap + i);
+               if (err)
+                       goto out;
        }
 
        mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
@@ -836,8 +910,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
         * we can't use any EQs whose doorbell falls on that page,
         * even if the EQ itself isn't reserved.
         */
-       dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
-                                   dev_cap->reserved_eqs);
+       if (dev_cap->num_sys_eqs == 0)
+               dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
+                                           dev_cap->reserved_eqs);
+       else
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS;
 
        mlx4_dbg(dev, "Max ICM size %lld MB\n",
                 (unsigned long long) dev_cap->max_icm_sz >> 20);
@@ -847,8 +924,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                 dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
        mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
                 dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
-       mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
-                dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz);
+       mlx4_dbg(dev, "Num sys EQs: %d, max EQs: %d, reserved EQs: %d, entry size: %d\n",
+                dev_cap->num_sys_eqs, dev_cap->max_eqs, dev_cap->reserved_eqs,
+                dev_cap->eqc_entry_sz);
        mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
                 dev_cap->reserved_mrws, dev_cap->reserved_mtts);
        mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
@@ -858,8 +936,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
                 dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
        mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
-                dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
-                dev_cap->max_port_width[1]);
+                dev_cap->local_ca_ack_delay, 128 << dev_cap->port_cap[1].ib_mtu,
+                dev_cap->port_cap[1].max_port_width);
        mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
                 dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
        mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
@@ -867,6 +945,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
        mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
        mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
+       mlx4_dbg(dev, "DMFS high rate steer QPn base: %d\n",
+                dev_cap->dmfs_high_rate_qpn_base);
+       mlx4_dbg(dev, "DMFS high rate steer QPn range: %d\n",
+                dev_cap->dmfs_high_rate_qpn_range);
 
        dump_dev_cap_flags(dev, dev_cap->flags);
        dump_dev_cap_flags2(dev, dev_cap->flags2);
@@ -876,6 +958,89 @@ out:
        return err;
 }
 
+int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       u8 field;
+       u32 field32;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
+               err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
+                                  MLX4_CMD_TIME_CLASS_A,
+                                  MLX4_CMD_NATIVE);
+
+               if (err)
+                       goto out;
+
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
+               port_cap->max_vl           = field >> 4;
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
+               port_cap->ib_mtu           = field >> 4;
+               port_cap->max_port_width = field & 0xf;
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
+               port_cap->max_gids         = 1 << (field & 0xf);
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
+               port_cap->max_pkeys        = 1 << (field & 0xf);
+       } else {
+#define QUERY_PORT_SUPPORTED_TYPE_OFFSET       0x00
+#define QUERY_PORT_MTU_OFFSET                  0x01
+#define QUERY_PORT_ETH_MTU_OFFSET              0x02
+#define QUERY_PORT_WIDTH_OFFSET                        0x06
+#define QUERY_PORT_MAX_GID_PKEY_OFFSET         0x07
+#define QUERY_PORT_MAX_MACVLAN_OFFSET          0x0a
+#define QUERY_PORT_MAX_VL_OFFSET               0x0b
+#define QUERY_PORT_MAC_OFFSET                  0x10
+#define QUERY_PORT_TRANS_VENDOR_OFFSET         0x18
+#define QUERY_PORT_WAVELENGTH_OFFSET           0x1c
+#define QUERY_PORT_TRANS_CODE_OFFSET           0x20
+
+               err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, MLX4_CMD_QUERY_PORT,
+                                  MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+               if (err)
+                       goto out;
+
+               MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
+               port_cap->supported_port_types = field & 3;
+               port_cap->suggested_type = (field >> 3) & 1;
+               port_cap->default_sense = (field >> 4) & 1;
+               port_cap->dmfs_optimized_state = (field >> 5) & 1;
+               MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
+               port_cap->ib_mtu           = field & 0xf;
+               MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
+               port_cap->max_port_width = field & 0xf;
+               MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
+               port_cap->max_gids         = 1 << (field >> 4);
+               port_cap->max_pkeys        = 1 << (field & 0xf);
+               MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
+               port_cap->max_vl           = field & 0xf;
+               MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
+               port_cap->log_max_macs  = field & 0xf;
+               port_cap->log_max_vlans = field >> 4;
+               MLX4_GET(port_cap->eth_mtu, outbox, QUERY_PORT_ETH_MTU_OFFSET);
+               MLX4_GET(port_cap->def_mac, outbox, QUERY_PORT_MAC_OFFSET);
+               MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
+               port_cap->trans_type = field32 >> 24;
+               port_cap->vendor_oui = field32 & 0xffffff;
+               MLX4_GET(port_cap->wavelength, outbox, QUERY_PORT_WAVELENGTH_OFFSET);
+               MLX4_GET(port_cap->trans_code, outbox, QUERY_PORT_TRANS_CODE_OFFSET);
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+#define DEV_CAP_EXT_2_FLAG_VLAN_CONTROL (1 << 26)
+#define DEV_CAP_EXT_2_FLAG_80_VFS      (1 << 21)
+#define DEV_CAP_EXT_2_FLAG_FSM         (1 << 20)
+
 int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
                               struct mlx4_vhcr *vhcr,
                               struct mlx4_cmd_mailbox *inbox,
@@ -885,7 +1050,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        u64     flags;
        int     err = 0;
        u8      field;
-       u32     bmme_flags;
+       u32     bmme_flags, field32;
        int     real_port;
        int     slave_port;
        int     first_port;
@@ -956,6 +1121,12 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        field &= ~0x80;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
 
+       /* turn off host side virt features (VST, FSM, etc) for guests */
+       MLX4_GET(field32, outbox->buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
+       field32 &= ~(DEV_CAP_EXT_2_FLAG_VLAN_CONTROL | DEV_CAP_EXT_2_FLAG_80_VFS |
+                    DEV_CAP_EXT_2_FLAG_FSM);
+       MLX4_PUT(outbox->buf, field32, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
+
        return 0;
 }
 
@@ -1374,6 +1545,12 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
        struct mlx4_cmd_mailbox *mailbox;
        __be32 *inbox;
        int err;
+       static const u8 a0_dmfs_hw_steering[] =  {
+               [MLX4_STEERING_DMFS_A0_DEFAULT]         = 0,
+               [MLX4_STEERING_DMFS_A0_DYNAMIC]         = 1,
+               [MLX4_STEERING_DMFS_A0_STATIC]          = 2,
+               [MLX4_STEERING_DMFS_A0_DISABLE]         = 3
+       };
 
 #define INIT_HCA_IN_SIZE                0x200
 #define INIT_HCA_VERSION_OFFSET                 0x000
@@ -1394,6 +1571,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
 #define         INIT_HCA_AUXC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x50)
 #define         INIT_HCA_EQC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x60)
 #define         INIT_HCA_LOG_EQ_OFFSET          (INIT_HCA_QPC_OFFSET + 0x67)
+#define        INIT_HCA_NUM_SYS_EQS_OFFSET     (INIT_HCA_QPC_OFFSET + 0x6a)
 #define         INIT_HCA_RDMARC_BASE_OFFSET     (INIT_HCA_QPC_OFFSET + 0x70)
 #define         INIT_HCA_LOG_RD_OFFSET          (INIT_HCA_QPC_OFFSET + 0x77)
 #define INIT_HCA_MCAST_OFFSET           0x0c0
@@ -1406,6 +1584,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
 #define  INIT_HCA_FS_PARAM_OFFSET         0x1d0
 #define  INIT_HCA_FS_BASE_OFFSET          (INIT_HCA_FS_PARAM_OFFSET + 0x00)
 #define  INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x12)
+#define  INIT_HCA_FS_A0_OFFSET           (INIT_HCA_FS_PARAM_OFFSET + 0x18)
 #define  INIT_HCA_FS_LOG_TABLE_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
 #define  INIT_HCA_FS_ETH_BITS_OFFSET      (INIT_HCA_FS_PARAM_OFFSET + 0x21)
 #define  INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22)
@@ -1497,6 +1676,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
        MLX4_PUT(inbox, param->auxc_base,     INIT_HCA_AUXC_BASE_OFFSET);
        MLX4_PUT(inbox, param->eqc_base,      INIT_HCA_EQC_BASE_OFFSET);
        MLX4_PUT(inbox, param->log_num_eqs,   INIT_HCA_LOG_EQ_OFFSET);
+       MLX4_PUT(inbox, param->num_sys_eqs,   INIT_HCA_NUM_SYS_EQS_OFFSET);
        MLX4_PUT(inbox, param->rdmarc_base,   INIT_HCA_RDMARC_BASE_OFFSET);
        MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
 
@@ -1515,8 +1695,11 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
                /* Enable Ethernet flow steering
                 * with udp unicast and tcp unicast
                 */
-               MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
-                        INIT_HCA_FS_ETH_BITS_OFFSET);
+               if (dev->caps.dmfs_high_steer_mode !=
+                   MLX4_STEERING_DMFS_A0_STATIC)
+                       MLX4_PUT(inbox,
+                                (u8)(MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
+                                INIT_HCA_FS_ETH_BITS_OFFSET);
                MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
                         INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
                /* Enable IPoIB flow steering
@@ -1526,6 +1709,13 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
                         INIT_HCA_FS_IB_BITS_OFFSET);
                MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
                         INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
+
+               if (dev->caps.dmfs_high_steer_mode !=
+                   MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
+                       MLX4_PUT(inbox,
+                                ((u8)(a0_dmfs_hw_steering[dev->caps.dmfs_high_steer_mode]
+                                      << 6)),
+                                INIT_HCA_FS_A0_OFFSET);
        } else {
                MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET);
                MLX4_PUT(inbox, param->log_mc_entry_sz,
@@ -1576,6 +1766,12 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
        u32 dword_field;
        int err;
        u8 byte_field;
+       static const u8 a0_dmfs_query_hw_steering[] =  {
+               [0] = MLX4_STEERING_DMFS_A0_DEFAULT,
+               [1] = MLX4_STEERING_DMFS_A0_DYNAMIC,
+               [2] = MLX4_STEERING_DMFS_A0_STATIC,
+               [3] = MLX4_STEERING_DMFS_A0_DISABLE
+       };
 
 #define QUERY_HCA_GLOBAL_CAPS_OFFSET   0x04
 #define QUERY_HCA_CORE_CLOCK_OFFSET    0x0c
@@ -1607,6 +1803,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
        MLX4_GET(param->auxc_base,     outbox, INIT_HCA_AUXC_BASE_OFFSET);
        MLX4_GET(param->eqc_base,      outbox, INIT_HCA_EQC_BASE_OFFSET);
        MLX4_GET(param->log_num_eqs,   outbox, INIT_HCA_LOG_EQ_OFFSET);
+       MLX4_GET(param->num_sys_eqs,   outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
        MLX4_GET(param->rdmarc_base,   outbox, INIT_HCA_RDMARC_BASE_OFFSET);
        MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET);
 
@@ -1627,6 +1824,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
                         INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
                MLX4_GET(param->log_mc_table_sz, outbox,
                         INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
+               MLX4_GET(byte_field, outbox,
+                        INIT_HCA_FS_A0_OFFSET);
+               param->dmfs_high_steer_mode =
+                       a0_dmfs_query_hw_steering[(byte_field >> 6) & 3];
        } else {
                MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
                MLX4_GET(param->log_mc_entry_sz, outbox,
@@ -1841,14 +2042,18 @@ int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
 
 struct mlx4_config_dev {
        __be32  update_flags;
-       __be32  rsdv1[3];
+       __be32  rsvd1[3];
        __be16  vxlan_udp_dport;
        __be16  rsvd2;
+       __be32  rsvd3[27];
+       __be16  rsvd4;
+       u8      rsvd5;
+       u8      rx_checksum_val;
 };
 
 #define MLX4_VXLAN_UDP_DPORT (1 << 0)
 
-static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
 {
        int err;
        struct mlx4_cmd_mailbox *mailbox;
@@ -1866,6 +2071,77 @@ static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_
        return err;
 }
 
+static int mlx4_CONFIG_DEV_get(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);
+
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 1, MLX4_CMD_CONFIG_DEV,
+                          MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
+
+       if (!err)
+               memcpy(config_dev, mailbox->buf, sizeof(*config_dev));
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+/* Conversion between the HW values and the actual functionality.
+ * The value represented by the array index,
+ * and the functionality determined by the flags.
+ */
+static const u8 config_dev_csum_flags[] = {
+       [0] =   0,
+       [1] =   MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP,
+       [2] =   MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP       |
+               MLX4_RX_CSUM_MODE_L4,
+       [3] =   MLX4_RX_CSUM_MODE_L4                    |
+               MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP  |
+               MLX4_RX_CSUM_MODE_MULTI_VLAN
+};
+
+int mlx4_config_dev_retrieval(struct mlx4_dev *dev,
+                             struct mlx4_config_dev_params *params)
+{
+       struct mlx4_config_dev config_dev;
+       int err;
+       u8 csum_mask;
+
+#define CONFIG_DEV_RX_CSUM_MODE_MASK                   0x7
+#define CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET       0
+#define CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET       4
+
+       if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CONFIG_DEV))
+               return -ENOTSUPP;
+
+       err = mlx4_CONFIG_DEV_get(dev, &config_dev);
+       if (err)
+               return err;
+
+       csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET) &
+                       CONFIG_DEV_RX_CSUM_MODE_MASK;
+
+       if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0]))
+               return -EINVAL;
+       params->rx_csum_flags_port_1 = config_dev_csum_flags[csum_mask];
+
+       csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET) &
+                       CONFIG_DEV_RX_CSUM_MODE_MASK;
+
+       if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0]))
+               return -EINVAL;
+       params->rx_csum_flags_port_2 = config_dev_csum_flags[csum_mask];
+
+       params->vxlan_udp_dport = be16_to_cpu(config_dev.vxlan_udp_dport);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_config_dev_retrieval);
+
 int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
 {
        struct mlx4_config_dev config_dev;
@@ -1874,7 +2150,7 @@ int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
        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);
+       return mlx4_CONFIG_DEV_set(dev, &config_dev);
 }
 EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
 
@@ -2144,3 +2420,142 @@ out:
        mlx4_free_cmd_mailbox(dev, mailbox);
        return err;
 }
+
+/* Access Reg commands */
+enum mlx4_access_reg_masks {
+       MLX4_ACCESS_REG_STATUS_MASK = 0x7f,
+       MLX4_ACCESS_REG_METHOD_MASK = 0x7f,
+       MLX4_ACCESS_REG_LEN_MASK = 0x7ff
+};
+
+struct mlx4_access_reg {
+       __be16 constant1;
+       u8 status;
+       u8 resrvd1;
+       __be16 reg_id;
+       u8 method;
+       u8 constant2;
+       __be32 resrvd2[2];
+       __be16 len_const;
+       __be16 resrvd3;
+#define MLX4_ACCESS_REG_HEADER_SIZE (20)
+       u8 reg_data[MLX4_MAILBOX_SIZE-MLX4_ACCESS_REG_HEADER_SIZE];
+} __attribute__((__packed__));
+
+/**
+ * mlx4_ACCESS_REG - Generic access reg command.
+ * @dev: mlx4_dev.
+ * @reg_id: register ID to access.
+ * @method: Access method Read/Write.
+ * @reg_len: register length to Read/Write in bytes.
+ * @reg_data: reg_data pointer to Read/Write From/To.
+ *
+ * Access ConnectX registers FW command.
+ * Returns 0 on success and copies outbox mlx4_access_reg data
+ * field into reg_data or a negative error code.
+ */
+static int mlx4_ACCESS_REG(struct mlx4_dev *dev, u16 reg_id,
+                          enum mlx4_access_reg_method method,
+                          u16 reg_len, void *reg_data)
+{
+       struct mlx4_cmd_mailbox *inbox, *outbox;
+       struct mlx4_access_reg *inbuf, *outbuf;
+       int err;
+
+       inbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(inbox))
+               return PTR_ERR(inbox);
+
+       outbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(outbox)) {
+               mlx4_free_cmd_mailbox(dev, inbox);
+               return PTR_ERR(outbox);
+       }
+
+       inbuf = inbox->buf;
+       outbuf = outbox->buf;
+
+       inbuf->constant1 = cpu_to_be16(0x1<<11 | 0x4);
+       inbuf->constant2 = 0x1;
+       inbuf->reg_id = cpu_to_be16(reg_id);
+       inbuf->method = method & MLX4_ACCESS_REG_METHOD_MASK;
+
+       reg_len = min(reg_len, (u16)(sizeof(inbuf->reg_data)));
+       inbuf->len_const =
+               cpu_to_be16(((reg_len/4 + 1) & MLX4_ACCESS_REG_LEN_MASK) |
+                           ((0x3) << 12));
+
+       memcpy(inbuf->reg_data, reg_data, reg_len);
+       err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 0, 0,
+                          MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
+                          MLX4_CMD_WRAPPED);
+       if (err)
+               goto out;
+
+       if (outbuf->status & MLX4_ACCESS_REG_STATUS_MASK) {
+               err = outbuf->status & MLX4_ACCESS_REG_STATUS_MASK;
+               mlx4_err(dev,
+                        "MLX4_CMD_ACCESS_REG(%x) returned REG status (%x)\n",
+                        reg_id, err);
+               goto out;
+       }
+
+       memcpy(reg_data, outbuf->reg_data, reg_len);
+out:
+       mlx4_free_cmd_mailbox(dev, inbox);
+       mlx4_free_cmd_mailbox(dev, outbox);
+       return err;
+}
+
+/* ConnectX registers IDs */
+enum mlx4_reg_id {
+       MLX4_REG_ID_PTYS = 0x5004,
+};
+
+/**
+ * mlx4_ACCESS_PTYS_REG - Access PTYs (Port Type and Speed)
+ * register
+ * @dev: mlx4_dev.
+ * @method: Access method Read/Write.
+ * @ptys_reg: PTYS register data pointer.
+ *
+ * Access ConnectX PTYS register, to Read/Write Port Type/Speed
+ * configuration
+ * Returns 0 on success or a negative error code.
+ */
+int mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev,
+                        enum mlx4_access_reg_method method,
+                        struct mlx4_ptys_reg *ptys_reg)
+{
+       return mlx4_ACCESS_REG(dev, MLX4_REG_ID_PTYS,
+                              method, sizeof(*ptys_reg), ptys_reg);
+}
+EXPORT_SYMBOL_GPL(mlx4_ACCESS_PTYS_REG);
+
+int mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave,
+                           struct mlx4_vhcr *vhcr,
+                           struct mlx4_cmd_mailbox *inbox,
+                           struct mlx4_cmd_mailbox *outbox,
+                           struct mlx4_cmd_info *cmd)
+{
+       struct mlx4_access_reg *inbuf = inbox->buf;
+       u8 method = inbuf->method & MLX4_ACCESS_REG_METHOD_MASK;
+       u16 reg_id = be16_to_cpu(inbuf->reg_id);
+
+       if (slave != mlx4_master_func_num(dev) &&
+           method == MLX4_ACCESS_REG_WRITE)
+               return -EPERM;
+
+       if (reg_id == MLX4_REG_ID_PTYS) {
+               struct mlx4_ptys_reg *ptys_reg =
+                       (struct mlx4_ptys_reg *)inbuf->reg_data;
+
+               ptys_reg->local_port =
+                       mlx4_slave_convert_port(dev, slave,
+                                               ptys_reg->local_port);
+       }
+
+       return mlx4_cmd_box(dev, inbox->dma, outbox->dma, vhcr->in_modifier,
+                           0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
+                           MLX4_CMD_NATIVE);
+}