nfp: debug dump ethtool ops
authorCarl Heymann <carl.heymann@netronome.com>
Mon, 4 Dec 2017 22:34:12 +0000 (23:34 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 5 Dec 2017 20:01:01 +0000 (15:01 -0500)
- Skeleton code to perform a binary debug dump via ethtoolops
  "set_dump", "get_dump_flags" and "get_dump_data", i.e. the ethtool
  -W/w mechanism.
- Skeleton functions for debugdump operations provided.
- An integer "dump level" can be specified, this is stored between
  ethtool invocations. Dump level 0 is still the "arm.diag" resource for
  backward compatibility. Other dump levels each define a set of state
  information to include in the dump, driven by a spec from FW.

Signed-off-by: Carl Heymann <carl.heymann@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/Makefile
drivers/net/ethernet/netronome/nfp/nfp_main.c
drivers/net/ethernet/netronome/nfp/nfp_main.h
drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c [new file with mode: 0644]
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c

index 24c4408..6e5ef98 100644 (file)
@@ -22,6 +22,7 @@ nfp-objs := \
            nfp_hwmon.o \
            nfp_main.o \
            nfp_net_common.o \
+           nfp_net_debugdump.o \
            nfp_net_ethtool.o \
            nfp_net_main.o \
            nfp_net_repr.o \
index 35eaccb..0953fa8 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/vermagic.h>
+#include <linux/vmalloc.h>
 #include <net/devlink.h>
 
 #include "nfpcore/nfp.h"
@@ -509,6 +510,9 @@ static int nfp_pci_probe(struct pci_dev *pdev,
        pf->mip = nfp_mip_open(pf->cpp);
        pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip);
 
+       pf->dump_flag = NFP_DUMP_NSP_DIAG;
+       pf->dumpspec = nfp_net_dump_load_dumpspec(pf->cpp, pf->rtbl);
+
        err = nfp_pcie_sriov_read_nfd_limit(pf);
        if (err)
                goto err_fw_unload;
@@ -544,6 +548,7 @@ err_fw_unload:
                nfp_fw_unload(pf);
        kfree(pf->eth_tbl);
        kfree(pf->nspi);
+       vfree(pf->dumpspec);
 err_devlink_unreg:
        devlink_unregister(devlink);
 err_hwinfo_free:
@@ -579,6 +584,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
 
        devlink_unregister(devlink);
 
+       vfree(pf->dumpspec);
        kfree(pf->rtbl);
        nfp_mip_close(pf->mip);
        if (pf->fw_loaded)
index be0ee59..add46e2 100644 (file)
@@ -39,6 +39,7 @@
 #ifndef NFP_MAIN_H
 #define NFP_MAIN_H
 
+#include <linux/ethtool.h>
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/msi.h>
@@ -61,6 +62,17 @@ struct nfp_nsp_identify;
 struct nfp_port;
 struct nfp_rtsym_table;
 
+/**
+ * struct nfp_dumpspec - NFP FW dump specification structure
+ * @size:      Size of the data
+ * @data:      Sequence of TLVs, each being an instruction to dump some data
+ *             from FW
+ */
+struct nfp_dumpspec {
+       u32 size;
+       u8 data[0];
+};
+
 /**
  * struct nfp_pf - NFP PF-specific device structure
  * @pdev:              Backpointer to PCI device
@@ -83,6 +95,9 @@ struct nfp_rtsym_table;
  * @mip:               MIP handle
  * @rtbl:              RTsym table
  * @hwinfo:            HWInfo table
+ * @dumpspec:          Debug dump specification
+ * @dump_flag:         Store dump flag between set_dump and get_dump_flag
+ * @dump_len:          Store dump length between set_dump and get_dump_flag
  * @eth_tbl:           NSP ETH table
  * @nspi:              NSP identification info
  * @hwmon_dev:         pointer to hwmon device
@@ -124,6 +139,9 @@ struct nfp_pf {
        const struct nfp_mip *mip;
        struct nfp_rtsym_table *rtbl;
        struct nfp_hwinfo *hwinfo;
+       struct nfp_dumpspec *dumpspec;
+       u32 dump_flag;
+       u32 dump_len;
        struct nfp_eth_table *eth_tbl;
        struct nfp_nsp_identify *nspi;
 
@@ -157,4 +175,15 @@ void nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port);
 
 bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
 
+enum nfp_dump_diag {
+       NFP_DUMP_NSP_DIAG = 0,
+};
+
+struct nfp_dumpspec *
+nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl);
+s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
+                               u32 flag);
+int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
+                                struct ethtool_dump *dump_param, void *dest);
+
 #endif /* NFP_MAIN_H */
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c
new file mode 100644 (file)
index 0000000..a7061b6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 Netronome Systems, Inc.
+ *
+ * This software is dual licensed under the GNU General License Version 2,
+ * June 1991 as shown in the file COPYING in the top-level directory of this
+ * source tree or the BSD 2-Clause License provided below.  You have the
+ * option to license this software under the complete terms of either license.
+ *
+ * The BSD 2-Clause License:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      1. Redistributions of source code must retain the above
+ *         copyright notice, this list of conditions and the following
+ *         disclaimer.
+ *
+ *      2. 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.
+ */
+
+#include <linux/ethtool.h>
+
+#include "nfp_main.h"
+
+struct nfp_dumpspec *
+nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
+{
+       return NULL;
+}
+
+s64 nfp_net_dump_calculate_size(struct nfp_pf *pf, struct nfp_dumpspec *spec,
+                               u32 flag)
+{
+       return -EOPNOTSUPP;
+}
+
+int nfp_net_dump_populate_buffer(struct nfp_pf *pf, struct nfp_dumpspec *spec,
+                                struct ethtool_dump *dump_param, void *dest)
+{
+       return -EOPNOTSUPP;
+}
index 2801ecd..2cde0eb 100644 (file)
 #include "nfpcore/nfp.h"
 #include "nfpcore/nfp_nsp.h"
 #include "nfp_app.h"
+#include "nfp_main.h"
 #include "nfp_net_ctrl.h"
 #include "nfp_net.h"
 #include "nfp_port.h"
 
-enum nfp_dump_diag {
-       NFP_DUMP_NSP_DIAG = 0,
-};
-
 struct nfp_et_stat {
        char name[ETH_GSTRING_LEN];
        int off;
@@ -1066,15 +1063,34 @@ exit_release:
        return ret;
 }
 
+/* Set the dump flag/level. Calculate the dump length for flag > 0 only (new TLV
+ * based dumps), since flag 0 (default) calculates the length in
+ * nfp_app_get_dump_flag(), and we need to support triggering a level 0 dump
+ * without setting the flag first, for backward compatibility.
+ */
 static int nfp_app_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 {
        struct nfp_app *app = nfp_app_from_netdev(netdev);
+       s64 len;
 
        if (!app)
                return -EOPNOTSUPP;
 
-       if (val->flag != NFP_DUMP_NSP_DIAG)
-               return -EINVAL;
+       if (val->flag == NFP_DUMP_NSP_DIAG) {
+               app->pf->dump_flag = val->flag;
+               return 0;
+       }
+
+       if (!app->pf->dumpspec)
+               return -EOPNOTSUPP;
+
+       len = nfp_net_dump_calculate_size(app->pf, app->pf->dumpspec,
+                                         val->flag);
+       if (len < 0)
+               return len;
+
+       app->pf->dump_flag = val->flag;
+       app->pf->dump_len = len;
 
        return 0;
 }
@@ -1082,14 +1098,37 @@ static int nfp_app_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 static int
 nfp_app_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
 {
-       return nfp_dump_nsp_diag(nfp_app_from_netdev(netdev), dump, NULL);
+       struct nfp_app *app = nfp_app_from_netdev(netdev);
+
+       if (!app)
+               return -EOPNOTSUPP;
+
+       if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
+               return nfp_dump_nsp_diag(app, dump, NULL);
+
+       dump->flag = app->pf->dump_flag;
+       dump->len = app->pf->dump_len;
+
+       return 0;
 }
 
 static int
 nfp_app_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
                      void *buffer)
 {
-       return nfp_dump_nsp_diag(nfp_app_from_netdev(netdev), dump, buffer);
+       struct nfp_app *app = nfp_app_from_netdev(netdev);
+
+       if (!app)
+               return -EOPNOTSUPP;
+
+       if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
+               return nfp_dump_nsp_diag(app, dump, buffer);
+
+       dump->flag = app->pf->dump_flag;
+       dump->len = app->pf->dump_len;
+
+       return nfp_net_dump_populate_buffer(app->pf, app->pf->dumpspec, dump,
+                                           buffer);
 }
 
 static int nfp_net_set_coalesce(struct net_device *netdev,