diff mbox

Freescale FEC i.MX28 restart problem

Message ID 53511079.2020206@meduna.org
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Stanislav Meduna April 18, 2014, 11:46 a.m. UTC
Hi,

I am experiencing a problem with the ethernet controller on an
i.MX28 SoC. When doing
  /etc/init.d/networking restart
sometimes I get "MDIO read timeout" and the controller does not
recover. The problem is more prominent if the interface is communicating
when the restart is performed.

I have found that the reason is the EBERR bit being set somewher.
The reference manual states:

  Ethernet bus error. This bit indicates a system bus error occurs when a DMA
  transaction is underway (Signal dma_eberr_int asserted). When the EBERR bit
  is set, ETHER_EN is cleared, halting frame processing by the MAC. When this
  occurs, software needs to insure proper actions (possibly resetting the
  system) to resume normal operation.

Clearing the ETHER_EN also disables the MII interrupts, so this
explains why the controller does not recover.

I assume the EBERR comes because of resetting the FEC at various
places - the fec_restart is called from 7 and fec_stop from 5 places.
It looks something here does not pay attention whether everything
is idle. In addition to EBERR also the BABR and MII are set
(MII because there was a MII transaction attempt, for babbling
receiver I have no idea). In case it matters the PHY connected
is the virtual port of the LAN9303 switch.

Trying to put a graceful stop before the reset in fec_restart
did not help. The controller is enabled when coming out of both
paths involving the reset, it is after this it falls into the
error state.

My platform is 3.12.15-rt, but I assume the problem is not rt-related.

The following patch remedies the situation, but this is just
a demonstration and not a solution. The warning is sometimes
output up to 3 times.

Please Cc: me when replying.




Regards

Comments

Fabio Estevam April 18, 2014, 12:59 p.m. UTC | #1
On Fri, Apr 18, 2014 at 8:46 AM, Stanislav Meduna <stano@meduna.org> wrote:
> Hi,
>
> I am experiencing a problem with the ethernet controller on an
> i.MX28 SoC. When doing
>   /etc/init.d/networking restart
> sometimes I get "MDIO read timeout" and the controller does not
> recover. The problem is more prominent if the interface is communicating
> when the restart is performed.
>
> I have found that the reason is the EBERR bit being set somewher.
> The reference manual states:
>
>   Ethernet bus error. This bit indicates a system bus error occurs when a DMA
>   transaction is underway (Signal dma_eberr_int asserted). When the EBERR bit
>   is set, ETHER_EN is cleared, halting frame processing by the MAC. When this
>   occurs, software needs to insure proper actions (possibly resetting the
>   system) to resume normal operation.
>
> Clearing the ETHER_EN also disables the MII interrupts, so this
> explains why the controller does not recover.
>
> I assume the EBERR comes because of resetting the FEC at various
> places - the fec_restart is called from 7 and fec_stop from 5 places.
> It looks something here does not pay attention whether everything
> is idle. In addition to EBERR also the BABR and MII are set
> (MII because there was a MII transaction attempt, for babbling
> receiver I have no idea). In case it matters the PHY connected
> is the virtual port of the LAN9303 switch.
>
> Trying to put a graceful stop before the reset in fec_restart
> did not help. The controller is enabled when coming out of both
> paths involving the reset, it is after this it falls into the
> error state.
>
> My platform is 3.12.15-rt, but I assume the problem is not rt-related.
>
> The following patch remedies the situation, but this is just
> a demonstration and not a solution. The warning is sometimes
> output up to 3 times.
>
> Please Cc: me when replying.
>
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index 1ec398b..cebb912 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -194,7 +194,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
>  #define FEC_ENET_MII   ((uint)0x00800000)      /* MII interrupt */
>  #define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */
>
> -#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
> +#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_EBERR)
>  #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
>
>  /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
> @@ -303,6 +303,31 @@ static void *swap_buffer(void *bufaddr, int len)
>         return bufaddr;
>  }
>
> +/* Re-enable the controller after an ethernet bus error.
> + *
> + * Reference manual: This bit indicates a system bus
> + * error occurs when a DMA transaction is underway
> + * (Signal dma_eberr_int asserted). When the EBERR bit
> + * is set, ETHER_EN is cleared, halting frame processing
> + * by the MAC. When this occurs, software needs to insure
> + * proper actions (possibly resetting the system) to resume
> + * normal operation.
> + *
> + * This seems to happen when we restart the controller.
> + */
> +static inline void fec_enet_clear_eberr_if_needed(struct net_device *ndev)
> +{
> +       struct fec_enet_private *fep = netdev_priv(ndev);
> +       u32 ctl = readl(fep->hwp + FEC_ECNTRL);
> +
> +       if (!(ctl & 2)) {
> +               ctl |= 2;
> +               writel(FEC_ENET_EBERR, fep->hwp + FEC_IEVENT);
> +               writel(ctl, fep->hwp + FEC_ECNTRL);
> +               netdev_warn(ndev, "Re-enabled after EBERR\n");
> +       }
> +}
> +
>  static int
>  fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
>  {
> @@ -1059,6 +1084,10 @@ fec_enet_interrupt(int irq, void *dev_id)
>                         ret = IRQ_HANDLED;
>                         complete(&fep->mdio_done);
>                 }
> +
> +               if (int_events & FEC_ENET_EBERR)
> +                       fec_enet_clear_eberr_if_needed(ndev);
> +
>         } while (int_events);
>
>         return ret;
> @@ -1200,6 +1229,8 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
>         struct fec_enet_private *fep = bus->priv;
>         unsigned long time_left;
>
> +       fec_enet_clear_eberr_if_needed(fep->netdev);
> +
>         fep->mii_timeout = 0;
>         init_completion(&fep->mdio_done);
>
> @@ -1227,6 +1258,8 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
>         struct fec_enet_private *fep = bus->priv;
>         unsigned long time_left;
>
> +       fec_enet_clear_eberr_if_needed(fep->netdev);
> +
>         fep->mii_timeout = 0;
>         init_completion(&fep->mdio_done);

Could you try the latest Russell's FEC patches available at?
http://ftp.arm.linux.org.uk/cgit/linux-arm.git/log/?h=fec-testing

Regards,

Fabio Estevam
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Fabio Estevam April 18, 2014, 1:05 p.m. UTC | #2
On Fri, Apr 18, 2014 at 9:59 AM, Fabio Estevam <festevam@gmail.com> wrote:

> Could you try the latest Russell's FEC patches available at?
> http://ftp.arm.linux.org.uk/cgit/linux-arm.git/log/?h=fec-testing

In particular this one could help with your "MDIO timeout" issue:
http://ftp.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=fec-testing&id=ec1fac3de70b16c69d3edc9f223e91d56b1915de
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 1ec398b..cebb912 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -194,7 +194,7 @@  MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #define FEC_ENET_MII   ((uint)0x00800000)      /* MII interrupt */
 #define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */

-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_EBERR)
 #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))

 /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
@@ -303,6 +303,31 @@  static void *swap_buffer(void *bufaddr, int len)
        return bufaddr;
 }

+/* Re-enable the controller after an ethernet bus error.
+ *
+ * Reference manual: This bit indicates a system bus
+ * error occurs when a DMA transaction is underway
+ * (Signal dma_eberr_int asserted). When the EBERR bit
+ * is set, ETHER_EN is cleared, halting frame processing
+ * by the MAC. When this occurs, software needs to insure
+ * proper actions (possibly resetting the system) to resume
+ * normal operation.
+ *
+ * This seems to happen when we restart the controller.
+ */
+static inline void fec_enet_clear_eberr_if_needed(struct net_device *ndev)
+{
+       struct fec_enet_private *fep = netdev_priv(ndev);
+       u32 ctl = readl(fep->hwp + FEC_ECNTRL);
+
+       if (!(ctl & 2)) {
+               ctl |= 2;
+               writel(FEC_ENET_EBERR, fep->hwp + FEC_IEVENT);
+               writel(ctl, fep->hwp + FEC_ECNTRL);
+               netdev_warn(ndev, "Re-enabled after EBERR\n");
+       }
+}
+
 static int
 fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -1059,6 +1084,10 @@  fec_enet_interrupt(int irq, void *dev_id)
                        ret = IRQ_HANDLED;
                        complete(&fep->mdio_done);
                }
+
+               if (int_events & FEC_ENET_EBERR)
+                       fec_enet_clear_eberr_if_needed(ndev);
+
        } while (int_events);

        return ret;
@@ -1200,6 +1229,8 @@  static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        struct fec_enet_private *fep = bus->priv;
        unsigned long time_left;

+       fec_enet_clear_eberr_if_needed(fep->netdev);
+
        fep->mii_timeout = 0;
        init_completion(&fep->mdio_done);

@@ -1227,6 +1258,8 @@  static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        struct fec_enet_private *fep = bus->priv;
        unsigned long time_left;

+       fec_enet_clear_eberr_if_needed(fep->netdev);
+
        fep->mii_timeout = 0;
        init_completion(&fep->mdio_done);