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 { 86 const struct nfp_devlink_param_u8_arg *arg; 87 struct nfp_pf *pf = devlink_priv(devlink); 88 struct nfp_nsp *nsp; 89 char hwinfo[32]; 90 long value; 91 int err; 92 93 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 94 return -EOPNOTSUPP; 95 96 arg = &nfp_devlink_u8_args[id]; 97 98 nsp = nfp_nsp_open(pf->cpp); 99 if (IS_ERR(nsp)) { 100 err = PTR_ERR(nsp); 101 nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 102 return err; 103 } 104 105 snprintf(hwinfo, sizeof(hwinfo), arg->hwinfo_name); 106 err = nfp_nsp_hwinfo_lookup_optional(nsp, hwinfo, sizeof(hwinfo), 107 arg->default_hi_val); 108 if (err) { 109 nfp_warn(pf->cpp, "HWinfo lookup failed: %d\n", err); 110 goto exit_close_nsp; 111 } 112 113 err = kstrtol(hwinfo, 0, &value); 114 if (err || value < 0 || value > arg->max_hi_val) { 115 nfp_warn(pf->cpp, "HWinfo '%s' value %li invalid\n", 116 arg->hwinfo_name, value); 117 118 if (arg->invalid_dl_val >= 0) 119 ctx->val.vu8 = arg->invalid_dl_val; 120 else 121 err = arg->invalid_dl_val; 122 123 goto exit_close_nsp; 124 } 125 126 ctx->val.vu8 = arg->hi_to_dl[value]; 127 128 exit_close_nsp: 129 nfp_nsp_close(nsp); 130 return err; 131 } 132 133 static int 134 nfp_devlink_param_u8_set(struct devlink *devlink, u32 id, 135 struct devlink_param_gset_ctx *ctx) 136 { 137 const struct nfp_devlink_param_u8_arg *arg; 138 struct nfp_pf *pf = devlink_priv(devlink); 139 struct nfp_nsp *nsp; 140 char hwinfo[32]; 141 int err; 142 143 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 144 return -EOPNOTSUPP; 145 146 arg = &nfp_devlink_u8_args[id]; 147 148 nsp = nfp_nsp_open(pf->cpp); 149 if (IS_ERR(nsp)) { 150 err = PTR_ERR(nsp); 151 nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 152 return err; 153 } 154 155 /* Note the value has already been validated. */ 156 snprintf(hwinfo, sizeof(hwinfo), "%s=%u", 157 arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]); 158 err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); 159 if (err) { 160 nfp_warn(pf->cpp, "HWinfo set failed: %d\n", err); 161 goto exit_close_nsp; 162 } 163 164 exit_close_nsp: 165 nfp_nsp_close(nsp); 166 return err; 167 } 168 169 static int 170 nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id, 171 union devlink_param_value val, 172 struct netlink_ext_ack *extack) 173 { 174 const struct nfp_devlink_param_u8_arg *arg; 175 176 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 177 return -EOPNOTSUPP; 178 179 arg = &nfp_devlink_u8_args[id]; 180 181 if (val.vu8 > arg->max_dl_val) { 182 NL_SET_ERR_MSG_MOD(extack, "parameter out of range"); 183 return -EINVAL; 184 } 185 186 if (val.vu8 == arg->invalid_dl_val) { 187 NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified"); 188 return -EINVAL; 189 } 190 191 return 0; 192 } 193 194 static const struct devlink_param nfp_devlink_params[] = { 195 DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, 196 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 197 nfp_devlink_param_u8_get, 198 nfp_devlink_param_u8_set, 199 nfp_devlink_param_u8_validate), 200 DEVLINK_PARAM_GENERIC(RESET_DEV_ON_DRV_PROBE, 201 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 202 nfp_devlink_param_u8_get, 203 nfp_devlink_param_u8_set, 204 nfp_devlink_param_u8_validate), 205 }; 206 207 static int nfp_devlink_supports_params(struct nfp_pf *pf) 208 { 209 struct nfp_nsp *nsp; 210 bool supported; 211 int err; 212 213 nsp = nfp_nsp_open(pf->cpp); 214 if (IS_ERR(nsp)) { 215 err = PTR_ERR(nsp); 216 dev_err(&pf->pdev->dev, "Failed to access the NSP: %d\n", err); 217 return err; 218 } 219 220 supported = nfp_nsp_has_hwinfo_lookup(nsp) && 221 nfp_nsp_has_hwinfo_set(nsp); 222 223 nfp_nsp_close(nsp); 224 return supported; 225 } 226 227 int nfp_devlink_params_register(struct nfp_pf *pf) 228 { 229 struct devlink *devlink = priv_to_devlink(pf); 230 int err; 231 232 err = nfp_devlink_supports_params(pf); 233 if (err <= 0) 234 return err; 235 236 err = devlink_params_register(devlink, nfp_devlink_params, 237 ARRAY_SIZE(nfp_devlink_params)); 238 if (err) 239 return err; 240 241 devlink_params_publish(devlink); 242 return 0; 243 } 244 245 void nfp_devlink_params_unregister(struct nfp_pf *pf) 246 { 247 int err; 248 249 err = nfp_devlink_supports_params(pf); 250 if (err <= 0) 251 return; 252 253 devlink_params_unregister(priv_to_devlink(pf), nfp_devlink_params, 254 ARRAY_SIZE(nfp_devlink_params)); 255 } 256