net/mlx5: Add tracepoints
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / diag / fs_tracepoint.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c
new file mode 100644 (file)
index 0000000..0be4575
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define CREATE_TRACE_POINTS
+
+#include "fs_tracepoint.h"
+#include <linux/stringify.h>
+
+#define DECLARE_MASK_VAL(type, name) struct {type m; type v; } name
+#define MASK_VAL(type, spec, name, mask, val, fld)     \
+               DECLARE_MASK_VAL(type, name) =          \
+                       {.m = MLX5_GET(spec, mask, fld),\
+                        .v = MLX5_GET(spec, val, fld)}
+#define MASK_VAL_BE(type, spec, name, mask, val, fld)  \
+                   DECLARE_MASK_VAL(type, name) =      \
+                       {.m = MLX5_GET_BE(type, spec, mask, fld),\
+                        .v = MLX5_GET_BE(type, spec, val, fld)}
+#define GET_MASKED_VAL(name) (name.m & name.v)
+
+#define GET_MASK_VAL(name, type, mask, val, fld)       \
+               (name.m = MLX5_GET(type, mask, fld),    \
+                name.v = MLX5_GET(type, val, fld),     \
+                name.m & name.v)
+#define PRINT_MASKED_VAL(name, p, format) {            \
+       if (name.m)                     \
+               trace_seq_printf(p, __stringify(name) "=" format " ", name.v); \
+       }
+#define PRINT_MASKED_VALP(name, cast, p, format) {     \
+       if (name.m)                     \
+               trace_seq_printf(p, __stringify(name) "=" format " ",          \
+                                (cast)&name.v);\
+       }
+
+static void print_lyr_2_4_hdrs(struct trace_seq *p,
+                              const u32 *mask, const u32 *value)
+{
+#define MASK_VAL_L2(type, name, fld) \
+       MASK_VAL(type, fte_match_set_lyr_2_4, name, mask, value, fld)
+       DECLARE_MASK_VAL(u64, smac) = {
+               .m = MLX5_GET(fte_match_set_lyr_2_4, mask, smac_47_16) << 16 |
+                    MLX5_GET(fte_match_set_lyr_2_4, mask, smac_15_0),
+               .v = MLX5_GET(fte_match_set_lyr_2_4, value, smac_47_16) << 16 |
+                    MLX5_GET(fte_match_set_lyr_2_4, value, smac_15_0)};
+       DECLARE_MASK_VAL(u64, dmac) = {
+               .m = MLX5_GET(fte_match_set_lyr_2_4, mask, dmac_47_16) << 16 |
+                    MLX5_GET(fte_match_set_lyr_2_4, mask, dmac_15_0),
+               .v = MLX5_GET(fte_match_set_lyr_2_4, value, dmac_47_16) << 16 |
+                    MLX5_GET(fte_match_set_lyr_2_4, value, dmac_15_0)};
+       MASK_VAL_L2(u16, ethertype, ethertype);
+
+       PRINT_MASKED_VALP(smac, u8 *, p, "%pM");
+       PRINT_MASKED_VALP(dmac, u8 *, p, "%pM");
+       PRINT_MASKED_VAL(ethertype, p, "%04x");
+
+       if (ethertype.m == 0xffff) {
+               if (ethertype.v == ETH_P_IP) {
+#define MASK_VAL_L2_BE(type, name, fld) \
+       MASK_VAL_BE(type, fte_match_set_lyr_2_4, name, mask, value, fld)
+                       MASK_VAL_L2_BE(u32, src_ipv4,
+                                      src_ipv4_src_ipv6.ipv4_layout.ipv4);
+                       MASK_VAL_L2_BE(u32, dst_ipv4,
+                                      dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
+
+                       PRINT_MASKED_VALP(src_ipv4, typeof(&src_ipv4.v), p,
+                                         "%pI4");
+                       PRINT_MASKED_VALP(dst_ipv4, typeof(&dst_ipv4.v), p,
+                                         "%pI4");
+               } else if (ethertype.v == ETH_P_IPV6) {
+                       static const struct in6_addr full_ones = {
+                               .in6_u.u6_addr32 = {htonl(0xffffffff),
+                                                   htonl(0xffffffff),
+                                                   htonl(0xffffffff),
+                                                   htonl(0xffffffff)},
+                       };
+                       DECLARE_MASK_VAL(struct in6_addr, src_ipv6);
+                       DECLARE_MASK_VAL(struct in6_addr, dst_ipv6);
+
+                       memcpy(src_ipv6.m.in6_u.u6_addr8,
+                              MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask,
+                                           src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                              sizeof(src_ipv6.m));
+                       memcpy(dst_ipv6.m.in6_u.u6_addr8,
+                              MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask,
+                                           dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                              sizeof(dst_ipv6.m));
+                       memcpy(src_ipv6.v.in6_u.u6_addr8,
+                              MLX5_ADDR_OF(fte_match_set_lyr_2_4, value,
+                                           src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                              sizeof(src_ipv6.v));
+                       memcpy(dst_ipv6.v.in6_u.u6_addr8,
+                              MLX5_ADDR_OF(fte_match_set_lyr_2_4, value,
+                                           dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                              sizeof(dst_ipv6.v));
+
+                       if (!memcmp(&src_ipv6.m, &full_ones, sizeof(full_ones)))
+                               trace_seq_printf(p, "src_ipv6=%pI6 ",
+                                                &src_ipv6.v);
+                       if (!memcmp(&dst_ipv6.m, &full_ones, sizeof(full_ones)))
+                               trace_seq_printf(p, "dst_ipv6=%pI6 ",
+                                                &dst_ipv6.v);
+               }
+       }
+
+#define PRINT_MASKED_VAL_L2(type, name, fld, p, format) {\
+       MASK_VAL_L2(type, name, fld);                    \
+       PRINT_MASKED_VAL(name, p, format);               \
+}
+
+       PRINT_MASKED_VAL_L2(u8, ip_protocol, ip_protocol, p, "%02x");
+       PRINT_MASKED_VAL_L2(u16, tcp_flags, tcp_flags, p, "%x");
+       PRINT_MASKED_VAL_L2(u16, tcp_sport, tcp_sport, p, "%u");
+       PRINT_MASKED_VAL_L2(u16, tcp_dport, tcp_dport, p, "%u");
+       PRINT_MASKED_VAL_L2(u16, udp_sport, udp_sport, p, "%u");
+       PRINT_MASKED_VAL_L2(u16, udp_dport, udp_dport, p, "%u");
+       PRINT_MASKED_VAL_L2(u16, first_vid, first_vid, p, "%04x");
+       PRINT_MASKED_VAL_L2(u8, first_prio, first_prio, p, "%x");
+       PRINT_MASKED_VAL_L2(u8, first_cfi, first_cfi, p, "%d");
+       PRINT_MASKED_VAL_L2(u8, ip_dscp, ip_dscp, p, "%02x");
+       PRINT_MASKED_VAL_L2(u8, ip_ecn, ip_ecn, p, "%x");
+       PRINT_MASKED_VAL_L2(u8, cvlan_tag, cvlan_tag, p, "%d");
+       PRINT_MASKED_VAL_L2(u8, svlan_tag, svlan_tag, p, "%d");
+       PRINT_MASKED_VAL_L2(u8, frag, frag, p, "%d");
+}
+
+static void print_misc_parameters_hdrs(struct trace_seq *p,
+                                      const u32 *mask, const u32 *value)
+{
+#define MASK_VAL_MISC(type, name, fld) \
+       MASK_VAL(type, fte_match_set_misc, name, mask, value, fld)
+#define PRINT_MASKED_VAL_MISC(type, name, fld, p, format) {\
+       MASK_VAL_MISC(type, name, fld);                    \
+       PRINT_MASKED_VAL(name, p, format);                 \
+}
+       DECLARE_MASK_VAL(u64, gre_key) = {
+               .m = MLX5_GET(fte_match_set_misc, mask, gre_key_h) << 8 |
+                    MLX5_GET(fte_match_set_misc, mask, gre_key_l),
+               .v = MLX5_GET(fte_match_set_misc, value, gre_key_h) << 8 |
+                    MLX5_GET(fte_match_set_misc, value, gre_key_l)};
+
+       PRINT_MASKED_VAL(gre_key, p, "%llu");
+       PRINT_MASKED_VAL_MISC(u32, source_sqn, source_sqn, p, "%u");
+       PRINT_MASKED_VAL_MISC(u16, source_port, source_port, p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, outer_second_prio, outer_second_prio,
+                             p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, outer_second_cfi, outer_second_cfi, p, "%u");
+       PRINT_MASKED_VAL_MISC(u16, outer_second_vid, outer_second_vid, p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, inner_second_prio, inner_second_prio,
+                             p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, inner_second_cfi, inner_second_cfi, p, "%u");
+       PRINT_MASKED_VAL_MISC(u16, inner_second_vid, inner_second_vid, p, "%u");
+
+       PRINT_MASKED_VAL_MISC(u8, outer_second_cvlan_tag,
+                             outer_second_cvlan_tag, p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, inner_second_cvlan_tag,
+                             inner_second_cvlan_tag, p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, outer_second_svlan_tag,
+                             outer_second_svlan_tag, p, "%u");
+       PRINT_MASKED_VAL_MISC(u8, inner_second_svlan_tag,
+                             inner_second_svlan_tag, p, "%u");
+
+       PRINT_MASKED_VAL_MISC(u8, gre_protocol, gre_protocol, p, "%u");
+
+       PRINT_MASKED_VAL_MISC(u32, vxlan_vni, vxlan_vni, p, "%u");
+       PRINT_MASKED_VAL_MISC(u32, outer_ipv6_flow_label, outer_ipv6_flow_label,
+                             p, "%x");
+       PRINT_MASKED_VAL_MISC(u32, inner_ipv6_flow_label, inner_ipv6_flow_label,
+                             p, "%x");
+}
+
+const char *parse_fs_hdrs(struct trace_seq *p,
+                         u8 match_criteria_enable,
+                         const u32 *mask_outer,
+                         const u32 *mask_misc,
+                         const u32 *mask_inner,
+                         const u32 *value_outer,
+                         const u32 *value_misc,
+                         const u32 *value_inner)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       if (match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
+               trace_seq_printf(p, "[outer] ");
+               print_lyr_2_4_hdrs(p, mask_outer, value_outer);
+       }
+
+       if (match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
+               trace_seq_printf(p, "[misc] ");
+               print_misc_parameters_hdrs(p, mask_misc, value_misc);
+       }
+       if (match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
+               trace_seq_printf(p, "[inner] ");
+               print_lyr_2_4_hdrs(p, mask_inner, value_inner);
+       }
+       trace_seq_putc(p, 0);
+       return ret;
+}
+
+const char *parse_fs_dst(struct trace_seq *p,
+                        const struct mlx5_flow_destination *dst,
+                        u32 counter_id)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       switch (dst->type) {
+       case MLX5_FLOW_DESTINATION_TYPE_VPORT:
+               trace_seq_printf(p, "vport=%u\n", dst->vport_num);
+               break;
+       case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
+               trace_seq_printf(p, "ft=%p\n", dst->ft);
+               break;
+       case MLX5_FLOW_DESTINATION_TYPE_TIR:
+               trace_seq_printf(p, "tir=%u\n", dst->tir_num);
+               break;
+       case MLX5_FLOW_DESTINATION_TYPE_COUNTER:
+               trace_seq_printf(p, "counter_id=%u\n", counter_id);
+               break;
+       }
+
+       trace_seq_putc(p, 0);
+       return ret;
+}
+
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_add_fg);
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_fg);
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_set_fte);
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_fte);
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_add_rule);
+EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_rule);
+