]> git.sur5r.net Git - freertos/blobdiff - Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/mss_ethernet_mac/mss_ethernet_mac.c
Continue work on the SmartFusion web server demo.
[freertos] / Demo / CORTEX_A2F200_SoftConsole / MicroSemi_Code / drivers / mss_ethernet_mac / mss_ethernet_mac.c
index 014ce512ceb57f7bb89a2a1f84c5f38f5223f0ba..3b85fd65b83f7a9d957bc7bffde4efd5b82f6da6 100644 (file)
@@ -51,6 +51,12 @@ extern "C" {
 #define MAC_TIME_OUT                     (-6)\r
 #define MAC_TOO_SMALL_PACKET      (-7)\r
 \r
+/* Allocating this many buffers will always ensure there is one free as, even\r
+though TX_RING_SIZE is set to two, the two Tx descriptors will only ever point\r
+to the same buffer. */\r
+#define macNUM_BUFFERS RX_RING_SIZE + TX_RING_SIZE\r
+#define macBUFFER_SIZE 1500\r
+\r
 /***************************************************************/\r
 MAC_instance_t g_mss_mac;\r
 \r
@@ -75,6 +81,7 @@ static const int8_t ErrorMessages[][MAX_ERROR_MESSAGE_WIDTH] = {
 static MAC_instance_t*         NULL_instance;\r
 static uint8_t*                NULL_buffer;\r
 static MSS_MAC_callback_t      NULL_callback;\r
+unsigned char *uip_buf = NULL;\r
 \r
 /**************************** INTERNAL FUNCTIONS ******************************/\r
 \r
@@ -95,6 +102,20 @@ static void     MAC_memset(uint8_t *s, uint8_t c, uint32_t n);
 static void     MAC_memcpy(uint8_t *dest, const uint8_t *src, uint32_t n);\r
 static void     MAC_memset_All(MAC_instance_t *s, uint32_t c);\r
 \r
+static unsigned char *MAC_obtain_buffer( void );\r
+static void MAC_release_buffer( unsigned char *pcBufferToRelease );\r
+\r
+#if( TX_RING_SIZE != 2 )\r
+       #error This uIP Ethernet driver required TX_RING_SIZE to be set to 2\r
+#endif\r
+\r
+/* Buffers that will dynamically be allocated to/from the Tx and Rx descriptors. */\r
+static unsigned char ucMACBuffers[ macNUM_BUFFERS ][ macBUFFER_SIZE ];\r
+\r
+/* Each array position indicated whether or not the buffer of the same index\r
+is currently allocated to a descriptor (pdFALSE) or is free for use (pdTRUE). */\r
+static unsigned char ucMACBufferFree[ macNUM_BUFFERS ];\r
+\r
 /***************************************************************************//**\r
  * Initializes the Ethernet Controller.\r
  * This function will prepare the Ethernet Controller for first time use in a\r
@@ -114,6 +135,12 @@ MSS_MAC_init
     const uint8_t mac_address[6] = { DEFAULT_MAC_ADDRESS };\r
     int32_t a;\r
 \r
+       /* To start with all buffers are free. */\r
+       for( a = 0; a < macNUM_BUFFERS; a++ )\r
+       {\r
+               ucMACBufferFree[ a ] = pdTRUE;\r
+       }\r
+       \r
     /* Try to reset chip */\r
     MAC_BITBAND->CSR0_SWR = 1u;\r
 \r
@@ -139,13 +166,19 @@ MSS_MAC_init
         /* Give the ownership to the MAC */\r
         g_mss_mac.rx_descriptors[a].descriptor_0 = RDES0_OWN;\r
         g_mss_mac.rx_descriptors[a].descriptor_1 = (MSS_RX_BUFF_SIZE << RDES1_RBS1_OFFSET);\r
-        g_mss_mac.rx_descriptors[a].buffer_1 = (uint32_t)g_mss_mac.rx_buffers[a];\r
+               \r
+               /* Allocate a buffer to the descriptor, then mark the buffer as in use\r
+               (not free). */\r
+        g_mss_mac.rx_descriptors[a].buffer_1 = ( unsigned long ) &( ucMACBuffers[ a ][ 0 ] );\r
+               ucMACBufferFree[ a ] = pdFALSE;\r
     }\r
     g_mss_mac.rx_descriptors[RX_RING_SIZE-1].descriptor_1 |= RDES1_RER;\r
 \r
     for( a = 0; a < TX_RING_SIZE; a++ )\r
     {\r
-        g_mss_mac.tx_descriptors[a].buffer_1 = ( unsigned long ) NULL; /* _RB_ used to be "(uint32_t)g_mss_mac.tx_buffers[a];" but set to NULL now to implement a zero copy scheme. */\r
+               /* Buffers only get allocated to the Tx buffers when something is\r
+               actually tranmitted. */\r
+        g_mss_mac.tx_descriptors[a].buffer_1 = ( unsigned long ) NULL;\r
     }\r
     g_mss_mac.tx_descriptors[TX_RING_SIZE - 1].descriptor_1 |= TDES1_TER;\r
 \r
@@ -343,31 +376,13 @@ MSS_MAC_get_configuration( void )
 \r
 \r
 /***************************************************************************//**\r
-  Sends a packet to the Ethernet Controller.\r
+  Sends a packet from the uIP stack to the Ethernet Controller.\r
   The MSS_MAC_tx_packet() function is used to send a packet to the MSS Ethernet\r
-  MAC. This function writes pacLen bytes of the packet contained in pacData into\r
+  MAC. This function writes uip_len bytes of the packet contained in uip_buf into\r
   the transmit FIFO and then activates the transmitter for this packet. If space\r
-  is available in the FIFO, the function will return once pacLen bytes of the\r
+  is available in the FIFO, the function will return once pac_len bytes of the\r
   packet have been placed into the FIFO and the transmitter has been started.\r
-  This function will not wait for the transmission to complete. If space is not\r
-  available in FIFO, the function will keep trying until time_out expires. The\r
-  function will wait for the transmission to complete when the time_out parameter\r
-  is set to MSS_MAC_BLOCKING.\r
\r
-  @param pacData\r
-    The pacData parameter is a pointer to the packet data to be transmitted.\r
-    \r
-  @param pacLen\r
-    The pacLen parameter is the number of bytes in the packet to be transmitted.\r
-    \r
-  @param time_out\r
-    The time_out parameter is the timeout value for the transmission in milliseconds.\r
-    The time_out parameter value can be one of the following values:\r
-    \95 Unsigned integer greater than 0 and less than 0x01000000\r
-    \95 MSS_MAC_BLOCKING \96 there will be no timeout. \r
-    \95 MSS_MAC_NONBLOCKING \96 the function will return immediately if the MSS Ethernet\r
-      MAC does not have any available transmit descriptor. This would happen when\r
-      several packets are already queued into the MSS Ethernet MAC transmit descriptor FIFO.\r
+  This function will not wait for the transmission to complete. \r
 \r
   @return\r
     The function returns zero if a timeout occurs otherwise it returns size of the packet.\r
@@ -378,119 +393,101 @@ MSS_MAC_get_configuration( void )
 int32_t\r
 MSS_MAC_tx_packet\r
 (\r
-    const uint8_t *pacData,\r
-    uint16_t pacLen,\r
-    uint32_t time_out\r
+    unsigned short usLength\r
 )\r
 {\r
        uint32_t desc;\r
+       unsigned long ulDescriptor;\r
     int32_t error = MAC_OK;\r
+       extern unsigned char *uip_buf;\r
 \r
     ASSERT( MAC_test_instance() == MAC_OK );\r
 \r
-    ASSERT( pacData != NULL_buffer );\r
+    ASSERT( uip_buf != NULL_buffer );\r
 \r
-       ASSERT( pacLen >= 12 );\r
+       ASSERT( usLength >= 12 );\r
 \r
     if( (g_mss_mac.flags & FLAG_EXCEED_LIMIT) == 0u )\r
     {\r
-               ASSERT( pacLen <= MSS_MAX_PACKET_SIZE );\r
+               ASSERT( usLength <= MSS_MAX_PACKET_SIZE );\r
        }\r
 \r
-    ASSERT(  (time_out == MSS_MAC_BLOCKING) ||\r
-                       (time_out == MSS_MAC_NONBLOCKING) ||\r
-                       ((time_out >= 1) && (time_out <= 0x01000000uL)) );\r
-\r
-    if( time_out == MSS_MAC_NONBLOCKING )\r
-    {\r
-       /* Check if current descriptor is free */\r
-       if(((g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0) & TDES0_OWN) == TDES0_OWN )\r
-        {\r
-                       error = MAC_BUFFER_IS_FULL;\r
-       }\r
-    }\r
-    else\r
+       /* Check if second descriptor is free, if it is then the first must\r
+       also be free. */\r
+       if(((g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == TDES0_OWN )\r
        {\r
-           /* Wait until descriptor is free */\r
-           if( time_out != MSS_MAC_BLOCKING ) {\r
-           MAC_set_time_out( time_out );\r
-           }\r
-        \r
-        while( (((g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0) & TDES0_OWN) == TDES0_OWN )\r
-                && (error == MAC_OK) )\r
-           {\r
-                    /* transmit poll demand */\r
-            MAC->CSR1 = 1u;\r
-            \r
-               if(time_out != MSS_MAC_BLOCKING){\r
-                       if(MAC_get_time_out() == 0u) {\r
-                               error = MAC_TIME_OUT;\r
-                       }\r
-               }\r
-           }\r
+               error = MAC_BUFFER_IS_FULL;\r
        }\r
 \r
        if( error == MAC_OK ) {\r
+               /* Assumed TX_RING_SIZE == 2. */\r
+               for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )\r
+               {\r
+                       g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_1 = 0u;\r
 \r
-               g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;\r
+                       if( (g_mss_mac.flags & FLAG_CRC_DISABLE) != 0u ) {\r
+                               g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_1 |= TDES1_AC;\r
+                       }\r
 \r
-               if( (g_mss_mac.flags & FLAG_CRC_DISABLE) != 0u ) {\r
-                       g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |=     TDES1_AC;\r
-               }\r
+                       /* Every buffer can hold a full frame so they are always first and last\r
+                          descriptor */\r
+                       g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_1 |= TDES1_LS | TDES1_FS;\r
 \r
-        /* Every buffer can hold a full frame so they are always first and last\r
-           descriptor */\r
-        g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_LS | TDES1_FS;\r
+                       /* set data size */\r
+                       g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_1 |= usLength;\r
 \r
-        /* set data size */\r
-        g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= pacLen;\r
+                       /* reset end of ring */\r
+                       g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;\r
 \r
-        /* reset end of ring */\r
-        g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;\r
+                       if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */\r
+                       {\r
+                               usLength = (uint16_t)MSS_TX_BUFF_SIZE;\r
+                       }\r
 \r
-        /* copy data into buffer */\r
-        if( pacLen > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */\r
-        {\r
-               pacLen = (uint16_t)MSS_TX_BUFF_SIZE;\r
-        }\r
+                       /* The data buffer is assigned to the Tx descriptor. */\r
+                       g_mss_mac.tx_descriptors[ ulDescriptor ].buffer_1 = ( unsigned long ) uip_buf;\r
 \r
-        g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) pacData;\r
+                       /* update counters */\r
+                       desc = g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_0;\r
+                       if( (desc & TDES0_LO) != 0u ) {\r
+                               g_mss_mac.statistics.tx_loss_of_carrier++;\r
+                       }\r
+                       if( (desc & TDES0_NC) != 0u ) {\r
+                               g_mss_mac.statistics.tx_no_carrier++;\r
+                       }\r
+                       if( (desc & TDES0_LC) != 0u ) {\r
+                               g_mss_mac.statistics.tx_late_collision++;\r
+                       }\r
+                       if( (desc & TDES0_EC) != 0u ) {\r
+                               g_mss_mac.statistics.tx_excessive_collision++;\r
+                       }\r
+                       if( (desc & TDES0_UF) != 0u ) {\r
+                               g_mss_mac.statistics.tx_underflow_error++;\r
+                       }\r
+                       g_mss_mac.statistics.tx_collision_count +=\r
+                               (desc >> TDES0_CC_OFFSET) & TDES0_CC_MASK;\r
 \r
-        /* update counters */\r
-        desc = g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0;\r
-        if( (desc & TDES0_LO) != 0u ) {\r
-               g_mss_mac.statistics.tx_loss_of_carrier++;\r
-        }\r
-        if( (desc & TDES0_NC) != 0u ) {\r
-               g_mss_mac.statistics.tx_no_carrier++;\r
-        }\r
-        if( (desc & TDES0_LC) != 0u ) {\r
-               g_mss_mac.statistics.tx_late_collision++;\r
-        }\r
-        if( (desc & TDES0_EC) != 0u ) {\r
-               g_mss_mac.statistics.tx_excessive_collision++;\r
-        }\r
-        if( (desc & TDES0_UF) != 0u ) {\r
-               g_mss_mac.statistics.tx_underflow_error++;\r
-        }\r
-        g_mss_mac.statistics.tx_collision_count +=\r
-               (desc >> TDES0_CC_OFFSET) & TDES0_CC_MASK;\r
+                       /* Give ownership of descriptor to the MAC */\r
+                       g_mss_mac.tx_descriptors[ ulDescriptor ].descriptor_0 = TDES0_OWN;\r
 \r
-        /* Give ownership of descriptor to the MAC */\r
-        g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0 = RDES0_OWN;\r
+                       g_mss_mac.tx_desc_index = 0; \r
+               }\r
+    }\r
 \r
-        g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;\r
+       /* Start transmission */\r
+       MAC_start_transmission();\r
 \r
-        /* Start transmission */\r
-        MAC_start_transmission();\r
+       /* transmit poll demand */\r
+       MAC->CSR1 = 1u;\r
 \r
-        /* transmit poll demand */\r
-        MAC->CSR1 = 1u;\r
-    }\r
-    \r
+       \r
+       \r
     if (error == MAC_OK)\r
     {\r
-        error = (int32_t)pacLen;\r
+               /* The buffer uip_buf was pointing to is now under the control of the \r
+               MAC (it is being transmitted).  Set uip_buf to point to a free buffer. */\r
+               uip_buf = MAC_obtain_buffer();\r
+        error = (int32_t)usLength;\r
     }\r
     else\r
     {\r
@@ -535,24 +532,11 @@ MSS_MAC_rx_pckt_size
 \r
 \r
 /***************************************************************************//**\r
- * Receives a packet from the Ethernet Controller.\r
+ * Receives a packet from the Ethernet Controller into the uIP stack.\r
  * This function reads a packet from the receive FIFO of the controller and\r
- * places it into pacData. If time_out parameter is zero the function will return\r
- * immediately (after the copy operation if data is available. Otherwise the function\r
- * will keep trying to read till time_out expires or data is read, if MSS_MAC_BLOCKING\r
- * value is given as time_out, function will wait for the reception to complete.\r
- *\r
- * @param instance      Pointer to a MAC_instance_t structure\r
- * @param pacData       The pointer to the packet data.\r
- * @param pacLen        The pacLen parameter is the size in bytes of the pacData\r
- *                      buffer where the received data will be copied.\r
- * @param time_out      Time out value in milli seconds for receiving.\r
- *                                         if value is #MSS_MAC_BLOCKING, there will be no time out.\r
- *                                         if value is #MSS_MAC_NONBLOCKING, function will return immediately\r
- *                                         if there is no packet waiting.\r
- *                                         Otherwise value must be greater than 0 and smaller than\r
- *                                         0x01000000.\r
- * @return              Size of packet if packet fits in pacData.\r
+ * places it into uip_buf.\r
\r
+ * @return              Size of packet if packet fits in uip_buf.\r
  *                                         0 if there is no received packet.\r
  * @see   MAC_rx_pckt_size()\r
  * @see   MAC_tx_packet()\r
@@ -560,42 +544,16 @@ MSS_MAC_rx_pckt_size
 int32_t\r
 MSS_MAC_rx_packet\r
 (\r
-    unsigned char **pacData,\r
-    uint16_t pacLen,\r
-    uint32_t time_out\r
+       void\r
 )\r
 {\r
        uint16_t frame_length=0u;\r
-    int8_t exit=0;\r
 \r
     ASSERT( MAC_test_instance() == MAC_OK );\r
-    ASSERT(  (time_out == MSS_MAC_BLOCKING) ||\r
-                       (time_out == MSS_MAC_NONBLOCKING) ||\r
-                       ((time_out >= 1) && (time_out <= 0x01000000UL)) );\r
-\r
+    \r
     MAC_dismiss_bad_frames();\r
 \r
-    /* wait for a packet */\r
-       if( time_out != MSS_MAC_BLOCKING ) {\r
-               if( time_out == MSS_MAC_NONBLOCKING ) {\r
-               MAC_set_time_out( 0u );\r
-               } else {\r
-               MAC_set_time_out( time_out );\r
-               }\r
-       }\r
-\r
-    while( ((g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 &\r
-       RDES0_OWN) != 0u) && (exit == 0) )\r
-    {\r
-       if( time_out != MSS_MAC_BLOCKING )\r
-       {\r
-               if( MAC_get_time_out() == 0u ) {\r
-                       exit = 1;\r
-               }\r
-       }\r
-    }\r
-\r
-    if(exit == 0)\r
+    if( (g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 & RDES0_OWN) == 0u )\r
     {\r
         frame_length = ( (\r
            g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 >>\r
@@ -604,14 +562,21 @@ MSS_MAC_rx_packet
         /* strip crc */\r
         frame_length -= 4u;\r
 \r
-        if( frame_length > pacLen ) {\r
+        if( frame_length > macBUFFER_SIZE ) {\r
                return MAC_NOT_ENOUGH_SPACE;\r
         }\r
        \r
-        *pacData = ( unsigned char * ) g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1;\r
+               /* uip_buf is about to point to the buffer that contains the received\r
+               data, mark the buffer that uip_buf is currently pointing to as free\r
+               again. */\r
+               MAC_release_buffer( uip_buf );\r
+        uip_buf = ( unsigned char * ) g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1;\r
+               \r
+               /* The buffer the Rx descriptor was pointing to is now in use by the\r
+               uIP stack - allocate a new buffer to the Rx descriptor. */\r
+               g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1 = ( unsigned long ) MAC_obtain_buffer();\r
 \r
         MSS_MAC_prepare_rx_descriptor();\r
-       \r
     }\r
     return ((int32_t)frame_length);\r
 }\r
@@ -1444,10 +1409,10 @@ static void MAC_memset_All(MAC_instance_t *s, uint32_t c)
        MAC_memset( s->mac_address, (uint8_t)c, 6u );\r
        MAC_memset( s->mac_filter_data, (uint8_t)c, 90u );\r
     s->phy_address = (uint8_t)c;\r
-    for(count = 0; count<RX_RING_SIZE ;count++)\r
-    {\r
-        MAC_memset(s->rx_buffers[count], (uint8_t)c, (MSS_RX_BUFF_SIZE + 4u) );\r
-    }\r
+//    for(count = 0; count<RX_RING_SIZE ;count++)\r
+//    {\r
+//        MAC_memset(s->rx_buffers[count], (uint8_t)c, (MSS_RX_BUFF_SIZE + 4u) );\r
+//    }\r
     s->rx_desc_index =c;\r
     for(count = 0; count<RX_RING_SIZE ;count++)\r
     {\r
@@ -1475,10 +1440,10 @@ static void MAC_memset_All(MAC_instance_t *s, uint32_t c)
     s->statistics.tx_no_carrier = c;\r
     s->statistics.tx_underflow_error = c;\r
     s->time_out_value = c;\r
-    for(count = 0; count < TX_RING_SIZE ;count++)\r
-    {\r
-        MAC_memset( s->tx_buffers[count], (uint8_t)c, MSS_TX_BUFF_SIZE );\r
-    }\r
+//    for(count = 0; count < TX_RING_SIZE ;count++)\r
+//    {\r
+//        MAC_memset( s->tx_buffers[count], (uint8_t)c, MSS_TX_BUFF_SIZE );\r
+//    }\r
     s->tx_desc_index = c;\r
     for(count = 0; count < TX_RING_SIZE ;count++)\r
     {\r
@@ -1505,6 +1470,59 @@ static void MAC_memcpy(uint8_t *dest, const uint8_t *src, uint32_t n)
     }\r
 }\r
 \r
+void MSS_MAC_TxBufferCompleted( void )\r
+{\r
+unsigned char *pxTransmittedBuffer;\r
+\r
+       /* Was it the second transmission that has completed? */\r
+       if( ( g_mss_mac.tx_descriptors[ 1 ].descriptor_0 & TDES0_OWN ) == 0UL )\r
+       {\r
+               pxTransmittedBuffer = ( unsigned char * ) g_mss_mac.tx_descriptors[ 1 ].buffer_1;\r
+\r
+               /* The buffer has been transmitted and is no longer in use. */\r
+               MAC_release_buffer( pxTransmittedBuffer );\r
+       }\r
+}\r
+\r
+static unsigned char *MAC_obtain_buffer( void )\r
+{\r
+long lIndex;\r
+unsigned char *pcReturn = NULL;\r
+\r
+       /* Find and return the address of a buffer that is not being used.  Mark\r
+       the buffer as now in use. */\r
+       for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )\r
+       {\r
+               if( ucMACBufferFree[ lIndex ] == pdTRUE )\r
+               {\r
+                       pcReturn = &( ucMACBuffers[ lIndex ][ 0 ] );\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       configASSERT( pcReturn );\r
+       return pcReturn;\r
+}\r
+\r
+void MAC_release_buffer( unsigned char *pucBufferToRelease )\r
+{\r
+long lIndex;\r
+\r
+       /* uip_buf is going to point to a different buffer - first ensure the buffer\r
+       it is currently pointing to is marked as being free again. */\r
+       for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )\r
+       {\r
+               if( pucBufferToRelease == &( ucMACBuffers[ lIndex ][ 0 ] ) )\r
+               {\r
+                       /* This is the buffer in use, mark it as being free. */\r
+                       ucMACBufferFree[ lIndex ] = pdTRUE;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
 #ifdef __cplusplus\r
 }\r
 #endif\r