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:
parent
bd45193a79
commit
4e3e9fabc7
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user