nfp: devlink: add 'fw_load_policy' support
authorDirk van der Merwe <dirk.vandermerwe@netronome.com>
Sun, 8 Sep 2019 23:54:24 +0000 (00:54 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 10 Sep 2019 16:29:27 +0000 (17:29 +0100)
Add support for the 'fw_load_policy' devlink parameter. The FW load
policy is controlled by the 'app_fw_from_flash' hwinfo key.

Remap the values from devlink to the hwinfo key and back.

Signed-off-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-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>
Documentation/networking/devlink-params-nfp.txt [new file with mode: 0644]
drivers/net/ethernet/netronome/nfp/devlink_param.c

diff --git a/Documentation/networking/devlink-params-nfp.txt b/Documentation/networking/devlink-params-nfp.txt
new file mode 100644 (file)
index 0000000..85b1e36
--- /dev/null
@@ -0,0 +1,2 @@
+fw_load_policy         [DEVICE, GENERIC]
+                       Configuration mode: permanent
index aece985..d9c74cf 100644 (file)
 
 #include <net/devlink.h>
 
+#include "nfpcore/nfp.h"
 #include "nfpcore/nfp_nsp.h"
 #include "nfp_main.h"
 
+/**
+ * struct nfp_devlink_param_u8_arg - Devlink u8 parameter get/set arguments
+ * @hwinfo_name:       HWinfo key name
+ * @default_hi_val:    Default HWinfo value if HWinfo doesn't exist
+ * @invalid_dl_val:    Devlink value to use if HWinfo is unknown/invalid.
+ *                     -errno if there is no unknown/invalid value available
+ * @hi_to_dl:  HWinfo to devlink value mapping
+ * @dl_to_hi:  Devlink to hwinfo value mapping
+ * @max_dl_val:        Maximum devlink value supported, for validation only
+ * @max_hi_val:        Maximum HWinfo value supported, for validation only
+ */
+struct nfp_devlink_param_u8_arg {
+       const char *hwinfo_name;
+       const char *default_hi_val;
+       int invalid_dl_val;
+       u8 hi_to_dl[4];
+       u8 dl_to_hi[4];
+       u8 max_dl_val;
+       u8 max_hi_val;
+};
+
+static const struct nfp_devlink_param_u8_arg nfp_devlink_u8_args[] = {
+       [DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY] = {
+               .hwinfo_name = "app_fw_from_flash",
+               .default_hi_val = NFP_NSP_APP_FW_LOAD_DEFAULT,
+               .invalid_dl_val = -EINVAL,
+               .hi_to_dl = {
+                       [NFP_NSP_APP_FW_LOAD_DISK] =
+                               DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
+                       [NFP_NSP_APP_FW_LOAD_FLASH] =
+                               DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
+                       [NFP_NSP_APP_FW_LOAD_PREF] =
+                               DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
+               },
+               .dl_to_hi = {
+                       [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER] =
+                               NFP_NSP_APP_FW_LOAD_PREF,
+                       [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH] =
+                               NFP_NSP_APP_FW_LOAD_FLASH,
+                       [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK] =
+                               NFP_NSP_APP_FW_LOAD_DISK,
+               },
+               .max_dl_val = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
+               .max_hi_val = NFP_NSP_APP_FW_LOAD_PREF,
+       },
+};
+
+static int
+nfp_devlink_param_u8_get(struct devlink *devlink, u32 id,
+                        struct devlink_param_gset_ctx *ctx)
+{
+       const struct nfp_devlink_param_u8_arg *arg;
+       struct nfp_pf *pf = devlink_priv(devlink);
+       struct nfp_nsp *nsp;
+       char hwinfo[32];
+       long value;
+       int err;
+
+       if (id >= ARRAY_SIZE(nfp_devlink_u8_args))
+               return -EOPNOTSUPP;
+
+       arg = &nfp_devlink_u8_args[id];
+
+       nsp = nfp_nsp_open(pf->cpp);
+       if (IS_ERR(nsp)) {
+               err = PTR_ERR(nsp);
+               nfp_warn(pf->cpp, "can't access NSP: %d\n", err);
+               return err;
+       }
+
+       snprintf(hwinfo, sizeof(hwinfo), arg->hwinfo_name);
+       err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo),
+                                            arg->default_hi_val);
+       if (err) {
+               nfp_warn(pf->cpp, "HWinfo lookup failed: %d\n", err);
+               goto exit_close_nsp;
+       }
+
+       err = kstrtol(hwinfo, 0, &value);
+       if (err || value < 0 || value > arg->max_hi_val) {
+               nfp_warn(pf->cpp, "HWinfo '%s' value %li invalid\n",
+                        arg->hwinfo_name, value);
+
+               if (arg->invalid_dl_val >= 0)
+                       ctx->val.vu8 = arg->invalid_dl_val;
+               else
+                       err = arg->invalid_dl_val;
+
+               goto exit_close_nsp;
+       }
+
+       ctx->val.vu8 = arg->hi_to_dl[value];
+
+exit_close_nsp:
+       nfp_nsp_close(nsp);
+       return err;
+}
+
+static int
+nfp_devlink_param_u8_set(struct devlink *devlink, u32 id,
+                        struct devlink_param_gset_ctx *ctx)
+{
+       const struct nfp_devlink_param_u8_arg *arg;
+       struct nfp_pf *pf = devlink_priv(devlink);
+       struct nfp_nsp *nsp;
+       char hwinfo[32];
+       int err;
+
+       if (id >= ARRAY_SIZE(nfp_devlink_u8_args))
+               return -EOPNOTSUPP;
+
+       arg = &nfp_devlink_u8_args[id];
+
+       nsp = nfp_nsp_open(pf->cpp);
+       if (IS_ERR(nsp)) {
+               err = PTR_ERR(nsp);
+               nfp_warn(pf->cpp, "can't access NSP: %d\n", err);
+               return err;
+       }
+
+       /* Note the value has already been validated. */
+       snprintf(hwinfo, sizeof(hwinfo), "%s=%u",
+                arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]);
+       err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
+       if (err) {
+               nfp_warn(pf->cpp, "HWinfo set failed: %d\n", err);
+               goto exit_close_nsp;
+       }
+
+exit_close_nsp:
+       nfp_nsp_close(nsp);
+       return err;
+}
+
+static int
+nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id,
+                             union devlink_param_value val,
+                             struct netlink_ext_ack *extack)
+{
+       const struct nfp_devlink_param_u8_arg *arg;
+
+       if (id >= ARRAY_SIZE(nfp_devlink_u8_args))
+               return -EOPNOTSUPP;
+
+       arg = &nfp_devlink_u8_args[id];
+
+       if (val.vu8 > arg->max_dl_val) {
+               NL_SET_ERR_MSG_MOD(extack, "parameter out of range");
+               return -EINVAL;
+       }
+
+       if (val.vu8 == arg->invalid_dl_val) {
+               NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct devlink_param nfp_devlink_params[] = {
+       DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY,
+                             BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+                             nfp_devlink_param_u8_get,
+                             nfp_devlink_param_u8_set,
+                             nfp_devlink_param_u8_validate),
 };
 
 static int nfp_devlink_supports_params(struct nfp_pf *pf)