ice: rename devlink_port.[ch] to port.[ch]
authorPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Mon, 16 Dec 2024 14:15:33 +0000 (15:15 +0100)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Tue, 17 Dec 2024 17:32:08 +0000 (09:32 -0800)
Drop "devlink_" prefix from files that sit in devlink/.
I'm going to add more files there, and repeating "devlink" does not feel
good. This is also the scheme used in most other places, most notably the
devlink core files are named like that.

devlink.[ch] stays as is.

Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/Makefile
drivers/net/ethernet/intel/ice/devlink/devlink.c
drivers/net/ethernet/intel/ice/devlink/devlink_port.c [deleted file]
drivers/net/ethernet/intel/ice/devlink/devlink_port.h [deleted file]
drivers/net/ethernet/intel/ice/devlink/port.c [new file with mode: 0644]
drivers/net/ethernet/intel/ice/devlink/port.h [new file with mode: 0644]
drivers/net/ethernet/intel/ice/ice_eswitch.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_repr.c
drivers/net/ethernet/intel/ice/ice_sf_eth.c

index 3307d551f431a49ebb9b7e6713eb2469c8aa7c08..56aa23aee472b997d712f70a37fa4f74e2179533 100644 (file)
@@ -32,7 +32,7 @@ ice-y := ice_main.o   \
         ice_parser_rt.o \
         ice_idc.o      \
         devlink/devlink.o      \
-        devlink/devlink_port.o \
+        devlink/port.o \
         ice_sf_eth.o   \
         ice_sf_vsi_vlan_ops.o \
         ice_ddp.o      \
index 415445cefdb2aa0c17d98dd0d61bb2b9fc945a24..1b10682c00b8ad5f5434da0840b3e5d4adaa52d2 100644 (file)
@@ -6,7 +6,7 @@
 #include "ice.h"
 #include "ice_lib.h"
 #include "devlink.h"
-#include "devlink_port.h"
+#include "port.h"
 #include "ice_eswitch.h"
 #include "ice_fw_update.h"
 #include "ice_dcb_lib.h"
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
deleted file mode 100644 (file)
index c6779d9..0000000
+++ /dev/null
@@ -1,999 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2024, Intel Corporation. */
-
-#include <linux/vmalloc.h>
-
-#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;
-
-/**
- * ice_devlink_port_opt_speed_str - convert speed to a string
- * @speed: speed value
- */
-static const char *ice_devlink_port_opt_speed_str(u8 speed)
-{
-       switch (speed & ICE_AQC_PORT_OPT_MAX_LANE_M) {
-       case ICE_AQC_PORT_OPT_MAX_LANE_100M:
-               return "0.1";
-       case ICE_AQC_PORT_OPT_MAX_LANE_1G:
-               return "1";
-       case ICE_AQC_PORT_OPT_MAX_LANE_2500M:
-               return "2.5";
-       case ICE_AQC_PORT_OPT_MAX_LANE_5G:
-               return "5";
-       case ICE_AQC_PORT_OPT_MAX_LANE_10G:
-               return "10";
-       case ICE_AQC_PORT_OPT_MAX_LANE_25G:
-               return "25";
-       case ICE_AQC_PORT_OPT_MAX_LANE_50G:
-               return "50";
-       case ICE_AQC_PORT_OPT_MAX_LANE_100G:
-               return "100";
-       }
-
-       return "-";
-}
-
-#define ICE_PORT_OPT_DESC_LEN  50
-/**
- * ice_devlink_port_options_print - Print available port split options
- * @pf: the PF to print split port options
- *
- * Prints a table with available port split options and max port speeds
- */
-static void ice_devlink_port_options_print(struct ice_pf *pf)
-{
-       u8 i, j, options_count, cnt, speed, pending_idx, active_idx;
-       struct ice_aqc_get_port_options_elem *options, *opt;
-       struct device *dev = ice_pf_to_dev(pf);
-       bool active_valid, pending_valid;
-       char desc[ICE_PORT_OPT_DESC_LEN];
-       const char *str;
-       int status;
-
-       options = kcalloc(ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV,
-                         sizeof(*options), GFP_KERNEL);
-       if (!options)
-               return;
-
-       for (i = 0; i < ICE_MAX_PORT_PER_PCI_DEV; i++) {
-               opt = options + i * ICE_AQC_PORT_OPT_MAX;
-               options_count = ICE_AQC_PORT_OPT_MAX;
-               active_valid = 0;
-
-               status = ice_aq_get_port_options(&pf->hw, opt, &options_count,
-                                                i, true, &active_idx,
-                                                &active_valid, &pending_idx,
-                                                &pending_valid);
-               if (status) {
-                       dev_dbg(dev, "Couldn't read port option for port %d, err %d\n",
-                               i, status);
-                       goto err;
-               }
-       }
-
-       dev_dbg(dev, "Available port split options and max port speeds (Gbps):\n");
-       dev_dbg(dev, "Status  Split      Quad 0          Quad 1\n");
-       dev_dbg(dev, "        count  L0  L1  L2  L3  L4  L5  L6  L7\n");
-
-       for (i = 0; i < options_count; i++) {
-               cnt = 0;
-
-               if (i == ice_active_port_option)
-                       str = "Active";
-               else if ((i == pending_idx) && pending_valid)
-                       str = "Pending";
-               else
-                       str = "";
-
-               cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
-                               "%-8s", str);
-
-               cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
-                               "%-6u", options[i].pmd);
-
-               for (j = 0; j < ICE_MAX_PORT_PER_PCI_DEV; ++j) {
-                       speed = options[i + j * ICE_AQC_PORT_OPT_MAX].max_lane_speed;
-                       str = ice_devlink_port_opt_speed_str(speed);
-                       cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
-                                       "%3s ", str);
-               }
-
-               dev_dbg(dev, "%s\n", desc);
-       }
-
-err:
-       kfree(options);
-}
-
-/**
- * ice_devlink_aq_set_port_option - Send set port option admin queue command
- * @pf: the PF to print split port options
- * @option_idx: selected port option
- * @extack: extended netdev ack structure
- *
- * Sends set port option admin queue command with selected port option and
- * calls NVM write activate.
- */
-static int
-ice_devlink_aq_set_port_option(struct ice_pf *pf, u8 option_idx,
-                              struct netlink_ext_ack *extack)
-{
-       struct device *dev = ice_pf_to_dev(pf);
-       int status;
-
-       status = ice_aq_set_port_option(&pf->hw, 0, true, option_idx);
-       if (status) {
-               dev_dbg(dev, "ice_aq_set_port_option, err %d aq_err %d\n",
-                       status, pf->hw.adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Port split request failed");
-               return -EIO;
-       }
-
-       status = ice_acquire_nvm(&pf->hw, ICE_RES_WRITE);
-       if (status) {
-               dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
-                       status, pf->hw.adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
-               return -EIO;
-       }
-
-       status = ice_nvm_write_activate(&pf->hw, ICE_AQC_NVM_ACTIV_REQ_EMPR, NULL);
-       if (status) {
-               dev_dbg(dev, "ice_nvm_write_activate failed, err %d aq_err %d\n",
-                       status, pf->hw.adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Port split request failed to save data");
-               ice_release_nvm(&pf->hw);
-               return -EIO;
-       }
-
-       ice_release_nvm(&pf->hw);
-
-       NL_SET_ERR_MSG_MOD(extack, "Reboot required to finish port split");
-       return 0;
-}
-
-/**
- * ice_devlink_port_split - .port_split devlink handler
- * @devlink: devlink instance structure
- * @port: devlink port structure
- * @count: number of ports to split to
- * @extack: extended netdev ack structure
- *
- * Callback for the devlink .port_split operation.
- *
- * Unfortunately, the devlink expression of available options is limited
- * to just a number, so search for an FW port option which supports
- * the specified number. As there could be multiple FW port options with
- * the same port split count, allow switching between them. When the same
- * port split count request is issued again, switch to the next FW port
- * option with the same port split count.
- *
- * Return: zero on success or an error code on failure.
- */
-static int
-ice_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
-                      unsigned int count, struct netlink_ext_ack *extack)
-{
-       struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
-       u8 i, j, active_idx, pending_idx, new_option;
-       struct ice_pf *pf = devlink_priv(devlink);
-       u8 option_count = ICE_AQC_PORT_OPT_MAX;
-       struct device *dev = ice_pf_to_dev(pf);
-       bool active_valid, pending_valid;
-       int status;
-
-       status = ice_aq_get_port_options(&pf->hw, options, &option_count,
-                                        0, true, &active_idx, &active_valid,
-                                        &pending_idx, &pending_valid);
-       if (status) {
-               dev_dbg(dev, "Couldn't read port split options, err = %d\n",
-                       status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to get available port split options");
-               return -EIO;
-       }
-
-       new_option = ICE_AQC_PORT_OPT_MAX;
-       active_idx = pending_valid ? pending_idx : active_idx;
-       for (i = 1; i <= option_count; i++) {
-               /* In order to allow switching between FW port options with
-                * the same port split count, search for a new option starting
-                * from the active/pending option (with array wrap around).
-                */
-               j = (active_idx + i) % option_count;
-
-               if (count == options[j].pmd) {
-                       new_option = j;
-                       break;
-               }
-       }
-
-       if (new_option == active_idx) {
-               dev_dbg(dev, "request to split: count: %u is already set and there are no other options\n",
-                       count);
-               NL_SET_ERR_MSG_MOD(extack, "Requested split count is already set");
-               ice_devlink_port_options_print(pf);
-               return -EINVAL;
-       }
-
-       if (new_option == ICE_AQC_PORT_OPT_MAX) {
-               dev_dbg(dev, "request to split: count: %u not found\n", count);
-               NL_SET_ERR_MSG_MOD(extack, "Port split requested unsupported port config");
-               ice_devlink_port_options_print(pf);
-               return -EINVAL;
-       }
-
-       status = ice_devlink_aq_set_port_option(pf, new_option, extack);
-       if (status)
-               return status;
-
-       ice_devlink_port_options_print(pf);
-
-       return 0;
-}
-
-/**
- * ice_devlink_port_unsplit - .port_unsplit devlink handler
- * @devlink: devlink instance structure
- * @port: devlink port structure
- * @extack: extended netdev ack structure
- *
- * Callback for the devlink .port_unsplit operation.
- * Calls ice_devlink_port_split with split count set to 1.
- * There could be no FW option available with split count 1.
- *
- * Return: zero on success or an error code on failure.
- */
-static int
-ice_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
-                        struct netlink_ext_ack *extack)
-{
-       return ice_devlink_port_split(devlink, port, 1, extack);
-}
-
-/**
- * ice_devlink_set_port_split_options - Set port split options
- * @pf: the PF to set port split options
- * @attrs: devlink attributes
- *
- * Sets devlink port split options based on available FW port options
- */
-static void
-ice_devlink_set_port_split_options(struct ice_pf *pf,
-                                  struct devlink_port_attrs *attrs)
-{
-       struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
-       u8 i, active_idx, pending_idx, option_count = ICE_AQC_PORT_OPT_MAX;
-       bool active_valid, pending_valid;
-       int status;
-
-       status = ice_aq_get_port_options(&pf->hw, options, &option_count,
-                                        0, true, &active_idx, &active_valid,
-                                        &pending_idx, &pending_valid);
-       if (status) {
-               dev_dbg(ice_pf_to_dev(pf), "Couldn't read port split options, err = %d\n",
-                       status);
-               return;
-       }
-
-       /* find the biggest available port split count */
-       for (i = 0; i < option_count; i++)
-               attrs->lanes = max_t(int, attrs->lanes, options[i].pmd);
-
-       attrs->splittable = attrs->lanes ? 1 : 0;
-       ice_active_port_option = active_idx;
-}
-
-static const struct devlink_port_ops ice_devlink_port_ops = {
-       .port_split = ice_devlink_port_split,
-       .port_unsplit = ice_devlink_port_unsplit,
-};
-
-/**
- * ice_devlink_set_switch_id - Set unique switch id based on pci dsn
- * @pf: the PF to create a devlink port for
- * @ppid: struct with switch id information
- */
-static void
-ice_devlink_set_switch_id(struct ice_pf *pf, struct netdev_phys_item_id *ppid)
-{
-       struct pci_dev *pdev = pf->pdev;
-       u64 id;
-
-       id = pci_get_dsn(pdev);
-
-       ppid->id_len = sizeof(id);
-       put_unaligned_be64(id, &ppid->id);
-}
-
-/**
- * ice_devlink_create_pf_port - Create a devlink port for this PF
- * @pf: the PF to create a devlink port for
- *
- * Create and register a devlink_port for this PF.
- * This function has to be called under devl_lock.
- *
- * Return: zero on success or an error code on failure.
- */
-int ice_devlink_create_pf_port(struct ice_pf *pf)
-{
-       struct devlink_port_attrs attrs = {};
-       struct devlink_port *devlink_port;
-       struct devlink *devlink;
-       struct ice_vsi *vsi;
-       struct device *dev;
-       int err;
-
-       devlink = priv_to_devlink(pf);
-
-       dev = ice_pf_to_dev(pf);
-
-       devlink_port = &pf->devlink_port;
-
-       vsi = ice_get_main_vsi(pf);
-       if (!vsi)
-               return -EIO;
-
-       attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
-       attrs.phys.port_number = pf->hw.pf_id;
-
-       /* As FW supports only port split options for whole device,
-        * set port split options only for first PF.
-        */
-       if (pf->hw.pf_id == 0)
-               ice_devlink_set_port_split_options(pf, &attrs);
-
-       ice_devlink_set_switch_id(pf, &attrs.switch_id);
-
-       devlink_port_attrs_set(devlink_port, &attrs);
-
-       err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
-                                         &ice_devlink_port_ops);
-       if (err) {
-               dev_err(dev, "Failed to create devlink port for PF %d, error %d\n",
-                       pf->hw.pf_id, err);
-               return err;
-       }
-
-       return 0;
-}
-
-/**
- * ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF
- * @pf: the PF to cleanup
- *
- * Unregisters the devlink_port structure associated with this PF.
- * This function has to be called under devl_lock.
- */
-void ice_devlink_destroy_pf_port(struct ice_pf *pf)
-{
-       devl_port_unregister(&pf->devlink_port);
-}
-
-/**
- * ice_devlink_port_get_vf_fn_mac - .port_fn_hw_addr_get devlink handler
- * @port: devlink port structure
- * @hw_addr: MAC address of the port
- * @hw_addr_len: length of MAC address
- * @extack: extended netdev ack structure
- *
- * Callback for the devlink .port_fn_hw_addr_get operation
- * Return: zero on success or an error code on failure.
- */
-static int ice_devlink_port_get_vf_fn_mac(struct devlink_port *port,
-                                         u8 *hw_addr, int *hw_addr_len,
-                                         struct netlink_ext_ack *extack)
-{
-       struct ice_vf *vf = container_of(port, struct ice_vf, devlink_port);
-
-       ether_addr_copy(hw_addr, vf->dev_lan_addr);
-       *hw_addr_len = ETH_ALEN;
-
-       return 0;
-}
-
-/**
- * ice_devlink_port_set_vf_fn_mac - .port_fn_hw_addr_set devlink handler
- * @port: devlink port structure
- * @hw_addr: MAC address of the port
- * @hw_addr_len: length of MAC address
- * @extack: extended netdev ack structure
- *
- * Callback for the devlink .port_fn_hw_addr_set operation
- * Return: zero on success or an error code on failure.
- */
-static int ice_devlink_port_set_vf_fn_mac(struct devlink_port *port,
-                                         const u8 *hw_addr,
-                                         int hw_addr_len,
-                                         struct netlink_ext_ack *extack)
-
-{
-       struct devlink_port_attrs *attrs = &port->attrs;
-       struct devlink_port_pci_vf_attrs *pci_vf;
-       struct devlink *devlink = port->devlink;
-       struct ice_pf *pf;
-       u16 vf_id;
-
-       pf = devlink_priv(devlink);
-       pci_vf = &attrs->pci_vf;
-       vf_id = pci_vf->vf;
-
-       return __ice_set_vf_mac(pf, vf_id, hw_addr);
-}
-
-static const struct devlink_port_ops ice_devlink_vf_port_ops = {
-       .port_fn_hw_addr_get = ice_devlink_port_get_vf_fn_mac,
-       .port_fn_hw_addr_set = ice_devlink_port_set_vf_fn_mac,
-};
-
-/**
- * ice_devlink_create_vf_port - Create a devlink port for this VF
- * @vf: the VF to create a port for
- *
- * Create and register a devlink_port for this VF.
- *
- * Return: zero on success or an error code on failure.
- */
-int ice_devlink_create_vf_port(struct ice_vf *vf)
-{
-       struct devlink_port_attrs attrs = {};
-       struct devlink_port *devlink_port;
-       struct devlink *devlink;
-       struct ice_vsi *vsi;
-       struct device *dev;
-       struct ice_pf *pf;
-       int err;
-
-       pf = vf->pf;
-       dev = ice_pf_to_dev(pf);
-       devlink_port = &vf->devlink_port;
-
-       vsi = ice_get_vf_vsi(vf);
-       if (!vsi)
-               return -EINVAL;
-
-       attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
-       attrs.pci_vf.pf = pf->hw.pf_id;
-       attrs.pci_vf.vf = vf->vf_id;
-
-       ice_devlink_set_switch_id(pf, &attrs.switch_id);
-
-       devlink_port_attrs_set(devlink_port, &attrs);
-       devlink = priv_to_devlink(pf);
-
-       err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
-                                         &ice_devlink_vf_port_ops);
-       if (err) {
-               dev_err(dev, "Failed to create devlink port for VF %d, error %d\n",
-                       vf->vf_id, err);
-               return err;
-       }
-
-       return 0;
-}
-
-/**
- * ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF
- * @vf: the VF to cleanup
- *
- * Unregisters the devlink_port structure associated with this VF.
- */
-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;
-
-       if (!ice_is_eswitch_mode_switchdev(pf)) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "SF ports are only supported in eswitch switchdev mode");
-               return -EOPNOTSUPP;
-       }
-
-       return ice_alloc_dynamic_port(pf, new_attr, extack, devlink_port);
-}
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.h b/drivers/net/ethernet/intel/ice/devlink/devlink_port.h
deleted file mode 100644 (file)
index d60efc3..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (c) 2024, Intel Corporation. */
-
-#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_ */
diff --git a/drivers/net/ethernet/intel/ice/devlink/port.c b/drivers/net/ethernet/intel/ice/devlink/port.c
new file mode 100644 (file)
index 0000000..767419a
--- /dev/null
@@ -0,0 +1,999 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2024, Intel Corporation. */
+
+#include <linux/vmalloc.h>
+
+#include "ice.h"
+#include "devlink.h"
+#include "port.h"
+#include "ice_lib.h"
+#include "ice_fltr.h"
+
+static int ice_active_port_option = -1;
+
+/**
+ * ice_devlink_port_opt_speed_str - convert speed to a string
+ * @speed: speed value
+ */
+static const char *ice_devlink_port_opt_speed_str(u8 speed)
+{
+       switch (speed & ICE_AQC_PORT_OPT_MAX_LANE_M) {
+       case ICE_AQC_PORT_OPT_MAX_LANE_100M:
+               return "0.1";
+       case ICE_AQC_PORT_OPT_MAX_LANE_1G:
+               return "1";
+       case ICE_AQC_PORT_OPT_MAX_LANE_2500M:
+               return "2.5";
+       case ICE_AQC_PORT_OPT_MAX_LANE_5G:
+               return "5";
+       case ICE_AQC_PORT_OPT_MAX_LANE_10G:
+               return "10";
+       case ICE_AQC_PORT_OPT_MAX_LANE_25G:
+               return "25";
+       case ICE_AQC_PORT_OPT_MAX_LANE_50G:
+               return "50";
+       case ICE_AQC_PORT_OPT_MAX_LANE_100G:
+               return "100";
+       }
+
+       return "-";
+}
+
+#define ICE_PORT_OPT_DESC_LEN  50
+/**
+ * ice_devlink_port_options_print - Print available port split options
+ * @pf: the PF to print split port options
+ *
+ * Prints a table with available port split options and max port speeds
+ */
+static void ice_devlink_port_options_print(struct ice_pf *pf)
+{
+       u8 i, j, options_count, cnt, speed, pending_idx, active_idx;
+       struct ice_aqc_get_port_options_elem *options, *opt;
+       struct device *dev = ice_pf_to_dev(pf);
+       bool active_valid, pending_valid;
+       char desc[ICE_PORT_OPT_DESC_LEN];
+       const char *str;
+       int status;
+
+       options = kcalloc(ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV,
+                         sizeof(*options), GFP_KERNEL);
+       if (!options)
+               return;
+
+       for (i = 0; i < ICE_MAX_PORT_PER_PCI_DEV; i++) {
+               opt = options + i * ICE_AQC_PORT_OPT_MAX;
+               options_count = ICE_AQC_PORT_OPT_MAX;
+               active_valid = 0;
+
+               status = ice_aq_get_port_options(&pf->hw, opt, &options_count,
+                                                i, true, &active_idx,
+                                                &active_valid, &pending_idx,
+                                                &pending_valid);
+               if (status) {
+                       dev_dbg(dev, "Couldn't read port option for port %d, err %d\n",
+                               i, status);
+                       goto err;
+               }
+       }
+
+       dev_dbg(dev, "Available port split options and max port speeds (Gbps):\n");
+       dev_dbg(dev, "Status  Split      Quad 0          Quad 1\n");
+       dev_dbg(dev, "        count  L0  L1  L2  L3  L4  L5  L6  L7\n");
+
+       for (i = 0; i < options_count; i++) {
+               cnt = 0;
+
+               if (i == ice_active_port_option)
+                       str = "Active";
+               else if ((i == pending_idx) && pending_valid)
+                       str = "Pending";
+               else
+                       str = "";
+
+               cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
+                               "%-8s", str);
+
+               cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
+                               "%-6u", options[i].pmd);
+
+               for (j = 0; j < ICE_MAX_PORT_PER_PCI_DEV; ++j) {
+                       speed = options[i + j * ICE_AQC_PORT_OPT_MAX].max_lane_speed;
+                       str = ice_devlink_port_opt_speed_str(speed);
+                       cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
+                                       "%3s ", str);
+               }
+
+               dev_dbg(dev, "%s\n", desc);
+       }
+
+err:
+       kfree(options);
+}
+
+/**
+ * ice_devlink_aq_set_port_option - Send set port option admin queue command
+ * @pf: the PF to print split port options
+ * @option_idx: selected port option
+ * @extack: extended netdev ack structure
+ *
+ * Sends set port option admin queue command with selected port option and
+ * calls NVM write activate.
+ */
+static int
+ice_devlink_aq_set_port_option(struct ice_pf *pf, u8 option_idx,
+                              struct netlink_ext_ack *extack)
+{
+       struct device *dev = ice_pf_to_dev(pf);
+       int status;
+
+       status = ice_aq_set_port_option(&pf->hw, 0, true, option_idx);
+       if (status) {
+               dev_dbg(dev, "ice_aq_set_port_option, err %d aq_err %d\n",
+                       status, pf->hw.adminq.sq_last_status);
+               NL_SET_ERR_MSG_MOD(extack, "Port split request failed");
+               return -EIO;
+       }
+
+       status = ice_acquire_nvm(&pf->hw, ICE_RES_WRITE);
+       if (status) {
+               dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
+                       status, pf->hw.adminq.sq_last_status);
+               NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
+               return -EIO;
+       }
+
+       status = ice_nvm_write_activate(&pf->hw, ICE_AQC_NVM_ACTIV_REQ_EMPR, NULL);
+       if (status) {
+               dev_dbg(dev, "ice_nvm_write_activate failed, err %d aq_err %d\n",
+                       status, pf->hw.adminq.sq_last_status);
+               NL_SET_ERR_MSG_MOD(extack, "Port split request failed to save data");
+               ice_release_nvm(&pf->hw);
+               return -EIO;
+       }
+
+       ice_release_nvm(&pf->hw);
+
+       NL_SET_ERR_MSG_MOD(extack, "Reboot required to finish port split");
+       return 0;
+}
+
+/**
+ * ice_devlink_port_split - .port_split devlink handler
+ * @devlink: devlink instance structure
+ * @port: devlink port structure
+ * @count: number of ports to split to
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_split operation.
+ *
+ * Unfortunately, the devlink expression of available options is limited
+ * to just a number, so search for an FW port option which supports
+ * the specified number. As there could be multiple FW port options with
+ * the same port split count, allow switching between them. When the same
+ * port split count request is issued again, switch to the next FW port
+ * option with the same port split count.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+static int
+ice_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
+                      unsigned int count, struct netlink_ext_ack *extack)
+{
+       struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
+       u8 i, j, active_idx, pending_idx, new_option;
+       struct ice_pf *pf = devlink_priv(devlink);
+       u8 option_count = ICE_AQC_PORT_OPT_MAX;
+       struct device *dev = ice_pf_to_dev(pf);
+       bool active_valid, pending_valid;
+       int status;
+
+       status = ice_aq_get_port_options(&pf->hw, options, &option_count,
+                                        0, true, &active_idx, &active_valid,
+                                        &pending_idx, &pending_valid);
+       if (status) {
+               dev_dbg(dev, "Couldn't read port split options, err = %d\n",
+                       status);
+               NL_SET_ERR_MSG_MOD(extack, "Failed to get available port split options");
+               return -EIO;
+       }
+
+       new_option = ICE_AQC_PORT_OPT_MAX;
+       active_idx = pending_valid ? pending_idx : active_idx;
+       for (i = 1; i <= option_count; i++) {
+               /* In order to allow switching between FW port options with
+                * the same port split count, search for a new option starting
+                * from the active/pending option (with array wrap around).
+                */
+               j = (active_idx + i) % option_count;
+
+               if (count == options[j].pmd) {
+                       new_option = j;
+                       break;
+               }
+       }
+
+       if (new_option == active_idx) {
+               dev_dbg(dev, "request to split: count: %u is already set and there are no other options\n",
+                       count);
+               NL_SET_ERR_MSG_MOD(extack, "Requested split count is already set");
+               ice_devlink_port_options_print(pf);
+               return -EINVAL;
+       }
+
+       if (new_option == ICE_AQC_PORT_OPT_MAX) {
+               dev_dbg(dev, "request to split: count: %u not found\n", count);
+               NL_SET_ERR_MSG_MOD(extack, "Port split requested unsupported port config");
+               ice_devlink_port_options_print(pf);
+               return -EINVAL;
+       }
+
+       status = ice_devlink_aq_set_port_option(pf, new_option, extack);
+       if (status)
+               return status;
+
+       ice_devlink_port_options_print(pf);
+
+       return 0;
+}
+
+/**
+ * ice_devlink_port_unsplit - .port_unsplit devlink handler
+ * @devlink: devlink instance structure
+ * @port: devlink port structure
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_unsplit operation.
+ * Calls ice_devlink_port_split with split count set to 1.
+ * There could be no FW option available with split count 1.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+static int
+ice_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
+                        struct netlink_ext_ack *extack)
+{
+       return ice_devlink_port_split(devlink, port, 1, extack);
+}
+
+/**
+ * ice_devlink_set_port_split_options - Set port split options
+ * @pf: the PF to set port split options
+ * @attrs: devlink attributes
+ *
+ * Sets devlink port split options based on available FW port options
+ */
+static void
+ice_devlink_set_port_split_options(struct ice_pf *pf,
+                                  struct devlink_port_attrs *attrs)
+{
+       struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
+       u8 i, active_idx, pending_idx, option_count = ICE_AQC_PORT_OPT_MAX;
+       bool active_valid, pending_valid;
+       int status;
+
+       status = ice_aq_get_port_options(&pf->hw, options, &option_count,
+                                        0, true, &active_idx, &active_valid,
+                                        &pending_idx, &pending_valid);
+       if (status) {
+               dev_dbg(ice_pf_to_dev(pf), "Couldn't read port split options, err = %d\n",
+                       status);
+               return;
+       }
+
+       /* find the biggest available port split count */
+       for (i = 0; i < option_count; i++)
+               attrs->lanes = max_t(int, attrs->lanes, options[i].pmd);
+
+       attrs->splittable = attrs->lanes ? 1 : 0;
+       ice_active_port_option = active_idx;
+}
+
+static const struct devlink_port_ops ice_devlink_port_ops = {
+       .port_split = ice_devlink_port_split,
+       .port_unsplit = ice_devlink_port_unsplit,
+};
+
+/**
+ * ice_devlink_set_switch_id - Set unique switch id based on pci dsn
+ * @pf: the PF to create a devlink port for
+ * @ppid: struct with switch id information
+ */
+static void
+ice_devlink_set_switch_id(struct ice_pf *pf, struct netdev_phys_item_id *ppid)
+{
+       struct pci_dev *pdev = pf->pdev;
+       u64 id;
+
+       id = pci_get_dsn(pdev);
+
+       ppid->id_len = sizeof(id);
+       put_unaligned_be64(id, &ppid->id);
+}
+
+/**
+ * ice_devlink_create_pf_port - Create a devlink port for this PF
+ * @pf: the PF to create a devlink port for
+ *
+ * Create and register a devlink_port for this PF.
+ * This function has to be called under devl_lock.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+int ice_devlink_create_pf_port(struct ice_pf *pf)
+{
+       struct devlink_port_attrs attrs = {};
+       struct devlink_port *devlink_port;
+       struct devlink *devlink;
+       struct ice_vsi *vsi;
+       struct device *dev;
+       int err;
+
+       devlink = priv_to_devlink(pf);
+
+       dev = ice_pf_to_dev(pf);
+
+       devlink_port = &pf->devlink_port;
+
+       vsi = ice_get_main_vsi(pf);
+       if (!vsi)
+               return -EIO;
+
+       attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+       attrs.phys.port_number = pf->hw.pf_id;
+
+       /* As FW supports only port split options for whole device,
+        * set port split options only for first PF.
+        */
+       if (pf->hw.pf_id == 0)
+               ice_devlink_set_port_split_options(pf, &attrs);
+
+       ice_devlink_set_switch_id(pf, &attrs.switch_id);
+
+       devlink_port_attrs_set(devlink_port, &attrs);
+
+       err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
+                                         &ice_devlink_port_ops);
+       if (err) {
+               dev_err(dev, "Failed to create devlink port for PF %d, error %d\n",
+                       pf->hw.pf_id, err);
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF
+ * @pf: the PF to cleanup
+ *
+ * Unregisters the devlink_port structure associated with this PF.
+ * This function has to be called under devl_lock.
+ */
+void ice_devlink_destroy_pf_port(struct ice_pf *pf)
+{
+       devl_port_unregister(&pf->devlink_port);
+}
+
+/**
+ * ice_devlink_port_get_vf_fn_mac - .port_fn_hw_addr_get devlink handler
+ * @port: devlink port structure
+ * @hw_addr: MAC address of the port
+ * @hw_addr_len: length of MAC address
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_fn_hw_addr_get operation
+ * Return: zero on success or an error code on failure.
+ */
+static int ice_devlink_port_get_vf_fn_mac(struct devlink_port *port,
+                                         u8 *hw_addr, int *hw_addr_len,
+                                         struct netlink_ext_ack *extack)
+{
+       struct ice_vf *vf = container_of(port, struct ice_vf, devlink_port);
+
+       ether_addr_copy(hw_addr, vf->dev_lan_addr);
+       *hw_addr_len = ETH_ALEN;
+
+       return 0;
+}
+
+/**
+ * ice_devlink_port_set_vf_fn_mac - .port_fn_hw_addr_set devlink handler
+ * @port: devlink port structure
+ * @hw_addr: MAC address of the port
+ * @hw_addr_len: length of MAC address
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_fn_hw_addr_set operation
+ * Return: zero on success or an error code on failure.
+ */
+static int ice_devlink_port_set_vf_fn_mac(struct devlink_port *port,
+                                         const u8 *hw_addr,
+                                         int hw_addr_len,
+                                         struct netlink_ext_ack *extack)
+
+{
+       struct devlink_port_attrs *attrs = &port->attrs;
+       struct devlink_port_pci_vf_attrs *pci_vf;
+       struct devlink *devlink = port->devlink;
+       struct ice_pf *pf;
+       u16 vf_id;
+
+       pf = devlink_priv(devlink);
+       pci_vf = &attrs->pci_vf;
+       vf_id = pci_vf->vf;
+
+       return __ice_set_vf_mac(pf, vf_id, hw_addr);
+}
+
+static const struct devlink_port_ops ice_devlink_vf_port_ops = {
+       .port_fn_hw_addr_get = ice_devlink_port_get_vf_fn_mac,
+       .port_fn_hw_addr_set = ice_devlink_port_set_vf_fn_mac,
+};
+
+/**
+ * ice_devlink_create_vf_port - Create a devlink port for this VF
+ * @vf: the VF to create a port for
+ *
+ * Create and register a devlink_port for this VF.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+int ice_devlink_create_vf_port(struct ice_vf *vf)
+{
+       struct devlink_port_attrs attrs = {};
+       struct devlink_port *devlink_port;
+       struct devlink *devlink;
+       struct ice_vsi *vsi;
+       struct device *dev;
+       struct ice_pf *pf;
+       int err;
+
+       pf = vf->pf;
+       dev = ice_pf_to_dev(pf);
+       devlink_port = &vf->devlink_port;
+
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi)
+               return -EINVAL;
+
+       attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
+       attrs.pci_vf.pf = pf->hw.pf_id;
+       attrs.pci_vf.vf = vf->vf_id;
+
+       ice_devlink_set_switch_id(pf, &attrs.switch_id);
+
+       devlink_port_attrs_set(devlink_port, &attrs);
+       devlink = priv_to_devlink(pf);
+
+       err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
+                                         &ice_devlink_vf_port_ops);
+       if (err) {
+               dev_err(dev, "Failed to create devlink port for VF %d, error %d\n",
+                       vf->vf_id, err);
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF
+ * @vf: the VF to cleanup
+ *
+ * Unregisters the devlink_port structure associated with this VF.
+ */
+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;
+
+       if (!ice_is_eswitch_mode_switchdev(pf)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "SF ports are only supported in eswitch switchdev mode");
+               return -EOPNOTSUPP;
+       }
+
+       return ice_alloc_dynamic_port(pf, new_attr, extack, devlink_port);
+}
diff --git a/drivers/net/ethernet/intel/ice/devlink/port.h b/drivers/net/ethernet/intel/ice/devlink/port.h
new file mode 100644 (file)
index 0000000..d60efc3
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2024, Intel Corporation. */
+
+#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_ */
index ac7db100e2cd352c32646c6355d4f2f2067355c5..5c7dcf21b222bbc565cad7894d207c03e84d31a4 100644 (file)
@@ -5,7 +5,7 @@
 #define _ICE_ESWITCH_H_
 
 #include <net/devlink.h>
-#include "devlink/devlink_port.h"
+#include "devlink/port.h"
 
 #ifdef CONFIG_ICE_SWITCHDEV
 void ice_eswitch_detach_vf(struct ice_pf *pf, struct ice_vf *vf);
index 0ab35607e5d569b987ad1b0400ee00c666beb228..d641dd8b81846283a6b12bf16d829918256de1ca 100644 (file)
@@ -14,7 +14,7 @@
 #include "ice_dcb_lib.h"
 #include "ice_dcb_nl.h"
 #include "devlink/devlink.h"
-#include "devlink/devlink_port.h"
+#include "devlink/port.h"
 #include "ice_sf_eth.h"
 #include "ice_hwmon.h"
 /* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
index 970a99a52bf181fd69fac9a2c418460312799678..fb7a1b9a4313919574b08da9fbd0877010c08dd9 100644 (file)
@@ -4,7 +4,7 @@
 #include "ice.h"
 #include "ice_eswitch.h"
 #include "devlink/devlink.h"
-#include "devlink/devlink_port.h"
+#include "devlink/port.h"
 #include "ice_sriov.h"
 #include "ice_tc_lib.h"
 #include "ice_dcb_lib.h"
index 75d7147e1c01c0311bb6182ec326830313168f55..1a2c94375ca71ea804e9c619c603c0c0efa91d27 100644 (file)
@@ -5,8 +5,8 @@
 #include "ice_txrx.h"
 #include "ice_fltr.h"
 #include "ice_sf_eth.h"
-#include "devlink/devlink_port.h"
 #include "devlink/devlink.h"
+#include "devlink/port.h"
 
 static const struct net_device_ops ice_sf_netdev_ops = {
        .ndo_open = ice_open,