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 struct netlink_ext_ack *extack) 137 { 138 const struct nfp_devlink_param_u8_arg *arg; 139 struct nfp_pf *pf = devlink_priv(devlink); 140 struct nfp_nsp *nsp; 141 char hwinfo[32]; 142 int err; 143 144 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 145 return -EOPNOTSUPP; 146 147 arg = &nfp_devlink_u8_args[id]; 148 149 nsp = nfp_nsp_open(pf->cpp); 150 if (IS_ERR(nsp)) { 151 err = PTR_ERR(nsp); 152 nfp_warn(pf->cpp, "can't access NSP: %d\n", err); 153 return err; 154 } 155 156 /* Note the value has already been validated. */ 157 snprintf(hwinfo, sizeof(hwinfo), "%s=%u", 158 arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]); 159 err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo)); 160 if (err) { 161 nfp_warn(pf->cpp, "HWinfo set failed: %d\n", err); 162 goto exit_close_nsp; 163 } 164 165 exit_close_nsp: 166 nfp_nsp_close(nsp); 167 return err; 168 } 169 170 static int 171 nfp_devlink_param_u8_validate(struct devlink *devlink, u32 id, 172 union devlink_param_value val, 173 struct netlink_ext_ack *extack) 174 { 175 const struct nfp_devlink_param_u8_arg *arg; 176 177 if (id >= ARRAY_SIZE(nfp_devlink_u8_args)) 178 return -EOPNOTSUPP; 179 180 arg = &nfp_devlink_u8_args[id]; 181 182 if (val.vu8 > arg->max_dl_val) { 183 NL_SET_ERR_MSG_MOD(extack, "parameter out of range"); 184 return -EINVAL; 185 } 186 187 if (val.vu8 == arg->invalid_dl_val) { 188 NL_SET_ERR_MSG_MOD(extack, "unknown/invalid value specified"); 189 return -EINVAL; 190 } 191 192 return 0; 193 } 194 195 static const struct devlink_param nfp_devlink_params[] = { 196 DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, 197 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 198 nfp_devlink_param_u8_get, 199 nfp_devlink_param_u8_set, 200 nfp_devlink_param_u8_validate), 201 DEVLINK_PARAM_GENERIC(RESET_DEV_ON_DRV_PROBE, 202 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 203 nfp_devlink_param_u8_get, 204 nfp_devlink_param_u8_set, 205 nfp_devlink_param_u8_validate), 206 }; 207 208 static int nfp_devlink_supports_params(struct nfp_pf *pf) 209 { 210 struct nfp_nsp *nsp; 211 bool supported; 212 int err; 213 214 nsp = nfp_nsp_open(pf->cpp); 215 if (IS_ERR(nsp)) { 216 err = PTR_ERR(nsp); 217 dev_err(&pf->pdev->dev, "Failed to access the NSP: %d\n", err); 218 return err; 219 } 220 221 supported = nfp_nsp_has_hwinfo_lookup(nsp) && 222 nfp_nsp_has_hwinfo_set(nsp); 223 224 nfp_nsp_close(nsp); 225 return supported; 226 } 227 228 int nfp_devlink_params_register(struct nfp_pf *pf) 229 { 230 struct devlink *devlink = priv_to_devlink(pf); 231 int err; 232 233 err = nfp_devlink_supports_params(pf); 234 if (err <= 0) 235 return err; 236 237 return devl_params_register(devlink, nfp_devlink_params, 238 ARRAY_SIZE(nfp_devlink_params)); 239 } 240 241 void nfp_devlink_params_unregister(struct nfp_pf *pf) 242 { 243 int err; 244 245 err = nfp_devlink_supports_params(pf); 246 if (err <= 0) 247 return; 248 249 devl_params_unregister(priv_to_devlink(pf), nfp_devlink_params, 250 ARRAY_SIZE(nfp_devlink_params)); 251 } 252