arch/arm/src/sama5/sam_gmac: Prevent txtimeout from always firing and fix txbuffer leak during high-volume sends
This commit is contained in:
parent
8ee6be0780
commit
cdc61a08e0
@ -1,4 +1,4 @@
|
|||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* arch/arm/src/sama5/hardware/sam_gmac.h
|
* arch/arm/src/sama5/hardware/sam_gmac.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||||
@ -31,22 +31,23 @@
|
|||||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_GMAC_H
|
#ifndef __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_GMAC_H
|
||||||
#define __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_GMAC_H
|
#define __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_GMAC_H
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Included Files
|
* Included Files
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include "hardware/sam_memorymap.h"
|
#include "hardware/sam_memorymap.h"
|
||||||
|
|
||||||
/************************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
/* GMAC Register Offsets ************************************************************/
|
|
||||||
|
/* GMAC Register Offsets ****************************************************/
|
||||||
|
|
||||||
#define SAM_GMAC_NCR_OFFSET 0x0000 /* Network Control Register */
|
#define SAM_GMAC_NCR_OFFSET 0x0000 /* Network Control Register */
|
||||||
#define SAM_GMAC_NCFGR_OFFSET 0x0004 /* Network Configuration Register */
|
#define SAM_GMAC_NCFGR_OFFSET 0x0004 /* Network Configuration Register */
|
||||||
@ -243,7 +244,7 @@
|
|||||||
#define SAM_GMAC_IMRPQ5_OFFSET 0x654 /* Interrupt Mask Register Priority Queue 5 */
|
#define SAM_GMAC_IMRPQ5_OFFSET 0x654 /* Interrupt Mask Register Priority Queue 5 */
|
||||||
#define SAM_GMAC_IMRPQ6_OFFSET 0x658 /* Interrupt Mask Register Priority Queue 6 */
|
#define SAM_GMAC_IMRPQ6_OFFSET 0x658 /* Interrupt Mask Register Priority Queue 6 */
|
||||||
|
|
||||||
/* GMAC Register Addresses *********************************************************/
|
/* GMAC Register Addresses **************************************************/
|
||||||
|
|
||||||
#define SAM_GMAC_NCR (SAM_GMAC_VBASE+SAM_GMAC_NCR_OFFSET)
|
#define SAM_GMAC_NCR (SAM_GMAC_VBASE+SAM_GMAC_NCR_OFFSET)
|
||||||
#define SAM_GMAC_NCFGR (SAM_GMAC_VBASE+SAM_GMAC_NCFGR_OFFSET)
|
#define SAM_GMAC_NCFGR (SAM_GMAC_VBASE+SAM_GMAC_NCFGR_OFFSET)
|
||||||
@ -436,7 +437,7 @@
|
|||||||
#define SAM_GMAC_IMRPQ5 (SAM_GMAC_VBASE+SAM_GMAC_IMRPQ5_OFFSET)
|
#define SAM_GMAC_IMRPQ5 (SAM_GMAC_VBASE+SAM_GMAC_IMRPQ5_OFFSET)
|
||||||
#define SAM_GMAC_IMRPQ6 (SAM_GMAC_VBASE+SAM_GMAC_IMRPQ6_OFFSET)
|
#define SAM_GMAC_IMRPQ6 (SAM_GMAC_VBASE+SAM_GMAC_IMRPQ6_OFFSET)
|
||||||
|
|
||||||
/* GMAC Register Bit Definitions ***************************************************/
|
/* GMAC Register Bit Definitions ********************************************/
|
||||||
|
|
||||||
/* Network Control Register */
|
/* Network Control Register */
|
||||||
|
|
||||||
@ -871,13 +872,13 @@
|
|||||||
*
|
*
|
||||||
* Use these definitions:
|
* Use these definitions:
|
||||||
*
|
*
|
||||||
* GMAC_INT_RCOMP Bit 1: Receive Complete
|
* GMAC_INT_RCOMP Bit 1: Receive Complete
|
||||||
* GMAC_INT_RXUBR Bit 2: Receive Used Bit Read
|
* GMAC_INT_RXUBR Bit 2: Receive Used Bit Read
|
||||||
* GMAC_INT_RLEX Bit 5: Retry Limit Exceeded or Late Collision
|
* GMAC_INT_RLEX Bit 5: Retry Limit Exceeded or Late Collision
|
||||||
* GMAC_INT_TFC Bit 6: Transmit Frame Corruption due to AHB error
|
* GMAC_INT_TFC Bit 6: Transmit Frame Corruption due to AHB error
|
||||||
* GMAC_INT_TCOMP Bit 7: Transmit Complete
|
* GMAC_INT_TCOMP Bit 7: Transmit Complete
|
||||||
* GMAC_INT_ROVR Bit 10: Receive Overrun
|
* GMAC_INT_ROVR Bit 10: Receive Overrun
|
||||||
* GMAC_INT_HRESP Bit 11: HRESP not OK
|
* GMAC_INT_HRESP Bit 11: HRESP not OK
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Transmit Buffer Queue Base Address Priority Queue 0-6 */
|
/* Transmit Buffer Queue Base Address Priority Queue 0-6 */
|
||||||
@ -916,7 +917,7 @@
|
|||||||
# define GMAC_ST2RPQ0_VLANP(n) ((uint32_t)(n) << GMAC_ST2RPQ0_VLANP_SHIFT)
|
# define GMAC_ST2RPQ0_VLANP(n) ((uint32_t)(n) << GMAC_ST2RPQ0_VLANP_SHIFT)
|
||||||
#define GMAC_ST2RPQ0_VLANE (1 << 8) /* Bit 8: VLAN Enable */
|
#define GMAC_ST2RPQ0_VLANE (1 << 8) /* Bit 8: VLAN Enable */
|
||||||
|
|
||||||
/* Descriptors **********************************************************************/
|
/* Descriptors **************************************************************/
|
||||||
|
|
||||||
/* Receive buffer descriptor: Address word */
|
/* Receive buffer descriptor: Address word */
|
||||||
|
|
||||||
@ -992,9 +993,12 @@
|
|||||||
#define GMACTXD_STA_WRAP (1 << 30) /* Bit 30: Last descriptor in descriptor list */
|
#define GMACTXD_STA_WRAP (1 << 30) /* Bit 30: Last descriptor in descriptor list */
|
||||||
#define GMACTXD_STA_USED (1 << 31) /* Bit 31: Zero for the GMAC to read from buffer */
|
#define GMACTXD_STA_USED (1 << 31) /* Bit 31: Zero for the GMAC to read from buffer */
|
||||||
|
|
||||||
/************************************************************************************
|
#define GMAC_STATUS_LENGTH_MASK 0x3fffu
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
************************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Receive buffer descriptor */
|
/* Receive buffer descriptor */
|
||||||
|
|
||||||
struct gmac_rxdesc_s
|
struct gmac_rxdesc_s
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Configuration ************************************************************/
|
/* Configuration ************************************************************/
|
||||||
|
|
||||||
/* If processing is not done at the interrupt level, then work queue support
|
/* If processing is not done at the interrupt level, then work queue support
|
||||||
@ -168,6 +169,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Timing *******************************************************************/
|
/* Timing *******************************************************************/
|
||||||
|
|
||||||
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
|
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
|
||||||
* second
|
* second
|
||||||
*/
|
*/
|
||||||
@ -183,6 +185,7 @@
|
|||||||
#define PHY_RETRY_MAX 300000
|
#define PHY_RETRY_MAX 300000
|
||||||
|
|
||||||
/* Helpers ******************************************************************/
|
/* Helpers ******************************************************************/
|
||||||
|
|
||||||
/* This is a helper pointer for accessing the contents of the GMAC
|
/* This is a helper pointer for accessing the contents of the GMAC
|
||||||
* header
|
* header
|
||||||
*/
|
*/
|
||||||
@ -250,6 +253,7 @@ static uint8_t g_pktbuf[MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE];
|
|||||||
|
|
||||||
#ifdef CONFIG_SAMA5_GMAC_PREALLOCATE
|
#ifdef CONFIG_SAMA5_GMAC_PREALLOCATE
|
||||||
/* Preallocated data */
|
/* Preallocated data */
|
||||||
|
|
||||||
/* TX descriptors list */
|
/* TX descriptors list */
|
||||||
|
|
||||||
static struct gmac_txdesc_s g_txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS]
|
static struct gmac_txdesc_s g_txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS]
|
||||||
@ -262,9 +266,9 @@ static struct gmac_rxdesc_s g_rxdesc[CONFIG_SAMA5_GMAC_NRXBUFFERS]
|
|||||||
|
|
||||||
/* Transmit Buffers
|
/* Transmit Buffers
|
||||||
*
|
*
|
||||||
* Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K Boundaries.
|
* Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K
|
||||||
* Receive buffer manager writes are burst of 2 words => 3 lsb bits of the address
|
* Boundaries. Receive buffer manager writes are burst of
|
||||||
* shall be set to 0
|
* 2 words => 3 lsb bits of the address shall be set to 0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint8_t g_txbuffer[CONFIG_SAMA5_GMAC_NTXBUFFERS * GMAC_TX_UNITSIZE]
|
static uint8_t g_txbuffer[CONFIG_SAMA5_GMAC_NTXBUFFERS * GMAC_TX_UNITSIZE]
|
||||||
@ -279,13 +283,15 @@ static uint8_t g_rxbuffer[CONFIG_SAMA5_GMAC_NRXBUFFERS * GMAC_RX_UNITSIZE]
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Function Prototypes
|
* Private Function Prototypes
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Register operations ******************************************************/
|
/* Register operations ******************************************************/
|
||||||
|
|
||||||
#if defined(CONFIG_SAMA5_GMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES)
|
#if defined(CONFIG_SAMA5_GMAC_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES)
|
||||||
static bool sam_checkreg(struct sam_gmac_s *priv, bool wr,
|
static bool sam_checkreg(struct sam_gmac_s *priv, bool wr,
|
||||||
uint32_t regval, uintptr_t address);
|
uint32_t regval, uintptr_t address);
|
||||||
static uint32_t sam_getreg(struct sam_gmac_s *priv, uintptr_t addr);
|
static uint32_t sam_getreg(struct sam_gmac_s *priv, uintptr_t addr);
|
||||||
static void sam_putreg(struct sam_gmac_s *priv, uintptr_t addr, uint32_t val);
|
static void sam_putreg(struct sam_gmac_s *priv, uintptr_t addr,
|
||||||
|
uint32_t val);
|
||||||
#else
|
#else
|
||||||
# define sam_getreg(priv,addr) getreg32(addr)
|
# define sam_getreg(priv,addr) getreg32(addr)
|
||||||
# define sam_putreg(priv,addr,val) putreg32(val,addr)
|
# define sam_putreg(priv,addr,val) putreg32(val,addr)
|
||||||
@ -383,6 +389,7 @@ static int sam_gmac_configure(struct sam_gmac_s *priv);
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_checkreg
|
* Name: sam_checkreg
|
||||||
*
|
*
|
||||||
@ -526,7 +533,7 @@ static uint16_t sam_txfree(struct sam_gmac_s *priv)
|
|||||||
* the configured size minus 1.
|
* the configured size minus 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return (CONFIG_SAMA5_GMAC_NTXBUFFERS-1) - sam_txinuse(priv);
|
return (CONFIG_SAMA5_GMAC_NTXBUFFERS - 1) - sam_txinuse(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -708,7 +715,14 @@ static int sam_transmit(struct sam_gmac_s *priv)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup/Copy data to transmission buffer */
|
/* Mark buffer as used temporarily so DMA doesn't operate on it */
|
||||||
|
|
||||||
|
status = GMACTXD_STA_USED | GMACTXD_STA_LAST;
|
||||||
|
txdesc->status = status;
|
||||||
|
up_clean_dcache((uint32_t)txdesc,
|
||||||
|
(uint32_t)txdesc + sizeof(struct gmac_txdesc_s));
|
||||||
|
|
||||||
|
/* Setup/Copy data to transmition buffer */
|
||||||
|
|
||||||
if (dev->d_len > 0)
|
if (dev->d_len > 0)
|
||||||
{
|
{
|
||||||
@ -721,8 +735,10 @@ static int sam_transmit(struct sam_gmac_s *priv)
|
|||||||
|
|
||||||
/* Update TX descriptor status. */
|
/* Update TX descriptor status. */
|
||||||
|
|
||||||
|
status = dev->d_len & GMAC_STATUS_LENGTH_MASK;
|
||||||
status = dev->d_len | GMACTXD_STA_LAST;
|
status = dev->d_len | GMACTXD_STA_LAST;
|
||||||
if (priv->txhead == CONFIG_SAMA5_GMAC_NTXBUFFERS-1)
|
|
||||||
|
if (priv->txhead == CONFIG_SAMA5_GMAC_NTXBUFFERS - 1)
|
||||||
{
|
{
|
||||||
status |= GMACTXD_STA_WRAP;
|
status |= GMACTXD_STA_WRAP;
|
||||||
}
|
}
|
||||||
@ -777,8 +793,9 @@ static int sam_transmit(struct sam_gmac_s *priv)
|
|||||||
* Function: sam_txpoll
|
* Function: sam_txpoll
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* The transmitter is available, check if the network has any outgoing packets ready
|
* The transmitter is available, check if the network has any outgoing
|
||||||
* to send. This is a callback from devif_poll(). devif_poll() may be called:
|
* packets ready to send. This is a callback from devif_poll().
|
||||||
|
* devif_poll() may be called:
|
||||||
*
|
*
|
||||||
* 1. When the preceding TX packet send is complete,
|
* 1. When the preceding TX packet send is complete,
|
||||||
* 2. When the preceding TX packet send timesout and the interface is reset
|
* 2. When the preceding TX packet send timesout and the interface is reset
|
||||||
@ -850,8 +867,8 @@ static int sam_txpoll(struct net_driver_s *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If zero is returned, the polling will continue until all connections have
|
/* If zero is returned, the polling will continue until all connections
|
||||||
* been examined.
|
* have been examined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -866,7 +883,8 @@ static int sam_txpoll(struct net_driver_s *dev)
|
|||||||
*
|
*
|
||||||
* 1. After completion of a transmission (sam_txdone),
|
* 1. After completion of a transmission (sam_txdone),
|
||||||
* 2. When new TX data is available (sam_txavail), and
|
* 2. When new TX data is available (sam_txavail), and
|
||||||
* 3. After a TX timeout to restart the sending process (sam_txtimeout_expiry).
|
* 3. After a TX timeout to restart the sending process
|
||||||
|
* (sam_txtimeout_expiry).
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* priv - Reference to the driver state structure
|
* priv - Reference to the driver state structure
|
||||||
@ -1095,7 +1113,8 @@ static int sam_recvframe(struct sam_gmac_s *priv)
|
|||||||
|
|
||||||
if (pktlen < dev->d_len)
|
if (pktlen < dev->d_len)
|
||||||
{
|
{
|
||||||
nerr("ERROR: Buffer size %d; frame size %d\n", dev->d_len, pktlen);
|
nerr("ERROR: Buffer size %d; frame size %d\n",
|
||||||
|
dev->d_len, pktlen);
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1103,7 +1122,9 @@ static int sam_recvframe(struct sam_gmac_s *priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have not encount the SOF yet... discard this fragment and keep looking */
|
/* We have not encount the SOF yet... discard this fragment and keep
|
||||||
|
* looking
|
||||||
|
*/
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1181,8 +1202,8 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
{
|
{
|
||||||
sam_dumppacket("Received packet", dev->d_buf, dev->d_len);
|
sam_dumppacket("Received packet", dev->d_buf, dev->d_len);
|
||||||
|
|
||||||
/* Check if the packet is a valid size for the network buffer configuration
|
/* Check if the packet is a valid size for the network buffer
|
||||||
* (this should not happen)
|
* configuration (this should not happen)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
|
if (dev->d_len > CONFIG_NET_ETH_PKTSIZE)
|
||||||
@ -1192,7 +1213,9 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NET_PKT
|
#ifdef CONFIG_NET_PKT
|
||||||
/* When packet sockets are enabled, feed the frame into the packet tap */
|
/* When packet sockets are enabled, feed the frame into the packet
|
||||||
|
* tap
|
||||||
|
*/
|
||||||
|
|
||||||
pkt_input(&priv->dev);
|
pkt_input(&priv->dev);
|
||||||
#endif
|
#endif
|
||||||
@ -1212,7 +1235,8 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
ipv4_input(&priv->dev);
|
ipv4_input(&priv->dev);
|
||||||
|
|
||||||
/* If the above function invocation resulted in data that should be
|
/* If the above function invocation resulted in data that should be
|
||||||
* sent out on the network, the field d_len will set to a value > 0.
|
* sent out on the network, the field d_len will set to a
|
||||||
|
* value > 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->dev.d_len > 0)
|
if (priv->dev.d_len > 0)
|
||||||
@ -1249,7 +1273,8 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
ipv6_input(&priv->dev);
|
ipv6_input(&priv->dev);
|
||||||
|
|
||||||
/* If the above function invocation resulted in data that should be
|
/* If the above function invocation resulted in data that should be
|
||||||
* sent out on the network, the field d_len will set to a value > 0.
|
* sent out on the network, the field d_len will set to a
|
||||||
|
* value > 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->dev.d_len > 0)
|
if (priv->dev.d_len > 0)
|
||||||
@ -1286,7 +1311,8 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
arp_arpin(&priv->dev);
|
arp_arpin(&priv->dev);
|
||||||
|
|
||||||
/* If the above function invocation resulted in data that should be
|
/* If the above function invocation resulted in data that should be
|
||||||
* sent out on the network, the field d_len will set to a value > 0.
|
* sent out on the network, the field d_len will set to a
|
||||||
|
* value > 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->dev.d_len > 0)
|
if (priv->dev.d_len > 0)
|
||||||
@ -1323,6 +1349,7 @@ static void sam_receive(struct sam_gmac_s *priv)
|
|||||||
static void sam_txdone(struct sam_gmac_s *priv)
|
static void sam_txdone(struct sam_gmac_s *priv)
|
||||||
{
|
{
|
||||||
struct gmac_txdesc_s *txdesc;
|
struct gmac_txdesc_s *txdesc;
|
||||||
|
struct net_driver_s *dev = &priv->dev;
|
||||||
|
|
||||||
/* Are there any outstanding transmissions? Loop until either (1) all of
|
/* Are there any outstanding transmissions? Loop until either (1) all of
|
||||||
* the TX descriptors have been examined, or (2) until we encounter the
|
* the TX descriptors have been examined, or (2) until we encounter the
|
||||||
@ -1337,24 +1364,39 @@ static void sam_txdone(struct sam_gmac_s *priv)
|
|||||||
up_invalidate_dcache((uintptr_t)txdesc,
|
up_invalidate_dcache((uintptr_t)txdesc,
|
||||||
(uintptr_t)txdesc + sizeof(struct gmac_txdesc_s));
|
(uintptr_t)txdesc + sizeof(struct gmac_txdesc_s));
|
||||||
|
|
||||||
/* Is this TX descriptor still in use? */
|
/* Is this TX descriptor done transmitting? (SAMA5D36 datasheet,
|
||||||
|
* p. 934)
|
||||||
|
* First TX descriptor in chain has GMACTXD_STA_USED = 1
|
||||||
|
*/
|
||||||
|
|
||||||
if ((txdesc->status & GMACTXD_STA_USED) == 0)
|
if ((txdesc->status & GMACTXD_STA_USED) == 0)
|
||||||
{
|
{
|
||||||
/* Yes.. the descriptor is still in use. However, I have seen a
|
/* Yes.. the descriptor is still in use. However, I have seen a
|
||||||
* case (only repeatable on start-up) where the USED bit is never
|
* case (only repeatable on start-up) where the USED bit is never
|
||||||
* set. Yikes! If we have encountered the first still busy
|
* set. Yikes! If we have encountered the first still busy
|
||||||
* descriptor, then we should also have TQBD equal to the descriptor
|
* descriptor, then we should also have TQBD equal to the
|
||||||
* address. If it is not, then treat is as used anyway.
|
* descriptor address. If it is not, then treat is as used anyway.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#warning REVISIT
|
|
||||||
if (priv->txtail == 0 &&
|
if (priv->txtail == 0 &&
|
||||||
sam_physramaddr((uintptr_t)txdesc) != sam_getreg(priv, SAM_GMAC_TBQB))
|
sam_physramaddr((uintptr_t)txdesc) != sam_getreg(priv,
|
||||||
|
SAM_GMAC_TBQB))
|
||||||
{
|
{
|
||||||
txdesc->status = (uint32_t)GMACTXD_STA_USED;
|
ninfo("TX buffer marked in-use: unusual startup case (%d)\n",
|
||||||
|
priv->txtail);
|
||||||
|
txdesc->status = (uint32_t) dev->d_len | GMACTXD_STA_USED;
|
||||||
up_clean_dcache((uintptr_t)txdesc,
|
up_clean_dcache((uintptr_t)txdesc,
|
||||||
(uintptr_t)txdesc + sizeof(struct gmac_txdesc_s));
|
(uintptr_t)txdesc +
|
||||||
|
sizeof(struct gmac_txdesc_s));
|
||||||
|
}
|
||||||
|
else if (((txdesc->status & GMACTXD_STA_USED) == 0) &&
|
||||||
|
((txdesc->status & GMACTXD_STA_LAST) != 0))
|
||||||
|
{
|
||||||
|
txdesc->status = (uint32_t) dev->d_len | GMACTXD_STA_USED |
|
||||||
|
GMACTXD_STA_LAST;
|
||||||
|
up_clean_dcache((uintptr_t)txdesc,
|
||||||
|
(uintptr_t)txdesc +
|
||||||
|
sizeof(struct gmac_txdesc_s));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1428,8 +1470,8 @@ static void sam_interrupt_work(FAR void *arg)
|
|||||||
ninfo("isr: %08x pending: %08x\n", isr, pending);
|
ninfo("isr: %08x pending: %08x\n", isr, pending);
|
||||||
|
|
||||||
/* Check for the completion of a transmission. This should be done before
|
/* Check for the completion of a transmission. This should be done before
|
||||||
* checking for received data (because receiving can cause another transmission
|
* checking for received data (because receiving can cause another
|
||||||
* before we had a chance to handle the last one).
|
* transmission before we had a chance to handle the last one).
|
||||||
*
|
*
|
||||||
* ISR:TCOMP is set when a frame has been transmitted. Cleared on read.
|
* ISR:TCOMP is set when a frame has been transmitted. Cleared on read.
|
||||||
* TSR:COMP is set when a frame has been transmitted. Cleared by writing a
|
* TSR:COMP is set when a frame has been transmitted. Cleared by writing a
|
||||||
@ -1579,7 +1621,8 @@ static void sam_interrupt_work(FAR void *arg)
|
|||||||
#ifdef CONFIG_DEBUG_NET
|
#ifdef CONFIG_DEBUG_NET
|
||||||
/* Check for PAUSE Frame received (PFRE).
|
/* Check for PAUSE Frame received (PFRE).
|
||||||
*
|
*
|
||||||
* ISR:PFRE indicates that a pause frame has been received. Cleared on a read.
|
* ISR:PFRE indicates that a pause frame has been received. Cleared on a
|
||||||
|
* read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((pending & GMAC_INT_PFNZ) != 0)
|
if ((pending & GMAC_INT_PFNZ) != 0)
|
||||||
@ -1638,15 +1681,15 @@ static int sam_gmac_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
*
|
*
|
||||||
* ISR:TCOMP is set when a frame has been transmitted. Cleared on read (so
|
* ISR:TCOMP is set when a frame has been transmitted. Cleared on read (so
|
||||||
* we cannot read it here).
|
* we cannot read it here).
|
||||||
* TSR:TXCOMP is set when a frame has been transmitted. Cleared by writing a
|
* TSR:TXCOMP is set when a frame has been transmitted. Cleared by writing
|
||||||
* one to this bit.
|
* a one to this bit.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tsr = sam_getreg(priv, SAM_GMAC_TSR_OFFSET);
|
tsr = sam_getreg(priv, SAM_GMAC_TSR);
|
||||||
if ((tsr & GMAC_TSR_TXCOMP) != 0)
|
if ((tsr & GMAC_TSR_TXCOMP) != 0)
|
||||||
{
|
{
|
||||||
/* If a TX transfer just completed, then cancel the TX timeout so
|
/* If a TX transfer just completed, then cancel the TX timeout so
|
||||||
* there will be do race condition between any subsequent timeout
|
* there will be no race condition between any subsequent timeout
|
||||||
* expiration and the deferred interrupt processing.
|
* expiration and the deferred interrupt processing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2032,7 +2075,8 @@ static unsigned int sam_hashindx(const uint8_t *mac)
|
|||||||
unsigned int ndx;
|
unsigned int ndx;
|
||||||
|
|
||||||
/* Isolate: mac[0]
|
/* Isolate: mac[0]
|
||||||
* ... 05 04 03 02 01 00] */
|
* ... 05 04 03 02 01 00]
|
||||||
|
*/
|
||||||
|
|
||||||
ndx = mac[0];
|
ndx = mac[0];
|
||||||
|
|
||||||
@ -2203,8 +2247,8 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac)
|
|||||||
* Function: sam_rmmac
|
* Function: sam_rmmac
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* NuttX Callback: Remove the specified MAC address from the hardware multicast
|
* NuttX Callback: Remove the specified MAC address from the hardware
|
||||||
* address filtering
|
* multicast address filtering
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* dev - Reference to the NuttX driver state structure
|
* dev - Reference to the NuttX driver state structure
|
||||||
@ -2301,9 +2345,9 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac)
|
|||||||
* specified using the req->reg_no struct field and then write its output
|
* specified using the req->reg_no struct field and then write its output
|
||||||
* to the req->val_out field.
|
* to the req->val_out field.
|
||||||
*
|
*
|
||||||
* When called with SIOCSMIIREG it will write to a register of the PHY that
|
* When called with SIOCSMIIREG it will write to a register of the PHY
|
||||||
* is specified using the req->reg_no struct field and use req->val_in as
|
* that is specified using the req->reg_no struct field and use
|
||||||
* its input.
|
* req->val_in as its input.
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* dev - Ethernet device structure
|
* dev - Ethernet device structure
|
||||||
@ -2330,7 +2374,8 @@ static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
|||||||
#ifdef CONFIG_ARCH_PHY_INTERRUPT
|
#ifdef CONFIG_ARCH_PHY_INTERRUPT
|
||||||
case SIOCMIINOTIFY: /* Set up for PHY event notifications */
|
case SIOCMIINOTIFY: /* Set up for PHY event notifications */
|
||||||
{
|
{
|
||||||
struct mii_ioctl_notify_s *req = (struct mii_ioctl_notify_s *)((uintptr_t)arg);
|
struct mii_ioctl_notify_s *req =
|
||||||
|
(struct mii_ioctl_notify_s *)((uintptr_t)arg);
|
||||||
|
|
||||||
ret = phy_notify_subscribe(dev->d_ifname, req->pid, &req->event);
|
ret = phy_notify_subscribe(dev->d_ifname, req->pid, &req->event);
|
||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
@ -2345,7 +2390,8 @@ static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
case SIOCGMIIPHY: /* Get MII PHY address */
|
case SIOCGMIIPHY: /* Get MII PHY address */
|
||||||
{
|
{
|
||||||
struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg);
|
struct mii_ioctl_data_s *req =
|
||||||
|
(struct mii_ioctl_data_s *)((uintptr_t)arg);
|
||||||
req->phy_id = priv->phyaddr;
|
req->phy_id = priv->phyaddr;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
@ -2353,7 +2399,8 @@ static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
case SIOCGMIIREG: /* Get register from MII PHY */
|
case SIOCGMIIREG: /* Get register from MII PHY */
|
||||||
{
|
{
|
||||||
struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg);
|
struct mii_ioctl_data_s *req =
|
||||||
|
(struct mii_ioctl_data_s *)((uintptr_t)arg);
|
||||||
|
|
||||||
/* Enable the management port */
|
/* Enable the management port */
|
||||||
|
|
||||||
@ -2371,7 +2418,8 @@ static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
case SIOCSMIIREG: /* Set register in MII PHY */
|
case SIOCSMIIREG: /* Set register in MII PHY */
|
||||||
{
|
{
|
||||||
struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg);
|
struct mii_ioctl_data_s *req =
|
||||||
|
(struct mii_ioctl_data_s *)((uintptr_t)arg);
|
||||||
|
|
||||||
/* Enable the management port */
|
/* Enable the management port */
|
||||||
|
|
||||||
@ -3119,6 +3167,7 @@ static int sam_autonegotiate(struct sam_gmac_s *priv)
|
|||||||
sam_putreg(priv, SAM_GMAC_UR, regval);
|
sam_putreg(priv, SAM_GMAC_UR, regval);
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
|
|
||||||
/* Disable the management port */
|
/* Disable the management port */
|
||||||
|
|
||||||
sam_disablemdio(priv);
|
sam_disablemdio(priv);
|
||||||
@ -3367,13 +3416,14 @@ static void sam_txreset(struct sam_gmac_s *priv)
|
|||||||
|
|
||||||
/* Mark the final descriptor in the list */
|
/* Mark the final descriptor in the list */
|
||||||
|
|
||||||
txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS - 1].status = GMACTXD_STA_USED | GMACTXD_STA_WRAP;
|
txdesc[CONFIG_SAMA5_GMAC_NTXBUFFERS - 1].status = GMACTXD_STA_USED |
|
||||||
|
GMACTXD_STA_WRAP;
|
||||||
|
|
||||||
/* Flush the entire TX descriptor table to RAM */
|
/* Flush the entire TX descriptor table to RAM */
|
||||||
|
|
||||||
up_clean_dcache((uintptr_t)txdesc,
|
up_clean_dcache((uintptr_t)txdesc,
|
||||||
(uintptr_t)txdesc +
|
(uintptr_t)txdesc + CONFIG_SAMA5_GMAC_NTXBUFFERS *
|
||||||
CONFIG_SAMA5_GMAC_NTXBUFFERS * sizeof(struct gmac_txdesc_s));
|
sizeof(struct gmac_txdesc_s));
|
||||||
|
|
||||||
/* Set the Transmit Buffer Queue Base Register */
|
/* Set the Transmit Buffer Queue Base Register */
|
||||||
|
|
||||||
@ -3436,8 +3486,8 @@ static void sam_rxreset(struct sam_gmac_s *priv)
|
|||||||
/* Flush the entire RX descriptor table to RAM */
|
/* Flush the entire RX descriptor table to RAM */
|
||||||
|
|
||||||
up_clean_dcache((uintptr_t)rxdesc,
|
up_clean_dcache((uintptr_t)rxdesc,
|
||||||
(uintptr_t)rxdesc +
|
(uintptr_t)rxdesc + CONFIG_SAMA5_GMAC_NRXBUFFERS *
|
||||||
CONFIG_SAMA5_GMAC_NRXBUFFERS * sizeof(struct gmac_rxdesc_s));
|
sizeof(struct gmac_rxdesc_s));
|
||||||
|
|
||||||
/* Set the Receive Buffer Queue Base Register */
|
/* Set the Receive Buffer Queue Base Register */
|
||||||
|
|
||||||
@ -3526,9 +3576,12 @@ static void sam_macaddress(struct sam_gmac_s *priv)
|
|||||||
|
|
||||||
ninfo("%s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
ninfo("%s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||||
dev->d_ifname,
|
dev->d_ifname,
|
||||||
dev->d_mac.ether.ether_addr_octet[0], dev->d_mac.ether.ether_addr_octet[1],
|
dev->d_mac.ether.ether_addr_octet[0],
|
||||||
dev->d_mac.ether.ether_addr_octet[2], dev->d_mac.ether.ether_addr_octet[3],
|
dev->d_mac.ether.ether_addr_octet[1],
|
||||||
dev->d_mac.ether.ether_addr_octet[4], dev->d_mac.ether.ether_addr_octet[5]);
|
dev->d_mac.ether.ether_addr_octet[2],
|
||||||
|
dev->d_mac.ether.ether_addr_octet[3],
|
||||||
|
dev->d_mac.ether.ether_addr_octet[4],
|
||||||
|
dev->d_mac.ether.ether_addr_octet[5]);
|
||||||
|
|
||||||
/* Set the MAC address */
|
/* Set the MAC address */
|
||||||
|
|
||||||
@ -3717,12 +3770,14 @@ static int sam_gmac_configure(struct sam_gmac_s *priv)
|
|||||||
|
|
||||||
/* Setup the interrupts for TX events, RX events, and error events */
|
/* Setup the interrupts for TX events, RX events, and error events */
|
||||||
|
|
||||||
regval = GMAC_INT_MFS | GMAC_INT_RCOMP | GMAC_INT_RXUBR | GMAC_INT_TXUBR |
|
regval = GMAC_INT_MFS | GMAC_INT_RCOMP | GMAC_INT_RXUBR |
|
||||||
GMAC_INT_TUR | GMAC_INT_RLEX | GMAC_INT_TFC | GMAC_INT_TCOMP |
|
GMAC_INT_TXUBR | GMAC_INT_TUR | GMAC_INT_RLEX |
|
||||||
GMAC_INT_ROVR | GMAC_INT_HRESP | GMAC_INT_PFNZ | GMAC_INT_PTZ |
|
GMAC_INT_TFC | GMAC_INT_TCOMP | GMAC_INT_ROVR |
|
||||||
GMAC_INT_PFTR | GMAC_INT_EXINT | GMAC_INT_DRQFR | GMAC_INT_SFR |
|
GMAC_INT_HRESP | GMAC_INT_PFNZ | GMAC_INT_PTZ |
|
||||||
GMAC_INT_DRQFT | GMAC_INT_SFT | GMAC_INT_PDRQFR | GMAC_INT_PDRSFR |
|
GMAC_INT_PFTR | GMAC_INT_EXINT | GMAC_INT_DRQFR |
|
||||||
GMAC_INT_PDRQFT | GMAC_INT_PDRSFT;
|
GMAC_INT_SFR | GMAC_INT_DRQFT | GMAC_INT_SFT |
|
||||||
|
GMAC_INT_PDRQFR | GMAC_INT_PDRSFR | GMAC_INT_PDRQFT |
|
||||||
|
GMAC_INT_PDRSFT;
|
||||||
sam_putreg(priv, SAM_GMAC_IER, regval);
|
sam_putreg(priv, SAM_GMAC_IER, regval);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -3807,7 +3862,8 @@ int sam_gmac_initialize(void)
|
|||||||
ret = irq_attach(SAM_IRQ_GMAC, sam_gmac_interrupt, NULL);
|
ret = irq_attach(SAM_IRQ_GMAC, sam_gmac_interrupt, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
nerr("ERROR: Failed to attach the handler to the IRQ%d\n", SAM_IRQ_GMAC);
|
nerr("ERROR: Failed to attach the handler to the IRQ%d\n",
|
||||||
|
SAM_IRQ_GMAC);
|
||||||
goto errout_with_buffers;
|
goto errout_with_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3820,7 +3876,8 @@ int sam_gmac_initialize(void)
|
|||||||
ret = sam_ifdown(&priv->dev);
|
ret = sam_ifdown(&priv->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
nerr("ERROR: Failed to put the interface in the down state: %d\n", ret);
|
nerr("ERROR: Failed to put the interface in the down state: %d\n",
|
||||||
|
ret);
|
||||||
goto errout_with_buffers;
|
goto errout_with_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user