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:
parent
2c7e41c0b2
commit
02082701b9
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 @@ err_free:
|
|||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue