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