LS1021A Qoriq SDK-v2.0 eTSEC error handling (Busy error) but RSTATn[QHLTm] is not cleared, so controller remains halted

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LS1021A Qoriq SDK-v2.0 eTSEC error handling (Busy error) but RSTATn[QHLTm] is not cleared, so controller remains halted

681 Views
psijpkes
Contributor I

In a test with many illegally fragmented ICMP echo request frames we get into a situation where at some point nothing is processed anymore, the controller (TSEC) is halted as indicated by RSTATn bit QHLTm.

During this test the IEVENT triggers on event BSY. This is handled in the gianfar error handler (gfar_error). Bit QHLTm of RSTATn is set. The documentation mentions for the Error-handling procedure, reception errors: "The halted queue resumes reception once the RSTATn[QHLTm] bit is cleared". However this does not happen.

When done by hand this actually resolves the issue, the question is how this should work ?  Shouldn't the error handler take care of the RSTAT clear ?

To point out some detail, after switching on debug we get the following print just before we get stuck:
Jan  1 17:54:03 ls1021atwr user.debug kernel: fsl-gianfar soc:ethernet@2d10000 eth0: error interrupt (ievent=0x20000000 imask=0xf1310083)
Jan  1 17:54:03 ls1021atwr user.debug kernel: fsl-gianfar soc:ethernet@2d10000 eth0: busy error (rstat: 800080)

Any help is appreciated

0 Kudos
1 Reply

574 Views
yipingwang
NXP TechSupport
NXP TechSupport

Hello Peter Sijpkes,

If a frame is accepted, the Ethernet controller fetches the receive buffer descript(RxBD) pointed to by a corresponding RBPTRn register. If the fetches RxBD is not empty, a receive busy error condition is raised in IEVENT[BSY] and increments the discarded frame counter(RDRP), in addition the RSTAT[QHLTn] bit is set.

In gfar_error, EVENT is clear, so the interrupt aren't called again, the system resume the original execution, RSTAT[QHLTn]  is clear in the function gfar_poll_rx_sq.

I consider you could use CodeWarrior to track gianfar driver execution to get where it stuck? Or did you get any Kernel call trace information?

We found a similar problem in LS1021a testing recently. Kernel panic when the packet length is larger than MTU during IPFWD. We have the following patch which is applied to the latest Kernel source code. Please check whether it is helpful for your problem.

diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3bdeb29..f5c87bd3 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2934,29 +2934,17 @@  static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
 {
         int size = lstatus & BD_LENGTH_MASK;
         struct page *page = rxb->page;
-        bool last = !!(lstatus & BD_LFLAG(RXBD_LAST));
-
-        /* Remove the FCS from the packet length */
-        if (last)
-                size -= ETH_FCS_LEN;
 
         if (likely(first)) {
                 skb_put(skb, size);
         } else {
                 /* the last fragments' length contains the full frame length */
-                if (last)
+                if (lstatus & BD_LFLAG(RXBD_LAST))
                          size -= skb->len;
 
-                /* Add the last fragment if it contains something other than
-                 * the FCS, otherwise drop it and trim off any part of the FCS
-                 * that was already received.
-                 */
-                if (size > 0)
-                         skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-                                           rxb->page_offset + RXBUF_ALIGNMENT,
-                                           size, GFAR_RXB_TRUESIZE);
-                else if (size < 0)
-                         pskb_trim(skb, skb->len + size);
+                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                                  rxb->page_offset + RXBUF_ALIGNMENT,
+                                  size, GFAR_RXB_TRUESIZE);
         }
 
         /* try reuse page */
@@ -3069,6 +3057,9 @@  static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
         if (priv->padding)
                 skb_pull(skb, priv->padding);
 
+        /* Trim off the FCS */
+        pskb_trim(skb, skb->len - ETH_FCS_LEN);
+
         if (ndev->features & NETIF_F_RXCSUM)
                 gfar_rx_checksum(skb, fcb);


Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos