net/mlx4: Set enhanced QoS support by default when ETS supported
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / fw.c
index 5a21e5d..b93e23b 100644 (file)
@@ -49,9 +49,9 @@ enum {
 extern void __buggy_use_of_MLX4_GET(void);
 extern void __buggy_use_of_MLX4_PUT(void);
 
-static bool enable_qos;
+static bool enable_qos = true;
 module_param(enable_qos, bool, 0444);
-MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)");
+MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: on)");
 
 #define MLX4_GET(dest, source, offset)                               \
        do {                                                          \
@@ -105,6 +105,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
                [41] = "Unicast VEP steering support",
                [42] = "Multicast VEP steering support",
                [48] = "Counters support",
+               [52] = "RSS IP fragments support",
                [53] = "Port ETS Scheduler support",
                [55] = "Port link type sensing support",
                [59] = "Port management change event support",
@@ -143,7 +144,12 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [18] = "More than 80 VFs support",
                [19] = "Performance optimized for limited rule configuration flow steering support",
                [20] = "Recoverable error events support",
-               [21] = "Port Remap support"
+               [21] = "Port Remap support",
+               [22] = "QCN support",
+               [23] = "QP rate limiting support",
+               [24] = "Ethernet Flow control statistics support",
+               [25] = "Granular QoS per VF support",
+               [26] = "Port ETS Scheduler support",
        };
        int i;
 
@@ -670,12 +676,13 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_RSVD_XRC_OFFSET          0x66
 #define QUERY_DEV_CAP_MAX_XRC_OFFSET           0x67
 #define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET      0x68
+#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET   0x70
 #define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET       0x70
 #define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET       0x74
 #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_ECN_QCN_VER_OFFSET       0x7b
 #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
@@ -696,6 +703,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #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
+#define QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET 0xcc
+#define QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET 0xd0
+#define QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET 0xd2
+
 
        dev_cap->flags2 = 0;
        mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -767,6 +778,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
        dev_cap->num_ports = field & 0xf;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET);
+       if (field & 0x10)
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN;
        dev_cap->max_msg_sz = 1 << (field & 0x1f);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
        if (field & 0x80)
@@ -777,6 +791,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET);
        dev_cap->fs_max_num_qp_per_entry = field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
+       if (field & 0x1)
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QCN;
        MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
        dev_cap->stat_rate_support = stat_rate;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
@@ -856,6 +873,8 @@ 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 << 4))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QOS_VPP;
        if (field & (1 << 5))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL;
        if (field & (1 << 6))
@@ -882,6 +901,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
        if (field & 1<<3)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS;
+       if (field & (1 << 5))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG;
        MLX4_GET(dev_cap->max_icm_sz, outbox,
                 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
        if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
@@ -900,6 +921,18 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                 QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET);
        dev_cap->dmfs_high_rate_qpn_range &= MGM_QPN_MASK;
 
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET);
+       dev_cap->rl_caps.num_rates = size;
+       if (dev_cap->rl_caps.num_rates) {
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT;
+               MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET);
+               dev_cap->rl_caps.max_val  = size & 0xfff;
+               dev_cap->rl_caps.max_unit = size >> 14;
+               MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET);
+               dev_cap->rl_caps.min_val  = size & 0xfff;
+               dev_cap->rl_caps.min_unit = size >> 14;
+       }
+
        MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
        if (field32 & (1 << 16))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
@@ -975,6 +1008,15 @@ void mlx4_dev_cap_dump(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                 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);
+
+       if (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT) {
+               struct mlx4_rate_limit_caps *rl_caps = &dev_cap->rl_caps;
+
+               mlx4_dbg(dev, "QP Rate-Limit: #rates %d, unit/val max %d/%d, min %d/%d\n",
+                        rl_caps->num_rates, rl_caps->max_unit, rl_caps->max_val,
+                        rl_caps->min_unit, rl_caps->min_val);
+       }
+
        dump_dev_cap_flags(dev, dev_cap->flags);
        dump_dev_cap_flags2(dev, dev_cap->flags2);
 }
@@ -1058,6 +1100,7 @@ out:
        return err;
 }
 
+#define DEV_CAP_EXT_2_FLAG_PFC_COUNTERS        (1 << 28)
 #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)
@@ -1071,6 +1114,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        u64     flags;
        int     err = 0;
        u8      field;
+       u16     field16;
        u32     bmme_flags, field32;
        int     real_port;
        int     slave_port;
@@ -1101,6 +1145,9 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        }
        for (; slave_port < dev->caps.num_ports; ++slave_port)
                flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
+
+       /* Not exposing RSS IP fragments to guests */
+       flags &= ~MLX4_DEV_CAP_FLAG_RSS_IP_FRAG;
        MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
 
        MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET);
@@ -1113,9 +1160,9 @@ 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 */
+       /* For guests, disable vxlan tunneling and QoS support */
        MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
-       field &= 0xf7;
+       field &= 0xd7;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
 
        /* For guests, report Blueflame disabled */
@@ -1146,9 +1193,23 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        /* 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);
+                    DEV_CAP_EXT_2_FLAG_FSM | DEV_CAP_EXT_2_FLAG_PFC_COUNTERS);
        MLX4_PUT(outbox->buf, field32, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
 
+       /* turn off QCN for guests */
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
+       field &= 0xfe;
+       MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
+
+       /* turn off QP max-rate limiting for guests */
+       field16 = 0;
+       MLX4_PUT(outbox->buf, field16, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET);
+
+       /* turn off QoS per VF support for guests */
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
+       field &= 0xef;
+       MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
+
        return 0;
 }
 
@@ -1648,13 +1709,17 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
                *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3);
 
        /* Enable QoS support if module parameter set */
-       if (enable_qos)
+       if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG && enable_qos)
                *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2);
 
        /* enable counters */
        if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)
                *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4);
 
+       /* Enable RSS spread to fragmented IP packets when supported */
+       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_RSS_IP_FRAG)
+               *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 13);
+
        /* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */
        if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) {
                *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29);
@@ -1843,6 +1908,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
                else
                        param->steering_mode = MLX4_STEERING_MODE_A0;
        }
+
+       if (dword_field & (1 << 13))
+               param->rss_ip_frags = 1;
+
        /* steering attributes */
        if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
                MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET);