diff mbox series

[iwl-next,v4,02/10] ice: Add driver support for firmware changes for LAG

Message ID 20230609211626.621968-3-david.m.ertman@intel.com
State Superseded
Delegated to: Anthony Nguyen
Headers show
Series Implement support for SRIOV + LAG | expand

Commit Message

Dave Ertman June 9, 2023, 9:16 p.m. UTC
Add the defines, fields, and detection code for FW support of LAG for
SRIOV.  Also exposes some previously static functions to allow access
in the lag code.

Clean up code that is unused or not needed for LAG support.  Also add
an ordered workqueue for processing LAG events.

Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
---
 drivers/net/ethernet/intel/ice/ice.h          |  5 ++
 .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  3 ++
 drivers/net/ethernet/intel/ice/ice_common.c   |  8 +++
 drivers/net/ethernet/intel/ice/ice_lag.c      | 53 ++++++++++---------
 drivers/net/ethernet/intel/ice/ice_lib.c      |  2 +-
 drivers/net/ethernet/intel/ice/ice_lib.h      |  1 +
 drivers/net/ethernet/intel/ice/ice_main.c     | 12 +++++
 drivers/net/ethernet/intel/ice/ice_type.h     |  2 +
 8 files changed, 59 insertions(+), 27 deletions(-)

Comments

Simon Horman June 14, 2023, 11:17 a.m. UTC | #1
On Fri, Jun 09, 2023 at 02:16:18PM -0700, Dave Ertman wrote:

...

Hi Dave,

some minor feedback from my side.

> @@ -5576,10 +5579,18 @@ static int __init ice_module_init(void)
>  		return -ENOMEM;
>  	}
>  
> +	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
> +	if (!ice_lag_wq) {
> +		pr_err("Failed to create LAG workqueue\n");

Is the allocation failure already logged by core code?
If so, perhaps this is unnecessary?

> +		destroy_workqueue(ice_wq);
> +		return -ENOMEM;
> +	}
> +
>  	status = pci_register_driver(&ice_driver);
>  	if (status) {
>  		pr_err("failed to register PCI driver, err %d\n", status);
>  		destroy_workqueue(ice_wq);
> +		destroy_workqueue(ice_lag_wq);
>  	}
>  
>  	return status;

As there are now a few things (more than zero) to unwind I think it would
be best to use the Kernel's idiomatic goto-based approach.

(Completely untested!)

	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
	if (!ice_lag_wq) {
		pr_err("Failed to create LAG workqueue\n");
		status = -ENOMEM;
		goto err_destroy_ice_wq;
	}

	status = pci_register_driver(&ice_driver);
	if (status) {
		pr_err("failed to register PCI driver, err %d\n", status);
		goto err_destroy_lag_wq;
	}

	return status;

err_destroy_lag_wq:
	destroy_workqueue(ice_lag_wq);
err_destroy_ice_wq:
	destroy_workqueue(ice_wq);
	return status


> @@ -5596,6 +5607,7 @@ static void __exit ice_module_exit(void)
>  {
>  	pci_unregister_driver(&ice_driver);
>  	destroy_workqueue(ice_wq);
> +	destroy_workqueue(ice_lag_wq);
>  	pr_info("module unloaded\n");
>  }
>  module_exit(ice_module_exit);

...
Dave Ertman June 14, 2023, 4:56 p.m. UTC | #2
> -----Original Message-----
> From: Simon Horman <simon.horman@corigine.com>
> Sent: Wednesday, June 14, 2023 4:18 AM
> To: Ertman, David M <david.m.ertman@intel.com>
> Cc: intel-wired-lan@lists.osuosl.org; daniel.machon@microchip.com;
> netdev@vger.kernel.org
> Subject: Re: [PATCH iwl-next v4 02/10] ice: Add driver support for firmware
> changes for LAG
> 
> On Fri, Jun 09, 2023 at 02:16:18PM -0700, Dave Ertman wrote:
> 
> ...
> 
> Hi Dave,
> 
> some minor feedback from my side.
> 
> > @@ -5576,10 +5579,18 @@ static int __init ice_module_init(void)
> >  		return -ENOMEM;
> >  	}
> >
> > +	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
> > +	if (!ice_lag_wq) {
> > +		pr_err("Failed to create LAG workqueue\n");
> 
> Is the allocation failure already logged by core code?
> If so, perhaps this is unnecessary?

I do not see any messaging from the core, so I should probably leave this here
unless you can point out something I missed 😊

> 
> > +		destroy_workqueue(ice_wq);
> > +		return -ENOMEM;
> > +	}
> > +
> >  	status = pci_register_driver(&ice_driver);
> >  	if (status) {
> >  		pr_err("failed to register PCI driver, err %d\n", status);
> >  		destroy_workqueue(ice_wq);
> > +		destroy_workqueue(ice_lag_wq);
> >  	}
> >
> >  	return status;
> 
> As there are now a few things (more than zero) to unwind I think it would
> be best to use the Kernel's idiomatic goto-based approach.
> 

Sounds reasonable - will switch to a goto based approach.

Changes to come in v5.

DaveE

> (Completely untested!)
> 
> 	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
> 	if (!ice_lag_wq) {
> 		pr_err("Failed to create LAG workqueue\n");
> 		status = -ENOMEM;
> 		goto err_destroy_ice_wq;
> 	}
> 
> 	status = pci_register_driver(&ice_driver);
> 	if (status) {
> 		pr_err("failed to register PCI driver, err %d\n", status);
> 		goto err_destroy_lag_wq;
> 	}
> 
> 	return status;
> 
> err_destroy_lag_wq:
> 	destroy_workqueue(ice_lag_wq);
> err_destroy_ice_wq:
> 	destroy_workqueue(ice_wq);
> 	return status
> 
> 
> > @@ -5596,6 +5607,7 @@ static void __exit ice_module_exit(void)
> >  {
> >  	pci_unregister_driver(&ice_driver);
> >  	destroy_workqueue(ice_wq);
> > +	destroy_workqueue(ice_lag_wq);
> >  	pr_info("module unloaded\n");
> >  }
> >  module_exit(ice_module_exit);
> 
> ...
Simon Horman June 14, 2023, 7:44 p.m. UTC | #3
On Wed, Jun 14, 2023 at 04:56:53PM +0000, Ertman, David M wrote:
> > -----Original Message-----
> > From: Simon Horman <simon.horman@corigine.com>
> > Sent: Wednesday, June 14, 2023 4:18 AM
> > To: Ertman, David M <david.m.ertman@intel.com>
> > Cc: intel-wired-lan@lists.osuosl.org; daniel.machon@microchip.com;
> > netdev@vger.kernel.org
> > Subject: Re: [PATCH iwl-next v4 02/10] ice: Add driver support for firmware
> > changes for LAG
> > 
> > On Fri, Jun 09, 2023 at 02:16:18PM -0700, Dave Ertman wrote:
> > 
> > ...
> > 
> > Hi Dave,
> > 
> > some minor feedback from my side.
> > 
> > > @@ -5576,10 +5579,18 @@ static int __init ice_module_init(void)
> > >  		return -ENOMEM;
> > >  	}
> > >
> > > +	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
> > > +	if (!ice_lag_wq) {
> > > +		pr_err("Failed to create LAG workqueue\n");
> > 
> > Is the allocation failure already logged by core code?
> > If so, perhaps this is unnecessary?
> 
> I do not see any messaging from the core, so I should probably leave this here
> unless you can point out something I missed 😊

Let's keep it :)

...
Brett Creeley June 14, 2023, 9:23 p.m. UTC | #4
On 6/9/2023 2:16 PM, Dave Ertman wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
> 
> 
> Add the defines, fields, and detection code for FW support of LAG for
> SRIOV.  Also exposes some previously static functions to allow access
> in the lag code.
> 
> Clean up code that is unused or not needed for LAG support.  Also add
> an ordered workqueue for processing LAG events.
> 
> Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
> Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
> ---
>   drivers/net/ethernet/intel/ice/ice.h          |  5 ++
>   .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  3 ++
>   drivers/net/ethernet/intel/ice/ice_common.c   |  8 +++
>   drivers/net/ethernet/intel/ice/ice_lag.c      | 53 ++++++++++---------
>   drivers/net/ethernet/intel/ice/ice_lib.c      |  2 +-
>   drivers/net/ethernet/intel/ice/ice_lib.h      |  1 +
>   drivers/net/ethernet/intel/ice/ice_main.c     | 12 +++++
>   drivers/net/ethernet/intel/ice/ice_type.h     |  2 +
>   8 files changed, 59 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index 9109006336f0..5ac0ad12f9f1 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -200,6 +200,8 @@ enum ice_feature {
>          ICE_F_PTP_EXTTS,
>          ICE_F_SMA_CTRL,
>          ICE_F_GNSS,
> +       ICE_F_ROCE_LAG,
> +       ICE_F_SRIOV_LAG,
>          ICE_F_MAX
>   };
> 
> @@ -569,6 +571,7 @@ struct ice_pf {
>          struct mutex sw_mutex;          /* lock for protecting VSI alloc flow */
>          struct mutex tc_mutex;          /* lock to protect TC changes */
>          struct mutex adev_mutex;        /* lock to protect aux device access */
> +       struct mutex lag_mutex;         /* protect ice_lag struct in PF */
>          u32 msg_enable;
>          struct ice_ptp ptp;
>          struct gnss_serial *gnss_serial;
> @@ -639,6 +642,8 @@ struct ice_pf {
>          struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
>   };
> 
> +extern struct workqueue_struct *ice_lag_wq;
> +
>   struct ice_netdev_priv {
>          struct ice_vsi *vsi;
>          struct ice_repr *repr;
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index 6ea0d4c017f0..6b5ba9a02bad 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -120,6 +120,9 @@ struct ice_aqc_list_caps_elem {
>   #define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE              0x0076
>   #define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT                0x0077
>   #define ICE_AQC_CAPS_NVM_MGMT                          0x0080
> +#define ICE_AQC_CAPS_FW_LAG_SUPPORT                    0x0092
> +#define ICE_AQC_BIT_ROCEV2_LAG                         0x01
> +#define ICE_AQC_BIT_SRIOV_LAG                          0x02
> 
>          u8 major_ver;
>          u8 minor_ver;
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
> index 09e2e38d538e..6ddf607d2edf 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -2241,6 +2241,14 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
>                            "%s: reset_restrict_support = %d\n", prefix,
>                            caps->reset_restrict_support);
>                  break;
> +       case ICE_AQC_CAPS_FW_LAG_SUPPORT:
> +               caps->roce_lag = !!(number & ICE_AQC_BIT_ROCEV2_LAG);
> +               ice_debug(hw, ICE_DBG_INIT, "%s: roce_lag = %u\n",
> +                         prefix, caps->roce_lag);
> +               caps->sriov_lag = !!(number & ICE_AQC_BIT_SRIOV_LAG);
> +               ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n",
> +                         prefix, caps->sriov_lag);
> +               break;
>          default:
>                  /* Not one of the recognized common capabilities */
>                  found = false;
> diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
> index 5a7753bda324..73bfc5cd8b37 100644
> --- a/drivers/net/ethernet/intel/ice/ice_lag.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lag.c
> @@ -4,8 +4,12 @@
>   /* Link Aggregation code */
> 
>   #include "ice.h"
> +#include "ice_lib.h"
>   #include "ice_lag.h"
> 
> +#define ICE_LAG_RES_SHARED     BIT(14)
> +#define ICE_LAG_RES_VALID      BIT(15)
> +
>   /**
>    * ice_lag_set_primary - set PF LAG state as Primary
>    * @lag: LAG info struct
> @@ -225,6 +229,26 @@ static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
>          lag->role = ICE_LAG_NONE;
>   }
> 
> +/**
> + * ice_lag_check_nvm_support - Check for NVM support for LAG
> + * @pf: PF struct
> + */
> +static void ice_lag_check_nvm_support(struct ice_pf *pf)

Nit, but this name is a bit misleading to me. I would expect it to be 
called something like "ice_lag_init_feature_support_flag()" or something 
similar that better describes what the function is doing.

> +{
> +       struct ice_hw_dev_caps *caps;
> +
> +       caps = &pf->hw.dev_caps;

Nit, but since you are already creating a local variable you could go 
one level further to the common_cap, so it could be:

common_cap->roce_lag and common_cap->sriov_lag

> +       if (caps->common_cap.roce_lag)
> +               ice_set_feature_support(pf, ICE_F_ROCE_LAG);
> +       else
> +               ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
> +
> +       if (caps->common_cap.sriov_lag)
> +               ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
> +       else
> +               ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
> +}
> +

[...]
Dave Ertman June 14, 2023, 10:42 p.m. UTC | #5
> -----Original Message-----
> From: Brett Creeley <bcreeley@amd.com>
> Sent: Wednesday, June 14, 2023 2:24 PM
> To: Ertman, David M <david.m.ertman@intel.com>; intel-wired-
> lan@lists.osuosl.org
> Cc: daniel.machon@microchip.com; simon.horman@corigine.com;
> netdev@vger.kernel.org
> Subject: Re: [PATCH iwl-next v4 02/10] ice: Add driver support for firmware
> changes for LAG
> 
> On 6/9/2023 2:16 PM, Dave Ertman wrote:
> > Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
> >
> >
> > Add the defines, fields, and detection code for FW support of LAG for
> > SRIOV.  Also exposes some previously static functions to allow access
> > in the lag code.
> >
> > Clean up code that is unused or not needed for LAG support.  Also add
> > an ordered workqueue for processing LAG events.
> >
> > Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
> > Signed-off-by: Dave Ertman <david.m.ertman@intel.com>

...

> > +/**
> > + * ice_lag_check_nvm_support - Check for NVM support for LAG
> > + * @pf: PF struct
> > + */
> > +static void ice_lag_check_nvm_support(struct ice_pf *pf)
> 
> Nit, but this name is a bit misleading to me. I would expect it to be
> called something like "ice_lag_init_feature_support_flag()" or something
> similar that better describes what the function is doing.

Name changed

> 
> > +{
> > +       struct ice_hw_dev_caps *caps;
> > +
> > +       caps = &pf->hw.dev_caps;
> 
> Nit, but since you are already creating a local variable you could go
> one level further to the common_cap, so it could be:
> 
> common_cap->roce_lag and common_cap->sriov_lag

Variable changed to go down one mor level.

Changes to come out in v5
DaveE
> 
> > +       if (caps->common_cap.roce_lag)
> > +               ice_set_feature_support(pf, ICE_F_ROCE_LAG);
> > +       else
> > +               ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
> > +
> > +       if (caps->common_cap.sriov_lag)
> > +               ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
> > +       else
> > +               ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
> > +}
> > +
> 
> [...]
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 9109006336f0..5ac0ad12f9f1 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -200,6 +200,8 @@  enum ice_feature {
 	ICE_F_PTP_EXTTS,
 	ICE_F_SMA_CTRL,
 	ICE_F_GNSS,
+	ICE_F_ROCE_LAG,
+	ICE_F_SRIOV_LAG,
 	ICE_F_MAX
 };
 
@@ -569,6 +571,7 @@  struct ice_pf {
 	struct mutex sw_mutex;		/* lock for protecting VSI alloc flow */
 	struct mutex tc_mutex;		/* lock to protect TC changes */
 	struct mutex adev_mutex;	/* lock to protect aux device access */
+	struct mutex lag_mutex;		/* protect ice_lag struct in PF */
 	u32 msg_enable;
 	struct ice_ptp ptp;
 	struct gnss_serial *gnss_serial;
@@ -639,6 +642,8 @@  struct ice_pf {
 	struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
 };
 
+extern struct workqueue_struct *ice_lag_wq;
+
 struct ice_netdev_priv {
 	struct ice_vsi *vsi;
 	struct ice_repr *repr;
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 6ea0d4c017f0..6b5ba9a02bad 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -120,6 +120,9 @@  struct ice_aqc_list_caps_elem {
 #define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE		0x0076
 #define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT		0x0077
 #define ICE_AQC_CAPS_NVM_MGMT				0x0080
+#define ICE_AQC_CAPS_FW_LAG_SUPPORT			0x0092
+#define ICE_AQC_BIT_ROCEV2_LAG				0x01
+#define ICE_AQC_BIT_SRIOV_LAG				0x02
 
 	u8 major_ver;
 	u8 minor_ver;
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 09e2e38d538e..6ddf607d2edf 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -2241,6 +2241,14 @@  ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
 			  "%s: reset_restrict_support = %d\n", prefix,
 			  caps->reset_restrict_support);
 		break;
+	case ICE_AQC_CAPS_FW_LAG_SUPPORT:
+		caps->roce_lag = !!(number & ICE_AQC_BIT_ROCEV2_LAG);
+		ice_debug(hw, ICE_DBG_INIT, "%s: roce_lag = %u\n",
+			  prefix, caps->roce_lag);
+		caps->sriov_lag = !!(number & ICE_AQC_BIT_SRIOV_LAG);
+		ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n",
+			  prefix, caps->sriov_lag);
+		break;
 	default:
 		/* Not one of the recognized common capabilities */
 		found = false;
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index 5a7753bda324..73bfc5cd8b37 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -4,8 +4,12 @@ 
 /* Link Aggregation code */
 
 #include "ice.h"
+#include "ice_lib.h"
 #include "ice_lag.h"
 
+#define ICE_LAG_RES_SHARED	BIT(14)
+#define ICE_LAG_RES_VALID	BIT(15)
+
 /**
  * ice_lag_set_primary - set PF LAG state as Primary
  * @lag: LAG info struct
@@ -225,6 +229,26 @@  static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
 	lag->role = ICE_LAG_NONE;
 }
 
+/**
+ * ice_lag_check_nvm_support - Check for NVM support for LAG
+ * @pf: PF struct
+ */
+static void ice_lag_check_nvm_support(struct ice_pf *pf)
+{
+	struct ice_hw_dev_caps *caps;
+
+	caps = &pf->hw.dev_caps;
+	if (caps->common_cap.roce_lag)
+		ice_set_feature_support(pf, ICE_F_ROCE_LAG);
+	else
+		ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
+
+	if (caps->common_cap.sriov_lag)
+		ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
+	else
+		ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
+}
+
 /**
  * ice_lag_changeupper_event - handle LAG changeupper event
  * @lag: LAG info struct
@@ -264,26 +288,6 @@  static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr)
 	ice_display_lag_info(lag);
 }
 
-/**
- * ice_lag_changelower_event - handle LAG changelower event
- * @lag: LAG info struct
- * @ptr: opaque data pointer
- *
- * ptr to be cast to netdev_notifier_changelowerstate_info
- */
-static void ice_lag_changelower_event(struct ice_lag *lag, void *ptr)
-{
-	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
-
-	if (netdev != lag->netdev)
-		return;
-
-	netdev_dbg(netdev, "bonding info\n");
-
-	if (!netif_is_lag_port(netdev))
-		netdev_dbg(netdev, "CHANGELOWER rcvd, but netdev not in LAG. Bail\n");
-}
-
 /**
  * ice_lag_event_handler - handle LAG events from netdev
  * @notif_blk: notifier block registered by this netdev
@@ -310,9 +314,6 @@  ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
 	case NETDEV_CHANGEUPPER:
 		ice_lag_changeupper_event(lag, ptr);
 		break;
-	case NETDEV_CHANGELOWERSTATE:
-		ice_lag_changelower_event(lag, ptr);
-		break;
 	case NETDEV_BONDING_INFO:
 		ice_lag_info_event(lag, ptr);
 		break;
@@ -379,6 +380,8 @@  int ice_init_lag(struct ice_pf *pf)
 	struct ice_vsi *vsi;
 	int err;
 
+	ice_lag_check_nvm_support(pf);
+
 	pf->lag = kzalloc(sizeof(*lag), GFP_KERNEL);
 	if (!pf->lag)
 		return -ENOMEM;
@@ -435,9 +438,7 @@  void ice_deinit_lag(struct ice_pf *pf)
 	if (lag->pf)
 		ice_unregister_lag_handler(lag);
 
-	dev_put(lag->upper_netdev);
-
-	dev_put(lag->peer_netdev);
+	flush_workqueue(ice_lag_wq);
 
 	kfree(lag);
 
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 984b381386ff..cdb352e0fa07 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3997,7 +3997,7 @@  bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f)
  * @pf: pointer to the struct ice_pf instance
  * @f: feature enum to set
  */
-static void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f)
+void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f)
 {
 	if (f < 0 || f >= ICE_F_MAX)
 		return;
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 1628385a9672..dd53fe968ad8 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -163,6 +163,7 @@  int ice_vsi_del_vlan_zero(struct ice_vsi *vsi);
 bool ice_vsi_has_non_zero_vlans(struct ice_vsi *vsi);
 u16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi);
 bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f);
+void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f);
 void ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f);
 void ice_init_feature_support(struct ice_pf *pf);
 bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index f358018337af..e01834d0417e 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -64,6 +64,7 @@  struct device *ice_hw_to_dev(struct ice_hw *hw)
 }
 
 static struct workqueue_struct *ice_wq;
+struct workqueue_struct *ice_lag_wq;
 static const struct net_device_ops ice_netdev_safe_mode_ops;
 static const struct net_device_ops ice_netdev_ops;
 
@@ -3795,6 +3796,7 @@  u16 ice_get_avail_rxq_count(struct ice_pf *pf)
 static void ice_deinit_pf(struct ice_pf *pf)
 {
 	ice_service_task_stop(pf);
+	mutex_destroy(&pf->lag_mutex);
 	mutex_destroy(&pf->adev_mutex);
 	mutex_destroy(&pf->sw_mutex);
 	mutex_destroy(&pf->tc_mutex);
@@ -3875,6 +3877,7 @@  static int ice_init_pf(struct ice_pf *pf)
 	mutex_init(&pf->sw_mutex);
 	mutex_init(&pf->tc_mutex);
 	mutex_init(&pf->adev_mutex);
+	mutex_init(&pf->lag_mutex);
 
 	INIT_HLIST_HEAD(&pf->aq_wait_list);
 	spin_lock_init(&pf->aq_wait_lock);
@@ -5576,10 +5579,18 @@  static int __init ice_module_init(void)
 		return -ENOMEM;
 	}
 
+	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
+	if (!ice_lag_wq) {
+		pr_err("Failed to create LAG workqueue\n");
+		destroy_workqueue(ice_wq);
+		return -ENOMEM;
+	}
+
 	status = pci_register_driver(&ice_driver);
 	if (status) {
 		pr_err("failed to register PCI driver, err %d\n", status);
 		destroy_workqueue(ice_wq);
+		destroy_workqueue(ice_lag_wq);
 	}
 
 	return status;
@@ -5596,6 +5607,7 @@  static void __exit ice_module_exit(void)
 {
 	pci_unregister_driver(&ice_driver);
 	destroy_workqueue(ice_wq);
+	destroy_workqueue(ice_lag_wq);
 	pr_info("module unloaded\n");
 }
 module_exit(ice_module_exit);
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index a073616671ef..5e353b0cbe6f 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -277,6 +277,8 @@  struct ice_hw_common_caps {
 	u8 dcb;
 	u8 ieee_1588;
 	u8 rdma;
+	u8 roce_lag;
+	u8 sriov_lag;
 
 	bool nvm_update_pending_nvm;
 	bool nvm_update_pending_orom;