net/mlx4_core: Add basic support for TCP/IP offloads under tunneling
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / mellanox / mlx4 / fw.c
index 91b50fed289b74d4d8615a1ee8f53f74451426e9..55c4ea7402586f8f2b3124f570ca6bd4246046bd 100644 (file)
@@ -134,7 +134,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [5] = "Time stamping support",
                [6] = "VST (control vlan insertion/stripping) support",
                [7] = "FSM (MAC anti-spoofing) support",
-               [8] = "Dynamic QP updates support"
+               [8] = "Dynamic QP updates support",
+               [9] = "TCP/IP offloads/flow-steering for VXLAN support"
        };
        int i;
 
@@ -207,20 +208,26 @@ 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_RDMA_PROPS_OFFSET       0x8
-#define QUERY_FUNC_CAP_ETH_PROPS_OFFSET                0xc
+#define QUERY_FUNC_CAP_FLAGS0_OFFSET           0x8
+#define QUERY_FUNC_CAP_FLAGS1_OFFSET           0xc
 
 #define QUERY_FUNC_CAP_QP0_TUNNEL              0x10
 #define QUERY_FUNC_CAP_QP0_PROXY               0x14
 #define QUERY_FUNC_CAP_QP1_TUNNEL              0x18
 #define QUERY_FUNC_CAP_QP1_PROXY               0x1c
+#define QUERY_FUNC_CAP_PHYS_PORT_ID            0x28
 
-#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC     0x40
-#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN    0x80
+#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_RDMA_PROPS_FORCE_PHY_WQE_GID 0x80
+#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
 
        if (vhcr->op_modifier == 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);
 
@@ -237,6 +244,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                size += 2;
                MLX4_PUT(outbox->buf, size, 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) {
                /* enable rdma and ethernet interfaces, and new quota locations */
                field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
@@ -385,22 +395,22 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
                goto out;
        }
 
+       MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
        if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) {
-               MLX4_GET(field, outbox, QUERY_FUNC_CAP_ETH_PROPS_OFFSET);
-               if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN) {
+               if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_OFFSET) {
                        mlx4_err(dev, "VLAN is enforced on this port\n");
                        err = -EPROTONOSUPPORT;
                        goto out;
                }
 
-               if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC) {
+               if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_MAC) {
                        mlx4_err(dev, "Force mac is enabled on this port\n");
                        err = -EPROTONOSUPPORT;
                        goto out;
                }
        } else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) {
-               MLX4_GET(field, outbox, QUERY_FUNC_CAP_RDMA_PROPS_OFFSET);
-               if (field & QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID) {
+               MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
+               if (field & QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID) {
                        mlx4_err(dev, "phy_wqe_gid is "
                                 "enforced on this ib port\n");
                        err = -EPROTONOSUPPORT;
@@ -427,6 +437,10 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
        MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY);
        func_cap->qp1_proxy_qpn = size & 0xFFFFFF;
 
+       if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_NIC_INFO)
+               MLX4_GET(func_cap->phys_port_id, outbox,
+                        QUERY_FUNC_CAP_PHYS_PORT_ID);
+
        /* All other resources are allocated by the master, but we still report
         * 'num' and 'reserved' capabilities as follows:
         * - num remains the maximum resource index
@@ -523,6 +537,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET         0x98
 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET                0xa0
 #define QUERY_DEV_CAP_FW_REASSIGN_MAC          0x9d
+#define QUERY_DEV_CAP_VXLAN                    0x9e
 
        dev_cap->flags2 = 0;
        mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -688,6 +703,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
        if (field & 1<<6)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+       if (field & 1<<3)
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS;
        MLX4_GET(dev_cap->max_icm_sz, outbox,
                 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
        if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
@@ -836,6 +854,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        field &= 0x7f;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
 
+       /* For guests, disable vxlan tunneling */
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+       field &= 0xf7;
+       MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
+
        /* For guests, report Blueflame disabled */
        MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET);
        field &= 0x7f;
@@ -1261,6 +1284,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
 #define INIT_HCA_IN_SIZE                0x200
 #define INIT_HCA_VERSION_OFFSET                 0x000
 #define         INIT_HCA_VERSION                2
+#define INIT_HCA_VXLAN_OFFSET           0x0c
 #define INIT_HCA_CACHELINE_SZ_OFFSET    0x0e
 #define INIT_HCA_FLAGS_OFFSET           0x014
 #define INIT_HCA_QPC_OFFSET             0x020
@@ -1419,6 +1443,12 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
        MLX4_PUT(inbox, param->uar_page_sz,     INIT_HCA_UAR_PAGE_SZ_OFFSET);
        MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
 
+       /* set parser VXLAN attributes */
+       if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS) {
+               u8 parser_params = 0;
+               MLX4_PUT(inbox, parser_params,  INIT_HCA_VXLAN_OFFSET);
+       }
+
        err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000,
                       MLX4_CMD_NATIVE);
 
@@ -1707,6 +1737,43 @@ int mlx4_NOP(struct mlx4_dev *dev)
        return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100, MLX4_CMD_NATIVE);
 }
 
+int mlx4_get_phys_port_id(struct mlx4_dev *dev)
+{
+       u8 port;
+       u32 *outbox;
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 in_mod;
+       u32 guid_hi, guid_lo;
+       int err, ret = 0;
+#define MOD_STAT_CFG_PORT_OFFSET 8
+#define MOD_STAT_CFG_GUID_H     0X14
+#define MOD_STAT_CFG_GUID_L     0X1c
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       for (port = 1; port <= dev->caps.num_ports; port++) {
+               in_mod = port << MOD_STAT_CFG_PORT_OFFSET;
+               err = mlx4_cmd_box(dev, 0, mailbox->dma, in_mod, 0x2,
+                                  MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A,
+                                  MLX4_CMD_NATIVE);
+               if (err) {
+                       mlx4_err(dev, "Fail to get port %d uplink guid\n",
+                                port);
+                       ret = err;
+               } else {
+                       MLX4_GET(guid_hi, outbox, MOD_STAT_CFG_GUID_H);
+                       MLX4_GET(guid_lo, outbox, MOD_STAT_CFG_GUID_L);
+                       dev->caps.phys_port_id[port] = (u64)guid_lo |
+                                                      (u64)guid_hi << 32;
+               }
+       }
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return ret;
+}
+
 #define MLX4_WOL_SETUP_MODE (5 << 28)
 int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port)
 {