main.c 18.4 KB
Newer Older
S
Simon Horman 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*
 * Copyright (C) 2017 Netronome Systems, Inc.
 *
 * This software is dual licensed under the GNU General License Version 2,
 * June 1991 as shown in the file COPYING in the top-level directory of this
 * source tree or the BSD 2-Clause License provided below.  You have the
 * option to license this software under the complete terms of either license.
 *
 * The BSD 2-Clause License:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      1. Redistributions of source code must retain the above
 *         copyright notice, this list of conditions and the following
 *         disclaimer.
 *
 *      2. Redistributions in binary form must reproduce the above
 *         copyright notice, this list of conditions and the following
 *         disclaimer in the documentation and/or other materials
 *         provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <linux/etherdevice.h>
35
#include <linux/lockdep.h>
S
Simon Horman 已提交
36 37
#include <linux/pci.h>
#include <linux/skbuff.h>
38
#include <linux/vmalloc.h>
S
Simon Horman 已提交
39 40 41
#include <net/devlink.h>
#include <net/dst_metadata.h>

42
#include "main.h"
S
Simon Horman 已提交
43
#include "../nfpcore/nfp_cpp.h"
44
#include "../nfpcore/nfp_nffw.h"
S
Simon Horman 已提交
45 46 47 48 49 50 51 52
#include "../nfpcore/nfp_nsp.h"
#include "../nfp_app.h"
#include "../nfp_main.h"
#include "../nfp_net.h"
#include "../nfp_net_repr.h"
#include "../nfp_port.h"
#include "./cmsg.h"

53 54
#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL

S
Simon Horman 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
{
	return "FLOWER";
}

static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
{
	return DEVLINK_ESWITCH_MODE_SWITCHDEV;
}

static enum nfp_repr_type
nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port)
{
	switch (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id)) {
	case NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT:
		*port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM,
				  port_id);
		return NFP_REPR_TYPE_PHYS_PORT;

	case NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT:
		*port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port_id);
		if (FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, port_id) ==
		    NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF)
			return NFP_REPR_TYPE_PF;
		else
			return NFP_REPR_TYPE_VF;
	}

83
	return __NFP_REPR_TYPE_MAX;
S
Simon Horman 已提交
84 85 86 87 88 89 90 91 92 93
}

static struct net_device *
nfp_flower_repr_get(struct nfp_app *app, u32 port_id)
{
	enum nfp_repr_type repr_type;
	struct nfp_reprs *reprs;
	u8 port = 0;

	repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port);
94 95
	if (repr_type > NFP_REPR_TYPE_MAX)
		return NULL;
S
Simon Horman 已提交
96 97 98 99 100 101 102 103

	reprs = rcu_dereference(app->reprs[repr_type]);
	if (!reprs)
		return NULL;

	if (port >= reprs->num_reprs)
		return NULL;

104
	return rcu_dereference(reprs->reprs[port]);
S
Simon Horman 已提交
105 106
}

107 108 109 110 111 112 113 114 115 116 117 118
static int
nfp_flower_reprs_reify(struct nfp_app *app, enum nfp_repr_type type,
		       bool exists)
{
	struct nfp_reprs *reprs;
	int i, err, count = 0;

	reprs = rcu_dereference_protected(app->reprs[type],
					  lockdep_is_held(&app->pf->lock));
	if (!reprs)
		return 0;

119 120 121 122 123 124
	for (i = 0; i < reprs->num_reprs; i++) {
		struct net_device *netdev;

		netdev = nfp_repr_get_locked(app, reprs, i);
		if (netdev) {
			struct nfp_repr *repr = netdev_priv(netdev);
125 126 127 128 129 130

			err = nfp_flower_cmsg_portreify(repr, exists);
			if (err)
				return err;
			count++;
		}
131
	}
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

	return count;
}

static int
nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl)
{
	struct nfp_flower_priv *priv = app->priv;
	int err;

	if (!tot_repl)
		return 0;

	lockdep_assert_held(&app->pf->lock);
	err = wait_event_interruptible_timeout(priv->reify_wait_queue,
					       atomic_read(replies) >= tot_repl,
					       msecs_to_jiffies(10));
	if (err <= 0) {
		nfp_warn(app->cpp, "Not all reprs responded to reify\n");
		return -EIO;
	}

	return 0;
}

157 158
static int
nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr)
S
Simon Horman 已提交
159 160 161
{
	int err;

162
	err = nfp_flower_cmsg_portmod(repr, true, repr->netdev->mtu, false);
S
Simon Horman 已提交
163 164 165
	if (err)
		return err;

166
	netif_tx_wake_all_queues(repr->netdev);
S
Simon Horman 已提交
167 168 169 170

	return 0;
}

171 172
static int
nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr)
S
Simon Horman 已提交
173
{
174
	netif_tx_disable(repr->netdev);
S
Simon Horman 已提交
175

176
	return nfp_flower_cmsg_portmod(repr, false, repr->netdev->mtu, false);
S
Simon Horman 已提交
177 178
}

179 180 181 182 183 184 185 186 187 188 189
static int
nfp_flower_repr_netdev_init(struct nfp_app *app, struct net_device *netdev)
{
	return tc_setup_cb_egdev_register(netdev,
					  nfp_flower_setup_tc_egress_cb,
					  netdev_priv(netdev));
}

static void
nfp_flower_repr_netdev_clean(struct nfp_app *app, struct net_device *netdev)
{
190 191 192 193
	struct nfp_repr *repr = netdev_priv(netdev);

	kfree(repr->app_priv);

194 195 196 197
	tc_setup_cb_egdev_unregister(netdev, nfp_flower_setup_tc_egress_cb,
				     netdev_priv(netdev));
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
static void
nfp_flower_repr_netdev_preclean(struct nfp_app *app, struct net_device *netdev)
{
	struct nfp_repr *repr = netdev_priv(netdev);
	struct nfp_flower_priv *priv = app->priv;
	atomic_t *replies = &priv->reify_replies;
	int err;

	atomic_set(replies, 0);
	err = nfp_flower_cmsg_portreify(repr, false);
	if (err) {
		nfp_warn(app->cpp, "Failed to notify firmware about repr destruction\n");
		return;
	}

	nfp_flower_wait_repr_reify(app, replies, 1);
}

216 217
static void nfp_flower_sriov_disable(struct nfp_app *app)
{
218 219 220 221 222
	struct nfp_flower_priv *priv = app->priv;

	if (!priv->nn)
		return;

223 224 225 226 227 228 229 230 231 232
	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
}

static int
nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
			    enum nfp_flower_cmsg_port_vnic_type vnic_type,
			    enum nfp_repr_type repr_type, unsigned int cnt)
{
	u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp);
	struct nfp_flower_priv *priv = app->priv;
233
	atomic_t *replies = &priv->reify_replies;
234
	struct nfp_flower_repr_priv *repr_priv;
235
	enum nfp_port_type port_type;
236
	struct nfp_repr *nfp_repr;
237
	struct nfp_reprs *reprs;
238
	int i, err, reify_cnt;
239 240
	const u8 queue = 0;

241 242 243
	port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT :
						    NFP_PORT_VF_PORT;

244 245 246 247 248
	reprs = nfp_reprs_alloc(cnt);
	if (!reprs)
		return -ENOMEM;

	for (i = 0; i < cnt; i++) {
249
		struct net_device *repr;
250
		struct nfp_port *port;
251 252
		u32 port_id;

253 254
		repr = nfp_repr_alloc(app);
		if (!repr) {
255 256 257 258
			err = -ENOMEM;
			goto err_reprs_clean;
		}

259 260 261
		repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL);
		if (!repr_priv) {
			err = -ENOMEM;
262
			nfp_repr_free(repr);
263 264 265 266 267 268
			goto err_reprs_clean;
		}

		nfp_repr = netdev_priv(repr);
		nfp_repr->app_priv = repr_priv;

269 270 271
		/* For now we only support 1 PF */
		WARN_ON(repr_type == NFP_REPR_TYPE_PF && i);

272
		port = nfp_port_alloc(app, port_type, repr);
273 274
		if (IS_ERR(port)) {
			err = PTR_ERR(port);
275
			kfree(repr_priv);
276 277 278
			nfp_repr_free(repr);
			goto err_reprs_clean;
		}
279 280
		if (repr_type == NFP_REPR_TYPE_PF) {
			port->pf_id = i;
281
			port->vnic = priv->nn->dp.ctrl_bar;
282
		} else {
283
			port->pf_id = 0;
284
			port->vf_id = i;
285 286
			port->vnic =
				app->pf->vf_cfg_mem + i * NFP_NET_CFG_BAR_SZ;
287 288
		}

289
		eth_hw_addr_random(repr);
290 291 292

		port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type,
						    i, queue);
293
		err = nfp_repr_init(app, repr,
294 295
				    port_id, port, priv->nn->dp.netdev);
		if (err) {
296
			kfree(repr_priv);
297
			nfp_port_free(port);
298
			nfp_repr_free(repr);
299
			goto err_reprs_clean;
300
		}
301

302
		RCU_INIT_POINTER(reprs->reprs[i], repr);
303 304
		nfp_info(app->cpp, "%s%d Representor(%s) created\n",
			 repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i,
305
			 repr->name);
306 307
	}

308
	nfp_app_reprs_set(app, repr_type, reprs);
309

310 311 312 313 314 315 316 317 318 319 320 321
	atomic_set(replies, 0);
	reify_cnt = nfp_flower_reprs_reify(app, repr_type, true);
	if (reify_cnt < 0) {
		err = reify_cnt;
		nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n");
		goto err_reprs_remove;
	}

	err = nfp_flower_wait_repr_reify(app, replies, reify_cnt);
	if (err)
		goto err_reprs_remove;

322
	return 0;
323 324
err_reprs_remove:
	reprs = nfp_app_reprs_set(app, repr_type, NULL);
325
err_reprs_clean:
326
	nfp_reprs_clean_and_free(app, reprs);
327 328 329 330 331
	return err;
}

static int nfp_flower_sriov_enable(struct nfp_app *app, int num_vfs)
{
332 333 334 335 336
	struct nfp_flower_priv *priv = app->priv;

	if (!priv->nn)
		return 0;

337 338 339 340 341 342 343
	return nfp_flower_spawn_vnic_reprs(app,
					   NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF,
					   NFP_REPR_TYPE_VF, num_vfs);
}

static int
nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
S
Simon Horman 已提交
344 345
{
	struct nfp_eth_table *eth_tbl = app->pf->eth_tbl;
346
	atomic_t *replies = &priv->reify_replies;
347 348
	struct nfp_flower_repr_priv *repr_priv;
	struct nfp_repr *nfp_repr;
349
	struct sk_buff *ctrl_skb;
350
	struct nfp_reprs *reprs;
351
	int err, reify_cnt;
S
Simon Horman 已提交
352 353
	unsigned int i;

354 355
	ctrl_skb = nfp_flower_cmsg_mac_repr_start(app, eth_tbl->count);
	if (!ctrl_skb)
S
Simon Horman 已提交
356 357
		return -ENOMEM;

358 359 360 361 362 363
	reprs = nfp_reprs_alloc(eth_tbl->max_index + 1);
	if (!reprs) {
		err = -ENOMEM;
		goto err_free_ctrl_skb;
	}

S
Simon Horman 已提交
364
	for (i = 0; i < eth_tbl->count; i++) {
365
		unsigned int phys_port = eth_tbl->ports[i].index;
366
		struct net_device *repr;
S
Simon Horman 已提交
367 368 369
		struct nfp_port *port;
		u32 cmsg_port_id;

370 371
		repr = nfp_repr_alloc(app);
		if (!repr) {
S
Simon Horman 已提交
372 373 374 375
			err = -ENOMEM;
			goto err_reprs_clean;
		}

376 377 378
		repr_priv = kzalloc(sizeof(*repr_priv), GFP_KERNEL);
		if (!repr_priv) {
			err = -ENOMEM;
379
			nfp_repr_free(repr);
380 381 382 383 384 385
			goto err_reprs_clean;
		}

		nfp_repr = netdev_priv(repr);
		nfp_repr->app_priv = repr_priv;

386
		port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr);
S
Simon Horman 已提交
387 388
		if (IS_ERR(port)) {
			err = PTR_ERR(port);
389
			kfree(repr_priv);
390
			nfp_repr_free(repr);
S
Simon Horman 已提交
391 392 393 394
			goto err_reprs_clean;
		}
		err = nfp_port_init_phy_port(app->pf, app, port, i);
		if (err) {
395
			kfree(repr_priv);
S
Simon Horman 已提交
396
			nfp_port_free(port);
397
			nfp_repr_free(repr);
S
Simon Horman 已提交
398 399 400
			goto err_reprs_clean;
		}

401
		SET_NETDEV_DEV(repr, &priv->nn->pdev->dev);
402
		nfp_net_get_mac_addr(app->pf, repr, port);
S
Simon Horman 已提交
403 404

		cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port);
405
		err = nfp_repr_init(app, repr,
S
Simon Horman 已提交
406 407
				    cmsg_port_id, port, priv->nn->dp.netdev);
		if (err) {
408
			kfree(repr_priv);
S
Simon Horman 已提交
409
			nfp_port_free(port);
410
			nfp_repr_free(repr);
S
Simon Horman 已提交
411 412 413
			goto err_reprs_clean;
		}

414 415 416 417 418
		nfp_flower_cmsg_mac_repr_add(ctrl_skb, i,
					     eth_tbl->ports[i].nbi,
					     eth_tbl->ports[i].base,
					     phys_port);

419
		RCU_INIT_POINTER(reprs->reprs[phys_port], repr);
S
Simon Horman 已提交
420
		nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n",
421
			 phys_port, repr->name);
S
Simon Horman 已提交
422 423
	}

424
	nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs);
S
Simon Horman 已提交
425

426
	/* The REIFY/MAC_REPR control messages should be sent after the MAC
427 428 429 430 431 432
	 * representors are registered using nfp_app_reprs_set().  This is
	 * because the firmware may respond with control messages for the
	 * MAC representors, f.e. to provide the driver with information
	 * about their state, and without registration the driver will drop
	 * any such messages.
	 */
433 434 435 436 437 438 439 440 441 442 443 444
	atomic_set(replies, 0);
	reify_cnt = nfp_flower_reprs_reify(app, NFP_REPR_TYPE_PHYS_PORT, true);
	if (reify_cnt < 0) {
		err = reify_cnt;
		nfp_warn(app->cpp, "Failed to notify firmware about repr creation\n");
		goto err_reprs_remove;
	}

	err = nfp_flower_wait_repr_reify(app, replies, reify_cnt);
	if (err)
		goto err_reprs_remove;

445 446
	nfp_ctrl_tx(app->ctrl, ctrl_skb);

S
Simon Horman 已提交
447
	return 0;
448 449
err_reprs_remove:
	reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, NULL);
S
Simon Horman 已提交
450
err_reprs_clean:
451
	nfp_reprs_clean_and_free(app, reprs);
452 453
err_free_ctrl_skb:
	kfree_skb(ctrl_skb);
S
Simon Horman 已提交
454 455 456
	return err;
}

457 458
static int nfp_flower_vnic_alloc(struct nfp_app *app, struct nfp_net *nn,
				 unsigned int id)
S
Simon Horman 已提交
459 460 461 462 463 464 465 466
{
	if (id > 0) {
		nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n");
		goto err_invalid_port;
	}

	eth_hw_addr_random(nn->dp.netdev);
	netif_keep_dst(nn->dp.netdev);
467
	nn->vnic_no_name = true;
S
Simon Horman 已提交
468 469 470 471 472 473 474 475

	return 0;

err_invalid_port:
	nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev);
	return PTR_ERR_OR_ZERO(nn->port);
}

476 477 478 479
static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
{
	struct nfp_flower_priv *priv = app->priv;

480 481 482 483 484
	if (app->pf->num_vfs)
		nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);

485 486 487 488 489 490
	priv->nn = NULL;
}

static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn)
{
	struct nfp_flower_priv *priv = app->priv;
491
	int err;
492 493 494

	priv->nn = nn;

495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
	err = nfp_flower_spawn_phy_reprs(app, app->priv);
	if (err)
		goto err_clear_nn;

	err = nfp_flower_spawn_vnic_reprs(app,
					  NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF,
					  NFP_REPR_TYPE_PF, 1);
	if (err)
		goto err_destroy_reprs_phy;

	if (app->pf->num_vfs) {
		err = nfp_flower_spawn_vnic_reprs(app,
						  NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF,
						  NFP_REPR_TYPE_VF,
						  app->pf->num_vfs);
		if (err)
			goto err_destroy_reprs_pf;
	}

514
	return 0;
515 516 517 518 519 520 521 522

err_destroy_reprs_pf:
	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
err_destroy_reprs_phy:
	nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
err_clear_nn:
	priv->nn = NULL;
	return err;
523 524
}

S
Simon Horman 已提交
525 526 527
static int nfp_flower_init(struct nfp_app *app)
{
	const struct nfp_pf *pf = app->pf;
528
	struct nfp_flower_priv *app_priv;
529
	u64 version, features;
530
	int err;
S
Simon Horman 已提交
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

	if (!pf->eth_tbl) {
		nfp_warn(app->cpp, "FlowerNIC requires eth table\n");
		return -EINVAL;
	}

	if (!pf->mac_stats_bar) {
		nfp_warn(app->cpp, "FlowerNIC requires mac_stats BAR\n");
		return -EINVAL;
	}

	if (!pf->vf_cfg_bar) {
		nfp_warn(app->cpp, "FlowerNIC requires vf_cfg BAR\n");
		return -EINVAL;
	}

547 548 549 550 551 552 553 554 555 556 557 558
	version = nfp_rtsym_read_le(app->pf->rtbl, "hw_flower_version", &err);
	if (err) {
		nfp_warn(app->cpp, "FlowerNIC requires hw_flower_version memory symbol\n");
		return err;
	}

	/* We need to ensure hardware has enough flower capabilities. */
	if (version != NFP_FLOWER_ALLOWED_VER) {
		nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n");
		return -EINVAL;
	}

559 560
	app_priv = vzalloc(sizeof(struct nfp_flower_priv));
	if (!app_priv)
561 562
		return -ENOMEM;

563
	app->priv = app_priv;
564
	app_priv->app = app;
565 566
	skb_queue_head_init(&app_priv->cmsg_skbs_high);
	skb_queue_head_init(&app_priv->cmsg_skbs_low);
567
	INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx);
568
	init_waitqueue_head(&app_priv->reify_wait_queue);
569

570 571 572
	init_waitqueue_head(&app_priv->mtu_conf.wait_q);
	spin_lock_init(&app_priv->mtu_conf.lock);

573 574 575 576
	err = nfp_flower_metadata_init(app);
	if (err)
		goto err_free_app_priv;

577 578 579 580 581 582 583 584
	/* Extract the extra features supported by the firmware. */
	features = nfp_rtsym_read_le(app->pf->rtbl,
				     "_abi_flower_extra_features", &err);
	if (err)
		app_priv->flower_ext_feats = 0;
	else
		app_priv->flower_ext_feats = features;

585 586 587
	/* Tell the firmware that the driver supports lag. */
	err = nfp_rtsym_write_le(app->pf->rtbl,
				 "_abi_flower_balance_sync_enable", 1);
588
	if (!err) {
589
		app_priv->flower_ext_feats |= NFP_FL_FEATS_LAG;
590 591
		nfp_flower_lag_init(&app_priv->nfp_lag);
	} else if (err == -ENOENT) {
592
		nfp_warn(app->cpp, "LAG not supported by FW.\n");
593
	} else {
594
		goto err_cleanup_metadata;
595
	}
596

S
Simon Horman 已提交
597
	return 0;
598

599 600
err_cleanup_metadata:
	nfp_flower_metadata_cleanup(app);
601 602 603
err_free_app_priv:
	vfree(app->priv);
	return err;
S
Simon Horman 已提交
604 605
}

606 607
static void nfp_flower_clean(struct nfp_app *app)
{
608 609
	struct nfp_flower_priv *app_priv = app->priv;

610 611
	skb_queue_purge(&app_priv->cmsg_skbs_high);
	skb_queue_purge(&app_priv->cmsg_skbs_low);
612 613
	flush_work(&app_priv->cmsg_work);

614 615 616
	if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
		nfp_flower_lag_cleanup(&app_priv->nfp_lag);

617
	nfp_flower_metadata_cleanup(app);
618
	vfree(app->priv);
619 620 621
	app->priv = NULL;
}

622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
static bool nfp_flower_check_ack(struct nfp_flower_priv *app_priv)
{
	bool ret;

	spin_lock_bh(&app_priv->mtu_conf.lock);
	ret = app_priv->mtu_conf.ack;
	spin_unlock_bh(&app_priv->mtu_conf.lock);

	return ret;
}

static int
nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev,
			   int new_mtu)
{
	struct nfp_flower_priv *app_priv = app->priv;
	struct nfp_repr *repr = netdev_priv(netdev);
	int err, ack;

	/* Only need to config FW for physical port MTU change. */
	if (repr->port->type != NFP_PORT_PHYS_PORT)
		return 0;

	if (!(app_priv->flower_ext_feats & NFP_FL_NBI_MTU_SETTING)) {
		nfp_err(app->cpp, "Physical port MTU setting not supported\n");
		return -EINVAL;
	}

	spin_lock_bh(&app_priv->mtu_conf.lock);
	app_priv->mtu_conf.ack = false;
	app_priv->mtu_conf.requested_val = new_mtu;
	app_priv->mtu_conf.portnum = repr->dst->u.port_info.port_id;
	spin_unlock_bh(&app_priv->mtu_conf.lock);

	err = nfp_flower_cmsg_portmod(repr, netif_carrier_ok(netdev), new_mtu,
				      true);
	if (err) {
		spin_lock_bh(&app_priv->mtu_conf.lock);
		app_priv->mtu_conf.requested_val = 0;
		spin_unlock_bh(&app_priv->mtu_conf.lock);
		return err;
	}

	/* Wait for fw to ack the change. */
	ack = wait_event_timeout(app_priv->mtu_conf.wait_q,
				 nfp_flower_check_ack(app_priv),
				 msecs_to_jiffies(10));

	if (!ack) {
		spin_lock_bh(&app_priv->mtu_conf.lock);
		app_priv->mtu_conf.requested_val = 0;
		spin_unlock_bh(&app_priv->mtu_conf.lock);
		nfp_warn(app->cpp, "MTU change not verified with fw\n");
		return -EIO;
	}

	return 0;
}

681 682
static int nfp_flower_start(struct nfp_app *app)
{
683 684 685 686 687 688 689 690 691 692 693 694 695
	struct nfp_flower_priv *app_priv = app->priv;
	int err;

	if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) {
		err = nfp_flower_lag_reset(&app_priv->nfp_lag);
		if (err)
			return err;

		err = register_netdevice_notifier(&app_priv->nfp_lag.lag_nb);
		if (err)
			return err;
	}

696 697 698 699 700
	return nfp_tunnel_config_start(app);
}

static void nfp_flower_stop(struct nfp_app *app)
{
701 702 703 704 705
	struct nfp_flower_priv *app_priv = app->priv;

	if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
		unregister_netdevice_notifier(&app_priv->nfp_lag.lag_nb);

706 707 708
	nfp_tunnel_config_stop(app);
}

S
Simon Horman 已提交
709 710 711
const struct nfp_app_type app_flower = {
	.id		= NFP_APP_FLOWER_NIC,
	.name		= "flower",
712 713

	.ctrl_cap_mask	= ~0U,
S
Simon Horman 已提交
714 715 716 717 718
	.ctrl_has_meta	= true,

	.extra_cap	= nfp_flower_extra_cap,

	.init		= nfp_flower_init,
719
	.clean		= nfp_flower_clean,
S
Simon Horman 已提交
720

721 722
	.repr_change_mtu  = nfp_flower_repr_change_mtu,

723
	.vnic_alloc	= nfp_flower_vnic_alloc,
S
Simon Horman 已提交
724
	.vnic_init	= nfp_flower_vnic_init,
725
	.vnic_clean	= nfp_flower_vnic_clean,
S
Simon Horman 已提交
726

727
	.repr_init	= nfp_flower_repr_netdev_init,
728
	.repr_preclean	= nfp_flower_repr_netdev_preclean,
729 730
	.repr_clean	= nfp_flower_repr_netdev_clean,

731 732 733
	.repr_open	= nfp_flower_repr_netdev_open,
	.repr_stop	= nfp_flower_repr_netdev_stop,

734 735 736
	.start		= nfp_flower_start,
	.stop		= nfp_flower_stop,

S
Simon Horman 已提交
737 738
	.ctrl_msg_rx	= nfp_flower_cmsg_rx,

739 740 741
	.sriov_enable	= nfp_flower_sriov_enable,
	.sriov_disable	= nfp_flower_sriov_disable,

S
Simon Horman 已提交
742 743
	.eswitch_mode_get  = eswitch_mode_get,
	.repr_get	= nfp_flower_repr_get,
744 745

	.setup_tc	= nfp_flower_setup_tc,
S
Simon Horman 已提交
746
};