162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2019 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <net/devlink.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "nfpcore/nfp.h" 762306a36Sopenharmony_ci#include "nfpcore/nfp_nsp.h" 862306a36Sopenharmony_ci#include "nfp_main.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/** 1162306a36Sopenharmony_ci * struct nfp_devlink_param_u8_arg - Devlink u8 parameter get/set arguments 1262306a36Sopenharmony_ci * @hwinfo_name: HWinfo key name 1362306a36Sopenharmony_ci * @default_hi_val: Default HWinfo value if HWinfo doesn't exist 1462306a36Sopenharmony_ci * @invalid_dl_val: Devlink value to use if HWinfo is unknown/invalid. 1562306a36Sopenharmony_ci * -errno if there is no unknown/invalid value available 1662306a36Sopenharmony_ci * @hi_to_dl: HWinfo to devlink value mapping 1762306a36Sopenharmony_ci * @dl_to_hi: Devlink to hwinfo value mapping 1862306a36Sopenharmony_ci * @max_dl_val: Maximum devlink value supported, for validation only 1962306a36Sopenharmony_ci * @max_hi_val: Maximum HWinfo value supported, for validation only 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_cistruct nfp_devlink_param_u8_arg { 2262306a36Sopenharmony_ci const char *hwinfo_name; 2362306a36Sopenharmony_ci const char *default_hi_val; 2462306a36Sopenharmony_ci int invalid_dl_val; 2562306a36Sopenharmony_ci u8 hi_to_dl[4]; 2662306a36Sopenharmony_ci u8 dl_to_hi[4]; 2762306a36Sopenharmony_ci u8 max_dl_val; 2862306a36Sopenharmony_ci u8 max_hi_val; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct nfp_devlink_param_u8_arg nfp_devlink_u8_args[] = { 3262306a36Sopenharmony_ci [DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY] = { 3362306a36Sopenharmony_ci .hwinfo_name = "app_fw_from_flash", 3462306a36Sopenharmony_ci .default_hi_val = NFP_NSP_APP_FW_LOAD_DEFAULT, 3562306a36Sopenharmony_ci .invalid_dl_val = 3662306a36Sopenharmony_ci DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN, 3762306a36Sopenharmony_ci .hi_to_dl = { 3862306a36Sopenharmony_ci [NFP_NSP_APP_FW_LOAD_DISK] = 3962306a36Sopenharmony_ci DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK, 4062306a36Sopenharmony_ci [NFP_NSP_APP_FW_LOAD_FLASH] = 4162306a36Sopenharmony_ci DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH, 4262306a36Sopenharmony_ci [NFP_NSP_APP_FW_LOAD_PREF] = 4362306a36Sopenharmony_ci DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER, 4462306a36Sopenharmony_ci }, 4562306a36Sopenharmony_ci .dl_to_hi = { 4662306a36Sopenharmony_ci [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER] = 4762306a36Sopenharmony_ci NFP_NSP_APP_FW_LOAD_PREF, 4862306a36Sopenharmony_ci [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH] = 4962306a36Sopenharmony_ci NFP_NSP_APP_FW_LOAD_FLASH, 5062306a36Sopenharmony_ci [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK] = 5162306a36Sopenharmony_ci NFP_NSP_APP_FW_LOAD_DISK, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci .max_dl_val = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK, 5462306a36Sopenharmony_ci .max_hi_val = NFP_NSP_APP_FW_LOAD_PREF, 5562306a36Sopenharmony_ci }, 5662306a36Sopenharmony_ci [DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE] = { 5762306a36Sopenharmony_ci .hwinfo_name = "abi_drv_reset", 5862306a36Sopenharmony_ci .default_hi_val = NFP_NSP_DRV_RESET_DEFAULT, 5962306a36Sopenharmony_ci .invalid_dl_val = 6062306a36Sopenharmony_ci DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN, 6162306a36Sopenharmony_ci .hi_to_dl = { 6262306a36Sopenharmony_ci [NFP_NSP_DRV_RESET_ALWAYS] = 6362306a36Sopenharmony_ci DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS, 6462306a36Sopenharmony_ci [NFP_NSP_DRV_RESET_NEVER] = 6562306a36Sopenharmony_ci DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER, 6662306a36Sopenharmony_ci [NFP_NSP_DRV_RESET_DISK] = 6762306a36Sopenharmony_ci DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK, 6862306a36Sopenharmony_ci }, 6962306a36Sopenharmony_ci .dl_to_hi = { 7062306a36Sopenharmony_ci [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS] = 7162306a36Sopenharmony_ci NFP_NSP_DRV_RESET_ALWAYS, 7262306a36Sopenharmony_ci [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER] = 7362306a36Sopenharmony_ci NFP_NSP_DRV_RESET_NEVER, 7462306a36Sopenharmony_ci [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK] = 7562306a36Sopenharmony_ci NFP_NSP_DRV_RESET_DISK, 7662306a36Sopenharmony_ci }, 7762306a36Sopenharmony_ci .max_dl_val = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK, 7862306a36Sopenharmony_ci .max_hi_val = NFP_NSP_DRV_RESET_NEVER, 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int 8362306a36Sopenharmony_cinfp_devlink_param_u8_get(struct devlink *devlink, u32 id, 8462306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci const struct nfp_devlink_param_u8_arg *arg; 8762306a36Sopenharmony_ci struct nfp_pf *pf = devlink_priv(devlink); 8862306a36Sopenharmony_ci struct nfp_nsp *nsp; 8962306a36Sopenharmony_ci char hwinfo[32]; 9062306a36Sopenharmony_ci long value; 9162306a36Sopenharmony_ci int err; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 9462306a36Sopenharmony_ci return -EOPNOTSUPP; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci arg = &nfp_devlink_u8_args[id]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci nsp = nfp_nsp_open(pf->cpp); 9962306a36Sopenharmony_ci if (IS_ERR(nsp)) { 10062306a36Sopenharmony_ci err = PTR_ERR(nsp); 10162306a36Sopenharmony_ci nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 10262306a36Sopenharmony_ci return err; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci snprintf(hwinfo, sizeof(hwinfo), arg->hwinfo_name); 10662306a36Sopenharmony_ci err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo), 10762306a36Sopenharmony_ci arg->default_hi_val); 10862306a36Sopenharmony_ci if (err) { 10962306a36Sopenharmony_ci nfp_warn(pf->cpp, "HWinfo lookup failed: %d\n", err); 11062306a36Sopenharmony_ci goto exit_close_nsp; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci err = kstrtol(hwinfo, 0, &value); 11462306a36Sopenharmony_ci if (err || value < 0 || value > arg->max_hi_val) { 11562306a36Sopenharmony_ci nfp_warn(pf->cpp, "HWinfo '%s' value %li invalid\n", 11662306a36Sopenharmony_ci arg->hwinfo_name, value); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (arg->invalid_dl_val >= 0) 11962306a36Sopenharmony_ci ctx->val.vu8 = arg->invalid_dl_val; 12062306a36Sopenharmony_ci else 12162306a36Sopenharmony_ci err = arg->invalid_dl_val; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci goto exit_close_nsp; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci ctx->val.vu8 = arg->hi_to_dl[value]; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciexit_close_nsp: 12962306a36Sopenharmony_ci nfp_nsp_close(nsp); 13062306a36Sopenharmony_ci return err; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int 13462306a36Sopenharmony_cinfp_devlink_param_u8_set(struct devlink *devlink, u32 id, 13562306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci const struct nfp_devlink_param_u8_arg *arg; 13862306a36Sopenharmony_ci struct nfp_pf *pf = devlink_priv(devlink); 13962306a36Sopenharmony_ci struct nfp_nsp *nsp; 14062306a36Sopenharmony_ci char hwinfo[32]; 14162306a36Sopenharmony_ci int err; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 14462306a36Sopenharmony_ci return -EOPNOTSUPP; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci arg = &nfp_devlink_u8_args[id]; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci nsp = nfp_nsp_open(pf->cpp); 14962306a36Sopenharmony_ci if (IS_ERR(nsp)) { 15062306a36Sopenharmony_ci err = PTR_ERR(nsp); 15162306a36Sopenharmony_ci nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 15262306a36Sopenharmony_ci return err; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Note the value has already been validated. */ 15662306a36Sopenharmony_ci snprintf(hwinfo, sizeof(hwinfo), "%s=%u", 15762306a36Sopenharmony_ci arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]); 15862306a36Sopenharmony_ci err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); 15962306a36Sopenharmony_ci if (err) { 16062306a36Sopenharmony_ci nfp_warn(pf->cpp, "HWinfo set failed: %d\n", err); 16162306a36Sopenharmony_ci goto exit_close_nsp; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciexit_close_nsp: 16562306a36Sopenharmony_ci nfp_nsp_close(nsp); 16662306a36Sopenharmony_ci return err; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int 17062306a36Sopenharmony_cinfp_devlink_param_u8_validate(struct devlink *devlink, u32 id, 17162306a36Sopenharmony_ci union devlink_param_value val, 17262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci const struct nfp_devlink_param_u8_arg *arg; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 17762306a36Sopenharmony_ci return -EOPNOTSUPP; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci arg = &nfp_devlink_u8_args[id]; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (val.vu8 > arg->max_dl_val) { 18262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "parameter out of range"); 18362306a36Sopenharmony_ci return -EINVAL; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (val.vu8 == arg->invalid_dl_val) { 18762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified"); 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic const struct devlink_param nfp_devlink_params[] = { 19562306a36Sopenharmony_ci DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, 19662306a36Sopenharmony_ci BIT(DEVLINK_PARAM_CMODE_PERMANENT), 19762306a36Sopenharmony_ci nfp_devlink_param_u8_get, 19862306a36Sopenharmony_ci nfp_devlink_param_u8_set, 19962306a36Sopenharmony_ci nfp_devlink_param_u8_validate), 20062306a36Sopenharmony_ci DEVLINK_PARAM_GENERIC(RESET_DEV_ON_DRV_PROBE, 20162306a36Sopenharmony_ci BIT(DEVLINK_PARAM_CMODE_PERMANENT), 20262306a36Sopenharmony_ci nfp_devlink_param_u8_get, 20362306a36Sopenharmony_ci nfp_devlink_param_u8_set, 20462306a36Sopenharmony_ci nfp_devlink_param_u8_validate), 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int nfp_devlink_supports_params(struct nfp_pf *pf) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct nfp_nsp *nsp; 21062306a36Sopenharmony_ci bool supported; 21162306a36Sopenharmony_ci int err; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci nsp = nfp_nsp_open(pf->cpp); 21462306a36Sopenharmony_ci if (IS_ERR(nsp)) { 21562306a36Sopenharmony_ci err = PTR_ERR(nsp); 21662306a36Sopenharmony_ci dev_err(&pf->pdev->dev, "Failed to access the NSP: %d\n", err); 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci supported = nfp_nsp_has_hwinfo_lookup(nsp) && 22162306a36Sopenharmony_ci nfp_nsp_has_hwinfo_set(nsp); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci nfp_nsp_close(nsp); 22462306a36Sopenharmony_ci return supported; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint nfp_devlink_params_register(struct nfp_pf *pf) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(pf); 23062306a36Sopenharmony_ci int err; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci err = nfp_devlink_supports_params(pf); 23362306a36Sopenharmony_ci if (err <= 0) 23462306a36Sopenharmony_ci return err; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return devl_params_register(devlink, nfp_devlink_params, 23762306a36Sopenharmony_ci ARRAY_SIZE(nfp_devlink_params)); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_civoid nfp_devlink_params_unregister(struct nfp_pf *pf) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci int err; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci err = nfp_devlink_supports_params(pf); 24562306a36Sopenharmony_ci if (err <= 0) 24662306a36Sopenharmony_ci return; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci devl_params_unregister(priv_to_devlink(pf), nfp_devlink_params, 24962306a36Sopenharmony_ci ARRAY_SIZE(nfp_devlink_params)); 25062306a36Sopenharmony_ci} 251