/* 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 + 1\r
+#define macNUM_BUFFERS RX_RING_SIZE + TX_RING_SIZE\r
#define macBUFFER_SIZE 1488\r
\r
/***************************************************************/\r
configASSERT( usLength <= MSS_MAX_PACKET_SIZE );\r
}\r
\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[ 0 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) || ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) )\r
+ taskENTER_CRITICAL();\r
{\r
- error = MAC_BUFFER_IS_FULL;\r
+ /* Check both Tx descriptors are free, meaning the double send has completed. */\r
+ if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) || ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == TDES0_OWN ) )\r
+ {\r
+ error = MAC_BUFFER_IS_FULL;\r
+ }\r
}\r
+ taskEXIT_CRITICAL();\r
\r
+ configASSERT( ( g_mss_mac.tx_desc_index == 0 ) );\r
\r
if( error == MAC_OK )\r
{\r
+ /* Ensure nothing is going to get sent until both descriptors are ready.\r
+ This is done to prevent a Tx end occurring prior to the second descriptor\r
+ being ready. */\r
+ MAC_BITBAND->CSR6_ST = 0u;\r
+\r
/* Assumed TX_RING_SIZE == 2. A #error directive checks this is the\r
case. */\r
- for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )\r
+ taskENTER_CRITICAL();\r
{\r
- g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;\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
-\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 | TDES1_IC;\r
-\r
- /* set data size */\r
- g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= usLength;\r
-\r
- /* reset end of ring */\r
- g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;\r
-\r
- if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */\r
+ for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )\r
{\r
- usLength = (uint16_t)MSS_TX_BUFF_SIZE;\r
- }\r
-\r
- /* The data buffer is assigned to the Tx descriptor. */\r
- g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) uip_buf;\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
-\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
- \r
- g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;\r
- \r
- MAC_start_transmission();\r
- MAC->CSR1 = 1u;\r
- } \r
+ g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;\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
+ \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
+ \r
+ /* set data size */\r
+ g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= usLength;\r
+ \r
+ /* reset end of ring */\r
+ g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;\r
+ \r
+ if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */\r
+ {\r
+ usLength = (uint16_t)MSS_TX_BUFF_SIZE;\r
+ }\r
+ \r
+ /* The data buffer is assigned to the Tx descriptor. */\r
+ g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) uip_buf;\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
+ \r
+ /* Give ownership of descriptor to the MAC */\r
+ g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0 = TDES0_OWN;\r
+ \r
+ g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;\r
+ } \r
+ }\r
+ taskEXIT_CRITICAL();\r
}\r
\r
if (error == MAC_OK)\r
{\r
error = (int32_t)usLength;\r
\r
+ /* Start sending now both descriptors are set up. This is done to\r
+ prevent a Tx end occurring prior to the second descriptor being\r
+ ready. */\r
+ MAC_BITBAND->CSR6_ST = 1u;\r
+ MAC->CSR1 = 1u;\r
+ \r
/* The buffer pointed to by uip_buf is now assigned to a Tx descriptor.\r
Find anothere free buffer for uip_buf. */\r
uip_buf = MAC_obtain_buffer();\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 pacData The pointer to the packet data.\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
(desc & (CSR8_MFO_MASK|CSR8_MFC_MASK));\r
\r
/* Give ownership of descriptor to the MAC */\r
- g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 =\r
- RDES0_OWN;\r
+ g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 = RDES0_OWN;\r
g_mss_mac.rx_desc_index = (g_mss_mac.rx_desc_index + 1u) % RX_RING_SIZE;\r
\r
/* Start receive */\r
*/\r
void MSS_MAC_FreeTxBuffers( void )\r
{\r
- if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == 0 ) && ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == 0 ) )\r
+ /* Check the buffers have not already been freed in the first of the\r
+ two Tx interrupts - which could potentially happen if the second Tx completed\r
+ during the interrupt for the first Tx. */\r
+ if( g_mss_mac.tx_descriptors[ 0 ].buffer_1 != NULL )\r
{\r
- MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 0 ].buffer_1 );\r
- MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 1 ].buffer_1 );\r
+ if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == 0 ) && ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == 0 ) )\r
+ {\r
+ configASSERT( g_mss_mac.tx_descriptors[ 0 ].buffer_1 == g_mss_mac.tx_descriptors[ 1 ].buffer_1 );\r
+ MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 0 ].buffer_1 );\r
+ \r
+ /* Just to mark the fact that the buffer has already been released. */\r
+ g_mss_mac.tx_descriptors[ 0 ].buffer_1 == NULL;\r
+ }\r
}\r
}\r
\r
*/\r
unsigned char *MAC_obtain_buffer( void )\r
{\r
-long lIndex;\r
+long lIndex, lAttempt = 0, lDescriptor, lBufferIsInUse;\r
unsigned char *pcReturn = NULL;\r
+unsigned char *pcBufferAddress;\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
+ while( ( lAttempt <= 1 ) && ( pcReturn == NULL ) )\r
{\r
- if( ucMACBufferInUse[ lIndex ] == pdFALSE )\r
+ for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )\r
{\r
- pcReturn = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );\r
- ucMACBufferInUse[ lIndex ] = pdTRUE;\r
- break;\r
+ if( ucMACBufferInUse[ lIndex ] == pdFALSE )\r
+ {\r
+ pcReturn = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );\r
+ ucMACBufferInUse[ lIndex ] = pdTRUE;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if( pcReturn == NULL )\r
+ {\r
+ /* Did not find a buffer. That should not really happen, but could if\r
+ an interrupt was missed. See if any buffers are marked as in use, but\r
+ are not actually in use. */\r
+ for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )\r
+ {\r
+ pcBufferAddress = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );\r
+ lBufferIsInUse = pdFALSE;\r
+ \r
+ /* Is the buffer used by an Rx descriptor? */\r
+ for( lDescriptor = 0; lDescriptor < RX_RING_SIZE; lDescriptor++ )\r
+ {\r
+ if( g_mss_mac.rx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )\r
+ {\r
+ /* The buffer is in use by an Rx descriptor. */\r
+ lBufferIsInUse = pdTRUE;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if( lBufferIsInUse != pdTRUE )\r
+ {\r
+ /* Is the buffer used by an Tx descriptor? */\r
+ for( lDescriptor = 0; lDescriptor < TX_RING_SIZE; lDescriptor++ )\r
+ {\r
+ if( g_mss_mac.tx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )\r
+ {\r
+ /* The buffer is in use by an Tx descriptor. */\r
+ lBufferIsInUse = pdTRUE;\r
+ break;\r
+ }\r
+ } \r
+ }\r
+ \r
+ /* If the buffer was not found to be in use by either a Tx or an\r
+ Rx descriptor, but the buffer is marked as in use, then mark the\r
+ buffer to be in it's correct state of "not in use". */\r
+ if( ( lBufferIsInUse == pdFALSE ) && ( ucMACBufferInUse[ lIndex ] == pdTRUE ) )\r
+ {\r
+ ucMACBufferInUse[ lIndex ] = pdFALSE;\r
+ }\r
+ }\r
}\r
+ \r
+ /* If any buffer states were changed it might be that a buffer can now\r
+ be obtained. Try again, but only one more time. */\r
+ lAttempt++;\r
}\r
\r
configASSERT( pcReturn );\r