nfp_net_main.c 19.5 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 205

	val = nfp_rtsym_read_le(pf->cpp, name, &err);
	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);
}

J
Jakub Kicinski 已提交
226 227 228 229 230 231 232 233 234
static unsigned int
nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar,
		     unsigned int stride, u32 start_off, u32 num_off)
{
	unsigned int i, min_qc, max_qc;

	min_qc = readl(ctrl_bar + start_off);
	max_qc = min_qc;

J
Jakub Kicinski 已提交
235
	for (i = 0; i < pf->max_data_vnics; i++) {
J
Jakub Kicinski 已提交
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
		/* To make our lives simpler only accept configuration where
		 * queues are allocated to PFs in order (queues of PFn all have
		 * indexes lower than PFn+1).
		 */
		if (max_qc > readl(ctrl_bar + start_off))
			return 0;

		max_qc = readl(ctrl_bar + start_off);
		max_qc += readl(ctrl_bar + num_off) * stride;
		ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
	}

	return max_qc - min_qc;
}

251 252 253
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 已提交
254
{
255
	const struct nfp_rtsym *sym;
J
Jakub Kicinski 已提交
256
	char pf_symbol[256];
257
	u8 __iomem *mem;
J
Jakub Kicinski 已提交
258

259
	snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt,
260
		 nfp_cppcore_pcie_unit(pf->cpp));
J
Jakub Kicinski 已提交
261

262 263 264 265
	sym = nfp_rtsym_lookup(pf->cpp, pf_symbol);
	if (!sym) {
		nfp_err(pf->cpp, "Failed to find PF symbol %s\n", pf_symbol);
		return (u8 __iomem *)ERR_PTR(-ENOENT);
J
Jakub Kicinski 已提交
266 267
	}

268 269 270
	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 已提交
271 272
	}

273 274 275 276 277 278
	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 已提交
279 280
	}

281
	return mem;
J
Jakub Kicinski 已提交
282 283
}

284 285
static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
J
Jakub Kicinski 已提交
286
	nfp_port_free(nn->port);
287 288 289 290 291
	list_del(&nn->vnic_list);
	pf->num_vnics--;
	nfp_net_free(nn);
}

J
Jakub Kicinski 已提交
292
static void nfp_net_pf_free_vnics(struct nfp_pf *pf)
J
Jakub Kicinski 已提交
293 294 295
{
	struct nfp_net *nn;

J
Jakub Kicinski 已提交
296 297
	while (!list_empty(&pf->vnics)) {
		nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list);
298
		nfp_net_pf_free_vnic(pf, nn);
J
Jakub Kicinski 已提交
299 300 301 302
	}
}

static struct nfp_net *
303 304
nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev,
		      void __iomem *ctrl_bar,
J
Jakub Kicinski 已提交
305 306
		      void __iomem *tx_bar, void __iomem *rx_bar,
		      int stride, struct nfp_net_fw_version *fw_ver,
307
		      unsigned int eth_id)
J
Jakub Kicinski 已提交
308 309 310
{
	u32 n_tx_rings, n_rx_rings;
	struct nfp_net *nn;
J
Jakub Kicinski 已提交
311
	int err;
J
Jakub Kicinski 已提交
312 313 314 315

	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 已提交
316
	/* Allocate and initialise the vNIC */
317
	nn = nfp_net_alloc(pf->pdev, needs_netdev, n_tx_rings, n_rx_rings);
J
Jakub Kicinski 已提交
318 319 320
	if (IS_ERR(nn))
		return nn;

321
	nn->app = pf->app;
J
Jakub Kicinski 已提交
322
	nn->fw_ver = *fw_ver;
323
	nn->dp.ctrl_bar = ctrl_bar;
J
Jakub Kicinski 已提交
324 325
	nn->tx_bar = tx_bar;
	nn->rx_bar = rx_bar;
326
	nn->dp.is_vf = 0;
J
Jakub Kicinski 已提交
327 328
	nn->stride_rx = stride;
	nn->stride_tx = stride;
J
Jakub Kicinski 已提交
329

J
Jakub Kicinski 已提交
330 331 332 333
	err = nfp_app_vnic_init(pf->app, nn, eth_id);
	if (err) {
		nfp_net_free(nn);
		return ERR_PTR(err);
J
Jakub Kicinski 已提交
334
	}
335 336 337

	pf->num_vnics++;
	list_add_tail(&nn->vnic_list, &pf->vnics);
J
Jakub Kicinski 已提交
338 339 340 341 342

	return nn;
}

static int
J
Jakub Kicinski 已提交
343
nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id)
J
Jakub Kicinski 已提交
344 345 346 347 348 349 350 351 352
{
	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;

353
	err = nfp_net_init(nn);
J
Jakub Kicinski 已提交
354 355 356
	if (err)
		return err;

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

359 360 361 362 363 364
	if (nn->port) {
		err = nfp_devlink_port_register(pf->app, nn->port);
		if (err)
			goto err_dfs_clean;
	}

J
Jakub Kicinski 已提交
365 366 367
	nfp_net_info(nn);

	return 0;
368 369 370 371 372

err_dfs_clean:
	nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
	nfp_net_clean(nn);
	return err;
J
Jakub Kicinski 已提交
373 374 375
}

static int
J
Jakub Kicinski 已提交
376 377 378
nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
		       void __iomem *tx_bar, void __iomem *rx_bar,
		       int stride, struct nfp_net_fw_version *fw_ver)
J
Jakub Kicinski 已提交
379 380 381 382 383 384 385 386 387
{
	u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base;
	struct nfp_net *nn;
	unsigned int i;
	int err;

	prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
	prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);

J
Jakub Kicinski 已提交
388
	for (i = 0; i < pf->max_data_vnics; i++) {
J
Jakub Kicinski 已提交
389 390 391 392 393 394 395
		tgt_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
		tgt_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
		tx_bar += (tgt_tx_base - prev_tx_base) * NFP_QCP_QUEUE_ADDR_SZ;
		rx_bar += (tgt_rx_base - prev_rx_base) * NFP_QCP_QUEUE_ADDR_SZ;
		prev_tx_base = tgt_tx_base;
		prev_rx_base = tgt_rx_base;

396
		nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, tx_bar, rx_bar,
397 398 399 400
					   stride, fw_ver, i);
		if (IS_ERR(nn)) {
			err = PTR_ERR(nn);
			goto err_free_prev;
J
Jakub Kicinski 已提交
401 402 403
		}

		ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
404

J
Jakub Kicinski 已提交
405 406
		/* Kill the vNIC if app init marked it as invalid */
		if (nn->port && nn->port->type == NFP_PORT_INVALID) {
407 408 409
			nfp_net_pf_free_vnic(pf, nn);
			continue;
		}
J
Jakub Kicinski 已提交
410 411
	}

J
Jakub Kicinski 已提交
412
	if (list_empty(&pf->vnics))
413 414
		return -ENODEV;

J
Jakub Kicinski 已提交
415 416 417
	return 0;

err_free_prev:
J
Jakub Kicinski 已提交
418
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
419 420 421
	return err;
}

422 423
static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
424 425
	if (nn->port)
		nfp_devlink_port_unregister(nn->port);
426 427
	nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
	nfp_net_clean(nn);
428
	nfp_app_vnic_clean(pf->app, nn);
429 430
}

J
Jakub Kicinski 已提交
431
static int
J
Jakub Kicinski 已提交
432 433 434 435
nfp_net_pf_spawn_vnics(struct nfp_pf *pf,
		       void __iomem *ctrl_bar, void __iomem *tx_bar,
		       void __iomem *rx_bar, int stride,
		       struct nfp_net_fw_version *fw_ver)
J
Jakub Kicinski 已提交
436
{
J
Jakub Kicinski 已提交
437
	unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left;
J
Jakub Kicinski 已提交
438 439 440
	struct nfp_net *nn;
	int err;

J
Jakub Kicinski 已提交
441 442 443
	/* Allocate the vnics and do basic init */
	err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, tx_bar, rx_bar,
				     stride, fw_ver);
J
Jakub Kicinski 已提交
444 445 446 447 448
	if (err)
		return err;

	/* Get MSI-X vectors */
	wanted_irqs = 0;
J
Jakub Kicinski 已提交
449
	list_for_each_entry(nn, &pf->vnics, vnic_list)
450
		wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs;
J
Jakub Kicinski 已提交
451 452 453 454 455 456 457 458
	pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries),
				  GFP_KERNEL);
	if (!pf->irq_entries) {
		err = -ENOMEM;
		goto err_nn_free;
	}

	num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries,
J
Jakub Kicinski 已提交
459
				      NFP_NET_MIN_VNIC_IRQS * pf->num_vnics,
J
Jakub Kicinski 已提交
460 461 462 463 464 465 466
				      wanted_irqs);
	if (!num_irqs) {
		nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n");
		err = -ENOMEM;
		goto err_vec_free;
	}

J
Jakub Kicinski 已提交
467
	/* Distribute IRQs to vNICs */
J
Jakub Kicinski 已提交
468
	irqs_left = num_irqs;
J
Jakub Kicinski 已提交
469 470
	vnics_left = pf->num_vnics;
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
J
Jakub Kicinski 已提交
471 472
		unsigned int n;

J
Jakub Kicinski 已提交
473
		n = DIV_ROUND_UP(irqs_left, vnics_left);
J
Jakub Kicinski 已提交
474 475 476
		nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left],
				    n);
		irqs_left -= n;
J
Jakub Kicinski 已提交
477
		vnics_left--;
J
Jakub Kicinski 已提交
478 479
	}

J
Jakub Kicinski 已提交
480
	/* Finish vNIC init and register */
J
Jakub Kicinski 已提交
481
	id = 0;
J
Jakub Kicinski 已提交
482 483
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
		err = nfp_net_pf_init_vnic(pf, nn, id);
J
Jakub Kicinski 已提交
484 485 486 487 488 489 490 491 492
		if (err)
			goto err_prev_deinit;

		id++;
	}

	return 0;

err_prev_deinit:
493 494
	list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list)
		nfp_net_pf_clean_vnic(pf, nn);
J
Jakub Kicinski 已提交
495 496 497 498
	nfp_net_irqs_disable(pf->pdev);
err_vec_free:
	kfree(pf->irq_entries);
err_nn_free:
J
Jakub Kicinski 已提交
499
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
500 501 502
	return err;
}

503 504
static int nfp_net_pf_app_init(struct nfp_pf *pf)
{
J
Jakub Kicinski 已提交
505 506 507 508 509 510 511 512 513 514 515
	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;

	return 0;
516

J
Jakub Kicinski 已提交
517 518 519
err_free:
	nfp_app_free(pf->app);
	return err;
520 521 522 523 524
}

static void nfp_net_pf_app_clean(struct nfp_pf *pf)
{
	nfp_app_free(pf->app);
S
Simon Horman 已提交
525
	pf->app = NULL;
526 527
}

J
Jakub Kicinski 已提交
528 529 530 531 532 533 534
static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
{
	nfp_net_debugfs_dir_clean(&pf->ddir);

	nfp_net_irqs_disable(pf->pdev);
	kfree(pf->irq_entries);

535 536
	nfp_net_pf_app_clean(pf);

J
Jakub Kicinski 已提交
537 538
	nfp_cpp_area_release_free(pf->rx_area);
	nfp_cpp_area_release_free(pf->tx_area);
J
Jakub Kicinski 已提交
539
	nfp_cpp_area_release_free(pf->data_vnic_bar);
J
Jakub Kicinski 已提交
540 541
}

J
Jakub Kicinski 已提交
542 543 544 545 546 547 548 549 550 551
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) {
552
		set_bit(NFP_PORT_CHANGED, &port->flags);
J
Jakub Kicinski 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566
		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;
}

567
int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
J
Jakub Kicinski 已提交
568
{
569
	struct nfp_eth_table *eth_table;
J
Jakub Kicinski 已提交
570
	struct nfp_net *nn, *next;
571
	struct nfp_port *port;
J
Jakub Kicinski 已提交
572

573
	lockdep_assert_held(&pf->lock);
J
Jakub Kicinski 已提交
574 575

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

579 580
	/* Update state of all ports */
	rtnl_lock();
581 582
	list_for_each_entry(port, &pf->ports, port_list)
		clear_bit(NFP_PORT_CHANGED, &port->flags);
583 584 585

	eth_table = nfp_eth_read_ports(pf->cpp);
	if (!eth_table) {
586 587 588
		list_for_each_entry(port, &pf->ports, port_list)
			if (__nfp_port_get_eth_port(port))
				set_bit(NFP_PORT_CHANGED, &port->flags);
589
		rtnl_unlock();
590
		nfp_err(pf->cpp, "Error refreshing port config!\n");
591
		return -EIO;
592 593
	}

594 595 596
	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);
597 598
	rtnl_unlock();

J
Jakub Kicinski 已提交
599
	kfree(eth_table);
600

601
	/* Shoot off the ports which became invalid */
J
Jakub Kicinski 已提交
602
	list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) {
J
Jakub Kicinski 已提交
603
		if (!nn->port || nn->port->type != NFP_PORT_INVALID)
J
Jakub Kicinski 已提交
604 605
			continue;

606
		nfp_net_pf_clean_vnic(pf, nn);
607
		nfp_net_pf_free_vnic(pf, nn);
J
Jakub Kicinski 已提交
608 609
	}

J
Jakub Kicinski 已提交
610
	if (list_empty(&pf->vnics))
J
Jakub Kicinski 已提交
611
		nfp_net_pci_remove_finish(pf);
612 613 614 615 616 617 618 619 620 621 622

	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 已提交
623
	mutex_unlock(&pf->lock);
J
Jakub Kicinski 已提交
624 625
}

J
Jakub Kicinski 已提交
626
void nfp_net_refresh_port_table(struct nfp_port *port)
J
Jakub Kicinski 已提交
627
{
J
Jakub Kicinski 已提交
628
	struct nfp_pf *pf = port->app->pf;
J
Jakub Kicinski 已提交
629

630 631
	set_bit(NFP_PORT_CHANGED, &port->flags);

632 633
	schedule_work(&pf->port_refresh_work);
}
J
Jakub Kicinski 已提交
634

J
Jakub Kicinski 已提交
635
int nfp_net_refresh_eth_port(struct nfp_port *port)
636
{
J
Jakub Kicinski 已提交
637
	struct nfp_cpp *cpp = port->app->cpp;
638
	struct nfp_eth_table *eth_table;
J
Jakub Kicinski 已提交
639
	int ret;
J
Jakub Kicinski 已提交
640

641 642
	clear_bit(NFP_PORT_CHANGED, &port->flags);

J
Jakub Kicinski 已提交
643
	eth_table = nfp_eth_read_ports(cpp);
644
	if (!eth_table) {
645
		set_bit(NFP_PORT_CHANGED, &port->flags);
J
Jakub Kicinski 已提交
646
		nfp_err(cpp, "Error refreshing port state table!\n");
647 648
		return -EIO;
	}
J
Jakub Kicinski 已提交
649

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

652
	kfree(eth_table);
J
Jakub Kicinski 已提交
653

J
Jakub Kicinski 已提交
654
	return ret;
J
Jakub Kicinski 已提交
655 656
}

J
Jakub Kicinski 已提交
657 658 659 660 661
/*
 * PCI device functions
 */
int nfp_net_pci_probe(struct nfp_pf *pf)
{
662
	u32 ctrl_bar_sz, tx_area_sz, rx_area_sz;
J
Jakub Kicinski 已提交
663 664 665 666 667 668 669
	u8 __iomem *ctrl_bar, *tx_bar, *rx_bar;
	u32 total_tx_qcs, total_rx_qcs;
	struct nfp_net_fw_version fw_ver;
	u32 start_q;
	int stride;
	int err;

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

J
Jakub Kicinski 已提交
672 673 674 675 676 677
	/* 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 已提交
678 679
	mutex_lock(&pf->lock);
	pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
680 681 682 683
	if ((int)pf->max_data_vnics < 0) {
		err = pf->max_data_vnics;
		goto err_unlock;
	}
J
Jakub Kicinski 已提交
684

685 686 687 688 689 690 691
	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;
692 693
		goto err_unlock;
	}
J
Jakub Kicinski 已提交
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759

	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) {
		case 1 ... 4:
			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;
		}
	}

	/* Find how many QC structs need to be mapped */
	total_tx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride,
					    NFP_NET_CFG_START_TXQ,
					    NFP_NET_CFG_MAX_TXRINGS);
	total_rx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride,
					    NFP_NET_CFG_START_RXQ,
					    NFP_NET_CFG_MAX_RXRINGS);
	if (!total_tx_qcs || !total_rx_qcs) {
		nfp_err(pf->cpp, "Invalid PF QC configuration [%d,%d]\n",
			total_tx_qcs, total_rx_qcs);
		err = -EINVAL;
		goto err_ctrl_unmap;
	}

	tx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_tx_qcs;
	rx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_rx_qcs;

	/* Map TX queues */
	start_q = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
	tx_bar = nfp_net_map_area(pf->cpp, "net.tx", 0, 0,
				  NFP_PCIE_QUEUE(start_q),
				  tx_area_sz, &pf->tx_area);
	if (IS_ERR(tx_bar)) {
		nfp_err(pf->cpp, "Failed to map TX area.\n");
		err = PTR_ERR(tx_bar);
		goto err_ctrl_unmap;
	}

	/* Map RX queues */
	start_q = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
	rx_bar = nfp_net_map_area(pf->cpp, "net.rx", 0, 0,
				  NFP_PCIE_QUEUE(start_q),
				  rx_area_sz, &pf->rx_area);
	if (IS_ERR(rx_bar)) {
		nfp_err(pf->cpp, "Failed to map RX area.\n");
		err = PTR_ERR(rx_bar);
		goto err_unmap_tx;
	}

760 761 762 763
	err = nfp_net_pf_app_init(pf);
	if (err)
		goto err_unmap_rx;

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

J
Jakub Kicinski 已提交
766 767
	err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar,
				     stride, &fw_ver);
J
Jakub Kicinski 已提交
768 769 770
	if (err)
		goto err_clean_ddir;

J
Jakub Kicinski 已提交
771
	mutex_unlock(&pf->lock);
772

J
Jakub Kicinski 已提交
773 774 775 776
	return 0;

err_clean_ddir:
	nfp_net_debugfs_dir_clean(&pf->ddir);
777 778
	nfp_net_pf_app_clean(pf);
err_unmap_rx:
J
Jakub Kicinski 已提交
779 780 781 782
	nfp_cpp_area_release_free(pf->rx_area);
err_unmap_tx:
	nfp_cpp_area_release_free(pf->tx_area);
err_ctrl_unmap:
J
Jakub Kicinski 已提交
783
	nfp_cpp_area_release_free(pf->data_vnic_bar);
784
err_unlock:
J
Jakub Kicinski 已提交
785
	mutex_unlock(&pf->lock);
J
Jakub Kicinski 已提交
786 787 788 789 790 791 792
	return err;
}

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

J
Jakub Kicinski 已提交
793 794
	mutex_lock(&pf->lock);
	if (list_empty(&pf->vnics))
795 796
		goto out;

797 798
	list_for_each_entry(nn, &pf->vnics, vnic_list)
		nfp_net_pf_clean_vnic(pf, nn);
J
Jakub Kicinski 已提交
799

J
Jakub Kicinski 已提交
800
	nfp_net_pf_free_vnics(pf);
J
Jakub Kicinski 已提交
801

J
Jakub Kicinski 已提交
802
	nfp_net_pci_remove_finish(pf);
803
out:
J
Jakub Kicinski 已提交
804
	mutex_unlock(&pf->lock);
J
Jakub Kicinski 已提交
805 806

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