mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-06 21:14:18 +00:00
ice: add basic devlink subfunctions support
Implement devlink port handlers responsible for ethernet type devlink subfunctions. Create subfunction devlink port and setup all resources needed for a subfunction netdev to operate. Configure new VSI for each new subfunction, initialize and configure interrupts and Tx/Rx resources. Set correct MAC filters and create new netdev. For now, subfunction is limited to only one Tx/Rx queue pair. Only allocate new subfunction VSI with devlink port new command. Allocate and free subfunction MSIX interrupt vectors using new API calls with pci_msix_alloc_irq_at and pci_msix_free_irq. Support both automatic and manual subfunction numbers. If no subfunction number is provided, use xa_alloc to pick a number automatically. This will find the first free index and use that as the number. This reduces burden on users in the simple case where a specific number is not required. It may also be slightly faster to check that a number exists since xarray lookup should be faster than a linear scan of the dyn_ports xarray. Co-developed-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Piotr Raczynski <piotr.raczynski@intel.com> Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com> Tested-by: Rafal Romanowski <rafal.romanowski@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
parent
004688c4cb
commit
eda69d654c
@ -6,6 +6,7 @@
|
||||
#include "ice.h"
|
||||
#include "ice_lib.h"
|
||||
#include "devlink.h"
|
||||
#include "devlink_port.h"
|
||||
#include "ice_eswitch.h"
|
||||
#include "ice_fw_update.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
@ -1277,6 +1278,8 @@ static const struct devlink_ops ice_devlink_ops = {
|
||||
|
||||
.rate_leaf_parent_set = ice_devlink_set_parent,
|
||||
.rate_node_parent_set = ice_devlink_set_parent,
|
||||
|
||||
.port_new = ice_devlink_port_new,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
#include "ice.h"
|
||||
#include "devlink.h"
|
||||
#include "devlink_port.h"
|
||||
#include "ice_lib.h"
|
||||
#include "ice_fltr.h"
|
||||
|
||||
static int ice_active_port_option = -1;
|
||||
|
||||
@ -485,3 +488,288 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
|
||||
devl_rate_leaf_destroy(&vf->devlink_port);
|
||||
devl_port_unregister(&vf->devlink_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_dealloc_dynamic_port - Deallocate and remove a dynamic port
|
||||
* @dyn_port: dynamic port instance to deallocate
|
||||
*
|
||||
* Free resources associated with a dynamically added devlink port. Will
|
||||
* deactivate the port if its currently active.
|
||||
*/
|
||||
static void ice_dealloc_dynamic_port(struct ice_dynamic_port *dyn_port)
|
||||
{
|
||||
struct devlink_port *devlink_port = &dyn_port->devlink_port;
|
||||
struct ice_pf *pf = dyn_port->pf;
|
||||
|
||||
xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
|
||||
devl_port_unregister(devlink_port);
|
||||
ice_vsi_free(dyn_port->vsi);
|
||||
xa_erase(&pf->dyn_ports, dyn_port->vsi->idx);
|
||||
kfree(dyn_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_dealloc_all_dynamic_ports - Deallocate all dynamic devlink ports
|
||||
* @pf: pointer to the pf structure
|
||||
*/
|
||||
void ice_dealloc_all_dynamic_ports(struct ice_pf *pf)
|
||||
{
|
||||
struct ice_dynamic_port *dyn_port;
|
||||
unsigned long index;
|
||||
|
||||
xa_for_each(&pf->dyn_ports, index, dyn_port)
|
||||
ice_dealloc_dynamic_port(dyn_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_port_new_check_attr - Check that new port attributes are valid
|
||||
* @pf: pointer to the PF structure
|
||||
* @new_attr: the attributes for the new port
|
||||
* @extack: extack for reporting error messages
|
||||
*
|
||||
* Check that the attributes for the new port are valid before continuing to
|
||||
* allocate the devlink port.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
static int
|
||||
ice_devlink_port_new_check_attr(struct ice_pf *pf,
|
||||
const struct devlink_port_new_attrs *new_attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (new_attr->flavour != DEVLINK_PORT_FLAVOUR_PCI_SF) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Flavour other than pcisf is not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (new_attr->controller_valid) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Setting controller is not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (new_attr->port_index_valid) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Driver does not support user defined port index assignment");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (new_attr->pfnum != pf->hw.pf_id) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Incorrect pfnum supplied");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pci_msix_can_alloc_dyn(pf->pdev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Dynamic MSIX-X interrupt allocation is not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_port_del - devlink handler for port delete
|
||||
* @devlink: pointer to devlink
|
||||
* @port: devlink port to be deleted
|
||||
* @extack: pointer to extack
|
||||
*
|
||||
* Deletes devlink port and deallocates all resources associated with
|
||||
* created subfunction.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
static int
|
||||
ice_devlink_port_del(struct devlink *devlink, struct devlink_port *port,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ice_dynamic_port *dyn_port;
|
||||
|
||||
dyn_port = ice_devlink_port_to_dyn(port);
|
||||
ice_dealloc_dynamic_port(dyn_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct devlink_port_ops ice_devlink_port_sf_ops = {
|
||||
.port_del = ice_devlink_port_del,
|
||||
};
|
||||
|
||||
/**
|
||||
* ice_reserve_sf_num - Reserve a subfunction number for this port
|
||||
* @pf: pointer to the pf structure
|
||||
* @new_attr: devlink port attributes requested
|
||||
* @extack: extack for reporting error messages
|
||||
* @sfnum: on success, the sf number reserved
|
||||
*
|
||||
* Reserve a subfunction number for this port. Only called for
|
||||
* DEVLINK_PORT_FLAVOUR_PCI_SF ports.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
static int
|
||||
ice_reserve_sf_num(struct ice_pf *pf,
|
||||
const struct devlink_port_new_attrs *new_attr,
|
||||
struct netlink_ext_ack *extack, u32 *sfnum)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* If user didn't request an explicit number, pick one */
|
||||
if (!new_attr->sfnum_valid)
|
||||
return xa_alloc(&pf->sf_nums, sfnum, NULL, xa_limit_32b,
|
||||
GFP_KERNEL);
|
||||
|
||||
/* Otherwise, check and use the number provided */
|
||||
err = xa_insert(&pf->sf_nums, new_attr->sfnum, NULL, GFP_KERNEL);
|
||||
if (err) {
|
||||
if (err == -EBUSY)
|
||||
NL_SET_ERR_MSG_MOD(extack, "Subfunction with given sfnum already exists");
|
||||
return err;
|
||||
}
|
||||
|
||||
*sfnum = new_attr->sfnum;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_create_sf_port - Register PCI subfunction devlink port
|
||||
* @dyn_port: the dynamic port instance structure for this subfunction
|
||||
*
|
||||
* Register PCI subfunction flavour devlink port for a dynamically added
|
||||
* subfunction port.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_sf_port(struct ice_dynamic_port *dyn_port)
|
||||
{
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
struct ice_vsi *vsi;
|
||||
struct ice_pf *pf;
|
||||
|
||||
vsi = dyn_port->vsi;
|
||||
pf = dyn_port->pf;
|
||||
|
||||
devlink_port = &dyn_port->devlink_port;
|
||||
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_SF;
|
||||
attrs.pci_sf.pf = pf->hw.pf_id;
|
||||
attrs.pci_sf.sf = dyn_port->sfnum;
|
||||
|
||||
devlink_port_attrs_set(devlink_port, &attrs);
|
||||
devlink = priv_to_devlink(pf);
|
||||
|
||||
return devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
|
||||
&ice_devlink_port_sf_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_sf_port - Destroy the devlink_port for this SF
|
||||
* @dyn_port: the dynamic port instance structure for this subfunction
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this SF.
|
||||
*/
|
||||
void ice_devlink_destroy_sf_port(struct ice_dynamic_port *dyn_port)
|
||||
{
|
||||
devl_port_unregister(&dyn_port->devlink_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_alloc_dynamic_port - Allocate new dynamic port
|
||||
* @pf: pointer to the pf structure
|
||||
* @new_attr: devlink port attributes requested
|
||||
* @extack: extack for reporting error messages
|
||||
* @devlink_port: index of newly created devlink port
|
||||
*
|
||||
* Allocate a new dynamic port instance and prepare it for configuration
|
||||
* with devlink.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
static int
|
||||
ice_alloc_dynamic_port(struct ice_pf *pf,
|
||||
const struct devlink_port_new_attrs *new_attr,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct devlink_port **devlink_port)
|
||||
{
|
||||
struct ice_dynamic_port *dyn_port;
|
||||
struct ice_vsi *vsi;
|
||||
u32 sfnum;
|
||||
int err;
|
||||
|
||||
err = ice_reserve_sf_num(pf, new_attr, extack, &sfnum);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dyn_port = kzalloc(sizeof(*dyn_port), GFP_KERNEL);
|
||||
if (!dyn_port) {
|
||||
err = -ENOMEM;
|
||||
goto unroll_reserve_sf_num;
|
||||
}
|
||||
|
||||
vsi = ice_vsi_alloc(pf);
|
||||
if (!vsi) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate VSI");
|
||||
err = -ENOMEM;
|
||||
goto unroll_dyn_port_alloc;
|
||||
}
|
||||
|
||||
dyn_port->vsi = vsi;
|
||||
dyn_port->pf = pf;
|
||||
dyn_port->sfnum = sfnum;
|
||||
eth_random_addr(dyn_port->hw_addr);
|
||||
|
||||
err = xa_insert(&pf->dyn_ports, vsi->idx, dyn_port, GFP_KERNEL);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port index reservation failed");
|
||||
goto unroll_vsi_alloc;
|
||||
}
|
||||
|
||||
err = ice_devlink_create_sf_port(dyn_port);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port registration failed");
|
||||
goto unroll_xa_insert;
|
||||
}
|
||||
|
||||
*devlink_port = &dyn_port->devlink_port;
|
||||
|
||||
return 0;
|
||||
|
||||
unroll_xa_insert:
|
||||
xa_erase(&pf->dyn_ports, vsi->idx);
|
||||
unroll_vsi_alloc:
|
||||
ice_vsi_free(vsi);
|
||||
unroll_dyn_port_alloc:
|
||||
kfree(dyn_port);
|
||||
unroll_reserve_sf_num:
|
||||
xa_erase(&pf->sf_nums, sfnum);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_port_new - devlink handler for the new port
|
||||
* @devlink: pointer to devlink
|
||||
* @new_attr: pointer to the port new attributes
|
||||
* @extack: extack for reporting error messages
|
||||
* @devlink_port: pointer to a new port
|
||||
*
|
||||
* Creates new devlink port, checks new port attributes and reject
|
||||
* any unsupported parameters, allocates new subfunction for that port.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int
|
||||
ice_devlink_port_new(struct devlink *devlink,
|
||||
const struct devlink_port_new_attrs *new_attr,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct devlink_port **devlink_port)
|
||||
{
|
||||
struct ice_pf *pf = devlink_priv(devlink);
|
||||
int err;
|
||||
|
||||
err = ice_devlink_port_new_check_attr(pf, new_attr, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ice_alloc_dynamic_port(pf, new_attr, extack, devlink_port);
|
||||
}
|
||||
|
@ -4,9 +4,43 @@
|
||||
#ifndef _DEVLINK_PORT_H_
|
||||
#define _DEVLINK_PORT_H_
|
||||
|
||||
#include "../ice.h"
|
||||
|
||||
/**
|
||||
* struct ice_dynamic_port - Track dynamically added devlink port instance
|
||||
* @hw_addr: the HW address for this port
|
||||
* @active: true if the port has been activated
|
||||
* @devlink_port: the associated devlink port structure
|
||||
* @pf: pointer to the PF private structure
|
||||
* @vsi: the VSI associated with this port
|
||||
* @sfnum: the subfunction ID
|
||||
*
|
||||
* An instance of a dynamically added devlink port. Each port flavour
|
||||
*/
|
||||
struct ice_dynamic_port {
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
u8 active: 1;
|
||||
struct devlink_port devlink_port;
|
||||
struct ice_pf *pf;
|
||||
struct ice_vsi *vsi;
|
||||
u32 sfnum;
|
||||
};
|
||||
|
||||
void ice_dealloc_all_dynamic_ports(struct ice_pf *pf);
|
||||
|
||||
int ice_devlink_create_pf_port(struct ice_pf *pf);
|
||||
void ice_devlink_destroy_pf_port(struct ice_pf *pf);
|
||||
int ice_devlink_create_vf_port(struct ice_vf *vf);
|
||||
void ice_devlink_destroy_vf_port(struct ice_vf *vf);
|
||||
int ice_devlink_create_sf_port(struct ice_dynamic_port *dyn_port);
|
||||
void ice_devlink_destroy_sf_port(struct ice_dynamic_port *dyn_port);
|
||||
|
||||
#define ice_devlink_port_to_dyn(port) \
|
||||
container_of(port, struct ice_dynamic_port, devlink_port)
|
||||
|
||||
int
|
||||
ice_devlink_port_new(struct devlink *devlink,
|
||||
const struct devlink_port_new_attrs *new_attr,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct devlink_port **devlink_port);
|
||||
#endif /* _DEVLINK_PORT_H_ */
|
||||
|
@ -652,6 +652,9 @@ struct ice_pf {
|
||||
struct ice_eswitch eswitch;
|
||||
struct ice_esw_br_port *br_port;
|
||||
|
||||
struct xarray dyn_ports;
|
||||
struct xarray sf_nums;
|
||||
|
||||
#define ICE_INVALID_AGG_NODE_ID 0
|
||||
#define ICE_PF_AGG_NODE_ID_START 1
|
||||
#define ICE_MAX_PF_AGG_NODES 32
|
||||
@ -918,6 +921,7 @@ int ice_vsi_open(struct ice_vsi *vsi);
|
||||
void ice_set_ethtool_ops(struct net_device *netdev);
|
||||
void ice_set_ethtool_repr_ops(struct net_device *netdev);
|
||||
void ice_set_ethtool_safe_mode_ops(struct net_device *netdev);
|
||||
void ice_set_ethtool_sf_ops(struct net_device *netdev);
|
||||
u16 ice_get_avail_txq_count(struct ice_pf *pf);
|
||||
u16 ice_get_avail_rxq_count(struct ice_pf *pf);
|
||||
int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "ice_lib.h"
|
||||
#include "ice_fltr.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
#include "ice_type.h"
|
||||
#include "ice_vsi_vlan_ops.h"
|
||||
|
||||
/**
|
||||
@ -432,7 +433,7 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
|
||||
* This deallocates the VSI's queue resources, removes it from the PF's
|
||||
* VSI array if necessary, and deallocates the VSI
|
||||
*/
|
||||
static void ice_vsi_free(struct ice_vsi *vsi)
|
||||
void ice_vsi_free(struct ice_vsi *vsi)
|
||||
{
|
||||
struct ice_pf *pf = NULL;
|
||||
struct device *dev;
|
||||
@ -605,7 +606,7 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch)
|
||||
*
|
||||
* returns a pointer to a VSI on success, NULL on failure.
|
||||
*/
|
||||
static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf)
|
||||
struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf)
|
||||
{
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
struct ice_vsi *vsi = NULL;
|
||||
|
@ -60,6 +60,8 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked);
|
||||
|
||||
int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags);
|
||||
int ice_vsi_cfg(struct ice_vsi *vsi);
|
||||
struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf);
|
||||
void ice_vsi_free(struct ice_vsi *vsi);
|
||||
|
||||
bool ice_is_reset_in_progress(unsigned long *state);
|
||||
int ice_wait_for_reset(struct ice_pf *pf, unsigned long timeout);
|
||||
|
@ -4004,6 +4004,9 @@ static void ice_deinit_pf(struct ice_pf *pf)
|
||||
|
||||
if (pf->ptp.clock)
|
||||
ptp_clock_unregister(pf->ptp.clock);
|
||||
|
||||
xa_destroy(&pf->dyn_ports);
|
||||
xa_destroy(&pf->sf_nums);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4097,6 +4100,9 @@ static int ice_init_pf(struct ice_pf *pf)
|
||||
hash_init(pf->vfs.table);
|
||||
ice_mbx_init_snapshot(&pf->hw);
|
||||
|
||||
xa_init(&pf->dyn_ports);
|
||||
xa_init(&pf->sf_nums);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5439,6 +5445,7 @@ static void ice_remove(struct pci_dev *pdev)
|
||||
ice_remove_arfs(pf);
|
||||
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
ice_dealloc_all_dynamic_ports(pf);
|
||||
ice_deinit_devlink(pf);
|
||||
|
||||
ice_unload(pf);
|
||||
|
Loading…
Reference in New Issue
Block a user