diff mbox series

[net,1/3] lan78xx: PHY DSP registers initialization to address EEE link drop issues with long cables

Message ID 20180406061204.18257-2-raghuramchary.jallipalli@microchip.com
State Changes Requested, archived
Delegated to: David Miller
Headers show
Series lan78xx: Fixes and enhancements | expand

Commit Message

Raghuram Chary J April 6, 2018, 6:12 a.m. UTC
The patch is to configure DSP registers of PHY device
to handle Gbe-EEE failures with >40m cable length.

Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver")
Signed-off-by: Raghuram Chary J <raghuramchary.jallipalli@microchip.com>
---
 drivers/net/phy/microchip.c  | 123 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/microchipphy.h |   8 +++
 2 files changed, 130 insertions(+), 1 deletion(-)

Comments

Andrew Lunn April 6, 2018, 2:43 p.m. UTC | #1
On Fri, Apr 06, 2018 at 11:42:02AM +0530, Raghuram Chary J wrote:
> The patch is to configure DSP registers of PHY device
> to handle Gbe-EEE failures with >40m cable length.
> 
> Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver")
> Signed-off-by: Raghuram Chary J <raghuramchary.jallipalli@microchip.com>
> ---
>  drivers/net/phy/microchip.c  | 123 ++++++++++++++++++++++++++++++++++++++++++-
>  include/linux/microchipphy.h |   8 +++
>  2 files changed, 130 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
> index 0f293ef28935..174ae9808722 100644
> --- a/drivers/net/phy/microchip.c
> +++ b/drivers/net/phy/microchip.c
> @@ -20,6 +20,7 @@
>  #include <linux/ethtool.h>
>  #include <linux/phy.h>
>  #include <linux/microchipphy.h>
> +#include <linux/delay.h>
>  
>  #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
>  #define DRIVER_DESC	"Microchip LAN88XX PHY driver"
> @@ -66,6 +67,107 @@ static int lan88xx_suspend(struct phy_device *phydev)
>  	return 0;
>  }
>  
> +static void lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
> +			       u32 data)
> +{
> +	int val;
> +	u16 buf;
> +
> +	/* Get access to token ring page */
> +	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
> +		  LAN88XX_EXT_PAGE_ACCESS_TR);

Hi Raghuram

You might want to look at phy_read_paged(), phy_write_paged(), etc.

There can be race conditions with paged access.

      Andrew
David Miller April 6, 2018, 3:21 p.m. UTC | #2
From: Andrew Lunn <andrew@lunn.ch>
Date: Fri, 6 Apr 2018 16:43:42 +0200

> On Fri, Apr 06, 2018 at 11:42:02AM +0530, Raghuram Chary J wrote:
>> The patch is to configure DSP registers of PHY device
>> to handle Gbe-EEE failures with >40m cable length.
>> 
>> Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver")
>> Signed-off-by: Raghuram Chary J <raghuramchary.jallipalli@microchip.com>
>> ---
>>  drivers/net/phy/microchip.c  | 123 ++++++++++++++++++++++++++++++++++++++++++-
>>  include/linux/microchipphy.h |   8 +++
>>  2 files changed, 130 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
>> index 0f293ef28935..174ae9808722 100644
>> --- a/drivers/net/phy/microchip.c
>> +++ b/drivers/net/phy/microchip.c
>> @@ -20,6 +20,7 @@
>>  #include <linux/ethtool.h>
>>  #include <linux/phy.h>
>>  #include <linux/microchipphy.h>
>> +#include <linux/delay.h>
>>  
>>  #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
>>  #define DRIVER_DESC	"Microchip LAN88XX PHY driver"
>> @@ -66,6 +67,107 @@ static int lan88xx_suspend(struct phy_device *phydev)
>>  	return 0;
>>  }
>>  
>> +static void lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
>> +			       u32 data)
>> +{
>> +	int val;
>> +	u16 buf;
>> +
>> +	/* Get access to token ring page */
>> +	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
>> +		  LAN88XX_EXT_PAGE_ACCESS_TR);
> 
> Hi Raghuram
> 
> You might want to look at phy_read_paged(), phy_write_paged(), etc.
> 
> There can be race conditions with paged access.

Yep, so something like:

static void lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
			       u32 data)
{
	int save_page, val;
	u16 buf;

	save_page = phy_save_page(phydev);
	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
			LAN88XX_EXT_PAGE_TR_LOW_DATA, (data & 0xFFFF));
	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
			LAN88XX_EXT_PAGE_TR_HIGH_DATA,
			(data & 0x00FF0000) >> 16);

	/* Config control bits [15:13] of register */
	buf = (regaddr & ~(0x3 << 13));/* Clr [14:13] to write data in reg */
	buf |= 0x8000; /* Set [15] to Packet transmit */

	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
			LAN88XX_EXT_PAGE_TR_CR, buf);
	usleep_range(1000, 2000);/* Wait for Data to be written */

	val = phy_read_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
			     LAN88XX_EXT_PAGE_TR_CR);
	if (!(val & 0x8000))
		pr_warn("TR Register[0x%X] configuration failed\n", regaddr);

	phy_restore_page(phydev, save_page, 0);
}

Since PHY accesses and thus things like phy_save_page() can fail, the
return type of this function should be changed to 'int' and some error
checking should be added.
Raghuram Chary J April 10, 2018, 2:27 a.m. UTC | #3
> >
> > Hi Raghuram
> >
> > You might want to look at phy_read_paged(), phy_write_paged(), etc.
> >
> > There can be race conditions with paged access.
> 
> Yep, so something like:
> 
> static void lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
> 			       u32 data)
> {
> 	int save_page, val;
> 	u16 buf;
> 
> 	save_page = phy_save_page(phydev);
> 	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
> 			LAN88XX_EXT_PAGE_TR_LOW_DATA, (data &
> 0xFFFF));
> 	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
> 			LAN88XX_EXT_PAGE_TR_HIGH_DATA,
> 			(data & 0x00FF0000) >> 16);
> 
> 	/* Config control bits [15:13] of register */
> 	buf = (regaddr & ~(0x3 << 13));/* Clr [14:13] to write data in reg */
> 	buf |= 0x8000; /* Set [15] to Packet transmit */
> 
> 	phy_write_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
> 			LAN88XX_EXT_PAGE_TR_CR, buf);
> 	usleep_range(1000, 2000);/* Wait for Data to be written */
> 
> 	val = phy_read_paged(phydev, LAN88XX_EXT_PAGE_ACCESS_TR,
> 			     LAN88XX_EXT_PAGE_TR_CR);
> 	if (!(val & 0x8000))
> 		pr_warn("TR Register[0x%X] configuration failed\n",
> regaddr);
> 
> 	phy_restore_page(phydev, save_page, 0); }
> 
> Since PHY accesses and thus things like phy_save_page() can fail, the return
> type of this function should be changed to 'int' and some error checking
> should be added.

Thanks David/Andrew.
Will take care of it.

Thanks,
Raghu
Sasha Levin April 10, 2018, 1:50 p.m. UTC | #4
Hi,

[This is an automated email]

This commit has been processed because it contains a "Fixes:" tag,
fixing commit: 55d7de9de6c3 Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver.

The bot has also determined it's probably a bug fixing patch. (score: 3.9486)

The bot has tested the following trees: v4.16.1, v4.15.16, v4.14.33, v4.9.93, v4.4.127.

v4.16.1: Build OK!
v4.15.16: Build OK!
v4.14.33: Build OK!
v4.9.93: Failed to apply! Possible dependencies:
    f6e3ef3e4d35 ("lan78xx: relocate mdix setting to phy driver")

v4.4.127: Failed to apply! Possible dependencies:
    f6e3ef3e4d35 ("lan78xx: relocate mdix setting to phy driver")


--
Thanks,
Sasha
diff mbox series

Patch

diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index 0f293ef28935..174ae9808722 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -20,6 +20,7 @@ 
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/microchipphy.h>
+#include <linux/delay.h>
 
 #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC	"Microchip LAN88XX PHY driver"
@@ -66,6 +67,107 @@  static int lan88xx_suspend(struct phy_device *phydev)
 	return 0;
 }
 
+static void lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
+			       u32 data)
+{
+	int val;
+	u16 buf;
+
+	/* Get access to token ring page */
+	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
+		  LAN88XX_EXT_PAGE_ACCESS_TR);
+
+	phy_write(phydev, LAN88XX_EXT_PAGE_TR_LOW_DATA, (data & 0xFFFF));
+	phy_write(phydev, LAN88XX_EXT_PAGE_TR_HIGH_DATA,
+		  (data & 0x00FF0000) >> 16);
+
+	/* Config control bits [15:13] of register */
+	buf = (regaddr & ~(0x3 << 13));/* Clr [14:13] to write data in reg */
+	buf |= 0x8000; /* Set [15] to Packet transmit */
+
+	phy_write(phydev, LAN88XX_EXT_PAGE_TR_CR, buf);
+
+	usleep_range(1000, 2000);/* Wait for Data to be written */
+	val = phy_read(phydev, LAN88XX_EXT_PAGE_TR_CR);
+	if (!(val & 0x8000))
+		pr_warn("TR Register[0x%X] configuration failed\n", regaddr);
+
+	/* Setting to Main page registers space*/
+	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
+}
+
+static void lan88xx_config_TR_regs(struct phy_device *phydev)
+{
+	/* Get access to Channel 0x1, Node 0xF , Register 0x01.
+	 * Write 24-bit value 0x12B00A to register. Setting MrvlTrFix1000Kf,
+	 * MrvlTrFix1000Kp, MasterEnableTR bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x0F82, 0x12B00A);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x06.
+	 * Write 24-bit value 0xD2C46F to register. Setting SSTrKf1000Slv,
+	 * SSTrKp1000Mas bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x168C, 0xD2C46F);
+
+	/* Get access to Channel b'10, Node b'1111, Register 0x11.
+	 * Write 24-bit value 0x620 to register. Setting rem_upd_done_thresh
+	 * bits
+	 */
+	lan88xx_TR_reg_set(phydev, 0x17A2, 0x620);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x10.
+	 * Write 24-bit value 0xEEFFDD to register. Setting
+	 * eee_TrKp1Long_1000, eee_TrKp2Long_1000, eee_TrKp3Long_1000,
+	 * eee_TrKp1Short_1000,eee_TrKp2Short_1000, eee_TrKp3Short_1000 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x16A0, 0xEEFFDD);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x13.
+	 * Write 24-bit value 0x071448 to register. Setting
+	 * slv_lpi_tr_tmr_val1, slv_lpi_tr_tmr_val2 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x16A6, 0x071448);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x12.
+	 * Write 24-bit value 0x13132F to register. Setting
+	 * slv_sigdet_timer_val1, slv_sigdet_timer_val2 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x16A4, 0x13132F);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x14.
+	 * Write 24-bit value 0x0 to register. Setting eee_3level_delay,
+	 * eee_TrKf_freeze_delay bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x16A8, 0x0);
+
+	/* Get access to Channel b'01, Node b'1111, Register 0x34.
+	 * Write 24-bit value 0x91B06C to register. Setting
+	 * FastMseSearchThreshLong1000, FastMseSearchThreshShort1000,
+	 * FastMseSearchUpdGain1000 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x0FE8, 0x91B06C);
+
+	/* Get access to Channel b'01, Node b'1111, Register 0x3E.
+	 * Write 24-bit value 0xC0A028 to register. Setting
+	 * FastMseKp2ThreshLong1000, FastMseKp2ThreshShort1000,
+	 * FastMseKp2UpdGain1000, FastMseKp2ExitEn1000 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x0FFC, 0xC0A028);
+
+	/* Get access to Channel b'01, Node b'1111, Register 0x35.
+	 * Write 24-bit value 0x041600 to register. Setting
+	 * FastMseSearchPhShNum1000, FastMseSearchClksPerPh1000,
+	 * FastMsePhChangeDelay1000 bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x0FEA, 0x041600);
+
+	/* Get access to Channel b'10, Node b'1101, Register 0x03.
+	 * Write 24-bit value 0x000004 to register. Setting TrFreeze bits.
+	 */
+	lan88xx_TR_reg_set(phydev, 0x1686, 0x000004);
+}
+
 static int lan88xx_probe(struct phy_device *phydev)
 {
 	struct device *dev = &phydev->mdio.dev;
@@ -132,6 +234,25 @@  static void lan88xx_set_mdix(struct phy_device *phydev)
 	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
 }
 
+static int lan88xx_config_init(struct phy_device *phydev)
+{
+	int val;
+
+	genphy_config_init(phydev);
+	/*Zerodetect delay enable */
+	val = phy_read_mmd(phydev, MDIO_MMD_PCS,
+			   PHY_ARDENNES_MMD_DEV_3_PHY_CFG);
+	val |= PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_;
+
+	phy_write_mmd(phydev, MDIO_MMD_PCS, PHY_ARDENNES_MMD_DEV_3_PHY_CFG,
+		      val);
+
+	/* Config DSP registers */
+	lan88xx_config_TR_regs(phydev);
+
+	return 0;
+}
+
 static int lan88xx_config_aneg(struct phy_device *phydev)
 {
 	lan88xx_set_mdix(phydev);
@@ -151,7 +272,7 @@  static struct phy_driver microchip_phy_driver[] = {
 	.probe		= lan88xx_probe,
 	.remove		= lan88xx_remove,
 
-	.config_init	= genphy_config_init,
+	.config_init	= lan88xx_config_init,
 	.config_aneg	= lan88xx_config_aneg,
 
 	.ack_interrupt	= lan88xx_phy_ack_interrupt,
diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h
index eb492d47f717..8f9c90379732 100644
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -70,4 +70,12 @@ 
 #define	LAN88XX_MMD3_CHIP_ID			(32877)
 #define	LAN88XX_MMD3_CHIP_REV			(32878)
 
+/* DSP registers */
+#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG		(0x806A)
+#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_	(0x2000)
+#define LAN88XX_EXT_PAGE_ACCESS_TR		(0x52B5)
+#define LAN88XX_EXT_PAGE_TR_CR			16
+#define LAN88XX_EXT_PAGE_TR_LOW_DATA		17
+#define LAN88XX_EXT_PAGE_TR_HIGH_DATA		18
+
 #endif /* _MICROCHIPPHY_H */