diff mbox series

[net-next,7/7] sfc: add debugfs node for filter table contents

Message ID 0cf27cb7a42cc81c8d360b5812690e636a100244.1702314695.git.ecree.xilinx@gmail.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series sfc: initial debugfs support | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline fail Detected static functions without inline keyword in header files: 1
netdev/build_32bit fail Errors and warnings before: 21 this patch: 1115
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang fail Errors and warnings before: 23 this patch: 1142
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 21 this patch: 1142
netdev/checkpatch warning CHECK: No space is necessary after a cast CHECK: Please use a blank line after function/struct/union/enum declarations WARNING: line length of 81 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

edward.cree@amd.com Dec. 11, 2023, 5:18 p.m. UTC
From: Edward Cree <ecree.xilinx@gmail.com>

Expose the filter table entries.

Reviewed-by: Jonathan Cooper <jonathan.s.cooper@amd.com>
Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/debugfs.c      | 117 +++++++++++++++++++++++-
 drivers/net/ethernet/sfc/debugfs.h      |  45 +++++++++
 drivers/net/ethernet/sfc/mcdi_filters.c |  39 ++++++++
 3 files changed, 197 insertions(+), 4 deletions(-)

Comments

Simon Horman Dec. 11, 2023, 7:17 p.m. UTC | #1
On Mon, Dec 11, 2023 at 05:18:32PM +0000, edward.cree@amd.com wrote:
> From: Edward Cree <ecree.xilinx@gmail.com>
> 
> Expose the filter table entries.
> 
> Reviewed-by: Jonathan Cooper <jonathan.s.cooper@amd.com>
> Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>

...

> diff --git a/drivers/net/ethernet/sfc/debugfs.h b/drivers/net/ethernet/sfc/debugfs.h

...

> @@ -63,6 +67,45 @@ void efx_fini_debugfs_nic(struct efx_nic *efx);
>  int efx_init_debugfs(void);
>  void efx_fini_debugfs(void);
>  
> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec);
> +
> +/* Generate operations for a debugfs node with a custom reader function.
> + * The reader should have signature int (*)(struct seq_file *s, void *data)
> + * where data is the pointer passed to EFX_DEBUGFS_CREATE_RAW.
> + */
> +#define EFX_DEBUGFS_RAW_PARAMETER(_reader)				       \
> +									       \
> +static int efx_debugfs_##_reader##_read(struct seq_file *s, void *d)	       \
> +{									       \
> +	return _reader(s, s->private);					       \
> +}									       \
> +									       \
> +static int efx_debugfs_##_reader##_open(struct inode *inode, struct file *f)   \
> +{									       \
> +	return single_open(f, efx_debugfs_##_reader##_read, inode->i_private); \
> +}									       \

Hi Edward,

I think that probably the above should be static inline.

...
Edward Cree Dec. 12, 2023, 1:58 p.m. UTC | #2
On 11/12/2023 19:17, Simon Horman wrote:
> On Mon, Dec 11, 2023 at 05:18:32PM +0000, edward.cree@amd.com wrote:
>> @@ -63,6 +67,45 @@ void efx_fini_debugfs_nic(struct efx_nic *efx);
>>  int efx_init_debugfs(void);
>>  void efx_fini_debugfs(void);
>>  
>> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec);
>> +
>> +/* Generate operations for a debugfs node with a custom reader function.
>> + * The reader should have signature int (*)(struct seq_file *s, void *data)
>> + * where data is the pointer passed to EFX_DEBUGFS_CREATE_RAW.
>> + */
>> +#define EFX_DEBUGFS_RAW_PARAMETER(_reader)				       \
>> +									       \
>> +static int efx_debugfs_##_reader##_read(struct seq_file *s, void *d)	       \
>> +{									       \
>> +	return _reader(s, s->private);					       \
>> +}									       \
>> +									       \
>> +static int efx_debugfs_##_reader##_open(struct inode *inode, struct file *f)   \
>> +{									       \
>> +	return single_open(f, efx_debugfs_##_reader##_read, inode->i_private); \
>> +}									       \
> 
> Hi Edward,
> 
> I think that probably the above should be static inline.

Yep, in fact there are instances of this from patch 2 onwards (most
 of those aren't even static).  Clearly I hadn't had enough sleep
 the day I wrote this :/
Will fix in v2, along with the build break on #6.
Thanks for reviewing.

-ed
Edward Cree Dec. 12, 2023, 3:14 p.m. UTC | #3
On 12/12/2023 13:58, Edward Cree wrote:
> On 11/12/2023 19:17, Simon Horman wrote:
>> On Mon, Dec 11, 2023 at 05:18:32PM +0000, edward.cree@amd.com wrote:
>>> @@ -63,6 +67,45 @@ void efx_fini_debugfs_nic(struct efx_nic *efx);
>>>  int efx_init_debugfs(void);
>>>  void efx_fini_debugfs(void);
>>>  
>>> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec);
>>> +
>>> +/* Generate operations for a debugfs node with a custom reader function.
>>> + * The reader should have signature int (*)(struct seq_file *s, void *data)
>>> + * where data is the pointer passed to EFX_DEBUGFS_CREATE_RAW.
>>> + */
>>> +#define EFX_DEBUGFS_RAW_PARAMETER(_reader)				       \
>>> +									       \
>>> +static int efx_debugfs_##_reader##_read(struct seq_file *s, void *d)	       \
>>> +{									       \
>>> +	return _reader(s, s->private);					       \
>>> +}									       \
>>> +									       \
>>> +static int efx_debugfs_##_reader##_open(struct inode *inode, struct file *f)   \
>>> +{									       \
>>> +	return single_open(f, efx_debugfs_##_reader##_read, inode->i_private); \
>>> +}									       \
>>
>> Hi Edward,
>>
>> I think that probably the above should be static inline.
> 
> Yep, in fact there are instances of this from patch 2 onwards (most
>  of those aren't even static).  Clearly I hadn't had enough sleep
>  the day I wrote this :/
Or maybe it's *today* I haven't had enough sleep...
Unlike the functions in patches 2-4, which are stubs for the
 CONFIG_DEBUG_FS=n build, these functions should *not* be "static
 inline", because they are intended to be referenced from ops
 structs or passed as callbacks.
The check on patchwork is actually a false positive here, because
 this is not a function that's defined in the header file.  It's
 part of the body of a *macro*, EFX_DEBUGFS_RAW_PARAMETER.
Functions are only defined when some C file expands the macro.

I will update the commit message to call out and explain this; I
 believe the code is actually fine.

-ed
Jakub Kicinski Dec. 12, 2023, 4:19 p.m. UTC | #4
On Tue, 12 Dec 2023 15:14:17 +0000 Edward Cree wrote:
> On 12/12/2023 13:58, Edward Cree wrote:
> > On 11/12/2023 19:17, Simon Horman wrote:  
> >> On Mon, Dec 11, 2023 at 05:18:32PM +0000, edward.cree@amd.com wrote:  
>  [...]  
> >>
> >> Hi Edward,
> >>
> >> I think that probably the above should be static inline.  
> > 
> > Yep, in fact there are instances of this from patch 2 onwards (most
> >  of those aren't even static).  Clearly I hadn't had enough sleep
> >  the day I wrote this :/  
> Or maybe it's *today* I haven't had enough sleep...
> Unlike the functions in patches 2-4, which are stubs for the
>  CONFIG_DEBUG_FS=n build, these functions should *not* be "static
>  inline", because they are intended to be referenced from ops
>  structs or passed as callbacks.
> The check on patchwork is actually a false positive here, because
>  this is not a function that's defined in the header file.  It's
>  part of the body of a *macro*, EFX_DEBUGFS_RAW_PARAMETER.
> Functions are only defined when some C file expands the macro.
> 
> I will update the commit message to call out and explain this; I
>  believe the code is actually fine.

Fair point, second time in a ~month we see this sort of false positive.
I'll throw [^\\]$ at the end of the regex to try to avoid matching stuff
that's most likely a macro.

This one looks legit tho:

+void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec) {}
Edward Cree Dec. 13, 2023, 12:15 p.m. UTC | #5
On 12/12/2023 16:19, Jakub Kicinski wrote:
> On Tue, 12 Dec 2023 15:14:17 +0000 Edward Cree wrote:
>> I will update the commit message to call out and explain this; I
>>  believe the code is actually fine.
> 
> Fair point, second time in a ~month we see this sort of false positive.
> I'll throw [^\\]$ at the end of the regex to try to avoid matching stuff
> that's most likely a macro.

Sounds good, thanks.

> This one looks legit tho:
> 
> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec) {}

Yep, that one's real, will be fixed in v2.
And this time I'll actually build-test with CONFIG_DEBUG_FS=n,
 which I forgot to do with v1 (sorry).

-ed
Simon Horman Dec. 14, 2023, 4:56 p.m. UTC | #6
On Wed, Dec 13, 2023 at 12:15:04PM +0000, Edward Cree wrote:
> On 12/12/2023 16:19, Jakub Kicinski wrote:
> > On Tue, 12 Dec 2023 15:14:17 +0000 Edward Cree wrote:
> >> I will update the commit message to call out and explain this; I
> >>  believe the code is actually fine.
> > 
> > Fair point, second time in a ~month we see this sort of false positive.
> > I'll throw [^\\]$ at the end of the regex to try to avoid matching stuff
> > that's most likely a macro.
> 
> Sounds good, thanks.
> 
> > This one looks legit tho:
> > 
> > +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec) {}
> 
> Yep, that one's real, will be fixed in v2.
> And this time I'll actually build-test with CONFIG_DEBUG_FS=n,
>  which I forgot to do with v1 (sorry).

Thanks, and sorry for the false positives.
Also, I like coffee :)

> 
> -ed
Nelson, Shannon Dec. 15, 2023, 12:05 a.m. UTC | #7
On 12/11/2023 9:18 AM, edward.cree@amd.com wrote:
> 
> From: Edward Cree <ecree.xilinx@gmail.com>
> 
> Expose the filter table entries.
> 
> Reviewed-by: Jonathan Cooper <jonathan.s.cooper@amd.com>
> Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
> ---
>   drivers/net/ethernet/sfc/debugfs.c      | 117 +++++++++++++++++++++++-
>   drivers/net/ethernet/sfc/debugfs.h      |  45 +++++++++
>   drivers/net/ethernet/sfc/mcdi_filters.c |  39 ++++++++
>   3 files changed, 197 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/sfc/debugfs.c b/drivers/net/ethernet/sfc/debugfs.c
> index 549ff1ee273e..e67b0fc927fe 100644
> --- a/drivers/net/ethernet/sfc/debugfs.c
> +++ b/drivers/net/ethernet/sfc/debugfs.c
> @@ -9,10 +9,6 @@
>    */
> 
>   #include "debugfs.h"
> -#include <linux/module.h>
> -#include <linux/debugfs.h>
> -#include <linux/dcache.h>
> -#include <linux/seq_file.h>

Can you leave these out of the original patch and not have to remove 
them here?

> 
>   /* Maximum length for a name component or symlink target */
>   #define EFX_DEBUGFS_NAME_LEN 32
> @@ -428,3 +424,116 @@ void efx_fini_debugfs(void)
>          efx_debug_cards = NULL;
>          efx_debug_root = NULL;
>   }
> +
> +/**
> + * efx_debugfs_print_filter - format a filter spec for display
> + * @s: buffer to write result into
> + * @l: length of buffer @s
> + * @spec: filter specification
> + */
> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec)
> +{
> +       u32 ip[4];
> +       int p = snprintf(s, l, "match=%#x,pri=%d,flags=%#x,q=%d",
> +                        spec->match_flags, spec->priority, spec->flags,
> +                        spec->dmaq_id);
> +
> +       if (spec->vport_id)
> +               p += snprintf(s + p, l - p, ",vport=%#x", spec->vport_id);
> +
> +       if (spec->flags & EFX_FILTER_FLAG_RX_RSS)
> +               p += snprintf(s + p, l - p, ",rss=%#x", spec->rss_context);
> +
> +       if (spec->match_flags & EFX_FILTER_MATCH_OUTER_VID)
> +               p += snprintf(s + p, l - p,
> +                             ",ovid=%d", ntohs(spec->outer_vid));
> +       if (spec->match_flags & EFX_FILTER_MATCH_INNER_VID)
> +               p += snprintf(s + p, l - p,
> +                             ",ivid=%d", ntohs(spec->inner_vid));
> +       if (spec->match_flags & EFX_FILTER_MATCH_ENCAP_TYPE)
> +               p += snprintf(s + p, l - p,
> +                             ",encap=%d", spec->encap_type);
> +       if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC)
> +               p += snprintf(s + p, l - p,
> +                             ",lmac=%02x:%02x:%02x:%02x:%02x:%02x",
> +                             spec->loc_mac[0], spec->loc_mac[1],
> +                             spec->loc_mac[2], spec->loc_mac[3],
> +                             spec->loc_mac[4], spec->loc_mac[5]);
> +       if (spec->match_flags & EFX_FILTER_MATCH_REM_MAC)
> +               p += snprintf(s + p, l - p,
> +                             ",rmac=%02x:%02x:%02x:%02x:%02x:%02x",
> +                             spec->rem_mac[0], spec->rem_mac[1],
> +                             spec->rem_mac[2], spec->rem_mac[3],
> +                             spec->rem_mac[4], spec->rem_mac[5]);
> +       if (spec->match_flags & EFX_FILTER_MATCH_ETHER_TYPE)
> +               p += snprintf(s + p, l - p,
> +                             ",ether=%#x", ntohs(spec->ether_type));
> +       if (spec->match_flags & EFX_FILTER_MATCH_IP_PROTO)
> +               p += snprintf(s + p, l - p,
> +                             ",ippr=%#x", spec->ip_proto);
> +       if (spec->match_flags & EFX_FILTER_MATCH_LOC_HOST) {
> +               if (ntohs(spec->ether_type) == ETH_P_IP) {
> +                       ip[0] = (__force u32) spec->loc_host[0];
> +                       p += snprintf(s + p, l - p,
> +                                     ",lip=%d.%d.%d.%d",
> +                                     ip[0] & 0xff,
> +                                     (ip[0] >> 8) & 0xff,
> +                                     (ip[0] >> 16) & 0xff,
> +                                     (ip[0] >> 24) & 0xff);
> +               } else if (ntohs(spec->ether_type) == ETH_P_IPV6) {
> +                       ip[0] = (__force u32) spec->loc_host[0];
> +                       ip[1] = (__force u32) spec->loc_host[1];
> +                       ip[2] = (__force u32) spec->loc_host[2];
> +                       ip[3] = (__force u32) spec->loc_host[3];
> +                       p += snprintf(s + p, l - p,
> +                                     ",lip=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
> +                                     ip[0] & 0xffff,
> +                                     (ip[0] >> 16) & 0xffff,
> +                                     ip[1] & 0xffff,
> +                                     (ip[1] >> 16) & 0xffff,
> +                                     ip[2] & 0xffff,
> +                                     (ip[2] >> 16) & 0xffff,
> +                                     ip[3] & 0xffff,
> +                                     (ip[3] >> 16) & 0xffff);
> +               } else {
> +                       p += snprintf(s + p, l - p, ",lip=?");
> +               }
> +       }
> +       if (spec->match_flags & EFX_FILTER_MATCH_REM_HOST) {
> +               if (ntohs(spec->ether_type) == ETH_P_IP) {
> +                       ip[0] = (__force u32) spec->rem_host[0];
> +                       p += snprintf(s + p, l - p,
> +                                     ",rip=%d.%d.%d.%d",
> +                                     ip[0] & 0xff,
> +                                     (ip[0] >> 8) & 0xff,
> +                                     (ip[0] >> 16) & 0xff,
> +                                     (ip[0] >> 24) & 0xff);
> +               } else if (ntohs(spec->ether_type) == ETH_P_IPV6) {
> +                       ip[0] = (__force u32) spec->rem_host[0];
> +                       ip[1] = (__force u32) spec->rem_host[1];
> +                       ip[2] = (__force u32) spec->rem_host[2];
> +                       ip[3] = (__force u32) spec->rem_host[3];
> +                       p += snprintf(s + p, l - p,
> +                                     ",rip=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
> +                                     ip[0] & 0xffff,
> +                                     (ip[0] >> 16) & 0xffff,
> +                                     ip[1] & 0xffff,
> +                                     (ip[1] >> 16) & 0xffff,
> +                                     ip[2] & 0xffff,
> +                                     (ip[2] >> 16) & 0xffff,
> +                                     ip[3] & 0xffff,
> +                                     (ip[3] >> 16) & 0xffff);
> +               } else {
> +                       p += snprintf(s + p, l - p, ",rip=?");
> +               }

Since you have this code more than once, it might be a candidate for a 
utility function, if one doesn't already exist somewhere in the kernel 
already.

> +       }
> +       if (spec->match_flags & EFX_FILTER_MATCH_LOC_PORT)
> +               p += snprintf(s + p, l - p,
> +                             ",lport=%d", ntohs(spec->loc_port));
> +       if (spec->match_flags & EFX_FILTER_MATCH_REM_PORT)
> +               p += snprintf(s + p, l - p,
> +                             ",rport=%d", ntohs(spec->rem_port));
> +       if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC_IG)
> +               p += snprintf(s + p, l - p, ",%s",
> +                             spec->loc_mac[0] ? "mc" : "uc");
> +}
> diff --git a/drivers/net/ethernet/sfc/debugfs.h b/drivers/net/ethernet/sfc/debugfs.h
> index 7a96f3798cbd..f50b4bf33a6b 100644
> --- a/drivers/net/ethernet/sfc/debugfs.h
> +++ b/drivers/net/ethernet/sfc/debugfs.h
> @@ -10,6 +10,10 @@
> 
>   #ifndef EFX_DEBUGFS_H
>   #define EFX_DEBUGFS_H
> +#include <linux/module.h>
> +#include <linux/debugfs.h>
> +#include <linux/dcache.h>
> +#include <linux/seq_file.h>
>   #include "net_driver.h"
> 
>   #ifdef CONFIG_DEBUG_FS
> @@ -63,6 +67,45 @@ void efx_fini_debugfs_nic(struct efx_nic *efx);
>   int efx_init_debugfs(void);
>   void efx_fini_debugfs(void);
> 
> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec);
> +
> +/* Generate operations for a debugfs node with a custom reader function.
> + * The reader should have signature int (*)(struct seq_file *s, void *data)
> + * where data is the pointer passed to EFX_DEBUGFS_CREATE_RAW.
> + */
> +#define EFX_DEBUGFS_RAW_PARAMETER(_reader)                                    \
> +                                                                              \
> +static int efx_debugfs_##_reader##_read(struct seq_file *s, void *d)          \
> +{                                                                             \
> +       return _reader(s, s->private);                                         \
> +}                                                                             \
> +                                                                              \
> +static int efx_debugfs_##_reader##_open(struct inode *inode, struct file *f)   \
> +{                                                                             \
> +       return single_open(f, efx_debugfs_##_reader##_read, inode->i_private); \
> +}                                                                             \
> +                                                                              \
> +static const struct file_operations efx_debugfs_##_reader##_ops = {           \
> +       .owner = THIS_MODULE,                                                  \
> +       .open = efx_debugfs_##_reader##_open,                                  \
> +       .release = single_release,                                             \
> +       .read = seq_read,                                                      \
> +       .llseek = seq_lseek,                                                   \
> +};                                                                            \
> +                                                                              \
> +static void efx_debugfs_create_##_reader(const char *name, umode_t mode,       \
> +                                        struct dentry *parent, void *data)    \
> +{                                                                             \
> +       debugfs_create_file(name, mode, parent, data,                          \
> +                           &efx_debugfs_##_reader##_ops);                     \
> +}
> +
> +/* Instantiate a debugfs node with a custom reader function.  The operations
> + * must have been generated with EFX_DEBUGFS_RAW_PARAMETER(_reader).
> + */
> +#define EFX_DEBUGFS_CREATE_RAW(_name, _mode, _parent, _data, _reader)         \
> +               efx_debugfs_create_##_reader(_name, _mode, _parent, _data)
> +
>   #else /* CONFIG_DEBUG_FS */
> 
>   static inline void efx_fini_debugfs_netdev(struct net_device *net_dev) {}
> @@ -99,6 +142,8 @@ static inline int efx_init_debugfs(void)
>   }
>   static inline void efx_fini_debugfs(void) {}
> 
> +void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec) {}
> +
>   #endif /* CONFIG_DEBUG_FS */
> 
>   #endif /* EFX_DEBUGFS_H */
> diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c
> index a4ab45082c8f..465226c3e8c7 100644
> --- a/drivers/net/ethernet/sfc/mcdi_filters.c
> +++ b/drivers/net/ethernet/sfc/mcdi_filters.c
> @@ -13,6 +13,7 @@
>   #include "mcdi.h"
>   #include "nic.h"
>   #include "rx_common.h"
> +#include "debugfs.h"
> 
>   /* The maximum size of a shared RSS context */
>   /* TODO: this should really be from the mcdi protocol export */
> @@ -1173,6 +1174,42 @@ s32 efx_mcdi_filter_get_rx_ids(struct efx_nic *efx,
>          return count;
>   }
> 
> +static int efx_debugfs_read_filter_list(struct seq_file *file, void *data)
> +{
> +       struct efx_mcdi_filter_table *table;
> +       struct efx_nic *efx = data;
> +       int i;
> +
> +       down_read(&efx->filter_sem);
> +       table = efx->filter_state;
> +       if (!table || !table->entry) {
> +               up_read(&efx->filter_sem);
> +               return -ENETDOWN;
> +       }
> +
> +       /* deliberately don't lock the table->lock, so that we can
> +        * still dump the table even if we hang mid-operation.
> +        */
> +       for (i = 0; i < EFX_MCDI_FILTER_TBL_ROWS; ++i) {
> +               struct efx_filter_spec *spec =
> +                       efx_mcdi_filter_entry_spec(table, i);
> +               char filter[256];
> +
> +               if (spec) {
> +                       efx_debugfs_print_filter(filter, sizeof(filter), spec);
> +
> +                       seq_printf(file, "%d[%#04llx],%#x = %s\n",
> +                                  i, table->entry[i].handle & 0xffff,
> +                                  efx_mcdi_filter_entry_flags(table, i),
> +                                  filter);
> +               }
> +       }
> +
> +       up_read(&efx->filter_sem);
> +       return 0;
> +}
> +EFX_DEBUGFS_RAW_PARAMETER(efx_debugfs_read_filter_list);
> +
>   static int efx_mcdi_filter_match_flags_from_mcdi(bool encap, u32 mcdi_flags)
>   {
>          int match_flags = 0;
> @@ -1360,6 +1397,8 @@ int efx_mcdi_filter_table_probe(struct efx_nic *efx, bool multicast_chaining)
>                              &table->mc_overflow);
>          debugfs_create_bool("mc_chaining", 0444, table->debug_dir,
>                              &table->mc_chaining);
> +       EFX_DEBUGFS_CREATE_RAW("entries", 0444, table->debug_dir, efx,
> +                              efx_debugfs_read_filter_list);
>   #endif
> 
>          efx->filter_state = table;
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/sfc/debugfs.c b/drivers/net/ethernet/sfc/debugfs.c
index 549ff1ee273e..e67b0fc927fe 100644
--- a/drivers/net/ethernet/sfc/debugfs.c
+++ b/drivers/net/ethernet/sfc/debugfs.c
@@ -9,10 +9,6 @@ 
  */
 
 #include "debugfs.h"
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/dcache.h>
-#include <linux/seq_file.h>
 
 /* Maximum length for a name component or symlink target */
 #define EFX_DEBUGFS_NAME_LEN 32
@@ -428,3 +424,116 @@  void efx_fini_debugfs(void)
 	efx_debug_cards = NULL;
 	efx_debug_root = NULL;
 }
+
+/**
+ * efx_debugfs_print_filter - format a filter spec for display
+ * @s: buffer to write result into
+ * @l: length of buffer @s
+ * @spec: filter specification
+ */
+void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec)
+{
+	u32 ip[4];
+	int p = snprintf(s, l, "match=%#x,pri=%d,flags=%#x,q=%d",
+			 spec->match_flags, spec->priority, spec->flags,
+			 spec->dmaq_id);
+
+	if (spec->vport_id)
+		p += snprintf(s + p, l - p, ",vport=%#x", spec->vport_id);
+
+	if (spec->flags & EFX_FILTER_FLAG_RX_RSS)
+		p += snprintf(s + p, l - p, ",rss=%#x", spec->rss_context);
+
+	if (spec->match_flags & EFX_FILTER_MATCH_OUTER_VID)
+		p += snprintf(s + p, l - p,
+			      ",ovid=%d", ntohs(spec->outer_vid));
+	if (spec->match_flags & EFX_FILTER_MATCH_INNER_VID)
+		p += snprintf(s + p, l - p,
+			      ",ivid=%d", ntohs(spec->inner_vid));
+	if (spec->match_flags & EFX_FILTER_MATCH_ENCAP_TYPE)
+		p += snprintf(s + p, l - p,
+			      ",encap=%d", spec->encap_type);
+	if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC)
+		p += snprintf(s + p, l - p,
+			      ",lmac=%02x:%02x:%02x:%02x:%02x:%02x",
+			      spec->loc_mac[0], spec->loc_mac[1],
+			      spec->loc_mac[2], spec->loc_mac[3],
+			      spec->loc_mac[4], spec->loc_mac[5]);
+	if (spec->match_flags & EFX_FILTER_MATCH_REM_MAC)
+		p += snprintf(s + p, l - p,
+			      ",rmac=%02x:%02x:%02x:%02x:%02x:%02x",
+			      spec->rem_mac[0], spec->rem_mac[1],
+			      spec->rem_mac[2], spec->rem_mac[3],
+			      spec->rem_mac[4], spec->rem_mac[5]);
+	if (spec->match_flags & EFX_FILTER_MATCH_ETHER_TYPE)
+		p += snprintf(s + p, l - p,
+			      ",ether=%#x", ntohs(spec->ether_type));
+	if (spec->match_flags & EFX_FILTER_MATCH_IP_PROTO)
+		p += snprintf(s + p, l - p,
+			      ",ippr=%#x", spec->ip_proto);
+	if (spec->match_flags & EFX_FILTER_MATCH_LOC_HOST) {
+		if (ntohs(spec->ether_type) == ETH_P_IP) {
+			ip[0] = (__force u32) spec->loc_host[0];
+			p += snprintf(s + p, l - p,
+				      ",lip=%d.%d.%d.%d",
+				      ip[0] & 0xff,
+				      (ip[0] >> 8) & 0xff,
+				      (ip[0] >> 16) & 0xff,
+				      (ip[0] >> 24) & 0xff);
+		} else if (ntohs(spec->ether_type) == ETH_P_IPV6) {
+			ip[0] = (__force u32) spec->loc_host[0];
+			ip[1] = (__force u32) spec->loc_host[1];
+			ip[2] = (__force u32) spec->loc_host[2];
+			ip[3] = (__force u32) spec->loc_host[3];
+			p += snprintf(s + p, l - p,
+				      ",lip=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+				      ip[0] & 0xffff,
+				      (ip[0] >> 16) & 0xffff,
+				      ip[1] & 0xffff,
+				      (ip[1] >> 16) & 0xffff,
+				      ip[2] & 0xffff,
+				      (ip[2] >> 16) & 0xffff,
+				      ip[3] & 0xffff,
+				      (ip[3] >> 16) & 0xffff);
+		} else {
+			p += snprintf(s + p, l - p, ",lip=?");
+		}
+	}
+	if (spec->match_flags & EFX_FILTER_MATCH_REM_HOST) {
+		if (ntohs(spec->ether_type) == ETH_P_IP) {
+			ip[0] = (__force u32) spec->rem_host[0];
+			p += snprintf(s + p, l - p,
+				      ",rip=%d.%d.%d.%d",
+				      ip[0] & 0xff,
+				      (ip[0] >> 8) & 0xff,
+				      (ip[0] >> 16) & 0xff,
+				      (ip[0] >> 24) & 0xff);
+		} else if (ntohs(spec->ether_type) == ETH_P_IPV6) {
+			ip[0] = (__force u32) spec->rem_host[0];
+			ip[1] = (__force u32) spec->rem_host[1];
+			ip[2] = (__force u32) spec->rem_host[2];
+			ip[3] = (__force u32) spec->rem_host[3];
+			p += snprintf(s + p, l - p,
+				      ",rip=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+				      ip[0] & 0xffff,
+				      (ip[0] >> 16) & 0xffff,
+				      ip[1] & 0xffff,
+				      (ip[1] >> 16) & 0xffff,
+				      ip[2] & 0xffff,
+				      (ip[2] >> 16) & 0xffff,
+				      ip[3] & 0xffff,
+				      (ip[3] >> 16) & 0xffff);
+		} else {
+			p += snprintf(s + p, l - p, ",rip=?");
+		}
+	}
+	if (spec->match_flags & EFX_FILTER_MATCH_LOC_PORT)
+		p += snprintf(s + p, l - p,
+			      ",lport=%d", ntohs(spec->loc_port));
+	if (spec->match_flags & EFX_FILTER_MATCH_REM_PORT)
+		p += snprintf(s + p, l - p,
+			      ",rport=%d", ntohs(spec->rem_port));
+	if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC_IG)
+		p += snprintf(s + p, l - p, ",%s",
+			      spec->loc_mac[0] ? "mc" : "uc");
+}
diff --git a/drivers/net/ethernet/sfc/debugfs.h b/drivers/net/ethernet/sfc/debugfs.h
index 7a96f3798cbd..f50b4bf33a6b 100644
--- a/drivers/net/ethernet/sfc/debugfs.h
+++ b/drivers/net/ethernet/sfc/debugfs.h
@@ -10,6 +10,10 @@ 
 
 #ifndef EFX_DEBUGFS_H
 #define EFX_DEBUGFS_H
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
 #include "net_driver.h"
 
 #ifdef CONFIG_DEBUG_FS
@@ -63,6 +67,45 @@  void efx_fini_debugfs_nic(struct efx_nic *efx);
 int efx_init_debugfs(void);
 void efx_fini_debugfs(void);
 
+void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec);
+
+/* Generate operations for a debugfs node with a custom reader function.
+ * The reader should have signature int (*)(struct seq_file *s, void *data)
+ * where data is the pointer passed to EFX_DEBUGFS_CREATE_RAW.
+ */
+#define EFX_DEBUGFS_RAW_PARAMETER(_reader)				       \
+									       \
+static int efx_debugfs_##_reader##_read(struct seq_file *s, void *d)	       \
+{									       \
+	return _reader(s, s->private);					       \
+}									       \
+									       \
+static int efx_debugfs_##_reader##_open(struct inode *inode, struct file *f)   \
+{									       \
+	return single_open(f, efx_debugfs_##_reader##_read, inode->i_private); \
+}									       \
+									       \
+static const struct file_operations efx_debugfs_##_reader##_ops = {	       \
+	.owner = THIS_MODULE,						       \
+	.open = efx_debugfs_##_reader##_open,				       \
+	.release = single_release,					       \
+	.read = seq_read,						       \
+	.llseek = seq_lseek,						       \
+};									       \
+									       \
+static void efx_debugfs_create_##_reader(const char *name, umode_t mode,       \
+					 struct dentry *parent, void *data)    \
+{									       \
+	debugfs_create_file(name, mode, parent, data,			       \
+			    &efx_debugfs_##_reader##_ops);		       \
+}
+
+/* Instantiate a debugfs node with a custom reader function.  The operations
+ * must have been generated with EFX_DEBUGFS_RAW_PARAMETER(_reader).
+ */
+#define EFX_DEBUGFS_CREATE_RAW(_name, _mode, _parent, _data, _reader)	       \
+		efx_debugfs_create_##_reader(_name, _mode, _parent, _data)
+
 #else /* CONFIG_DEBUG_FS */
 
 static inline void efx_fini_debugfs_netdev(struct net_device *net_dev) {}
@@ -99,6 +142,8 @@  static inline int efx_init_debugfs(void)
 }
 static inline void efx_fini_debugfs(void) {}
 
+void efx_debugfs_print_filter(char *s, size_t l, struct efx_filter_spec *spec) {}
+
 #endif /* CONFIG_DEBUG_FS */
 
 #endif /* EFX_DEBUGFS_H */
diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c
index a4ab45082c8f..465226c3e8c7 100644
--- a/drivers/net/ethernet/sfc/mcdi_filters.c
+++ b/drivers/net/ethernet/sfc/mcdi_filters.c
@@ -13,6 +13,7 @@ 
 #include "mcdi.h"
 #include "nic.h"
 #include "rx_common.h"
+#include "debugfs.h"
 
 /* The maximum size of a shared RSS context */
 /* TODO: this should really be from the mcdi protocol export */
@@ -1173,6 +1174,42 @@  s32 efx_mcdi_filter_get_rx_ids(struct efx_nic *efx,
 	return count;
 }
 
+static int efx_debugfs_read_filter_list(struct seq_file *file, void *data)
+{
+	struct efx_mcdi_filter_table *table;
+	struct efx_nic *efx = data;
+	int i;
+
+	down_read(&efx->filter_sem);
+	table = efx->filter_state;
+	if (!table || !table->entry) {
+		up_read(&efx->filter_sem);
+		return -ENETDOWN;
+	}
+
+	/* deliberately don't lock the table->lock, so that we can
+	 * still dump the table even if we hang mid-operation.
+	 */
+	for (i = 0; i < EFX_MCDI_FILTER_TBL_ROWS; ++i) {
+		struct efx_filter_spec *spec =
+			efx_mcdi_filter_entry_spec(table, i);
+		char filter[256];
+
+		if (spec) {
+			efx_debugfs_print_filter(filter, sizeof(filter), spec);
+
+			seq_printf(file, "%d[%#04llx],%#x = %s\n",
+				   i, table->entry[i].handle & 0xffff,
+				   efx_mcdi_filter_entry_flags(table, i),
+				   filter);
+		}
+	}
+
+	up_read(&efx->filter_sem);
+	return 0;
+}
+EFX_DEBUGFS_RAW_PARAMETER(efx_debugfs_read_filter_list);
+
 static int efx_mcdi_filter_match_flags_from_mcdi(bool encap, u32 mcdi_flags)
 {
 	int match_flags = 0;
@@ -1360,6 +1397,8 @@  int efx_mcdi_filter_table_probe(struct efx_nic *efx, bool multicast_chaining)
 			    &table->mc_overflow);
 	debugfs_create_bool("mc_chaining", 0444, table->debug_dir,
 			    &table->mc_chaining);
+	EFX_DEBUGFS_CREATE_RAW("entries", 0444, table->debug_dir, efx,
+			       efx_debugfs_read_filter_list);
 #endif
 
 	efx->filter_state = table;