Skip to content

Commit

Permalink
ice: subfunction activation and base devlink ops
Browse files Browse the repository at this point in the history
Use previously implemented SF aux driver. It is probe during SF
activation and remove after deactivation.

Implement set/get hw_address and set/get state as basic devlink ops for
subfunction.

Reviewed-by: Simon Horman <horms@kernel.org>
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>
  • Loading branch information
Piotr Raczynski authored and Tony Nguyen committed Sep 6, 2024
1 parent 0c6a3cb commit 13acc5c
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 0 deletions.
176 changes: 176 additions & 0 deletions drivers/net/ethernet/intel/ice/devlink/devlink_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,48 @@ 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
Expand All @@ -542,6 +584,8 @@ 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);
Expand Down Expand Up @@ -629,8 +673,140 @@ ice_devlink_port_del(struct devlink *devlink, struct devlink_port *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,
};

/**
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/intel/ice/devlink/devlink_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,29 @@
* 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);
Expand Down
104 changes: 104 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_sf_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ static int ice_sf_dev_probe(struct auxiliary_device *adev,
devl_register(devlink);
devl_unlock(devlink);

dyn_port->attached = true;

return 0;

err_netdev_decfg:
Expand Down Expand Up @@ -189,6 +191,8 @@ static void ice_sf_dev_remove(struct auxiliary_device *adev)
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[] = {
Expand All @@ -205,6 +209,8 @@ static struct auxiliary_driver ice_sf_driver = {
.id_table = ice_sf_dev_id_table
};

static DEFINE_XARRAY_ALLOC1(ice_sf_aux_id);

/**
* ice_sf_driver_register - Register new auxiliary subfunction driver
*
Expand All @@ -223,3 +229,101 @@ 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);
}
3 changes: 3 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_sf_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ ice_sf_dev *ice_adev_to_sf_dev(struct auxiliary_device *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_ */

0 comments on commit 13acc5c

Please sign in to comment.