arch/mips/src/pic32mz/pic32mz-ethernet.c: Clean/invalidate descriptors and buffers when needed to account for an enabled cache.

This commit is contained in:
Ouss4 2019-11-23 09:28:14 -06:00 committed by Gregory Nutt
parent bd45193a79
commit 4e3e9fabc7

View File

@ -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