Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / drivers / net / ethernet / netronome / nfp / nfp_devlink.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3
4 #include <linux/rtnetlink.h>
5 #include <net/devlink.h>
6
7 #include "nfpcore/nfp.h"
8 #include "nfpcore/nfp_nsp.h"
9 #include "nfp_app.h"
10 #include "nfp_main.h"
11 #include "nfp_port.h"
12
13 static int
14 nfp_devlink_fill_eth_port(struct nfp_port *port,
15                           struct nfp_eth_table_port *copy)
16 {
17         struct nfp_eth_table_port *eth_port;
18
19         eth_port = __nfp_port_get_eth_port(port);
20         if (!eth_port)
21                 return -EINVAL;
22
23         memcpy(copy, eth_port, sizeof(*eth_port));
24
25         return 0;
26 }
27
28 static int
29 nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
30                                   struct nfp_eth_table_port *copy)
31 {
32         struct nfp_port *port;
33
34         port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
35
36         return nfp_devlink_fill_eth_port(port, copy);
37 }
38
39 static int
40 nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
41 {
42         struct nfp_nsp *nsp;
43         int ret;
44
45         nsp = nfp_eth_config_start(pf->cpp, idx);
46         if (IS_ERR(nsp))
47                 return PTR_ERR(nsp);
48
49         ret = __nfp_eth_set_split(nsp, lanes);
50         if (ret) {
51                 nfp_eth_config_cleanup_end(nsp);
52                 return ret;
53         }
54
55         ret = nfp_eth_config_commit_end(nsp);
56         if (ret < 0)
57                 return ret;
58         if (ret) /* no change */
59                 return 0;
60
61         return nfp_net_refresh_port_table_sync(pf);
62 }
63
64 static int
65 nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
66                        unsigned int count, struct netlink_ext_ack *extack)
67 {
68         struct nfp_pf *pf = devlink_priv(devlink);
69         struct nfp_eth_table_port eth_port;
70         unsigned int lanes;
71         int ret;
72
73         mutex_lock(&pf->lock);
74
75         rtnl_lock();
76         ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
77         rtnl_unlock();
78         if (ret)
79                 goto out;
80
81         if (eth_port.port_lanes % count) {
82                 ret = -EINVAL;
83                 goto out;
84         }
85
86         /* Special case the 100G CXP -> 2x40G split */
87         lanes = eth_port.port_lanes / count;
88         if (eth_port.lanes == 10 && count == 2)
89                 lanes = 8 / count;
90
91         ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
92 out:
93         mutex_unlock(&pf->lock);
94
95         return ret;
96 }
97
98 static int
99 nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
100                          struct netlink_ext_ack *extack)
101 {
102         struct nfp_pf *pf = devlink_priv(devlink);
103         struct nfp_eth_table_port eth_port;
104         unsigned int lanes;
105         int ret;
106
107         mutex_lock(&pf->lock);
108
109         rtnl_lock();
110         ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
111         rtnl_unlock();
112         if (ret)
113                 goto out;
114
115         if (!eth_port.is_split) {
116                 ret = -EINVAL;
117                 goto out;
118         }
119
120         /* Special case the 100G CXP -> 2x40G unsplit */
121         lanes = eth_port.port_lanes;
122         if (eth_port.port_lanes == 8)
123                 lanes = 10;
124
125         ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
126 out:
127         mutex_unlock(&pf->lock);
128
129         return ret;
130 }
131
132 static int
133 nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
134                         u16 pool_index, struct devlink_sb_pool_info *pool_info)
135 {
136         struct nfp_pf *pf = devlink_priv(devlink);
137
138         return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
139 }
140
141 static int
142 nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
143                         u16 pool_index,
144                         u32 size, enum devlink_sb_threshold_type threshold_type,
145                         struct netlink_ext_ack *extack)
146 {
147         struct nfp_pf *pf = devlink_priv(devlink);
148
149         return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
150                                        size, threshold_type);
151 }
152
153 static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
154 {
155         struct nfp_pf *pf = devlink_priv(devlink);
156
157         return nfp_app_eswitch_mode_get(pf->app, mode);
158 }
159
160 static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
161                                         struct netlink_ext_ack *extack)
162 {
163         struct nfp_pf *pf = devlink_priv(devlink);
164         int ret;
165
166         mutex_lock(&pf->lock);
167         ret = nfp_app_eswitch_mode_set(pf->app, mode);
168         mutex_unlock(&pf->lock);
169
170         return ret;
171 }
172
173 static const struct nfp_devlink_versions_simple {
174         const char *key;
175         const char *hwinfo;
176 } nfp_devlink_versions_hwinfo[] = {
177         { DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,        "assembly.partno", },
178         { DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,       "assembly.revision", },
179         { DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },
180         { "board.model", /* code name */                "assembly.model", },
181 };
182
183 static int
184 nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
185 {
186         unsigned int i;
187         int err;
188
189         for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
190                 const struct nfp_devlink_versions_simple *info;
191                 const char *val;
192
193                 info = &nfp_devlink_versions_hwinfo[i];
194
195                 val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
196                 if (!val)
197                         continue;
198
199                 err = devlink_info_version_fixed_put(req, info->key, val);
200                 if (err)
201                         return err;
202         }
203
204         return 0;
205 }
206
207 static const struct nfp_devlink_versions {
208         enum nfp_nsp_versions id;
209         const char *key;
210 } nfp_devlink_versions_nsp[] = {
211         { NFP_VERSIONS_BUNDLE,  DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },
212         { NFP_VERSIONS_BSP,     DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
213         { NFP_VERSIONS_CPLD,    "fw.cpld", },
214         { NFP_VERSIONS_APP,     DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
215         { NFP_VERSIONS_UNDI,    DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },
216         { NFP_VERSIONS_NCSI,    DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },
217         { NFP_VERSIONS_CFGR,    "chip.init", },
218 };
219
220 static int
221 nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
222                              const u8 *buf, unsigned int size)
223 {
224         unsigned int i;
225         int err;
226
227         for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
228                 const struct nfp_devlink_versions *info;
229                 const char *version;
230
231                 info = &nfp_devlink_versions_nsp[i];
232
233                 version = nfp_nsp_versions_get(info->id, flash, buf, size);
234                 if (IS_ERR(version)) {
235                         if (PTR_ERR(version) == -ENOENT)
236                                 continue;
237                         else
238                                 return PTR_ERR(version);
239                 }
240
241                 if (flash)
242                         err = devlink_info_version_stored_put(req, info->key,
243                                                               version);
244                 else
245                         err = devlink_info_version_running_put(req, info->key,
246                                                                version);
247                 if (err)
248                         return err;
249         }
250
251         return 0;
252 }
253
254 static int
255 nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
256                      struct netlink_ext_ack *extack)
257 {
258         struct nfp_pf *pf = devlink_priv(devlink);
259         const char *sn, *vendor, *part;
260         struct nfp_nsp *nsp;
261         char *buf = NULL;
262         int err;
263
264         err = devlink_info_driver_name_put(req, "nfp");
265         if (err)
266                 return err;
267
268         vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");
269         part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
270         sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
271         if (vendor && part && sn) {
272                 char *buf;
273
274                 buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,
275                               GFP_KERNEL);
276                 if (!buf)
277                         return -ENOMEM;
278
279                 buf[0] = '\0';
280                 strcat(buf, vendor);
281                 strcat(buf, part);
282                 strcat(buf, sn);
283
284                 err = devlink_info_serial_number_put(req, buf);
285                 kfree(buf);
286                 if (err)
287                         return err;
288         }
289
290         nsp = nfp_nsp_open(pf->cpp);
291         if (IS_ERR(nsp)) {
292                 NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
293                 return PTR_ERR(nsp);
294         }
295
296         if (nfp_nsp_has_versions(nsp)) {
297                 buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
298                 if (!buf) {
299                         err = -ENOMEM;
300                         goto err_close_nsp;
301                 }
302
303                 err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
304                 if (err)
305                         goto err_free_buf;
306
307                 err = nfp_devlink_versions_get_nsp(req, false,
308                                                    buf, NFP_NSP_VERSION_BUFSZ);
309                 if (err)
310                         goto err_free_buf;
311
312                 err = nfp_devlink_versions_get_nsp(req, true,
313                                                    buf, NFP_NSP_VERSION_BUFSZ);
314                 if (err)
315                         goto err_free_buf;
316
317                 kfree(buf);
318         }
319
320         nfp_nsp_close(nsp);
321
322         return nfp_devlink_versions_get_hwinfo(pf, req);
323
324 err_free_buf:
325         kfree(buf);
326 err_close_nsp:
327         nfp_nsp_close(nsp);
328         return err;
329 }
330
331 static int
332 nfp_devlink_flash_update(struct devlink *devlink,
333                          struct devlink_flash_update_params *params,
334                          struct netlink_ext_ack *extack)
335 {
336         return nfp_flash_update_common(devlink_priv(devlink), params->fw, extack);
337 }
338
339 const struct devlink_ops nfp_devlink_ops = {
340         .port_split             = nfp_devlink_port_split,
341         .port_unsplit           = nfp_devlink_port_unsplit,
342         .sb_pool_get            = nfp_devlink_sb_pool_get,
343         .sb_pool_set            = nfp_devlink_sb_pool_set,
344         .eswitch_mode_get       = nfp_devlink_eswitch_mode_get,
345         .eswitch_mode_set       = nfp_devlink_eswitch_mode_set,
346         .info_get               = nfp_devlink_info_get,
347         .flash_update           = nfp_devlink_flash_update,
348 };
349
350 int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
351 {
352         struct devlink_port_attrs attrs = {};
353         struct nfp_eth_table_port eth_port;
354         struct devlink *devlink;
355         const u8 *serial;
356         int serial_len;
357         int ret;
358
359         rtnl_lock();
360         ret = nfp_devlink_fill_eth_port(port, &eth_port);
361         rtnl_unlock();
362         if (ret)
363                 return ret;
364
365         attrs.split = eth_port.is_split;
366         attrs.splittable = !attrs.split;
367         attrs.lanes = eth_port.port_lanes;
368         attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
369         attrs.phys.port_number = eth_port.label_port;
370         attrs.phys.split_subport_number = eth_port.label_subport;
371         serial_len = nfp_cpp_serial(port->app->cpp, &serial);
372         memcpy(attrs.switch_id.id, serial, serial_len);
373         attrs.switch_id.id_len = serial_len;
374         devlink_port_attrs_set(&port->dl_port, &attrs);
375
376         devlink = priv_to_devlink(app->pf);
377
378         return devlink_port_register(devlink, &port->dl_port, port->eth_id);
379 }
380
381 void nfp_devlink_port_unregister(struct nfp_port *port)
382 {
383         devlink_port_unregister(&port->dl_port);
384 }
385
386 void nfp_devlink_port_type_eth_set(struct nfp_port *port)
387 {
388         devlink_port_type_eth_set(&port->dl_port, port->netdev);
389 }
390
391 void nfp_devlink_port_type_clear(struct nfp_port *port)
392 {
393         devlink_port_type_clear(&port->dl_port);
394 }
395
396 struct devlink_port *nfp_devlink_get_devlink_port(struct net_device *netdev)
397 {
398         struct nfp_port *port;
399
400         port = nfp_port_from_netdev(netdev);
401         if (!port)
402                 return NULL;
403
404         return &port->dl_port;
405 }