Commit f3b6129b authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
ice: support devlink subfunction

Michal Swiatkowski says:

Currently ice driver does not allow creating more than one networking
device per physical function. The only way to have more hardware backed
netdev is to use SR-IOV.

Following patchset adds support for devlink port API. For each new
pcisf type port, driver allocates new VSI, configures all resources
needed, including dynamically MSIX vectors, program rules and registers
new netdev.

This series supports only one Tx/Rx queue pair per subfunction.

Example commands:
devlink port add pci/0000:31:00.1 flavour pcisf pfnum 1 sfnum 1000
devlink port function set pci/0000:31:00.1/1 hw_addr 00:00:00:00:03:14
devlink port function set pci/0000:31:00.1/1 state active
devlink port function del pci/0000:31:00.1/1

Make the port representor and eswitch code generic to support
subfunction representor type.

VSI configuration is slightly different between VF and SF. It needs to
be reflected in the code.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: subfunction activation and base devlink ops
  ice: basic support for VLAN in subfunctions
  ice: support subfunction devlink Tx topology
  ice: implement netdevice ops for SF representor
  ice: check if SF is ready in ethtool ops
  ice: don't set target VSI for subfunction
  ice: create port representor for SF
  ice: make representor code generic
  ice: implement netdev for subfunction
  ice: base subfunction aux driver
  ice: allocate devlink for subfunction
  ice: treat subfunction VSI the same as PF VSI
  ice: add basic devlink subfunctions support
  ice: export ice ndo_ops functions
  ice: add new VSI type for subfunctions
====================

Link: https://patch.msgid.link/20240906223010.2194591-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 474bb1aa 13acc5c4
......@@ -33,6 +33,8 @@ ice-y := ice_main.o \
ice_idc.o \
devlink/devlink.o \
devlink/devlink_port.o \
ice_sf_eth.o \
ice_sf_vsi_vlan_ops.o \
ice_ddp.o \
ice_fw_update.o \
ice_lag.o \
......
......@@ -6,9 +6,11 @@
#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"
#include "ice_sf_eth.h"
/* context for devlink info version reporting */
struct ice_info_ctx {
......@@ -744,6 +746,7 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node
struct ice_sched_node *tc_node, struct ice_pf *pf)
{
struct devlink_rate *rate_node = NULL;
struct ice_dynamic_port *sf;
struct ice_vf *vf;
int i;
......@@ -755,6 +758,7 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node
/* create root node */
rate_node = devl_rate_node_create(devlink, node, node->name, NULL);
} else if (node->vsi_handle &&
pf->vsi[node->vsi_handle]->type == ICE_VSI_VF &&
pf->vsi[node->vsi_handle]->vf) {
vf = pf->vsi[node->vsi_handle]->vf;
if (!vf->devlink_port.devlink_rate)
......@@ -763,6 +767,16 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node
*/
devl_rate_leaf_create(&vf->devlink_port, node,
node->parent->rate_node);
} else if (node->vsi_handle &&
pf->vsi[node->vsi_handle]->type == ICE_VSI_SF &&
pf->vsi[node->vsi_handle]->sf) {
sf = pf->vsi[node->vsi_handle]->sf;
if (!sf->devlink_port.devlink_rate)
/* leaf nodes doesn't have children
* so we don't set rate_node
*/
devl_rate_leaf_create(&sf->devlink_port, node,
node->parent->rate_node);
} else if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF &&
node->parent->rate_node) {
rate_node = devl_rate_node_create(devlink, node, node->name,
......@@ -1277,8 +1291,12 @@ 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 const struct devlink_ops ice_sf_devlink_ops;
static int
ice_devlink_enable_roce_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
......@@ -1561,6 +1579,34 @@ struct ice_pf *ice_allocate_pf(struct device *dev)
return devlink_priv(devlink);
}
/**
* ice_allocate_sf - Allocate devlink and return SF structure pointer
* @dev: the device to allocate for
* @pf: pointer to the PF structure
*
* Allocate a devlink instance for SF.
*
* Return: ice_sf_priv pointer to allocated memory or ERR_PTR in case of error
*/
struct ice_sf_priv *ice_allocate_sf(struct device *dev, struct ice_pf *pf)
{
struct devlink *devlink;
int err;
devlink = devlink_alloc(&ice_sf_devlink_ops, sizeof(struct ice_sf_priv),
dev);
if (!devlink)
return ERR_PTR(-ENOMEM);
err = devl_nested_devlink_set(priv_to_devlink(pf), devlink);
if (err) {
devlink_free(devlink);
return ERR_PTR(err);
}
return devlink_priv(devlink);
}
/**
* ice_devlink_register - Register devlink interface for this PF
* @pf: the PF to register the devlink for.
......
......@@ -5,6 +5,7 @@
#define _ICE_DEVLINK_H_
struct ice_pf *ice_allocate_pf(struct device *dev);
struct ice_sf_priv *ice_allocate_sf(struct device *dev, struct ice_pf *pf);
void ice_devlink_register(struct ice_pf *pf);
void ice_devlink_unregister(struct ice_pf *pf);
......
......@@ -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,506 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
devl_rate_leaf_destroy(&vf->devlink_port);
devl_port_unregister(&vf->devlink_port);
}
/**
* ice_devlink_create_sf_dev_port - Register virtual port for a subfunction
* @sf_dev: the subfunction device to create a devlink port for
*
* Register virtual flavour devlink port for the subfunction auxiliary device
* created after activating a dynamically added devlink port.
*
* Return: zero on success or an error code on failure.
*/
int ice_devlink_create_sf_dev_port(struct ice_sf_dev *sf_dev)
{
struct devlink_port_attrs attrs = {};
struct ice_dynamic_port *dyn_port;
struct devlink_port *devlink_port;
struct devlink *devlink;
struct ice_vsi *vsi;
dyn_port = sf_dev->dyn_port;
vsi = dyn_port->vsi;
devlink_port = &sf_dev->priv->devlink_port;
attrs.flavour = DEVLINK_PORT_FLAVOUR_VIRTUAL;
devlink_port_attrs_set(devlink_port, &attrs);
devlink = priv_to_devlink(sf_dev->priv);
return devl_port_register(devlink, devlink_port, vsi->idx);
}
/**
* ice_devlink_destroy_sf_dev_port - Destroy virtual port for a subfunction
* @sf_dev: the subfunction device to create a devlink port for
*
* Unregisters the virtual port associated with this subfunction.
*/
void ice_devlink_destroy_sf_dev_port(struct ice_sf_dev *sf_dev)
{
devl_port_unregister(&sf_dev->priv->devlink_port);
}
/**
* ice_activate_dynamic_port - Activate a dynamic port
* @dyn_port: dynamic port instance to activate
* @extack: extack for reporting error messages
*
* Activate the dynamic port based on its flavour.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_activate_dynamic_port(struct ice_dynamic_port *dyn_port,
struct netlink_ext_ack *extack)
{
int err;
if (dyn_port->active)
return 0;
err = ice_sf_eth_activate(dyn_port, extack);
if (err)
return err;
dyn_port->active = true;
return 0;
}
/**
* ice_deactivate_dynamic_port - Deactivate a dynamic port
* @dyn_port: dynamic port instance to deactivate
*
* Undo activation of a dynamic port.
*/
static void ice_deactivate_dynamic_port(struct ice_dynamic_port *dyn_port)
{
if (!dyn_port->active)
return;
ice_sf_eth_deactivate(dyn_port);
dyn_port->active = false;
}
/**
* 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;
ice_deactivate_dynamic_port(dyn_port);
xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
ice_eswitch_detach_sf(pf, dyn_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;
}
/**
* ice_devlink_port_fn_hw_addr_set - devlink handler for mac address set
* @port: pointer to devlink port
* @hw_addr: hw address to set
* @hw_addr_len: hw address length
* @extack: extack for reporting error messages
*
* Sets mac address for the port, verifies arguments and copies address
* to the subfunction structure.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_fn_hw_addr_set(struct devlink_port *port, const u8 *hw_addr,
int hw_addr_len,
struct netlink_ext_ack *extack)
{
struct ice_dynamic_port *dyn_port;
dyn_port = ice_devlink_port_to_dyn(port);
if (dyn_port->attached) {
NL_SET_ERR_MSG_MOD(extack,
"Ethernet address can be change only in detached state");
return -EBUSY;
}
if (hw_addr_len != ETH_ALEN || !is_valid_ether_addr(hw_addr)) {
NL_SET_ERR_MSG_MOD(extack, "Invalid ethernet address");
return -EADDRNOTAVAIL;
}
ether_addr_copy(dyn_port->hw_addr, hw_addr);
return 0;
}
/**
* ice_devlink_port_fn_hw_addr_get - devlink handler for mac address get
* @port: pointer to devlink port
* @hw_addr: hw address to set
* @hw_addr_len: hw address length
* @extack: extack for reporting error messages
*
* Returns mac address for the port.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_fn_hw_addr_get(struct devlink_port *port, u8 *hw_addr,
int *hw_addr_len,
struct netlink_ext_ack *extack)
{
struct ice_dynamic_port *dyn_port;
dyn_port = ice_devlink_port_to_dyn(port);
ether_addr_copy(hw_addr, dyn_port->hw_addr);
*hw_addr_len = ETH_ALEN;
return 0;
}
/**
* ice_devlink_port_fn_state_set - devlink handler for port state set
* @port: pointer to devlink port
* @state: state to set
* @extack: extack for reporting error messages
*
* Activates or deactivates the port.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_fn_state_set(struct devlink_port *port,
enum devlink_port_fn_state state,
struct netlink_ext_ack *extack)
{
struct ice_dynamic_port *dyn_port;
dyn_port = ice_devlink_port_to_dyn(port);
switch (state) {
case DEVLINK_PORT_FN_STATE_ACTIVE:
return ice_activate_dynamic_port(dyn_port, extack);
case DEVLINK_PORT_FN_STATE_INACTIVE:
ice_deactivate_dynamic_port(dyn_port);
break;
}
return 0;
}
/**
* ice_devlink_port_fn_state_get - devlink handler for port state get
* @port: pointer to devlink port
* @state: admin configured state of the port
* @opstate: current port operational state
* @extack: extack for reporting error messages
*
* Gets port state.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_fn_state_get(struct devlink_port *port,
enum devlink_port_fn_state *state,
enum devlink_port_fn_opstate *opstate,
struct netlink_ext_ack *extack)
{
struct ice_dynamic_port *dyn_port;
dyn_port = ice_devlink_port_to_dyn(port);
if (dyn_port->active)
*state = DEVLINK_PORT_FN_STATE_ACTIVE;
else
*state = DEVLINK_PORT_FN_STATE_INACTIVE;
if (dyn_port->attached)
*opstate = DEVLINK_PORT_FN_OPSTATE_ATTACHED;
else
*opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED;
return 0;
}
static const struct devlink_port_ops ice_devlink_port_sf_ops = {
.port_del = ice_devlink_port_del,
.port_fn_hw_addr_get = ice_devlink_port_fn_hw_addr_get,
.port_fn_hw_addr_set = ice_devlink_port_fn_hw_addr_set,
.port_fn_state_get = ice_devlink_port_fn_state_get,
.port_fn_state_set = ice_devlink_port_fn_state_set,
};
/**
* 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_rate_leaf_destroy(&dyn_port->devlink_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_eswitch_attach_sf(pf, dyn_port);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to attach SF to eswitch");
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,55 @@
#ifndef _DEVLINK_PORT_H_
#define _DEVLINK_PORT_H_
#include "../ice.h"
#include "../ice_sf_eth.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
* @attached: true it the prot is attached
* @devlink_port: the associated devlink port structure
* @pf: pointer to the PF private structure
* @vsi: the VSI associated with this port
* @repr_id: the representor ID
* @sfnum: the subfunction ID
* @sf_dev: pointer to the subfunction device
*
* An instance of a dynamically added devlink port. Each port flavour
*/
struct ice_dynamic_port {
u8 hw_addr[ETH_ALEN];
u8 active: 1;
u8 attached: 1;
struct devlink_port devlink_port;
struct ice_pf *pf;
struct ice_vsi *vsi;
unsigned long repr_id;
u32 sfnum;
/* Flavour-specific implementation data */
union {
struct ice_sf_dev *sf_dev;
};
};
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);
int ice_devlink_create_sf_dev_port(struct ice_sf_dev *sf_dev);
void ice_devlink_destroy_sf_dev_port(struct ice_sf_dev *sf_dev);
#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_ */
......@@ -451,7 +451,12 @@ struct ice_vsi {
struct_group_tagged(ice_vsi_cfg_params, params,
struct ice_port_info *port_info; /* back pointer to port_info */
struct ice_channel *ch; /* VSI's channel structure, may be NULL */
struct ice_vf *vf; /* VF associated with this VSI, may be NULL */
union {
/* VF associated with this VSI, may be NULL */
struct ice_vf *vf;
/* SF associated with this VSI, may be NULL */
struct ice_dynamic_port *sf;
};
u32 flags; /* VSI flags used for rebuild and configuration */
enum ice_vsi_type type; /* the type of the VSI */
);
......@@ -652,6 +657,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 +926,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);
......@@ -1003,6 +1012,14 @@ void ice_unload(struct ice_pf *pf);
void ice_adv_lnk_speed_maps_init(void);
int ice_init_dev(struct ice_pf *pf);
void ice_deinit_dev(struct ice_pf *pf);
int ice_change_mtu(struct net_device *netdev, int new_mtu);
void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue);
int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp);
void ice_set_netdev_features(struct net_device *netdev);
int ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
int ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
void ice_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats);
/**
* ice_set_rdma_cap - enable RDMA support
......
......@@ -325,6 +325,9 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf
tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf->vf_id;
tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF;
break;
case ICE_VSI_SF:
tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ;
break;
default:
return;
}
......@@ -540,7 +543,7 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
ring->rx_buf_len = ring->vsi->rx_buf_len;
if (ring->vsi->type == ICE_VSI_PF) {
if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
......
......@@ -187,6 +187,7 @@ void ice_vsi_set_dcb_tc_cfg(struct ice_vsi *vsi)
vsi->tc_cfg.numtc = ice_dcb_get_num_tc(cfg);
break;
case ICE_VSI_CHNL:
case ICE_VSI_SF:
vsi->tc_cfg.ena_tc = BIT(ice_get_first_droptc(vsi));
vsi->tc_cfg.numtc = 1;
break;
......
......@@ -452,11 +452,9 @@ static void ice_eswitch_start_reprs(struct ice_pf *pf)
ice_eswitch_start_all_tx_queues(pf);
}
int
ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
static int
ice_eswitch_attach(struct ice_pf *pf, struct ice_repr *repr, unsigned long *id)
{
struct devlink *devlink = priv_to_devlink(pf);
struct ice_repr *repr;
int err;
if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY)
......@@ -470,13 +468,9 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
ice_eswitch_stop_reprs(pf);
devl_lock(devlink);
repr = ice_repr_add_vf(vf);
devl_unlock(devlink);
if (IS_ERR(repr)) {
err = PTR_ERR(repr);
err = repr->ops.add(repr);
if (err)
goto err_create_repr;
}
err = ice_eswitch_setup_repr(pf, repr);
if (err)
......@@ -486,7 +480,7 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
if (err)
goto err_xa_alloc;
vf->repr_id = repr->id;
*id = repr->id;
ice_eswitch_start_reprs(pf);
......@@ -495,9 +489,7 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
err_xa_alloc:
ice_eswitch_release_repr(pf, repr);
err_setup_repr:
devl_lock(devlink);
ice_repr_rem_vf(repr);
devl_unlock(devlink);
repr->ops.rem(repr);
err_create_repr:
if (xa_empty(&pf->eswitch.reprs))
ice_eswitch_disable_switchdev(pf);
......@@ -506,14 +498,59 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
return err;
}
void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)
/**
* ice_eswitch_attach_vf - attach VF to a eswitch
* @pf: pointer to PF structure
* @vf: pointer to VF structure to be attached
*
* During attaching port representor for VF is created.
*
* Return: zero on success or an error code on failure.
*/
int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
{
struct ice_repr *repr = xa_load(&pf->eswitch.reprs, vf->repr_id);
struct ice_repr *repr = ice_repr_create_vf(vf);
struct devlink *devlink = priv_to_devlink(pf);
int err;
if (!repr)
return;
if (IS_ERR(repr))
return PTR_ERR(repr);
devl_lock(devlink);
err = ice_eswitch_attach(pf, repr, &vf->repr_id);
if (err)
ice_repr_destroy(repr);
devl_unlock(devlink);
return err;
}
/**
* ice_eswitch_attach_sf - attach SF to a eswitch
* @pf: pointer to PF structure
* @sf: pointer to SF structure to be attached
*
* During attaching port representor for SF is created.
*
* Return: zero on success or an error code on failure.
*/
int ice_eswitch_attach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf)
{
struct ice_repr *repr = ice_repr_create_sf(sf);
int err;
if (IS_ERR(repr))
return PTR_ERR(repr);
err = ice_eswitch_attach(pf, repr, &sf->repr_id);
if (err)
ice_repr_destroy(repr);
return err;
}
static void ice_eswitch_detach(struct ice_pf *pf, struct ice_repr *repr)
{
ice_eswitch_stop_reprs(pf);
xa_erase(&pf->eswitch.reprs, repr->id);
......@@ -521,10 +558,12 @@ void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)
ice_eswitch_disable_switchdev(pf);
ice_eswitch_release_repr(pf, repr);
devl_lock(devlink);
ice_repr_rem_vf(repr);
repr->ops.rem(repr);
ice_repr_destroy(repr);
if (xa_empty(&pf->eswitch.reprs)) {
struct devlink *devlink = priv_to_devlink(pf);
/* since all port representors are destroyed, there is
* no point in keeping the nodes
*/
......@@ -533,9 +572,41 @@ void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)
} else {
ice_eswitch_start_reprs(pf);
}
}
/**
* ice_eswitch_detach_vf - detach VF from a eswitch
* @pf: pointer to PF structure
* @vf: pointer to VF structure to be detached
*/
void ice_eswitch_detach_vf(struct ice_pf *pf, struct ice_vf *vf)
{
struct ice_repr *repr = xa_load(&pf->eswitch.reprs, vf->repr_id);
struct devlink *devlink = priv_to_devlink(pf);
if (!repr)
return;
devl_lock(devlink);
ice_eswitch_detach(pf, repr);
devl_unlock(devlink);
}
/**
* ice_eswitch_detach_sf - detach SF from a eswitch
* @pf: pointer to PF structure
* @sf: pointer to SF structure to be detached
*/
void ice_eswitch_detach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf)
{
struct ice_repr *repr = xa_load(&pf->eswitch.reprs, sf->repr_id);
if (!repr)
return;
ice_eswitch_detach(pf, repr);
}
/**
* ice_eswitch_get_target - get netdev based on src_vsi from descriptor
* @rx_ring: ring used to receive the packet
......
......@@ -5,11 +5,13 @@
#define _ICE_ESWITCH_H_
#include <net/devlink.h>
#include "devlink/devlink_port.h"
#ifdef CONFIG_ICE_SWITCHDEV
void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf);
int
ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf);
void ice_eswitch_detach_vf(struct ice_pf *pf, struct ice_vf *vf);
void ice_eswitch_detach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf);
int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf);
int ice_eswitch_attach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf);
int ice_eswitch_mode_get(struct devlink *devlink, u16 *mode);
int
......@@ -31,10 +33,20 @@ struct net_device *ice_eswitch_get_target(struct ice_rx_ring *rx_ring,
int ice_eswitch_cfg_vsi(struct ice_vsi *vsi, const u8 *mac);
void ice_eswitch_decfg_vsi(struct ice_vsi *vsi, const u8 *mac);
#else /* CONFIG_ICE_SWITCHDEV */
static inline void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) { }
static inline void
ice_eswitch_detach_vf(struct ice_pf *pf, struct ice_vf *vf) { }
static inline void
ice_eswitch_detach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf) { }
static inline int
ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
{
return -EOPNOTSUPP;
}
static inline int
ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
ice_eswitch_attach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf)
{
return -EOPNOTSUPP;
}
......
......@@ -4412,7 +4412,7 @@ ice_repr_get_drvinfo(struct net_device *netdev,
{
struct ice_repr *repr = ice_netdev_to_repr(netdev);
if (ice_check_vf_ready_for_cfg(repr->vf))
if (repr->ops.ready(repr))
return;
__ice_get_drvinfo(netdev, drvinfo, repr->src_vsi);
......@@ -4424,8 +4424,7 @@ ice_repr_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
struct ice_repr *repr = ice_netdev_to_repr(netdev);
/* for port representors only ETH_SS_STATS is supported */
if (ice_check_vf_ready_for_cfg(repr->vf) ||
stringset != ETH_SS_STATS)
if (repr->ops.ready(repr) || stringset != ETH_SS_STATS)
return;
__ice_get_strings(netdev, stringset, data, repr->src_vsi);
......@@ -4438,7 +4437,7 @@ ice_repr_get_ethtool_stats(struct net_device *netdev,
{
struct ice_repr *repr = ice_netdev_to_repr(netdev);
if (ice_check_vf_ready_for_cfg(repr->vf))
if (repr->ops.ready(repr))
return;
__ice_get_ethtool_stats(netdev, stats, data, repr->src_vsi);
......
......@@ -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"
/**
......@@ -20,6 +21,8 @@ const char *ice_vsi_type_str(enum ice_vsi_type vsi_type)
return "ICE_VSI_PF";
case ICE_VSI_VF:
return "ICE_VSI_VF";
case ICE_VSI_SF:
return "ICE_VSI_SF";
case ICE_VSI_CTRL:
return "ICE_VSI_CTRL";
case ICE_VSI_CHNL:
......@@ -135,6 +138,7 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)
{
switch (vsi->type) {
case ICE_VSI_PF:
case ICE_VSI_SF:
case ICE_VSI_CTRL:
case ICE_VSI_LB:
/* a user could change the values of num_[tr]x_desc using
......@@ -201,6 +205,12 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
max_t(int, vsi->alloc_rxq,
vsi->alloc_txq));
break;
case ICE_VSI_SF:
vsi->alloc_txq = 1;
vsi->alloc_rxq = 1;
vsi->num_q_vectors = 1;
vsi->irq_dyn_alloc = true;
break;
case ICE_VSI_VF:
if (vf->num_req_qs)
vf->num_vf_qs = vf->num_req_qs;
......@@ -423,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;
......@@ -559,6 +569,7 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch)
switch (vsi->type) {
case ICE_VSI_PF:
case ICE_VSI_SF:
/* Setup default MSIX irq handler for VSI */
vsi->irq_handler = ice_msix_clean_rings;
break;
......@@ -595,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;
......@@ -889,6 +900,11 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
max_rss_size);
vsi->rss_lut_type = ICE_LUT_PF;
break;
case ICE_VSI_SF:
vsi->rss_table_size = ICE_LUT_VSI_SIZE;
vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size);
vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_VF:
/* VF VSI will get a small RSS table.
* For VSI_LUT, LUT size should be set to 64 bytes.
......@@ -1136,6 +1152,7 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
break;
case ICE_VSI_VF:
case ICE_VSI_SF:
/* VF VSI will gets a small RSS table which is a VSI LUT type */
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
break;
......@@ -1214,6 +1231,7 @@ static int ice_vsi_init(struct ice_vsi *vsi, u32 vsi_flags)
case ICE_VSI_PF:
ctxt->flags = ICE_AQ_VSI_TYPE_PF;
break;
case ICE_VSI_SF:
case ICE_VSI_CHNL:
ctxt->flags = ICE_AQ_VSI_TYPE_VMDQ2;
break;
......@@ -2095,6 +2113,7 @@ static void ice_set_agg_vsi(struct ice_vsi *vsi)
case ICE_VSI_CHNL:
case ICE_VSI_LB:
case ICE_VSI_PF:
case ICE_VSI_SF:
max_agg_nodes = ICE_MAX_PF_AGG_NODES;
agg_node_id_start = ICE_PF_AGG_NODE_ID_START;
agg_node_iter = &pf->pf_agg_node[0];
......@@ -2264,6 +2283,7 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
switch (vsi->type) {
case ICE_VSI_CTRL:
case ICE_VSI_SF:
case ICE_VSI_PF:
ret = ice_vsi_alloc_q_vectors(vsi);
if (ret)
......@@ -2648,7 +2668,8 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked)
clear_bit(ICE_VSI_NEEDS_RESTART, vsi->state);
if (vsi->netdev && vsi->type == ICE_VSI_PF) {
if (vsi->netdev && (vsi->type == ICE_VSI_PF ||
vsi->type == ICE_VSI_SF)) {
if (netif_running(vsi->netdev)) {
if (!locked)
rtnl_lock();
......@@ -2676,7 +2697,8 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked)
set_bit(ICE_VSI_NEEDS_RESTART, vsi->state);
if (vsi->type == ICE_VSI_PF && vsi->netdev) {
if (vsi->netdev && (vsi->type == ICE_VSI_PF ||
vsi->type == ICE_VSI_SF)) {
if (netif_running(vsi->netdev)) {
if (!locked)
rtnl_lock();
......@@ -2746,6 +2768,26 @@ void ice_vsi_clear_napi_queues(struct ice_vsi *vsi)
netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX, NULL);
}
/**
* ice_napi_add - register NAPI handler for the VSI
* @vsi: VSI for which NAPI handler is to be registered
*
* This function is only called in the driver's load path. Registering the NAPI
* handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume,
* reset/rebuild, etc.)
*/
void ice_napi_add(struct ice_vsi *vsi)
{
int v_idx;
if (!vsi->netdev)
return;
ice_for_each_q_vector(vsi, v_idx)
netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
ice_napi_poll);
}
/**
* ice_vsi_release - Delete a VSI and free its resources
* @vsi: the VSI being removed
......
......@@ -45,6 +45,7 @@ struct ice_vsi *
ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params);
void ice_vsi_set_napi_queues(struct ice_vsi *vsi);
void ice_napi_add(struct ice_vsi *vsi);
void ice_vsi_clear_napi_queues(struct ice_vsi *vsi);
......@@ -59,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);
......
......@@ -15,6 +15,7 @@
#include "ice_dcb_nl.h"
#include "devlink/devlink.h"
#include "devlink/devlink_port.h"
#include "ice_sf_eth.h"
#include "ice_hwmon.h"
/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
* ice tracepoint functions. This must be done exactly once across the
......@@ -2974,6 +2975,9 @@ int ice_vsi_determine_xdp_res(struct ice_vsi *vsi)
if (avail < cpus / 2)
return -ENOMEM;
if (vsi->type == ICE_VSI_SF)
avail = vsi->alloc_txq;
vsi->num_xdp_txq = min_t(u16, avail, cpus);
if (vsi->num_xdp_txq < cpus)
......@@ -3089,14 +3093,14 @@ static int ice_xdp_safe_mode(struct net_device __always_unused *dev,
* @dev: netdevice
* @xdp: XDP command
*/
static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp)
int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp)
{
struct ice_netdev_priv *np = netdev_priv(dev);
struct ice_vsi *vsi = np->vsi;
int ret;
if (vsi->type != ICE_VSI_PF) {
NL_SET_ERR_MSG_MOD(xdp->extack, "XDP can be loaded only on PF VSI");
if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_SF) {
NL_SET_ERR_MSG_MOD(xdp->extack, "XDP can be loaded only on PF or SF VSI");
return -EINVAL;
}
......@@ -3555,26 +3559,6 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
return 0;
}
/**
* ice_napi_add - register NAPI handler for the VSI
* @vsi: VSI for which NAPI handler is to be registered
*
* This function is only called in the driver's load path. Registering the NAPI
* handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume,
* reset/rebuild, etc.)
*/
static void ice_napi_add(struct ice_vsi *vsi)
{
int v_idx;
if (!vsi->netdev)
return;
ice_for_each_q_vector(vsi, v_idx)
netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
ice_napi_poll);
}
/**
* ice_set_ops - set netdev and ethtools ops for the given netdev
* @vsi: the VSI associated with the new netdev
......@@ -3608,7 +3592,7 @@ static void ice_set_ops(struct ice_vsi *vsi)
* ice_set_netdev_features - set features for the given netdev
* @netdev: netdev instance
*/
static void ice_set_netdev_features(struct net_device *netdev)
void ice_set_netdev_features(struct net_device *netdev)
{
struct ice_pf *pf = ice_netdev_to_pf(netdev);
bool is_dvm_ena = ice_is_dvm_ena(&pf->hw);
......@@ -3790,8 +3774,7 @@ ice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
*
* net_device_ops implementation for adding VLAN IDs
*/
static int
ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
int ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi_vlan_ops *vlan_ops;
......@@ -3853,8 +3836,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
*
* net_device_ops implementation for removing VLAN IDs
*/
static int
ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
int ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi_vlan_ops *vlan_ops;
......@@ -4023,6 +4005,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);
}
/**
......@@ -4116,6 +4101,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;
}
......@@ -5458,6 +5446,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);
......@@ -5946,8 +5935,16 @@ static int __init ice_module_init(void)
goto err_dest_lag_wq;
}
status = ice_sf_driver_register();
if (status) {
pr_err("Failed to register SF driver, err %d\n", status);
goto err_sf_driver;
}
return 0;
err_sf_driver:
pci_unregister_driver(&ice_driver);
err_dest_lag_wq:
destroy_workqueue(ice_lag_wq);
ice_debugfs_exit();
......@@ -5965,6 +5962,7 @@ module_init(ice_module_init);
*/
static void __exit ice_module_exit(void)
{
ice_sf_driver_unregister();
pci_unregister_driver(&ice_driver);
ice_debugfs_exit();
destroy_workqueue(ice_wq);
......@@ -6766,7 +6764,8 @@ static int ice_up_complete(struct ice_vsi *vsi)
if (vsi->port_info &&
(vsi->port_info->phy.link_info.link_info & ICE_AQ_LINK_UP) &&
vsi->netdev && vsi->type == ICE_VSI_PF) {
((vsi->netdev && (vsi->type == ICE_VSI_PF ||
vsi->type == ICE_VSI_SF)))) {
ice_print_link_msg(vsi, true);
netif_tx_start_all_queues(vsi->netdev);
netif_carrier_on(vsi->netdev);
......@@ -7124,7 +7123,6 @@ void ice_update_pf_stats(struct ice_pf *pf)
* @netdev: network interface device structure
* @stats: main device statistics structure
*/
static
void ice_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
......@@ -7465,7 +7463,7 @@ int ice_vsi_open(struct ice_vsi *vsi)
ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc);
if (vsi->type == ICE_VSI_PF) {
if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_SF) {
/* Notify the stack of the actual queue counts. */
err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_txq);
if (err)
......@@ -7801,7 +7799,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
*
* Returns 0 on success, negative on failure
*/
static int ice_change_mtu(struct net_device *netdev, int new_mtu)
int ice_change_mtu(struct net_device *netdev, int new_mtu)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
......@@ -8225,7 +8223,7 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
* @netdev: network interface device structure
* @txqueue: Tx queue
*/
static void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_tx_ring *tx_ring = NULL;
......
......@@ -59,12 +59,13 @@ static void
ice_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_repr *repr = np->repr;
struct ice_eth_stats *eth_stats;
struct ice_vsi *vsi;
if (ice_is_vf_disabled(np->repr->vf))
if (repr->ops.ready(repr))
return;
vsi = np->repr->src_vsi;
vsi = repr->src_vsi;
ice_update_vsi_stats(vsi);
eth_stats = &vsi->eth_stats;
......@@ -93,7 +94,7 @@ struct ice_repr *ice_netdev_to_repr(const struct net_device *netdev)
}
/**
* ice_repr_open - Enable port representor's network interface
* ice_repr_vf_open - Enable port representor's network interface
* @netdev: network interface device structure
*
* The open entry point is called when a port representor's network
......@@ -102,7 +103,7 @@ struct ice_repr *ice_netdev_to_repr(const struct net_device *netdev)
*
* Returns 0 on success
*/
static int ice_repr_open(struct net_device *netdev)
static int ice_repr_vf_open(struct net_device *netdev)
{
struct ice_repr *repr = ice_netdev_to_repr(netdev);
struct ice_vf *vf;
......@@ -118,8 +119,16 @@ static int ice_repr_open(struct net_device *netdev)
return 0;
}
static int ice_repr_sf_open(struct net_device *netdev)
{
netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);
return 0;
}
/**
* ice_repr_stop - Disable port representor's network interface
* ice_repr_vf_stop - Disable port representor's network interface
* @netdev: network interface device structure
*
* The stop entry point is called when a port representor's network
......@@ -128,7 +137,7 @@ static int ice_repr_open(struct net_device *netdev)
*
* Returns 0 on success
*/
static int ice_repr_stop(struct net_device *netdev)
static int ice_repr_vf_stop(struct net_device *netdev)
{
struct ice_repr *repr = ice_netdev_to_repr(netdev);
struct ice_vf *vf;
......@@ -144,6 +153,14 @@ static int ice_repr_stop(struct net_device *netdev)
return 0;
}
static int ice_repr_sf_stop(struct net_device *netdev)
{
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
return 0;
}
/**
* ice_repr_sp_stats64 - get slow path stats for port representor
* @dev: network interface device structure
......@@ -245,10 +262,20 @@ ice_repr_setup_tc(struct net_device *netdev, enum tc_setup_type type,
}
}
static const struct net_device_ops ice_repr_netdev_ops = {
static const struct net_device_ops ice_repr_vf_netdev_ops = {
.ndo_get_stats64 = ice_repr_get_stats64,
.ndo_open = ice_repr_vf_open,
.ndo_stop = ice_repr_vf_stop,
.ndo_start_xmit = ice_eswitch_port_start_xmit,
.ndo_setup_tc = ice_repr_setup_tc,
.ndo_has_offload_stats = ice_repr_ndo_has_offload_stats,
.ndo_get_offload_stats = ice_repr_ndo_get_offload_stats,
};
static const struct net_device_ops ice_repr_sf_netdev_ops = {
.ndo_get_stats64 = ice_repr_get_stats64,
.ndo_open = ice_repr_open,
.ndo_stop = ice_repr_stop,
.ndo_open = ice_repr_sf_open,
.ndo_stop = ice_repr_sf_stop,
.ndo_start_xmit = ice_eswitch_port_start_xmit,
.ndo_setup_tc = ice_repr_setup_tc,
.ndo_has_offload_stats = ice_repr_ndo_has_offload_stats,
......@@ -261,18 +288,20 @@ static const struct net_device_ops ice_repr_netdev_ops = {
*/
bool ice_is_port_repr_netdev(const struct net_device *netdev)
{
return netdev && (netdev->netdev_ops == &ice_repr_netdev_ops);
return netdev && (netdev->netdev_ops == &ice_repr_vf_netdev_ops ||
netdev->netdev_ops == &ice_repr_sf_netdev_ops);
}
/**
* ice_repr_reg_netdev - register port representor netdev
* @netdev: pointer to port representor netdev
* @ops: new ops for netdev
*/
static int
ice_repr_reg_netdev(struct net_device *netdev)
ice_repr_reg_netdev(struct net_device *netdev, const struct net_device_ops *ops)
{
eth_hw_addr_random(netdev);
netdev->netdev_ops = &ice_repr_netdev_ops;
netdev->netdev_ops = ops;
ice_set_ethtool_repr_ops(netdev);
netdev->hw_features |= NETIF_F_HW_TC;
......@@ -283,57 +312,56 @@ ice_repr_reg_netdev(struct net_device *netdev)
return register_netdev(netdev);
}
static void ice_repr_remove_node(struct devlink_port *devlink_port)
static int ice_repr_ready_vf(struct ice_repr *repr)
{
return !ice_check_vf_ready_for_cfg(repr->vf);
}
static int ice_repr_ready_sf(struct ice_repr *repr)
{
devl_rate_leaf_destroy(devlink_port);
return !repr->sf->active;
}
/**
* ice_repr_rem - remove representor from VF
* ice_repr_destroy - remove representor from VF
* @repr: pointer to representor structure
*/
static void ice_repr_rem(struct ice_repr *repr)
void ice_repr_destroy(struct ice_repr *repr)
{
free_percpu(repr->stats);
free_netdev(repr->netdev);
kfree(repr);
}
/**
* ice_repr_rem_vf - remove representor from VF
* @repr: pointer to representor structure
*/
void ice_repr_rem_vf(struct ice_repr *repr)
static void ice_repr_rem_vf(struct ice_repr *repr)
{
ice_repr_remove_node(&repr->vf->devlink_port);
ice_eswitch_decfg_vsi(repr->src_vsi, repr->parent_mac);
unregister_netdev(repr->netdev);
ice_devlink_destroy_vf_port(repr->vf);
ice_virtchnl_set_dflt_ops(repr->vf);
ice_repr_rem(repr);
}
static void ice_repr_set_tx_topology(struct ice_pf *pf)
static void ice_repr_rem_sf(struct ice_repr *repr)
{
struct devlink *devlink;
unregister_netdev(repr->netdev);
ice_devlink_destroy_sf_port(repr->sf);
}
static void ice_repr_set_tx_topology(struct ice_pf *pf, struct devlink *devlink)
{
/* only export if ADQ and DCB disabled and eswitch enabled*/
if (ice_is_adq_active(pf) || ice_is_dcb_active(pf) ||
!ice_is_switchdev_running(pf))
return;
devlink = priv_to_devlink(pf);
ice_devlink_rate_init_tx_topology(devlink, ice_get_main_vsi(pf));
}
/**
* ice_repr_add - add representor for generic VSI
* @pf: pointer to PF structure
* ice_repr_create - add representor for generic VSI
* @src_vsi: pointer to VSI structure of device to represent
* @parent_mac: device MAC address
*/
static struct ice_repr *
ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac)
static struct ice_repr *ice_repr_create(struct ice_vsi *src_vsi)
{
struct ice_netdev_priv *np;
struct ice_repr *repr;
......@@ -360,7 +388,10 @@ ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac)
np = netdev_priv(repr->netdev);
np->repr = repr;
ether_addr_copy(repr->parent_mac, parent_mac);
repr->netdev->min_mtu = ETH_MIN_MTU;
repr->netdev->max_mtu = ICE_MAX_MTU;
SET_NETDEV_DEV(repr->netdev, ice_pf_to_dev(src_vsi->back));
return repr;
......@@ -371,34 +402,18 @@ ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac)
return ERR_PTR(err);
}
struct ice_repr *ice_repr_add_vf(struct ice_vf *vf)
static int ice_repr_add_vf(struct ice_repr *repr)
{
struct ice_repr *repr;
struct ice_vsi *vsi;
struct ice_vf *vf = repr->vf;
struct devlink *devlink;
int err;
vsi = ice_get_vf_vsi(vf);
if (!vsi)
return ERR_PTR(-ENOENT);
err = ice_devlink_create_vf_port(vf);
if (err)
return ERR_PTR(err);
repr = ice_repr_add(vf->pf, vsi, vf->hw_lan_addr);
if (IS_ERR(repr)) {
err = PTR_ERR(repr);
goto err_repr_add;
}
repr->vf = vf;
repr->netdev->min_mtu = ETH_MIN_MTU;
repr->netdev->max_mtu = ICE_MAX_MTU;
return err;
SET_NETDEV_DEV(repr->netdev, ice_pf_to_dev(vf->pf));
SET_NETDEV_DEVLINK_PORT(repr->netdev, &vf->devlink_port);
err = ice_repr_reg_netdev(repr->netdev);
err = ice_repr_reg_netdev(repr->netdev, &ice_repr_vf_netdev_ops);
if (err)
goto err_netdev;
......@@ -407,17 +422,97 @@ struct ice_repr *ice_repr_add_vf(struct ice_vf *vf)
goto err_cfg_vsi;
ice_virtchnl_set_repr_ops(vf);
ice_repr_set_tx_topology(vf->pf);
return repr;
devlink = priv_to_devlink(vf->pf);
ice_repr_set_tx_topology(vf->pf, devlink);
return 0;
err_cfg_vsi:
unregister_netdev(repr->netdev);
err_netdev:
ice_repr_rem(repr);
err_repr_add:
ice_devlink_destroy_vf_port(vf);
return ERR_PTR(err);
return err;
}
/**
* ice_repr_create_vf - add representor for VF VSI
* @vf: VF to create port representor on
*
* Set correct representor type for VF and functions pointer.
*
* Return: created port representor on success, error otherwise
*/
struct ice_repr *ice_repr_create_vf(struct ice_vf *vf)
{
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_repr *repr;
if (!vsi)
return ERR_PTR(-EINVAL);
repr = ice_repr_create(vsi);
if (!repr)
return ERR_PTR(-ENOMEM);
repr->type = ICE_REPR_TYPE_VF;
repr->vf = vf;
repr->ops.add = ice_repr_add_vf;
repr->ops.rem = ice_repr_rem_vf;
repr->ops.ready = ice_repr_ready_vf;
ether_addr_copy(repr->parent_mac, vf->hw_lan_addr);
return repr;
}
static int ice_repr_add_sf(struct ice_repr *repr)
{
struct ice_dynamic_port *sf = repr->sf;
int err;
err = ice_devlink_create_sf_port(sf);
if (err)
return err;
SET_NETDEV_DEVLINK_PORT(repr->netdev, &sf->devlink_port);
err = ice_repr_reg_netdev(repr->netdev, &ice_repr_sf_netdev_ops);
if (err)
goto err_netdev;
ice_repr_set_tx_topology(sf->vsi->back, priv_to_devlink(sf->vsi->back));
return 0;
err_netdev:
ice_devlink_destroy_sf_port(sf);
return err;
}
/**
* ice_repr_create_sf - add representor for SF VSI
* @sf: SF to create port representor on
*
* Set correct representor type for SF and functions pointer.
*
* Return: created port representor on success, error otherwise
*/
struct ice_repr *ice_repr_create_sf(struct ice_dynamic_port *sf)
{
struct ice_repr *repr = ice_repr_create(sf->vsi);
if (!repr)
return ERR_PTR(-ENOMEM);
repr->type = ICE_REPR_TYPE_SF;
repr->sf = sf;
repr->ops.add = ice_repr_add_sf;
repr->ops.rem = ice_repr_rem_sf;
repr->ops.ready = ice_repr_ready_sf;
ether_addr_copy(repr->parent_mac, sf->hw_addr);
return repr;
}
struct ice_repr *ice_repr_get(struct ice_pf *pf, u32 id)
......
......@@ -15,19 +15,35 @@ struct ice_repr_pcpu_stats {
u64 tx_drops;
};
enum ice_repr_type {
ICE_REPR_TYPE_VF,
ICE_REPR_TYPE_SF,
};
struct ice_repr {
struct ice_vsi *src_vsi;
struct ice_vf *vf;
struct net_device *netdev;
struct metadata_dst *dst;
struct ice_esw_br_port *br_port;
struct ice_repr_pcpu_stats __percpu *stats;
u32 id;
u8 parent_mac[ETH_ALEN];
enum ice_repr_type type;
union {
struct ice_vf *vf;
struct ice_dynamic_port *sf;
};
struct {
int (*add)(struct ice_repr *repr);
void (*rem)(struct ice_repr *repr);
int (*ready)(struct ice_repr *repr);
} ops;
};
struct ice_repr *ice_repr_add_vf(struct ice_vf *vf);
void ice_repr_rem_vf(struct ice_repr *repr);
struct ice_repr *ice_repr_create_vf(struct ice_vf *vf);
struct ice_repr *ice_repr_create_sf(struct ice_dynamic_port *sf);
void ice_repr_destroy(struct ice_repr *repr);
void ice_repr_start_tx_queues(struct ice_repr *repr);
void ice_repr_stop_tx_queues(struct ice_repr *repr);
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024, Intel Corporation. */
#include "ice.h"
#include "ice_lib.h"
#include "ice_txrx.h"
#include "ice_fltr.h"
#include "ice_sf_eth.h"
#include "devlink/devlink_port.h"
#include "devlink/devlink.h"
static const struct net_device_ops ice_sf_netdev_ops = {
.ndo_open = ice_open,
.ndo_stop = ice_stop,
.ndo_start_xmit = ice_start_xmit,
.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
.ndo_change_mtu = ice_change_mtu,
.ndo_get_stats64 = ice_get_stats64,
.ndo_tx_timeout = ice_tx_timeout,
.ndo_bpf = ice_xdp,
.ndo_xdp_xmit = ice_xdp_xmit,
.ndo_xsk_wakeup = ice_xsk_wakeup,
};
/**
* ice_sf_cfg_netdev - Allocate, configure and register a netdev
* @dyn_port: subfunction associated with configured netdev
* @devlink_port: subfunction devlink port to be linked with netdev
*
* Return: 0 on success, negative value on failure
*/
static int ice_sf_cfg_netdev(struct ice_dynamic_port *dyn_port,
struct devlink_port *devlink_port)
{
struct ice_vsi *vsi = dyn_port->vsi;
struct ice_netdev_priv *np;
struct net_device *netdev;
int err;
netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
vsi->alloc_rxq);
if (!netdev)
return -ENOMEM;
SET_NETDEV_DEV(netdev, &vsi->back->pdev->dev);
set_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
vsi->netdev = netdev;
np = netdev_priv(netdev);
np->vsi = vsi;
ice_set_netdev_features(netdev);
netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
NETDEV_XDP_ACT_XSK_ZEROCOPY |
NETDEV_XDP_ACT_RX_SG;
netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD;
eth_hw_addr_set(netdev, dyn_port->hw_addr);
ether_addr_copy(netdev->perm_addr, dyn_port->hw_addr);
netdev->netdev_ops = &ice_sf_netdev_ops;
SET_NETDEV_DEVLINK_PORT(netdev, devlink_port);
err = register_netdev(netdev);
if (err) {
free_netdev(netdev);
vsi->netdev = NULL;
return -ENOMEM;
}
set_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
return 0;
}
static void ice_sf_decfg_netdev(struct ice_vsi *vsi)
{
unregister_netdev(vsi->netdev);
clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
free_netdev(vsi->netdev);
vsi->netdev = NULL;
clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
}
/**
* ice_sf_dev_probe - subfunction driver probe function
* @adev: pointer to the auxiliary device
* @id: pointer to the auxiliary_device id
*
* Configure VSI and netdev resources for the subfunction device.
*
* Return: zero on success or an error code on failure.
*/
static int ice_sf_dev_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
struct ice_dynamic_port *dyn_port = sf_dev->dyn_port;
struct ice_vsi *vsi = dyn_port->vsi;
struct ice_pf *pf = dyn_port->pf;
struct device *dev = &adev->dev;
struct ice_sf_priv *priv;
struct devlink *devlink;
int err;
vsi->type = ICE_VSI_SF;
vsi->port_info = pf->hw.port_info;
vsi->flags = ICE_VSI_FLAG_INIT;
priv = ice_allocate_sf(&adev->dev, pf);
if (!priv) {
dev_err(dev, "Subfunction devlink alloc failed");
return -ENOMEM;
}
priv->dev = sf_dev;
sf_dev->priv = priv;
devlink = priv_to_devlink(priv);
devl_lock(devlink);
err = ice_vsi_cfg(vsi);
if (err) {
dev_err(dev, "Subfunction vsi config failed");
goto err_free_devlink;
}
vsi->sf = dyn_port;
ice_eswitch_update_repr(&dyn_port->repr_id, vsi);
err = ice_devlink_create_sf_dev_port(sf_dev);
if (err) {
dev_err(dev, "Cannot add ice virtual devlink port for subfunction");
goto err_vsi_decfg;
}
err = ice_sf_cfg_netdev(dyn_port, &sf_dev->priv->devlink_port);
if (err) {
dev_err(dev, "Subfunction netdev config failed");
goto err_devlink_destroy;
}
err = devl_port_fn_devlink_set(&dyn_port->devlink_port, devlink);
if (err) {
dev_err(dev, "Can't link devlink instance to SF devlink port");
goto err_netdev_decfg;
}
ice_napi_add(vsi);
devl_register(devlink);
devl_unlock(devlink);
dyn_port->attached = true;
return 0;
err_netdev_decfg:
ice_sf_decfg_netdev(vsi);
err_devlink_destroy:
ice_devlink_destroy_sf_dev_port(sf_dev);
err_vsi_decfg:
ice_vsi_decfg(vsi);
err_free_devlink:
devl_unlock(devlink);
devlink_free(devlink);
return err;
}
/**
* ice_sf_dev_remove - subfunction driver remove function
* @adev: pointer to the auxiliary device
*
* Deinitalize VSI and netdev resources for the subfunction device.
*/
static void ice_sf_dev_remove(struct auxiliary_device *adev)
{
struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
struct ice_dynamic_port *dyn_port = sf_dev->dyn_port;
struct ice_vsi *vsi = dyn_port->vsi;
struct devlink *devlink;
devlink = priv_to_devlink(sf_dev->priv);
devl_lock(devlink);
ice_vsi_close(vsi);
ice_sf_decfg_netdev(vsi);
ice_devlink_destroy_sf_dev_port(sf_dev);
devl_unregister(devlink);
devl_unlock(devlink);
devlink_free(devlink);
ice_vsi_decfg(vsi);
dyn_port->attached = false;
}
static const struct auxiliary_device_id ice_sf_dev_id_table[] = {
{ .name = "ice.sf", },
{ },
};
MODULE_DEVICE_TABLE(auxiliary, ice_sf_dev_id_table);
static struct auxiliary_driver ice_sf_driver = {
.name = "sf",
.probe = ice_sf_dev_probe,
.remove = ice_sf_dev_remove,
.id_table = ice_sf_dev_id_table
};
static DEFINE_XARRAY_ALLOC1(ice_sf_aux_id);
/**
* ice_sf_driver_register - Register new auxiliary subfunction driver
*
* Return: zero on success or an error code on failure.
*/
int ice_sf_driver_register(void)
{
return auxiliary_driver_register(&ice_sf_driver);
}
/**
* ice_sf_driver_unregister - Unregister new auxiliary subfunction driver
*
*/
void ice_sf_driver_unregister(void)
{
auxiliary_driver_unregister(&ice_sf_driver);
}
/**
* ice_sf_dev_release - Release device associated with auxiliary device
* @device: pointer to the device
*
* Since most of the code for subfunction deactivation is handled in
* the remove handler, here just free tracking resources.
*/
static void ice_sf_dev_release(struct device *device)
{
struct auxiliary_device *adev = to_auxiliary_dev(device);
struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
xa_erase(&ice_sf_aux_id, adev->id);
kfree(sf_dev);
}
/**
* ice_sf_eth_activate - Activate Ethernet subfunction port
* @dyn_port: the dynamic port instance for this subfunction
* @extack: extack for reporting error messages
*
* Activate the dynamic port as an Ethernet subfunction. Setup the netdev
* resources associated and initialize the auxiliary device.
*
* Return: zero on success or an error code on failure.
*/
int
ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = dyn_port->pf;
struct ice_sf_dev *sf_dev;
struct pci_dev *pdev;
int err;
u32 id;
err = xa_alloc(&ice_sf_aux_id, &id, NULL, xa_limit_32b,
GFP_KERNEL);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not allocate SF ID");
return err;
}
sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL);
if (!sf_dev) {
err = -ENOMEM;
NL_SET_ERR_MSG_MOD(extack, "Could not allocate SF memory");
goto xa_erase;
}
pdev = pf->pdev;
sf_dev->dyn_port = dyn_port;
sf_dev->adev.id = id;
sf_dev->adev.name = "sf";
sf_dev->adev.dev.release = ice_sf_dev_release;
sf_dev->adev.dev.parent = &pdev->dev;
err = auxiliary_device_init(&sf_dev->adev);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to initialize SF device");
goto sf_dev_free;
}
err = auxiliary_device_add(&sf_dev->adev);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to add SF device");
goto aux_dev_uninit;
}
dyn_port->sf_dev = sf_dev;
return 0;
aux_dev_uninit:
auxiliary_device_uninit(&sf_dev->adev);
sf_dev_free:
kfree(sf_dev);
xa_erase:
xa_erase(&ice_sf_aux_id, id);
return err;
}
/**
* ice_sf_eth_deactivate - Deactivate Ethernet subfunction port
* @dyn_port: the dynamic port instance for this subfunction
*
* Deactivate the Ethernet subfunction, removing its auxiliary device and the
* associated resources.
*/
void ice_sf_eth_deactivate(struct ice_dynamic_port *dyn_port)
{
struct ice_sf_dev *sf_dev = dyn_port->sf_dev;
auxiliary_device_delete(&sf_dev->adev);
auxiliary_device_uninit(&sf_dev->adev);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024, Intel Corporation. */
#ifndef _ICE_SF_ETH_H_
#define _ICE_SF_ETH_H_
#include <linux/auxiliary_bus.h>
#include "ice.h"
struct ice_sf_dev {
struct auxiliary_device adev;
struct ice_dynamic_port *dyn_port;
struct ice_sf_priv *priv;
};
struct ice_sf_priv {
struct ice_sf_dev *dev;
struct devlink_port devlink_port;
};
static inline struct
ice_sf_dev *ice_adev_to_sf_dev(struct auxiliary_device *adev)
{
return container_of(adev, struct ice_sf_dev, adev);
}
int ice_sf_driver_register(void);
void ice_sf_driver_unregister(void);
int ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
struct netlink_ext_ack *extack);
void ice_sf_eth_deactivate(struct ice_dynamic_port *dyn_port);
#endif /* _ICE_SF_ETH_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2023, Intel Corporation. */
#include "ice_vsi_vlan_ops.h"
#include "ice_vsi_vlan_lib.h"
#include "ice_vlan_mode.h"
#include "ice.h"
#include "ice_sf_vsi_vlan_ops.h"
void ice_sf_vsi_init_vlan_ops(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops;
if (ice_is_dvm_ena(&vsi->back->hw))
vlan_ops = &vsi->outer_vlan_ops;
else
vlan_ops = &vsi->inner_vlan_ops;
vlan_ops->add_vlan = ice_vsi_add_vlan;
vlan_ops->del_vlan = ice_vsi_del_vlan;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2023, Intel Corporation. */
#ifndef _ICE_SF_VSI_VLAN_OPS_H_
#define _ICE_SF_VSI_VLAN_OPS_H_
#include "ice_vsi_vlan_ops.h"
struct ice_vsi;
void ice_sf_vsi_init_vlan_ops(struct ice_vsi *vsi);
#endif /* _ICE_SF_VSI_VLAN_OPS_H_ */
......@@ -175,7 +175,7 @@ void ice_free_vfs(struct ice_pf *pf)
ice_for_each_vf(pf, bkt, vf) {
mutex_lock(&vf->cfg_lock);
ice_eswitch_detach(pf, vf);
ice_eswitch_detach_vf(pf, vf);
ice_dis_vf_qs(vf);
if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
......@@ -598,7 +598,7 @@ static int ice_start_vfs(struct ice_pf *pf)
goto teardown;
}
retval = ice_eswitch_attach(pf, vf);
retval = ice_eswitch_attach_vf(pf, vf);
if (retval) {
dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
vf->vf_id, retval);
......
......@@ -2368,7 +2368,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
ICE_TXD_CTX_QW1_CMD_S);
ice_tstamp(tx_ring, skb, first, &offload);
if (ice_is_switchdev_running(vsi->back))
if (ice_is_switchdev_running(vsi->back) && vsi->type != ICE_VSI_SF)
ice_eswitch_set_target_vsi(skb, &offload);
if (offload.cd_qw1 & ICE_TX_DESC_DTYPE_CTX) {
......
......@@ -159,6 +159,7 @@ enum ice_vsi_type {
ICE_VSI_CTRL = 3, /* equates to ICE_VSI_PF with 1 queue pair */
ICE_VSI_CHNL = 4,
ICE_VSI_LB = 6,
ICE_VSI_SF = 9,
};
struct ice_link_status {
......
......@@ -766,7 +766,7 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_for_each_vf(pf, bkt, vf) {
mutex_lock(&vf->cfg_lock);
ice_eswitch_detach(pf, vf);
ice_eswitch_detach_vf(pf, vf);
vf->driver_caps = 0;
ice_vc_set_default_allowlist(vf);
......@@ -782,7 +782,7 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_vf_rebuild_vsi(vf);
ice_vf_post_vsi_rebuild(vf);
ice_eswitch_attach(pf, vf);
ice_eswitch_attach_vf(pf, vf);
mutex_unlock(&vf->cfg_lock);
}
......
......@@ -3,6 +3,7 @@
#include "ice_pf_vsi_vlan_ops.h"
#include "ice_vf_vsi_vlan_ops.h"
#include "ice_sf_vsi_vlan_ops.h"
#include "ice_lib.h"
#include "ice.h"
......@@ -77,6 +78,9 @@ void ice_vsi_init_vlan_ops(struct ice_vsi *vsi)
case ICE_VSI_VF:
ice_vf_vsi_init_vlan_ops(vsi);
break;
case ICE_VSI_SF:
ice_sf_vsi_init_vlan_ops(vsi);
break;
default:
dev_dbg(ice_pf_to_dev(vsi->back), "%s does not support VLAN operations\n",
ice_vsi_type_str(vsi->type));
......
......@@ -289,7 +289,7 @@ ice_xsk_pool_enable(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid)
{
int err;
if (vsi->type != ICE_VSI_PF)
if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_SF)
return -EINVAL;
if (qid >= vsi->netdev->real_num_rx_queues ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment