blob: 2b73d065784f77f3ac8a671c928f659bf568876b [file] [log] [blame]
/***************************************************************************//**
* @file
* SmartFusion MSS Ethernet MAC driver implementation.
*
* (c) Copyright 2007 Actel Corporation
*
* SVN $Revision: 2369 $
* SVN $Date: 2010-03-01 18:31:45 +0000 (Mon, 01 Mar 2010) $
*
******************************************************************************/
/*
*
*
* NOTE: This driver has been modified specifically for use with the* uIP stack.
* It is no longer a generic driver.
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "crc32.h"
#include "mss_ethernet_mac.h"
#include "mss_ethernet_mac_regs.h"
#include "mss_ethernet_mac_desc.h"
#include "mss_ethernet_mac_conf.h"
#include "../../CMSIS/mss_assert.h"
#include "phy.h"
/**************************** INTERNAL DEFINES ********************************/
#define MAC_CHECK(CHECK,ERRNO) \
{if(!(CHECK)){g_mss_mac.last_error=(ERRNO); configASSERT((CHECK));}}
/*
* Flags
*/
#define FLAG_MAC_INIT_DONE 1u
#define FLAG_PERFECT_FILTERING 2u
#define FLAG_CRC_DISABLE 4u
#define FLAG_EXCEED_LIMIT 8u
/*
* Return types
*/
#define MAC_OK 0
#define MAC_FAIL (-1)
#define MAC_WRONG_PARAMETER (-2)
#define MAC_TOO_BIG_PACKET (-3)
#define MAC_BUFFER_IS_FULL (-4)
#define MAC_NOT_ENOUGH_SPACE (-5)
#define MAC_TIME_OUT (-6)
#define MAC_TOO_SMALL_PACKET (-7)
/* Allocating this many buffers will always ensure there is one free as, even
though TX_RING_SIZE is set to two, the two Tx descriptors will only ever point
to the same buffer. */
#define macNUM_BUFFERS RX_RING_SIZE + TX_RING_SIZE
#define macBUFFER_SIZE 1488
/***************************************************************/
MAC_instance_t g_mss_mac;
/**************************** INTERNAL DATA ***********************************/
#define ERROR_MESSAGE_COUNT 8
#define MAX_ERROR_MESSAGE_WIDTH 40
static const int8_t unknown_error[] = "Unknown error";
static const int8_t ErrorMessages[][MAX_ERROR_MESSAGE_WIDTH] = {
"No error occured",
"Method failed",
"Wrong parameter pased to function",
"Frame is too long",
"Not enough space in buffer",
"Not enough space in buffer",
"Timed out",
"Frame is too small"
};
/*
* Null variables
*/
static uint8_t* NULL_buffer;
static MSS_MAC_callback_t NULL_callback;
/* Declare the uip_buf as a pointer, rather than the traditional array, as this
is a zero copy driver. uip_buf just gets set to whichever buffer is being
processed. */
unsigned char *uip_buf = NULL;
/**************************** INTERNAL FUNCTIONS ******************************/
static int32_t MAC_dismiss_bad_frames( void );
static int32_t MAC_send_setup_frame( void );
static int32_t MAC_stop_transmission( void );
static void MAC_start_transmission( void );
static int32_t MAC_stop_receiving( void );
static void MAC_start_receiving( void );
static void MAC_set_time_out( uint32_t time_out );
static uint32_t MAC_get_time_out( void );
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);
static void MAC_memset_All(MAC_instance_t *s, uint32_t c);
static unsigned char *MAC_obtain_buffer( void );
static void MAC_release_buffer( unsigned char *pcBufferToRelease );
#if( TX_RING_SIZE != 2 )
#error This uIP Ethernet driver required TX_RING_SIZE to be set to 2
#endif
/* Buffers that will dynamically be allocated to/from the Tx and Rx descriptors.
The union is used for alignment only. */
static union xMAC_BUFFERS
{
unsigned long ulAlignmentVariable; /* For alignment only, not used anywhere. */
unsigned char ucBuffer[ macNUM_BUFFERS ][ macBUFFER_SIZE ];
} xMACBuffers;
/* Each array position indicates whether or not the buffer of the same index
is currently allocated to a descriptor (pdTRUE) or is free for use (pdFALSE). */
static unsigned char ucMACBufferInUse[ macNUM_BUFFERS ] = { 0 };
/***************************************************************************//**
* Initializes the Ethernet Controller.
* This function will prepare the Ethernet Controller for first time use in a
* given hardware/software configuration. This function should be called before
* any other Ethernet API functions are called.
*
* Initialization of registers - config registers, enable Tx/Rx interrupts,
* enable Tx/Rx, initialize MAC addr, init PHY, autonegotiation, MAC address
* filter table (unicats/multicast)/hash init
*/
void
MSS_MAC_init
(
uint8_t phy_address
)
{
const uint8_t mac_address[6] = { DEFAULT_MAC_ADDRESS };
int32_t a;
/* To start with all buffers are free. */
for( a = 0; a < macNUM_BUFFERS; a++ )
{
ucMACBufferInUse[ a ] = pdFALSE;
}
/* Try to reset chip */
MAC_BITBAND->CSR0_SWR = 1u;
do
{
vTaskDelay( 10 );
} while ( 1u == MAC_BITBAND->CSR0_SWR );
/* Check reset values of some registers to constrol
* base address validity */
configASSERT( MAC->CSR0 == 0xFE000000uL );
configASSERT( MAC->CSR5 == 0xF0000000uL );
configASSERT( MAC->CSR6 == 0x32000040uL );
/* Instance setup */
MAC_memset_All( &g_mss_mac, 0u );
g_mss_mac.base_address = MAC_BASE;
g_mss_mac.phy_address = phy_address;
for( a=0; a<RX_RING_SIZE; a++ )
{
/* Give the ownership to the MAC */
g_mss_mac.rx_descriptors[a].descriptor_0 = RDES0_OWN;
g_mss_mac.rx_descriptors[a].descriptor_1 = (MSS_RX_BUFF_SIZE << RDES1_RBS1_OFFSET);
/* Allocate a buffer to the descriptor, then mark the buffer as in use
(not free). */
g_mss_mac.rx_descriptors[a].buffer_1 = ( unsigned long ) &( xMACBuffers.ucBuffer[ a ][ 0 ] );
ucMACBufferInUse[ a ] = pdTRUE;
}
g_mss_mac.rx_descriptors[RX_RING_SIZE-1].descriptor_1 |= RDES1_RER;
for( a = 0; a < TX_RING_SIZE; a++ )
{
/* Buffers only get allocated to the Tx buffers when something is
actually tranmitted. */
g_mss_mac.tx_descriptors[a].buffer_1 = ( unsigned long ) NULL;
}
g_mss_mac.tx_descriptors[TX_RING_SIZE - 1].descriptor_1 |= TDES1_TER;
/* Configurable settings */
MAC_BITBAND->CSR0_DBO = DESCRIPTOR_BYTE_ORDERING_MODE;
MAC->CSR0 = (MAC->CSR0 & ~CSR0_PBL_MASK) | ((uint32_t)PROGRAMMABLE_BURST_LENGTH << CSR0_PBL_SHIFT);
MAC_BITBAND->CSR0_BLE = BUFFER_BYTE_ORDERING_MODE;
MAC_BITBAND->CSR0_BAR = (uint32_t)BUS_ARBITRATION_SCHEME;
/* Fixed settings */
/* No space between descriptors */
MAC->CSR0 = MAC->CSR0 &~ CSR0_DSL_MASK;
/* General-purpose timer works in continuous mode */
MAC_BITBAND->CSR11_CON = 1u;
/* Start general-purpose */
MAC->CSR11 = (MAC->CSR11 & ~CSR11_TIM_MASK) | (0x0000FFFFuL << CSR11_TIM_SHIFT);
/* Ensure promiscous mode is off (it should be by default anyway). */
MAC_BITBAND->CSR6_PR = 0;
/* Perfect filter. */
MAC_BITBAND->CSR6_HP = 1;
/* Pass multcast. */
MAC_BITBAND->CSR6_PM = 1;
/* Set descriptors */
MAC->CSR3 = (uint32_t)&(g_mss_mac.rx_descriptors[0].descriptor_0);
MAC->CSR4 = (uint32_t)&(g_mss_mac.tx_descriptors[0].descriptor_0);
/* enable normal interrupts */
MAC_BITBAND->CSR7_NIE = 1u;
/* Set default MAC address and reset mac filters */
MAC_memcpy( g_mss_mac.mac_address, mac_address, 6u );
MSS_MAC_set_mac_address((uint8_t *)mac_address);
/* Detect PHY */
if( g_mss_mac.phy_address > MSS_PHY_ADDRESS_MAX )
{
PHY_probe();
configASSERT( g_mss_mac.phy_address <= MSS_PHY_ADDRESS_MAX );
}
/* Reset PHY */
PHY_reset();
/* Configure chip according to PHY status */
MSS_MAC_auto_setup_link();
/* Ensure uip_buf starts by pointing somewhere. */
uip_buf = MAC_obtain_buffer();
}
/***************************************************************************//**
* Sets the configuration of the Ethernet Controller.
* After the EthernetInit function has been called, this API function can be
* used to configure the various features of the Ethernet Controller.
*
* @param instance Pointer to a MAC_instance_t structure
* @param config The logical OR of the following values:
* - #MSS_MAC_CFG_RECEIVE_ALL
* - #MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE
* - #MSS_MSS_MAC_CFG_STORE_AND_FORWARD
* - #MAC_CFG_THRESHOLD_CONTROL_[00,01,10,11]
* - #MSS_MAC_CFG_FULL_DUPLEX_MODE
* - #MSS_MAC_CFG_PASS_ALL_MULTICAST
* - #MSS_MAC_CFG_PROMISCUOUS_MODE
* - #MSS_MAC_CFG_PASS_BAD_FRAMES
* @see MAC_get_configuration()
*/
void
MSS_MAC_configure
(
uint32_t configuration
)
{
int32_t ret;
ret = MAC_stop_transmission();
configASSERT( ret == MAC_OK );
ret = MAC_stop_receiving();
configASSERT( ret == MAC_OK );
MAC_BITBAND->CSR6_RA = (uint32_t)(((configuration & MSS_MAC_CFG_RECEIVE_ALL) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_TTM = (((configuration & MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_SF = (uint32_t)(((configuration & MSS_MAC_CFG_STORE_AND_FORWARD) != 0u) ? 1u : 0u );
switch( configuration & MSS_MAC_CFG_THRESHOLD_CONTROL_11 ) {
case MSS_MAC_CFG_THRESHOLD_CONTROL_00:
MAC->CSR6 = MAC->CSR6 & ~CSR6_TR_MASK;
break;
case MSS_MAC_CFG_THRESHOLD_CONTROL_01:
MAC->CSR6 = (MAC->CSR6 & ~CSR6_TR_MASK) | ((uint32_t)1 << CSR6_TR_SHIFT );
break;
case MSS_MAC_CFG_THRESHOLD_CONTROL_10:
MAC->CSR6 = (MAC->CSR6 & ~CSR6_TR_MASK) | ((uint32_t)2 << CSR6_TR_SHIFT );
break;
case MSS_MAC_CFG_THRESHOLD_CONTROL_11:
MAC->CSR6 = (MAC->CSR6 & ~CSR6_TR_MASK) | ((uint32_t)3 << CSR6_TR_SHIFT );
break;
default:
break;
}
MAC_BITBAND->CSR6_FD = (uint32_t)(((configuration & MSS_MAC_CFG_FULL_DUPLEX_MODE) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_PM = (uint32_t)(((configuration & MSS_MAC_CFG_PASS_ALL_MULTICAST) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_PR = (uint32_t)(((configuration & MSS_MAC_CFG_PROMISCUOUS_MODE) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_PB = (uint32_t)(((configuration & MSS_MAC_CFG_PASS_BAD_FRAMES) != 0u) ? 1u : 0u );
PHY_set_link_type( (uint8_t)
((((configuration & MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE) != 0u) ? MSS_MAC_LINK_STATUS_100MB : 0u ) |
(((configuration & MSS_MAC_CFG_FULL_DUPLEX_MODE) != 0u) ? MSS_MAC_LINK_STATUS_FDX : 0u )) );
MSS_MAC_auto_setup_link();
}
/***************************************************************************//**
* Returns the configuration of the Ethernet Controller.
*
* @param instance Pointer to a MAC_instance_t structure
* @return The logical OR of the following values:
* - #MSS_MAC_CFG_RECEIVE_ALL
* - #MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE
* - #MSS_MAC_CFG_STORE_AND_FORWARD
* - #MAC_CFG_THRESHOLD_CONTROL_[00,01,10,11]
* - #MSS_MAC_CFG_FULL_DUPLEX_MODE
* - #MSS_MAC_CFG_PASS_ALL_MULTICAST
* - #MSS_MAC_CFG_PROMISCUOUS_MODE
* - #MSS_MAC_CFG_INVERSE_FILTERING
* - #MSS_MAC_CFG_PASS_BAD_FRAMES
* - #MSS_MAC_CFG_HASH_ONLY_FILTERING_MODE
* - #MSS_MAC_CFG_HASH_PERFECT_RECEIVE_FILTERING_MODE
* @see MAC_configure()
*/
int32_t
MSS_MAC_get_configuration( void )
{
uint32_t configuration;
configuration = 0u;
if( MAC_BITBAND->CSR6_RA != 0u ) {
configuration |= MSS_MAC_CFG_RECEIVE_ALL;
}
if( MAC_BITBAND->CSR6_TTM != 0u ) {
configuration |= MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE;
}
if( MAC_BITBAND->CSR6_SF != 0u ) {
configuration |= MSS_MAC_CFG_STORE_AND_FORWARD;
}
switch( (MAC->CSR6 & CSR6_TR_MASK) >> CSR6_TR_SHIFT ) {
case 1: configuration |= MSS_MAC_CFG_THRESHOLD_CONTROL_01; break;
case 2: configuration |= MSS_MAC_CFG_THRESHOLD_CONTROL_10; break;
case 3: configuration |= MSS_MAC_CFG_THRESHOLD_CONTROL_11; break;
default: break;
}
if( MAC_BITBAND->CSR6_FD != 0u ) {
configuration |= MSS_MAC_CFG_FULL_DUPLEX_MODE;
}
if( MAC_BITBAND->CSR6_PM != 0u ) {
configuration |= MSS_MAC_CFG_PASS_ALL_MULTICAST;
}
if( MAC_BITBAND->CSR6_PR != 0u ) {
configuration |= MSS_MAC_CFG_PROMISCUOUS_MODE;
}
if( MAC_BITBAND->CSR6_IF != 0u ) {
configuration |= MSS_MAC_CFG_INVERSE_FILTERING;
}
if( MAC_BITBAND->CSR6_PB != 0u ) {
configuration |= MSS_MAC_CFG_PASS_BAD_FRAMES;
}
if( MAC_BITBAND->CSR6_HO != 0u ) {
configuration |= MSS_MAC_CFG_HASH_ONLY_FILTERING_MODE;
}
if( MAC_BITBAND->CSR6_HP != 0u ) {
configuration |= MSS_MAC_CFG_HASH_PERFECT_RECEIVE_FILTERING_MODE;
}
return (int32_t)configuration;
}
/***************************************************************************//**
Sends a packet from the uIP stack to the Ethernet Controller.
The MSS_MAC_tx_packet() function is used to send a packet to the MSS Ethernet
MAC. This function writes uip_len bytes of the packet contained in uip_buf into
the transmit FIFO and then activates the transmitter for this packet. If space
is available in the FIFO, the function will return once pac_len bytes of the
packet have been placed into the FIFO and the transmitter has been started.
This function will not wait for the transmission to complete.
@return
The function returns zero if a timeout occurs otherwise it returns size of the packet.
@see MAC_rx_packet()
*/
int32_t
MSS_MAC_tx_packet
(
unsigned short usLength
)
{
uint32_t desc;
unsigned long ulDescriptor;
int32_t error = MAC_OK;
configASSERT( uip_buf != NULL_buffer );
configASSERT( usLength >= 12 );
if( (g_mss_mac.flags & FLAG_EXCEED_LIMIT) == 0u )
{
configASSERT( usLength <= MSS_MAX_PACKET_SIZE );
}
taskENTER_CRITICAL();
{
/* Check both Tx descriptors are free, meaning the double send has completed. */
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 ) )
{
error = MAC_BUFFER_IS_FULL;
}
}
taskEXIT_CRITICAL();
configASSERT( ( g_mss_mac.tx_desc_index == 0 ) );
if( error == MAC_OK )
{
/* Ensure nothing is going to get sent until both descriptors are ready.
This is done to prevent a Tx end occurring prior to the second descriptor
being ready. */
MAC_BITBAND->CSR6_ST = 0u;
/* Assumed TX_RING_SIZE == 2. A #error directive checks this is the
case. */
taskENTER_CRITICAL();
{
for( ulDescriptor = 0; ulDescriptor < TX_RING_SIZE; ulDescriptor++ )
{
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 = 0u;
if( (g_mss_mac.flags & FLAG_CRC_DISABLE) != 0u ) {
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_AC;
}
/* Every buffer can hold a full frame so they are always first and last
descriptor */
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= TDES1_LS | TDES1_FS;
/* set data size */
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_1 |= usLength;
/* reset end of ring */
g_mss_mac.tx_descriptors[TX_RING_SIZE-1].descriptor_1 |= TDES1_TER;
if( usLength > MSS_TX_BUFF_SIZE ) /* FLAG_EXCEED_LIMIT */
{
usLength = (uint16_t)MSS_TX_BUFF_SIZE;
}
/* The data buffer is assigned to the Tx descriptor. */
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].buffer_1 = ( unsigned long ) uip_buf;
/* update counters */
desc = g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0;
if( (desc & TDES0_LO) != 0u ) {
g_mss_mac.statistics.tx_loss_of_carrier++;
}
if( (desc & TDES0_NC) != 0u ) {
g_mss_mac.statistics.tx_no_carrier++;
}
if( (desc & TDES0_LC) != 0u ) {
g_mss_mac.statistics.tx_late_collision++;
}
if( (desc & TDES0_EC) != 0u ) {
g_mss_mac.statistics.tx_excessive_collision++;
}
if( (desc & TDES0_UF) != 0u ) {
g_mss_mac.statistics.tx_underflow_error++;
}
g_mss_mac.statistics.tx_collision_count +=
(desc >> TDES0_CC_OFFSET) & TDES0_CC_MASK;
/* Give ownership of descriptor to the MAC */
g_mss_mac.tx_descriptors[ g_mss_mac.tx_desc_index ].descriptor_0 = TDES0_OWN;
g_mss_mac.tx_desc_index = (g_mss_mac.tx_desc_index + 1u) % (uint32_t)TX_RING_SIZE;
}
}
taskEXIT_CRITICAL();
}
if (error == MAC_OK)
{
error = (int32_t)usLength;
/* Start sending now both descriptors are set up. This is done to
prevent a Tx end occurring prior to the second descriptor being
ready. */
MAC_BITBAND->CSR6_ST = 1u;
MAC->CSR1 = 1u;
/* The buffer pointed to by uip_buf is now assigned to a Tx descriptor.
Find anothere free buffer for uip_buf. */
uip_buf = MAC_obtain_buffer();
}
else
{
error = 0;
}
return ( error );
}
/***************************************************************************//**
* Returns available packet size.
*
* @param instance Pointer to a MAC_instance_t structure
* @return size of packet, bigger than 0, if a packet is available.
* If not, returns 0.
* @see MAC_rx_packet()
*/
int32_t
MSS_MAC_rx_pckt_size
(
void
)
{
int32_t retval;
MAC_dismiss_bad_frames();
if( (g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 & RDES0_OWN) != 0u )
{
/* Current descriptor is empty */
retval = 0;
}
else
{
uint32_t frame_length;
frame_length = ( g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 >> RDES0_FL_OFFSET ) & RDES0_FL_MASK;
retval = (int32_t)( frame_length );
}
return retval;
}
/***************************************************************************//**
* Receives a packet from the Ethernet Controller into the uIP stack.
* This function reads a packet from the receive FIFO of the controller and
* places it into uip_buf.
* @return Size of packet if packet fits in uip_buf.
* 0 if there is no received packet.
* @see MAC_rx_pckt_size()
* @see MAC_tx_packet()
*/
int32_t
MSS_MAC_rx_packet
(
void
)
{
uint16_t frame_length=0u;
MAC_dismiss_bad_frames();
if( (g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 & RDES0_OWN) == 0u )
{
frame_length = ( (
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 >>
RDES0_FL_OFFSET ) & RDES0_FL_MASK );
/* strip crc */
frame_length -= 4u;
if( frame_length > macBUFFER_SIZE ) {
return MAC_NOT_ENOUGH_SPACE;
}
/* uip_buf is about to point to the buffer that contains the received
data, mark the buffer that uip_buf is currently pointing to as free
again. */
MAC_release_buffer( uip_buf );
uip_buf = ( unsigned char * ) g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1;
/* The buffer the Rx descriptor was pointing to is now in use by the
uIP stack - allocate a new buffer to the Rx descriptor. */
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1 = ( unsigned long ) MAC_obtain_buffer();
MSS_MAC_prepare_rx_descriptor();
}
return ((int32_t)frame_length);
}
/***************************************************************************//**
* Receives a packet from the Ethernet Controller.
* This function reads a packet from the receive FIFO of the controller and
* sets the address of pacData to the received data.
* If time_out parameter is zero the function will return
* immediately (after the copy operation if data is available. Otherwise the function
* will keep trying to read till time_out expires or data is read, if MSS_MAC_BLOCKING
* value is given as time_out, function will wait for the reception to complete.
*
* @param pacData The pointer to the packet data.
* @param time_out Time out value in milli seconds for receiving.
* if value is #MSS_MAC_BLOCKING, there will be no time out.
* if value is #MSS_MAC_NONBLOCKING, function will return immediately
* if there is no packet waiting.
* Otherwise value must be greater than 0 and smaller than
* 0x01000000.
* @return Size of packet if packet fits in pacData.
* 0 if there is no received packet.
* @see MAC_rx_pckt_size()
* @see MAC_tx_packet()
*/
int32_t
MSS_MAC_rx_packet_ptrset
(
uint8_t **pacData,
uint32_t time_out
)
{
uint16_t frame_length = 0u;
int8_t exit = 0;
configASSERT( (time_out == MSS_MAC_BLOCKING) ||
(time_out == MSS_MAC_NONBLOCKING) ||
((time_out >= 1) && (time_out <= 0x01000000UL)) );
MAC_dismiss_bad_frames();
/* wait for a packet */
if( time_out != MSS_MAC_BLOCKING ) {
if( time_out == MSS_MAC_NONBLOCKING ) {
MAC_set_time_out( 0u );
} else {
MAC_set_time_out( time_out );
}
}
while( ((g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 &
RDES0_OWN) != 0u) && (exit == 0) )
{
if( time_out != MSS_MAC_BLOCKING )
{
if( MAC_get_time_out() == 0u ) {
exit = 1;
}
}
}
if(exit == 0)
{
frame_length = ( (
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 >>
RDES0_FL_OFFSET ) & RDES0_FL_MASK );
/* strip crc */
frame_length -= 4u;
/* Here we are setting the buffer 'pacData' address to the address
RX descriptor address. After this is called, the following function
must be called 'MAC_prepare_rx_descriptor'
to prepare the current rx descriptor for receiving the next packet.
*/
*pacData = (uint8_t *)g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].buffer_1 ;
}
return ((int32_t)frame_length);
}
/***************************************************************************//**
* Returns the status of connection.
*
* @return the logical OR of the following values:
* #MSS_MAC_LINK_STATUS_LINK - Link up/down
* #MSS_MAC_LINK_STATUS_100MB - Connection is 100Mb/10Mb
* #MSS_MAC_LINK_STATUS_FDX - Connection is full/half duplex
* @see MAC_auto_setup_link()
*/
int32_t
MSS_MAC_link_status
(
void
)
{
uint32_t link;
link = PHY_link_status();
if( link == MSS_MAC_LINK_STATUS_LINK ) {
link |= PHY_link_type();
}
return ((int32_t)link);
}
/***************************************************************************//**
* Setups the link between PHY and MAC and returns the status of connection.
*
* @return the logical OR of the following values:
* #MSS_MAC_LINK_STATUS_LINK - Link up/down
* #MSS_MAC_LINK_STATUS_100MB - Connection is 100Mb/10Mb
* #MSS_MAC_LINK_STATUS_FDX - Connection is full/half duplex
* @see MAC_link_status()
*/
int32_t
MSS_MAC_auto_setup_link
(
void
)
{
int32_t link;
PHY_auto_negotiate();
link = MSS_MAC_link_status();
if( (link & MSS_MAC_LINK_STATUS_LINK) != 0u ) {
int32_t ret;
ret = MAC_stop_transmission();
MAC_CHECK( ret == MAC_OK, ret );
ret = MAC_stop_receiving();
MAC_CHECK( ret == MAC_OK, ret );
MAC_BITBAND->CSR6_TTM = (uint32_t)((((uint32_t)link & MSS_MAC_LINK_STATUS_100MB) != 0u) ? 1u : 0u );
MAC_BITBAND->CSR6_FD = (uint32_t)((((uint32_t)link & MSS_MAC_LINK_STATUS_FDX) != 0u) ? 1u : 1u );
MAC_start_transmission();
MAC_start_receiving();
}
return link;
}
/***************************************************************************//**
* Sets mac address. New address must be unicast.
*
* @param new_address Pointer to a MAC_instance_t structure
* @see MAC_get_mac_address()
*/
void
MSS_MAC_set_mac_address
(
const uint8_t *new_address
)
{
/* Check if the new address is unicast */
configASSERT( (new_address[0]&1) == 0 );
MAC_memcpy( g_mss_mac.mac_address, new_address, 6u );
if((g_mss_mac.flags & FLAG_PERFECT_FILTERING) != 0u ) {
int32_t a;
/* set unused filters to the new mac address */
for( a=14*6; a>=0; a-=6 ) {
if( (g_mss_mac.mac_filter_data[a] & 1u) != 0u ) {
/* Filters with multicast addresses are used */
a = -1;
} else {
MAC_memcpy( &(g_mss_mac.mac_filter_data[a]),
g_mss_mac.mac_address, 6u );
}
}
}
MAC_send_setup_frame();
}
/***************************************************************************//**
* Returns mac address.
*
* @param address Pointer to receive the MAC address
* @see MAC_set_mac_address()
*/
void
MSS_MAC_get_mac_address
(
uint8_t *address
)
{
MAC_memcpy( address, g_mss_mac.mac_address, 6u );
}
/***************************************************************************//**
* Sets mac address filters. Addresses must be multicast.
*
* @param filter_count number of addresses
* @param filters Pointer to addresses to be filtered
*/
void
MSS_MAC_set_mac_filters
(
uint16_t filter_count,
const uint8_t *filters
)
{
configASSERT( (filter_count==0) || (filters != NULL_buffer) );
/* Check if the mac addresses is multicast */
{
int32_t a;
for( a = 0u; a < filter_count; a++ ) {
configASSERT( (filters[a*6]&1) == 1 );
}
}
if( filter_count <= 15 ){
int32_t a;
g_mss_mac.flags |= FLAG_PERFECT_FILTERING;
/* copy new filters */
MAC_memcpy( g_mss_mac.mac_filter_data, filters, (uint32_t)(filter_count*6));
/* set unused filters to our mac address */
for( a=filter_count; a<15; a++ ) {
MAC_memcpy( &(g_mss_mac.mac_filter_data[a*6]),
g_mss_mac.mac_address, 6 );
}
} else {
int32_t a,b;
uint32_t hash;
g_mss_mac.flags &= ~FLAG_PERFECT_FILTERING;
/* reset hash table */
MAC_memset( g_mss_mac.mac_filter_data, 0u, 64u );
for( a=0, b=0; a<filter_count; a++, b+=6 ) {
hash = mss_ethernet_crc( &(filters[b]), 6 ) & 0x1FF;
g_mss_mac.mac_filter_data[ hash / 8 ] |= 1 << (hash & 0x7);
}
}
MAC_send_setup_frame();
}
/***************************************************************************//**
* MAC interrupt service routine.
*
* @param instance Pointer to a MAC_instance_t structure
* @see MAC_set_callback()
*/
#if defined(__GNUC__)
__attribute__((__interrupt__)) void EthernetMAC_IRQHandler( void )
#else
void EthernetMAC_IRQHandler( void )
#endif
{
uint32_t events;
uint32_t intr_status;
events = 0u;
intr_status = MAC->CSR5;
if( (intr_status & CSR5_NIS_MASK) != 0u ) {
if( (intr_status & CSR5_TI_MASK) != 0u ) { /* Transmit */
g_mss_mac.statistics.tx_interrupts++;
events |= MSS_MAC_EVENT_PACKET_SEND;
}
if( (intr_status & CSR5_RI_MASK) != 0u ) { /* Receive */
g_mss_mac.statistics.rx_interrupts++;
events |= MSS_MAC_EVENT_PACKET_RECEIVED;
}
}
/* Clear interrupts */
MAC->CSR5 = CSR5_INT_BITS;
if( (events != 0u) && (g_mss_mac.listener != NULL_callback) ) {
g_mss_mac.listener( events );
}
}
/***************************************************************************//**
* Sets MAC event listener.
* Sets the given event listener function to be triggered inside MAC_isr().
* Assigning NULL pointer as the listener function will disable it.
*
* @param instance Pointer to a MAC_instance_t structure
* @param listener function pointer to a MAC_callback_t function
* @return #MAC_OK if everything is OK
* #MAC_WRONG_PARAMETER if instance is null or hasn't been
* initialized.
* @see MAC_isr()
*/
void
MSS_MAC_set_callback
(
MSS_MAC_callback_t listener
)
{
/* disable tx and rx interrupts */
MAC_BITBAND->CSR7_RIE = 0u;
MAC_BITBAND->CSR7_TIE = 0u;
g_mss_mac.listener = listener;
if( listener != NULL_callback ) {
/* enable tx and rx interrupts */
MAC_BITBAND->CSR7_RIE = 1u;
MAC_BITBAND->CSR7_TIE = 1u;
}
}
/***************************************************************************//**
* Returns description of last error.
*
* @param instance Pointer to a MAC_instance_t structure
* @return A string describing the error. This string must not be
* modified by the application.
* #MAC_WRONG_PARAMETER if instance is null or hasn't been
* initialized.
*/
const int8_t*
MSS_MAC_last_error
(
void
)
{
int8_t error_msg_nb;
const int8_t* returnvalue;
error_msg_nb = -(g_mss_mac.last_error);
if( error_msg_nb >= ERROR_MESSAGE_COUNT ) {
returnvalue = unknown_error;
} else {
returnvalue = ErrorMessages[error_msg_nb];
}
return returnvalue;
}
/***************************************************************************//**
* Returns statistics counter of stat_id identifier.
*
* @param instance Pointer to a MAC_instance_t structure
* @param stat_id Identifier of statistics counter.
* @return Statistics counter of stat_id identifier.
* On error returns 0.
*/
uint32_t
MSS_MAC_get_statistics
(
mss_mac_statistics_id_t stat_id
)
{
uint32_t returnval = 0u;
switch( stat_id ) {
case MSS_MAC_RX_INTERRUPTS:
returnval = g_mss_mac.statistics.rx_interrupts;
break;
case MSS_MAC_RX_FILTERING_FAIL:
returnval = g_mss_mac.statistics.rx_filtering_fail;
break;
case MSS_MAC_RX_DESCRIPTOR_ERROR:
returnval = g_mss_mac.statistics.rx_descriptor_error;
break;
case MSS_MAC_RX_RUNT_FRAME:
returnval = g_mss_mac.statistics.rx_runt_frame;
break;
case MSS_MAC_RX_NOT_FIRST:
returnval = g_mss_mac.statistics.rx_not_first;
break;
case MSS_MAC_RX_NOT_LAST:
returnval = g_mss_mac.statistics.rx_not_last;
break;
case MSS_MAC_RX_FRAME_TOO_LONG:
returnval = g_mss_mac.statistics.rx_frame_too_long;
break;
case MSS_MAC_RX_COLLISION_SEEN:
returnval = g_mss_mac.statistics.rx_collision_seen;
break;
case MSS_MAC_RX_CRC_ERROR:
returnval = g_mss_mac.statistics.rx_crc_error;
break;
case MSS_MAC_RX_FIFO_OVERFLOW:
returnval = g_mss_mac.statistics.rx_fifo_overflow;
break;
case MSS_MAC_RX_MISSED_FRAME:
returnval = g_mss_mac.statistics.rx_missed_frame;
break;
case MSS_MAC_TX_INTERRUPTS:
returnval = g_mss_mac.statistics.tx_interrupts;
break;
case MSS_MAC_TX_LOSS_OF_CARRIER:
returnval = g_mss_mac.statistics.tx_loss_of_carrier;
break;
case MSS_MAC_TX_NO_CARRIER:
returnval = g_mss_mac.statistics.tx_no_carrier;
break;
case MSS_MAC_TX_LATE_COLLISION:
returnval = g_mss_mac.statistics.tx_late_collision;
break;
case MSS_MAC_TX_EXCESSIVE_COLLISION:
returnval = g_mss_mac.statistics.tx_excessive_collision;
break;
case MSS_MAC_TX_COLLISION_COUNT:
returnval = g_mss_mac.statistics.tx_collision_count;
break;
case MSS_MAC_TX_UNDERFLOW_ERROR:
returnval = g_mss_mac.statistics.tx_underflow_error;
break;
default:
break;
}
return returnval;
}
/**************************** INTERNAL FUNCTIONS ******************************/
/***************************************************************************//**
* Prepares current rx descriptor for receiving.
*/
void
MSS_MAC_prepare_rx_descriptor
(
void
)
{
uint32_t desc;
/* update counters */
desc = g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0;
if( (desc & RDES0_FF) != 0u ) {
g_mss_mac.statistics.rx_filtering_fail++;
}
if( (desc & RDES0_DE) != 0u ) {
g_mss_mac.statistics.rx_descriptor_error++;
}
if( (desc & RDES0_RF) != 0u ) {
g_mss_mac.statistics.rx_runt_frame++;
}
if( (desc & RDES0_FS) == 0u ) {
g_mss_mac.statistics.rx_not_first++;
}
if( (desc & RDES0_LS) == 0u ) {
g_mss_mac.statistics.rx_not_last++;
}
if( (desc & RDES0_TL) != 0u ) {
g_mss_mac.statistics.rx_frame_too_long++;
}
if( (desc & RDES0_CS) != 0u ) {
g_mss_mac.statistics.rx_collision_seen++;
}
if( (desc & RDES0_CE) != 0u ) {
g_mss_mac.statistics.rx_crc_error++;
}
desc = MAC->CSR8;
g_mss_mac.statistics.rx_fifo_overflow +=
(desc & (CSR8_OCO_MASK|CSR8_FOC_MASK)) >> CSR8_FOC_SHIFT;
g_mss_mac.statistics.rx_missed_frame +=
(desc & (CSR8_MFO_MASK|CSR8_MFC_MASK));
/* Give ownership of descriptor to the MAC */
g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 = RDES0_OWN;
g_mss_mac.rx_desc_index = (g_mss_mac.rx_desc_index + 1u) % RX_RING_SIZE;
/* Start receive */
MAC_start_receiving();
}
/***************************************************************************//**
* Prepares a setup frame and sends it to MAC.
* This function is blocking.
* @return #MAC_OK if everything is ok.
* #MAC_TIME_OUT if timed out before packet send.
*/
static int32_t
MAC_send_setup_frame
(
void
)
{
volatile MAC_descriptor_t descriptor;
uint8_t frame_data[192];
uint8_t *data;
int32_t a,b,c,d;
int32_t ret;
/* prepare descriptor */
descriptor.descriptor_0 = TDES0_OWN;
descriptor.descriptor_1 = TDES1_SET | TDES1_TER |
(sizeof(frame_data) << TDES1_TBS1_OFFSET);
if( (g_mss_mac.flags & FLAG_PERFECT_FILTERING) == 0u ) {
descriptor.descriptor_1 |= TDES1_FT0;
}
descriptor.buffer_1 = (uint32_t)frame_data;
descriptor.buffer_2 = 0u;
/* prepare frame */
if( (g_mss_mac.flags & FLAG_PERFECT_FILTERING) != 0u ) {
b = 0;
d = 12;
c = 90;
} else {
b = 156;
d = 0;
c = 64;
}
data = g_mss_mac.mac_address;
frame_data[b] = data[0];
frame_data[b+1] = data[1];
frame_data[b+4] = data[2];
frame_data[b+5] = data[3];
frame_data[b+8] = data[4];
frame_data[b+9] = data[5];
data = g_mss_mac.mac_filter_data;
for( a = 0; a < c; ) {
frame_data[d] = data[a++];
frame_data[d+1] = data[a++];
frame_data[d+4] = data[a++];
frame_data[d+5] = data[a++];
frame_data[d+8] = data[a++];
frame_data[d+9] = data[a++];
d += 12;
}
/* Stop transmission */
ret = MAC_stop_transmission();
configASSERT( ret == MAC_OK );
ret = MAC_stop_receiving();
configASSERT( ret == MAC_OK );
/* Set descriptor */
MAC->CSR4 = (uint32_t)&descriptor;
/* Start transmission */
MAC_start_transmission();
/* Wait until transmission over */
ret = MAC_OK;
MAC_set_time_out( (uint32_t)SETUP_FRAME_TIME_OUT );
while( (((MAC->CSR5 & CSR5_TS_MASK) >> CSR5_TS_SHIFT) !=
CSR5_TS_SUSPENDED) && (MAC_OK == ret) )
{
/* transmit poll demand */
MAC->CSR1 = 1u;
if( MAC_get_time_out() == 0u ) {
ret = MAC_TIME_OUT;
}
}
MAC_CHECK( MAC_stop_transmission() == MAC_OK, MAC_FAIL );
/* Set tx descriptor */
MAC->CSR4 = (uint32_t)g_mss_mac.tx_descriptors;
/* Start receiving and transmission */
MAC_start_receiving();
MAC_start_transmission();
return ret;
}
/***************************************************************************//**
* Stops transmission.
* Function will wait until transmit operation enters stop state.
*
* @return #MAC_OK if everything is ok.
* #MAC_TIME_OUT if timed out.
*/
static int32_t
MAC_stop_transmission
(
void
)
{
int32_t retval = MAC_OK;
MAC_set_time_out( (uint16_t)STATE_CHANGE_TIME_OUT );
while( (((MAC->CSR5 & CSR5_TS_MASK) >> CSR5_TS_SHIFT) !=
CSR5_TS_STOPPED) && (retval == MAC_OK) )
{
MAC_BITBAND->CSR6_ST = 0u;
if( MAC_get_time_out() == 0u ) {
retval = MAC_TIME_OUT;
}
}
return retval;
}
/***************************************************************************//**
* Starts transmission.
*/
static void
MAC_start_transmission
(
void
)
{
MAC_BITBAND->CSR6_ST = 1u;
}
/***************************************************************************//**
* Stops transmission.
* Function will wait until transmit operation enters stop state.
*
* @return #MAC_OK if everything is ok.
* #MAC_TIME_OUT if timed out.
*/
static int32_t
MAC_stop_receiving
(
void
)
{
int32_t retval = MAC_OK;
MAC_set_time_out( (uint16_t)STATE_CHANGE_TIME_OUT );
while( (((MAC->CSR5 & CSR5_RS_MASK) >> CSR5_RS_SHIFT) != CSR5_RS_STOPPED)
&& (retval == MAC_OK) )
{
MAC_BITBAND->CSR6_SR = 0u;
if( MAC_get_time_out() == 0u ) {
retval = MAC_TIME_OUT;
}
}
return retval;
}
/***************************************************************************//**
* Starts transmission.
*/
static void
MAC_start_receiving
(
void
)
{
MAC_BITBAND->CSR6_SR = 1u;
}
/***************************************************************************//**
* Dismisses bad frames.
*
* @return dismissed frame count.
*/
static int32_t
MAC_dismiss_bad_frames
(
void
)
{
int32_t dc = 0;
int8_t cont = 1;
if( MAC_BITBAND->CSR6_PB != 0u ) {
/* User wants bad frames too, don't dismiss anything */
cont = 0;
}
while( ( (g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 &
RDES0_OWN) == 0u) && (cont == 1) ) /* Host owns this descriptor */
{
/* check error summary */
if( (g_mss_mac.rx_descriptors[ g_mss_mac.rx_desc_index ].descriptor_0 &
(RDES0_ES | RDES0_LS | RDES0_FS)) != (RDES0_LS | RDES0_FS) )
{
MSS_MAC_prepare_rx_descriptor();
dc++;
}
else
{
cont = 0;
}
}
return dc;
}
/***************************************************************************//**
* Sets time out value.
* #MAC_get_time_out must be called frequently to make time out value updated.
* Because of user may not be using ISR, we can not update time out in ISR.
*
* @time_out time out value in milli seconds.
* Must be smaller than 0x01000000.
*/
static void
MAC_set_time_out
(
uint32_t time_out
)
{
g_mss_mac.time_out_value = (time_out * 122u) / 10u;
g_mss_mac.last_timer_value = (uint16_t)( MAC->CSR11 & CSR11_TIM_MASK );
}
/***************************************************************************//**
* Returns time out value.
*
* @return timer out value in milli seconds.
*/
static uint32_t
MAC_get_time_out
(
void
)
{
uint32_t timer;
uint32_t time = 0u;
timer = ( MAC->CSR11 & CSR11_TIM_MASK );
if( timer > g_mss_mac.last_timer_value ) {
time = 0x0000ffffUL;
}
time += g_mss_mac.last_timer_value - timer;
if( MAC_BITBAND->CSR6_TTM == 0u ) {
time *= 10u;
}
if( g_mss_mac.time_out_value <= time ){
g_mss_mac.time_out_value = 0u;
} else {
g_mss_mac.time_out_value -= time;
}
g_mss_mac.last_timer_value = (uint16_t)timer;
return ((g_mss_mac.time_out_value * 10u) / 122u);
}
/***************************************************************************//**
* Fills the first n bytes of the memory area pointed to by s with the constant
* byte c.
*/
static void MAC_memset(uint8_t *s, uint8_t c, uint32_t n)
{
uint8_t *sb = s;
while( n > 0u ) {
n--;
sb[n] = c;
}
}
/***************************************************************************//**
* Fills all fields of MAC_instance_t with c.
*
* @return a pointer to the given MAC_instance_t s.
*/
static void MAC_memset_All(MAC_instance_t *s, uint32_t c)
{
int32_t count;
s->base_address = (addr_t)c;
s->flags = (uint8_t)c;
s->last_error = (int8_t)c;
s->last_timer_value = (uint16_t)c;
s->listener = NULL_callback;
MAC_memset( s->mac_address, (uint8_t)c, 6u );
MAC_memset( s->mac_filter_data, (uint8_t)c, 90u );
s->phy_address = (uint8_t)c;
s->rx_desc_index =c;
for(count = 0; count<RX_RING_SIZE ;count++)
{
s->rx_descriptors[count].buffer_1 = c;
s->rx_descriptors[count].buffer_2 = c;
s->rx_descriptors[count].descriptor_0 = c;
s->rx_descriptors[count].descriptor_1 = c;
}
s->statistics.rx_collision_seen =c;
s->statistics.rx_crc_error = c;
s->statistics.rx_descriptor_error = c;
s->statistics.rx_fifo_overflow = c;
s->statistics.rx_filtering_fail = c;
s->statistics.rx_frame_too_long = c;
s->statistics.rx_interrupts = c;
s->statistics.rx_missed_frame = c;
s->statistics.rx_not_first = c;
s->statistics.rx_not_last = c;
s->statistics.rx_runt_frame = c;
s->statistics.tx_collision_count = c;
s->statistics.tx_excessive_collision = c;
s->statistics.tx_interrupts = c;
s->statistics.tx_late_collision = c;
s->statistics.tx_loss_of_carrier = c;
s->statistics.tx_no_carrier = c;
s->statistics.tx_underflow_error = c;
s->time_out_value = c;
s->tx_desc_index = c;
for(count = 0; count < TX_RING_SIZE ;count++)
{
s->tx_descriptors[count].buffer_1 = c;
s->tx_descriptors[count].buffer_2 = c;
s->tx_descriptors[count].descriptor_0 = c;
s->tx_descriptors[count].descriptor_1 = c;
}
}
/***************************************************************************//**
* Copies n bytes from memory area src to memory area dest.
* The memory areas should not overlap.
*
* @return a pointer to the memory area dest.
*/
static void MAC_memcpy(uint8_t *dest, const uint8_t *src, uint32_t n)
{
uint8_t *d = dest;
while( n > 0u ) {
n--;
d[n] = src[n];
}
}
/***************************************************************************//**
* Tx has completed, mark the buffers that were assigned to the Tx descriptors
* as free again.
*
*/
void MSS_MAC_FreeTxBuffers( void )
{
/* Check the buffers have not already been freed in the first of the
two Tx interrupts - which could potentially happen if the second Tx completed
during the interrupt for the first Tx. */
if( g_mss_mac.tx_descriptors[ 0 ].buffer_1 != NULL )
{
if( ( ( (g_mss_mac.tx_descriptors[ 0 ].descriptor_0) & TDES0_OWN) == 0 ) && ( ( (g_mss_mac.tx_descriptors[ 1 ].descriptor_0) & TDES0_OWN) == 0 ) )
{
configASSERT( g_mss_mac.tx_descriptors[ 0 ].buffer_1 == g_mss_mac.tx_descriptors[ 1 ].buffer_1 );
MAC_release_buffer( ( unsigned char * ) g_mss_mac.tx_descriptors[ 0 ].buffer_1 );
/* Just to mark the fact that the buffer has already been released. */
g_mss_mac.tx_descriptors[ 0 ].buffer_1 = NULL;
}
}
}
/***************************************************************************//**
* Look through the array of buffers until one is found that is free for use -
* that is, not currently assigned to an Rx or a Tx descriptor. Mark the buffer
* as in use, then return its address.
*
* @return a pointer to a free buffer.
*/
unsigned char *MAC_obtain_buffer( void )
{
long lIndex, lAttempt = 0, lDescriptor, lBufferIsInUse;
unsigned char *pcReturn = NULL;
unsigned char *pcBufferAddress;
/* Find and return the address of a buffer that is not being used. Mark
the buffer as now in use. */
while( ( lAttempt <= 1 ) && ( pcReturn == NULL ) )
{
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
{
if( ucMACBufferInUse[ lIndex ] == pdFALSE )
{
pcReturn = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );
ucMACBufferInUse[ lIndex ] = pdTRUE;
break;
}
}
if( pcReturn == NULL )
{
/* Did not find a buffer. That should not really happen, but could if
an interrupt was missed. See if any buffers are marked as in use, but
are not actually in use. */
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
{
pcBufferAddress = &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] );
lBufferIsInUse = pdFALSE;
/* Is the buffer used by an Rx descriptor? */
for( lDescriptor = 0; lDescriptor < RX_RING_SIZE; lDescriptor++ )
{
if( g_mss_mac.rx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )
{
/* The buffer is in use by an Rx descriptor. */
lBufferIsInUse = pdTRUE;
break;
}
}
if( lBufferIsInUse != pdTRUE )
{
/* Is the buffer used by an Tx descriptor? */
for( lDescriptor = 0; lDescriptor < TX_RING_SIZE; lDescriptor++ )
{
if( g_mss_mac.tx_descriptors[ lDescriptor ].buffer_1 == ( uint32_t ) pcBufferAddress )
{
/* The buffer is in use by an Tx descriptor. */
lBufferIsInUse = pdTRUE;
break;
}
}
}
/* If the buffer was not found to be in use by either a Tx or an
Rx descriptor, but the buffer is marked as in use, then mark the
buffer to be in it's correct state of "not in use". */
if( ( lBufferIsInUse == pdFALSE ) && ( ucMACBufferInUse[ lIndex ] == pdTRUE ) )
{
ucMACBufferInUse[ lIndex ] = pdFALSE;
}
}
}
/* If any buffer states were changed it might be that a buffer can now
be obtained. Try again, but only one more time. */
lAttempt++;
}
configASSERT( pcReturn );
return pcReturn;
}
/***************************************************************************//**
* Return a buffer to the list of free buffers, it was in use, but is not now.
*
*/
void MAC_release_buffer( unsigned char *pucBufferToRelease )
{
long lIndex;
/* uip_buf is going to point to a different buffer - first ensure the buffer
it is currently pointing to is marked as being free again. */
for( lIndex = 0; lIndex < macNUM_BUFFERS; lIndex++ )
{
if( pucBufferToRelease == &( xMACBuffers.ucBuffer[ lIndex ][ 0 ] ) )
{
/* This is the buffer in use, mark it as being free. */
ucMACBufferInUse[ lIndex ] = pdFALSE;
break;
}
}
configASSERT( lIndex < macNUM_BUFFERS );
}
#ifdef __cplusplus
}
#endif
/******************************** END OF FILE *********************************/