]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Zynq / x_emacpsif_dma.c
index fc09d218335022fd0750a72d6ceb635138ca90e7..913b4b46cccde712d7d7daf0f95a125712ff19c0 100644 (file)
@@ -1,36 +1,27 @@
 /*\r
-FreeRTOS+TCP V2.0.11\r
-Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy of\r
-this software and associated documentation files (the "Software"), to deal in\r
-the Software without restriction, including without limitation the rights to\r
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
-the Software, and to permit persons to whom the Software is furnished to do so,\r
-subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in all\r
-copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-\r
- http://aws.amazon.com/freertos\r
- http://www.FreeRTOS.org\r
-*/\r
-\r
-#include "Zynq/x_emacpsif.h"\r
-#include "Zynq/x_topology.h"\r
-#include "xstatus.h"\r
-\r
-#include "xparameters.h"\r
-#include "xparameters_ps.h"\r
-#include "xil_exception.h"\r
-#include "xil_mmu.h"\r
+ * FreeRTOS V202002.00\r
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://aws.amazon.com/freertos\r
+ * http://www.FreeRTOS.org\r
+ */\r
 \r
 #include "FreeRTOS.h"\r
 #include "task.h"\r
@@ -43,6 +34,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "FreeRTOS_IP_Private.h"\r
 #include "NetworkBufferManagement.h"\r
 \r
+#include "Zynq/x_emacpsif.h"\r
+#include "Zynq/x_topology.h"\r
+#include "xstatus.h"\r
+\r
+#include "xparameters.h"\r
+#include "xparameters_ps.h"\r
+#include "xil_exception.h"\r
+#include "xil_mmu.h"\r
+\r
 #include "uncached_memory.h"\r
 \r
 /* Two defines used to set or clear the EMAC interrupt */\r
@@ -56,7 +56,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #endif\r
 #define TX_OFFSET                              ipconfigPACKET_FILLER_SIZE\r
 \r
-#define RX_BUFFER_ALIGNMENT    14\r
+#define dmaRX_TX_BUFFER_SIZE                   1536\r
 \r
 /* Defined in NetworkInterface.c */\r
 extern TaskHandle_t xEMACTaskHandle;\r
@@ -120,8 +120,6 @@ size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount
                {\r
                        break;\r
                }\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-#warning ipconfigZERO_COPY_TX_DRIVER is defined\r
                {\r
                void *pvBuffer = pxDMA_tx_buffers[ tail ];\r
                NetworkBufferDescriptor_t *pxBuffer;\r
@@ -140,7 +138,6 @@ size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount
                                }\r
                        }\r
                }\r
-#endif\r
                /* Clear all but the "used" and "wrap" bits. */\r
                if( tail < ipconfigNIC_N_TX_DESC - 1 )\r
                {\r
@@ -170,6 +167,11 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 \r
        xemacpsif = (xemacpsif_s *)(arg);\r
 \r
+       /* This function is called from an ISR. The Xilinx ISR-handler has already\r
+       cleared the TXCOMPL and TXSR_USEDREAD status bits in the XEMACPS_TXSR register.\r
+       But it forgets to do a read-back. Do so now to avoid ever-returning ISR's. */\r
+       ( void ) XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);\r
+\r
        /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in\r
        "isr_events". The task in NetworkInterface will wake-up and do the necessary work.\r
        */\r
@@ -188,7 +190,7 @@ static BaseType_t xValidLength( BaseType_t xLength )
 {\r
 BaseType_t xReturn;\r
 \r
-       if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )\r
+       if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= dmaRX_TX_BUFFER_SIZE ) )\r
        {\r
                xReturn = pdTRUE;\r
        }\r
@@ -207,12 +209,8 @@ int iHasSent = 0;
 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;\r
 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );\r
 \r
-       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-       {\r
-               /* This driver wants to own all network buffers which are to be transmitted. */\r
-               configASSERT( iReleaseAfterSend != pdFALSE );\r
-       }\r
-       #endif\r
+       /* This driver wants to own all network buffers which are to be transmitted. */\r
+       configASSERT( iReleaseAfterSend != pdFALSE );\r
 \r
        /* Open a do {} while ( 0 ) loop to be able to call break. */\r
        do\r
@@ -235,7 +233,6 @@ TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
                        break;\r
                }\r
 \r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
                /* Pass the pointer (and its ownership) directly to DMA. */\r
                pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;\r
                if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
@@ -244,15 +241,7 @@ TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
                }\r
                /* Buffer has been transferred, do not release it. */\r
                iReleaseAfterSend = pdFALSE;\r
-#else\r
-               if( pxDMA_tx_buffers[ head ] == NULL )\r
-               {\r
-                       FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );\r
-                       break;\r
-               }\r
-               /* Copy the message to unbuffered space in RAM. */\r
-               memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
-#endif\r
+\r
                /* Packets will be sent one-by-one, so for each packet\r
                the TXBUF_LAST bit will be set. */\r
                ulFlags |= XEMACPS_TXBUF_LAST_MASK;\r
@@ -292,6 +281,8 @@ TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
                /* Start transmit */\r
                xemacpsif->txBusy = pdTRUE;\r
                XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );\r
+               /* Read back the register to make sure the data is flushed. */\r
+               ( void ) XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );\r
        }\r
        dsb();\r
 \r
@@ -306,6 +297,11 @@ void emacps_recv_handler(void *arg)
        xemacpsif = (xemacpsif_s *)(arg);\r
        xemacpsif->isr_events |= EMAC_IF_RX_EVENT;\r
 \r
+       /* The driver has already cleared the FRAMERX, BUFFNA and error bits\r
+       in the XEMACPS_RXSR register,\r
+       But it forgets to do a read-back. Do so now. */\r
+       ( void ) XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);\r
+\r
        if( xEMACTaskHandle != NULL )\r
        {\r
                vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
@@ -314,33 +310,35 @@ void emacps_recv_handler(void *arg)
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
 }\r
 \r
-static NetworkBufferDescriptor_t *ethMsg = NULL;\r
-static NetworkBufferDescriptor_t *ethLast = NULL;\r
-\r
-static void passEthMessages( void )\r
+static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor )\r
 {\r
 IPStackEvent_t xRxEvent;\r
 \r
        xRxEvent.eEventType = eNetworkRxEvent;\r
-       xRxEvent.pvData = ( void * ) ethMsg;\r
+       xRxEvent.pvData = ( void * ) pxDescriptor;\r
 \r
        if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )\r
        {\r
                /* The buffer could not be sent to the stack so must be released again.\r
                This is a deferred handler taskr, not a real interrupt, so it is ok to\r
                use the task level function here. */\r
-               do\r
+               #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
                {\r
-                       NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;\r
-                       vReleaseNetworkBufferAndDescriptor( ethMsg );\r
-                       ethMsg = xNext;\r
-               } while( ethMsg != NULL );\r
-\r
+                       do\r
+                       {\r
+                               NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer;\r
+                               vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
+                               pxDescriptor = pxNext;\r
+                       } while( pxDescriptor != NULL );\r
+               }\r
+               #else\r
+               {\r
+                       vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
+               }\r
+               #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
                iptraceETHERNET_RX_EVENT_LOST();\r
-               FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );\r
+               FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );\r
        }\r
-\r
-       ethMsg = ethLast = NULL;\r
 }\r
 \r
 int emacps_check_rx( xemacpsif_s *xemacpsif )\r
@@ -349,6 +347,10 @@ NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
 int rx_bytes;\r
 volatile int msgCount = 0;\r
 int head = xemacpsif->rxHead;\r
+#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
+       NetworkBufferDescriptor_t *pxFirstDescriptor = NULL;\r
+       NetworkBufferDescriptor_t *pxLastDescriptor = NULL;\r
+#endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
 \r
        /* There seems to be an issue (SI# 692601), see comments below. */\r
        resetrx_on_no_rxdata(xemacpsif);\r
@@ -364,12 +366,12 @@ int head = xemacpsif->rxHead;
                        break;\r
                }\r
 \r
-               pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );\r
+               pxNewBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );\r
                if( pxNewBuffer == NULL )\r
                {\r
                        /* A packet has been received, but there is no replacement for this Network Buffer.\r
                        The packet will be dropped, and it Network Buffer will stay in place. */\r
-                       FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );\r
+                       FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Network Buffer\n" ) );\r
                        pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
                }\r
                else\r
@@ -394,26 +396,35 @@ int head = xemacpsif->rxHead;
                        /* store it in the receive queue, where it'll be processed by a\r
                        different handler. */\r
                        iptraceNETWORK_INTERFACE_RECEIVE();\r
-                       pxBuffer->pxNextBuffer = NULL;\r
-\r
-                       if( ethMsg == NULL )\r
+                       #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
                        {\r
-                               // Becomes the first message\r
-                               ethMsg = pxBuffer;\r
+                               pxBuffer->pxNextBuffer = NULL;\r
+\r
+                               if( pxFirstDescriptor == NULL )\r
+                               {\r
+                                       // Becomes the first message\r
+                                       pxFirstDescriptor = pxBuffer;\r
+                               }\r
+                               else if( pxLastDescriptor != NULL )\r
+                               {\r
+                                       // Add to the tail\r
+                                       pxLastDescriptor->pxNextBuffer = pxBuffer;\r
+                               }\r
+\r
+                               pxLastDescriptor = pxBuffer;\r
                        }\r
-                       else if( ethLast != NULL )\r
+                       #else\r
                        {\r
-                               // Add to the tail\r
-                               ethLast->pxNextBuffer = pxBuffer;\r
+                               prvPassEthMessages( pxBuffer );\r
                        }\r
+                       #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
 \r
-                       ethLast = pxBuffer;\r
                        msgCount++;\r
                }\r
                {\r
                        if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
                        {\r
-                               Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);\r
+                               Xil_DCacheInvalidateRange( ( ( uint32_t ) pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( uint32_t ) dmaRX_TX_BUFFER_SIZE );\r
                        }\r
                        {\r
                                uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
@@ -422,8 +433,10 @@ int head = xemacpsif->rxHead;
                                        addr |= XEMACPS_RXBUF_WRAP_MASK;\r
                                }\r
                                /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
-                               xemacpsif->rxSegments[ head ].address = addr;\r
                                xemacpsif->rxSegments[ head ].flags = 0;\r
+                               xemacpsif->rxSegments[ head ].address = addr;\r
+                               /* Make sure that the value has reached the peripheral by reading it back. */\r
+                               ( void ) xemacpsif->rxSegments[ head ].address;\r
                        }\r
                }\r
 \r
@@ -434,10 +447,14 @@ int head = xemacpsif->rxHead;
                xemacpsif->rxHead = head;\r
        }\r
 \r
-       if( ethMsg != NULL )\r
+       #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
        {\r
-               passEthMessages( );\r
+               if( pxFirstDescriptor != NULL )\r
+               {\r
+                       prvPassEthMessages( pxFirstDescriptor );\r
+               }\r
        }\r
+       #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
 \r
        return msgCount;\r
 }\r
@@ -455,11 +472,7 @@ unsigned char *ucTxBuffer;
        {\r
                xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
                xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               pxDMA_tx_buffers[ index ] = ( void* )NULL;\r
-#else\r
-               pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );\r
-#endif\r
+               pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;\r
                ucTxBuffer += xemacpsif->uTxUnitSize;\r
        }\r
        xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
@@ -479,8 +492,7 @@ XStatus init_dma(xemacpsif_s *xemacpsif)
 \r
        xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
 \r
-       /* Also round-up to 4KB */\r
-       xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;\r
+       xemacpsif->uTxUnitSize = dmaRX_TX_BUFFER_SIZE;\r
        /*\r
         * We allocate 65536 bytes for RX BDs which can accommodate a\r
         * maximum of 8192 BDs which is much more than any application\r
@@ -507,7 +519,7 @@ XStatus init_dma(xemacpsif_s *xemacpsif)
                pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
                if( pxBuffer == NULL )\r
                {\r
-                       pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );\r
+                       pxBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );\r
                        if( pxBuffer == NULL )\r
                        {\r
                                FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
@@ -523,7 +535,7 @@ XStatus init_dma(xemacpsif_s *xemacpsif)
                if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
                {\r
                        Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
-                               (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);\r
+                               (unsigned)dmaRX_TX_BUFFER_SIZE );\r
                }\r
        }\r
 \r