struct bpf_prog;
struct net_device;
struct pci_dev;
+struct sk_buff;
struct tc_to_netdev;
struct sk_buff;
struct nfp_app;
* @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
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);
* @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 {
struct nfp_pf *pf;
struct nfp_cpp *cpp;
+ struct nfp_net *ctrl;
+
const struct nfp_app_type *type;
};
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)
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;
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);
* @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
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;
bool fw_loaded;
+ struct nfp_net *ctrl_vnic;
+
struct nfp_eth_table *eth_tbl;
struct nfp_nsp_identify *nspi;
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 */
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 *
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++;
/* 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;
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));
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;
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);
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;
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:
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);