nfp_net_main.c 19.3 KB
Newer Older
J
Jakub Kicinski 已提交
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 35 36 37 38 39 40 41 42 43 44 45
/*
 * Copyright (C) 2015-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.
 */

/*
 * nfp_net_main.c
 * Netronome network device driver: Main entry point
 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
 *          Alejandro Lucero <alejandro.lucero@netronome.com>
 *          Jason McMullan <jason.mcmullan@netronome.com>
 *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
 */

#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/init.h>
46
#include <linux/lockdep.h>
J
Jakub Kicinski 已提交
47 48 49 50
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/msi.h>
#include <linux/random.h>
J
Jakub Kicinski 已提交
51
#include <linux/rtnetlink.h>
J
Jakub Kicinski 已提交
52 53 54 55

#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nffw.h"
56
#include "nfpcore/nfp_nsp.h"
J
Jakub Kicinski 已提交
57
#include "nfpcore/nfp6000_pcie.h"
58
#include "nfp_app.h"
J
Jakub Kicinski 已提交
59 60 61
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_main.h"
J
Jakub Kicinski 已提交
62
#include "nfp_port.h"
J
Jakub Kicinski 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

#define NFP_PF_CSR_SLICE_SIZE	(32 * 1024)

static int nfp_is_ready(struct nfp_cpp *cpp)
{
	const char *cp;
	long state;
	int err;

	cp = nfp_hwinfo_lookup(cpp, "board.state");
	if (!cp)
		return 0;

	err = kstrtol(cp, 0, &state);
	if (err < 0)
		return 0;

	return state == 15;
}

/**
 * nfp_net_map_area() - Help function to map an area
 * @cpp:    NFP CPP handler
 * @name:   Name for the area
 * @target: CPP target
 * @addr:   CPP address
 * @size:   Size of the area
 * @area:   Area handle (returned).
 *
 * This function is primarily to simplify the code in the main probe
 * function. To undo the effect of this functions call
 * @nfp_cpp_area_release_free(*area);
 *
 * Return: Pointer to memory mapped area or ERR_PTR
 */
static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp,
				    const char *name, int isl, int target,
				    unsigned long long addr, unsigned long size,
				    struct nfp_cpp_area **area)
{
	u8 __iomem *res;
	u32 dest;
	int err;

	dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, isl);

	*area = nfp_cpp_area_alloc_with_name(cpp, dest, name, addr, size);
	if (!*area) {
		err = -EIO;
		goto err_area;
	}

	err = nfp_cpp_area_acquire(*area);
	if (err < 0)
		goto err_acquire;

	res = nfp_cpp_area_iomem(*area);
	if (!res) {
		err = -EIO;
		goto err_map;
	}

	return res;

err_map:
	nfp_cpp_area_release(*area);
err_acquire:
	nfp_cpp_area_free(*area);
err_area:
	return (u8 __iomem *)ERR_PTR(err);
}

135 136 137 138 139 140 141 142 143
/**
 * nfp_net_get_mac_addr() - Get the MAC address.
 * @nn:       NFP Network structure
 * @cpp:      NFP CPP handle
 * @id:	      NFP port id
 *
 * First try to get the MAC address from NSP ETH table. If that
 * fails try HWInfo.  As a last resort generate a random address.
 */
J
Jakub Kicinski 已提交
144
void
145
nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id)
J
Jakub Kicinski 已提交
146
{
J
Jakub Kicinski 已提交
147
	struct nfp_eth_table_port *eth_port;
148
	struct nfp_net_dp *dp = &nn->dp;
J
Jakub Kicinski 已提交
149 150 151 152
	u8 mac_addr[ETH_ALEN];
	const char *mac_str;
	char name[32];

J
Jakub Kicinski 已提交
153 154 155 156
	eth_port = __nfp_port_get_eth_port(nn->port);
	if (eth_port) {
		ether_addr_copy(dp->netdev->dev_addr, eth_port->mac_addr);
		ether_addr_copy(dp->netdev->perm_addr, eth_port->mac_addr);
157 158 159
		return;
	}

J
Jakub Kicinski 已提交
160 161 162 163
	snprintf(name, sizeof(name), "eth%d.mac", id);

	mac_str = nfp_hwinfo_lookup(cpp, name);
	if (!mac_str) {
164 165
		dev_warn(dp->dev, "Can't lookup MAC address. Generate\n");
		eth_hw_addr_random(dp->netdev);
J
Jakub Kicinski 已提交
166 167 168 169 170 171
		return;
	}

	if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
		   &mac_addr[0], &mac_addr[1], &mac_addr[2],
		   &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
172
		dev_warn(dp->dev,
J
Jakub Kicinski 已提交
173
			 "Can't parse MAC address (%s). Generate.\n", mac_str);
174
		eth_hw_addr_random(dp->netdev);
J
Jakub Kicinski 已提交
175 176 177
		return;
	}

178 179
	ether_addr_copy(dp->netdev->dev_addr, mac_addr);
	ether_addr_copy(dp->netdev->perm_addr, mac_addr);
J
Jakub Kicinski 已提交
180 181
}

J
Jakub Kicinski 已提交
182
struct nfp_eth_table_port *
183
nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id)
J
Jakub Kicinski 已提交
184 185 186
{
	int i;

187 188 189
	for (i = 0; eth_tbl && i < eth_tbl->count; i++)
		if (eth_tbl->ports[i].eth_index == id)
			return &eth_tbl->ports[i];
190

191
	return NULL;
J
Jakub Kicinski 已提交
192 193
}

194 195 196
static int
nfp_net_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format,
			       unsigned int default_val)
J
Jakub Kicinski 已提交
197 198 199 200 201
{
	char name[256];
	int err = 0;
	u64 val;

202
	snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp));
J
Jakub Kicinski 已提交
203

204
	val = nfp_rtsym_read_le(pf->rtbl, name, &err);
J
Jakub Kicinski 已提交
205
	if (err) {
206 207 208 209
		if (err == -ENOENT)
			return default_val;
		nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
		return err;
J
Jakub Kicinski 已提交
210 211 212 213 214
	}

	return val;
}

215 216 217 218 219
static int nfp_net_pf_get_num_ports(struct nfp_pf *pf)
{
	return nfp_net_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1);
}

J
Jakub Kicinski 已提交
220 221 222 223 224 225
static int nfp_net_pf_get_app_id(struct nfp_pf *pf)
{
	return nfp_net_pf_rtsym_read_optional(pf, "_pf%u_net_app_id",
					      NFP_APP_CORE_NIC);
}

226 227 228
static u8 __iomem *
nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
		     unsigned int min_size, struct nfp_cpp_area **area)
J
Jakub Kicinski 已提交
229
{
230
	const struct nfp_rtsym *sym;
J
Jakub Kicinski 已提交
231
	char pf_symbol[256];
232
	u8 __iomem *mem;
J
Jakub Kicinski 已提交
233

234
	snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt,
235
		 nfp_cppcore_pcie_unit(pf->cpp));
J
Jakub Kicinski 已提交
236

237
	sym = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
238 239 240
	if (!sym) {
		nfp_err(pf->cpp, "Failed to find PF symbol %s\n", pf_symbol);
		return (u8 __iomem *)ERR_PTR(-ENOENT);
J
Jakub Kicinski 已提交
241 242
	}

243 244 245
	if (sym->size < min_size) {
		nfp_err(pf->cpp, "PF symbol %s too small\n", pf_symbol);
		return (u8 __iomem *)ERR_PTR(-EINVAL);
J
Jakub Kicinski 已提交
246 247
	}

248 249 250 251 252 253
	mem = nfp_net_map_area(pf->cpp, name, sym->domain, sym->target,
			       sym->addr, sym->size, area);
	if (IS_ERR(mem)) {
		nfp_err(pf->cpp, "Failed to map PF symbol %s: %ld\n",
			pf_symbol, PTR_ERR(mem));
		return mem;
J
Jakub Kicinski 已提交
254 255
	}

256
	return mem;
J
Jakub Kicinski 已提交
257 258
}

259 260
static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
J
Jakub Kicinski 已提交
261
	nfp_port_free(nn->port);
262 263 264 265 266
	list_del(&nn->vnic_list);
	pf->num_vnics--;
	nfp_net_free(nn);
}

J
Jakub Kicinski 已提交
267
static void nfp_net_pf_free_vnics(struct nfp_pf *pf)
J
Jakub Kicinski 已提交
268
{
269
	struct nfp_net *nn, *next;
J
Jakub Kicinski 已提交
270

271 272 273
	list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list)
		if (nfp_net_is_data_vnic(nn))
			nfp_net_pf_free_vnic(pf, nn);
J
Jakub Kicinski 已提交
274 275 276
}

static struct nfp_net *
277
nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev,
278
		      void __iomem *ctrl_bar, void __iomem *qc_bar,
279
		      int stride, unsigned int eth_id)
J
Jakub Kicinski 已提交
280
{
281
	u32 tx_base, rx_base, n_tx_rings, n_rx_rings;
J
Jakub Kicinski 已提交
282
	struct nfp_net *nn;
J
Jakub Kicinski 已提交
283
	int err;
J
Jakub Kicinski 已提交
284

285 286
	tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
	rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
J
Jakub Kicinski 已提交
287 288 289
	n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS);
	n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS);

J
Jakub Kicinski 已提交
290
	/* Allocate and initialise the vNIC */
291
	nn = nfp_net_alloc(pf->pdev, needs_netdev, n_tx_rings, n_rx_rings);
J
Jakub Kicinski 已提交
292 293 294
	if (IS_ERR(nn))
		return nn;

295
	nn->app = pf->app;
296
	nfp_net_get_fw_version(&nn->fw_ver, ctrl_bar);
297
	nn->dp.ctrl_bar = ctrl_bar;
298 299
	nn->tx_bar = qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
	nn->rx_bar = qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ;
300
	nn->dp.is_vf = 0;
J
Jakub Kicinski 已提交
301 302
	nn->stride_rx = stride;
	nn->stride_tx = stride;
J
Jakub Kicinski 已提交
303

304 305 306 307 308 309
	if (needs_netdev) {
		err = nfp_app_vnic_init(pf->app, nn, eth_id);
		if (err) {
			nfp_net_free(nn);
			return ERR_PTR(err);
		}
J
Jakub Kicinski 已提交
310
	}
311 312 313

	pf->num_vnics++;
	list_add_tail(&nn->vnic_list, &pf->vnics);
J
Jakub Kicinski 已提交
314 315 316 317 318

	return nn;
}

static int
J
Jakub Kicinski 已提交
319
nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id)
J
Jakub Kicinski 已提交
320 321 322 323 324 325 326 327 328
{
	int err;

	/* Get ME clock frequency from ctrl BAR
	 * XXX for now frequency is hardcoded until we figure out how
	 * to get the value from nfp-hwinfo into ctrl bar
	 */
	nn->me_freq_mhz = 1200;

329
	err = nfp_net_init(nn);
J
Jakub Kicinski 已提交
330 331 332
	if (err)
		return err;

J
Jakub Kicinski 已提交
333
	nfp_net_debugfs_vnic_add(nn, pf->ddir, id);
J
Jakub Kicinski 已提交
334

335 336 337 338 339 340
	if (nn->port) {
		err = nfp_devlink_port_register(pf->app, nn->port);
		if (err)
			goto err_dfs_clean;
	}

J
Jakub Kicinski 已提交
341 342 343
	nfp_net_info(nn);

	return 0;
344 345 346 347 348

err_dfs_clean:
	nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
	nfp_net_clean(nn);
	return err;
J
Jakub Kicinski 已提交
349 350 351
}

static int
J
Jakub Kicinski 已提交
352
nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
353
		       void __iomem *qc_bar, int stride)
J
Jakub Kicinski 已提交
354 355 356 357 358
{
	struct nfp_net *nn;
	unsigned int i;
	int err;

J
Jakub Kicinski 已提交
359
	for (i = 0; i < pf->max_data_vnics; i++) {
360
		nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, qc_bar,
361
					   stride, i);
362 363 364
		if (IS_ERR(nn)) {
			err = PTR_ERR(nn);
			goto err_free_prev;
J
Jakub Kicinski 已提交
365 366 367
		}

		ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
368

J
Jakub Kicinski 已提交
369 370
		/* Kill the vNIC if app init marked it as invalid */
		if (nn->port && nn->port->type == NFP_PORT_INVALID) {
371 372 373
			nfp_net_pf_free_vnic(pf, nn);
			continue;
		}
J
Jakub Kicinski 已提交
374 375
	}

J
Jakub Kicinski 已提交
376
	if (list_empty(&pf->vnics))
377 378
		return -ENODEV;

J
Jakub Kicinski 已提交
379 380 381
	return 0;

err_free_prev:
J
Jakub Kicinski 已提交
382
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
383 384 385
	return err;
}

386 387
static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
388 389
	if (nn->port)
		nfp_devlink_port_unregister(nn->port);
390 391
	nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
	nfp_net_clean(nn);
392
	nfp_app_vnic_clean(pf->app, nn);
393 394
}

395
static int nfp_net_pf_alloc_irqs(struct nfp_pf *pf)
J
Jakub Kicinski 已提交
396
{
397
	unsigned int wanted_irqs, num_irqs, vnics_left, irqs_left;
J
Jakub Kicinski 已提交
398 399 400 401
	struct nfp_net *nn;

	/* Get MSI-X vectors */
	wanted_irqs = 0;
J
Jakub Kicinski 已提交
402
	list_for_each_entry(nn, &pf->vnics, vnic_list)
403
		wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs;
J
Jakub Kicinski 已提交
404 405
	pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries),
				  GFP_KERNEL);
406 407
	if (!pf->irq_entries)
		return -ENOMEM;
J
Jakub Kicinski 已提交
408 409

	num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries,
J
Jakub Kicinski 已提交
410
				      NFP_NET_MIN_VNIC_IRQS * pf->num_vnics,
J
Jakub Kicinski 已提交
411 412
				      wanted_irqs);
	if (!num_irqs) {
413 414 415
		nfp_warn(pf->cpp, "Unable to allocate MSI-X vectors\n");
		kfree(pf->irq_entries);
		return -ENOMEM;
J
Jakub Kicinski 已提交
416 417
	}

J
Jakub Kicinski 已提交
418
	/* Distribute IRQs to vNICs */
J
Jakub Kicinski 已提交
419
	irqs_left = num_irqs;
J
Jakub Kicinski 已提交
420 421
	vnics_left = pf->num_vnics;
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
J
Jakub Kicinski 已提交
422 423
		unsigned int n;

424 425
		n = min(NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs,
			DIV_ROUND_UP(irqs_left, vnics_left));
J
Jakub Kicinski 已提交
426 427 428
		nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left],
				    n);
		irqs_left -= n;
J
Jakub Kicinski 已提交
429
		vnics_left--;
J
Jakub Kicinski 已提交
430 431
	}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
	return 0;
}

static void nfp_net_pf_free_irqs(struct nfp_pf *pf)
{
	nfp_net_irqs_disable(pf->pdev);
	kfree(pf->irq_entries);
}

static int nfp_net_pf_init_vnics(struct nfp_pf *pf)
{
	struct nfp_net *nn;
	unsigned int id;
	int err;

J
Jakub Kicinski 已提交
447
	/* Finish vNIC init and register */
J
Jakub Kicinski 已提交
448
	id = 0;
J
Jakub Kicinski 已提交
449
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
450 451
		if (!nfp_net_is_data_vnic(nn))
			continue;
J
Jakub Kicinski 已提交
452
		err = nfp_net_pf_init_vnic(pf, nn, id);
J
Jakub Kicinski 已提交
453 454 455 456 457 458 459 460 461
		if (err)
			goto err_prev_deinit;

		id++;
	}

	return 0;

err_prev_deinit:
462
	list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list)
463 464
		if (nfp_net_is_data_vnic(nn))
			nfp_net_pf_clean_vnic(pf, nn);
J
Jakub Kicinski 已提交
465 466 467
	return err;
}

468 469
static int
nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
470
{
471
	u8 __iomem *ctrl_bar;
J
Jakub Kicinski 已提交
472 473 474 475 476 477 478 479 480 481
	int err;

	pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf));
	if (IS_ERR(pf->app))
		return PTR_ERR(pf->app);

	err = nfp_app_init(pf->app);
	if (err)
		goto err_free;

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	if (!nfp_app_needs_ctrl_vnic(pf->app))
		return 0;

	ctrl_bar = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%u_net_ctrl_bar",
					NFP_PF_CSR_SLICE_SIZE,
					&pf->ctrl_vnic_bar);
	if (IS_ERR(ctrl_bar)) {
		err = PTR_ERR(ctrl_bar);
		goto err_free;
	}

	pf->ctrl_vnic =	nfp_net_pf_alloc_vnic(pf, false, ctrl_bar, qc_bar,
					      stride, 0);
	if (IS_ERR(pf->ctrl_vnic)) {
		err = PTR_ERR(pf->ctrl_vnic);
		goto err_unmap;
	}

J
Jakub Kicinski 已提交
500
	return 0;
501

502 503
err_unmap:
	nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
J
Jakub Kicinski 已提交
504 505 506
err_free:
	nfp_app_free(pf->app);
	return err;
507 508 509 510
}

static void nfp_net_pf_app_clean(struct nfp_pf *pf)
{
511 512 513 514
	if (pf->ctrl_vnic) {
		nfp_net_pf_free_vnic(pf, pf->ctrl_vnic);
		nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
	}
515
	nfp_app_free(pf->app);
S
Simon Horman 已提交
516
	pf->app = NULL;
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
static int nfp_net_pf_app_start_ctrl(struct nfp_pf *pf)
{
	int err;

	if (!pf->ctrl_vnic)
		return 0;
	err = nfp_net_pf_init_vnic(pf, pf->ctrl_vnic, 0);
	if (err)
		return err;

	err = nfp_ctrl_open(pf->ctrl_vnic);
	if (err)
		goto err_clean_ctrl;

	return 0;

err_clean_ctrl:
	nfp_net_pf_clean_vnic(pf, pf->ctrl_vnic);
	return err;
}

static void nfp_net_pf_app_stop_ctrl(struct nfp_pf *pf)
{
	if (!pf->ctrl_vnic)
		return;
	nfp_ctrl_close(pf->ctrl_vnic);
	nfp_net_pf_clean_vnic(pf, pf->ctrl_vnic);
}

static int nfp_net_pf_app_start(struct nfp_pf *pf)
{
	int err;

	err = nfp_net_pf_app_start_ctrl(pf);
	if (err)
		return err;

	err = nfp_app_start(pf->app, pf->ctrl_vnic);
	if (err)
		goto err_ctrl_stop;

	return 0;

err_ctrl_stop:
	nfp_net_pf_app_stop_ctrl(pf);
	return err;
}

static void nfp_net_pf_app_stop(struct nfp_pf *pf)
{
	nfp_app_stop(pf->app);
	nfp_net_pf_app_stop_ctrl(pf);
}

J
Jakub Kicinski 已提交
573 574
static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
{
575 576
	nfp_net_pf_app_stop(pf);
	/* stop app first, to avoid double free of ctrl vNIC's ddir */
J
Jakub Kicinski 已提交
577 578
	nfp_net_debugfs_dir_clean(&pf->ddir);

579
	nfp_net_pf_free_irqs(pf);
J
Jakub Kicinski 已提交
580

581 582
	nfp_net_pf_app_clean(pf);

583
	nfp_cpp_area_release_free(pf->qc_area);
J
Jakub Kicinski 已提交
584
	nfp_cpp_area_release_free(pf->data_vnic_bar);
J
Jakub Kicinski 已提交
585 586
}

J
Jakub Kicinski 已提交
587 588 589 590 591 592 593 594 595 596
static int
nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
			struct nfp_eth_table *eth_table)
{
	struct nfp_eth_table_port *eth_port;

	ASSERT_RTNL();

	eth_port = nfp_net_find_port(eth_table, port->eth_id);
	if (!eth_port) {
597
		set_bit(NFP_PORT_CHANGED, &port->flags);
J
Jakub Kicinski 已提交
598 599 600 601 602 603 604 605 606 607 608 609 610 611
		nfp_warn(cpp, "Warning: port #%d not present after reconfig\n",
			 port->eth_id);
		return -EIO;
	}
	if (eth_port->override_changed) {
		nfp_warn(cpp, "Port #%d config changed, unregistering. Reboot required before port will be operational again.\n", port->eth_id);
		port->type = NFP_PORT_INVALID;
	}

	memcpy(port->eth_port, eth_port, sizeof(*eth_port));

	return 0;
}

612
int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
J
Jakub Kicinski 已提交
613
{
614
	struct nfp_eth_table *eth_table;
J
Jakub Kicinski 已提交
615
	struct nfp_net *nn, *next;
616
	struct nfp_port *port;
J
Jakub Kicinski 已提交
617

618
	lockdep_assert_held(&pf->lock);
J
Jakub Kicinski 已提交
619 620

	/* Check for nfp_net_pci_remove() racing against us */
J
Jakub Kicinski 已提交
621
	if (list_empty(&pf->vnics))
622
		return 0;
J
Jakub Kicinski 已提交
623

624 625
	/* Update state of all ports */
	rtnl_lock();
626 627
	list_for_each_entry(port, &pf->ports, port_list)
		clear_bit(NFP_PORT_CHANGED, &port->flags);
628 629 630

	eth_table = nfp_eth_read_ports(pf->cpp);
	if (!eth_table) {
631 632 633
		list_for_each_entry(port, &pf->ports, port_list)
			if (__nfp_port_get_eth_port(port))
				set_bit(NFP_PORT_CHANGED, &port->flags);
634
		rtnl_unlock();
635
		nfp_err(pf->cpp, "Error refreshing port config!\n");
636
		return -EIO;
637 638
	}

639 640 641
	list_for_each_entry(port, &pf->ports, port_list)
		if (__nfp_port_get_eth_port(port))
			nfp_net_eth_port_update(pf->cpp, port, eth_table);
642 643
	rtnl_unlock();

J
Jakub Kicinski 已提交
644
	kfree(eth_table);
645

646
	/* Shoot off the ports which became invalid */
J
Jakub Kicinski 已提交
647
	list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) {
J
Jakub Kicinski 已提交
648
		if (!nn->port || nn->port->type != NFP_PORT_INVALID)
J
Jakub Kicinski 已提交
649 650
			continue;

651
		nfp_net_pf_clean_vnic(pf, nn);
652
		nfp_net_pf_free_vnic(pf, nn);
J
Jakub Kicinski 已提交
653 654
	}

J
Jakub Kicinski 已提交
655
	if (list_empty(&pf->vnics))
J
Jakub Kicinski 已提交
656
		nfp_net_pci_remove_finish(pf);
657 658 659 660 661 662 663 664 665 666 667

	return 0;
}

static void nfp_net_refresh_vnics(struct work_struct *work)
{
	struct nfp_pf *pf = container_of(work, struct nfp_pf,
					 port_refresh_work);

	mutex_lock(&pf->lock);
	nfp_net_refresh_port_table_sync(pf);
J
Jakub Kicinski 已提交
668
	mutex_unlock(&pf->lock);
J
Jakub Kicinski 已提交
669 670
}

J
Jakub Kicinski 已提交
671
void nfp_net_refresh_port_table(struct nfp_port *port)
J
Jakub Kicinski 已提交
672
{
J
Jakub Kicinski 已提交
673
	struct nfp_pf *pf = port->app->pf;
J
Jakub Kicinski 已提交
674

675 676
	set_bit(NFP_PORT_CHANGED, &port->flags);

677 678
	schedule_work(&pf->port_refresh_work);
}
J
Jakub Kicinski 已提交
679

J
Jakub Kicinski 已提交
680
int nfp_net_refresh_eth_port(struct nfp_port *port)
681
{
J
Jakub Kicinski 已提交
682
	struct nfp_cpp *cpp = port->app->cpp;
683
	struct nfp_eth_table *eth_table;
J
Jakub Kicinski 已提交
684
	int ret;
J
Jakub Kicinski 已提交
685

686 687
	clear_bit(NFP_PORT_CHANGED, &port->flags);

J
Jakub Kicinski 已提交
688
	eth_table = nfp_eth_read_ports(cpp);
689
	if (!eth_table) {
690
		set_bit(NFP_PORT_CHANGED, &port->flags);
J
Jakub Kicinski 已提交
691
		nfp_err(cpp, "Error refreshing port state table!\n");
692 693
		return -EIO;
	}
J
Jakub Kicinski 已提交
694

J
Jakub Kicinski 已提交
695
	ret = nfp_net_eth_port_update(cpp, port, eth_table);
J
Jakub Kicinski 已提交
696

697
	kfree(eth_table);
J
Jakub Kicinski 已提交
698

J
Jakub Kicinski 已提交
699
	return ret;
J
Jakub Kicinski 已提交
700 701
}

J
Jakub Kicinski 已提交
702 703 704 705 706 707
/*
 * PCI device functions
 */
int nfp_net_pci_probe(struct nfp_pf *pf)
{
	struct nfp_net_fw_version fw_ver;
708 709
	u8 __iomem *ctrl_bar, *qc_bar;
	u32 ctrl_bar_sz;
J
Jakub Kicinski 已提交
710 711 712
	int stride;
	int err;

J
Jakub Kicinski 已提交
713
	INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics);
714

J
Jakub Kicinski 已提交
715 716 717 718 719 720
	/* Verify that the board has completed initialization */
	if (!nfp_is_ready(pf->cpp)) {
		nfp_err(pf->cpp, "NFP is not ready for NIC operation.\n");
		return -EINVAL;
	}

J
Jakub Kicinski 已提交
721 722
	mutex_lock(&pf->lock);
	pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
723 724 725 726
	if ((int)pf->max_data_vnics < 0) {
		err = pf->max_data_vnics;
		goto err_unlock;
	}
J
Jakub Kicinski 已提交
727

728 729 730 731 732 733 734
	ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE;
	ctrl_bar = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0",
					ctrl_bar_sz, &pf->data_vnic_bar);
	if (IS_ERR(ctrl_bar)) {
		err = PTR_ERR(ctrl_bar);
		if (!pf->fw_loaded && err == -ENOENT)
			err = -EPROBE_DEFER;
735 736
		goto err_unlock;
	}
J
Jakub Kicinski 已提交
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751

	nfp_net_get_fw_version(&fw_ver, ctrl_bar);
	if (fw_ver.resv || fw_ver.class != NFP_NET_CFG_VERSION_CLASS_GENERIC) {
		nfp_err(pf->cpp, "Unknown Firmware ABI %d.%d.%d.%d\n",
			fw_ver.resv, fw_ver.class, fw_ver.major, fw_ver.minor);
		err = -EINVAL;
		goto err_ctrl_unmap;
	}

	/* Determine stride */
	if (nfp_net_fw_ver_eq(&fw_ver, 0, 0, 0, 1)) {
		stride = 2;
		nfp_warn(pf->cpp, "OBSOLETE Firmware detected - VF isolation not available\n");
	} else {
		switch (fw_ver.major) {
752
		case 1 ... 5:
J
Jakub Kicinski 已提交
753 754 755 756 757 758 759 760 761 762 763
			stride = 4;
			break;
		default:
			nfp_err(pf->cpp, "Unsupported Firmware ABI %d.%d.%d.%d\n",
				fw_ver.resv, fw_ver.class,
				fw_ver.major, fw_ver.minor);
			err = -EINVAL;
			goto err_ctrl_unmap;
		}
	}

764 765 766 767 768 769 770
	/* Map queues */
	qc_bar = nfp_net_map_area(pf->cpp, "net.qc", 0, 0,
				  NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ,
				  &pf->qc_area);
	if (IS_ERR(qc_bar)) {
		nfp_err(pf->cpp, "Failed to map Queue Controller area.\n");
		err = PTR_ERR(qc_bar);
J
Jakub Kicinski 已提交
771 772 773
		goto err_ctrl_unmap;
	}

774
	err = nfp_net_pf_app_init(pf, qc_bar, stride);
775
	if (err)
776
		goto err_unmap_qc;
777

J
Jakub Kicinski 已提交
778 779
	pf->ddir = nfp_net_debugfs_device_add(pf->pdev);

780 781
	/* Allocate the vnics and do basic init */
	err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride);
J
Jakub Kicinski 已提交
782 783 784
	if (err)
		goto err_clean_ddir;

785 786 787 788
	err = nfp_net_pf_alloc_irqs(pf);
	if (err)
		goto err_free_vnics;

789
	err = nfp_net_pf_app_start(pf);
790 791 792
	if (err)
		goto err_free_irqs;

793 794 795 796
	err = nfp_net_pf_init_vnics(pf);
	if (err)
		goto err_stop_app;

J
Jakub Kicinski 已提交
797
	mutex_unlock(&pf->lock);
798

J
Jakub Kicinski 已提交
799 800
	return 0;

801 802
err_stop_app:
	nfp_net_pf_app_stop(pf);
803 804 805 806
err_free_irqs:
	nfp_net_pf_free_irqs(pf);
err_free_vnics:
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
807 808
err_clean_ddir:
	nfp_net_debugfs_dir_clean(&pf->ddir);
809
	nfp_net_pf_app_clean(pf);
810 811
err_unmap_qc:
	nfp_cpp_area_release_free(pf->qc_area);
J
Jakub Kicinski 已提交
812
err_ctrl_unmap:
J
Jakub Kicinski 已提交
813
	nfp_cpp_area_release_free(pf->data_vnic_bar);
814
err_unlock:
J
Jakub Kicinski 已提交
815
	mutex_unlock(&pf->lock);
816
	cancel_work_sync(&pf->port_refresh_work);
J
Jakub Kicinski 已提交
817 818 819 820 821 822 823
	return err;
}

void nfp_net_pci_remove(struct nfp_pf *pf)
{
	struct nfp_net *nn;

J
Jakub Kicinski 已提交
824 825
	mutex_lock(&pf->lock);
	if (list_empty(&pf->vnics))
826 827
		goto out;

828
	list_for_each_entry(nn, &pf->vnics, vnic_list)
829 830
		if (nfp_net_is_data_vnic(nn))
			nfp_net_pf_clean_vnic(pf, nn);
J
Jakub Kicinski 已提交
831

J
Jakub Kicinski 已提交
832
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
833

J
Jakub Kicinski 已提交
834
	nfp_net_pci_remove_finish(pf);
835
out:
J
Jakub Kicinski 已提交
836
	mutex_unlock(&pf->lock);
J
Jakub Kicinski 已提交
837 838

	cancel_work_sync(&pf->port_refresh_work);
J
Jakub Kicinski 已提交
839
}