net: replace ndo_get_devlink with ndo_get_devlink_port
[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         if (count < 2)
74                 return -EINVAL;
75
76         mutex_lock(&pf->lock);
77
78         rtnl_lock();
79         ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
80         rtnl_unlock();
81         if (ret)
82                 goto out;
83
84         if (eth_port.is_split || eth_port.port_lanes % count) {
85                 ret = -EINVAL;
86                 goto out;
87         }
88
89         /* Special case the 100G CXP -> 2x40G split */
90         lanes = eth_port.port_lanes / count;
91         if (eth_port.lanes == 10 && count == 2)
92                 lanes = 8 / count;
93
94         ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
95 out:
96         mutex_unlock(&pf->lock);
97
98         return ret;
99 }
100
101 static int
102 nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
103                          struct netlink_ext_ack *extack)
104 {
105         struct nfp_pf *pf = devlink_priv(devlink);
106         struct nfp_eth_table_port eth_port;
107         unsigned int lanes;
108         int ret;
109
110         mutex_lock(&pf->lock);
111
112         rtnl_lock();
113         ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
114         rtnl_unlock();
115         if (ret)
116                 goto out;
117
118         if (!eth_port.is_split) {
119                 ret = -EINVAL;
120                 goto out;
121         }
122
123         /* Special case the 100G CXP -> 2x40G unsplit */
124         lanes = eth_port.port_lanes;
125         if (eth_port.port_lanes == 8)
126                 lanes = 10;
127
128         ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
129 out:
130         mutex_unlock(&pf->lock);
131
132         return ret;
133 }
134
135 static int
136 nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
137                         u16 pool_index, struct devlink_sb_pool_info *pool_info)
138 {
139         struct nfp_pf *pf = devlink_priv(devlink);
140
141         return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
142 }
143
144 static int
145 nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
146                         u16 pool_index,
147                         u32 size, enum devlink_sb_threshold_type threshold_type)
148 {
149         struct nfp_pf *pf = devlink_priv(devlink);
150
151         return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
152                                        size, threshold_type);
153 }
154
155 static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
156 {
157         struct nfp_pf *pf = devlink_priv(devlink);
158
159         return nfp_app_eswitch_mode_get(pf->app, mode);
160 }
161
162 static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
163                                         struct netlink_ext_ack *extack)
164 {
165         struct nfp_pf *pf = devlink_priv(devlink);
166         int ret;
167
168         mutex_lock(&pf->lock);
169         ret = nfp_app_eswitch_mode_set(pf->app, mode);
170         mutex_unlock(&pf->lock);
171
172         return ret;
173 }
174
175 static const struct nfp_devlink_versions_simple {
176         const char *key;
177         const char *hwinfo;
178 } nfp_devlink_versions_hwinfo[] = {
179         { DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,        "assembly.partno", },
180         { DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,       "assembly.revision", },
181         { DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },
182         { "board.model", /* code name */                "assembly.model", },
183 };
184
185 static int
186 nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
187 {
188         unsigned int i;
189         int err;
190
191         for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
192                 const struct nfp_devlink_versions_simple *info;
193                 const char *val;
194
195                 info = &nfp_devlink_versions_hwinfo[i];
196
197                 val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
198                 if (!val)
199                         continue;
200
201                 err = devlink_info_version_fixed_put(req, info->key, val);
202                 if (err)
203                         return err;
204         }
205
206         return 0;
207 }
208
209 static const struct nfp_devlink_versions {
210         enum nfp_nsp_versions id;
211         const char *key;
212 } nfp_devlink_versions_nsp[] = {
213         { NFP_VERSIONS_BUNDLE,  "fw.bundle_id", },
214         { NFP_VERSIONS_BSP,     DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
215         { NFP_VERSIONS_CPLD,    "fw.cpld", },
216         { NFP_VERSIONS_APP,     DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
217         { NFP_VERSIONS_UNDI,    DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },
218         { NFP_VERSIONS_NCSI,    DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },
219         { NFP_VERSIONS_CFGR,    "chip.init", },
220 };
221
222 static int
223 nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
224                              const u8 *buf, unsigned int size)
225 {
226         unsigned int i;
227         int err;
228
229         for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
230                 const struct nfp_devlink_versions *info;
231                 const char *version;
232
233                 info = &nfp_devlink_versions_nsp[i];
234
235                 version = nfp_nsp_versions_get(info->id, flash, buf, size);
236                 if (IS_ERR(version)) {
237                         if (PTR_ERR(version) == -ENOENT)
238                                 continue;
239                         else
240                                 return PTR_ERR(version);
241                 }
242
243                 if (flash)
244                         err = devlink_info_version_stored_put(req, info->key,
245                                                               version);
246                 else
247                         err = devlink_info_version_running_put(req, info->key,
248                                                                version);
249                 if (err)
250                         return err;
251         }
252
253         return 0;
254 }
255
256 static int
257 nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
258                      struct netlink_ext_ack *extack)
259 {
260         struct nfp_pf *pf = devlink_priv(devlink);
261         const char *sn, *vendor, *part;
262         struct nfp_nsp *nsp;
263         char *buf = NULL;
264         int err;
265
266         err = devlink_info_driver_name_put(req, "nfp");
267         if (err)
268                 return err;
269
270         vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");
271         part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
272         sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
273         if (vendor && part && sn) {
274                 char *buf;
275
276                 buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,
277                               GFP_KERNEL);
278                 if (!buf)
279                         return -ENOMEM;
280
281                 buf[0] = '\0';
282                 strcat(buf, vendor);
283                 strcat(buf, part);
284                 strcat(buf, sn);
285
286                 err = devlink_info_serial_number_put(req, buf);
287                 kfree(buf);
288                 if (err)
289                         return err;
290         }
291
292         nsp = nfp_nsp_open(pf->cpp);
293         if (IS_ERR(nsp)) {
294                 NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
295                 return PTR_ERR(nsp);
296         }
297
298         if (nfp_nsp_has_versions(nsp)) {
299                 buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
300                 if (!buf) {
301                         err = -ENOMEM;
302                         goto err_close_nsp;
303                 }
304
305                 err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
306                 if (err)
307                         goto err_free_buf;
308
309                 err = nfp_devlink_versions_get_nsp(req, false,
310                                                    buf, NFP_NSP_VERSION_BUFSZ);
311                 if (err)
312                         goto err_free_buf;
313
314                 err = nfp_devlink_versions_get_nsp(req, true,
315                                                    buf, NFP_NSP_VERSION_BUFSZ);
316                 if (err)
317                         goto err_free_buf;
318
319                 kfree(buf);
320         }
321
322         nfp_nsp_close(nsp);
323
324         return nfp_devlink_versions_get_hwinfo(pf, req);
325
326 err_free_buf:
327         kfree(buf);
328 err_close_nsp:
329         nfp_nsp_close(nsp);
330         return err;
331 }
332
333 static int
334 nfp_devlink_flash_update(struct devlink *devlink, const char *path,
335                          const char *component, struct netlink_ext_ack *extack)
336 {
337         if (component)
338                 return -EOPNOTSUPP;
339         return nfp_flash_update_common(devlink_priv(devlink), path, extack);
340 }
341
342 const struct devlink_ops nfp_devlink_ops = {
343         .port_split             = nfp_devlink_port_split,
344         .port_unsplit           = nfp_devlink_port_unsplit,
345         .sb_pool_get            = nfp_devlink_sb_pool_get,
346         .sb_pool_set            = nfp_devlink_sb_pool_set,
347         .eswitch_mode_get       = nfp_devlink_eswitch_mode_get,
348         .eswitch_mode_set       = nfp_devlink_eswitch_mode_set,
349         .info_get               = nfp_devlink_info_get,
350         .flash_update           = nfp_devlink_flash_update,
351 };
352
353 int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
354 {
355         struct nfp_eth_table_port eth_port;
356         struct devlink *devlink;
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         devlink_port_attrs_set(&port->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
366                                eth_port.label_port, eth_port.is_split,
367                                eth_port.label_subport);
368
369         devlink = priv_to_devlink(app->pf);
370
371         return devlink_port_register(devlink, &port->dl_port, port->eth_id);
372 }
373
374 void nfp_devlink_port_unregister(struct nfp_port *port)
375 {
376         devlink_port_unregister(&port->dl_port);
377 }
378
379 void nfp_devlink_port_type_eth_set(struct nfp_port *port)
380 {
381         devlink_port_type_eth_set(&port->dl_port, port->netdev);
382 }
383
384 void nfp_devlink_port_type_clear(struct nfp_port *port)
385 {
386         devlink_port_type_clear(&port->dl_port);
387 }
388
389 struct devlink_port *nfp_devlink_get_devlink_port(struct net_device *netdev)
390 {
391         struct nfp_port *port;
392
393         port = nfp_port_from_netdev(netdev);
394         if (!port)
395                 return NULL;
396
397         return &port->dl_port;
398 }