Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02082701 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: create control vNICs and wire up rx/tx



When driver encounters an nfp_app which has a control message handler
defined, allocate a control vNIC.  This control channel will be used
to exchange data with the application FW such as flow table programming,
statistics and global datapath control.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2c7e41c0
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
 * SOFTWARE.
 */

#include <linux/skbuff.h>
#include <linux/slab.h>

#include "nfpcore/nfp_cpp.h"
@@ -42,6 +43,23 @@ static const struct nfp_app_type *apps[] = {
	&app_bpf,
};

struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size)
{
	struct sk_buff *skb;

	if (nfp_app_ctrl_has_meta(app))
		size += 8;

	skb = alloc_skb(size, GFP_ATOMIC);
	if (!skb)
		return NULL;

	if (nfp_app_ctrl_has_meta(app))
		skb_reserve(skb, 8);

	return skb;
}

struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id)
{
	struct nfp_app *app;
+44 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
struct bpf_prog;
struct net_device;
struct pci_dev;
struct sk_buff;
struct tc_to_netdev;
struct sk_buff;
struct nfp_app;
@@ -63,6 +64,9 @@ extern const struct nfp_app_type app_bpf;
 * @extra_cap:	extra capabilities string
 * @vnic_init:	init vNICs (assign port types, etc.)
 * @vnic_clean:	clean up app's vNIC state
 * @start:	start application logic
 * @stop:	stop application logic
 * @ctrl_msg_rx:    control message handler
 * @setup_tc:	setup TC ndo
 * @tc_busy:	TC HW offload busy (rules loaded)
 * @xdp_offload:    offload an XDP program
@@ -81,6 +85,11 @@ struct nfp_app_type {
			 unsigned int id);
	void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn);

	int (*start)(struct nfp_app *app);
	void (*stop)(struct nfp_app *app);

	void (*ctrl_msg_rx)(struct nfp_app *app, struct sk_buff *skb);

	int (*setup_tc)(struct nfp_app *app, struct net_device *netdev,
			u32 handle, __be16 proto, struct tc_to_netdev *tc);
	bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn);
@@ -93,6 +102,7 @@ struct nfp_app_type {
 * @pdev:	backpointer to PCI device
 * @pf:		backpointer to NFP PF structure
 * @cpp:	pointer to the CPP handle
 * @ctrl:	pointer to ctrl vNIC struct
 * @type:	pointer to const application ops and info
 */
struct nfp_app {
@@ -100,6 +110,8 @@ struct nfp_app {
	struct nfp_pf *pf;
	struct nfp_cpp *cpp;

	struct nfp_net *ctrl;

	const struct nfp_app_type *type;
};

@@ -124,6 +136,21 @@ static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
		app->type->vnic_clean(app, nn);
}

static inline int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl)
{
	app->ctrl = ctrl;
	if (!app->type->start)
		return 0;
	return app->type->start(app);
}

static inline void nfp_app_stop(struct nfp_app *app)
{
	if (!app->type->stop)
		return;
	app->type->stop(app);
}

static inline const char *nfp_app_name(struct nfp_app *app)
{
	if (!app)
@@ -131,6 +158,11 @@ static inline const char *nfp_app_name(struct nfp_app *app)
	return app->type->name;
}

static inline bool nfp_app_needs_ctrl_vnic(struct nfp_app *app)
{
	return app && app->type->ctrl_msg_rx;
}

static inline bool nfp_app_ctrl_has_meta(struct nfp_app *app)
{
	return app->type->ctrl_has_meta;
@@ -174,6 +206,18 @@ static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
	return app->type->xdp_offload(app, nn, prog);
}

static inline bool nfp_app_ctrl_tx(struct nfp_app *app, struct sk_buff *skb)
{
	return nfp_ctrl_tx(app->ctrl, skb);
}

static inline void nfp_app_ctrl_rx(struct nfp_app *app, struct sk_buff *skb)
{
	app->type->ctrl_msg_rx(app, skb);
}

struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size);

struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id);
void nfp_app_free(struct nfp_app *app);

+7 −0
Original line number Diff line number Diff line
@@ -63,11 +63,13 @@ struct nfp_nsp_identify;
 * @cpp:		Pointer to the CPP handle
 * @app:		Pointer to the APP handle
 * @data_vnic_bar:	Pointer to the CPP area for the data vNICs' BARs
 * @ctrl_vnic_bar:	Pointer to the CPP area for the ctrl vNIC's BAR
 * @qc_area:		Pointer to the CPP area for the queues
 * @irq_entries:	Array of MSI-X entries for all vNICs
 * @limit_vfs:		Number of VFs supported by firmware (~0 for PCI limit)
 * @num_vfs:		Number of SR-IOV VFs enabled
 * @fw_loaded:		Is the firmware loaded?
 * @ctrl_vnic:		Pointer to the control vNIC if available
 * @eth_tbl:		NSP ETH table
 * @nspi:		NSP identification info
 * @hwmon_dev:		pointer to hwmon device
@@ -87,6 +89,7 @@ struct nfp_pf {
	struct nfp_app *app;

	struct nfp_cpp_area *data_vnic_bar;
	struct nfp_cpp_area *ctrl_vnic_bar;
	struct nfp_cpp_area *qc_area;

	struct msix_entry *irq_entries;
@@ -96,6 +99,8 @@ struct nfp_pf {

	bool fw_loaded;

	struct nfp_net *ctrl_vnic;

	struct nfp_eth_table *eth_tbl;
	struct nfp_nsp_identify *nspi;

@@ -127,4 +132,6 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id);
void
nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id);

bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);

#endif /* NFP_MAIN_H */
+1 −1
Original line number Diff line number Diff line
@@ -1950,7 +1950,7 @@ nfp_ctrl_rx_one(struct nfp_net *nn, struct nfp_net_dp *dp,
	skb_reserve(skb, pkt_off);
	skb_put(skb, pkt_len);

	dev_kfree_skb_any(skb);
	nfp_app_ctrl_rx(nn->app, skb);

	return true;
}
+107 −14
Original line number Diff line number Diff line
@@ -266,13 +266,12 @@ static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)

static void nfp_net_pf_free_vnics(struct nfp_pf *pf)
{
	struct nfp_net *nn;
	struct nfp_net *nn, *next;

	while (!list_empty(&pf->vnics)) {
		nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list);
	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);
}
}

static struct nfp_net *
nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev,
@@ -302,11 +301,13 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev,
	nn->stride_rx = stride;
	nn->stride_tx = stride;

	if (needs_netdev) {
		err = nfp_app_vnic_init(pf->app, nn, eth_id);
		if (err) {
			nfp_net_free(nn);
			return ERR_PTR(err);
		}
	}

	pf->num_vnics++;
	list_add_tail(&nn->vnic_list, &pf->vnics);
@@ -446,6 +447,8 @@ static int nfp_net_pf_init_vnics(struct nfp_pf *pf)
	/* Finish vNIC init and register */
	id = 0;
	list_for_each_entry(nn, &pf->vnics, vnic_list) {
		if (!nfp_net_is_data_vnic(nn))
			continue;
		err = nfp_net_pf_init_vnic(pf, nn, id);
		if (err)
			goto err_prev_deinit;
@@ -457,12 +460,15 @@ static int nfp_net_pf_init_vnics(struct nfp_pf *pf)

err_prev_deinit:
	list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list)
		if (nfp_net_is_data_vnic(nn))
			nfp_net_pf_clean_vnic(pf, nn);
	return err;
}

static int nfp_net_pf_app_init(struct nfp_pf *pf)
static int
nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
{
	u8 __iomem *ctrl_bar;
	int err;

	pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf));
@@ -473,8 +479,28 @@ static int nfp_net_pf_app_init(struct nfp_pf *pf)
	if (err)
		goto err_free;

	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;
	}

	return 0;

err_unmap:
	nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
err_free:
	nfp_app_free(pf->app);
	return err;
@@ -482,12 +508,72 @@ static int nfp_net_pf_app_init(struct nfp_pf *pf)

static void nfp_net_pf_app_clean(struct nfp_pf *pf)
{
	if (pf->ctrl_vnic) {
		nfp_net_pf_free_vnic(pf, pf->ctrl_vnic);
		nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
	}
	nfp_app_free(pf->app);
	pf->app = NULL;
}

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);
}

static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
{
	nfp_net_pf_app_stop(pf);
	/* stop app first, to avoid double free of ctrl vNIC's ddir */
	nfp_net_debugfs_dir_clean(&pf->ddir);

	nfp_net_pf_free_irqs(pf);
@@ -685,7 +771,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
		goto err_ctrl_unmap;
	}

	err = nfp_net_pf_app_init(pf);
	err = nfp_net_pf_app_init(pf, qc_bar, stride);
	if (err)
		goto err_unmap_qc;

@@ -700,14 +786,20 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
	if (err)
		goto err_free_vnics;

	err = nfp_net_pf_init_vnics(pf);
	err = nfp_net_pf_app_start(pf);
	if (err)
		goto err_free_irqs;

	err = nfp_net_pf_init_vnics(pf);
	if (err)
		goto err_stop_app;

	mutex_unlock(&pf->lock);

	return 0;

err_stop_app:
	nfp_net_pf_app_stop(pf);
err_free_irqs:
	nfp_net_pf_free_irqs(pf);
err_free_vnics:
@@ -733,6 +825,7 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
		goto out;

	list_for_each_entry(nn, &pf->vnics, vnic_list)
		if (nfp_net_is_data_vnic(nn))
			nfp_net_pf_clean_vnic(pf, nn);

	nfp_net_pf_free_vnics(pf);