1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2019 Netronome Systems, Inc. */ 3 4 #include <net/devlink.h> 5 6 #include "nfpcore/nfp.h" 7 #include "nfpcore/nfp_nsp.h" 8 #include "nfp_main.h" 9 10 /** 11 * struct nfp_devlink_param_u8_arg - Devlink u8 parameter get/set arguments 12 * @hwinfo_name: HWinfo key name 13 * @default_hi_val: Default HWinfo value if HWinfo doesn't exist 14 * @invalid_dl_val: Devlink value to use if HWinfo is unknown/invalid. 15 * -errno if there is no unknown/invalid value available 16 * @hi_to_dl: HWinfo to devlink value mapping 17 * @dl_to_hi: Devlink to hwinfo value mapping 18 * @max_dl_val: Maximum devlink value supported, for validation only 19 * @max_hi_val: Maximum HWinfo value supported, for validation only 20 */ 21 struct nfp_devlink_param_u8_arg { 22 const char *hwinfo_name; 23 const char *default_hi_val; 24 int invalid_dl_val; 25 u8 hi_to_dl[4]; 26 u8 dl_to_hi[4]; 27 u8 max_dl_val; 28 u8 max_hi_val; 29 }; 30 31 static const struct nfp_devlink_param_u8_arg nfp_devlink_u8_args[] = { 32 [DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY] = { 33 .hwinfo_name = "app_fw_from_flash", 34 .default_hi_val = NFP_NSP_APP_FW_LOAD_DEFAULT, 35 .invalid_dl_val = 36 DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN, 37 .hi_to_dl = { 38 [NFP_NSP_APP_FW_LOAD_DISK] = 39 DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK, 40 [NFP_NSP_APP_FW_LOAD_FLASH] = 41 DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH, 42 [NFP_NSP_APP_FW_LOAD_PREF] = 43 DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER, 44 }, 45 .dl_to_hi = { 46 [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER] = 47 NFP_NSP_APP_FW_LOAD_PREF, 48 [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH] = 49 NFP_NSP_APP_FW_LOAD_FLASH, 50 [DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK] = 51 NFP_NSP_APP_FW_LOAD_DISK, 52 }, 53 .max_dl_val = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK, 54 .max_hi_val = NFP_NSP_APP_FW_LOAD_PREF, 55 }, 56 [DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE] = { 57 .hwinfo_name = "abi_drv_reset", 58 .default_hi_val = NFP_NSP_DRV_RESET_DEFAULT, 59 .invalid_dl_val = 60 DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN, 61 .hi_to_dl = { 62 [NFP_NSP_DRV_RESET_ALWAYS] = 63 DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS, 64 [NFP_NSP_DRV_RESET_NEVER] = 65 DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER, 66 [NFP_NSP_DRV_RESET_DISK] = 67 DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK, 68 }, 69 .dl_to_hi = { 70 [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS] = 71 NFP_NSP_DRV_RESET_ALWAYS, 72 [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER] = 73 NFP_NSP_DRV_RESET_NEVER, 74 [DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK] = 75 NFP_NSP_DRV_RESET_DISK, 76 }, 77 .max_dl_val = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK, 78 .max_hi_val = NFP_NSP_DRV_RESET_NEVER, 79 } 80 }; 81 82 static int 83 nfp_devlink_param_u8_get(struct devlink *devlink, u32 id, 84 struct devlink_param_gset_ctx *ctx, 85 struct netlink_ext_ack *extack) 86 { 87 const struct nfp_devlink_param_u8_arg *arg; 88 struct nfp_pf *pf = devlink_priv(devlink); 89 struct nfp_nsp *nsp; 90 char hwinfo[32]; 91 long value; 92 int err; 93 94 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 95 return -EOPNOTSUPP; 96 97 arg = &nfp_devlink_u8_args[id]; 98 99 nsp = nfp_nsp_open(pf->cpp); 100 if (IS_ERR(nsp)) { 101 err = PTR_ERR(nsp); 102 nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 103 return err; 104 } 105 106 snprintf(hwinfo, sizeof(hwinfo), arg->hwinfo_name); 107 err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo), 108 arg->default_hi_val); 109 if (err) { 110 nfp_warn(pf->cpp, "HWinfo lookup failed: %d\n", err); 111 goto exit_close_nsp; 112 } 113 114 err = kstrtol(hwinfo, 0, &value); 115 if (err || value < 0 || value > arg->max_hi_val) { 116 nfp_warn(pf->cpp, "HWinfo '%s' value %li invalid\n", 117 arg->hwinfo_name, value); 118 119 if (arg->invalid_dl_val >= 0) 120 ctx->val.vu8 = arg->invalid_dl_val; 121 else 122 err = arg->invalid_dl_val; 123 124 goto exit_close_nsp; 125 } 126 127 ctx->val.vu8 = arg->hi_to_dl[value]; 128 129 exit_close_nsp: 130 nfp_nsp_close(nsp); 131 return err; 132 } 133 134 static int 135 nfp_devlink_param_u8_set(struct devlink *devlink, u32 id, 136 struct devlink_param_gset_ctx *ctx, 137 struct netlink_ext_ack *extack) 138 { 139 const struct nfp_devlink_param_u8_arg *arg; 140 struct nfp_pf *pf = devlink_priv(devlink); 141 struct nfp_nsp *nsp; 142 char hwinfo[32]; 143 int err; 144 145 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 146 return -EOPNOTSUPP; 147 148 arg = &nfp_devlink_u8_args[id]; 149 150 nsp = nfp_nsp_open(pf->cpp); 151 if (IS_ERR(nsp)) { 152 err = PTR_ERR(nsp); 153 nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 154 return err; 155 } 156 157 /* Note the value has already been validated. */ 158 snprintf(hwinfo, sizeof(hwinfo), "%s=%u", 159 arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]); 160 err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); 161 if (err) { 162 nfp_warn(pf->cpp, "HWinfo set failed: %d\n", err); 163 goto exit_close_nsp; 164 } 165 166 exit_close_nsp: 167 nfp_nsp_close(nsp); 168 return err; 169 } 170 171 static int 172 nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id, 173 union devlink_param_value val, 174 struct netlink_ext_ack *extack) 175 { 176 const struct nfp_devlink_param_u8_arg *arg; 177 178 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 179 return -EOPNOTSUPP; 180 181 arg = &nfp_devlink_u8_args[id]; 182 183 if (val.vu8 > arg->max_dl_val) { 184 NL_SET_ERR_MSG_MOD(extack, "parameter out of range"); 185 return -EINVAL; 186 } 187 188 if (val.vu8 == arg->invalid_dl_val) { 189 NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified"); 190 return -EINVAL; 191 } 192 193 return 0; 194 } 195 196 static const struct devlink_param nfp_devlink_params[] = { 197 DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, 198 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 199 nfp_devlink_param_u8_get, 200 nfp_devlink_param_u8_set, 201 nfp_devlink_param_u8_validate), 202 DEVLINK_PARAM_GENERIC(RESET_DEV_ON_DRV_PROBE, 203 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 204 nfp_devlink_param_u8_get, 205 nfp_devlink_param_u8_set, 206 nfp_devlink_param_u8_validate), 207 }; 208 209 static int nfp_devlink_supports_params(struct nfp_pf *pf) 210 { 211 struct nfp_nsp *nsp; 212 bool supported; 213 int err; 214 215 nsp = nfp_nsp_open(pf->cpp); 216 if (IS_ERR(nsp)) { 217 err = PTR_ERR(nsp); 218 dev_err(&pf->pdev->dev, "Failed to access the NSP: %d\n", err); 219 return err; 220 } 221 222 supported = nfp_nsp_has_hwinfo_lookup(nsp) && 223 nfp_nsp_has_hwinfo_set(nsp); 224 225 nfp_nsp_close(nsp); 226 return supported; 227 } 228 229 int nfp_devlink_params_register(struct nfp_pf *pf) 230 { 231 struct devlink *devlink = priv_to_devlink(pf); 232 int err; 233 234 err = nfp_devlink_supports_params(pf); 235 if (err <= 0) 236 return err; 237 238 return devl_params_register(devlink, nfp_devlink_params, 239 ARRAY_SIZE(nfp_devlink_params)); 240 } 241 242 void nfp_devlink_params_unregister(struct nfp_pf *pf) 243 { 244 int err; 245 246 err = nfp_devlink_supports_params(pf); 247 if (err <= 0) 248 return; 249 250 devl_params_unregister(priv_to_devlink(pf), nfp_devlink_params, 251 ARRAY_SIZE(nfp_devlink_params)); 252 } 253