* [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation
@ 2026-04-28 6:00 KhaiWenTan
2026-04-28 6:00 ` [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field KhaiWenTan
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: KhaiWenTan @ 2026-04-28 6:00 UTC (permalink / raw)
To: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni
Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim,
hong.aun.looi, 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 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.
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 (3):
igc: remove unused autoneg_failed field
igc: move autoneg-enabled settings into igc_handle_autoneg_enabled()
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 | 209 +++++++++++++------
drivers/net/ethernet/intel/igc/igc_hw.h | 10 +-
drivers/net/ethernet/intel/igc/igc_mac.c | 16 +-
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, 257 insertions(+), 90 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field 2026-04-28 6:00 [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-04-28 6:00 ` KhaiWenTan 2026-04-28 6:56 ` [Intel-wired-lan] " Paul Menzel 2026-04-28 6:00 ` [PATCH iwl-next v4 2/3] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: KhaiWenTan @ 2026-04-28 6:00 UTC (permalink / raw) To: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Faizal Rahim, Looi, Aleksandr Loktionov, KhaiWenTan 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(). 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: KhaiWenTan <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] 9+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field 2026-04-28 6:00 ` [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field KhaiWenTan @ 2026-04-28 6:56 ` Paul Menzel 2026-04-28 10:39 ` Abdul Rahim, Faizal 0 siblings, 1 reply; 9+ messages in thread From: Paul Menzel @ 2026-04-28 6:56 UTC (permalink / raw) To: khai.wen.tan Cc: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Faizal Rahim, Aleksandr Loktionov [Cc: Removed stray *Looi*] Dear Khai Wen Tan, Thank you for your patch. Am 28.04.26 um 08:00 schrieb KhaiWenTan: (Should spaces be added in your name?) > 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(). Could you please elaborate. Why is removal the correct fix, and it’s not an incomplete feature? Does auto-negotiation always succeed? > Reviewed-by: Looi, Hong Aun <hong.aun.looi@intel.com> Please order it to not use the comma: Hong Aun Looi > Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> > Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> > Signed-off-by: KhaiWenTan <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. Kind regards, Paul ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field 2026-04-28 6:56 ` [Intel-wired-lan] " Paul Menzel @ 2026-04-28 10:39 ` Abdul Rahim, Faizal 2026-04-28 15:06 ` Paul Menzel 0 siblings, 1 reply; 9+ messages in thread From: Abdul Rahim, Faizal @ 2026-04-28 10:39 UTC (permalink / raw) To: Paul Menzel, khai.wen.tan Cc: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Aleksandr Loktionov Hi Paul, Thank you for your review. On 28/4/2026 2:56 pm, Paul Menzel wrote: > [Cc: Removed stray *Looi*] > > Dear Khai Wen Tan, > > > Thank you for your patch. > > > Am 28.04.26 um 08:00 schrieb KhaiWenTan: > > (Should spaces be added in your name?) > >> 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(). > > Could you please elaborate. Why is removal the correct fix, and it’s not an > incomplete feature? Does auto-negotiation always succeed? > Auto-negotiation does not always succeed, but igc does not use autoneg_failed to handle that case, the field was never set anywhere in the igc driver. Before this patch, the only igc references to autoneg_failed were the struct member declaration and the read in igc_config_fc_after_link_up(). No igc code ever assigned it to true, and git history shows no commit that added a setter since the code creation in 2018. The field originates from the e1000/e1000e fiber/serdes forced-link path: when MAC-level auto-negotiation on fiber times out, the driver forces link up and sets autoneg_failed so the flow-control code knows pause was not negotiated and must be forced. igc has no fiber or serdes media, it only supports copper (igc_media_type_copper), so the code that sets autoneg_failed was never ported. On copper, PHY auto-negotiation failure is handled differently: - No link at all: igc_check_for_copper_link() returns before reaching flow-control configuration, there's nothing to configure FC on. - Link present but autoneg not yet complete: igc_config_fc_after_link_up() checks MII_SR_AUTONEG_COMPLETE and returns early without resolving pause. The next link-status event re-triggers the check. - Autoneg completes (including via parallel detection fallback when the link partner doesn't autoneg): the PHY still sets AUTONEG_COMPLETE but LP_ABILITY won't have PAUSE bits since the partner never sent autoneg pages. The existing flow-control logic in igc_config_fc_after_link_up() handles that correctly, it falls through to igc_fc_none or igc_fc_rx_pause based on requested_mode. None of these paths need autoneg_failed. Keeping the field would be misleading to reader. >> Reviewed-by: Looi, Hong Aun <hong.aun.looi@intel.com> > > Please order it to not use the comma: Hong Aun Looi > Will do, thanks. >> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> >> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >> Signed-off-by: KhaiWenTan <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. > > > Kind regards, > > Paul > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field 2026-04-28 10:39 ` Abdul Rahim, Faizal @ 2026-04-28 15:06 ` Paul Menzel 0 siblings, 0 replies; 9+ messages in thread From: Paul Menzel @ 2026-04-28 15:06 UTC (permalink / raw) To: Faizal Abdul Rahim Cc: khai.wen.tan, anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Aleksandr Loktionov Dear Faizal, Am 28.04.26 um 12:39 schrieb Abdul Rahim, Faizal: > On 28/4/2026 2:56 pm, Paul Menzel wrote: >> Am 28.04.26 um 08:00 schrieb KhaiWenTan: >> >> (Should spaces be added in your name?) >> >>> 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(). >> >> Could you please elaborate. Why is removal the correct fix, and it’s >> not an incomplete feature? Does auto-negotiation always succeed? > > Auto-negotiation does not always succeed, but igc does not use > autoneg_failed to handle that case, the field was never set anywhere > in the igc driver. > > Before this patch, the only igc references to autoneg_failed were > the struct member declaration and the read in > igc_config_fc_after_link_up(). No igc code ever assigned it to true, > and git history shows no commit that added a setter since the code > creation in 2018. > > The field originates from the e1000/e1000e fiber/serdes forced-link > path: when MAC-level auto-negotiation on fiber times out, the driver > forces link up and sets autoneg_failed so the flow-control code knows > pause was not negotiated and must be forced. igc has no fiber or > serdes media, it only supports copper (igc_media_type_copper), so > the code that sets autoneg_failed was never ported. > > On copper, PHY auto-negotiation failure is handled differently: > - No link at all: igc_check_for_copper_link() returns before reaching > flow-control configuration, there's nothing to configure FC on. > - Link present but autoneg not yet complete: > igc_config_fc_after_link_up() checks MII_SR_AUTONEG_COMPLETE and > returns early without resolving pause. The next link-status event > re-triggers the check. > - Autoneg completes (including via parallel detection fallback when > the link partner doesn't autoneg): the PHY still sets > AUTONEG_COMPLETE but LP_ABILITY won't have PAUSE bits since the > partner never sent autoneg pages. The existing flow-control logic > in igc_config_fc_after_link_up() handles that correctly, it falls > through to igc_fc_none or igc_fc_rx_pause based on requested_mode. > > None of these paths need autoneg_failed. Keeping the field would be > misleading to reader. Thank you. For me the information about just supporting copper would be great to have in the commit message. >>> Reviewed-by: Looi, Hong Aun <hong.aun.looi@intel.com> >> >> Please order it to not use the comma: Hong Aun Looi > > Will do, thanks. > >>> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> >>> Signed-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com> >>> Signed-off-by: KhaiWenTan <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 Just for your information, that your mailer wraps the lines of the quotes. […] >>> * 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. Kind regards, Paul ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH iwl-next v4 2/3] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() 2026-04-28 6:00 [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field KhaiWenTan @ 2026-04-28 6:00 ` KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-04-30 14:41 ` [PATCH iwl-next v4 0/3] " David Laight 3 siblings, 0 replies; 9+ messages in thread From: KhaiWenTan @ 2026-04-28 6:00 UTC (permalink / raw) To: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Faizal Rahim, Looi, Aleksandr Loktionov, KhaiWenTan 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: KhaiWenTan <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] 9+ messages in thread
* [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation 2026-04-28 6:00 [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 2/3] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan @ 2026-04-28 6:00 ` KhaiWenTan 2026-04-30 13:50 ` Simon Horman 2026-04-30 14:41 ` [PATCH iwl-next v4 0/3] " David Laight 3 siblings, 1 reply; 9+ messages in thread From: KhaiWenTan @ 2026-04-28 6:00 UTC (permalink / raw) To: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni Cc: intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Faizal Rahim, Looi, KhaiWenTan 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: KhaiWenTan <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 | 137 ++++++++++++++----- drivers/net/ethernet/intel/igc/igc_hw.h | 9 ++ drivers/net/ethernet/intel/igc/igc_mac.c | 10 ++ 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, 217 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..9997ebbdf778 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,41 @@ 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; + + /* Half-duplex cannot support flow control per IEEE 802.3 */ + if (duplex != DUPLEX_FULL) + adapter->hw.fc.requested_mode = igc_fc_none; +} + /** * igc_handle_autoneg_enabled - Configure autonegotiation advertisement * @adapter: private driver structure @@ -2038,6 +2086,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 +2108,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 +2126,20 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, } } + if (cmd->base.autoneg == AUTONEG_DISABLE && + cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) { + netdev_info(dev, "Unsupported speed 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 142beb9ae557..8bbb6d5581c7 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -446,6 +446,16 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) u16 speed, duplex; s32 ret_val = 0; + /* When autoneg is disabled, force the MAC flow control settings + * to match the "fc" parameter. + */ + if (!hw->mac.autoneg_enabled) { + 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. 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] 9+ messages in thread
* Re: [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation 2026-04-28 6:00 ` [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-04-30 13:50 ` Simon Horman 0 siblings, 0 replies; 9+ messages in thread From: Simon Horman @ 2026-04-30 13:50 UTC (permalink / raw) To: khai.wen.tan Cc: 'Simon Horman', anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, faizal.abdul.rahim From: 'Simon Horman' <horms@kernel.org> This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible. Full review at: https://sashiko.dev --- igc: add support for forcing link speed without autonegotiation This commit allows users to force 10/100 Mb/s link speed and duplex via ethtool when autonegotiation is disabled. Previously, the driver rejected these requests. > diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c > index cfcbf2fdad6e..9997ebbdf778 100644 > --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c > +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c [ ... ] > @@ -2000,6 +2013,41 @@ 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; > + > + /* Half-duplex cannot support flow control per IEEE 802.3 */ > + if (duplex != DUPLEX_FULL) > + adapter->hw.fc.requested_mode = igc_fc_none; Does this permanently overwrite the user's flow control preference? If half-duplex is requested, requested_mode is set to igc_fc_none. Because requested_mode represents the persistent state for the user's flow control preference, the user might permanently lose their configuration. If they later switch back to full-duplex, requested_mode remains igc_fc_none, and flow control stays disabled. Would it be better to dynamically override hw->fc.current_mode to igc_fc_none during link configuration instead of mutating requested_mode? > +} [ ... ] > @@ -2071,14 +2126,20 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, > } > } > > + if (cmd->base.autoneg == AUTONEG_DISABLE && > + cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) { > + netdev_info(dev, "Unsupported speed for forced link\n"); > + return -EINVAL; > + } > + Should we also validate cmd->base.duplex here to prevent a fallback to half-duplex? If a user runs a command like "ethtool -s eth0 speed 100 autoneg off" while the link is down, ethtool queries and preserves the current duplex value, which is DUPLEX_UNKNOWN (0xff). In igc_handle_autoneg_disabled(), the code checks if duplex == DUPLEX_FULL, which evaluates to false, and forces the interface to 100 Mbps half-duplex. Could we explicitly check that cmd->base.duplex is either DUPLEX_HALF or DUPLEX_FULL and return -EINVAL otherwise? > while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) > usleep_range(1000, 2000); This isn't a bug introduced by this patch, but does this ad-hoc synchronization loop reimplement locking without fairness or lockdep support? According to the Networking Subsystem Guidelines, using bit operations as a substitute for real locks violates core kernel locking rules and introduces potential races. Could this be replaced with a proper concurrency mechanism such as a mutex? > > - 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) { ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation 2026-04-28 6:00 [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan ` (2 preceding siblings ...) 2026-04-28 6:00 ` [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan @ 2026-04-30 14:41 ` David Laight 3 siblings, 0 replies; 9+ messages in thread From: David Laight @ 2026-04-30 14:41 UTC (permalink / raw) To: KhaiWenTan Cc: anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni, intel-wired-lan, netdev, linux-kernel, faizal.abdul.rahim, hong.aun.looi, khai.wen.tan, Faizal Rahim On Tue, 28 Apr 2026 14:00:06 +0800 KhaiWenTan <khai.wen.tan@linux.intel.com> 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. I'll ask 'why' ? In particular forcing half/full duplex has always been a very good way of 'breaking' a network connection. It really is much better to restrict the advertised link modes and let the autodetect/autonegotiation logic in the phy/mac do its job. About the only think I can think of is to force 10M HDX when connected to a remote system that supports 10M/100M HDX. In that case you need to send out single link test pulses, not the burst used to identify 100M HDX, or the pattern encoded on the burst used by autonegotiation. But you need to got back to the mid 1990s to find such systems. Anything that supports FDX will do autonegotiation. David > > 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. > > 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 (3): > igc: remove unused autoneg_failed field > igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() > 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 | 209 +++++++++++++------ > drivers/net/ethernet/intel/igc/igc_hw.h | 10 +- > drivers/net/ethernet/intel/igc/igc_mac.c | 16 +- > 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, 257 insertions(+), 90 deletions(-) > > -- > 2.43.0 > > ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-04-30 14:41 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-28 6:00 [PATCH iwl-next v4 0/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 1/3] igc: remove unused autoneg_failed field KhaiWenTan 2026-04-28 6:56 ` [Intel-wired-lan] " Paul Menzel 2026-04-28 10:39 ` Abdul Rahim, Faizal 2026-04-28 15:06 ` Paul Menzel 2026-04-28 6:00 ` [PATCH iwl-next v4 2/3] igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() KhaiWenTan 2026-04-28 6:00 ` [PATCH iwl-next v4 3/3] igc: add support for forcing link speed without autonegotiation KhaiWenTan 2026-04-30 13:50 ` Simon Horman 2026-04-30 14:41 ` [PATCH iwl-next v4 0/3] " David Laight
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox