* [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation
@ 2026-05-07 21:47 KhaiWenTan
2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: KhaiWenTan @ 2026-05-07 21:47 UTC (permalink / raw)
To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni
Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim,
hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim
From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>
This series adds support for forcing 10/100 Mb/s link speed via ethtool
when autonegotiation is disabled on the igc driver.
Changes in v5:
- add removal justification to include copper context in commit
description for igc: remove unused autoneg_failed field (Paul)
- check that cmd->base.duplex is either DUPLEX_HALF or DUPLEX_FULL
in igc_ethtool_set_link_ksettings() (Simon)
- dynamically override hw->fc.current_mode to igc_fc_none during
link configuration instead of mutating requested_mode (Simon)
Changes in v4:
- Validate that autoneg is AUTONEG_ENABLE or AUTONEG_DISABLE early
in igc_ethtool_set_link_ksettings() to avoid passing unexpected
values to igc_handle_autoneg_disabled(). (Simon Horman)
Changes in v3:
- Modify condition from "if (duplex == DUPLEX_HALF)" to
"if (duplex != DUPLEX_FULL)". (Simon Horman)
Changes in v2:
- When forcing half-duplex, set hw->fc.requested_mode = igc_fc_none,
since half-duplex cannot support flow control per IEEE 802.3.
(Simon Horman)
- Split the original single patch into three patches for clarity:
patches 1 and 2 are preparatory cleanups; patch 3 carries the
functional change.
v4 at:
https://patchwork.ozlabs.org/project/intel-wired-lan/cover/20260428060009.311393-1-khai.wen.tan@linux.intel.com/
v3 at:
https://patchwork.ozlabs.org/project/intel-wired-lan/cover/20260422155701.7420-1-khai.wen.tan@linux.intel.com/
v2 at:
https://patchwork.kernel.org/project/netdevbpf/patch/20260416015520.6090-4-khai.wen.tan@linux.intel.com/
v1 at:
https://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260409072747.217836-1-khai.wen.tan@linux.intel.com/
Faizal Rahim (4):
igc: remove unused autoneg_failed field
igc: move autoneg-enabled settings into igc_handle_autoneg_enabled()
igc: replace goto out with direct returns in
igc_config_fc_after_link_up()
igc: add support for forcing link speed without autonegotiation
drivers/net/ethernet/intel/igc/igc_base.c | 35 +++-
drivers/net/ethernet/intel/igc/igc_defines.h | 9 +-
drivers/net/ethernet/intel/igc/igc_ethtool.c | 210 +++++++++++++------
drivers/net/ethernet/intel/igc/igc_hw.h | 10 +-
drivers/net/ethernet/intel/igc/igc_mac.c | 35 ++--
drivers/net/ethernet/intel/igc/igc_main.c | 2 +-
drivers/net/ethernet/intel/igc/igc_phy.c | 65 +++++-
drivers/net/ethernet/intel/igc/igc_phy.h | 1 +
8 files changed, 268 insertions(+), 99 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-05-07 21:47 ` KhaiWenTan 2026-06-14 7:16 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-06-15 8:22 ` Kwapulinski, Piotr 2026-05-07 21:47 ` [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan ` (3 subsequent siblings) 4 siblings, 2 replies; 15+ messages in thread From: KhaiWenTan @ 2026-05-07 21:47 UTC (permalink / raw) To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov, Khai Wen Tan From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> autoneg_failed in struct igc_mac_info is never set in the igc driver. Remove the field and the dead code checking it in igc_config_fc_after_link_up(). The field originates from the e1000/e1000e fiber/serdes forced-link path, where MAC-level autoneg timeout sets it to signal the flow-control code to force pause. igc supports only copper, so it never needs to set this field. Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> --- drivers/net/ethernet/intel/igc/igc_hw.h | 1 - drivers/net/ethernet/intel/igc/igc_mac.c | 16 +--------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index be8a49a86d09..86ab8f566f44 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -92,7 +92,6 @@ struct igc_mac_info { bool asf_firmware_present; bool arc_subsystem_valid; - bool autoneg_failed; bool get_link_status; }; diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 7ac6637f8db7..142beb9ae557 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -438,28 +438,14 @@ void igc_config_collision_dist(struct igc_hw *hw) * Checks the status of auto-negotiation after link up to ensure that the * speed and duplex were not forced. If the link needed to be forced, then * flow control needs to be forced also. If auto-negotiation is enabled - * and did not fail, then we configure flow control based on our link - * partner. + * then we configure flow control based on our link partner. */ s32 igc_config_fc_after_link_up(struct igc_hw *hw) { u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; - struct igc_mac_info *mac = &hw->mac; u16 speed, duplex; s32 ret_val = 0; - /* Check for the case where we have fiber media and auto-neg failed - * so we had to force link. In this case, we need to force the - * configuration of the MAC to match the "fc" parameter. - */ - if (mac->autoneg_failed) - ret_val = igc_force_mac_fc(hw); - - if (ret_val) { - hw_dbg("Error forcing flow control settings\n"); - goto out; - } - /* In auto-neg, we need to check and see if Auto-Neg has completed, * and if so, how the PHY and link partner has flow control * configured. -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field 2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan @ 2026-06-14 7:16 ` Ruinskiy, Dima 2026-06-22 8:10 ` Kadosh, MoriyaX 2026-06-15 8:22 ` Kwapulinski, Piotr 1 sibling, 1 reply; 15+ messages in thread From: Ruinskiy, Dima @ 2026-06-14 7:16 UTC (permalink / raw) To: KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov On 08/05/2026 0:47, KhaiWenTan wrote: > From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > > autoneg_failed in struct igc_mac_info is never set in the igc driver. > Remove the field and the dead code checking it in > igc_config_fc_after_link_up(). > > The field originates from the e1000/e1000e fiber/serdes forced-link > path, where MAC-level autoneg timeout sets it to signal the flow-control > code to force pause. igc supports only copper, so it never needs to set > this field. > > Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> > Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> > Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> > --- > drivers/net/ethernet/intel/igc/igc_hw.h | 1 - > drivers/net/ethernet/intel/igc/igc_mac.c | 16 +--------------- > 2 files changed, 1 insertion(+), 16 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h > index be8a49a86d09..86ab8f566f44 100644 > --- a/drivers/net/ethernet/intel/igc/igc_hw.h > +++ b/drivers/net/ethernet/intel/igc/igc_hw.h > @@ -92,7 +92,6 @@ struct igc_mac_info { > bool asf_firmware_present; > bool arc_subsystem_valid; > > - bool autoneg_failed; > bool get_link_status; > }; > > diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c > index 7ac6637f8db7..142beb9ae557 100644 > --- a/drivers/net/ethernet/intel/igc/igc_mac.c > +++ b/drivers/net/ethernet/intel/igc/igc_mac.c > @@ -438,28 +438,14 @@ void igc_config_collision_dist(struct igc_hw *hw) > * Checks the status of auto-negotiation after link up to ensure that the > * speed and duplex were not forced. If the link needed to be forced, then > * flow control needs to be forced also. If auto-negotiation is enabled > - * and did not fail, then we configure flow control based on our link > - * partner. > + * then we configure flow control based on our link partner. > */ > s32 igc_config_fc_after_link_up(struct igc_hw *hw) > { > u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; > - struct igc_mac_info *mac = &hw->mac; > u16 speed, duplex; > s32 ret_val = 0; > > - /* Check for the case where we have fiber media and auto-neg failed > - * so we had to force link. In this case, we need to force the > - * configuration of the MAC to match the "fc" parameter. > - */ > - if (mac->autoneg_failed) > - ret_val = igc_force_mac_fc(hw); > - > - if (ret_val) { > - hw_dbg("Error forcing flow control settings\n"); > - goto out; > - } > - > /* In auto-neg, we need to check and see if Auto-Neg has completed, > * and if so, how the PHY and link partner has flow control > * configured. Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field 2026-06-14 7:16 ` [Intel-wired-lan] " Ruinskiy, Dima @ 2026-06-22 8:10 ` Kadosh, MoriyaX 0 siblings, 0 replies; 15+ messages in thread From: Kadosh, MoriyaX @ 2026-06-22 8:10 UTC (permalink / raw) To: Ruinskiy, Dima, KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov On 14/06/2026 10:16, Ruinskiy, Dima wrote: > On 08/05/2026 0:47, KhaiWenTan wrote: >> From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> >> autoneg_failed in struct igc_mac_info is never set in the igc driver. >> Remove the field and the dead code checking it in >> igc_config_fc_after_link_up(). >> >> The field originates from the e1000/e1000e fiber/serdes forced-link >> path, where MAC-level autoneg timeout sets it to signal the flow-control >> code to force pause. igc supports only copper, so it never needs to set >> this field. >> >> Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> >> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> >> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> >> --- >> drivers/net/ethernet/intel/igc/igc_hw.h | 1 - >> drivers/net/ethernet/intel/igc/igc_mac.c | 16 +--------------- >> 2 files changed, 1 insertion(+), 16 deletions(-) >> >> diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ >> ethernet/intel/igc/igc_hw.h >> index be8a49a86d09..86ab8f566f44 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_hw.h >> +++ b/drivers/net/ethernet/intel/igc/igc_hw.h >> @@ -92,7 +92,6 @@ struct igc_mac_info { >> bool asf_firmware_present; >> bool arc_subsystem_valid; >> - bool autoneg_failed; >> bool get_link_status; >> }; >> diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ >> ethernet/intel/igc/igc_mac.c >> index 7ac6637f8db7..142beb9ae557 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_mac.c >> +++ b/drivers/net/ethernet/intel/igc/igc_mac.c >> @@ -438,28 +438,14 @@ void igc_config_collision_dist(struct igc_hw *hw) >> * Checks the status of auto-negotiation after link up to ensure >> that the >> * speed and duplex were not forced. If the link needed to be >> forced, then >> * flow control needs to be forced also. If auto-negotiation is >> enabled >> - * and did not fail, then we configure flow control based on our link >> - * partner. >> + * then we configure flow control based on our link partner. >> */ >> s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> { >> u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; >> - struct igc_mac_info *mac = &hw->mac; >> u16 speed, duplex; >> s32 ret_val = 0; >> - /* Check for the case where we have fiber media and auto-neg failed >> - * so we had to force link. In this case, we need to force the >> - * configuration of the MAC to match the "fc" parameter. >> - */ >> - if (mac->autoneg_failed) >> - ret_val = igc_force_mac_fc(hw); >> - >> - if (ret_val) { >> - hw_dbg("Error forcing flow control settings\n"); >> - goto out; >> - } >> - >> /* In auto-neg, we need to check and see if Auto-Neg has completed, >> * and if so, how the PHY and link partner has flow control >> * configured. > Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> Tested-by: Moriya Kadosh <moriyax.kadosh@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [Intel-wired-lan] [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field 2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan 2026-06-14 7:16 ` [Intel-wired-lan] " Ruinskiy, Dima @ 2026-06-15 8:22 ` Kwapulinski, Piotr 1 sibling, 0 replies; 15+ messages in thread From: Kwapulinski, Piotr @ 2026-06-15 8:22 UTC (permalink / raw) To: KhaiWenTan, Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Abdul Rahim, Faizal, Looi, Hong Aun, Blanco Alcaine, Hector, Tan, Khai Wen, Faizal Rahim, Loktionov, Aleksandr >-----Original Message----- >From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of KhaiWenTan >Sent: Thursday, May 7, 2026 11:47 PM >To: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw <przemyslaw.kitszel@intel.com>; andrew+netdev@lunn.ch; davem@davemloft.net; edumazet@google.com; kuba@kernel.org; pabeni@redhat.com >Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Abdul Rahim, Faizal <faizal.abdul.rahim@intel.com>; Looi, Hong Aun <hong.aun.looi@intel.com>; Blanco Alcaine, Hector <hector.blanco.alcaine@intel.com>; Tan, Khai Wen <khai.wen.tan@intel.com>; Faizal Rahim <faizal.abdul.rahim@linux.intel.com>; Loktionov, Aleksandr <aleksandr.loktionov@intel.com>; Khai Wen Tan <khai.wen.tan@linux.intel.com> >Subject: [Intel-wired-lan] [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field > >From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > >autoneg_failed in struct igc_mac_info is never set in the igc driver. >Remove the field and the dead code checking it in igc_config_fc_after_link_up(). > >The field originates from the e1000/e1000e fiber/serdes forced-link path, where MAC-level autoneg timeout sets it to signal the flow-control code to force pause. igc supports only copper, so it never needs to set this field. > >Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> >Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> >Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> >--- > drivers/net/ethernet/intel/igc/igc_hw.h | 1 - drivers/net/ethernet/intel/igc/igc_mac.c | 16 +--------------- > 2 files changed, 1 insertion(+), 16 deletions(-) > >diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h >index be8a49a86d09..86ab8f566f44 100644 >--- a/drivers/net/ethernet/intel/igc/igc_hw.h >+++ b/drivers/net/ethernet/intel/igc/igc_hw.h >@@ -92,7 +92,6 @@ struct igc_mac_info { > bool asf_firmware_present; > bool arc_subsystem_valid; > >- bool autoneg_failed; > bool get_link_status; > }; > >diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c >index 7ac6637f8db7..142beb9ae557 100644 >--- a/drivers/net/ethernet/intel/igc/igc_mac.c >+++ b/drivers/net/ethernet/intel/igc/igc_mac.c >@@ -438,28 +438,14 @@ void igc_config_collision_dist(struct igc_hw *hw) > * Checks the status of auto-negotiation after link up to ensure that the > * speed and duplex were not forced. If the link needed to be forced, then > * flow control needs to be forced also. If auto-negotiation is enabled >- * and did not fail, then we configure flow control based on our link >- * partner. >+ * then we configure flow control based on our link partner. > */ > s32 igc_config_fc_after_link_up(struct igc_hw *hw) { > u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; >- struct igc_mac_info *mac = &hw->mac; > u16 speed, duplex; > s32 ret_val = 0; > >- /* Check for the case where we have fiber media and auto-neg failed >- * so we had to force link. In this case, we need to force the >- * configuration of the MAC to match the "fc" parameter. >- */ >- if (mac->autoneg_failed) >- ret_val = igc_force_mac_fc(hw); >- >- if (ret_val) { >- hw_dbg("Error forcing flow control settings\n"); >- goto out; >- } >- > /* In auto-neg, we need to check and see if Auto-Neg has completed, > * and if so, how the PHY and link partner has flow control > * configured. >-- >2.43.0 Reviewed-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan @ 2026-05-07 21:47 ` KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-05-07 21:47 ` [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() KhaiWenTan ` (2 subsequent siblings) 4 siblings, 1 reply; 15+ messages in thread From: KhaiWenTan @ 2026-05-07 21:47 UTC (permalink / raw) To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov, Khai Wen Tan From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Move the advertised link modes and flow control configuration from igc_ethtool_set_link_ksettings() into igc_handle_autoneg_enabled(). No functional change. Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 72 ++++++++++++-------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 0122009bedd0..cfcbf2fdad6e 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -2000,6 +2000,49 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, return 0; } +/** + * igc_handle_autoneg_enabled - Configure autonegotiation advertisement + * @adapter: private driver structure + * @cmd: ethtool link ksettings from user + * + * Records advertised speeds and flow control settings when autoneg + * is enabled. + */ +static void igc_handle_autoneg_enabled(struct igc_adapter *adapter, + const struct ethtool_link_ksettings *cmd) +{ + struct igc_hw *hw = &adapter->hw; + u16 advertised = 0; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 2500baseT_Full)) + advertised |= ADVERTISE_2500_FULL; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 1000baseT_Full)) + advertised |= ADVERTISE_1000_FULL; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 100baseT_Full)) + advertised |= ADVERTISE_100_FULL; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 100baseT_Half)) + advertised |= ADVERTISE_100_HALF; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 10baseT_Full)) + advertised |= ADVERTISE_10_FULL; + + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, + 10baseT_Half)) + advertised |= ADVERTISE_10_HALF; + + hw->phy.autoneg_advertised = advertised; + if (adapter->fc_autoneg) + hw->fc.requested_mode = igc_fc_default; +} + static int igc_ethtool_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) @@ -2007,7 +2050,6 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, struct igc_adapter *adapter = netdev_priv(netdev); struct net_device *dev = adapter->netdev; struct igc_hw *hw = &adapter->hw; - u16 advertised = 0; /* When adapter in resetting mode, autoneg/speed/duplex * cannot be changed @@ -2032,34 +2074,8 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) usleep_range(1000, 2000); - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 2500baseT_Full)) - advertised |= ADVERTISE_2500_FULL; - - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 1000baseT_Full)) - advertised |= ADVERTISE_1000_FULL; - - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 100baseT_Full)) - advertised |= ADVERTISE_100_FULL; - - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 100baseT_Half)) - advertised |= ADVERTISE_100_HALF; - - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 10baseT_Full)) - advertised |= ADVERTISE_10_FULL; - - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, - 10baseT_Half)) - advertised |= ADVERTISE_10_HALF; - if (cmd->base.autoneg == AUTONEG_ENABLE) { - hw->phy.autoneg_advertised = advertised; - if (adapter->fc_autoneg) - hw->fc.requested_mode = igc_fc_default; + igc_handle_autoneg_enabled(adapter, cmd); } else { netdev_info(dev, "Force mode currently not supported\n"); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() 2026-05-07 21:47 ` [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan @ 2026-06-14 7:17 ` Ruinskiy, Dima 2026-06-22 8:08 ` Kadosh, MoriyaX 0 siblings, 1 reply; 15+ messages in thread From: Ruinskiy, Dima @ 2026-06-14 7:17 UTC (permalink / raw) To: KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov On 08/05/2026 0:47, KhaiWenTan wrote: > From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > > Move the advertised link modes and flow control configuration from > igc_ethtool_set_link_ksettings() into igc_handle_autoneg_enabled(). > > No functional change. > > Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> > Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> > Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> > --- > drivers/net/ethernet/intel/igc/igc_ethtool.c | 72 ++++++++++++-------- > 1 file changed, 44 insertions(+), 28 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c > index 0122009bedd0..cfcbf2fdad6e 100644 > --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c > +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c > @@ -2000,6 +2000,49 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, > return 0; > } > > +/** > + * igc_handle_autoneg_enabled - Configure autonegotiation advertisement > + * @adapter: private driver structure > + * @cmd: ethtool link ksettings from user > + * > + * Records advertised speeds and flow control settings when autoneg > + * is enabled. > + */ > +static void igc_handle_autoneg_enabled(struct igc_adapter *adapter, > + const struct ethtool_link_ksettings *cmd) > +{ > + struct igc_hw *hw = &adapter->hw; > + u16 advertised = 0; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 2500baseT_Full)) > + advertised |= ADVERTISE_2500_FULL; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 1000baseT_Full)) > + advertised |= ADVERTISE_1000_FULL; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 100baseT_Full)) > + advertised |= ADVERTISE_100_FULL; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 100baseT_Half)) > + advertised |= ADVERTISE_100_HALF; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 10baseT_Full)) > + advertised |= ADVERTISE_10_FULL; > + > + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > + 10baseT_Half)) > + advertised |= ADVERTISE_10_HALF; > + > + hw->phy.autoneg_advertised = advertised; > + if (adapter->fc_autoneg) > + hw->fc.requested_mode = igc_fc_default; > +} > + > static int > igc_ethtool_set_link_ksettings(struct net_device *netdev, > const struct ethtool_link_ksettings *cmd) > @@ -2007,7 +2050,6 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, > struct igc_adapter *adapter = netdev_priv(netdev); > struct net_device *dev = adapter->netdev; > struct igc_hw *hw = &adapter->hw; > - u16 advertised = 0; > > /* When adapter in resetting mode, autoneg/speed/duplex > * cannot be changed > @@ -2032,34 +2074,8 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, > while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) > usleep_range(1000, 2000); > > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 2500baseT_Full)) > - advertised |= ADVERTISE_2500_FULL; > - > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 1000baseT_Full)) > - advertised |= ADVERTISE_1000_FULL; > - > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 100baseT_Full)) > - advertised |= ADVERTISE_100_FULL; > - > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 100baseT_Half)) > - advertised |= ADVERTISE_100_HALF; > - > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 10baseT_Full)) > - advertised |= ADVERTISE_10_FULL; > - > - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, > - 10baseT_Half)) > - advertised |= ADVERTISE_10_HALF; > - > if (cmd->base.autoneg == AUTONEG_ENABLE) { > - hw->phy.autoneg_advertised = advertised; > - if (adapter->fc_autoneg) > - hw->fc.requested_mode = igc_fc_default; > + igc_handle_autoneg_enabled(adapter, cmd); > } else { > netdev_info(dev, "Force mode currently not supported\n"); > } Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima @ 2026-06-22 8:08 ` Kadosh, MoriyaX 0 siblings, 0 replies; 15+ messages in thread From: Kadosh, MoriyaX @ 2026-06-22 8:08 UTC (permalink / raw) To: Ruinskiy, Dima, KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov On 14/06/2026 10:17, Ruinskiy, Dima wrote: > On 08/05/2026 0:47, KhaiWenTan wrote: >> From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> >> Move the advertised link modes and flow control configuration from >> igc_ethtool_set_link_ksettings() into igc_handle_autoneg_enabled(). >> >> No functional change. >> >> Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> >> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> >> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> >> --- >> drivers/net/ethernet/intel/igc/igc_ethtool.c | 72 ++++++++++++-------- >> 1 file changed, 44 insertions(+), 28 deletions(-) >> >> diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/ >> net/ethernet/intel/igc/igc_ethtool.c >> index 0122009bedd0..cfcbf2fdad6e 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c >> +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c >> @@ -2000,6 +2000,49 @@ static int >> igc_ethtool_get_link_ksettings(struct net_device *netdev, >> return 0; >> } >> +/** >> + * igc_handle_autoneg_enabled - Configure autonegotiation advertisement >> + * @adapter: private driver structure >> + * @cmd: ethtool link ksettings from user >> + * >> + * Records advertised speeds and flow control settings when autoneg >> + * is enabled. >> + */ >> +static void igc_handle_autoneg_enabled(struct igc_adapter *adapter, >> + const struct ethtool_link_ksettings *cmd) >> +{ >> + struct igc_hw *hw = &adapter->hw; >> + u16 advertised = 0; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 2500baseT_Full)) >> + advertised |= ADVERTISE_2500_FULL; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 1000baseT_Full)) >> + advertised |= ADVERTISE_1000_FULL; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 100baseT_Full)) >> + advertised |= ADVERTISE_100_FULL; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 100baseT_Half)) >> + advertised |= ADVERTISE_100_HALF; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 10baseT_Full)) >> + advertised |= ADVERTISE_10_FULL; >> + >> + if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> + 10baseT_Half)) >> + advertised |= ADVERTISE_10_HALF; >> + >> + hw->phy.autoneg_advertised = advertised; >> + if (adapter->fc_autoneg) >> + hw->fc.requested_mode = igc_fc_default; >> +} >> + >> static int >> igc_ethtool_set_link_ksettings(struct net_device *netdev, >> const struct ethtool_link_ksettings *cmd) >> @@ -2007,7 +2050,6 @@ igc_ethtool_set_link_ksettings(struct net_device >> *netdev, >> struct igc_adapter *adapter = netdev_priv(netdev); >> struct net_device *dev = adapter->netdev; >> struct igc_hw *hw = &adapter->hw; >> - u16 advertised = 0; >> /* When adapter in resetting mode, autoneg/speed/duplex >> * cannot be changed >> @@ -2032,34 +2074,8 @@ igc_ethtool_set_link_ksettings(struct >> net_device *netdev, >> while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) >> usleep_range(1000, 2000); >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 2500baseT_Full)) >> - advertised |= ADVERTISE_2500_FULL; >> - >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 1000baseT_Full)) >> - advertised |= ADVERTISE_1000_FULL; >> - >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 100baseT_Full)) >> - advertised |= ADVERTISE_100_FULL; >> - >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 100baseT_Half)) >> - advertised |= ADVERTISE_100_HALF; >> - >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 10baseT_Full)) >> - advertised |= ADVERTISE_10_FULL; >> - >> - if (ethtool_link_ksettings_test_link_mode(cmd, advertising, >> - 10baseT_Half)) >> - advertised |= ADVERTISE_10_HALF; >> - >> if (cmd->base.autoneg == AUTONEG_ENABLE) { >> - hw->phy.autoneg_advertised = advertised; >> - if (adapter->fc_autoneg) >> - hw->fc.requested_mode = igc_fc_default; >> + igc_handle_autoneg_enabled(adapter, cmd); >> } else { >> netdev_info(dev, "Force mode currently not supported\n"); >> } > Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> Tested-by: Moriya Kadosh <moriyax.kadosh@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan 2026-05-07 21:47 ` [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan @ 2026-05-07 21:47 ` KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-05-07 21:47 ` [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-05-11 16:28 ` [PATCH iwl-next v5 0/4] " Simon Horman 4 siblings, 1 reply; 15+ messages in thread From: KhaiWenTan @ 2026-05-07 21:47 UTC (permalink / raw) To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Khai Wen Tan From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> The out: label only returns ret_val with no cleanup. The kernel coding style guide states: "If there is no cleanup needed then just return directly." (Documentation/process/coding-style.rst, section 7). This improves readability ahead of a subsequent patch that introduces a new goto label in this function. No functional change. Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> --- drivers/net/ethernet/intel/igc/igc_mac.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 142beb9ae557..0a3d3f357505 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -458,15 +458,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); if (ret_val) - goto out; + return ret_val; ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); if (ret_val) - goto out; + return ret_val; if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { hw_dbg("Copper PHY and Auto Neg has not completed.\n"); - goto out; + return ret_val; } /* The AutoNeg process has completed, so we now need to @@ -478,11 +478,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg); if (ret_val) - goto out; + return ret_val; ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg); if (ret_val) - goto out; + return ret_val; /* Two bits in the Auto Negotiation Advertisement Register * (Address 4) and two bits in the Auto Negotiation Base * Page Ability Register (Address 5) determine flow control @@ -598,7 +598,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); if (ret_val) { hw_dbg("Error getting link speed and duplex\n"); - goto out; + return ret_val; } if (duplex == HALF_DUPLEX) @@ -610,10 +610,9 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) ret_val = igc_force_mac_fc(hw); if (ret_val) { hw_dbg("Error forcing flow control settings\n"); - goto out; + return ret_val; } -out: return ret_val; } -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() 2026-05-07 21:47 ` [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() KhaiWenTan @ 2026-06-14 7:17 ` Ruinskiy, Dima 2026-06-22 8:11 ` Kadosh, MoriyaX 0 siblings, 1 reply; 15+ messages in thread From: Ruinskiy, Dima @ 2026-06-14 7:17 UTC (permalink / raw) To: KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim On 08/05/2026 0:47, KhaiWenTan wrote: > From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > > The out: label only returns ret_val with no cleanup. The kernel coding > style guide states: "If there is no cleanup needed then just return > directly." (Documentation/process/coding-style.rst, section 7). > > This improves readability ahead of a subsequent patch that introduces a > new goto label in this function. > > No functional change. > > Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> > Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> > --- > drivers/net/ethernet/intel/igc/igc_mac.c | 15 +++++++-------- > 1 file changed, 7 insertions(+), 8 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c > index 142beb9ae557..0a3d3f357505 100644 > --- a/drivers/net/ethernet/intel/igc/igc_mac.c > +++ b/drivers/net/ethernet/intel/igc/igc_mac.c > @@ -458,15 +458,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, > &mii_status_reg); > if (ret_val) > - goto out; > + return ret_val; > ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, > &mii_status_reg); > if (ret_val) > - goto out; > + return ret_val; > > if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { > hw_dbg("Copper PHY and Auto Neg has not completed.\n"); > - goto out; > + return ret_val; > } > > /* The AutoNeg process has completed, so we now need to > @@ -478,11 +478,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, > &mii_nway_adv_reg); > if (ret_val) > - goto out; > + return ret_val; > ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, > &mii_nway_lp_ability_reg); > if (ret_val) > - goto out; > + return ret_val; > /* Two bits in the Auto Negotiation Advertisement Register > * (Address 4) and two bits in the Auto Negotiation Base > * Page Ability Register (Address 5) determine flow control > @@ -598,7 +598,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); > if (ret_val) { > hw_dbg("Error getting link speed and duplex\n"); > - goto out; > + return ret_val; > } > > if (duplex == HALF_DUPLEX) > @@ -610,10 +610,9 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > ret_val = igc_force_mac_fc(hw); > if (ret_val) { > hw_dbg("Error forcing flow control settings\n"); > - goto out; > + return ret_val; > } > > -out: > return ret_val; > } > Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima @ 2026-06-22 8:11 ` Kadosh, MoriyaX 0 siblings, 0 replies; 15+ messages in thread From: Kadosh, MoriyaX @ 2026-06-22 8:11 UTC (permalink / raw) To: Ruinskiy, Dima, KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim On 14/06/2026 10:17, Ruinskiy, Dima wrote: > On 08/05/2026 0:47, KhaiWenTan wrote: >> From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> >> The out: label only returns ret_val with no cleanup. The kernel coding >> style guide states: "If there is no cleanup needed then just return >> directly." (Documentation/process/coding-style.rst, section 7). >> >> This improves readability ahead of a subsequent patch that introduces a >> new goto label in this function. >> >> No functional change. >> >> Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> >> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> >> --- >> drivers/net/ethernet/intel/igc/igc_mac.c | 15 +++++++-------- >> 1 file changed, 7 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ >> ethernet/intel/igc/igc_mac.c >> index 142beb9ae557..0a3d3f357505 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_mac.c >> +++ b/drivers/net/ethernet/intel/igc/igc_mac.c >> @@ -458,15 +458,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, >> &mii_status_reg); >> if (ret_val) >> - goto out; >> + return ret_val; >> ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, >> &mii_status_reg); >> if (ret_val) >> - goto out; >> + return ret_val; >> if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { >> hw_dbg("Copper PHY and Auto Neg has not completed.\n"); >> - goto out; >> + return ret_val; >> } >> /* The AutoNeg process has completed, so we now need to >> @@ -478,11 +478,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, >> &mii_nway_adv_reg); >> if (ret_val) >> - goto out; >> + return ret_val; >> ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, >> &mii_nway_lp_ability_reg); >> if (ret_val) >> - goto out; >> + return ret_val; >> /* Two bits in the Auto Negotiation Advertisement Register >> * (Address 4) and two bits in the Auto Negotiation Base >> * Page Ability Register (Address 5) determine flow control >> @@ -598,7 +598,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); >> if (ret_val) { >> hw_dbg("Error getting link speed and duplex\n"); >> - goto out; >> + return ret_val; >> } >> if (duplex == HALF_DUPLEX) >> @@ -610,10 +610,9 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> ret_val = igc_force_mac_fc(hw); >> if (ret_val) { >> hw_dbg("Error forcing flow control settings\n"); >> - goto out; >> + return ret_val; >> } >> -out: >> return ret_val; >> } > Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> Tested-by: Moriya Kadosh <moriyax.kadosh@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan ` (2 preceding siblings ...) 2026-05-07 21:47 ` [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() KhaiWenTan @ 2026-05-07 21:47 ` KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-05-11 16:28 ` [PATCH iwl-next v5 0/4] " Simon Horman 4 siblings, 1 reply; 15+ messages in thread From: KhaiWenTan @ 2026-05-07 21:47 UTC (permalink / raw) To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim, Khai Wen Tan From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Allow users to force 10/100 Mb/s link speed and duplex via ethtool when autonegotiation is disabled. Previously, the driver rejected these requests with "Force mode currently not supported.". Forcing at 1000 Mb/s and 2500 Mb/s is not supported. Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> --- drivers/net/ethernet/intel/igc/igc_base.c | 35 ++++- drivers/net/ethernet/intel/igc/igc_defines.h | 9 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 138 ++++++++++++++----- drivers/net/ethernet/intel/igc/igc_hw.h | 9 ++ drivers/net/ethernet/intel/igc/igc_mac.c | 12 ++ drivers/net/ethernet/intel/igc/igc_main.c | 2 +- drivers/net/ethernet/intel/igc/igc_phy.c | 65 ++++++++- drivers/net/ethernet/intel/igc/igc_phy.h | 1 + 8 files changed, 220 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 1613b562d17c..ab9120a3127f 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw) u32 ctrl; ctrl = rd32(IGC_CTRL); - ctrl |= IGC_CTRL_SLU; - ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX); - wr32(IGC_CTRL, ctrl); - - ret_val = igc_setup_copper_link(hw); + ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX | + IGC_CTRL_SPEED_MASK | IGC_CTRL_FD); + + if (hw->mac.autoneg_enabled) { + ctrl |= IGC_CTRL_SLU; + wr32(IGC_CTRL, ctrl); + ret_val = igc_setup_copper_link(hw); + } else { + ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX; + + switch (hw->mac.forced_speed_duplex) { + case IGC_FORCED_10H: + ctrl |= IGC_CTRL_SPEED_10; + break; + case IGC_FORCED_10F: + ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD; + break; + case IGC_FORCED_100H: + ctrl |= IGC_CTRL_SPEED_100; + break; + case IGC_FORCED_100F: + ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD; + break; + default: + return -IGC_ERR_CONFIG; + } + wr32(IGC_CTRL, ctrl); + ret_val = igc_setup_copper_link(hw); + } return ret_val; } @@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = { .reset = igc_phy_hw_reset, .read_reg = igc_read_phy_reg_gpy, .write_reg = igc_write_phy_reg_gpy, + .force_speed_duplex = igc_force_speed_duplex, }; const struct igc_info igc_base_info = { diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 9482ab11f050..3f504751c2d9 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -129,10 +129,13 @@ #define IGC_ERR_SWFW_SYNC 13 /* Device Control */ +#define IGC_CTRL_FD BIT(0) /* Full Duplex */ #define IGC_CTRL_RST 0x04000000 /* Global reset */ - #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ #define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define IGC_CTRL_SPEED_MASK GENMASK(10, 8) +#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0) +#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1) #define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */ #define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ @@ -673,6 +676,10 @@ #define IGC_GEN_POLL_TIMEOUT 1920 /* PHY Control Register */ +#define MII_CR_SPEED_MASK (BIT(6) | BIT(13)) +#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */ +#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */ +#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full Duplex */ #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ #define MII_CR_POWER_DOWN 0x0800 /* Power down */ #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index cfcbf2fdad6e..b103836a895f 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1914,44 +1914,58 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); - /* advertising link modes */ - if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); - if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); - if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); - if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); - if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); - if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) - ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full); - /* set autoneg settings */ ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); - ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); + if (hw->mac.autoneg_enabled) { + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); + cmd->base.autoneg = AUTONEG_ENABLE; + + /* advertising link modes only apply when autoneg is on */ + if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10baseT_Half); + if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10baseT_Full); + if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 100baseT_Half); + if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 100baseT_Full); + if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 1000baseT_Full); + if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 2500baseT_Full); + + /* Set pause flow control advertising */ + switch (hw->fc.requested_mode) { + case igc_fc_full: + ethtool_link_ksettings_add_link_mode(cmd, advertising, + Pause); + break; + case igc_fc_rx_pause: + ethtool_link_ksettings_add_link_mode(cmd, advertising, + Pause); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + Asym_Pause); + break; + case igc_fc_tx_pause: + ethtool_link_ksettings_add_link_mode(cmd, advertising, + Asym_Pause); + break; + default: + break; + } + } else { + cmd->base.autoneg = AUTONEG_DISABLE; + } - /* Set pause flow control settings */ + /* Pause is always supported */ ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); - switch (hw->fc.requested_mode) { - case igc_fc_full: - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); - break; - case igc_fc_rx_pause: - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - Asym_Pause); - break; - case igc_fc_tx_pause: - ethtool_link_ksettings_add_link_mode(cmd, advertising, - Asym_Pause); - break; - default: - break; - } - status = pm_runtime_suspended(&adapter->pdev->dev) ? 0 : rd32(IGC_STATUS); @@ -1983,7 +1997,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, cmd->base.duplex = DUPLEX_UNKNOWN; } cmd->base.speed = speed; - cmd->base.autoneg = AUTONEG_ENABLE; /* MDI-X => 2; MDI =>1; Invalid =>0 */ if (hw->phy.media_type == igc_media_type_copper) @@ -2000,6 +2013,37 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, return 0; } +/** + * igc_handle_autoneg_disabled - Configure forced speed/duplex settings + * @adapter: private driver structure + * @speed: requested speed (must be SPEED_10 or SPEED_100) + * @duplex: requested duplex + * + * Records forced speed/duplex when autoneg is disabled. + * Caller must validate speed before calling this function. + */ +static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, u32 speed, + u8 duplex) +{ + struct igc_mac_info *mac = &adapter->hw.mac; + + switch (speed) { + case SPEED_10: + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? + IGC_FORCED_10F : IGC_FORCED_10H; + break; + case SPEED_100: + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? + IGC_FORCED_100F : IGC_FORCED_100H; + break; + default: + WARN_ONCE(1, "Unsupported speed %u\n", speed); + return; + } + + mac->autoneg_enabled = false; +} + /** * igc_handle_autoneg_enabled - Configure autonegotiation advertisement * @adapter: private driver structure @@ -2038,6 +2082,7 @@ static void igc_handle_autoneg_enabled(struct igc_adapter *adapter, 10baseT_Half)) advertised |= ADVERTISE_10_HALF; + hw->mac.autoneg_enabled = true; hw->phy.autoneg_advertised = advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = igc_fc_default; @@ -2059,6 +2104,12 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, return -EINVAL; } + if (cmd->base.autoneg != AUTONEG_ENABLE && + cmd->base.autoneg != AUTONEG_DISABLE) { + netdev_info(dev, "Unsupported autoneg setting\n"); + return -EINVAL; + } + /* MDI setting is only allowed when autoneg enabled because * some hardware doesn't allow MDI setting when speed or * duplex is forced. @@ -2071,14 +2122,25 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, } } + if (cmd->base.autoneg == AUTONEG_DISABLE) { + if (cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) { + netdev_info(dev, "Unsupported speed for forced link\n"); + return -EINVAL; + } + if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) { + netdev_info(dev, "Duplex must be half or full for forced link\n"); + return -EINVAL; + } + } + while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) usleep_range(1000, 2000); - if (cmd->base.autoneg == AUTONEG_ENABLE) { + if (cmd->base.autoneg == AUTONEG_ENABLE) igc_handle_autoneg_enabled(adapter, cmd); - } else { - netdev_info(dev, "Force mode currently not supported\n"); - } + else + igc_handle_autoneg_disabled(adapter, cmd->base.speed, + cmd->base.duplex); /* MDI-X => 2; MDI => 1; Auto => 3 */ if (cmd->base.eth_tp_mdix_ctrl) { diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 86ab8f566f44..62aaee55668a 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -73,6 +73,13 @@ struct igc_info { extern const struct igc_info igc_base_info; +enum igc_forced_speed_duplex { + IGC_FORCED_10H, + IGC_FORCED_10F, + IGC_FORCED_100H, + IGC_FORCED_100F, +}; + struct igc_mac_info { struct igc_mac_operations ops; @@ -93,6 +100,8 @@ struct igc_mac_info { bool arc_subsystem_valid; bool get_link_status; + bool autoneg_enabled; + enum igc_forced_speed_duplex forced_speed_duplex; }; struct igc_nvm_operations { diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 0a3d3f357505..d6f3f6618469 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -446,6 +446,17 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) u16 speed, duplex; s32 ret_val = 0; + /* Without autoneg, flow control capability is not exchanged with the + * link partner. IEEE 802.3 prohibits flow control in half-duplex mode. + */ + if (!hw->mac.autoneg_enabled) { + if (hw->mac.forced_speed_duplex == IGC_FORCED_10H || + hw->mac.forced_speed_duplex == IGC_FORCED_100H) + hw->fc.current_mode = igc_fc_none; + + goto force_fc; + } + /* In auto-neg, we need to check and see if Auto-Neg has completed, * and if so, how the PHY and link partner has flow control * configured. @@ -607,6 +618,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) /* Now we call a subroutine to actually force the MAC * controller to use the correct flow control settings. */ +force_fc: ret_val = igc_force_mac_fc(hw); if (ret_val) { hw_dbg("Error forcing flow control settings\n"); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 72bc5128d8b8..437e1d1ef1e4 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev, /* Initialize link properties that are user-changeable */ adapter->fc_autoneg = true; hw->phy.autoneg_advertised = 0xaf; - + hw->mac.autoneg_enabled = true; hw->fc.requested_mode = igc_fc_default; hw->fc.current_mode = igc_fc_default; diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index 6c4d204aecfa..4cf737fb3b21 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw) s32 ret_val = 0; bool link; - /* Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = igc_copper_link_autoneg(hw); - if (ret_val) - goto out; + if (hw->mac.autoneg_enabled) { + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. + */ + ret_val = igc_copper_link_autoneg(hw); + if (ret_val) + goto out; + } else { + ret_val = hw->phy.ops.force_speed_duplex(hw); + if (ret_val) { + hw_dbg("Error Forcing Speed/Duplex\n"); + goto out; + } + } /* Check link status. Wait up to 100 microseconds for link to become * valid. @@ -778,3 +786,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw) return gphy_version; } + +/** + * igc_force_speed_duplex - Force PHY speed and duplex settings + * @hw: pointer to the HW structure + * + * Programs the GPY PHY control register to disable autonegotiation + * and force the speed/duplex indicated by hw->mac.forced_speed_duplex. + */ +s32 igc_force_speed_duplex(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + u16 phy_ctrl; + s32 ret_val; + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + return ret_val; + + phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN | + MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + switch (hw->mac.forced_speed_duplex) { + case IGC_FORCED_10H: + phy_ctrl |= MII_CR_SPEED_10; + break; + case IGC_FORCED_10F: + phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN; + break; + case IGC_FORCED_100H: + phy_ctrl |= MII_CR_SPEED_100; + break; + case IGC_FORCED_100F: + phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN; + break; + default: + return -IGC_ERR_CONFIG; + } + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + return ret_val; + + hw->mac.get_link_status = true; + return 0; +} diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h index 832a7e359f18..d37a89174826 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.h +++ b/drivers/net/ethernet/intel/igc/igc_phy.h @@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw); s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data); u16 igc_read_phy_fw_version(struct igc_hw *hw); +s32 igc_force_speed_duplex(struct igc_hw *hw); #endif -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation 2026-05-07 21:47 ` [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-06-14 7:17 ` Ruinskiy, Dima 2026-06-22 8:12 ` Kadosh, MoriyaX 0 siblings, 1 reply; 15+ messages in thread From: Ruinskiy, Dima @ 2026-06-14 7:17 UTC (permalink / raw) To: KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim On 08/05/2026 0:47, KhaiWenTan wrote: > From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > > Allow users to force 10/100 Mb/s link speed and duplex via ethtool > when autonegotiation is disabled. Previously, the driver rejected > these requests with "Force mode currently not supported.". > > Forcing at 1000 Mb/s and 2500 Mb/s is not supported. > > Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> > Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> > --- > drivers/net/ethernet/intel/igc/igc_base.c | 35 ++++- > drivers/net/ethernet/intel/igc/igc_defines.h | 9 +- > drivers/net/ethernet/intel/igc/igc_ethtool.c | 138 ++++++++++++++----- > drivers/net/ethernet/intel/igc/igc_hw.h | 9 ++ > drivers/net/ethernet/intel/igc/igc_mac.c | 12 ++ > drivers/net/ethernet/intel/igc/igc_main.c | 2 +- > drivers/net/ethernet/intel/igc/igc_phy.c | 65 ++++++++- > drivers/net/ethernet/intel/igc/igc_phy.h | 1 + > 8 files changed, 220 insertions(+), 51 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c > index 1613b562d17c..ab9120a3127f 100644 > --- a/drivers/net/ethernet/intel/igc/igc_base.c > +++ b/drivers/net/ethernet/intel/igc/igc_base.c > @@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw) > u32 ctrl; > > ctrl = rd32(IGC_CTRL); > - ctrl |= IGC_CTRL_SLU; > - ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX); > - wr32(IGC_CTRL, ctrl); > - > - ret_val = igc_setup_copper_link(hw); > + ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX | > + IGC_CTRL_SPEED_MASK | IGC_CTRL_FD); > + > + if (hw->mac.autoneg_enabled) { > + ctrl |= IGC_CTRL_SLU; > + wr32(IGC_CTRL, ctrl); > + ret_val = igc_setup_copper_link(hw); > + } else { > + ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX; > + > + switch (hw->mac.forced_speed_duplex) { > + case IGC_FORCED_10H: > + ctrl |= IGC_CTRL_SPEED_10; > + break; > + case IGC_FORCED_10F: > + ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD; > + break; > + case IGC_FORCED_100H: > + ctrl |= IGC_CTRL_SPEED_100; > + break; > + case IGC_FORCED_100F: > + ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD; > + break; > + default: > + return -IGC_ERR_CONFIG; > + } > + wr32(IGC_CTRL, ctrl); > + ret_val = igc_setup_copper_link(hw); > + } > > return ret_val; > } > @@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = { > .reset = igc_phy_hw_reset, > .read_reg = igc_read_phy_reg_gpy, > .write_reg = igc_write_phy_reg_gpy, > + .force_speed_duplex = igc_force_speed_duplex, > }; > > const struct igc_info igc_base_info = { > diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h > index 9482ab11f050..3f504751c2d9 100644 > --- a/drivers/net/ethernet/intel/igc/igc_defines.h > +++ b/drivers/net/ethernet/intel/igc/igc_defines.h > @@ -129,10 +129,13 @@ > #define IGC_ERR_SWFW_SYNC 13 > > /* Device Control */ > +#define IGC_CTRL_FD BIT(0) /* Full Duplex */ > #define IGC_CTRL_RST 0x04000000 /* Global reset */ > - > #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ > #define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ > +#define IGC_CTRL_SPEED_MASK GENMASK(10, 8) > +#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0) > +#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1) > #define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */ > #define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */ > #define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ > @@ -673,6 +676,10 @@ > #define IGC_GEN_POLL_TIMEOUT 1920 > > /* PHY Control Register */ > +#define MII_CR_SPEED_MASK (BIT(6) | BIT(13)) > +#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */ > +#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */ > +#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full Duplex */ > #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ > #define MII_CR_POWER_DOWN 0x0800 /* Power down */ > #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ > diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c > index cfcbf2fdad6e..b103836a895f 100644 > --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c > +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c > @@ -1914,44 +1914,58 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, > ethtool_link_ksettings_add_link_mode(cmd, supported, TP); > ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); > > - /* advertising link modes */ > - if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); > - if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); > - if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); > - if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); > - if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); > - if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) > - ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full); > - > /* set autoneg settings */ > ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); > - ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); > + if (hw->mac.autoneg_enabled) { > + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); > + cmd->base.autoneg = AUTONEG_ENABLE; > + > + /* advertising link modes only apply when autoneg is on */ > + if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 10baseT_Half); > + if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 10baseT_Full); > + if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 100baseT_Half); > + if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 100baseT_Full); > + if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 1000baseT_Full); > + if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + 2500baseT_Full); > + > + /* Set pause flow control advertising */ > + switch (hw->fc.requested_mode) { > + case igc_fc_full: > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + Pause); > + break; > + case igc_fc_rx_pause: > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + Pause); > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + Asym_Pause); > + break; > + case igc_fc_tx_pause: > + ethtool_link_ksettings_add_link_mode(cmd, advertising, > + Asym_Pause); > + break; > + default: > + break; > + } > + } else { > + cmd->base.autoneg = AUTONEG_DISABLE; > + } > > - /* Set pause flow control settings */ > + /* Pause is always supported */ > ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); > > - switch (hw->fc.requested_mode) { > - case igc_fc_full: > - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); > - break; > - case igc_fc_rx_pause: > - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); > - ethtool_link_ksettings_add_link_mode(cmd, advertising, > - Asym_Pause); > - break; > - case igc_fc_tx_pause: > - ethtool_link_ksettings_add_link_mode(cmd, advertising, > - Asym_Pause); > - break; > - default: > - break; > - } > - > status = pm_runtime_suspended(&adapter->pdev->dev) ? > 0 : rd32(IGC_STATUS); > > @@ -1983,7 +1997,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, > cmd->base.duplex = DUPLEX_UNKNOWN; > } > cmd->base.speed = speed; > - cmd->base.autoneg = AUTONEG_ENABLE; > > /* MDI-X => 2; MDI =>1; Invalid =>0 */ > if (hw->phy.media_type == igc_media_type_copper) > @@ -2000,6 +2013,37 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, > return 0; > } > > +/** > + * igc_handle_autoneg_disabled - Configure forced speed/duplex settings > + * @adapter: private driver structure > + * @speed: requested speed (must be SPEED_10 or SPEED_100) > + * @duplex: requested duplex > + * > + * Records forced speed/duplex when autoneg is disabled. > + * Caller must validate speed before calling this function. > + */ > +static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, u32 speed, > + u8 duplex) > +{ > + struct igc_mac_info *mac = &adapter->hw.mac; > + > + switch (speed) { > + case SPEED_10: > + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? > + IGC_FORCED_10F : IGC_FORCED_10H; > + break; > + case SPEED_100: > + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? > + IGC_FORCED_100F : IGC_FORCED_100H; > + break; > + default: > + WARN_ONCE(1, "Unsupported speed %u\n", speed); > + return; > + } > + > + mac->autoneg_enabled = false; > +} > + > /** > * igc_handle_autoneg_enabled - Configure autonegotiation advertisement > * @adapter: private driver structure > @@ -2038,6 +2082,7 @@ static void igc_handle_autoneg_enabled(struct igc_adapter *adapter, > 10baseT_Half)) > advertised |= ADVERTISE_10_HALF; > > + hw->mac.autoneg_enabled = true; > hw->phy.autoneg_advertised = advertised; > if (adapter->fc_autoneg) > hw->fc.requested_mode = igc_fc_default; > @@ -2059,6 +2104,12 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, > return -EINVAL; > } > > + if (cmd->base.autoneg != AUTONEG_ENABLE && > + cmd->base.autoneg != AUTONEG_DISABLE) { > + netdev_info(dev, "Unsupported autoneg setting\n"); > + return -EINVAL; > + } > + > /* MDI setting is only allowed when autoneg enabled because > * some hardware doesn't allow MDI setting when speed or > * duplex is forced. > @@ -2071,14 +2122,25 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, > } > } > > + if (cmd->base.autoneg == AUTONEG_DISABLE) { > + if (cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) { > + netdev_info(dev, "Unsupported speed for forced link\n"); > + return -EINVAL; > + } > + if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) { > + netdev_info(dev, "Duplex must be half or full for forced link\n"); > + return -EINVAL; > + } > + } > + > while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) > usleep_range(1000, 2000); > > - if (cmd->base.autoneg == AUTONEG_ENABLE) { > + if (cmd->base.autoneg == AUTONEG_ENABLE) > igc_handle_autoneg_enabled(adapter, cmd); > - } else { > - netdev_info(dev, "Force mode currently not supported\n"); > - } > + else > + igc_handle_autoneg_disabled(adapter, cmd->base.speed, > + cmd->base.duplex); > > /* MDI-X => 2; MDI => 1; Auto => 3 */ > if (cmd->base.eth_tp_mdix_ctrl) { > diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h > index 86ab8f566f44..62aaee55668a 100644 > --- a/drivers/net/ethernet/intel/igc/igc_hw.h > +++ b/drivers/net/ethernet/intel/igc/igc_hw.h > @@ -73,6 +73,13 @@ struct igc_info { > > extern const struct igc_info igc_base_info; > > +enum igc_forced_speed_duplex { > + IGC_FORCED_10H, > + IGC_FORCED_10F, > + IGC_FORCED_100H, > + IGC_FORCED_100F, > +}; > + > struct igc_mac_info { > struct igc_mac_operations ops; > > @@ -93,6 +100,8 @@ struct igc_mac_info { > bool arc_subsystem_valid; > > bool get_link_status; > + bool autoneg_enabled; > + enum igc_forced_speed_duplex forced_speed_duplex; > }; > > struct igc_nvm_operations { > diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c > index 0a3d3f357505..d6f3f6618469 100644 > --- a/drivers/net/ethernet/intel/igc/igc_mac.c > +++ b/drivers/net/ethernet/intel/igc/igc_mac.c > @@ -446,6 +446,17 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > u16 speed, duplex; > s32 ret_val = 0; > > + /* Without autoneg, flow control capability is not exchanged with the > + * link partner. IEEE 802.3 prohibits flow control in half-duplex mode. > + */ > + if (!hw->mac.autoneg_enabled) { > + if (hw->mac.forced_speed_duplex == IGC_FORCED_10H || > + hw->mac.forced_speed_duplex == IGC_FORCED_100H) > + hw->fc.current_mode = igc_fc_none; > + > + goto force_fc; > + } > + > /* In auto-neg, we need to check and see if Auto-Neg has completed, > * and if so, how the PHY and link partner has flow control > * configured. > @@ -607,6 +618,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) > /* Now we call a subroutine to actually force the MAC > * controller to use the correct flow control settings. > */ > +force_fc: > ret_val = igc_force_mac_fc(hw); > if (ret_val) { > hw_dbg("Error forcing flow control settings\n"); > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c > index 72bc5128d8b8..437e1d1ef1e4 100644 > --- a/drivers/net/ethernet/intel/igc/igc_main.c > +++ b/drivers/net/ethernet/intel/igc/igc_main.c > @@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev, > /* Initialize link properties that are user-changeable */ > adapter->fc_autoneg = true; > hw->phy.autoneg_advertised = 0xaf; > - > + hw->mac.autoneg_enabled = true; > hw->fc.requested_mode = igc_fc_default; > hw->fc.current_mode = igc_fc_default; > > diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c > index 6c4d204aecfa..4cf737fb3b21 100644 > --- a/drivers/net/ethernet/intel/igc/igc_phy.c > +++ b/drivers/net/ethernet/intel/igc/igc_phy.c > @@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw) > s32 ret_val = 0; > bool link; > > - /* Setup autoneg and flow control advertisement and perform > - * autonegotiation. > - */ > - ret_val = igc_copper_link_autoneg(hw); > - if (ret_val) > - goto out; > + if (hw->mac.autoneg_enabled) { > + /* Setup autoneg and flow control advertisement and perform > + * autonegotiation. > + */ > + ret_val = igc_copper_link_autoneg(hw); > + if (ret_val) > + goto out; > + } else { > + ret_val = hw->phy.ops.force_speed_duplex(hw); > + if (ret_val) { > + hw_dbg("Error Forcing Speed/Duplex\n"); > + goto out; > + } > + } > > /* Check link status. Wait up to 100 microseconds for link to become > * valid. > @@ -778,3 +786,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw) > > return gphy_version; > } > + > +/** > + * igc_force_speed_duplex - Force PHY speed and duplex settings > + * @hw: pointer to the HW structure > + * > + * Programs the GPY PHY control register to disable autonegotiation > + * and force the speed/duplex indicated by hw->mac.forced_speed_duplex. > + */ > +s32 igc_force_speed_duplex(struct igc_hw *hw) > +{ > + struct igc_phy_info *phy = &hw->phy; > + u16 phy_ctrl; > + s32 ret_val; > + > + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); > + if (ret_val) > + return ret_val; > + > + phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN | > + MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); > + > + switch (hw->mac.forced_speed_duplex) { > + case IGC_FORCED_10H: > + phy_ctrl |= MII_CR_SPEED_10; > + break; > + case IGC_FORCED_10F: > + phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN; > + break; > + case IGC_FORCED_100H: > + phy_ctrl |= MII_CR_SPEED_100; > + break; > + case IGC_FORCED_100F: > + phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN; > + break; > + default: > + return -IGC_ERR_CONFIG; > + } > + > + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); > + if (ret_val) > + return ret_val; > + > + hw->mac.get_link_status = true; > + return 0; > +} > diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h > index 832a7e359f18..d37a89174826 100644 > --- a/drivers/net/ethernet/intel/igc/igc_phy.h > +++ b/drivers/net/ethernet/intel/igc/igc_phy.h > @@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw); > s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); > s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data); > u16 igc_read_phy_fw_version(struct igc_hw *hw); > +s32 igc_force_speed_duplex(struct igc_hw *hw); > > #endif Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima @ 2026-06-22 8:12 ` Kadosh, MoriyaX 0 siblings, 0 replies; 15+ messages in thread From: Kadosh, MoriyaX @ 2026-06-22 8:12 UTC (permalink / raw) To: Ruinskiy, Dima, KhaiWenTan, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim On 14/06/2026 10:17, Ruinskiy, Dima wrote: > On 08/05/2026 0:47, KhaiWenTan wrote: >> From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> >> Allow users to force 10/100 Mb/s link speed and duplex via ethtool >> when autonegotiation is disabled. Previously, the driver rejected >> these requests with "Force mode currently not supported.". >> >> Forcing at 1000 Mb/s and 2500 Mb/s is not supported. >> >> Reviewed-by: Looi Hong Aun <hong.aun.looi@intel.com> >> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> Signed-off-by: Khai Wen Tan <khai.wen.tan@linux.intel.com> >> --- >> drivers/net/ethernet/intel/igc/igc_base.c | 35 ++++- >> drivers/net/ethernet/intel/igc/igc_defines.h | 9 +- >> drivers/net/ethernet/intel/igc/igc_ethtool.c | 138 ++++++++++++++----- >> drivers/net/ethernet/intel/igc/igc_hw.h | 9 ++ >> drivers/net/ethernet/intel/igc/igc_mac.c | 12 ++ >> drivers/net/ethernet/intel/igc/igc_main.c | 2 +- >> drivers/net/ethernet/intel/igc/igc_phy.c | 65 ++++++++- >> drivers/net/ethernet/intel/igc/igc_phy.h | 1 + >> 8 files changed, 220 insertions(+), 51 deletions(-) >> >> diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ >> ethernet/intel/igc/igc_base.c >> index 1613b562d17c..ab9120a3127f 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_base.c >> +++ b/drivers/net/ethernet/intel/igc/igc_base.c >> @@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct >> igc_hw *hw) >> u32 ctrl; >> ctrl = rd32(IGC_CTRL); >> - ctrl |= IGC_CTRL_SLU; >> - ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX); >> - wr32(IGC_CTRL, ctrl); >> - >> - ret_val = igc_setup_copper_link(hw); >> + ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX | >> + IGC_CTRL_SPEED_MASK | IGC_CTRL_FD); >> + >> + if (hw->mac.autoneg_enabled) { >> + ctrl |= IGC_CTRL_SLU; >> + wr32(IGC_CTRL, ctrl); >> + ret_val = igc_setup_copper_link(hw); >> + } else { >> + ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX; >> + >> + switch (hw->mac.forced_speed_duplex) { >> + case IGC_FORCED_10H: >> + ctrl |= IGC_CTRL_SPEED_10; >> + break; >> + case IGC_FORCED_10F: >> + ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD; >> + break; >> + case IGC_FORCED_100H: >> + ctrl |= IGC_CTRL_SPEED_100; >> + break; >> + case IGC_FORCED_100F: >> + ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD; >> + break; >> + default: >> + return -IGC_ERR_CONFIG; >> + } >> + wr32(IGC_CTRL, ctrl); >> + ret_val = igc_setup_copper_link(hw); >> + } >> return ret_val; >> } >> @@ -443,6 +467,7 @@ static const struct igc_phy_operations >> igc_phy_ops_base = { >> .reset = igc_phy_hw_reset, >> .read_reg = igc_read_phy_reg_gpy, >> .write_reg = igc_write_phy_reg_gpy, >> + .force_speed_duplex = igc_force_speed_duplex, >> }; >> const struct igc_info igc_base_info = { >> diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/ >> net/ethernet/intel/igc/igc_defines.h >> index 9482ab11f050..3f504751c2d9 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_defines.h >> +++ b/drivers/net/ethernet/intel/igc/igc_defines.h >> @@ -129,10 +129,13 @@ >> #define IGC_ERR_SWFW_SYNC 13 >> /* Device Control */ >> +#define IGC_CTRL_FD BIT(0) /* Full Duplex */ >> #define IGC_CTRL_RST 0x04000000 /* Global reset */ >> - >> #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ >> #define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ >> +#define IGC_CTRL_SPEED_MASK GENMASK(10, 8) >> +#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0) >> +#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1) >> #define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */ >> #define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */ >> #define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ >> @@ -673,6 +676,10 @@ >> #define IGC_GEN_POLL_TIMEOUT 1920 >> /* PHY Control Register */ >> +#define MII_CR_SPEED_MASK (BIT(6) | BIT(13)) >> +#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */ >> +#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */ >> +#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full >> Duplex */ >> #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto >> negotiation */ >> #define MII_CR_POWER_DOWN 0x0800 /* Power down */ >> #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ >> diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/ >> net/ethernet/intel/igc/igc_ethtool.c >> index cfcbf2fdad6e..b103836a895f 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c >> +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c >> @@ -1914,44 +1914,58 @@ static int >> igc_ethtool_get_link_ksettings(struct net_device *netdev, >> ethtool_link_ksettings_add_link_mode(cmd, supported, TP); >> ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); >> - /* advertising link modes */ >> - if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 10baseT_Half); >> - if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 10baseT_Full); >> - if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 100baseT_Half); >> - if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 100baseT_Full); >> - if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 1000baseT_Full); >> - if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> 2500baseT_Full); >> - >> /* set autoneg settings */ >> ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); >> + if (hw->mac.autoneg_enabled) { >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); >> + cmd->base.autoneg = AUTONEG_ENABLE; >> + >> + /* advertising link modes only apply when autoneg is on */ >> + if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 10baseT_Half); >> + if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 10baseT_Full); >> + if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 100baseT_Half); >> + if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 100baseT_Full); >> + if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 1000baseT_Full); >> + if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + 2500baseT_Full); >> + >> + /* Set pause flow control advertising */ >> + switch (hw->fc.requested_mode) { >> + case igc_fc_full: >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + Pause); >> + break; >> + case igc_fc_rx_pause: >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + Pause); >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + Asym_Pause); >> + break; >> + case igc_fc_tx_pause: >> + ethtool_link_ksettings_add_link_mode(cmd, advertising, >> + Asym_Pause); >> + break; >> + default: >> + break; >> + } >> + } else { >> + cmd->base.autoneg = AUTONEG_DISABLE; >> + } >> - /* Set pause flow control settings */ >> + /* Pause is always supported */ >> ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); >> - switch (hw->fc.requested_mode) { >> - case igc_fc_full: >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); >> - break; >> - case igc_fc_rx_pause: >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> - Asym_Pause); >> - break; >> - case igc_fc_tx_pause: >> - ethtool_link_ksettings_add_link_mode(cmd, advertising, >> - Asym_Pause); >> - break; >> - default: >> - break; >> - } >> - >> status = pm_runtime_suspended(&adapter->pdev->dev) ? >> 0 : rd32(IGC_STATUS); >> @@ -1983,7 +1997,6 @@ static int igc_ethtool_get_link_ksettings(struct >> net_device *netdev, >> cmd->base.duplex = DUPLEX_UNKNOWN; >> } >> cmd->base.speed = speed; >> - cmd->base.autoneg = AUTONEG_ENABLE; >> /* MDI-X => 2; MDI =>1; Invalid =>0 */ >> if (hw->phy.media_type == igc_media_type_copper) >> @@ -2000,6 +2013,37 @@ static int >> igc_ethtool_get_link_ksettings(struct net_device *netdev, >> return 0; >> } >> +/** >> + * igc_handle_autoneg_disabled - Configure forced speed/duplex settings >> + * @adapter: private driver structure >> + * @speed: requested speed (must be SPEED_10 or SPEED_100) >> + * @duplex: requested duplex >> + * >> + * Records forced speed/duplex when autoneg is disabled. >> + * Caller must validate speed before calling this function. >> + */ >> +static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, >> u32 speed, >> + u8 duplex) >> +{ >> + struct igc_mac_info *mac = &adapter->hw.mac; >> + >> + switch (speed) { >> + case SPEED_10: >> + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? >> + IGC_FORCED_10F : IGC_FORCED_10H; >> + break; >> + case SPEED_100: >> + mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ? >> + IGC_FORCED_100F : IGC_FORCED_100H; >> + break; >> + default: >> + WARN_ONCE(1, "Unsupported speed %u\n", speed); >> + return; >> + } >> + >> + mac->autoneg_enabled = false; >> +} >> + >> /** >> * igc_handle_autoneg_enabled - Configure autonegotiation advertisement >> * @adapter: private driver structure >> @@ -2038,6 +2082,7 @@ static void igc_handle_autoneg_enabled(struct >> igc_adapter *adapter, >> 10baseT_Half)) >> advertised |= ADVERTISE_10_HALF; >> + hw->mac.autoneg_enabled = true; >> hw->phy.autoneg_advertised = advertised; >> if (adapter->fc_autoneg) >> hw->fc.requested_mode = igc_fc_default; >> @@ -2059,6 +2104,12 @@ igc_ethtool_set_link_ksettings(struct >> net_device *netdev, >> return -EINVAL; >> } >> + if (cmd->base.autoneg != AUTONEG_ENABLE && >> + cmd->base.autoneg != AUTONEG_DISABLE) { >> + netdev_info(dev, "Unsupported autoneg setting\n"); >> + return -EINVAL; >> + } >> + >> /* MDI setting is only allowed when autoneg enabled because >> * some hardware doesn't allow MDI setting when speed or >> * duplex is forced. >> @@ -2071,14 +2122,25 @@ igc_ethtool_set_link_ksettings(struct >> net_device *netdev, >> } >> } >> + if (cmd->base.autoneg == AUTONEG_DISABLE) { >> + if (cmd->base.speed != SPEED_10 && cmd->base.speed != >> SPEED_100) { >> + netdev_info(dev, "Unsupported speed for forced link\n"); >> + return -EINVAL; >> + } >> + if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != >> DUPLEX_FULL) { >> + netdev_info(dev, "Duplex must be half or full for forced >> link\n"); >> + return -EINVAL; >> + } >> + } >> + >> while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) >> usleep_range(1000, 2000); >> - if (cmd->base.autoneg == AUTONEG_ENABLE) { >> + if (cmd->base.autoneg == AUTONEG_ENABLE) >> igc_handle_autoneg_enabled(adapter, cmd); >> - } else { >> - netdev_info(dev, "Force mode currently not supported\n"); >> - } >> + else >> + igc_handle_autoneg_disabled(adapter, cmd->base.speed, >> + cmd->base.duplex); >> /* MDI-X => 2; MDI => 1; Auto => 3 */ >> if (cmd->base.eth_tp_mdix_ctrl) { >> diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ >> ethernet/intel/igc/igc_hw.h >> index 86ab8f566f44..62aaee55668a 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_hw.h >> +++ b/drivers/net/ethernet/intel/igc/igc_hw.h >> @@ -73,6 +73,13 @@ struct igc_info { >> extern const struct igc_info igc_base_info; >> +enum igc_forced_speed_duplex { >> + IGC_FORCED_10H, >> + IGC_FORCED_10F, >> + IGC_FORCED_100H, >> + IGC_FORCED_100F, >> +}; >> + >> struct igc_mac_info { >> struct igc_mac_operations ops; >> @@ -93,6 +100,8 @@ struct igc_mac_info { >> bool arc_subsystem_valid; >> bool get_link_status; >> + bool autoneg_enabled; >> + enum igc_forced_speed_duplex forced_speed_duplex; >> }; >> struct igc_nvm_operations { >> diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ >> ethernet/intel/igc/igc_mac.c >> index 0a3d3f357505..d6f3f6618469 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_mac.c >> +++ b/drivers/net/ethernet/intel/igc/igc_mac.c >> @@ -446,6 +446,17 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> u16 speed, duplex; >> s32 ret_val = 0; >> + /* Without autoneg, flow control capability is not exchanged with >> the >> + * link partner. IEEE 802.3 prohibits flow control in half-duplex >> mode. >> + */ >> + if (!hw->mac.autoneg_enabled) { >> + if (hw->mac.forced_speed_duplex == IGC_FORCED_10H || >> + hw->mac.forced_speed_duplex == IGC_FORCED_100H) >> + hw->fc.current_mode = igc_fc_none; >> + >> + goto force_fc; >> + } >> + >> /* In auto-neg, we need to check and see if Auto-Neg has completed, >> * and if so, how the PHY and link partner has flow control >> * configured. >> @@ -607,6 +618,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) >> /* Now we call a subroutine to actually force the MAC >> * controller to use the correct flow control settings. >> */ >> +force_fc: >> ret_val = igc_force_mac_fc(hw); >> if (ret_val) { >> hw_dbg("Error forcing flow control settings\n"); >> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ >> ethernet/intel/igc/igc_main.c >> index 72bc5128d8b8..437e1d1ef1e4 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_main.c >> +++ b/drivers/net/ethernet/intel/igc/igc_main.c >> @@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev, >> /* Initialize link properties that are user-changeable */ >> adapter->fc_autoneg = true; >> hw->phy.autoneg_advertised = 0xaf; >> - >> + hw->mac.autoneg_enabled = true; >> hw->fc.requested_mode = igc_fc_default; >> hw->fc.current_mode = igc_fc_default; >> diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ >> ethernet/intel/igc/igc_phy.c >> index 6c4d204aecfa..4cf737fb3b21 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_phy.c >> +++ b/drivers/net/ethernet/intel/igc/igc_phy.c >> @@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw) >> s32 ret_val = 0; >> bool link; >> - /* Setup autoneg and flow control advertisement and perform >> - * autonegotiation. >> - */ >> - ret_val = igc_copper_link_autoneg(hw); >> - if (ret_val) >> - goto out; >> + if (hw->mac.autoneg_enabled) { >> + /* Setup autoneg and flow control advertisement and perform >> + * autonegotiation. >> + */ >> + ret_val = igc_copper_link_autoneg(hw); >> + if (ret_val) >> + goto out; >> + } else { >> + ret_val = hw->phy.ops.force_speed_duplex(hw); >> + if (ret_val) { >> + hw_dbg("Error Forcing Speed/Duplex\n"); >> + goto out; >> + } >> + } >> /* Check link status. Wait up to 100 microseconds for link to >> become >> * valid. >> @@ -778,3 +786,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw) >> return gphy_version; >> } >> + >> +/** >> + * igc_force_speed_duplex - Force PHY speed and duplex settings >> + * @hw: pointer to the HW structure >> + * >> + * Programs the GPY PHY control register to disable autonegotiation >> + * and force the speed/duplex indicated by hw->mac.forced_speed_duplex. >> + */ >> +s32 igc_force_speed_duplex(struct igc_hw *hw) >> +{ >> + struct igc_phy_info *phy = &hw->phy; >> + u16 phy_ctrl; >> + s32 ret_val; >> + >> + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); >> + if (ret_val) >> + return ret_val; >> + >> + phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN | >> + MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); >> + >> + switch (hw->mac.forced_speed_duplex) { >> + case IGC_FORCED_10H: >> + phy_ctrl |= MII_CR_SPEED_10; >> + break; >> + case IGC_FORCED_10F: >> + phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN; >> + break; >> + case IGC_FORCED_100H: >> + phy_ctrl |= MII_CR_SPEED_100; >> + break; >> + case IGC_FORCED_100F: >> + phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN; >> + break; >> + default: >> + return -IGC_ERR_CONFIG; >> + } >> + >> + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); >> + if (ret_val) >> + return ret_val; >> + >> + hw->mac.get_link_status = true; >> + return 0; >> +} >> diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ >> ethernet/intel/igc/igc_phy.h >> index 832a7e359f18..d37a89174826 100644 >> --- a/drivers/net/ethernet/intel/igc/igc_phy.h >> +++ b/drivers/net/ethernet/intel/igc/igc_phy.h >> @@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw); >> s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); >> s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data); >> u16 igc_read_phy_fw_version(struct igc_hw *hw); >> +s32 igc_force_speed_duplex(struct igc_hw *hw); >> #endif > Reviewed-by: Dima Ruinskiy <dima.ruinskiy@intel.com> Tested-by: Moriya Kadosh <moriyax.kadosh@intel.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan ` (3 preceding siblings ...) 2026-05-07 21:47 ` [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-05-11 16:28 ` Simon Horman 4 siblings, 0 replies; 15+ messages in thread From: Simon Horman @ 2026-05-11 16:28 UTC (permalink / raw) To: KhaiWenTan Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, hector.blanco.alcaine, khai.wen.tan, Faizal Rahim On Fri, May 08, 2026 at 05:47:02AM +0800, KhaiWenTan wrote: > From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > > This series adds support for forcing 10/100 Mb/s link speed via ethtool > when autonegotiation is disabled on the igc driver. > > Changes in v5: > - add removal justification to include copper context in commit > description for igc: remove unused autoneg_failed field (Paul) > - check that cmd->base.duplex is either DUPLEX_HALF or DUPLEX_FULL > in igc_ethtool_set_link_ksettings() (Simon) > - dynamically override hw->fc.current_mode to igc_fc_none during > link configuration instead of mutating requested_mode (Simon) > > Changes in v4: > - Validate that autoneg is AUTONEG_ENABLE or AUTONEG_DISABLE early > in igc_ethtool_set_link_ksettings() to avoid passing unexpected > values to igc_handle_autoneg_disabled(). (Simon Horman) > > Changes in v3: > - Modify condition from "if (duplex == DUPLEX_HALF)" to > "if (duplex != DUPLEX_FULL)". (Simon Horman) > > Changes in v2: > - When forcing half-duplex, set hw->fc.requested_mode = igc_fc_none, > since half-duplex cannot support flow control per IEEE 802.3. > (Simon Horman) > - Split the original single patch into three patches for clarity: > patches 1 and 2 are preparatory cleanups; patch 3 carries the > functional change. Thanks for your persistence. For the series: Reviewed-by: Simon Horman <horms@kernel.org> ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-06-22 8:12 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-07 21:47 [PATCH iwl-next v5 0/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-05-07 21:47 ` [PATCH iwl-next v5 1/4] igc: remove unused autoneg_failed field KhaiWenTan 2026-06-14 7:16 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-06-22 8:10 ` Kadosh, MoriyaX 2026-06-15 8:22 ` Kwapulinski, Piotr 2026-05-07 21:47 ` [PATCH iwl-next v5 2/4] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-06-22 8:08 ` Kadosh, MoriyaX 2026-05-07 21:47 ` [PATCH iwl-next v5 3/4] igc: replace goto out with direct returns in igc_config_fc_after_link_up() KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-06-22 8:11 ` Kadosh, MoriyaX 2026-05-07 21:47 ` [PATCH iwl-next v5 4/4] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-06-14 7:17 ` [Intel-wired-lan] " Ruinskiy, Dima 2026-06-22 8:12 ` Kadosh, MoriyaX 2026-05-11 16:28 ` [PATCH iwl-next v5 0/4] " Simon Horman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox