diff --git a/arch/mips/src/pic32mz/pic32mz-ethernet.c b/arch/mips/src/pic32mz/pic32mz-ethernet.c index b9cecf62181..a83b173f853 100644 --- a/arch/mips/src/pic32mz/pic32mz-ethernet.c +++ b/arch/mips/src/pic32mz/pic32mz-ethernet.c @@ -81,7 +81,9 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Configuration ************************************************************/ + /* If processing is not done at the interrupt level, then work queue support * is required. */ @@ -142,19 +144,41 @@ # define CONFIG_PIC32MZ_ETH_NRXDESC 4 #endif +/* Align descriptors' size to D-Cache line size */ + +#define DMA_BUFFER_MASK (PIC32MZ_DCACHE_LINESIZE - 1) +#define DMA_ALIGN_UP(n) (((n) + DMA_BUFFER_MASK) & ~DMA_BUFFER_MASK) +#define DMA_ALIGN_DOWN(n) ((n) & ~DMA_BUFFER_MASK) + +/* A circular linked list of descriptors is used in this implementation. + * This means the size of a descriptor is 20 bytes. If however a linear + * implementation is used, the descriptor size will be 16 bytes and no + * padding is required. + */ + +#define DESC_SIZE 20 +#define DESC_PADSIZE DMA_ALIGN_UP(DESC_SIZE) + /* Make sure that the size of each buffer is a multiple of 4 bytes. This * will force alignment of all buffers to 4-byte boundaries (this is needed * by the queuing logic which will cast each buffer address to a pointer * type). + * Furthermore, the buffers should be aligned to D-Cache line size, + * so that there are no spill-over effects at the borders of the + * cleaned line when D-Cache is enabled. + * + * D-Cache line size is 16 bytes, then we will fulfill both of the conditions + * above by aligning the buffer to D-Cache size. */ -#define PIC32MZ_ALIGNED_BUFSIZE ((CONFIG_NET_ETH_PKTSIZE + 3) & ~3) +#define PIC32MZ_ALIGNED_BUFSIZE DMA_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE) /* The number of buffers will, then, be one for each descriptor plus one extra */ #define PIC32MZ_NBUFFERS (CONFIG_PIC32MZ_ETH_NRXDESC + CONFIG_PIC32MZ_ETH_NTXDESC + 1) /* Debug Configuration *****************************************************/ + /* Register/Descriptor debug -- can only happen of CONFIG_DEBUG_FEATURES is selected. * This will probably generate much more output than you care to see. */ @@ -188,7 +212,7 @@ #define PIC32MZ_TXTIMEOUT (60*CLK_TCK) -/* PHY timout = 1 minute */ +/* PHY read/write delays in loop counts */ #define PIC32MZ_MIITIMEOUT (666666) @@ -231,8 +255,9 @@ /* Interrupts ***************************************************************/ -#define ETH_RXINTS (ETH_INT_RXOVFLW | ETH_INT_RXBUFNA | ETH_INT_RXDONE | ETH_INT_RXBUSE) -#define ETH_TXINTS (ETH_INT_TXABORT | ETH_INT_TXDONE | ETH_INT_TXBUSE) +#define ETH_RXINTS (ETH_INT_RXOVFLW | ETH_INT_RXBUFNA |\ + ETH_INT_RXDONE | ETH_INT_RXBUSE) +#define ETH_TXINTS (ETH_INT_TXABORT | ETH_INT_TXDONE | ETH_INT_TXBUSE) /* Misc. Helpers ***********************************************************/ @@ -241,6 +266,7 @@ #define BUF ((struct eth_hdr_s *)priv->pd_dev.d_buf) /* PHYs *********************************************************************/ + /* Select PHY-specific values. Add more PHYs as needed. */ #if defined(CONFIG_ETH0_PHY_KS8721) @@ -321,6 +347,22 @@ * Private Types ****************************************************************************/ +/* This union type forces the allocated size of RX descriptors to be the + * padded to a exact multiple of the Cortex-M7 D-Cache line size. + */ + +union pic32mz_txdesc_u +{ + uint8_t pad[DESC_PADSIZE]; + struct pic32mz_txdesc_s txdesc; +}; + +union pic32mz_rxdesc_u +{ + uint8_t pad[DESC_PADSIZE]; + struct pic32mz_rxdesc_s rxdesc; +}; + /* The pic32mz_driver_s encapsulates all state information for a single hardware * interface */ @@ -356,18 +398,23 @@ struct pic32mz_driver_s /* This holds the information visible to the NuttX network */ struct net_driver_s pd_dev; /* Interface understood by the network */ - - /* Descriptors and packet buffers */ - - struct pic32mz_rxdesc_s pd_rxdesc[CONFIG_PIC32MZ_ETH_NRXDESC]; - struct pic32mz_txdesc_s pd_txdesc[CONFIG_PIC32MZ_ETH_NTXDESC]; - uint8_t pd_buffers[PIC32MZ_NBUFFERS * PIC32MZ_ALIGNED_BUFSIZE]; }; /**************************************************************************** * Private Data ****************************************************************************/ +/* Descriptors and packet buffers */ + +union pic32mz_rxdesc_u g_rxdesc[CONFIG_PIC32MZ_ETH_NRXDESC] + __attribute__((aligned(PIC32MZ_DCACHE_LINESIZE))); + +union pic32mz_txdesc_u g_txdesc[CONFIG_PIC32MZ_ETH_NTXDESC] + __attribute__((aligned(PIC32MZ_DCACHE_LINESIZE))); + +uint8_t g_buffers[PIC32MZ_NBUFFERS * PIC32MZ_ALIGNED_BUFSIZE] + __attribute__((aligned(PIC32MZ_DCACHE_LINESIZE))); + /* Array of ethernet driver status structures */ static struct pic32mz_driver_s g_ethdrvr[CONFIG_PIC32MZ_NINTERFACES]; @@ -384,8 +431,8 @@ static void pic32mz_checkreg(uint32_t addr, uint32_t val, bool iswrite); static uint32_t pic32mz_getreg(uint32_t addr); static void pic32mz_putreg(uint32_t val, uint32_t addr); #else -# define pic32mz_getreg(addr) getreg32(addr) -# define pic32mz_putreg(val,addr) putreg32(val,addr) +# define pic32mz_getreg(addr) getreg32(addr) +# define pic32mz_putreg(val,addr) putreg32(val,addr) #endif /* Buffer and descriptor management */ @@ -394,8 +441,8 @@ static void pic32mz_putreg(uint32_t val, uint32_t addr); static void pic32mz_dumptxdesc(struct pic32mz_txdesc_s *txdesc, const char *msg); static void pic32mz_dumprxdesc(struct pic32mz_rxdesc_s *rxdesc, const char *msg); #else -# define pic32mz_dumptxdesc(txdesc,msg) -# define pic32mz_dumprxdesc(rxdesc,msg) +# define pic32mz_dumptxdesc(txdesc,msg) +# define pic32mz_dumprxdesc(rxdesc,msg) #endif static inline void pic32mz_bufferinit(struct pic32mz_driver_s *priv); @@ -673,16 +720,16 @@ static inline void pic32mz_bufferinit(struct pic32mz_driver_s *priv) uint8_t *buffer; int i; - for (i = 0, buffer = priv->pd_buffers; i < PIC32MZ_NBUFFERS; i++) - { - /* Add the buffer to the end of the list of free buffers */ + for (i = 0, buffer = g_buffers; i < PIC32MZ_NBUFFERS; i++) + { + /* Add the buffer to the end of the list of free buffers */ - sq_addlast((sq_entry_t *)buffer, &priv->pd_freebuffers); + sq_addlast((sq_entry_t *)buffer, &priv->pd_freebuffers); - /* Get the address of the next buffer */ + /* Get the address of the next buffer */ - buffer += PIC32MZ_ALIGNED_BUFSIZE; - } + buffer += PIC32MZ_ALIGNED_BUFSIZE; + } } /**************************************************************************** @@ -724,7 +771,7 @@ static void pic32mz_freebuffer(struct pic32mz_driver_s *priv, uint8_t *buffer) { /* Add the buffer to the end of the free buffer list */ - sq_addlast((sq_entry_t *)buffer, &priv->pd_freebuffers); + sq_addlast((sq_entry_t *)buffer, &priv->pd_freebuffers); } /**************************************************************************** @@ -749,14 +796,14 @@ static inline void pic32mz_txdescinit(struct pic32mz_driver_s *priv) int i; /* Assign a buffer to each TX descriptor. For now, just mark each TX - * descriptor as owned by softare andnot linked. + * descriptor as owned by softare and not linked. */ for (i = 0; i < CONFIG_PIC32MZ_ETH_NTXDESC; i++) { /* Point to the next entry */ - txdesc = &priv->pd_txdesc[i]; + txdesc = &g_txdesc[i].txdesc; /* Initialize the buffer. It is idle, owned by software and has * no buffer assigned to it. @@ -772,18 +819,24 @@ static inline void pic32mz_txdescinit(struct pic32mz_driver_s *priv) * creating a ring. */ - if (i == (CONFIG_PIC32MZ_ETH_NRXDESC-1)) + if (i == (CONFIG_PIC32MZ_ETH_NRXDESC - 1)) { - txdesc->nexted = PHYS_ADDR(priv->pd_txdesc); + txdesc->nexted = PHYS_ADDR(g_txdesc); } else { - txdesc->nexted = PHYS_ADDR(&priv->pd_txdesc[i+1]); + txdesc->nexted = PHYS_ADDR(&g_txdesc[i + 1]); } pic32mz_dumptxdesc(txdesc, "Initial"); } + /* Flush all of the initialized TX descriptors to physical memory */ + + up_flush_dcache((uintptr_t)g_txdesc, + (uintptr_t)g_txdesc + + CONFIG_PIC32MZ_ETH_NTXDESC * sizeof(union pic32mz_txdesc_u)); + /* Position the Tx index to the first descriptor in the ring */ priv->pd_txnext = 0; @@ -792,7 +845,7 @@ static inline void pic32mz_txdescinit(struct pic32mz_driver_s *priv) * the TX descriptors list. */ - pic32mz_putreg(PHYS_ADDR(priv->pd_txdesc), PIC32MZ_ETH_TXST); + pic32mz_putreg(PHYS_ADDR(g_txdesc), PIC32MZ_ETH_TXST); } /**************************************************************************** @@ -827,7 +880,7 @@ static inline void pic32mz_rxdescinit(struct pic32mz_driver_s *priv) { /* Point to the next entry */ - rxdesc = &priv->pd_rxdesc[i]; + rxdesc = &g_rxdesc[i].rxdesc; /* Initialize the descriptor. Assign it a buffer and make it ready * for reception. @@ -836,30 +889,36 @@ static inline void pic32mz_rxdescinit(struct pic32mz_driver_s *priv) rxdesc->rsv1 = 0; rxdesc->rsv2 = 0; rxdesc->address = PHYS_ADDR(pic32mz_allocbuffer(priv)); - rxdesc->status = RXDESC_STATUS_EOWN | TXDESC_STATUS_NPV; + rxdesc->status = RXDESC_STATUS_EOWN | RXDESC_STATUS_NPV; /* Set the NEXTED pointer. If this is the last descriptor in the * list, then set the NEXTED pointer back to the first entry, * creating a ring. */ - if (i == (CONFIG_PIC32MZ_ETH_NRXDESC-1)) + if (i == (CONFIG_PIC32MZ_ETH_NRXDESC - 1)) { - rxdesc->nexted = PHYS_ADDR(priv->pd_rxdesc); + rxdesc->nexted = PHYS_ADDR(g_rxdesc); } else { - rxdesc->nexted = PHYS_ADDR(&priv->pd_rxdesc[i+1]); + rxdesc->nexted = PHYS_ADDR(&g_rxdesc[i + 1]); } pic32mz_dumprxdesc(rxdesc, "Initial"); } + /* Flush all of the initialized RX descriptors to physical memory */ + + up_flush_dcache((uintptr_t)g_rxdesc, + (uintptr_t)g_rxdesc + + CONFIG_PIC32MZ_ETH_NRXDESC * sizeof(union pic32mz_rxdesc_u)); + /* Update the ETHRXST register with the physical address of the head of the * RX descriptors list. */ - pic32mz_putreg(PHYS_ADDR(priv->pd_rxdesc), PIC32MZ_ETH_RXST); + pic32mz_putreg(PHYS_ADDR(g_rxdesc), PIC32MZ_ETH_RXST); } /**************************************************************************** @@ -883,7 +942,15 @@ static inline struct pic32mz_txdesc_s *pic32mz_txdesc(struct pic32mz_driver_s *p /* Get a reference to the next Tx descriptor in the ring */ - txdesc = &priv->pd_txdesc[priv->pd_txnext]; + txdesc = &g_txdesc[priv->pd_txnext].txdesc; + + /* Force re-reading of the TX descriptor from physical memory. + * The descriptor may have been owned by the Ethernet controller. + * Cache data would be stale in this case. + */ + + up_invalidate_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(union pic32mz_txdesc_u)); /* Check if the EOWN bit is cleared. If it is, this descriptor is now under * software control and the message has been transmitted. @@ -965,8 +1032,13 @@ static inline void pic32mz_rxreturn(struct pic32mz_rxdesc_s *rxdesc) { rxdesc->rsv1 = 0; rxdesc->rsv2 = 0; - rxdesc->status = RXDESC_STATUS_EOWN | TXDESC_STATUS_NPV; + rxdesc->status = RXDESC_STATUS_EOWN | RXDESC_STATUS_NPV; pic32mz_dumprxdesc(rxdesc, "Returned to hardware"); + + /* Flush the content of the modified TX descriptor into physical memory. */ + + up_flush_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(union pic32mz_rxdesc_u)); } /**************************************************************************** @@ -1003,7 +1075,13 @@ static struct pic32mz_rxdesc_s *pic32mz_rxdesc(struct pic32mz_driver_s *priv) { /* Check if software owns this descriptor */ - rxdesc = &priv->pd_rxdesc[i]; + rxdesc = &g_rxdesc[i].rxdesc; + + /* Forces the first RX descriptor to be re-read from physical memory */ + + up_invalidate_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(union pic32mz_rxdesc_u)); + if ((rxdesc->status & RXDESC_STATUS_EOWN) == 0) { /* Yes.. return a pointer to the descriptor */ @@ -1055,6 +1133,11 @@ static int pic32mz_transmit(struct pic32mz_driver_s *priv) NETDEV_TXPACKETS(&priv->pd_dev); pic32mz_dumppacket("Transmit packet", priv->pd_dev.d_buf, priv->pd_dev.d_len); + /* Flush the content of the TX buffer into physical memory */ + + up_flush_dcache((uintptr_t)priv->pd_dev.d_buf, + (uintptr_t)priv->pd_dev.d_buf + PIC32MZ_ALIGNED_BUFSIZE); + /* In order to transmit a message: * * The SOP, EOP, DATA_BUFFER_ADDRESS and BYTE_COUNT will be updated when a @@ -1084,7 +1167,7 @@ static int pic32mz_transmit(struct pic32mz_driver_s *priv) * contained in the buffer. */ - status = ((uint32_t)priv->pd_dev.d_len << TXDESC_STATUS_BYTECOUNT_SHIFT); + status = ((uint32_t)priv->pd_dev.d_len << TXDESC_STATUS_BYTECOUNT_SHIFT); priv->pd_dev.d_len = 0; /* Set EOWN = 1 to indicate that the packet belongs to Ethernet and set both @@ -1097,6 +1180,11 @@ static int pic32mz_transmit(struct pic32mz_driver_s *priv) txdesc->status = status; pic32mz_dumptxdesc(txdesc, "After transmit setup"); + /* Flush the content of the modified TX descriptor into physical memory */ + + up_flush_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(union pic32mz_txdesc_u)); + /* Update the index to the next descriptor to use in the Tx ring */ pic32mz_txnext(priv); @@ -1256,10 +1344,10 @@ static void pic32mz_poll(struct pic32mz_driver_s *priv) pic32mz_freebuffer(priv, priv->pd_dev.d_buf); priv->pd_dev.d_buf = NULL; } + priv->pd_polling = false; } } - } /**************************************************************************** @@ -1302,6 +1390,7 @@ static void pic32mz_timerpoll(struct pic32mz_driver_s *priv) pic32mz_freebuffer(priv, priv->pd_dev.d_buf); priv->pd_dev.d_buf = NULL; } + priv->pd_polling = false; } } @@ -1340,19 +1429,19 @@ static void pic32mz_response(struct pic32mz_driver_s *priv) txdesc = pic32mz_txdesc(priv); if (txdesc != NULL) { - /* Yes.. queue the packet now. */ + /* Yes.. queue the packet now. */ - pic32mz_transmit(priv); + pic32mz_transmit(priv); } else { - /* No.. mark the Tx as pending and halt further Rx interrupts */ + /* No.. mark the Tx as pending and halt further Rx interrupts */ - DEBUGASSERT((priv->pd_inten & ETH_INT_TXDONE) != 0); + DEBUGASSERT((priv->pd_inten & ETH_INT_TXDONE) != 0); - priv->pd_txpending = true; - priv->pd_inten &= ~ETH_RXINTS; - pic32mz_putreg(priv->pd_inten, PIC32MZ_ETH_IEN); + priv->pd_txpending = true; + priv->pd_inten &= ~ETH_RXINTS; + pic32mz_putreg(priv->pd_inten, PIC32MZ_ETH_IEN); } } @@ -1397,16 +1486,18 @@ static void pic32mz_rxdone(struct pic32mz_driver_s *priv) return; } + pic32mz_dumprxdesc(rxdesc, "RX Complete"); + /* Get the packet length */ + + priv->pd_dev.d_len = (rxdesc->rsv2 & RXDESC_RSV2_BYTECOUNT_MASK) >> + RXDESC_RSV2_BYTECOUNT_SHIFT; + /* Update statistics */ NETDEV_RXPACKETS(&priv->pd_dev); - /* Get the packet length */ - - priv->pd_dev.d_len = (rxdesc->rsv2 & RXDESC_RSV2_BYTECOUNT_MASK) >> RXDESC_RSV2_BYTECOUNT_SHIFT; - /* Check for errors */ if ((rxdesc->rsv2 & RXDESC_RSV2_OK) == 0) @@ -1448,6 +1539,15 @@ static void pic32mz_rxdone(struct pic32mz_driver_s *priv) /* Get the Rx buffer address from the Rx descriptor */ priv->pd_dev.d_buf = (uint8_t *)VIRT_ADDR(rxdesc->address); + + /* Force the completed RX DMA buffer to be re-read from + * physical memory. + */ + + up_invalidate_dcache((uintptr_t)priv->pd_dev.d_buf, + (uintptr_t)priv->pd_dev.d_buf + + PIC32MZ_ALIGNED_BUFSIZE); + DEBUGASSERT(priv->pd_dev.d_buf != NULL); /* Replace the buffer in the RX descriptor with a new one */ @@ -1509,7 +1609,7 @@ static void pic32mz_rxdone(struct pic32mz_driver_s *priv) /* And send the packet */ - pic32mz_response(priv); + pic32mz_response(priv); } } else @@ -1530,7 +1630,7 @@ static void pic32mz_rxdone(struct pic32mz_driver_s *priv) */ if (priv->pd_dev.d_len > 0) - { + { /* Update the Ethernet header with the correct MAC address */ #ifdef CONFIG_NET_IPv4 @@ -1639,7 +1739,15 @@ static void pic32mz_txdone(struct pic32mz_driver_s *priv) for (i = 0; i < CONFIG_PIC32MZ_ETH_NTXDESC; i++) { - txdesc = &priv->pd_txdesc[i]; + txdesc = &g_txdesc[i].txdesc; + + /* Force re-reading of the TX descriptor from physical memory. + * The descriptor may have been owned by the Ethernet controller. + * Cache data would be stale in this case. + */ + + up_invalidate_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(union pic32mz_txdesc_u)); /* Check if software owns this descriptor */ @@ -1661,7 +1769,13 @@ static void pic32mz_txdone(struct pic32mz_driver_s *priv) txdesc->tsv1 = 0; txdesc->tsv2 = 0; txdesc->status = TXDESC_STATUS_SOWN | TXDESC_STATUS_NPV; + pic32mz_dumptxdesc(txdesc, "TX buffer freed"); + + /* Flush the content of the modified TX descriptor. */ + + up_flush_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(union pic32mz_txdesc_u)); } } } @@ -1729,10 +1843,12 @@ static void pic32mz_interrupt_work(void *arg) pic32mz_putreg(status, PIC32MZ_ETH_IRQCLR); /* Handle each pending interrupt **************************************/ + /* Receive Errors *****************************************************/ + /* RXOVFLW: Receive FIFO Over Flow Error. RXOVFLW is set by the RXBM * Logic for an RX FIFO Overflow condition. It is cleared by either a - * Reset or CPU write of a ‘1’ to the CLR register. + * Reset or CPU write of a '1' to the CLR register. */ if ((status & ETH_INT_RXOVFLW) != 0) @@ -1743,7 +1859,7 @@ static void pic32mz_interrupt_work(void *arg) /* RXBUFNA: Receive Buffer Not Available Interrupt. This bit is set by * a RX Buffer Descriptor Overrun condition. It is cleared by either a - * Reset or a CPU write of a ‘1’ to the CLR register. + * Reset or a CPU write of a '1' to the CLR register. */ if ((status & ETH_INT_RXBUFNA) != 0) @@ -1754,7 +1870,7 @@ static void pic32mz_interrupt_work(void *arg) /* RXBUSE: Receive BVCI Bus Error Interrupt. This bit is set when the * RX DMA encounters a BVCI Bus error during a memory access. It is - * cleared by either a Reset or CPU write of a ‘1’ to the CLR register. + * cleared by either a Reset or CPU write of a '1' to the CLR register. */ if ((status & ETH_INT_RXBUSE) != 0) @@ -1764,20 +1880,21 @@ static void pic32mz_interrupt_work(void *arg) } /* Receive Normal Events **********************************************/ + /* RXACT: Receive Activity Interrupt. This bit is set whenever RX packet * data is stored in the RXBM FIFO. It is cleared by either a Reset or CPU - * write of a ‘1’ to the CLR register. + * write of a '1' to the CLR register. */ /* PKTPEND: Packet Pending Interrupt. This bit is set when the BUFCNT - * counter has a value other than ‘0’. It is cleared by either a Reset + * counter has a value other than '0'. It is cleared by either a Reset * or by writing the BUFCDEC bit to decrement the BUFCNT counter. - * Writing a ‘0’ or a ‘1’ has no effect. + * Writing a '0' or a '1' has no effect. */ /* RXDONE: Receive Done Interrupt. This bit is set whenever an RX packet * is successfully received. It is cleared by either a Reset or CPU - * write of a ‘1’ to the CLR register. + * write of a '1' to the CLR register. */ if ((status & ETH_INT_RXDONE) != 0) @@ -1788,6 +1905,7 @@ static void pic32mz_interrupt_work(void *arg) } /* Transmit Errors ****************************************************/ + /* TXABORT: Transmit Abort Condition Interrupt. This bit is set when * the MAC aborts the transmission of a TX packet for one of the * following reasons: @@ -1796,7 +1914,7 @@ static void pic32mz_interrupt_work(void *arg) * - Excessive defer abort * - Late collision abort * - Excessive collisions abort - * This bit is cleared by either a Reset or CPU write of a ‘1’ to the + * This bit is cleared by either a Reset or CPU write of a '1' to the * CLR register. */ @@ -1808,7 +1926,7 @@ static void pic32mz_interrupt_work(void *arg) /* TXBUSE: Transmit BVCI Bus Error Interrupt. This bit is set when the * TX DMA encounters a BVCI Bus error during a memory access. It is - * cleared by either a Reset or CPU write of a ‘1’ to the CLR register. + * cleared by either a Reset or CPU write of a '1' to the CLR register. */ if ((status & ETH_INT_TXBUSE) != 0) @@ -1820,7 +1938,7 @@ static void pic32mz_interrupt_work(void *arg) /* TXDONE: Transmit Done Interrupt. This bit is set when the currently * transmitted TX packet completes transmission, and the Transmit * Status Vector is loaded into the first descriptor used for the - * packet. It is cleared by either a Reset or CPU write of a ‘1’ to + * packet. It is cleared by either a Reset or CPU write of a '1' to * the CLR register. */ @@ -1834,18 +1952,19 @@ static void pic32mz_interrupt_work(void *arg) } /* Watermark Events ***************************************************/ + /* EWMARK: Empty Watermark Interrupt. This bit is set when the RX * Descriptor Buffer Count is less than or equal to the value in the * RXEWM bit (ETHRXWM:0-7) value. It is cleared by BUFCNT bit - * (ETHSTAT:16-23) being incremented by hardware. Writing a ‘0’ or a ‘1’ + * (ETHSTAT:16-23) being incremented by hardware. Writing a '0' or a '1' * has no effect. */ /* FWMARK: Full Watermark Interrupt. This bit is set when the RX * escriptor Buffer Count is greater than or equal to the value in the * RXFWM bit (ETHRXWM:16-23) field. It is cleared by writing the BUFCDEC - * (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a ‘0’ or a - * ‘1’ has no effect. + * (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a '0' or a + * '1' has no effect. */ } @@ -2112,6 +2231,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) pic32mz_ethreset(priv); /* MAC Initialization *****************************************************/ + /* Configuration: * - Use the configuration fuse setting FETHIO bit (DEVCFG3:25) to detect * the alternate/default I/O configuration @@ -2162,7 +2282,8 @@ static int pic32mz_ifup(struct net_driver_s *dev) #if CONFIG_PIC32MZ_FMIIEN == 0 pic32mz_putreg(EMAC1_SUPP_RESETRMII, PIC32MZ_EMAC1_SUPPSET); - pic32mz_putreg((EMAC1_SUPP_RESETRMII | EMAC1_SUPP_SPEEDRMII), PIC32MZ_EMAC1_SUPPCLR); + pic32mz_putreg((EMAC1_SUPP_RESETRMII | EMAC1_SUPP_SPEEDRMII), + PIC32MZ_EMAC1_SUPPCLR); #endif /* Issue an MIIM block reset, by setting the RESETMGMT (EMAC1MCFG:15) bit, @@ -2188,6 +2309,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) pic32mz_putreg(regval, PIC32MZ_EMAC1_MCFG); /* PHY Initialization *****************************************************/ + /* Initialize the PHY and wait for the link to be established */ ret = pic32mz_phyinit(priv); @@ -2198,6 +2320,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) } /* MAC Configuration ******************************************************/ + /* Set other misc configuration-related registers to default values */ pic32mz_putreg(0, PIC32MZ_EMAC1_CFG2); @@ -2219,10 +2342,11 @@ static int pic32mz_ifup(struct net_driver_s *dev) */ /* Program EMAC1IPGT with the back-to-back inter-packet gap */ + /* Use EMAC1IPGR for setting the non back-to-back inter-packet gap */ - pic32mz_putreg(((12 << EMAC1_IPGR_GAP1_SHIFT) | (12 << EMAC1_IPGR_GAP2_SHIFT)), - PIC32MZ_EMAC1_IPGR); + pic32mz_putreg(((12 << EMAC1_IPGR_GAP1_SHIFT) | (12 << EMAC1_IPGR_GAP2_SHIFT)), + PIC32MZ_EMAC1_IPGR); /* Set the collision window and the maximum number of retransmissions in * EMAC1CLRT. @@ -2240,7 +2364,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) pic32mz_putreg(CONFIG_NET_ETH_PKTSIZE, PIC32MZ_EMAC1_MAXF); - /* Configure the MAC station address in the EMAC1SA0, EMAC1SA1 and + /* Configure the MAC station address in the EMAC1SA0, EMAC1SA1 and * EMAC1SA2 registers (these registers are loaded at reset from the * factory preprogrammed station address). */ @@ -2277,6 +2401,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) #endif /* Continue Ethernet Controller Initialization ****************************/ + /* If planning to turn on the flow control, update the PTV value * (ETHCON1:16-31). */ @@ -2310,7 +2435,7 @@ static int pic32mz_ifup(struct net_driver_s *dev) pic32mz_putreg(ETH_CON2_RXBUFSZ(CONFIG_NET_ETH_PKTSIZE), PIC32MZ_ETH_CON2); - /* Reset state varialbes */ + /* Reset state variables */ priv->pd_polling = false; priv->pd_txpending = false; @@ -2661,9 +2786,15 @@ static void pic32mz_phywrite(uint8_t phyaddr, uint8_t regaddr, uint16_t phydata) pic32mz_putreg((uint32_t)phydata, PIC32MZ_EMAC1_MWTD); - /* Two clock cycles until busy is set from the write operation */ + /* Sixteen clock cycles until busy is set from the write operation */ - __asm__ __volatile__ ("nop; nop;"); + __asm__ __volatile__ + ( + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + ); } #endif @@ -2701,16 +2832,25 @@ static uint16_t pic32mz_phyread(uint8_t phyaddr, uint8_t regaddr) /* Set up to read */ - pic32mz_putreg(EMAC1_MCMD_READ, PIC32MZ_EMAC1_MCMD); + pic32mz_putreg(EMAC1_MCMD_READ, PIC32MZ_EMAC1_MCMDSET); - /* Four clock cycles until busy is set from the write operation */ + /* Sixteen clock cycles until busy is set from the write operation */ - __asm__ __volatile__ ("nop; nop; nop; nop;"); + __asm__ __volatile__ + ( + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + "nop; nop; nop; nop;" + ); /* Wait for the PHY command to complete */ pic32mz_phybusywait(); - pic32mz_putreg(0, PIC32MZ_EMAC1_MCMD); + + /* Clear the read bit */ + + pic32mz_putreg(EMAC1_MCMD_READ, PIC32MZ_EMAC1_MCMDCLR); /* Return the PHY register data */ @@ -2927,6 +3067,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) * control (using the RBR register). For RMII mode, it is required to use the * strap option, since it requires a 50 MHz clock instead of the normal 25 MHz. */ + #endif #else @@ -2968,13 +3109,15 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) * PHY address. */ - phyreg = (unsigned int)pic32mz_phyread(phyaddr, MII_PHYID1); - ninfo("Addr: %d PHY ID1: %04x EXPECT: %04x\n", phyaddr, phyreg, PIC32MZ_PHYID1); + phyreg = (unsigned int)pic32mz_phyread(phyaddr, MII_PHYID1); + ninfo("Addr: %d PHY ID1: %04x EXPECT: %04x\n", + phyaddr, phyreg, PIC32MZ_PHYID1); - if (phyreg == PIC32MZ_PHYID1) + if (phyreg == PIC32MZ_PHYID1) { phyreg = pic32mz_phyread(phyaddr, MII_PHYID2); - ninfo("Addr: %d PHY ID2: %04x EXPECT: %04x\n", phyaddr, phyreg, PIC32MZ_PHYID2); + ninfo("Addr: %d PHY ID2: %04x EXPECT: %04x\n", + phyaddr, phyreg, PIC32MZ_PHYID2); if (phyreg == PIC32MZ_PHYID2) { @@ -3121,7 +3264,8 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) nerr("ERROR: Unrecognized mode: %04x\n", phyreg); return -ENODEV; } -#elif defined(CONFIG_ETH0_PHY_LAN8720) || defined(CONFIG_ETH0_PHY_LAN8740) || defined(CONFIG_ETH0_PHY_LAN8740A) +#elif defined(CONFIG_ETH0_PHY_LAN8720) || defined(CONFIG_ETH0_PHY_LAN8740) ||\ + defined(CONFIG_ETH0_PHY_LAN8740A) { uint16_t advertise; uint16_t lpa; @@ -3141,7 +3285,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) /* Check for 100BASETX half duplex */ else if ((advertise & MII_ADVERTISE_100BASETXHALF) != 0 && - (lpa & MII_LPA_100BASETXHALF) != 0) + (lpa & MII_LPA_100BASETXHALF) != 0) { priv->pd_mode = PIC32MZ_100BASET_HD; } @@ -3149,7 +3293,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) /* Check for 10BASETX full duplex */ else if ((advertise & MII_ADVERTISE_10BASETXFULL) != 0 && - (lpa & MII_LPA_10BASETXFULL) != 0) + (lpa & MII_LPA_10BASETXFULL) != 0) { priv->pd_mode = PIC32MZ_10BASET_FD; } @@ -3157,7 +3301,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) /* Check for 10BASETX half duplex */ else if ((advertise & MII_ADVERTISE_10BASETXHALF) != 0 && - (lpa & MII_LPA_10BASETXHALF) != 0) + (lpa & MII_LPA_10BASETXHALF) != 0) { priv->pd_mode = PIC32MZ_10BASET_HD; } @@ -3172,8 +3316,10 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv) #endif ninfo("%dBase-T %s duplex\n", - (priv->pd_mode & PIC32MZ_SPEED_MASK) == PIC32MZ_SPEED_100 ? 100 : 10, - (priv->pd_mode & PIC32MZ_DUPLEX_MASK) == PIC32MZ_DUPLEX_FULL ?"full" : "half"); + (priv->pd_mode & PIC32MZ_SPEED_MASK) == + PIC32MZ_SPEED_100 ? 100 : 10, + (priv->pd_mode & PIC32MZ_DUPLEX_MASK) == + PIC32MZ_DUPLEX_FULL ?"full" : "half"); /* Disable auto-configuration. Set the fixed speed/duplex mode. * (probably more than little redundant). @@ -3275,6 +3421,7 @@ static void pic32mz_ethreset(struct pic32mz_driver_s *priv) flags = enter_critical_section(); /* Ethernet Controller Initialization *************************************/ + /* Disable Ethernet interrupts in the EVIC */ #if CONFIG_PIC32MZ_NINTERFACES > 1 @@ -3323,6 +3470,7 @@ static void pic32mz_ethreset(struct pic32mz_driver_s *priv) pic32mz_putreg(0xffffffff, PIC32MZ_ETH_RXSTCLR); /* MAC Initialization *****************************************************/ + /* Put the MAC into the reset state */ pic32mz_putreg((EMAC1_CFG1_TXRST | EMAC1_CFG1_MCSTXRST | EMAC1_CFG1_RXRST | @@ -3381,10 +3529,10 @@ static inline int pic32mz_ethinitialize(int intf) priv->pd_dev.d_private = (void *)priv; /* Used to recover private state from dev */ #if CONFIG_PIC32MZ_NINTERFACES > 1 -# error "A mechanism to associate base address an IRQ with an interface is needed" - priv->pd_base = ??; /* Ethernet controller base address */ - priv->pd_irq = ??; /* Ethernet controller IRQ vector number */ - priv->pd_irqsrc = ??; /* Ethernet controller IRQ source number */ +# error "A mechanism to associate base address an IRQ with an interface is needed" + priv->pd_base = ; /* Ethernet controller base address */ + priv->pd_irq = ; /* Ethernet controller IRQ vector number */ + priv->pd_irqsrc = ; /* Ethernet controller IRQ source number */ #endif /* Create a watchdog for timing polling for and timing of transmissions */ @@ -3393,6 +3541,7 @@ static inline int pic32mz_ethinitialize(int intf) priv->pd_txtimeout = wd_create(); /* Create TX timeout timer */ /* Configure Ethernet peripheral pin selections */ + /* Controlled by DEVCFG FMIIEN and FETHIO settings */ /* Reset the Ethernet controller and leave in the ifdown state. The