|
|
@@ -20,6 +20,7 @@
|
|
|
|
|
|
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 3
|
|
|
#define configEMAC_TASK_STACK_SIZE (32 * configMINIMAL_STACK_SIZE)
|
|
|
+#define DCACHE_LINE_SIZE 64ul
|
|
|
|
|
|
#define ETH_DMA_ALL_INTS \
|
|
|
( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | \
|
|
|
@@ -42,21 +43,29 @@ struct ethernetif {
|
|
|
static ETH_HandleTypeDef xETH;
|
|
|
|
|
|
/* Ethernet Rx MA Descriptor */
|
|
|
-#pragma data_alignment=4
|
|
|
-static ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ];
|
|
|
+#if defined(__ICCARM__) || defined(__ICCRX__) /* for IAR compiler */
|
|
|
+#pragma data_alignment=DCACHE_LINE_SIZE
|
|
|
+static uint8_t DMARxDscrTab[((ETH_RXBUFNB * sizeof(ETH_DMADescTypeDef) - 1) & ~(DCACHE_LINE_SIZE -1)) + DCACHE_LINE_SIZE];
|
|
|
+#else
|
|
|
+static uint8_t DMARxDscrTab[((ETH_RXBUFNB * sizeof(ETH_DMADescTypeDef) - 1) & ~(DCACHE_LINE_SIZE -1)) + DCACHE_LINE_SIZE] __attribute__((aligned(DCACHE_LINE_SIZE)));
|
|
|
+#endif
|
|
|
|
|
|
/* DMATxDescToClear points to the next TX DMA descriptor
|
|
|
- * that must be cleared by vClearTXBuffers(). */
|
|
|
+ * that must be cleared by vClearTXBuffersFromISR(). */
|
|
|
static __IO ETH_DMADescTypeDef * DMATxDescToClear;
|
|
|
|
|
|
/* Ethernet Tx DMA Descriptor */
|
|
|
-#pragma data_alignment=4
|
|
|
-static ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ];
|
|
|
+#if defined(__ICCARM__) || defined(__ICCRX__) /* for IAR compiler */
|
|
|
+#pragma data_alignment=DCACHE_LINE_SIZE
|
|
|
+static uint8_t DMATxDscrTab[((ETH_TXBUFNB * sizeof(ETH_DMADescTypeDef) - 1) & ~(DCACHE_LINE_SIZE -1)) + DCACHE_LINE_SIZE];
|
|
|
+#else
|
|
|
+static uint8_t DMATxDscrTab[((ETH_TXBUFNB * sizeof(ETH_DMADescTypeDef) - 1) & ~(DCACHE_LINE_SIZE -1)) + DCACHE_LINE_SIZE] __attribute__((aligned(DCACHE_LINE_SIZE)));
|
|
|
+#endif
|
|
|
|
|
|
/* xTXDescriptorSemaphore is a counting semaphore with
|
|
|
* a maximum count of ETH_TXBUFNB, which is the number of
|
|
|
* DMA TX descriptors. */
|
|
|
-static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
|
|
|
+static QueueHandle_t xTXDescriptorSemaphore = NULL;
|
|
|
|
|
|
/* Holds the handle of the task used as a deferred interrupt processor. The
|
|
|
* handle is used so direct notifications can be sent to the task for all EMAC/DMA
|
|
|
@@ -79,8 +88,19 @@ static const PhyProperties_t xPHYProperties =
|
|
|
#else
|
|
|
.ucDuplex = PHY_DUPLEX_AUTO,
|
|
|
#endif
|
|
|
+
|
|
|
+#if PHY_JL3101_SEL
|
|
|
+ .ucMDI_X = PHY_MDIX_DIRECT,
|
|
|
+#else
|
|
|
.ucMDI_X = PHY_MDIX_AUTO,
|
|
|
+#endif
|
|
|
+
|
|
|
.ucMacIf = PHY_MACIF_MII,
|
|
|
+#if PHY_JL3101_SEL
|
|
|
+ .ucRole = PHY_ROLE_MASTER,
|
|
|
+#else
|
|
|
+ .ucRole = PHY_ROLE_AUTO,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static uint32_t ethernetif_input(void *h);
|
|
|
@@ -91,6 +111,7 @@ static BaseType_t ETH_WriteReg( BaseType_t xAddress,
|
|
|
BaseType_t xRegister,
|
|
|
uint32_t ulValue );
|
|
|
static void ETH_PhyCfg(ETH_HandleTypeDef *heth);
|
|
|
+static void vClearTXBuffersFromISR(BaseType_t * const pxHigherPriorityTaskWoken);
|
|
|
|
|
|
static void ETH_MspInitCallback(ETH_HandleTypeDef *heth)
|
|
|
{
|
|
|
@@ -127,10 +148,9 @@ static void ETH_TxCpltCallback(ETH_HandleTypeDef * heth)
|
|
|
|
|
|
( void ) heth;
|
|
|
|
|
|
- /* Pass a TX-event and wakeup the prvEMACHandlerTask. */
|
|
|
if( xEMACTaskHandle != NULL )
|
|
|
{
|
|
|
- xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
|
|
|
+ vClearTXBuffersFromISR( &xHigherPriorityTaskWoken );
|
|
|
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
|
}
|
|
|
}
|
|
|
@@ -401,18 +421,16 @@ static void prvDMARxDescListInit()
|
|
|
xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-static void vClearTXBuffers()
|
|
|
+static void vClearTXBuffersFromISR(BaseType_t * const pxHigherPriorityTaskWoken)
|
|
|
{
|
|
|
__IO ETH_DMADescTypeDef * txLastDescriptor = xETH.TxDesc;
|
|
|
__IO ETH_DMADescTypeDef * Descriptor;
|
|
|
- size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
|
|
+ size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxQueueMessagesWaitingFromISR(xTXDescriptorSemaphore);
|
|
|
|
|
|
/* This function is called after a TX-completion interrupt.
|
|
|
* It will release each Network Buffer used in xNetworkInterfaceOutput().
|
|
|
* 'uxCount' represents the number of descriptors given to DMA for transmission.
|
|
|
* After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
|
|
|
-
|
|
|
Descriptor = (ETH_DMADescTypeDef *)PHY_TO_UNCACHED_VIRT(DMATxDescToClear);
|
|
|
|
|
|
while( ( uxCount > 0 ) && ( ( Descriptor->Status & ETH_DMATXDESC_OWN ) == 0 ) ) {
|
|
|
@@ -425,7 +443,7 @@ static void vClearTXBuffers()
|
|
|
Descriptor = (ETH_DMADescTypeDef *)PHY_TO_UNCACHED_VIRT(DMATxDescToClear);
|
|
|
uxCount--;
|
|
|
/* Tell the counting semaphore that one more TX descriptor is available. */
|
|
|
- xSemaphoreGive( xTXDescriptorSemaphore );
|
|
|
+ xQueueSendFromISR(xTXDescriptorSemaphore, NULL, pxHigherPriorityTaskWoken);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -443,7 +461,7 @@ static void prvEMACHandlerTask(void * pvParameters)
|
|
|
ulISREvents = 0;
|
|
|
if (xTXDescriptorSemaphore != NULL) {
|
|
|
static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
|
|
|
- uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
|
|
+ uxCurrentCount = uxQueueMessagesWaiting(xTXDescriptorSemaphore);
|
|
|
if( uxLowestSemCount > uxCurrentCount ) {
|
|
|
uxLowestSemCount = uxCurrentCount;
|
|
|
printf( "TX DMA buffers: lowest %lu\n", uxLowestSemCount);
|
|
|
@@ -460,12 +478,6 @@ static void prvEMACHandlerTask(void * pvParameters)
|
|
|
xResult = ethernetif_input((void *)netif);
|
|
|
}
|
|
|
|
|
|
- if (( ulISREvents & EMAC_IF_TX_EVENT) != 0) {
|
|
|
- /* Code to release TX buffers in case zero-copy is used. */
|
|
|
- /* Check if DMA packets have been delivered. */
|
|
|
- vClearTXBuffers();
|
|
|
- }
|
|
|
-
|
|
|
if ((ulISREvents & EMAC_IF_ERR_EVENT) != 0) {
|
|
|
/* Future extension: logging about errors that occurred. */
|
|
|
}
|
|
|
@@ -490,6 +502,18 @@ static void prvEMACHandlerTask(void * pvParameters)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#if ETH_VLAN_EN
|
|
|
+static int ETH_TxFrameAddVlanTag(uint8_t *txbuf)
|
|
|
+{
|
|
|
+ txbuf[0] = 0x81;
|
|
|
+ txbuf[1] = 0x00;
|
|
|
+ txbuf[2] = ((ETH_VLAN_PRIORITY & 0x7) << 5) | ((ETH_VLAN_ID & 0xfff) >> 8);
|
|
|
+ txbuf[3] = (ETH_VLAN_ID & 0xff);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
Length: max length = ETH_TX_BUF_SIZE
|
|
|
*/
|
|
|
@@ -504,14 +528,23 @@ static int ETH_TransmitFrame(const uint8_t *Data, uint32_t Length)
|
|
|
|
|
|
if (!Data || !Length) {
|
|
|
printf("[%s] Data = NULL or Length = 0\n", __func__);
|
|
|
- return ERR_TIMEOUT;
|
|
|
+ return ERR_BUF;
|
|
|
+ }
|
|
|
+
|
|
|
+#if ETH_VLAN_EN
|
|
|
+ if ((Length + 4) > ETH_TX_BUF_SIZE)
|
|
|
+#else
|
|
|
+ if (Length > ETH_TX_BUF_SIZE)
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ printf("[%s] TX Length Error!\n", __func__);
|
|
|
+ return ERR_BUF;
|
|
|
}
|
|
|
|
|
|
/* Open a do {} while ( 0 ) loop to be able to call break. */
|
|
|
do {
|
|
|
- if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) {
|
|
|
- /* Time-out waiting for a free TX descriptor. */
|
|
|
- printf("xTXDescriptorSemaphore take fail!\n");
|
|
|
+ if (xQueuePeek(xTXDescriptorSemaphore, NULL, xBlockTimeTicks) != pdPASS) {
|
|
|
+ printf("txbuf full!\n");
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
@@ -523,15 +556,20 @@ static int ETH_TransmitFrame(const uint8_t *Data, uint32_t Length)
|
|
|
configASSERT( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );
|
|
|
|
|
|
/* Get bytes in current buffer. */
|
|
|
+#if ETH_VLAN_EN
|
|
|
+ ulTransmitSize = Length + 4;
|
|
|
+ memcpy((void *)pxDmaTxDesc->Buffer1Addr, Data, 12);
|
|
|
+ ETH_TxFrameAddVlanTag((uint8_t *)(pxDmaTxDesc->Buffer1Addr + 12));
|
|
|
+ memcpy((void *)(pxDmaTxDesc->Buffer1Addr + 12 + 4), Data + 12, Length - 12);
|
|
|
+ pxDmaTxDesc->Status |= ETH_DMATXDESC_VF;
|
|
|
+#else
|
|
|
ulTransmitSize = Length;
|
|
|
-
|
|
|
- if( ulTransmitSize > ETH_TX_BUF_SIZE ){
|
|
|
- ulTransmitSize = ETH_TX_BUF_SIZE;
|
|
|
- }
|
|
|
-
|
|
|
memcpy((void *)pxDmaTxDesc->Buffer1Addr, Data, ulTransmitSize);
|
|
|
+#endif
|
|
|
dma_flush_range((uint32_t)(pxDmaTxDesc->Buffer1Addr), (uint32_t)(pxDmaTxDesc->Buffer1Addr) + ulTransmitSize);
|
|
|
|
|
|
+ /* Ask to set the IPv4 checksum.
|
|
|
+ * Also need an Interrupt on Completion so that 'vClearTXBuffersFromISR()' will be called.. */
|
|
|
if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE ) {
|
|
|
pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;
|
|
|
} else {
|
|
|
@@ -539,7 +577,6 @@ static int ETH_TransmitFrame(const uint8_t *Data, uint32_t Length)
|
|
|
}
|
|
|
pxDmaTxDesc->Status |= ETH_DMATXDESC_IC;
|
|
|
|
|
|
-
|
|
|
/* Prepare transmit descriptors to give to DMA. */
|
|
|
|
|
|
/* Set LAST and FIRST segment */
|
|
|
@@ -547,13 +584,16 @@ static int ETH_TransmitFrame(const uint8_t *Data, uint32_t Length)
|
|
|
/* Set frame size */
|
|
|
pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
|
|
|
|
|
|
+ vPortEnterCritical();
|
|
|
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
|
|
|
pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
|
|
|
-
|
|
|
/* Point to next descriptor */
|
|
|
- xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( pxDmaTxDesc->Buffer2NextDescAddr );
|
|
|
+ xETH.TxDesc = (ETH_DMADescTypeDef *) (pxDmaTxDesc->Buffer2NextDescAddr);
|
|
|
/* Ensure completion of memory access */
|
|
|
__DSB();
|
|
|
+ /* Update the counting semaphore */
|
|
|
+ xQueueReceive(xTXDescriptorSemaphore, NULL, 0);
|
|
|
+ vPortExitCritical();
|
|
|
|
|
|
/* When Tx Buffer unavailable flag is set: clear it and resume transmission */
|
|
|
if (((xETH.Instance)->DMASR & ETH_DMASR_TBUS) != 0) {
|
|
|
@@ -568,6 +608,11 @@ static int ETH_TransmitFrame(const uint8_t *Data, uint32_t Length)
|
|
|
return xReturn;
|
|
|
}
|
|
|
|
|
|
+static int ETH_RxFrameVlanTagHandle(const uint8_t *vlan_tag)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct pbuf *ETH_ReceivedFrame(void)
|
|
|
{
|
|
|
BaseType_t xReceivedLength = 0;
|
|
|
@@ -579,8 +624,6 @@ static struct pbuf *ETH_ReceivedFrame(void)
|
|
|
|
|
|
if (( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0u)
|
|
|
{
|
|
|
- BaseType_t xAccepted = pdTRUE;
|
|
|
-
|
|
|
/* Get the Frame Length of the received packet: subtract 4 bytes of the CRC */
|
|
|
xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
|
|
|
|
|
|
@@ -597,29 +640,36 @@ static struct pbuf *ETH_ReceivedFrame(void)
|
|
|
/* In order to make the code easier and faster, only packets in a single buffer
|
|
|
* will be accepted. This can be done by making the buffers large enough to
|
|
|
* hold a complete Ethernet packet, minus ipBUFFER_PADDING.
|
|
|
- * Therefore, two sanity checks: */
|
|
|
- configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );
|
|
|
-
|
|
|
- if( xAccepted != pdFALSE )
|
|
|
- {
|
|
|
- /* The packet will be accepted, but check first if a new Network Buffer can
|
|
|
- * be obtained. If not, the packet will still be dropped. */
|
|
|
- Buf = pbuf_alloc(PBUF_RAW, xReceivedLength, PBUF_RAM);
|
|
|
-
|
|
|
- if( Buf == NULL ) {
|
|
|
- /* A new descriptor can not be allocated now. This packet will be dropped. */
|
|
|
- printf("-------------- get NetworkBuffer fail! -----------\n");
|
|
|
- xAccepted = pdFALSE;
|
|
|
- } else if (Buf->len < xReceivedLength) {
|
|
|
- printf("-------------- NewBuf->xDataLength != xReceivedLength! -----------\n");
|
|
|
+ * Therefore, sanity checks: */
|
|
|
+ if (xReceivedLength <= ETH_RX_BUF_SIZE) {
|
|
|
+#if !ETH_VLAN_EN
|
|
|
+ if (!(pxDMARxDescriptor->Status & ETH_DMARXDESC_VLAN))
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ /* The packet will be accepted, but check first if a new Network Buffer can
|
|
|
+ * be obtained. If not, the packet will still be dropped. */
|
|
|
+ Buf = pbuf_alloc(PBUF_RAW, xReceivedLength, PBUF_RAM);
|
|
|
+
|
|
|
+ if( Buf == NULL ) {
|
|
|
+ /* A new descriptor can not be allocated now. This packet will be dropped. */
|
|
|
+ printf("-------------- get NetworkBuffer fail! -----------\n");
|
|
|
+ } else if (Buf->len < xReceivedLength) {
|
|
|
+ printf("-------------- NewBuf->xDataLength != xReceivedLength! -----------\n");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
if( Buf != NULL ) {
|
|
|
/* The packet is accepted and a new Network Buffer was created,
|
|
|
* copy data to the Network Buffer. */
|
|
|
- memcpy(Buf->payload, pucBuffer, xReceivedLength );
|
|
|
- Buf->len = xReceivedLength;
|
|
|
+ if (pxDMARxDescriptor->Status & ETH_DMARXDESC_VLAN) {
|
|
|
+ ETH_RxFrameVlanTagHandle((const uint8_t *)(pucBuffer + 12));
|
|
|
+ memcpy(Buf->payload, pucBuffer, 12);
|
|
|
+ memcpy((uint8_t *)(Buf->payload) + 12, pucBuffer + 12 + 4, xReceivedLength - 12 - 4);
|
|
|
+ Buf->len = xReceivedLength - 4;
|
|
|
+ } else {
|
|
|
+ memcpy(Buf->payload, pucBuffer, xReceivedLength);
|
|
|
+ Buf->len = xReceivedLength;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Release descriptors to DMA */
|
|
|
@@ -658,6 +708,7 @@ static struct pbuf *ETH_ReceivedFrame(void)
|
|
|
*/
|
|
|
static err_t low_level_init(struct netif *netif)
|
|
|
{
|
|
|
+ int i;
|
|
|
struct ethernetif *ethernetif = netif->state;
|
|
|
//int ret = -1;
|
|
|
const uint8_t mac[6] = {0x02, 0x53, 0x4C, 0x00, 0x00, 0x15};
|
|
|
@@ -699,11 +750,19 @@ static err_t low_level_init(struct netif *netif)
|
|
|
|
|
|
|
|
|
/* Do whatever else is needed to initialize interface. */
|
|
|
- xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
|
|
|
+ xTXDescriptorSemaphore = xQueueCreate((UBaseType_t )ETH_TXBUFNB, 0);
|
|
|
if (!xTXDescriptorSemaphore) {
|
|
|
- printf("%s - Semaphore Create fail!\n", __func__);
|
|
|
+ printf("%s - Queue Create fail!\n", __func__);
|
|
|
return ERR_IF;
|
|
|
}
|
|
|
+ for (i = 0; i < ETH_TXBUFNB; i++) {
|
|
|
+ if (xQueueSend(xTXDescriptorSemaphore, NULL, 0) != pdPASS) {
|
|
|
+ printf("fill xTXDescriptorSemaphore fail!\n");
|
|
|
+ vQueueDelete(xTXDescriptorSemaphore);
|
|
|
+ xTXDescriptorSemaphore = NULL;
|
|
|
+ return ERR_IF;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* Initialise ETH */
|
|
|
xETH.Instance = (ETH_TypeDef *)REGS_ETH_BASE;
|
|
|
@@ -733,18 +792,18 @@ static err_t low_level_init(struct netif *netif)
|
|
|
request_irq(ETH_IRQn, 0, (ISRFunction_t)HAL_ETH_IRQHandler, (void *)&xETH);
|
|
|
|
|
|
/* Set the TxDesc and RxDesc pointers. */
|
|
|
- xETH.TxDesc = DMATxDscrTab;
|
|
|
- xETH.RxDesc = DMARxDscrTab;
|
|
|
+ xETH.TxDesc = (ETH_DMADescTypeDef *)DMATxDscrTab;
|
|
|
+ xETH.RxDesc = (ETH_DMADescTypeDef *)DMARxDscrTab;
|
|
|
|
|
|
/* Make sure that all unused fields are cleared. */
|
|
|
- memset(&DMATxDscrTab, '\0', sizeof(DMATxDscrTab));
|
|
|
- memset(&DMARxDscrTab, '\0', sizeof(DMARxDscrTab));
|
|
|
+ memset(DMATxDscrTab, '\0', sizeof(DMATxDscrTab));
|
|
|
+ memset(DMARxDscrTab, '\0', sizeof(DMARxDscrTab));
|
|
|
|
|
|
dma_flush_range((uint32_t)DMATxDscrTab, (uint32_t)DMATxDscrTab + sizeof(DMATxDscrTab));
|
|
|
dma_flush_range((uint32_t)DMARxDscrTab, (uint32_t)DMARxDscrTab + sizeof(DMARxDscrTab));
|
|
|
|
|
|
/* Initialize Tx Descriptors list: Chain Mode */
|
|
|
- DMATxDescToClear = DMATxDscrTab;
|
|
|
+ DMATxDescToClear = (ETH_DMADescTypeDef *)DMATxDscrTab;
|
|
|
|
|
|
/* Initialise TX-descriptors. */
|
|
|
prvDMATxDescListInit();
|