Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / net / ethernet / netronome / nfp / devlink_param.c
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 }