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: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2017-06-05 17:01:56 -07:00 committed by David S. Miller
parent 2c7e41c0b2
commit 02082701b9
5 changed files with 177 additions and 15 deletions

View File

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

View File

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

View File

@ -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 */

View File

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

View File

@ -266,12 +266,11 @@ 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);
nfp_net_pf_free_vnic(pf, nn);
}
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 *
@ -302,10 +301,12 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev,
nn->stride_rx = stride;
nn->stride_tx = stride;
err = nfp_app_vnic_init(pf->app, nn, eth_id);
if (err) {
nfp_net_free(nn);
return ERR_PTR(err);
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++;
@ -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)
nfp_net_pf_clean_vnic(pf, nn);
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,7 +825,8 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
goto out;
list_for_each_entry(nn, &pf->vnics, vnic_list)
nfp_net_pf_clean_vnic(pf, nn);
if (nfp_net_is_data_vnic(nn))
nfp_net_pf_clean_vnic(pf, nn);
nfp_net_pf_free_vnics(pf);