blob: ab68a8f58862bafe0e2d252b118c030d6c2cdb3d [file] [log] [blame]
Simon Horman10253512017-06-23 22:12:08 +02001/*
2 * Copyright (C) 2017 Netronome Systems, Inc.
3 *
4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this
6 * source tree or the BSD 2-Clause License provided below. You have the
7 * option to license this software under the complete terms of either license.
8 *
9 * The BSD 2-Clause License:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include <linux/etherdevice.h>
35#include <linux/pci.h>
36#include <linux/skbuff.h>
37#include <net/devlink.h>
38#include <net/dst_metadata.h>
39
40#include "../nfpcore/nfp_cpp.h"
41#include "../nfpcore/nfp_nsp.h"
42#include "../nfp_app.h"
43#include "../nfp_main.h"
44#include "../nfp_net.h"
45#include "../nfp_net_repr.h"
46#include "../nfp_port.h"
47#include "./cmsg.h"
48
49/**
50 * struct nfp_flower_priv - Flower APP per-vNIC priv data
51 * @nn: Pointer to vNIC
52 */
53struct nfp_flower_priv {
54 struct nfp_net *nn;
55};
56
57static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
58{
59 return "FLOWER";
60}
61
62static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
63{
64 return DEVLINK_ESWITCH_MODE_SWITCHDEV;
65}
66
67static enum nfp_repr_type
68nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port)
69{
70 switch (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id)) {
71 case NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT:
72 *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM,
73 port_id);
74 return NFP_REPR_TYPE_PHYS_PORT;
75
76 case NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT:
77 *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port_id);
78 if (FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, port_id) ==
79 NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF)
80 return NFP_REPR_TYPE_PF;
81 else
82 return NFP_REPR_TYPE_VF;
83 }
84
85 return NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC;
86}
87
88static struct net_device *
89nfp_flower_repr_get(struct nfp_app *app, u32 port_id)
90{
91 enum nfp_repr_type repr_type;
92 struct nfp_reprs *reprs;
93 u8 port = 0;
94
95 repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port);
96
97 reprs = rcu_dereference(app->reprs[repr_type]);
98 if (!reprs)
99 return NULL;
100
101 if (port >= reprs->num_reprs)
102 return NULL;
103
104 return reprs->reprs[port];
105}
106
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700107static int
108nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr)
Simon Horman10253512017-06-23 22:12:08 +0200109{
110 int err;
111
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700112 err = nfp_flower_cmsg_portmod(repr, true);
Simon Horman10253512017-06-23 22:12:08 +0200113 if (err)
114 return err;
115
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700116 netif_carrier_on(repr->netdev);
117 netif_tx_wake_all_queues(repr->netdev);
Simon Horman10253512017-06-23 22:12:08 +0200118
119 return 0;
120}
121
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700122static int
123nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr)
Simon Horman10253512017-06-23 22:12:08 +0200124{
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700125 netif_carrier_off(repr->netdev);
126 netif_tx_disable(repr->netdev);
Simon Horman10253512017-06-23 22:12:08 +0200127
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700128 return nfp_flower_cmsg_portmod(repr, false);
Simon Horman10253512017-06-23 22:12:08 +0200129}
130
Simon Horman24a021e2017-06-23 22:12:09 +0200131static void nfp_flower_sriov_disable(struct nfp_app *app)
Simon Horman10253512017-06-23 22:12:08 +0200132{
Simon Horman24a021e2017-06-23 22:12:09 +0200133 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
Simon Horman10253512017-06-23 22:12:08 +0200134}
135
Simon Horman24a021e2017-06-23 22:12:09 +0200136static int
137nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
138 enum nfp_flower_cmsg_port_vnic_type vnic_type,
139 enum nfp_repr_type repr_type, unsigned int cnt)
140{
141 u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp);
142 struct nfp_flower_priv *priv = app->priv;
143 struct nfp_reprs *reprs, *old_reprs;
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700144 enum nfp_port_type port_type;
Simon Horman24a021e2017-06-23 22:12:09 +0200145 const u8 queue = 0;
146 int i, err;
147
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700148 port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT :
149 NFP_PORT_VF_PORT;
150
Simon Horman24a021e2017-06-23 22:12:09 +0200151 reprs = nfp_reprs_alloc(cnt);
152 if (!reprs)
153 return -ENOMEM;
154
155 for (i = 0; i < cnt; i++) {
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700156 struct nfp_port *port;
Simon Horman24a021e2017-06-23 22:12:09 +0200157 u32 port_id;
158
159 reprs->reprs[i] = nfp_repr_alloc(app);
160 if (!reprs->reprs[i]) {
161 err = -ENOMEM;
162 goto err_reprs_clean;
163 }
164
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700165 port = nfp_port_alloc(app, port_type, reprs->reprs[i]);
166 if (repr_type == NFP_REPR_TYPE_PF) {
167 port->pf_id = i;
168 } else {
169 port->pf_id = 0; /* For now we only support 1 PF */
170 port->vf_id = i;
171 }
172
Simon Horman24a021e2017-06-23 22:12:09 +0200173 eth_hw_addr_random(reprs->reprs[i]);
174
175 port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type,
176 i, queue);
177 err = nfp_repr_init(app, reprs->reprs[i],
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700178 port_id, port, priv->nn->dp.netdev);
179 if (err) {
180 nfp_port_free(port);
Simon Horman24a021e2017-06-23 22:12:09 +0200181 goto err_reprs_clean;
Jakub Kicinski38edbf62017-06-27 00:50:20 -0700182 }
Simon Horman24a021e2017-06-23 22:12:09 +0200183
184 nfp_info(app->cpp, "%s%d Representor(%s) created\n",
185 repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i,
186 reprs->reprs[i]->name);
187 }
188
189 old_reprs = nfp_app_reprs_set(app, repr_type, reprs);
190 if (IS_ERR(old_reprs)) {
191 err = PTR_ERR(old_reprs);
192 goto err_reprs_clean;
193 }
194
195 return 0;
196err_reprs_clean:
197 nfp_reprs_clean_and_free(reprs);
198 return err;
199}
200
201static int nfp_flower_sriov_enable(struct nfp_app *app, int num_vfs)
202{
203 return nfp_flower_spawn_vnic_reprs(app,
204 NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF,
205 NFP_REPR_TYPE_VF, num_vfs);
206}
207
208static void nfp_flower_stop(struct nfp_app *app)
209{
210 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
211 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
212
213}
214
215static int
216nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
Simon Horman10253512017-06-23 22:12:08 +0200217{
218 struct nfp_eth_table *eth_tbl = app->pf->eth_tbl;
Simon Horman10253512017-06-23 22:12:08 +0200219 struct nfp_reprs *reprs, *old_reprs;
220 unsigned int i;
221 int err;
222
223 reprs = nfp_reprs_alloc(eth_tbl->max_index + 1);
224 if (!reprs)
225 return -ENOMEM;
226
227 for (i = 0; i < eth_tbl->count; i++) {
228 int phys_port = eth_tbl->ports[i].index;
229 struct nfp_port *port;
230 u32 cmsg_port_id;
231
232 reprs->reprs[phys_port] = nfp_repr_alloc(app);
233 if (!reprs->reprs[phys_port]) {
234 err = -ENOMEM;
235 goto err_reprs_clean;
236 }
237
238 port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT,
239 reprs->reprs[phys_port]);
240 if (IS_ERR(port)) {
241 err = PTR_ERR(port);
242 goto err_reprs_clean;
243 }
244 err = nfp_port_init_phy_port(app->pf, app, port, i);
245 if (err) {
246 nfp_port_free(port);
247 goto err_reprs_clean;
248 }
249
250 SET_NETDEV_DEV(reprs->reprs[phys_port], &priv->nn->pdev->dev);
251 nfp_net_get_mac_addr(app->pf, port,
252 eth_tbl->ports[i].eth_index);
253
254 cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port);
255 err = nfp_repr_init(app, reprs->reprs[phys_port],
Simon Horman10253512017-06-23 22:12:08 +0200256 cmsg_port_id, port, priv->nn->dp.netdev);
257 if (err) {
258 nfp_port_free(port);
259 goto err_reprs_clean;
260 }
261
262 nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n",
263 phys_port, reprs->reprs[phys_port]->name);
264 }
265
266 old_reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
267 if (IS_ERR(old_reprs)) {
268 err = PTR_ERR(old_reprs);
269 goto err_reprs_clean;
270 }
271
272 return 0;
273err_reprs_clean:
274 nfp_reprs_clean_and_free(reprs);
275 return err;
276}
277
Simon Horman24a021e2017-06-23 22:12:09 +0200278static int nfp_flower_start(struct nfp_app *app)
279{
280 int err;
281
282 err = nfp_flower_spawn_phy_reprs(app, app->priv);
283 if (err)
284 return err;
285
286 return nfp_flower_spawn_vnic_reprs(app,
287 NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF,
288 NFP_REPR_TYPE_PF, 1);
289}
290
Simon Horman10253512017-06-23 22:12:08 +0200291static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn,
292 unsigned int id)
293{
Jakub Kicinski9ce6bbb2017-06-27 00:50:19 -0700294 struct nfp_flower_priv *priv = app->priv;
Simon Horman10253512017-06-23 22:12:08 +0200295
296 if (id > 0) {
297 nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n");
298 goto err_invalid_port;
299 }
300
Simon Horman10253512017-06-23 22:12:08 +0200301 priv->nn = nn;
302
303 eth_hw_addr_random(nn->dp.netdev);
304 netif_keep_dst(nn->dp.netdev);
305
306 return 0;
307
308err_invalid_port:
309 nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev);
310 return PTR_ERR_OR_ZERO(nn->port);
311}
312
313static int nfp_flower_init(struct nfp_app *app)
314{
315 const struct nfp_pf *pf = app->pf;
316
317 if (!pf->eth_tbl) {
318 nfp_warn(app->cpp, "FlowerNIC requires eth table\n");
319 return -EINVAL;
320 }
321
322 if (!pf->mac_stats_bar) {
323 nfp_warn(app->cpp, "FlowerNIC requires mac_stats BAR\n");
324 return -EINVAL;
325 }
326
327 if (!pf->vf_cfg_bar) {
328 nfp_warn(app->cpp, "FlowerNIC requires vf_cfg BAR\n");
329 return -EINVAL;
330 }
331
Jakub Kicinski9ce6bbb2017-06-27 00:50:19 -0700332 app->priv = kzalloc(sizeof(struct nfp_flower_priv), GFP_KERNEL);
333 if (!app->priv)
334 return -ENOMEM;
335
Simon Horman10253512017-06-23 22:12:08 +0200336 return 0;
337}
338
Jakub Kicinski9ce6bbb2017-06-27 00:50:19 -0700339static void nfp_flower_clean(struct nfp_app *app)
340{
341 kfree(app->priv);
342 app->priv = NULL;
343}
344
Simon Horman10253512017-06-23 22:12:08 +0200345const struct nfp_app_type app_flower = {
346 .id = NFP_APP_FLOWER_NIC,
347 .name = "flower",
348 .ctrl_has_meta = true,
349
350 .extra_cap = nfp_flower_extra_cap,
351
352 .init = nfp_flower_init,
Jakub Kicinski9ce6bbb2017-06-27 00:50:19 -0700353 .clean = nfp_flower_clean,
Simon Horman10253512017-06-23 22:12:08 +0200354
355 .vnic_init = nfp_flower_vnic_init,
Simon Horman10253512017-06-23 22:12:08 +0200356
Jakub Kicinski5d7c64a2017-06-27 00:50:22 -0700357 .repr_open = nfp_flower_repr_netdev_open,
358 .repr_stop = nfp_flower_repr_netdev_stop,
359
Simon Horman10253512017-06-23 22:12:08 +0200360 .start = nfp_flower_start,
361 .stop = nfp_flower_stop,
362
363 .ctrl_msg_rx = nfp_flower_cmsg_rx,
364
Simon Horman24a021e2017-06-23 22:12:09 +0200365 .sriov_enable = nfp_flower_sriov_enable,
366 .sriov_disable = nfp_flower_sriov_disable,
367
Simon Horman10253512017-06-23 22:12:08 +0200368 .eswitch_mode_get = eswitch_mode_get,
369 .repr_get = nfp_flower_repr_get,
370};