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(cpp: pf->cpp); |
99 | if (IS_ERR(ptr: nsp)) { |
100 | err = PTR_ERR(ptr: nsp); |
101 | nfp_warn(pf->cpp, "can't access NSP: %d\n" , err); |
102 | return err; |
103 | } |
104 | |
105 | snprintf(buf: hwinfo, size: sizeof(hwinfo), fmt: arg->hwinfo_name); |
106 | err = nfp_nsp_hwinfo_lookup_optional(state: nsp, buf: hwinfo, size: sizeof(hwinfo), |
107 | default_val: 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(s: hwinfo, base: 0, res: &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(state: 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(cpp: pf->cpp); |
149 | if (IS_ERR(ptr: nsp)) { |
150 | err = PTR_ERR(ptr: 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(buf: hwinfo, size: sizeof(hwinfo), fmt: "%s=%u" , |
157 | arg->hwinfo_name, arg->dl_to_hi[ctx->val.vu8]); |
158 | err = nfp_nsp_hwinfo_set(state: nsp, buf: hwinfo, size: 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(state: 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(cpp: pf->cpp); |
214 | if (IS_ERR(ptr: nsp)) { |
215 | err = PTR_ERR(ptr: 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(state: nsp) && |
221 | nfp_nsp_has_hwinfo_set(state: nsp); |
222 | |
223 | nfp_nsp_close(state: nsp); |
224 | return supported; |
225 | } |
226 | |
227 | int nfp_devlink_params_register(struct nfp_pf *pf) |
228 | { |
229 | struct devlink *devlink = priv_to_devlink(priv: pf); |
230 | int err; |
231 | |
232 | err = nfp_devlink_supports_params(pf); |
233 | if (err <= 0) |
234 | return err; |
235 | |
236 | return devl_params_register(devlink, params: nfp_devlink_params, |
237 | ARRAY_SIZE(nfp_devlink_params)); |
238 | } |
239 | |
240 | void nfp_devlink_params_unregister(struct nfp_pf *pf) |
241 | { |
242 | int err; |
243 | |
244 | err = nfp_devlink_supports_params(pf); |
245 | if (err <= 0) |
246 | return; |
247 | |
248 | devl_params_unregister(devlink: priv_to_devlink(priv: pf), params: nfp_devlink_params, |
249 | ARRAY_SIZE(nfp_devlink_params)); |
250 | } |
251 | |