Mon, Sep 12, 2016 at 10:12:36AM CEST, rahul.lakkire...@chelsio.com wrote:
>Add debugfs support to dump filter debug information.

Please no debugfs. Why would you want to use it?
Use a well defined user api instead. If not available, please introduce it.



>
>Signed-off-by: Rahul Lakkireddy <rahul.lakkire...@chelsio.com>
>Signed-off-by: Hariprasad Shenai <haripra...@chelsio.com>
>---
> drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c |   4 +-
> drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c  | 415 +++++++++++++++++++++
> drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h  |   2 +
> drivers/net/ethernet/chelsio/cxgb4/t4_values.h     |   5 +-
> 4 files changed, 424 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c 
>b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
>index 91fb508..72cf3de2 100644
>--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
>+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
>@@ -1,7 +1,7 @@
> /*
>  * This file is part of the Chelsio T4 Ethernet driver for Linux.
>  *
>- * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
>+ * Copyright (c) 2003-2016 Chelsio Communications, Inc. 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
>@@ -45,6 +45,7 @@
> #include "cxgb4_debugfs.h"
> #include "clip_tbl.h"
> #include "l2t.h"
>+#include "cxgb4_filter.h"
> 
> /* generic seq_file support for showing a table of size rows x width. */
> static void *seq_tab_get_idx(struct seq_tab *tb, loff_t pos)
>@@ -3272,6 +3273,7 @@ int t4_setup_debugfs(struct adapter *adap)
>               { "tids", &tid_info_debugfs_fops, S_IRUSR, 0},
>               { "blocked_fl", &blocked_fl_fops, S_IRUSR | S_IWUSR, 0 },
>               { "meminfo", &meminfo_fops, S_IRUSR, 0 },
>+              { "filters", &filters_debugfs_fops, S_IRUSR, 0 },
>       };
> 
>       /* Debug FS nodes common to all T5 and later adapters.
>diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c 
>b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
>index 490bd94..51b6745 100644
>--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
>+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
>@@ -34,6 +34,7 @@
> 
> #include "cxgb4.h"
> #include "t4_regs.h"
>+#include "t4_values.h"
> #include "l2t.h"
> #include "t4fw_api.h"
> #include "cxgb4_filter.h"
>@@ -669,3 +670,417 @@ void filter_rpl(struct adapter *adap, const struct 
>cpl_set_tcb_rpl *rpl)
>                       complete(&ctx->completion);
>       }
> }
>+
>+/* Retrieve the packet count for the specified filter. */
>+int cxgb4_get_filter_count(struct adapter *adapter, unsigned int fidx,
>+                         u64 *c, int hash, bool get_byte)
>+{
>+      struct filter_entry *f;
>+      unsigned int tcb_base, tcbaddr;
>+      unsigned int max_ftids;
>+      int ret;
>+
>+      tcb_base = t4_read_reg(adapter, TP_CMM_TCB_BASE_A);
>+      max_ftids = adapter->tids.nftids;
>+      if ((fidx != (max_ftids + adapter->tids.nsftids - 1)) &&
>+          (fidx >= max_ftids))
>+              return -E2BIG;
>+
>+      f = &adapter->tids.ftid_tab[fidx];
>+      if (!f->valid)
>+              return -EINVAL;
>+
>+      tcbaddr = tcb_base + f->tid * TCB_SIZE;
>+
>+      if (is_t4(adapter->params.chip)) {
>+              /* For T4, the Filter Packet Hit Count is maintained as a
>+               * 64-bit Big Endian value in the TCB fields
>+               * {t_rtt_ts_recent_age, t_rtseq_recent} ... The format in
>+               * memory is swizzled/mapped in a manner such that instead
>+               * of having this 64-bit counter show up at offset 24
>+               * ((TCB_T_RTT_TS_RECENT_AGE_W == 6) * sizeof(u32)), it
>+               * actually shows up at offset 16. Hence the constant "4"
>+               * below instead of TCB_T_RTT_TS_RECENT_AGE_W.
>+               */
>+              if (get_byte) {
>+                      unsigned int word_offset = 4;
>+                      __be64 be64_byte_count;
>+
>+                      spin_lock(&adapter->win0_lock);
>+                      ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
>+                                         tcbaddr +
>+                                         (word_offset * sizeof(__be32)),
>+                                         sizeof(be64_byte_count),
>+                                         &be64_byte_count,
>+                                         T4_MEMORY_READ);
>+                      spin_unlock(&adapter->win0_lock);
>+                      if (ret < 0)
>+                              return ret;
>+                      *c = be64_to_cpu(be64_byte_count);
>+              } else {
>+                      unsigned int word_offset = 4;
>+                      __be64 be64_count;
>+
>+                      spin_lock(&adapter->win0_lock);
>+                      ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
>+                                         tcbaddr +
>+                                         (word_offset * sizeof(__be32)),
>+                                         sizeof(be64_count),
>+                                         (__be32 *)&be64_count,
>+                                         T4_MEMORY_READ);
>+                      spin_unlock(&adapter->win0_lock);
>+                      if (ret < 0)
>+                              return ret;
>+                      *c = be64_to_cpu(be64_count);
>+              }
>+      } else {
>+              /* For T5, the Filter Packet Hit Count is maintained as a
>+               * 32-bit Big Endian value in the TCB field {timestamp}.
>+               * Instead of the filter hit count showing up at offset 20
>+               * ((TCB_TIMESTAMP_W == 5) * sizeof(u32)), it actually shows
>+               * up at offset 24.  Hence the constant "6" below.
>+               */
>+              if (get_byte) {
>+                      unsigned int word_offset = 4;
>+                      __be64 be64_byte_count;
>+
>+                      spin_lock(&adapter->win0_lock);
>+                      ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
>+                                         tcbaddr +
>+                                         (word_offset * sizeof(__be32)),
>+                                         sizeof(be64_byte_count),
>+                                         &be64_byte_count,
>+                                         T4_MEMORY_READ);
>+                      spin_unlock(&adapter->win0_lock);
>+                      if (ret < 0)
>+                              return ret;
>+                      *c = be64_to_cpu(be64_byte_count);
>+              } else {
>+                      unsigned int word_offset = 6;
>+                      __be32 be32_count;
>+
>+                      spin_lock(&adapter->win0_lock);
>+                      ret = t4_memory_rw(adapter, MEMWIN_NIC, MEM_EDC0,
>+                                         tcbaddr +
>+                                         (word_offset * sizeof(__be32)),
>+                                         sizeof(be32_count), &be32_count,
>+                                         T4_MEMORY_READ);
>+                      spin_unlock(&adapter->win0_lock);
>+                      if (ret < 0)
>+                              return ret;
>+                      *c = (u64)be32_to_cpu(be32_count);
>+              }
>+      }
>+
>+      return 0;
>+}
>+
>+/* Filter Table. */
>+static void filters_show_ipaddr(struct seq_file *seq,
>+                              int type, u8 *addr, u8 *addrm)
>+{
>+      int noctets, octet;
>+
>+      seq_puts(seq, " ");
>+      if (type == 0) {
>+              noctets = 4;
>+              seq_printf(seq, "%48s", " ");
>+      } else {
>+              noctets = 16;
>+      }
>+
>+      for (octet = 0; octet < noctets; octet++)
>+              seq_printf(seq, "%02x", addr[octet]);
>+      seq_puts(seq, "/");
>+      for (octet = 0; octet < noctets; octet++)
>+              seq_printf(seq, "%02x", addrm[octet]);
>+}
>+
>+static void filters_display(struct seq_file *seq, unsigned int fidx,
>+                          struct filter_entry *f, int hash)
>+{
>+      struct adapter *adapter = seq->private;
>+      u32 fconf = adapter->params.tp.vlan_pri_map;
>+      u32 tpiconf = adapter->params.tp.ingress_config;
>+      int i;
>+
>+      /* Filter index */
>+      seq_printf(seq, "%4d%c%c", fidx,
>+                 (!f->locked  ? ' ' : '!'),
>+                 (!f->pending ? ' ' : (!f->valid ? '+' : '-')));
>+
>+      if (f->fs.hitcnts) {
>+              u64 hitcnt;
>+              int ret;
>+
>+              ret = cxgb4_get_filter_count(adapter, fidx, &hitcnt,
>+                                           hash, false);
>+              if (ret)
>+                      seq_printf(seq, " %20s", "hits={ERROR}");
>+              else
>+                      seq_printf(seq, " %20llu", hitcnt);
>+      } else {
>+              seq_printf(seq, " %20s", "Disabled");
>+      }
>+
>+      /* Compressed header portion of filter. */
>+      for (i = FT_FIRST_S; i <= FT_LAST_S; i++) {
>+              switch (fconf & (1 << i)) {
>+              case 0:
>+                      /* compressed filter field not enabled */
>+                      break;
>+
>+              case FCOE_F:
>+                      seq_printf(seq, "  %1d/%1d",
>+                                 f->fs.val.fcoe, f->fs.mask.fcoe);
>+                      break;
>+
>+              case PORT_F:
>+                      seq_printf(seq, "  %1d/%1d",
>+                                 f->fs.val.iport, f->fs.mask.iport);
>+                      break;
>+
>+              case VNIC_ID_F:
>+                      if ((tpiconf & VNIC_F) == 0)
>+                              seq_printf(seq, " %1d:%04x/%1d:%04x",
>+                                         f->fs.val.ovlan_vld,
>+                                         f->fs.val.ovlan,
>+                                         f->fs.mask.ovlan_vld,
>+                                         f->fs.mask.ovlan);
>+                      else
>+                              seq_printf(seq, " %1d:%1x:%02x/%1d:%1x:%02x",
>+                                         f->fs.val.ovlan_vld,
>+                                         (f->fs.val.ovlan >> 13) & 0x7,
>+                                         f->fs.val.ovlan & 0x7f,
>+                                         f->fs.mask.ovlan_vld,
>+                                         (f->fs.mask.ovlan >> 13) & 0x7,
>+                                         f->fs.mask.ovlan & 0x7f);
>+                      break;
>+
>+              case VLAN_F:
>+                      seq_printf(seq, " %1d:%04x/%1d:%04x",
>+                                 f->fs.val.ivlan_vld,
>+                                 f->fs.val.ivlan,
>+                                 f->fs.mask.ivlan_vld,
>+                                 f->fs.mask.ivlan);
>+                      break;
>+
>+              case TOS_F:
>+                      seq_printf(seq, " %02x/%02x",
>+                                 f->fs.val.tos, f->fs.mask.tos);
>+                      break;
>+
>+              case PROTOCOL_F:
>+                      seq_printf(seq, " %02x/%02x",
>+                                 f->fs.val.proto, f->fs.mask.proto);
>+                      break;
>+
>+              case ETHERTYPE_F:
>+                      seq_printf(seq, " %04x/%04x",
>+                                 f->fs.val.ethtype, f->fs.mask.ethtype);
>+                      break;
>+
>+              case MACMATCH_F:
>+                      seq_printf(seq, " %03x/%03x",
>+                                 f->fs.val.macidx, f->fs.mask.macidx);
>+                      break;
>+
>+              case MPSHITTYPE_F:
>+                      seq_printf(seq, " %1x/%1x",
>+                                 f->fs.val.matchtype,
>+                                 f->fs.mask.matchtype);
>+                      break;
>+
>+              case FRAGMENTATION_F:
>+                      seq_printf(seq, "  %1d/%1d",
>+                                 f->fs.val.frag, f->fs.mask.frag);
>+                      break;
>+              }
>+      }
>+
>+      /* Fixed portion of filter. */
>+      filters_show_ipaddr(seq, f->fs.type,
>+                          f->fs.val.lip, f->fs.mask.lip);
>+      filters_show_ipaddr(seq, f->fs.type,
>+                          f->fs.val.fip, f->fs.mask.fip);
>+      seq_printf(seq, " %04x/%04x %04x/%04x",
>+                 f->fs.val.lport, f->fs.mask.lport,
>+                 f->fs.val.fport, f->fs.mask.fport);
>+
>+      /* Variable length filter action. */
>+      if (f->fs.action == FILTER_DROP) {
>+              seq_puts(seq, " Drop");
>+      } else if (f->fs.action == FILTER_SWITCH) {
>+              seq_printf(seq, " Switch: port=%d", f->fs.eport);
>+              if (f->fs.newdmac)
>+                      seq_printf(seq,
>+                                 ", dmac=%02x:%02x:%02x:%02x:%02x:%02x, 
>l2tidx=%d",
>+                                 f->fs.dmac[0], f->fs.dmac[1],
>+                                 f->fs.dmac[2], f->fs.dmac[3],
>+                                 f->fs.dmac[4], f->fs.dmac[5],
>+                                 f->l2t->idx);
>+              if (f->fs.newsmac)
>+                      seq_printf(seq,
>+                                 ", smac=%02x:%02x:%02x:%02x:%02x:%02x, 
>smtidx=%d",
>+                                 f->fs.smac[0], f->fs.smac[1],
>+                                 f->fs.smac[2], f->fs.smac[3],
>+                                 f->fs.smac[4], f->fs.smac[5],
>+                                 f->smtidx);
>+              if (f->fs.newvlan == VLAN_REMOVE)
>+                      seq_puts(seq, ", vlan=none");
>+              else if (f->fs.newvlan == VLAN_INSERT)
>+                      seq_printf(seq, ", vlan=insert(%x)",
>+                                 f->fs.vlan);
>+              else if (f->fs.newvlan == VLAN_REWRITE)
>+                      seq_printf(seq, ", vlan=rewrite(%x)",
>+                                 f->fs.vlan);
>+      } else {
>+              seq_puts(seq, " Pass: Q=");
>+              if (f->fs.dirsteer == 0) {
>+                      seq_puts(seq, "RSS");
>+                      if (f->fs.maskhash)
>+                              seq_puts(seq, "(TCB=hash)");
>+              } else {
>+                      seq_printf(seq, "%d", f->fs.iq);
>+                      if (f->fs.dirsteerhash == 0)
>+                              seq_puts(seq, "(QID)");
>+                      else
>+                              seq_puts(seq, "(hash)");
>+              }
>+      }
>+      if (f->fs.prio)
>+              seq_puts(seq, " Prio");
>+      if (f->fs.rpttid)
>+              seq_puts(seq, " RptTID");
>+      seq_puts(seq, "\n");
>+}
>+
>+static int filters_show(struct seq_file *seq, void *v)
>+{
>+      struct adapter *adapter = seq->private;
>+      u32 fconf = adapter->params.tp.vlan_pri_map;
>+      u32 tpiconf = adapter->params.tp.ingress_config;
>+      int i;
>+
>+      if (v == SEQ_START_TOKEN) {
>+              seq_puts(seq, "[[Legend: '!' => locked; '+' => pending set; '-' 
>=> pending clear]]\n");
>+              seq_puts(seq, " Idx                   Hits");
>+              for (i = FT_FIRST_S; i <= FT_LAST_S; i++) {
>+                      switch (fconf & (1 << i)) {
>+                      case 0:
>+                              /* compressed filter field not enabled */
>+                              break;
>+
>+                      case FCOE_F:
>+                              seq_puts(seq, " FCoE");
>+                              break;
>+
>+                      case PORT_F:
>+                              seq_puts(seq, " Port");
>+                              break;
>+
>+                      case VNIC_ID_F:
>+                              if ((tpiconf & VNIC_F) == 0)
>+                                      seq_puts(seq, "     vld:oVLAN");
>+                              else
>+                                      seq_puts(seq, "   VFvld:PF:VF");
>+                              break;
>+
>+                      case VLAN_F:
>+                              seq_puts(seq, "     vld:iVLAN");
>+                              break;
>+
>+                      case TOS_F:
>+                              seq_puts(seq, "   TOS");
>+                              break;
>+
>+                      case PROTOCOL_F:
>+                              seq_puts(seq, "  Prot");
>+                              break;
>+
>+                      case ETHERTYPE_F:
>+                              seq_puts(seq, "   EthType");
>+                              break;
>+
>+                      case MACMATCH_F:
>+                              seq_puts(seq, "  MACIdx");
>+                              break;
>+
>+                      case MPSHITTYPE_F:
>+                              seq_puts(seq, " MPS");
>+                              break;
>+
>+                      case FRAGMENTATION_F:
>+                              seq_puts(seq, " Frag");
>+                              break;
>+                      }
>+              }
>+              seq_printf(seq, " %65s %65s %9s %9s %s\n",
>+                         "LIP", "FIP", "LPORT", "FPORT", "Action");
>+      } else {
>+              int fidx = (uintptr_t)v - 2;
>+              struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
>+
>+              /* if this entry isn't filled in just return */
>+              if (!f->valid && !f->pending)
>+                      return 0;
>+
>+              filters_display(seq, fidx, f, 0);
>+      }
>+      return 0;
>+}
>+
>+static inline void *filters_get_idx(struct adapter *adapter, loff_t pos)
>+{
>+      if (pos > (adapter->tids.nftids + adapter->tids.nsftids))
>+              return NULL;
>+
>+      return (void *)(uintptr_t)(pos + 1);
>+}
>+
>+static void *filters_start(struct seq_file *seq, loff_t *pos)
>+{
>+      struct adapter *adapter = seq->private;
>+
>+      return *pos ? filters_get_idx(adapter, *pos) : SEQ_START_TOKEN;
>+}
>+
>+static void *filters_next(struct seq_file *seq, void *v, loff_t *pos)
>+{
>+      struct adapter *adapter = seq->private;
>+
>+      (*pos)++;
>+      return filters_get_idx(adapter, *pos);
>+}
>+
>+static void filters_stop(struct seq_file *seq, void *v)
>+{
>+}
>+
>+static const struct seq_operations filters_seq_ops = {
>+      .start = filters_start,
>+      .next  = filters_next,
>+      .stop  = filters_stop,
>+      .show  = filters_show
>+};
>+
>+int filters_open(struct inode *inode, struct file *file)
>+{
>+      struct adapter *adapter = inode->i_private;
>+      int res;
>+
>+      res = seq_open(file, &filters_seq_ops);
>+      if (!res) {
>+              struct seq_file *seq = file->private_data;
>+
>+              seq->private = adapter;
>+      }
>+      return res;
>+}
>+
>+const struct file_operations filters_debugfs_fops = {
>+      .owner   = THIS_MODULE,
>+      .open    = filters_open,
>+      .read    = seq_read,
>+      .llseek  = seq_lseek,
>+};
>diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h 
>b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
>index 23742cb..e801e0b 100644
>--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
>+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
>@@ -37,6 +37,8 @@
> 
> #include "t4_msg.h"
> 
>+extern const struct file_operations filters_debugfs_fops;
>+
> void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl);
> void clear_filter(struct adapter *adap, struct filter_entry *f);
> 
>diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h 
>b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
>index 36cf307..0115222 100644
>--- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
>+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
>@@ -1,7 +1,7 @@
> /*
>  * This file is part of the Chelsio T4 Ethernet driver for Linux.
>  *
>- * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
>+ * Copyright (c) 2003-2016 Chelsio Communications, Inc. 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
>@@ -121,6 +121,9 @@
>  * selects for a particular field being present.  These fields, when present
>  * in the Compressed Filter Tuple, have the following widths in bits.
>  */
>+#define FT_FIRST_S                      FCOE_S
>+#define FT_LAST_S                       FRAGMENTATION_S
>+
> #define FT_FCOE_W                       1
> #define FT_PORT_W                       3
> #define FT_VNIC_ID_W                    17
>-- 
>2.5.3
>

Reply via email to