diff mbox

[2/2] net: mvneta: fix usage as a module on RGMII configurations

Message ID 1395789942-20764-3-git-send-email-thomas.petazzoni@free-electrons.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Thomas Petazzoni March 25, 2014, 11:25 p.m. UTC
Commit 5445eaf309ff ('mvneta: Try to fix mvneta when compiled as
module') fixed the mvneta driver to make it work properly when loaded
as a module in SGMII configuration, which was tested successful by the
author on the Armada XP OpenBlocks AX3, which uses SGMII.

However, it turns out that the Armada XP GP, which uses RGMII, is
affected by a similar problem: its SERDES configuration is lost when
mvneta is loaded as a module, because this configuration is set by the
bootloader, and then lost because the clock is gated by the clock
framework until the mvneta driver is loaded again and the clock is
re-enabled.

However, it turns out that for the RGMII case, setting the SERDES
configuration is not sufficient: the PCS enable bit in the
MVNETA_GMAC_CTRL_2 register must also be set, like in the SGMII
configuration.

Therefore, this commit reworks the SGMII/RGMII initialization: the
only difference between the two now is a different SERDES
configuration, all the rest is identical.

In detail, to achieve this, the commit:

 * Renames MVNETA_SGMII_SERDES_CFG to MVNETA_SERDES_CFG because it is
   not specific to SGMII, but also used on RGMII configurations.

 * Adds a MVNETA_RGMII_SERDES_PROTO definition, that must be used as
   the MVNETA_SERDES_CFG value in RGMII configurations.

 * Removes the mvneta_gmac_rgmii_set() and mvneta_port_sgmii_config()
   functions, and instead directly do the SGMII/RGMII configuration in
   mvneta_port_up(), from where those functions where called. It is
   worth mentioning that mvneta_gmac_rgmii_set() had an 'enable'
   parameter that was always passed as '1', so it was pretty useless.

 * Reworks the mvneta_port_up() function to set the MVNETA_SERDES_CFG
   register to the appropriate value depending on the RGMII vs. SGMII
   configuration. It also unconditionally set the PCS_ENABLE bit (was
   already done for SGMII, but is now also needed for RGMII), and sets
   the PORT_RGMII bit (which was already done for both SGMII and
   RGMII).

This commit was successfully tested with mvneta compiled as a module,
on both the OpenBlocks AX3 (SGMII configuration) and the Armada XP GP
(RGMII configuration).

Reported-by: Steve McIntyre <steve@einval.com>
Cc: stable@vger.kernel.org # 3.11.x: 5445eaf309ff mvneta: Try to fix mvneta when compiled as module
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/net/ethernet/marvell/mvneta.c | 41 +++++++----------------------------
 1 file changed, 8 insertions(+), 33 deletions(-)

Comments

Gregory CLEMENT April 2, 2014, 2:15 p.m. UTC | #1
Hi,

On 26/03/2014 00:25, Thomas Petazzoni wrote:
> Commit 5445eaf309ff ('mvneta: Try to fix mvneta when compiled as
> module') fixed the mvneta driver to make it work properly when loaded
> as a module in SGMII configuration, which was tested successful by the
> author on the Armada XP OpenBlocks AX3, which uses SGMII.
> 
> However, it turns out that the Armada XP GP, which uses RGMII, is
> affected by a similar problem: its SERDES configuration is lost when
> mvneta is loaded as a module, because this configuration is set by the
> bootloader, and then lost because the clock is gated by the clock
> framework until the mvneta driver is loaded again and the clock is
> re-enabled.
> 
> However, it turns out that for the RGMII case, setting the SERDES
> configuration is not sufficient: the PCS enable bit in the
> MVNETA_GMAC_CTRL_2 register must also be set, like in the SGMII
> configuration.
> 
> Therefore, this commit reworks the SGMII/RGMII initialization: the
> only difference between the two now is a different SERDES
> configuration, all the rest is identical.
> 
> In detail, to achieve this, the commit:
> 
>  * Renames MVNETA_SGMII_SERDES_CFG to MVNETA_SERDES_CFG because it is
>    not specific to SGMII, but also used on RGMII configurations.
> 
>  * Adds a MVNETA_RGMII_SERDES_PROTO definition, that must be used as
>    the MVNETA_SERDES_CFG value in RGMII configurations.
> 
>  * Removes the mvneta_gmac_rgmii_set() and mvneta_port_sgmii_config()
>    functions, and instead directly do the SGMII/RGMII configuration in
>    mvneta_port_up(), from where those functions where called. It is
>    worth mentioning that mvneta_gmac_rgmii_set() had an 'enable'
>    parameter that was always passed as '1', so it was pretty useless.
> 
>  * Reworks the mvneta_port_up() function to set the MVNETA_SERDES_CFG
>    register to the appropriate value depending on the RGMII vs. SGMII
>    configuration. It also unconditionally set the PCS_ENABLE bit (was
>    already done for SGMII, but is now also needed for RGMII), and sets
>    the PORT_RGMII bit (which was already done for both SGMII and
>    RGMII).
> 
> This commit was successfully tested with mvneta compiled as a module,
> on both the OpenBlocks AX3 (SGMII configuration) and the Armada XP GP
> (RGMII configuration).

Unfortunately with this patch, mvneta doesn't work anymore on the
Mirabox (Armada 370 based board) on 3.14.I didn't managed to do a
simple ping.

Once I removed this commit then the driver worked again.

Gregory


> 
> Reported-by: Steve McIntyre <steve@einval.com>
> Cc: stable@vger.kernel.org # 3.11.x: 5445eaf309ff mvneta: Try to fix mvneta when compiled as module
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
>  drivers/net/ethernet/marvell/mvneta.c | 41 +++++++----------------------------
>  1 file changed, 8 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
> index d6b04d0..c9c2faa 100644
> --- a/drivers/net/ethernet/marvell/mvneta.c
> +++ b/drivers/net/ethernet/marvell/mvneta.c
> @@ -88,8 +88,9 @@
>  #define      MVNETA_TX_IN_PRGRS                  BIT(1)
>  #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
>  #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
> -#define MVNETA_SGMII_SERDES_CFG			 0x24A0
> +#define MVNETA_SERDES_CFG			 0x24A0
>  #define      MVNETA_SGMII_SERDES_PROTO		 0x0cc7
> +#define      MVNETA_RGMII_SERDES_PROTO		 0x0667
>  #define MVNETA_TYPE_PRIO                         0x24bc
>  #define      MVNETA_FORCE_UNI                    BIT(21)
>  #define MVNETA_TXQ_CMD_1                         0x24e4
> @@ -710,35 +711,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
>  	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
>  }
>  
> -
> -
> -/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
> -static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
> -{
> -	u32  val;
> -
> -	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
> -
> -	if (enable)
> -		val |= MVNETA_GMAC2_PORT_RGMII;
> -	else
> -		val &= ~MVNETA_GMAC2_PORT_RGMII;
> -
> -	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
> -}
> -
> -/* Config SGMII port */
> -static void mvneta_port_sgmii_config(struct mvneta_port *pp)
> -{
> -	u32 val;
> -
> -	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
> -	val |= MVNETA_GMAC2_PCS_ENABLE;
> -	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
> -
> -	mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
> -}
> -
>  /* Start the Ethernet port RX and TX activity */
>  static void mvneta_port_up(struct mvneta_port *pp)
>  {
> @@ -2756,12 +2728,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
>  	mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
>  
>  	if (phy_mode == PHY_INTERFACE_MODE_SGMII)
> -		mvneta_port_sgmii_config(pp);
> +		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
> +	else
> +		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
>  
> -	mvneta_gmac_rgmii_set(pp, 1);
> +	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
> +
> +	val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
>  
>  	/* Cancel Port Reset */
> -	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
>  	val &= ~MVNETA_GMAC2_PORT_RESET;
>  	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
>  
>
Thomas Petazzoni April 3, 2014, 9:36 a.m. UTC | #2
Dear Gregory CLEMENT,

On Wed, 02 Apr 2014 16:15:17 +0200, Gregory CLEMENT wrote:

> > This commit was successfully tested with mvneta compiled as a module,
> > on both the OpenBlocks AX3 (SGMII configuration) and the Armada XP GP
> > (RGMII configuration).
> 
> Unfortunately with this patch, mvneta doesn't work anymore on the
> Mirabox (Armada 370 based board) on 3.14.I didn't managed to do a
> simple ping.
> 
> Once I removed this commit then the driver worked again.

Problem reproduced. It turns out that some RGMII platforms need the
PCS_ENABLE bit to be set (e.g: Armada XP GP), while some other
platforms need the PCS_ENABLE bit to be cleared (e.g: Armada 370
Mirabox). I've verified that on both platforms.

I've asked for more details about this bit to understand in which
situation it should be set or cleared. I'll get back to you with an
updated patch once I have enough information to write a fix.

Thanks for the report,

Thomas
Ezequiel Garcia April 9, 2014, 12:22 p.m. UTC | #3
Hello Thomas,

On Apr 03, Thomas Petazzoni wrote:
> On Wed, 02 Apr 2014 16:15:17 +0200, Gregory CLEMENT wrote:
> 
> > > This commit was successfully tested with mvneta compiled as a module,
> > > on both the OpenBlocks AX3 (SGMII configuration) and the Armada XP GP
> > > (RGMII configuration).
> > 
> > Unfortunately with this patch, mvneta doesn't work anymore on the
> > Mirabox (Armada 370 based board) on 3.14.I didn't managed to do a
> > simple ping.
> > 
> > Once I removed this commit then the driver worked again.
> 
> Problem reproduced. It turns out that some RGMII platforms need the
> PCS_ENABLE bit to be set (e.g: Armada XP GP), while some other
> platforms need the PCS_ENABLE bit to be cleared (e.g: Armada 370
> Mirabox). I've verified that on both platforms.
> 
> I've asked for more details about this bit to understand in which
> situation it should be set or cleared. I'll get back to you with an
> updated patch once I have enough information to write a fix.
> 

Just found this commit is in v3.12.17 and prevents booting the A370
Mirabox with nfsroot.

Maybe we should revert it in stable for now until we can solve it?

Unless you have a better idea.
Thomas Petazzoni April 9, 2014, 12:40 p.m. UTC | #4
Dear Ezequiel Garcia,

On Wed, 9 Apr 2014 09:22:41 -0300, Ezequiel Garcia wrote:

> Just found this commit is in v3.12.17 and prevents booting the A370
> Mirabox with nfsroot.
> 
> Maybe we should revert it in stable for now until we can solve it?
> 
> Unless you have a better idea.

Yes, this problem is already tracked at
https://bugzilla.kernel.org/show_bug.cgi?id=73401, where I've explained
what's going on.

Unfortunately, I'm still waiting for details from Marvell to understand
in which cases the PCS needs to be set, and in which situations it
needs to be cleared.

Since getting this information is apparently going to take much more
time that I originally hoped, I'm starting to think that the safest and
fastest course of action is indeed to revert this patch.

Thomas
diff mbox

Patch

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index d6b04d0..c9c2faa 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -88,8 +88,9 @@ 
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
-#define MVNETA_SGMII_SERDES_CFG			 0x24A0
+#define MVNETA_SERDES_CFG			 0x24A0
 #define      MVNETA_SGMII_SERDES_PROTO		 0x0cc7
+#define      MVNETA_RGMII_SERDES_PROTO		 0x0667
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -710,35 +711,6 @@  static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
 	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
 }
 
-
-
-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
-{
-	u32  val;
-
-	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-
-	if (enable)
-		val |= MVNETA_GMAC2_PORT_RGMII;
-	else
-		val &= ~MVNETA_GMAC2_PORT_RGMII;
-
-	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-}
-
-/* Config SGMII port */
-static void mvneta_port_sgmii_config(struct mvneta_port *pp)
-{
-	u32 val;
-
-	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-	val |= MVNETA_GMAC2_PCS_ENABLE;
-	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-
-	mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
-}
-
 /* Start the Ethernet port RX and TX activity */
 static void mvneta_port_up(struct mvneta_port *pp)
 {
@@ -2756,12 +2728,15 @@  static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
 	mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
 
 	if (phy_mode == PHY_INTERFACE_MODE_SGMII)
-		mvneta_port_sgmii_config(pp);
+		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
+	else
+		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
 
-	mvneta_gmac_rgmii_set(pp, 1);
+	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
+
+	val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
 
 	/* Cancel Port Reset */
-	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 	val &= ~MVNETA_GMAC2_PORT_RESET;
 	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);