Message ID | 20201105064056.4908-2-kai.heng.feng@canonical.com |
---|---|
State | New |
Headers | show |
Series | Fix broken igc device after reboot | expand |
Applied to Focal/master-next Thanks, Ian On 2020-11-05 14:40:56 , Kai-Heng Feng wrote: > From: Sasha Neftin <sasha.neftin@intel.com> > > BugLink: https://bugs.launchpad.net/bugs/1902578 > > PHY power management control should provide a reliable and accurate > indication of PHY reset completion and decrease the delay time > after a PHY reset > > Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> > Tested-by: Aaron Brown <aaron.f.brown@intel.com> > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> > (cherry picked from commit bcb3244ccdc4cebb6ed3d47d973da7b1a03837c0) > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> > --- > drivers/net/ethernet/intel/igc/igc_defines.h | 1 + > drivers/net/ethernet/intel/igc/igc_phy.c | 16 +++++++++++++++- > drivers/net/ethernet/intel/igc/igc_regs.h | 1 + > 3 files changed, 17 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h > index f3f2325fe567..460a99137a7d 100644 > --- a/drivers/net/ethernet/intel/igc/igc_defines.h > +++ b/drivers/net/ethernet/intel/igc/igc_defines.h > @@ -360,6 +360,7 @@ > /* PHY Status Register */ > #define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ > #define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ > +#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */ > > /* PHY 1000 MII Register/Bit Definitions */ > /* PHY Registers defined by IEEE */ > diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c > index f4b05af0dd2f..8e1799508edc 100644 > --- a/drivers/net/ethernet/intel/igc/igc_phy.c > +++ b/drivers/net/ethernet/intel/igc/igc_phy.c > @@ -173,6 +173,7 @@ s32 igc_check_downshift(struct igc_hw *hw) > s32 igc_phy_hw_reset(struct igc_hw *hw) > { > struct igc_phy_info *phy = &hw->phy; > + u32 phpm = 0, timeout = 10000; > s32 ret_val; > u32 ctrl; > > @@ -186,6 +187,8 @@ s32 igc_phy_hw_reset(struct igc_hw *hw) > if (ret_val) > goto out; > > + phpm = rd32(IGC_I225_PHPM); > + > ctrl = rd32(IGC_CTRL); > wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST); > wrfl(); > @@ -195,7 +198,18 @@ s32 igc_phy_hw_reset(struct igc_hw *hw) > wr32(IGC_CTRL, ctrl); > wrfl(); > > - usleep_range(1500, 2000); > + /* SW should guarantee 100us for the completion of the PHY reset */ > + usleep_range(100, 150); > + do { > + phpm = rd32(IGC_I225_PHPM); > + timeout--; > + udelay(1); > + } while (!(phpm & IGC_PHY_RST_COMP) && timeout); > + > + if (!timeout) > + hw_dbg("Timeout is expired after a phy reset\n"); > + > + usleep_range(100, 150); > > phy->ops.release(hw); > > diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h > index 50d7c04dccf5..0917e4436e25 100644 > --- a/drivers/net/ethernet/intel/igc/igc_regs.h > +++ b/drivers/net/ethernet/intel/igc/igc_regs.h > @@ -12,6 +12,7 @@ > #define IGC_MDIC 0x00020 /* MDI Control - RW */ > #define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */ > #define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ > +#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */ > > /* Internal Packet Buffer Size Registers */ > #define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ > -- > 2.17.1 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index f3f2325fe567..460a99137a7d 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -360,6 +360,7 @@ /* PHY Status Register */ #define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ #define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */ /* PHY 1000 MII Register/Bit Definitions */ /* PHY Registers defined by IEEE */ diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index f4b05af0dd2f..8e1799508edc 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -173,6 +173,7 @@ s32 igc_check_downshift(struct igc_hw *hw) s32 igc_phy_hw_reset(struct igc_hw *hw) { struct igc_phy_info *phy = &hw->phy; + u32 phpm = 0, timeout = 10000; s32 ret_val; u32 ctrl; @@ -186,6 +187,8 @@ s32 igc_phy_hw_reset(struct igc_hw *hw) if (ret_val) goto out; + phpm = rd32(IGC_I225_PHPM); + ctrl = rd32(IGC_CTRL); wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST); wrfl(); @@ -195,7 +198,18 @@ s32 igc_phy_hw_reset(struct igc_hw *hw) wr32(IGC_CTRL, ctrl); wrfl(); - usleep_range(1500, 2000); + /* SW should guarantee 100us for the completion of the PHY reset */ + usleep_range(100, 150); + do { + phpm = rd32(IGC_I225_PHPM); + timeout--; + udelay(1); + } while (!(phpm & IGC_PHY_RST_COMP) && timeout); + + if (!timeout) + hw_dbg("Timeout is expired after a phy reset\n"); + + usleep_range(100, 150); phy->ops.release(hw); diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index 50d7c04dccf5..0917e4436e25 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -12,6 +12,7 @@ #define IGC_MDIC 0x00020 /* MDI Control - RW */ #define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */ #define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ +#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */ /* Internal Packet Buffer Size Registers */ #define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */