Message ID | 20240417142028.2171-9-michal.swiatkowski@linux.intel.com (mailing list archive) |
---|---|
State | Awaiting Upstream |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | ice: support devlink subfunction | expand |
resend as plain test On 18/04/2024 10:53, Shay Drori wrote: > On 17/04/2024 17:20, Michal Swiatkowski wrote: >> +/** >> + * 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; >> + *opstate = DEVLINK_PORT_FN_OPSTATE_ATTACHED; > > > DEVLINK_PORT_FN_OPSTATE_ATTACHED means the SF is up/bind[1]. > ice is using auxiliary bus for SFs, which means user can unbind it > via the auxiliary sysfs (/sys/bus/auxiliary/drivers/ice_sf/unbind). > In this case[2], you need to return: > *state = DEVLINK_PORT_FN_STATE_ACTIVE; > *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; > > > [1] > Documentation from include/uapi/linux/devlink.h: > > * @DEVLINK_PORT_FN_OPSTATE_ATTACHED: Driver is attached to the function. > <...> > * @DEVLINK_PORT_FN_OPSTATE_DETACHED: Driver is detached from the function. > >> + } else { >> + *state = DEVLINK_PORT_FN_STATE_INACTIVE; >> + *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; >> + } >> + >> + return 0; >> +} >> +
On Thu, Apr 18, 2024 at 11:12:47AM +0300, Shay Drori wrote: > resend as plain test > > On 18/04/2024 10:53, Shay Drori wrote: > > On 17/04/2024 17:20, Michal Swiatkowski wrote: > > > +/** > > > + * 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; > > > + *opstate = DEVLINK_PORT_FN_OPSTATE_ATTACHED; > > > > > > DEVLINK_PORT_FN_OPSTATE_ATTACHED means the SF is up/bind[1]. > > ice is using auxiliary bus for SFs, which means user can unbind it > > via the auxiliary sysfs (/sys/bus/auxiliary/drivers/ice_sf/unbind). > > In this case[2], you need to return: > > *state = DEVLINK_PORT_FN_STATE_ACTIVE; > > *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; > > Thanks, I didn't think about unbinding/binding the aux driver via sysfs. To be sure: - user create the subfunction: INACTIVE, DETACHED - user activate it: ACTIVE, ATTACHED - user unbind driver: ACTIVE, DETACHED - user can bind it again as long as subfunction port is ACTIVE is it right? I will fix the comment from previous patch and add state tracking for ATTACHED/DETACHED. Thanks, Michal > > > > [1] > > Documentation from include/uapi/linux/devlink.h: > > > > * @DEVLINK_PORT_FN_OPSTATE_ATTACHED: Driver is attached to the function. > > <...> > > * @DEVLINK_PORT_FN_OPSTATE_DETACHED: Driver is detached from the function. > > > > > + } else { > > > + *state = DEVLINK_PORT_FN_STATE_INACTIVE; > > > + *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; > > > + } > > > + > > > + return 0; > > > +} > > > +
On 18/04/2024 14:55, Michal Swiatkowski wrote: > External email: Use caution opening links or attachments > > > On Thu, Apr 18, 2024 at 11:12:47AM +0300, Shay Drori wrote: >> resend as plain test >> >> On 18/04/2024 10:53, Shay Drori wrote: >>> On 17/04/2024 17:20, Michal Swiatkowski wrote: >>>> +/** >>>> + * 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; >>>> + *opstate = DEVLINK_PORT_FN_OPSTATE_ATTACHED; >>> >>> >>> DEVLINK_PORT_FN_OPSTATE_ATTACHED means the SF is up/bind[1]. >>> ice is using auxiliary bus for SFs, which means user can unbind it >>> via the auxiliary sysfs (/sys/bus/auxiliary/drivers/ice_sf/unbind). >>> In this case[2], you need to return: >>> *state = DEVLINK_PORT_FN_STATE_ACTIVE; >>> *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; >>> > > Thanks, I didn't think about unbinding/binding the aux driver via sysfs. > > To be sure: > - user create the subfunction: > INACTIVE, DETACHED > - user activate it: > ACTIVE, ATTACHED > - user unbind driver: > ACTIVE, DETACHED > - user can bind it again as long as subfunction port is ACTIVE > is it right? yes. > > I will fix the comment from previous patch and add state tracking for > ATTACHED/DETACHED. > > Thanks, > Michal > >>> >>> [1] >>> Documentation from include/uapi/linux/devlink.h: >>> >>> * @DEVLINK_PORT_FN_OPSTATE_ATTACHED: Driver is attached to the function. >>> <...> >>> * @DEVLINK_PORT_FN_OPSTATE_DETACHED: Driver is detached from the function. >>> >>>> + } else { >>>> + *state = DEVLINK_PORT_FN_STATE_INACTIVE; >>>> + *opstate = DEVLINK_PORT_FN_OPSTATE_DETACHED; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> +
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c index 0ab4d687e311..efff286f9e3e 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c @@ -482,6 +482,42 @@ 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; + + 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) +{ + 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 @@ -494,6 +530,9 @@ 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; + if (dyn_port->active) + ice_deactivate_dynamic_port(dyn_port); + xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf); devl_port_unregister(devlink_port); ice_vsi_free(dyn_port->vsi); @@ -638,10 +677,77 @@ ice_devlink_port_fn_hw_addr_get(struct devlink_port *port, u8 *hw_addr, 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: + if (!dyn_port->active) + return ice_activate_dynamic_port(dyn_port, extack); + break; + case DEVLINK_PORT_FN_STATE_INACTIVE: + if (dyn_port->active) + 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; + *opstate = DEVLINK_PORT_FN_OPSTATE_ATTACHED; + } else { + *state = DEVLINK_PORT_FN_STATE_INACTIVE; + *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, }; /** diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.h b/drivers/net/ethernet/intel/ice/devlink/devlink_port.h index 33f07cec6bd6..3692b8617bd5 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink_port.h +++ b/drivers/net/ethernet/intel/ice/devlink/devlink_port.h @@ -14,6 +14,7 @@ * @devlink_port: the associated devlink port structure * @pf: pointer to the PF private structure * @vsi: the VSI associated with this port + * @sf_dev: pointer to the subfunction device * * An instance of a dynamically added devlink port. Each port flavour */ @@ -23,6 +24,10 @@ struct ice_dynamic_port { struct devlink_port devlink_port; struct ice_pf *pf; struct ice_vsi *vsi; + /* Flavour-specific implementation data */ + union { + struct ice_sf_dev *sf_dev; + }; }; void ice_dealloc_all_dynamic_ports(struct ice_pf *pf); diff --git a/drivers/net/ethernet/intel/ice/ice_sf_eth.c b/drivers/net/ethernet/intel/ice/ice_sf_eth.c index ecef869c20a1..663bfdcf68b5 100644 --- a/drivers/net/ethernet/intel/ice/ice_sf_eth.c +++ b/drivers/net/ethernet/intel/ice/ice_sf_eth.c @@ -202,6 +202,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 * @@ -221,3 +223,105 @@ 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 subfunction 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_dev 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 auxiliary device"); + goto sf_dev_free; + } + + err = auxiliary_device_add(&sf_dev->adev); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Auxiliary device failed to probe"); + 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; + + if (sf_dev) { + auxiliary_device_delete(&sf_dev->adev); + auxiliary_device_uninit(&sf_dev->adev); + } + + dyn_port->sf_dev = NULL; +} diff --git a/drivers/net/ethernet/intel/ice/ice_sf_eth.h b/drivers/net/ethernet/intel/ice/ice_sf_eth.h index e972c50f96c9..c558cad0a183 100644 --- a/drivers/net/ethernet/intel/ice/ice_sf_eth.h +++ b/drivers/net/ethernet/intel/ice/ice_sf_eth.h @@ -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_ */