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

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

commit 8eae6d950df532b98fa4fc9eb0a5754ca99c75f5
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Sun Oct 4 00:54:54 2026 -0300

    arch/mips/pic32mz: fix the Ethernet D-Cache coherency.
    
    VIRT_ADDR() converted the DMA buffer addresses to KSEG1, while the
    buffers come from g_buffers, which is linked in KSEG0 when the data
    memory is cached.  Buffers then ended up in the free list under both
    aliases.  Use the segment g_buffers is linked in instead.
    
    A buffer handed to an RX descriptor may still have dirty D-Cache lines,
    at least the free list link written into it.  If such a line is evicted
    while the DMA writes the frame, it overwrites part of the frame.
    Discard the buffer from the D-Cache before giving it to the DMA.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Daniel P. Carvalho <[email protected]>
---
 arch/mips/src/pic32mz/pic32mz_ethernet.c | 41 +++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/arch/mips/src/pic32mz/pic32mz_ethernet.c 
b/arch/mips/src/pic32mz/pic32mz_ethernet.c
index 7d5b7004d0b..c2358940f27 100644
--- a/arch/mips/src/pic32mz/pic32mz_ethernet.c
+++ b/arch/mips/src/pic32mz/pic32mz_ethernet.c
@@ -334,7 +334,11 @@
 /* Misc Helper Macros *******************************************************/
 
 #define PHYS_ADDR(va) ((uint32_t)(va) & 0x1fffffff)
-#define VIRT_ADDR(pa) (KSEG1_BASE | (uint32_t)(pa))
+/* Buffers are always accessed through the segment g_buffers is linked in
+ * (KSEG0 or KSEG1), so that no buffer is ever reached through two aliases.
+ */
+
+#define VIRT_ADDR(pa) (((uint32_t)g_buffers & 0xe0000000) | (uint32_t)(pa))
 
 /****************************************************************************
  * Private Types
@@ -445,6 +449,7 @@ static void pic32mz_dumprxdesc(struct pic32mz_rxdesc_s 
*rxdesc,
 
 static inline void pic32mz_bufferinit(struct pic32mz_driver_s *priv);
 static uint8_t *pic32mz_allocbuffer(struct pic32mz_driver_s *priv);
+static uint8_t *pic32mz_rxbuffer(struct pic32mz_driver_s *priv);
 static void pic32mz_freebuffer(struct pic32mz_driver_s *priv,
                                uint8_t *buffer);
 
@@ -768,6 +773,36 @@ static uint8_t *pic32mz_allocbuffer(struct 
pic32mz_driver_s *priv)
   return (uint8_t *)sq_remfirst(&priv->pd_freebuffers);
 }
 
+/****************************************************************************
+ * Function: pic32mz_rxbuffer
+ *
+ * Description:
+ *   Allocate one buffer for an RX descriptor.  The free list link and any
+ *   data left by the network stack may still sit in dirty D-Cache lines;
+ *   they are discarded so that a later eviction cannot overwrite the frame
+ *   written by the DMA.
+ *
+ * Input Parameters:
+ *   priv - Pointer to EMAC device driver structure
+ *
+ * Returned Value:
+ *   Pointer to the allocated buffer (or NULL on failure)
+ *
+ ****************************************************************************/
+
+static uint8_t *pic32mz_rxbuffer(struct pic32mz_driver_s *priv)
+{
+  uint8_t *buffer = pic32mz_allocbuffer(priv);
+
+  if (buffer != NULL)
+    {
+      up_invalidate_dcache((uintptr_t)buffer,
+                           (uintptr_t)buffer + PIC32MZ_ALIGNED_BUFSIZE);
+    }
+
+  return buffer;
+}
+
 /****************************************************************************
  * Function: pic32mz_freebuffer
  *
@@ -905,7 +940,7 @@ static inline void pic32mz_rxdescinit(struct 
pic32mz_driver_s *priv)
 
       rxdesc->rsv1    = 0;
       rxdesc->rsv2    = 0;
-      rxdesc->address = PHYS_ADDR(pic32mz_allocbuffer(priv));
+      rxdesc->address = PHYS_ADDR(pic32mz_rxbuffer(priv));
       rxdesc->status  = RXDESC_STATUS_EOWN | RXDESC_STATUS_NPV;
 
       /* Set the NEXTED pointer.  If this is the last descriptor in the
@@ -1514,7 +1549,7 @@ static void pic32mz_rxdone(struct pic32mz_driver_s *priv)
            * descriptor back to the hardware with its current buffer.
            */
 
-          rxbuffer = pic32mz_allocbuffer(priv);
+          rxbuffer = pic32mz_rxbuffer(priv);
           if (rxbuffer == NULL)
             {
               nwarn("WARNING: No free buffer, packet dropped\n");

Reply via email to