diff options
author | David S. Miller <davem@davemloft.net> | 2017-05-22 21:59:07 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-05-22 21:59:07 +0300 |
commit | 0172397e2fcc29dc803c7d0b22aa2a25e4b02991 (patch) | |
tree | 93b886c2f25aa4b3e8fb6d9878bd1658ceafecf3 | |
parent | bd080488a6cfd37135becedfdc87643b139c2345 (diff) | |
parent | 1876749da87500c7228f91398e04291389a18634 (diff) | |
download | linux-0172397e2fcc29dc803c7d0b22aa2a25e4b02991.tar.xz |
Merge branch 'nfp-introduce-nfp_port-and-nfp_app'
Jakub Kicinski says:
====================
nfp: introduce nfp_port and nfp_app
This series builds foundation for upcoming development. So far the nfp
driver was focused on delivering basic NIC-like functionality. We want
to switch gears a bit going forward and support more advanced applications.
First few patches are naming clean ups and reshuffling. The two main
structures this series adds are nfp_port and nfp_app.
nfp_port represents a device port, where port can mean external port,
VF or PF. For now only external port/MAC/PHY port is added. nfp_port
is supposed to make it easy to share ethtool and devlink code regardless
of netdev type (full vNIC vs representors).
nfp_app is an abstraction which should allow easier development of new
applications. So far we have relied fully on port capabilities to detect
which offloads and features are available. The usual development model
for NFP is that people start with one of our "core NIC" FW apps (C one,
or a macro assembler one) and build advanced functionality on top of that.
Therefore basic netdev code is shared, but the higher-level logic is
usually more project specific. The higher-level logic is also per-adapter
rather than per-port, so creating per-adapter control entity makes sense.
Hopefully the separation of lower-level netdev code and application logic
will help us limit interdependencies and accelerate parallel projects
(e.g. TC flower offloads vs eBPF offload).
v2:
- don't hide definition of nfp_app to avoid silly function calls (Dave);
- reorder kdoc of nfp_main (Simon);
- make nfp_netdev_is_nfp_net() static inline as well.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_app.c | 57 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_app.h | 56 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_main.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_main.h | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net.h | 44 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 76 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 62 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 346 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_port.c | 121 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_port.h | 102 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 11 |
14 files changed, 658 insertions, 265 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 4b15f0f496aa..e8333283ada6 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -14,12 +14,14 @@ nfp-objs := \ nfpcore/nfp_resource.o \ nfpcore/nfp_rtsym.o \ nfpcore/nfp_target.o \ + nfp_app.o \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ nfp_net_offload.o \ nfp_net_main.o \ - nfp_netvf_main.o + nfp_netvf_main.o \ + nfp_port.o ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c new file mode 100644 index 000000000000..59be638bb60e --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 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. + */ + +#include <linux/slab.h> + +#include "nfp_app.h" +#include "nfp_main.h" + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf) +{ + struct nfp_app *app; + + app = kzalloc(sizeof(*app), GFP_KERNEL); + if (!app) + return ERR_PTR(-ENOMEM); + + app->pf = pf; + app->cpp = pf->cpp; + app->pdev = pf->pdev; + + return app; +} + +void nfp_app_free(struct nfp_app *app) +{ + kfree(app); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h new file mode 100644 index 000000000000..e63425c02c8d --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 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. + */ + +#ifndef _NFP_APP_H +#define _NFP_APP_H 1 + +struct pci_dev; +struct nfp_cpp; +struct nfp_pf; + +/** + * struct nfp_app - NFP application container + * @pdev: backpointer to PCI device + * @pf: backpointer to NFP PF structure + * @cpp: pointer to the CPP handle + */ +struct nfp_app { + struct pci_dev *pdev; + struct nfp_pf *pf; + struct nfp_cpp *cpp; +}; + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf); +void nfp_app_free(struct nfp_app *app); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index dde35dae35c5..bb586ce1ea06 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -340,6 +340,7 @@ static int nfp_pci_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_rel_regions; } + INIT_LIST_HEAD(&pf->vnics); INIT_LIST_HEAD(&pf->ports); pci_set_drvdata(pdev, pf); pf->pdev = pdev; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index b57de047b002..991c4cba0bbf 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -57,27 +57,31 @@ struct nfp_eth_table; * struct nfp_pf - NFP PF-specific device structure * @pdev: Backpointer to PCI device * @cpp: Pointer to the CPP handle - * @ctrl_area: Pointer to the CPP area for the control BAR + * @app: Pointer to the APP handle + * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs * @tx_area: Pointer to the CPP area for the TX queues * @rx_area: Pointer to the CPP area for the FL/RX queues - * @irq_entries: Array of MSI-X entries for all ports + * @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? * @eth_tbl: NSP ETH table * @ddir: Per-device debugfs directory - * @num_ports: Number of adapter ports app firmware supports - * @num_netdevs: Number of netdevs spawned - * @ports: Linked list of port structures (struct nfp_net) - * @port_lock: Protects @ports, @num_ports, @num_netdevs + * @max_data_vnics: Number of data vNICs app firmware supports + * @num_vnics: Number of vNICs spawned + * @vnics: Linked list of vNIC structures (struct nfp_net) + * @ports: Linked list of port structures (struct nfp_port) * @port_refresh_work: Work entry for taking netdevs out + * @lock: Protects all fields which may change after probe */ struct nfp_pf { struct pci_dev *pdev; struct nfp_cpp *cpp; - struct nfp_cpp_area *ctrl_area; + struct nfp_app *app; + + struct nfp_cpp_area *data_vnic_bar; struct nfp_cpp_area *tx_area; struct nfp_cpp_area *rx_area; @@ -92,12 +96,13 @@ struct nfp_pf { struct dentry *ddir; - unsigned int num_ports; - unsigned int num_netdevs; + unsigned int max_data_vnics; + unsigned int num_vnics; + struct list_head vnics; struct list_head ports; struct work_struct port_refresh_work; - struct mutex port_lock; + struct mutex lock; }; extern struct pci_driver nfp_netvf_pci_driver; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 7b9518cbe965..7882d2604835 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -84,7 +84,7 @@ #define NFP_NET_NON_Q_VECTORS 2 #define NFP_NET_IRQ_LSC_IDX 0 #define NFP_NET_IRQ_EXN_IDX 1 -#define NFP_NET_MIN_PORT_IRQS (NFP_NET_NON_Q_VECTORS + 1) +#define NFP_NET_MIN_VNIC_IRQS (NFP_NET_NON_Q_VECTORS + 1) /* Queue/Ring definitions */ #define NFP_NET_MAX_TX_RINGS 64 /* Max. # of Tx rings per device */ @@ -116,6 +116,7 @@ struct nfp_cpp; struct nfp_eth_table_port; struct nfp_net; struct nfp_net_r_vector; +struct nfp_port; /* Convenience macro for wrapping descriptor index on ring size */ #define D_IDX(ring, idx) ((idx) & ((ring)->cnt - 1)) @@ -542,7 +543,6 @@ struct nfp_net_dp { * @reconfig_sync_present: Some thread is performing synchronous reconfig * @reconfig_timer: Timer for async reading of reconfig results * @link_up: Is the link up? - * @link_changed: Has link state changes since last port refresh? * @link_status_lock: Protects @link_* and ensures atomicity with BAR reading * @rx_coalesce_usecs: RX interrupt moderation usecs delay parameter * @rx_coalesce_max_frames: RX interrupt moderation frame count parameter @@ -555,10 +555,10 @@ struct nfp_net_dp { * @rx_bar: Pointer to mapped FL/RX queues * @debugfs_dir: Device directory in debugfs * @ethtool_dump_flag: Ethtool dump flag - * @port_list: Entry on device port list + * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device - * @cpp: CPP device handle if available - * @eth_port: Translated ETH Table port entry + * @app: APP handle if available + * @port: Pointer to nfp_port structure if vNIC is a port */ struct nfp_net { struct nfp_net_dp dp; @@ -600,7 +600,6 @@ struct nfp_net { u32 me_freq_mhz; bool link_up; - bool link_changed; spinlock_t link_status_lock; spinlock_t reconfig_lock; @@ -625,12 +624,12 @@ struct nfp_net { struct dentry *debugfs_dir; u32 ethtool_dump_flag; - struct list_head port_list; + struct list_head vnic_list; struct pci_dev *pdev; - struct nfp_cpp *cpp; + struct nfp_app *app; - struct nfp_eth_table_port *eth_port; + struct nfp_port *port; }; /* Functions to read/write from/to a BAR @@ -802,16 +801,25 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q) /* Globals */ extern const char nfp_driver_version[]; +extern const struct net_device_ops nfp_net_netdev_ops; + +static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev) +{ + return netdev->netdev_ops == &nfp_net_netdev_ops; +} + /* Prototypes */ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver, void __iomem *ctrl_bar); struct nfp_net * -nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, unsigned int max_rx_rings); -void nfp_net_netdev_free(struct nfp_net *nn); -int nfp_net_netdev_init(struct net_device *netdev); -void nfp_net_netdev_clean(struct net_device *netdev); +nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, unsigned int max_rx_rings); +void nfp_net_free(struct nfp_net *nn); + +int nfp_net_init(struct nfp_net *nn); +void nfp_net_clean(struct nfp_net *nn); + void nfp_net_set_ethtool_ops(struct net_device *netdev); void nfp_net_info(struct nfp_net *nn); int nfp_net_reconfig(struct nfp_net *nn, u32 update); @@ -832,15 +840,11 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn); int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new, struct netlink_ext_ack *extack); -bool nfp_net_link_changed_read_clear(struct nfp_net *nn); -int nfp_net_refresh_eth_port(struct nfp_net *nn); -void nfp_net_refresh_port_table(struct nfp_net *nn); - #ifdef CONFIG_NFP_DEBUG void nfp_net_debugfs_create(void); void nfp_net_debugfs_destroy(void); struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev); -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id); +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id); void nfp_net_debugfs_dir_clean(struct dentry **dir); #else static inline void nfp_net_debugfs_create(void) @@ -857,7 +861,7 @@ static inline struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev) } static inline void -nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index da83e17b8b20..b3f5c8af6789 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -70,6 +70,7 @@ #include "nfpcore/nfp_nsp.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" /** * nfp_net_get_fw_version() - Read and parse the FW version @@ -391,19 +392,6 @@ static irqreturn_t nfp_net_irq_rxtx(int irq, void *data) return IRQ_HANDLED; } -bool nfp_net_link_changed_read_clear(struct nfp_net *nn) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&nn->link_status_lock, flags); - ret = nn->link_changed; - nn->link_changed = false; - spin_unlock_irqrestore(&nn->link_status_lock, flags); - - return ret; -} - /** * nfp_net_read_link_status() - Reread link status from control BAR * @nn: NFP Network structure @@ -423,7 +411,8 @@ static void nfp_net_read_link_status(struct nfp_net *nn) goto out; nn->link_up = link_up; - nn->link_changed = true; + if (nn->port) + set_bit(NFP_PORT_CHANGED, &nn->port->flags); if (nn->link_up) { netif_carrier_on(nn->dp.netdev); @@ -516,11 +505,10 @@ nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring, /** * nfp_net_vecs_init() - Assign IRQs and setup rvecs. - * @netdev: netdev structure + * @nn: NFP Network structure */ -static void nfp_net_vecs_init(struct net_device *netdev) +static void nfp_net_vecs_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); struct nfp_net_r_vector *r_vec; int r; @@ -2847,26 +2835,6 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, return features; } -static int -nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len) -{ - struct nfp_net *nn = netdev_priv(netdev); - int err; - - if (!nn->eth_port) - return -EOPNOTSUPP; - - if (!nn->eth_port->is_split) - err = snprintf(name, len, "p%d", nn->eth_port->label_port); - else - err = snprintf(name, len, "p%ds%d", nn->eth_port->label_port, - nn->eth_port->label_subport); - if (err >= len) - return -EINVAL; - - return 0; -} - /** * nfp_net_set_vxlan_port() - set vxlan port in SW and reconfigure HW * @nn: NFP Net device to reconfigure @@ -3029,7 +2997,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) } } -static const struct net_device_ops nfp_net_netdev_ops = { +const struct net_device_ops nfp_net_netdev_ops = { .ndo_open = nfp_net_netdev_open, .ndo_stop = nfp_net_netdev_close, .ndo_start_xmit = nfp_net_tx, @@ -3041,7 +3009,7 @@ static const struct net_device_ops nfp_net_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_set_features = nfp_net_set_features, .ndo_features_check = nfp_net_features_check, - .ndo_get_phys_port_name = nfp_net_get_phys_port_name, + .ndo_get_phys_port_name = nfp_port_get_phys_port_name, .ndo_udp_tunnel_add = nfp_net_add_vxlan_port, .ndo_udp_tunnel_del = nfp_net_del_vxlan_port, .ndo_xdp = nfp_net_xdp, @@ -3087,7 +3055,7 @@ void nfp_net_info(struct nfp_net *nn) } /** - * nfp_net_netdev_alloc() - Allocate netdev and related structure + * nfp_net_alloc() - Allocate netdev and related structure * @pdev: PCI device * @max_tx_rings: Maximum number of TX rings supported by device * @max_rx_rings: Maximum number of RX rings supported by device @@ -3097,9 +3065,9 @@ void nfp_net_info(struct nfp_net *nn) * * Return: NFP Net device structure, or ERR_PTR on error. */ -struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, - unsigned int max_rx_rings) +struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, + unsigned int max_rx_rings) { struct net_device *netdev; struct nfp_net *nn; @@ -3144,10 +3112,10 @@ struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, } /** - * nfp_net_netdev_free() - Undo what @nfp_net_netdev_alloc() did + * nfp_net_free() - Undo what @nfp_net_alloc() did * @nn: NFP Net device to reconfigure */ -void nfp_net_netdev_free(struct nfp_net *nn) +void nfp_net_free(struct nfp_net *nn) { free_netdev(nn->dp.netdev); } @@ -3221,14 +3189,14 @@ static void nfp_net_irqmod_init(struct nfp_net *nn) } /** - * nfp_net_netdev_init() - Initialise/finalise the netdev structure - * @netdev: netdev structure + * nfp_net_init() - Initialise/finalise the nfp_net structure + * @nn: NFP Net device structure * * Return: 0 on success or negative errno on error. */ -int nfp_net_netdev_init(struct net_device *netdev) +int nfp_net_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); + struct net_device *netdev = nn->dp.netdev; int err; nn->dp.rx_dma_dir = DMA_FROM_DEVICE; @@ -3367,19 +3335,17 @@ int nfp_net_netdev_init(struct net_device *netdev) netif_carrier_off(netdev); nfp_net_set_ethtool_ops(netdev); - nfp_net_vecs_init(netdev); + nfp_net_vecs_init(nn); return register_netdev(netdev); } /** - * nfp_net_netdev_clean() - Undo what nfp_net_netdev_init() did. - * @netdev: netdev structure + * nfp_net_clean() - Undo what nfp_net_init() did. + * @nn: NFP Net device structure */ -void nfp_net_netdev_clean(struct net_device *netdev) +void nfp_net_clean(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); - unregister_netdev(nn->dp.netdev); if (nn->dp.xdp_prog) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 4077c59bf782..6cf1b234eecd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -200,7 +200,7 @@ static const struct file_operations nfp_xdp_q_fops = { .llseek = seq_lseek }; -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { struct dentry *queues, *tx, *rx, *xdp; char name[20]; @@ -209,7 +209,7 @@ void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) if (IS_ERR_OR_NULL(nfp_dir)) return; - sprintf(name, "port%d", id); + sprintf(name, "vnic%d", id); nn->debugfs_dir = debugfs_create_dir(name, ddir); if (IS_ERR_OR_NULL(nn->debugfs_dir)) return; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 70bb0a0152b9..84fdbc4b835b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -50,8 +50,10 @@ #include "nfpcore/nfp.h" #include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" enum nfp_dump_diag { NFP_DUMP_NSP_DIAG = 0, @@ -134,14 +136,14 @@ static const struct _nfp_net_et_stats nfp_net_et_stats[] = { #define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \ NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN) -static void nfp_net_get_nspinfo(struct nfp_net *nn, char *version) +static void nfp_net_get_nspinfo(struct nfp_app *app, char *version) { struct nfp_nsp *nsp; - if (!nn->cpp) + if (!app) return; - nsp = nfp_nsp_open(nn->cpp); + nsp = nfp_nsp_open(app->cpp); if (IS_ERR(nsp)) return; @@ -162,7 +164,7 @@ static void nfp_net_get_drvinfo(struct net_device *netdev, sizeof(drvinfo->driver)); strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version)); - nfp_net_get_nspinfo(nn, nsp_version); + nfp_net_get_nspinfo(nn->app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d.%d %s", nn->fw_ver.resv, nn->fw_ver.class, @@ -195,37 +197,38 @@ nfp_net_get_link_ksettings(struct net_device *netdev, [NFP_NET_CFG_STS_LINK_RATE_50G] = SPEED_50000, [NFP_NET_CFG_STS_LINK_RATE_100G] = SPEED_100000, }; - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + struct nfp_net *nn; u32 sts, ls; + /* Init to unknowns */ ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); cmd->base.port = PORT_OTHER; cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; - if (nn->eth_port) - cmd->base.autoneg = nn->eth_port->aneg != NFP_ANEG_DISABLED ? + port = nfp_port_from_netdev(netdev); + eth_port = nfp_port_get_eth_port(port); + if (eth_port) + cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? AUTONEG_ENABLE : AUTONEG_DISABLE; if (!netif_carrier_ok(netdev)) return 0; /* Use link speed from ETH table if available, otherwise try the BAR */ - if (nn->eth_port) { - int err; - - if (nfp_net_link_changed_read_clear(nn)) { - err = nfp_net_refresh_eth_port(nn); - if (err) - return err; - } - - cmd->base.port = nn->eth_port->port_type; - cmd->base.speed = nn->eth_port->speed; + if (eth_port) { + cmd->base.port = eth_port->port_type; + cmd->base.speed = eth_port->speed; cmd->base.duplex = DUPLEX_FULL; return 0; } + if (!nfp_netdev_is_nfp_net(netdev)) + return -EOPNOTSUPP; + nn = netdev_priv(netdev); + sts = nn_readl(nn, NFP_NET_CFG_STS); ls = FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts); @@ -246,19 +249,22 @@ static int nfp_net_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) { - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; struct nfp_nsp *nsp; int err; - if (!nn->eth_port) + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) return -EOPNOTSUPP; if (netif_running(netdev)) { - nn_warn(nn, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); + netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); return -EBUSY; } - nsp = nfp_eth_config_start(nn->cpp, nn->eth_port->index); + nsp = nfp_eth_config_start(port->app->cpp, eth_port->index); if (IS_ERR(nsp)) return PTR_ERR(nsp); @@ -267,7 +273,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err) goto err_bad_set; if (cmd->base.speed != SPEED_UNKNOWN) { - u32 speed = cmd->base.speed / nn->eth_port->lanes; + u32 speed = cmd->base.speed / eth_port->lanes; err = __nfp_eth_set_speed(nsp, speed); if (err) @@ -278,7 +284,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err > 0) return 0; /* no change */ - nfp_net_refresh_port_table(nn); + nfp_net_refresh_port_table(port); return err; @@ -706,13 +712,13 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) struct nfp_resource *res; int ret; - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; dump->version = 1; dump->flag = NFP_DUMP_NSP_DIAG; - res = nfp_resource_acquire(nn->cpp, NFP_RESOURCE_NSP_DIAG); + res = nfp_resource_acquire(nn->app->cpp, NFP_RESOURCE_NSP_DIAG); if (IS_ERR(res)) return PTR_ERR(res); @@ -722,7 +728,7 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) goto exit_release; } - ret = nfp_cpp_read(nn->cpp, nfp_resource_cpp_id(res), + ret = nfp_cpp_read(nn->app->cpp, nfp_resource_cpp_id(res), nfp_resource_address(res), buffer, dump->len); if (ret != dump->len) @@ -743,7 +749,7 @@ static int nfp_net_set_dump(struct net_device *netdev, struct ethtool_dump *val) { struct nfp_net *nn = netdev_priv(netdev); - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; if (val->flag != NFP_DUMP_NSP_DIAG) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8cb87cbe1120..dd1118c7e1a4 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -54,10 +54,11 @@ #include "nfpcore/nfp_nffw.h" #include "nfpcore/nfp_nsp.h" #include "nfpcore/nfp6000_pcie.h" - +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" #include "nfp_main.h" +#include "nfp_port.h" #define NFP_PF_CSR_SLICE_SIZE (32 * 1024) @@ -142,14 +143,16 @@ err_area: static void nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) { + struct nfp_eth_table_port *eth_port; struct nfp_net_dp *dp = &nn->dp; u8 mac_addr[ETH_ALEN]; const char *mac_str; char name[32]; - if (nn->eth_port) { - ether_addr_copy(dp->netdev->dev_addr, nn->eth_port->mac_addr); - ether_addr_copy(dp->netdev->perm_addr, nn->eth_port->mac_addr); + 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); return; } @@ -190,21 +193,17 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf) { char name[256]; - u16 interface; - int pcie_pf; int err = 0; u64 val; - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - - snprintf(name, sizeof(name), "nfd_cfg_pf%d_num_ports", pcie_pf); + snprintf(name, sizeof(name), "nfd_cfg_pf%u_num_ports", + nfp_cppcore_pcie_unit(pf->cpp)); val = nfp_rtsym_read_le(pf->cpp, name, &err); - /* Default to one port */ + /* Default to one port/vNIC */ if (err) { if (err != -ENOENT) - nfp_err(pf->cpp, "Unable to read adapter port count\n"); + nfp_err(pf->cpp, "Unable to read adapter vNIC count\n"); val = 1; } @@ -220,7 +219,7 @@ nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, min_qc = readl(ctrl_bar + start_off); max_qc = min_qc; - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { /* 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). @@ -241,13 +240,9 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) const struct nfp_rtsym *ctrl_sym; u8 __iomem *ctrl_bar; char pf_symbol[256]; - u16 interface; - int pcie_pf; - - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - snprintf(pf_symbol, sizeof(pf_symbol), "_pf%d_net_bar0", pcie_pf); + snprintf(pf_symbol, sizeof(pf_symbol), "_pf%u_net_bar0", + nfp_cppcore_pcie_unit(pf->cpp)); ctrl_sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); if (!ctrl_sym) { @@ -256,17 +251,17 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return NULL; } - if (ctrl_sym->size < pf->num_ports * NFP_PF_CSR_SLICE_SIZE) { + if (ctrl_sym->size < pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE) { dev_err(&pf->pdev->dev, - "PF BAR0 too small to contain %d ports\n", - pf->num_ports); + "PF BAR0 too small to contain %d vNICs\n", + pf->max_data_vnics); return NULL; } ctrl_bar = nfp_net_map_area(pf->cpp, "net.ctrl", ctrl_sym->domain, ctrl_sym->target, ctrl_sym->addr, ctrl_sym->size, - &pf->ctrl_area); + &pf->data_vnic_bar); if (IS_ERR(ctrl_bar)) { dev_err(&pf->pdev->dev, "Failed to map PF BAR0: %ld\n", PTR_ERR(ctrl_bar)); @@ -276,37 +271,43 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return ctrl_bar; } -static void nfp_net_pf_free_netdevs(struct nfp_pf *pf) +static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) { - struct nfp_net *nn; + nfp_port_free(nn->port); + list_del(&nn->vnic_list); + pf->num_vnics--; + nfp_net_free(nn); +} - while (!list_empty(&pf->ports)) { - nn = list_first_entry(&pf->ports, struct nfp_net, port_list); - list_del(&nn->port_list); - pf->num_netdevs--; +static void nfp_net_pf_free_vnics(struct nfp_pf *pf) +{ + struct nfp_net *nn; - nfp_net_netdev_free(nn); + while (!list_empty(&pf->vnics)) { + nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list); + nfp_net_pf_free_vnic(pf, nn); } } static struct nfp_net * -nfp_net_pf_alloc_port_netdev(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, - struct nfp_eth_table_port *eth_port) +nfp_net_pf_alloc_vnic(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, + unsigned int eth_id) { + struct nfp_eth_table_port *eth_port; u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS); n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); - /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pf->pdev, n_tx_rings, n_rx_rings); + /* Allocate and initialise the vNIC */ + nn = nfp_net_alloc(pf->pdev, n_tx_rings, n_rx_rings); if (IS_ERR(nn)) return nn; - nn->cpp = pf->cpp; + nn->app = pf->app; nn->fw_ver = *fw_ver; nn->dp.ctrl_bar = ctrl_bar; nn->tx_bar = tx_bar; @@ -314,14 +315,27 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, nn->dp.is_vf = 0; nn->stride_rx = stride; nn->stride_tx = stride; - nn->eth_port = eth_port; + + eth_port = nfp_net_find_port(pf->eth_tbl, eth_id); + if (eth_port) { + nn->port = nfp_port_alloc(pf->app, NFP_PORT_PHYS_PORT, + nn->dp.netdev); + if (IS_ERR(nn->port)) { + nfp_net_free(nn); + return ERR_CAST(nn->port); + } + nn->port->eth_id = eth_id; + nn->port->eth_port = eth_port; + } + + pf->num_vnics++; + list_add_tail(&nn->vnic_list, &pf->vnics); return nn; } static int -nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, - unsigned int id) +nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) { int err; @@ -334,11 +348,11 @@ nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) return err; - nfp_net_debugfs_port_add(nn, pf->ddir, id); + nfp_net_debugfs_vnic_add(nn, pf->ddir, id); nfp_net_info(nn); @@ -346,20 +360,25 @@ nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, } static int -nfp_net_pf_alloc_netdevs(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) +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) { u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base; - struct nfp_eth_table_port *eth_port; struct nfp_net *nn; unsigned int i; int err; + if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) { + nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", + pf->max_data_vnics, pf->eth_tbl->count); + return -EINVAL; + } + prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { 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; @@ -367,53 +386,57 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = tgt_tx_base; prev_rx_base = tgt_rx_base; - eth_port = nfp_net_find_port(pf->eth_tbl, i); - if (eth_port && eth_port->override_changed) { - nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); - } else { - nn = nfp_net_pf_alloc_port_netdev(pf, ctrl_bar, tx_bar, - rx_bar, stride, - fw_ver, eth_port); - if (IS_ERR(nn)) { - err = PTR_ERR(nn); - goto err_free_prev; - } - list_add_tail(&nn->port_list, &pf->ports); - pf->num_netdevs++; + nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver, i); + if (IS_ERR(nn)) { + err = PTR_ERR(nn); + goto err_free_prev; } ctrl_bar += NFP_PF_CSR_SLICE_SIZE; + + /* Check if vNIC has external port associated and cfg is OK */ + if (pf->eth_tbl && !nn->port) { + nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i); + err = -EINVAL; + goto err_free_prev; + } + if (nn->port && nn->port->eth_port->override_changed) { + nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); + nfp_net_pf_free_vnic(pf, nn); + continue; + } } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) return -ENODEV; return 0; err_free_prev: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } static int -nfp_net_pf_spawn_netdevs(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) +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) { - unsigned int id, wanted_irqs, num_irqs, ports_left, irqs_left; + unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; struct nfp_net *nn; int err; - /* Allocate the netdevs and do basic init */ - err = nfp_net_pf_alloc_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, fw_ver); + /* Allocate the vnics and do basic init */ + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver); if (err) return err; /* Get MSI-X vectors */ wanted_irqs = 0; - list_for_each_entry(nn, &pf->ports, port_list) + list_for_each_entry(nn, &pf->vnics, vnic_list) wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs; pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries), GFP_KERNEL); @@ -423,7 +446,7 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, } num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries, - NFP_NET_MIN_PORT_IRQS * pf->num_netdevs, + NFP_NET_MIN_VNIC_IRQS * pf->num_vnics, wanted_irqs); if (!num_irqs) { nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n"); @@ -431,23 +454,23 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, goto err_vec_free; } - /* Distribute IRQs to ports */ + /* Distribute IRQs to vNICs */ irqs_left = num_irqs; - ports_left = pf->num_netdevs; - list_for_each_entry(nn, &pf->ports, port_list) { + vnics_left = pf->num_vnics; + list_for_each_entry(nn, &pf->vnics, vnic_list) { unsigned int n; - n = DIV_ROUND_UP(irqs_left, ports_left); + n = DIV_ROUND_UP(irqs_left, vnics_left); nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left], n); irqs_left -= n; - ports_left--; + vnics_left--; } - /* Finish netdev init and register */ + /* Finish vNIC init and register */ id = 0; - list_for_each_entry(nn, &pf->ports, port_list) { - err = nfp_net_pf_init_port_netdev(pf, nn, id); + list_for_each_entry(nn, &pf->vnics, vnic_list) { + err = nfp_net_pf_init_vnic(pf, nn, id); if (err) goto err_prev_deinit; @@ -457,18 +480,30 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, return 0; err_prev_deinit: - list_for_each_entry_continue_reverse(nn, &pf->ports, port_list) { + list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); } nfp_net_irqs_disable(pf->pdev); err_vec_free: kfree(pf->irq_entries); err_nn_free: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } +static int nfp_net_pf_app_init(struct nfp_pf *pf) +{ + pf->app = nfp_app_alloc(pf); + + return PTR_ERR_OR_ZERO(pf->app); +} + +static void nfp_net_pf_app_clean(struct nfp_pf *pf) +{ + nfp_app_free(pf->app); +} + static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { nfp_net_debugfs_dir_clean(&pf->ddir); @@ -476,99 +511,120 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_net_irqs_disable(pf->pdev); kfree(pf->irq_entries); + nfp_net_pf_app_clean(pf); + nfp_cpp_area_release_free(pf->rx_area); nfp_cpp_area_release_free(pf->tx_area); - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); } -static void nfp_net_refresh_netdevs(struct work_struct *work) +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) { + set_bit(NFP_PORT_CHANGED, &port->flags); + 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; +} + +static void nfp_net_refresh_vnics(struct work_struct *work) { struct nfp_pf *pf = container_of(work, struct nfp_pf, port_refresh_work); struct nfp_eth_table *eth_table; struct nfp_net *nn, *next; + struct nfp_port *port; - mutex_lock(&pf->port_lock); + mutex_lock(&pf->lock); /* Check for nfp_net_pci_remove() racing against us */ - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->ports, port_list) - nfp_net_link_changed_read_clear(nn); + /* Update state of all ports */ + rtnl_lock(); + list_for_each_entry(port, &pf->ports, port_list) + clear_bit(NFP_PORT_CHANGED, &port->flags); eth_table = nfp_eth_read_ports(pf->cpp); if (!eth_table) { + list_for_each_entry(port, &pf->ports, port_list) + if (__nfp_port_get_eth_port(port)) + set_bit(NFP_PORT_CHANGED, &port->flags); + rtnl_unlock(); nfp_err(pf->cpp, "Error refreshing port config!\n"); goto out; } - rtnl_lock(); - list_for_each_entry(nn, &pf->ports, port_list) { - if (!nn->eth_port) - continue; - nn->eth_port = nfp_net_find_port(eth_table, - nn->eth_port->eth_index); - } + 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); rtnl_unlock(); - kfree(pf->eth_tbl); - pf->eth_tbl = eth_table; + kfree(eth_table); - list_for_each_entry_safe(nn, next, &pf->ports, port_list) { - if (!nn->eth_port) { - nfp_warn(pf->cpp, "Warning: port not present after reconfig\n"); - continue; - } - if (!nn->eth_port->override_changed) + /* Shoot off the ports which became invalid */ + list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { + if (!nn->port || nn->port->type != NFP_PORT_INVALID) continue; - nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); - list_del(&nn->port_list); - pf->num_netdevs--; - nfp_net_netdev_free(nn); + nfp_net_pf_free_vnic(pf, nn); } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) nfp_net_pci_remove_finish(pf); out: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); } -void nfp_net_refresh_port_table(struct nfp_net *nn) +void nfp_net_refresh_port_table(struct nfp_port *port) { - struct nfp_pf *pf = pci_get_drvdata(nn->pdev); + struct nfp_pf *pf = port->app->pf; + + set_bit(NFP_PORT_CHANGED, &port->flags); schedule_work(&pf->port_refresh_work); } -int nfp_net_refresh_eth_port(struct nfp_net *nn) +int nfp_net_refresh_eth_port(struct nfp_port *port) { - struct nfp_eth_table_port *eth_port; + struct nfp_cpp *cpp = port->app->cpp; struct nfp_eth_table *eth_table; + int ret; - eth_table = nfp_eth_read_ports(nn->cpp); - if (!eth_table) { - nn_err(nn, "Error refreshing port state table!\n"); - return -EIO; - } + clear_bit(NFP_PORT_CHANGED, &port->flags); - eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index); - if (!eth_port) { - nn_err(nn, "Error finding state of the port!\n"); - kfree(eth_table); + eth_table = nfp_eth_read_ports(cpp); + if (!eth_table) { + set_bit(NFP_PORT_CHANGED, &port->flags); + nfp_err(cpp, "Error refreshing port state table!\n"); return -EIO; } - memcpy(nn->eth_port, eth_port, sizeof(*eth_port)); + ret = nfp_net_eth_port_update(cpp, port, eth_table); kfree(eth_table); - return 0; + return ret; } /* @@ -584,8 +640,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) int stride; int err; - INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_netdevs); - mutex_init(&pf->port_lock); + INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics); + mutex_init(&pf->lock); /* Verify that the board has completed initialization */ if (!nfp_is_ready(pf->cpp)) { @@ -593,8 +649,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) return -EINVAL; } - mutex_lock(&pf->port_lock); - pf->num_ports = nfp_net_pf_get_num_ports(pf); + mutex_lock(&pf->lock); + pf->max_data_vnics = nfp_net_pf_get_num_ports(pf); ctrl_bar = nfp_net_pf_map_ctrl_bar(pf); if (!ctrl_bar) { @@ -667,26 +723,32 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_unmap_tx; } + err = nfp_net_pf_app_init(pf); + if (err) + goto err_unmap_rx; + pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, &fw_ver); + err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, &fw_ver); if (err) goto err_clean_ddir; - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return 0; err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); + nfp_net_pf_app_clean(pf); +err_unmap_rx: nfp_cpp_area_release_free(pf->rx_area); err_unmap_tx: nfp_cpp_area_release_free(pf->tx_area); err_ctrl_unmap: - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); err_unlock: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return err; } @@ -694,21 +756,21 @@ void nfp_net_pci_remove(struct nfp_pf *pf) { struct nfp_net *nn; - mutex_lock(&pf->port_lock); - if (list_empty(&pf->ports)) + mutex_lock(&pf->lock); + if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->ports, port_list) { + list_for_each_entry(nn, &pf->vnics, vnic_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); } - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); nfp_net_pci_remove_finish(pf); out: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); cancel_work_sync(&pf->port_refresh_work); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 86e61be6f35c..3f1c7f0f392e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -202,7 +202,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, rx_bar_off = NFP_PCIE_QUEUE(startq); /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pdev, max_tx_rings, max_rx_rings); + nn = nfp_net_alloc(pdev, max_tx_rings, max_rx_rings); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_ctrl_unmap; @@ -267,7 +267,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, nfp_netvf_get_mac_addr(nn); num_irqs = nfp_net_irqs_alloc(pdev, vf->irq_entries, - NFP_NET_MIN_PORT_IRQS, + NFP_NET_MIN_VNIC_IRQS, NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs); if (!num_irqs) { @@ -283,13 +283,13 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) goto err_irqs_disable; nfp_net_info(nn); vf->ddir = nfp_net_debugfs_device_add(pdev); - nfp_net_debugfs_port_add(nn, vf->ddir, 0); + nfp_net_debugfs_vnic_add(nn, vf->ddir, 0); return 0; @@ -304,7 +304,7 @@ err_unmap_tx: else iounmap(vf->q_bar); err_netdev_free: - nfp_net_netdev_free(nn); + nfp_net_free(nn); err_ctrl_unmap: iounmap(ctrl_bar); err_pci_regions: @@ -328,7 +328,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_debugfs_dir_clean(&vf->ddir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); nfp_net_irqs_disable(pdev); @@ -340,7 +340,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) } iounmap(nn->dp.ctrl_bar); - nfp_net_netdev_free(nn); + nfp_net_free(nn); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c new file mode 100644 index 000000000000..3beed4167e2f --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 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. + */ + +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net.h" +#include "nfp_port.h" + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) +{ + struct nfp_net *nn; + + if (WARN_ON(!nfp_netdev_is_nfp_net(netdev))) + return NULL; + nn = netdev_priv(netdev); + + return nn->port; +} + +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!port) + return NULL; + if (port->type != NFP_PORT_PHYS_PORT) + return NULL; + + return port->eth_port; +} + +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!__nfp_port_get_eth_port(port)) + return NULL; + + if (test_bit(NFP_PORT_CHANGED, &port->flags)) + if (nfp_net_refresh_eth_port(port)) + return NULL; + + return __nfp_port_get_eth_port(port); +} + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + int n; + + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + if (!eth_port->is_split) + n = snprintf(name, len, "p%d", eth_port->label_port); + else + n = snprintf(name, len, "p%ds%d", eth_port->label_port, + eth_port->label_subport); + if (n >= len) + return -EINVAL; + + return 0; +} + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev) +{ + struct nfp_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->netdev = netdev; + port->type = type; + port->app = app; + + list_add_tail(&port->port_list, &app->pf->ports); + + return port; +} + +void nfp_port_free(struct nfp_port *port) +{ + if (!port) + return; + list_del(&port->port_list); + kfree(port); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h new file mode 100644 index 000000000000..641617de41cc --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 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. + */ + +#ifndef _NFP_PORT_H_ +#define _NFP_PORT_H_ + +struct net_device; +struct nfp_app; +struct nfp_port; + +/** + * enum nfp_port_type - type of port NFP can switch traffic to + * @NFP_PORT_INVALID: port is invalid, %NFP_PORT_PHYS_PORT transitions to this + * state when port disappears because of FW fault or config + * change + * @NFP_PORT_PHYS_PORT: external NIC port + */ +enum nfp_port_type { + NFP_PORT_INVALID, + NFP_PORT_PHYS_PORT, +}; + +/** + * enum nfp_port_flags - port flags (can be type-specific) + * @NFP_PORT_CHANGED: port state has changed since last eth table refresh; + * for NFP_PORT_PHYS_PORT, never set otherwise; must hold + * rtnl_lock to clear + */ +enum nfp_port_flags { + NFP_PORT_CHANGED = 0, +}; + +/** + * struct nfp_port - structure representing NFP port + * @netdev: backpointer to associated netdev + * @type: what port type does the entity represent + * @flags: port flags + * @app: backpointer to the app structure + * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme + * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry + * @port_list: entry on pf's list of ports + */ +struct nfp_port { + struct net_device *netdev; + enum nfp_port_type type; + + unsigned long flags; + + struct nfp_app *app; + + unsigned int eth_id; + struct nfp_eth_table_port *eth_port; + + struct list_head port_list; +}; + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port); +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port); + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len); + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev); +void nfp_port_free(struct nfp_port *port); + +int nfp_net_refresh_eth_port(struct nfp_port *port); +void nfp_net_refresh_port_table(struct nfp_port *port); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index edecc0a27485..154b0b594184 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -289,6 +289,17 @@ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex); +/** + * nfp_cppcore_pcie_unit() - Get PCI Unit of a CPP handle + * @cpp: CPP handle + * + * Return: PCI unit for the NFP CPP handle + */ +static inline u8 nfp_cppcore_pcie_unit(struct nfp_cpp *cpp) +{ + return NFP_CPP_INTERFACE_UNIT_of(nfp_cpp_interface(cpp)); +} + struct nfp_cpp_explicit; struct nfp_cpp_explicit_command { |