\r
/* BSP includes. */\r
#include "xemaclite.h"\r
+#include "xintc_l.h"\r
\r
/* lwIP includes. */\r
#include "lwip/opt.h"\r
#define IFNAME0 'e'\r
#define IFNAME1 'l'\r
\r
+/* When a packet is ready to be sent, if it cannot be sent immediately then\r
+ * the task performing the transmit will block for netifTX_BUFFER_FREE_WAIT\r
+ * milliseconds. It will do this a maximum of netifMAX_TX_ATTEMPTS before\r
+ * giving up.
+ */\r
+#define netifTX_BUFFER_FREE_WAIT ( ( portTickType ) 5UL / portTICK_RATE_MS )\r
+#define netifMAX_TX_ATTEMPTS ( 5 )\r
+\r
#define netifMAX_MTU 1500\r
\r
struct xEthernetIf\r
/*\r
* Copy the received data into a pbuf.\r
*/\r
-static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, long lDataLength );\r
+static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength );\r
\r
/*\r
* Send data from a pbuf to the hardware.\r
*/\r
static void prvLowLevelInit( struct netif *pxNetIf );\r
\r
+/*\r
+ * Functions that get registered as the Rx and Tx interrupt handers\r
+ * respectively.\r
+ */\r
+static void prvRxHandler( void *pvNetIf );\r
+static void prvTxHandler( void *pvUnused );\r
+\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The instance of the xEmacLite IP being used in this driver. */\r
+static XEmacLite xEMACInstance;\r
+\r
/*-----------------------------------------------------------*/\r
\r
/**\r
*/\r
static void prvLowLevelInit( struct netif *pxNetIf )\r
{\r
+portBASE_TYPE xStatus;\r
+\r
/* set MAC hardware address length */\r
pxNetIf->hwaddr_len = ETHARP_HWADDR_LEN;\r
\r
pxNetIf->hwaddr[ 5 ] = configMAC_ADDR5;\r
\r
/* device capabilities */\r
- /* don't set pxNetIf_FLAG_ETHARP if this device is not an ethernet one */\r
pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;\r
\r
-#if 0\r
-_RB_\r
-\r
- /* Query the computer the simulation is being executed on to find the\r
- network interfaces it has installed. */\r
- pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();\r
-\r
- /* Open the network interface. The number of the interface to be opened is\r
- set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.\r
- Calling this function will set the pxOpenedInterfaceHandle variable. If,\r
- after calling this function, pxOpenedInterfaceHandle is equal to NULL, then\r
- the interface could not be opened. */\r
- if( pxAllNetworkInterfaces != NULL )\r
+ /* maximum transfer unit */\r
+ pxNetIf->mtu = netifMAX_MTU;\r
+\r
+ /* Broadcast capability */\r
+ pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;\r
+\r
+ /* Initialize the mac */\r
+ xStatus = XEmacLite_Initialize( &xEMACInstance, XPAR_EMACLITE_0_DEVICE_ID );\r
+\r
+ if( xStatus == XST_SUCCESS )\r
{\r
- prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );\r
+ /* Set mac address */\r
+ XEmacLite_SetMacAddress( &xEMACInstance, ( Xuint8* )( pxNetIf->hwaddr ) );\r
+\r
+ /* Flush any frames already received */\r
+ XEmacLite_FlushReceive( &xEMACInstance );\r
+\r
+ /* Set Rx, Tx interrupt handlers */\r
+ XEmacLite_SetRecvHandler( &xEMACInstance, ( void * ) pxNetIf, prvRxHandler );\r
+ XEmacLite_SetSendHandler( &xEMACInstance, NULL, prvTxHandler );\r
+\r
+ /* Enable Rx, Tx interrupts */\r
+ XEmacLite_EnableInterrupts( &xEMACInstance );\r
+\r
+ /* Install the standard Xilinx library interrupt handler itself.\r
+ *NOTE* The xPortInstallInterruptHandler() API function must be used\r
+ for this purpose. */\r
+ xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_EMACLITE_0_VEC_ID, ( XInterruptHandler ) XEmacLite_InterruptHandler, &xEMACInstance );\r
+\r
+ /* Enable the interrupt in the interrupt controller.\r
+ *NOTE* The vPortEnableInterrupt() API function must be used for this\r
+ purpose. */\r
+ vPortEnableInterrupt( XPAR_INTC_0_EMACLITE_0_VEC_ID );\r
}\r
\r
- /* Remember which interface was opened as it is used in the interrupt\r
- simulator task. */\r
- pxlwIPNetIf = pxNetIf;\r
-#endif\r
+ configASSERT( xStatus == pdPASS );\r
}\r
\r
/**\r
to the FreeRTOS coding standard. */\r
\r
struct pbuf *q;\r
-static unsigned char ucBuffer[ 1520 ];\r
+static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));\r
unsigned char *pucBuffer = ucBuffer;\r
unsigned char *pucChar;\r
struct eth_hdr *pxHeader;\r
u16_t usTotalLength = p->tot_len - ETH_PAD_SIZE;\r
err_t xReturn = ERR_OK;\r
+long x;\r
\r
#if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF\r
LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len);\r
time. The size of the data in each pbuf is kept in the ->len\r
variable. */\r
/* send data from(q->payload, q->len); */\r
- LWIP_DEBUGF( NETIF_DEBUG, ("NETIF: send pucChar %p q->payload %p q->len %i q->next %p\n", pucChar, q->payload, ( int ) q->len, ( void* ) q->next ) );\r
+ LWIP_DEBUGF( NETIF_DEBUG, ( "NETIF: send pucChar %p q->payload %p q->len %i q->next %p\n", pucChar, q->payload, ( int ) q->len, ( void* ) q->next ) );\r
if( q == p )\r
{\r
memcpy( pucChar, &( ( char * ) q->payload )[ ETH_PAD_SIZE ], q->len - ETH_PAD_SIZE );\r
\r
if( xReturn == ERR_OK )\r
{\r
-#if 0\r
-_RB_\r
- /* signal that packet should be sent */\r
- if( pcap_sendpacket( pxOpenedInterfaceHandle, pucBuffer, usTotalLength ) < 0 ) \r
+ for( x = 0; x < netifMAX_TX_ATTEMPTS; x++ )\r
+ {\r
+ xReturn = XEmacLite_Send( &xEMACInstance, pucBuffer, ( int ) usTotalLength );\r
+ if( xReturn == XST_SUCCESS )\r
+ {\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ vTaskDelay( netifTX_BUFFER_FREE_WAIT );\r
+ }\r
+ }\r
+\r
+ if( xReturn != XST_SUCCESS )\r
{\r
LINK_STATS_INC( link.memerr );\r
LINK_STATS_INC( link.drop );\r
snmp_inc_ifoutucastpkts( pxNetIf );\r
}\r
}\r
-#endif\r
}\r
\r
return xReturn;\r
* @return a pbuf filled with the received packet (including MAC header)\r
* NULL on memory error\r
*/\r
-static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, long lDataLength )\r
+static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength )\r
{\r
struct pbuf *p = NULL, *q;\r
\r
- if( lDataLength > 0 )\r
+ if( usDataLength > 0U )\r
{\r
#if ETH_PAD_SIZE\r
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */\r
#endif\r
\r
/* We allocate a pbuf chain of pbufs from the pool. */\r
- p = pbuf_alloc( PBUF_RAW, lDataLength, PBUF_POOL );\r
+ p = pbuf_alloc( PBUF_RAW, usDataLength, PBUF_POOL );\r
\r
if( p != NULL ) \r
{\r
\r
/* We iterate over the pbuf chain until we have read the entire\r
* packet into the pbuf. */\r
- lDataLength = 0;\r
+ usDataLength = 0U;\r
for( q = p; q != NULL; q = q->next ) \r
{\r
/* Read enough bytes to fill this pbuf in the chain. The\r
* actually received size. In this case, ensure the usTotalLength member of the\r
* pbuf is the sum of the chained pbuf len members.\r
*/\r
- memcpy( q->payload, &( pucInputData[ lDataLength ] ), q->len );\r
- lDataLength += q->len;\r
+ memcpy( q->payload, &( pucInputData[ usDataLength ] ), q->len );\r
+ usDataLength += q->len;\r
}\r
\r
#if ETH_PAD_SIZE\r
return xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
+\r
+static void prvRxHandler( void *pvNetIf )\r
+{\r
+ /* This is taken from lwIP example code and therefore does not conform\r
+ to the FreeRTOS coding standard. */\r
+\r
+struct eth_hdr *pxHeader;\r
+struct pbuf *p;\r
+unsigned short usInputLength;\r
+static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));\r
+extern portBASE_TYPE xInsideISR;\r
+struct netif *pxNetIf = ( struct netif * ) pvNetIf;\r
+\r
+ XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );\r
+\r
+ /* Ensure the pbuf handling functions don't attempt to use critical\r
+ sections. */\r
+ xInsideISR++;\r
+\r
+ usInputLength = ( long ) XEmacLite_Recv( &xEMACInstance, ucBuffer );\r
+\r
+ /* move received packet into a new pbuf */\r
+ p = prvLowLevelInput( ucBuffer, usInputLength );\r
+\r
+ /* no packet could be read, silently ignore this */\r
+ if( p != NULL )\r
+ {\r
+ /* points to packet payload, which starts with an Ethernet header */\r
+ pxHeader = p->payload;\r
+\r
+ switch( htons( pxHeader->type ) )\r
+ {\r
+ /* IP or ARP packet? */\r
+ case ETHTYPE_IP:\r
+ case ETHTYPE_ARP:\r
+ /* full packet send to tcpip_thread to process */\r
+ if( pxNetIf->input( p, pxNetIf ) != ERR_OK )\r
+ {\r
+ LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_input: IP input error\n" ) );\r
+ pbuf_free(p);\r
+ p = NULL;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ pbuf_free( p );\r
+ p = NULL;\r
+ break;\r
+ }\r
+ }\r
+\r
+ xInsideISR--;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvTxHandler( void *pvUnused )\r
+{\r
+ XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );\r
+}\r
+\r
+\r
+void vTemp( void )\r
+{\r
+char *pc;\r
+\r
+ XEmacLite_Recv( &xEMACInstance, pc );\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+#if 0\r
+\r
+static void\r
+xemacif_recv_handler(void *arg) {\r
+ struct xemac_s *xemac = (struct xemac_s *)(arg);\r
+ xemacliteif_s *xemacliteif = (xemacliteif_s *)(xemac->state);\r
+ XEmacLite *instance = xemacliteif->instance;\r
+ struct pbuf *p;\r
+ int len = 0;\r
+ struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];\r
+\r
+ XIntc_AckIntr(xtopologyp->intc_baseaddr, 1 << xtopologyp->intc_emac_intr);\r
+ p = pbuf_alloc(PBUF_RAW, XEL_MAX_FRAME_SIZE, PBUF_POOL);\r
+ if (!p) {\r
+#if LINK_STATS\r
+ lwip_stats.link.memerr++;\r
+ lwip_stats.link.drop++;\r
+#endif\r
+ /* receive and just ignore the frame.\r
+ * we need to receive the frame because otherwise emaclite will\r
+ * not generate any other interrupts since it cannot receive,\r
+ * and we do not actively poll the emaclite\r
+ */\r
+ XEmacLite_Recv(instance, xemac_tx_frame);\r
+ return;\r
+ }\r
+\r
+ /* receive the packet */\r
+ len = XEmacLite_Recv(instance, p->payload);\r
+\r
+ if (len == 0) {\r
+#if LINK_STATS\r
+ lwip_stats.link.drop++;\r
+#endif\r
+ return;\r
+ }\r
+\r
+ /* store it in the receive queue, where it'll be processed by xemacif input thread */\r
+ if (pq_enqueue(xemacliteif->recv_q, (void*)p) < 0) {\r
+#if LINK_STATS\r
+ lwip_stats.link.memerr++;\r
+ lwip_stats.link.drop++;\r
+#endif\r
+ return;\r
+ }\r
+\r
+#if !NO_SYS\r
+ sys_sem_signal(xemac->sem_rx_data_available);\r
+#endif\r
+\r
+}\r
+\r
+#endif\r
+\r
+\r
#include "lwip/mem.h"\r
#include "lwip/stats.h"\r
\r
+/* Very crude mechanism used to determine if the critical section handling\r
+functions are being called from an interrupt context or not. This relies on\r
+the interrupt handler setting this variable manually. */\r
+portBASE_TYPE xInsideISR = pdFALSE;\r
+\r
/*---------------------------------------------------------------------------*\r
* Routine: sys_mbox_new\r
*---------------------------------------------------------------------------*\r
err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost )\r
{\r
err_t xReturn;\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ if( xInsideISR != pdFALSE )\r
+ {\r
+ xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken );\r
+ }\r
+ else\r
+ {\r
+ xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( portTickType ) 0 );\r
+ }\r
\r
- if( xQueueSend( *pxMailBox, &pxMessageToPost, 0UL ) == pdPASS )\r
+ if( xReturn == pdPASS )\r
{\r
xReturn = ERR_OK;\r
}\r
\r
if( ulTimeOut != 0UL )\r
{\r
+ configASSERT( xInsideISR == ( portBASE_TYPE ) 0 );\r
+\r
if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) )\r
{\r
xEndTime = xTaskGetTickCount();\r
{\r
void *pvDummy;\r
unsigned long ulReturn;\r
+long lResult;\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
\r
if( ppvBuffer== NULL )\r
{\r
ppvBuffer = &pvDummy;\r
}\r
\r
- if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ) )\r
+ if( xInsideISR != pdFALSE )\r
+ {\r
+ lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken );\r
+ }\r
+ else\r
+ {\r
+ lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL );\r
+ }\r
+\r
+ if( lResult == pdPASS )\r
{\r
ulReturn = ERR_OK;\r
}\r
*---------------------------------------------------------------------------*/\r
void sys_sem_signal( sys_sem_t *pxSemaphore )\r
{\r
- xSemaphoreGive( *pxSemaphore );\r
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ if( xInsideISR != pdFALSE )\r
+ {\r
+ xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken );\r
+ }\r
+ else\r
+ {\r
+ xSemaphoreGive( *pxSemaphore );\r
+ }\r
}\r
\r
/*---------------------------------------------------------------------------*\r
*---------------------------------------------------------------------------*/\r
sys_prot_t sys_arch_protect( void )\r
{\r
- taskENTER_CRITICAL();\r
+ if( xInsideISR == pdFALSE )\r
+ {\r
+ taskENTER_CRITICAL();\r
+ }\r
return ( sys_prot_t ) 1;\r
}\r
\r
void sys_arch_unprotect( sys_prot_t xValue )\r
{\r
(void) xValue;\r
- taskEXIT_CRITICAL();\r
+ if( xInsideISR == pdFALSE )\r
+ {\r
+ taskEXIT_CRITICAL();\r
+ }\r
}\r
\r
/*\r