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