You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/21 20:16:36 UTC

[incubator-nuttx] branch master updated: kinetis:Ethernet fixed & better interrupt management

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 5cbebda  kinetis:Ethernet fixed & better interrupt management
5cbebda is described below

commit 5cbebda133bddc987de84b8c1ba756be3a70691b
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Mon Jun 15 10:59:04 2020 -0700

    kinetis:Ethernet fixed & better interrupt management
    
       When any error was detected the buffers descriptors were
       blindly initialized. This caused the TX of the MAC to
       be in a bad state. The correct thing to do, we disable
       the MAC, init the bufffers and re-eanable the MAC.
    
       The interrupts were being throlled at the NVIC. This been
       cleaned up.
---
 arch/arm/src/kinetis/kinetis_enet.c | 110 +++++++++++++++++++++---------------
 1 file changed, 65 insertions(+), 45 deletions(-)

diff --git a/arch/arm/src/kinetis/kinetis_enet.c b/arch/arm/src/kinetis/kinetis_enet.c
index c78d98e..ff3cdf1 100644
--- a/arch/arm/src/kinetis/kinetis_enet.c
+++ b/arch/arm/src/kinetis/kinetis_enet.c
@@ -204,7 +204,9 @@
 #define ERROR_INTERRUPTS  (ENET_INT_UN    | ENET_INT_RL   | ENET_INT_LC | \
                            ENET_INT_EBERR | ENET_INT_BABT | ENET_INT_BABR)
 
-/* This is a helper pointer for accessing the contents of the Ethernet header */
+/* This is a helper pointer for accessing the contents of the Ethernet
+ * header
+ */
 
 #define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
 
@@ -237,6 +239,7 @@ struct kinetis_driver_s
   uint8_t phyaddr;             /* Selected PHY address */
   WDOG_ID txpoll;              /* TX poll timer */
   WDOG_ID txtimeout;           /* TX timeout timer */
+  uint32_t ints;               /* Enabled interrupts */
   struct work_s irqwork;       /* For deferring interrupt work to the work queue */
   struct work_s pollwork;      /* For deferring poll work to the work queue */
   struct enet_desc_s *txdesc;  /* A pointer to the list of TX descriptor */
@@ -447,7 +450,6 @@ static bool kinetis_txringfull(FAR struct kinetis_driver_s *priv)
 static int kinetis_transmit(FAR struct kinetis_driver_s *priv)
 {
   struct enet_desc_s *txdesc;
-  uint32_t regval;
   uint8_t *buf;
 
   /* Since this can be called from kinetis_receive, it is possible that
@@ -513,9 +515,8 @@ static int kinetis_transmit(FAR struct kinetis_driver_s *priv)
 
   /* Enable TX interrupts */
 
-  regval  = getreg32(KINETIS_ENET_EIMR);
-  regval |= TX_INTERRUPTS;
-  putreg32(regval, KINETIS_ENET_EIMR);
+  priv->ints |= TX_INTERRUPTS;
+  modifyreg32(KINETIS_ENET_EIMR, 0, TX_INTERRUPTS);
 
   /* Setup the TX timeout watchdog (perhaps restarting the timer) */
 
@@ -644,7 +645,9 @@ static void kinetis_receive(FAR struct kinetis_driver_s *priv)
         (uint8_t *)kinesis_swap32((uint32_t)priv->rxdesc[priv->rxtail].data);
 
 #ifdef CONFIG_NET_PKT
-      /* When packet sockets are enabled, feed the frame into the packet tap */
+      /* When packet sockets are enabled, feed the frame into the packet
+       * tap
+       */
 
        pkt_input(&priv->dev);
 #endif
@@ -796,14 +799,12 @@ static void kinetis_receive(FAR struct kinetis_driver_s *priv)
 
 static void kinetis_txdone(FAR struct kinetis_driver_s *priv)
 {
-  uint32_t regval;
-
   /* Verify that the oldest descriptor descriptor completed */
 
   while (((priv->txdesc[priv->txtail].status1 & TXDESC_R) == 0) &&
          (priv->txtail != priv->txhead))
     {
-      /* Yes.. bump up the tail pointer, making space for a new TX descriptor */
+      /* Yes. Bump the tail pointer, making space for a new TX descriptor */
 
       priv->txtail++;
       if (priv->txtail >= CONFIG_KINETIS_ENETNTXBUFFERS)
@@ -823,10 +824,8 @@ static void kinetis_txdone(FAR struct kinetis_driver_s *priv)
       /* No.. Cancel the TX timeout and disable further Tx interrupts. */
 
       wd_cancel(priv->txtimeout);
-
-      regval  = getreg32(KINETIS_ENET_EIMR);
-      regval &= ~TX_INTERRUPTS;
-      putreg32(regval, KINETIS_ENET_EIMR);
+      priv->ints &= ~TX_INTERRUPTS;
+      modifyreg32(KINETIS_ENET_EIMR, TX_INTERRUPTS, priv->ints);
     }
 
   /* There should be space for a new TX in any event.  Poll the network for
@@ -864,7 +863,7 @@ static void kinetis_interrupt_work(FAR void *arg)
 
   /* Get the set of unmasked, pending interrupt. */
 
-  pending = getreg32(KINETIS_ENET_EIR) & getreg32(KINETIS_ENET_EIMR);
+  pending = getreg32(KINETIS_ENET_EIR) & priv->ints;
 
   /* Clear the pending interrupts */
 
@@ -899,13 +898,35 @@ static void kinetis_interrupt_work(FAR void *arg)
     {
       /* An error has occurred, update statistics */
 
+      nerr("pending %0xd ints %0xd\n", pending, priv->ints);
+
       NETDEV_ERRORS(&priv->dev);
 
+      /* Shutdown the MAC to keep it out of the descriptors */
+
+      modifyreg32(KINETIS_ENET_ECR, ENET_ECR_ETHEREN, 0);
+
       /* Reinitialize all buffers. */
 
       kinetis_initbuffers(priv);
 
-      /* Indicate that there have been empty receive buffers produced */
+      /* Set the RX buffer size */
+
+      putreg32(KINETIS_BUF_SIZE, KINETIS_ENET_MRBR);
+
+      /* Point to the start of the circular RX buffer descriptor queue */
+
+      putreg32((uint32_t)priv->rxdesc, KINETIS_ENET_RDSR);
+
+      /* Point to the start of the circular TX buffer descriptor queue */
+
+      putreg32((uint32_t)priv->txdesc, KINETIS_ENET_TDSR);
+
+      /* Enable MAC */
+
+      modifyreg32(KINETIS_ENET_ECR, 0, ENET_ECR_ETHEREN);
+
+      /* Receive buffers available */
 
       putreg32(ENET_RDAR, KINETIS_ENET_RDAR);
     }
@@ -914,12 +935,7 @@ static void kinetis_interrupt_work(FAR void *arg)
 
   /* Re-enable Ethernet interrupts */
 
-#if 0
-  up_enable_irq(KINETIS_IRQ_EMACTMR);
-#endif
-  up_enable_irq(KINETIS_IRQ_EMACTX);
-  up_enable_irq(KINETIS_IRQ_EMACRX);
-  up_enable_irq(KINETIS_IRQ_EMACMISC);
+  putreg32(priv->ints, KINETIS_ENET_EIMR);
 }
 
 /****************************************************************************
@@ -951,10 +967,7 @@ static int kinetis_interrupt(int irq, FAR void *context, FAR void *arg)
    * condition here.
    */
 
-  up_disable_irq(KINETIS_IRQ_EMACTMR);
-  up_disable_irq(KINETIS_IRQ_EMACTX);
-  up_disable_irq(KINETIS_IRQ_EMACRX);
-  up_disable_irq(KINETIS_IRQ_EMACMISC);
+  putreg32(0, KINETIS_ENET_EIMR);
 
   /* TODO: Determine if a TX transfer just completed */
 
@@ -999,8 +1012,8 @@ static void kinetis_txtimeout_work(FAR void *arg)
   net_lock();
   NETDEV_TXTIMEOUTS(&priv->dev);
 
-  /* Take the interface down and bring it back up.  The is the most aggressive
-   * hardware reset.
+  /* Take the interface down and bring it back up.  The is the most
+   * aggressive hardware reset.
    */
 
   kinetis_ifdown(&priv->dev);
@@ -1040,10 +1053,8 @@ static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...)
    * condition with interrupt work that is already queued and in progress.
    */
 
-  up_disable_irq(KINETIS_IRQ_EMACTMR);
-  up_disable_irq(KINETIS_IRQ_EMACTX);
-  up_disable_irq(KINETIS_IRQ_EMACRX);
-  up_disable_irq(KINETIS_IRQ_EMACMISC);
+  putreg32(0, KINETIS_ENET_EIMR);
+  priv->ints = 0;
 
   /* Schedule to perform the TX timeout processing on the worker thread,
    * canceling any pending interrupt work.
@@ -1237,26 +1248,30 @@ static int kinetis_ifup(struct net_driver_s *dev)
   wd_start(priv->txpoll, KINETIS_WDDELAY, kinetis_polltimer_expiry, 1,
            (wdparm_t)priv);
 
+  putreg32(0, KINETIS_ENET_EIMR);
+
   /* Clear all pending ENET interrupt */
 
   putreg32(0xffffffff, KINETIS_ENET_EIR);
 
-  /* Enable RX and error interrupts at the controller (TX interrupts are
-   * still disabled).
-   */
-
-  putreg32(RX_INTERRUPTS | ERROR_INTERRUPTS,
-           KINETIS_ENET_EIMR);
-
-  /* Mark the interrupt "up" and enable interrupts at the NVIC */
-
-  priv->bifup = true;
 #if 0
   up_enable_irq(KINETIS_IRQ_EMACTMR);
 #endif
   up_enable_irq(KINETIS_IRQ_EMACTX);
   up_enable_irq(KINETIS_IRQ_EMACRX);
   up_enable_irq(KINETIS_IRQ_EMACMISC);
+
+  /* Mark the interrupt "up" and enable interrupts at the NVIC */
+
+  priv->bifup = true;
+
+  /* Enable RX and error interrupts at the controller (TX interrupts are
+   * still disabled).
+   */
+
+  priv->ints = RX_INTERRUPTS | ERROR_INTERRUPTS;
+  modifyreg32(KINETIS_ENET_EIMR, TX_INTERRUPTS,  priv->ints);
+
   return OK;
 }
 
@@ -1285,11 +1300,14 @@ static int kinetis_ifdown(struct net_driver_s *dev)
   /* Disable the Ethernet interrupts at the NVIC */
 
   flags = enter_critical_section();
+
+  priv->ints = 0;
+  putreg32(priv->ints, KINETIS_ENET_EIMR);
+
   up_disable_irq(KINETIS_IRQ_EMACTMR);
   up_disable_irq(KINETIS_IRQ_EMACTX);
   up_disable_irq(KINETIS_IRQ_EMACRX);
   up_disable_irq(KINETIS_IRQ_EMACMISC);
-  putreg32(0, KINETIS_ENET_EIMR);
 
   /* Cancel the TX poll timer and TX timeout timers */
 
@@ -1721,7 +1739,9 @@ static inline int kinetis_initphy(struct kinetis_driver_s *priv)
         }
       while ((ret < 0 || phydata == 0xffff) && ++retries < 3);
 
-      /* If we successfully read anything then break out, using this PHY address */
+      /* If we successfully read anything then break out, using this PHY
+       * address
+       */
 
       if (retries < 3)
         {
@@ -1809,8 +1829,8 @@ static inline int kinetis_initphy(struct kinetis_driver_s *priv)
        * MCU whenever the link is ready.
        */
 
-      ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?), default to 10Mbs mode\n", \
-            BOARD_PHY_NAME, retries);
+      ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?),"
+            " default to 10Mbs mode\n", BOARD_PHY_NAME, retries);
 
       /* Stop auto negotiation */