nfp: support port splitting via devlink
Add support for configuring port split with devlink. Add devlink callbacks to validate requested config and call NSP helpers. Getting the right nfp_port structure can be done with simple iteration. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f0b8119538
commit
ec8b1fbe68
@ -54,7 +54,104 @@ nfp_devlink_fill_eth_port(struct nfp_port *port,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
|
||||||
|
struct nfp_eth_table_port *copy)
|
||||||
|
{
|
||||||
|
struct nfp_port *port;
|
||||||
|
|
||||||
|
port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
|
||||||
|
|
||||||
|
return nfp_devlink_fill_eth_port(port, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
|
||||||
|
{
|
||||||
|
struct nfp_nsp *nsp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nsp = nfp_eth_config_start(pf->cpp, idx);
|
||||||
|
if (IS_ERR(nsp))
|
||||||
|
return PTR_ERR(nsp);
|
||||||
|
|
||||||
|
ret = __nfp_eth_set_split(nsp, lanes);
|
||||||
|
if (ret) {
|
||||||
|
nfp_eth_config_cleanup_end(nsp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfp_eth_config_commit_end(nsp);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (ret) /* no change */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return nfp_net_refresh_port_table_sync(pf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
struct nfp_pf *pf = devlink_priv(devlink);
|
||||||
|
struct nfp_eth_table_port eth_port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (count < 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&pf->lock);
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port);
|
||||||
|
rtnl_unlock();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (eth_port.is_split || eth_port.port_lanes % count) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfp_devlink_set_lanes(pf, eth_port.index,
|
||||||
|
eth_port.port_lanes / count);
|
||||||
|
out:
|
||||||
|
mutex_unlock(&pf->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index)
|
||||||
|
{
|
||||||
|
struct nfp_pf *pf = devlink_priv(devlink);
|
||||||
|
struct nfp_eth_table_port eth_port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&pf->lock);
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port);
|
||||||
|
rtnl_unlock();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!eth_port.is_split) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes);
|
||||||
|
out:
|
||||||
|
mutex_unlock(&pf->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const struct devlink_ops nfp_devlink_ops = {
|
const struct devlink_ops nfp_devlink_ops = {
|
||||||
|
.port_split = nfp_devlink_port_split,
|
||||||
|
.port_unsplit = nfp_devlink_port_unsplit,
|
||||||
};
|
};
|
||||||
|
|
||||||
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
|
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pci_regs.h>
|
#include <linux/pci_regs.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
@ -561,19 +562,17 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfp_net_refresh_vnics(struct work_struct *work)
|
int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
|
||||||
{
|
{
|
||||||
struct nfp_pf *pf = container_of(work, struct nfp_pf,
|
|
||||||
port_refresh_work);
|
|
||||||
struct nfp_eth_table *eth_table;
|
struct nfp_eth_table *eth_table;
|
||||||
struct nfp_net *nn, *next;
|
struct nfp_net *nn, *next;
|
||||||
struct nfp_port *port;
|
struct nfp_port *port;
|
||||||
|
|
||||||
mutex_lock(&pf->lock);
|
lockdep_assert_held(&pf->lock);
|
||||||
|
|
||||||
/* Check for nfp_net_pci_remove() racing against us */
|
/* Check for nfp_net_pci_remove() racing against us */
|
||||||
if (list_empty(&pf->vnics))
|
if (list_empty(&pf->vnics))
|
||||||
goto out;
|
return 0;
|
||||||
|
|
||||||
/* Update state of all ports */
|
/* Update state of all ports */
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
@ -587,7 +586,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
|
|||||||
set_bit(NFP_PORT_CHANGED, &port->flags);
|
set_bit(NFP_PORT_CHANGED, &port->flags);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
nfp_err(pf->cpp, "Error refreshing port config!\n");
|
nfp_err(pf->cpp, "Error refreshing port config!\n");
|
||||||
goto out;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(port, &pf->ports, port_list)
|
list_for_each_entry(port, &pf->ports, port_list)
|
||||||
@ -608,7 +607,17 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
|
|||||||
|
|
||||||
if (list_empty(&pf->vnics))
|
if (list_empty(&pf->vnics))
|
||||||
nfp_net_pci_remove_finish(pf);
|
nfp_net_pci_remove_finish(pf);
|
||||||
out:
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
mutex_lock(&pf->lock);
|
||||||
|
nfp_net_refresh_port_table_sync(pf);
|
||||||
mutex_unlock(&pf->lock);
|
mutex_unlock(&pf->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
|
||||||
#include "nfpcore/nfp_nsp.h"
|
#include "nfpcore/nfp_nsp.h"
|
||||||
#include "nfp_app.h"
|
#include "nfp_app.h"
|
||||||
#include "nfp_main.h"
|
#include "nfp_main.h"
|
||||||
@ -48,6 +50,23 @@ struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)
|
|||||||
return nn->port;
|
return nn->port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nfp_port *
|
||||||
|
nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id)
|
||||||
|
{
|
||||||
|
struct nfp_port *port;
|
||||||
|
|
||||||
|
lockdep_assert_held(&pf->lock);
|
||||||
|
|
||||||
|
if (type != NFP_PORT_PHYS_PORT)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(port, &pf->ports, port_list)
|
||||||
|
if (port->eth_id == id)
|
||||||
|
return port;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (!port)
|
if (!port)
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
struct net_device;
|
struct net_device;
|
||||||
struct nfp_app;
|
struct nfp_app;
|
||||||
|
struct nfp_pf;
|
||||||
struct nfp_port;
|
struct nfp_port;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,6 +91,8 @@ struct nfp_port {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct nfp_port *nfp_port_from_netdev(struct net_device *netdev);
|
struct nfp_port *nfp_port_from_netdev(struct net_device *netdev);
|
||||||
|
struct nfp_port *
|
||||||
|
nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
@ -103,6 +106,7 @@ void nfp_port_free(struct nfp_port *port);
|
|||||||
|
|
||||||
int nfp_net_refresh_eth_port(struct nfp_port *port);
|
int nfp_net_refresh_eth_port(struct nfp_port *port);
|
||||||
void nfp_net_refresh_port_table(struct nfp_port *port);
|
void nfp_net_refresh_port_table(struct nfp_port *port);
|
||||||
|
int nfp_net_refresh_port_table_sync(struct nfp_pf *pf);
|
||||||
|
|
||||||
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port);
|
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port);
|
||||||
void nfp_devlink_port_unregister(struct nfp_port *port);
|
void nfp_devlink_port_unregister(struct nfp_port *port);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user