Other Parts Discussed in Thread: OMAPL138, AM1808, OMAP-L138
/**
* @file - sitaraif.c
* lwIP Ethernet interface for Sitara Devices
*
*/
/**
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/**
* Copyright (c) 2010 Texas Instruments Incorporated
*
* This file is dervied from the "ethernetif.c" skeleton Ethernet network
* interface driver for lwIP.
*
*/
#include "src/include/lwip/opt.h"
#include "src/include/lwip/def.h"
#include "src/include/lwip/mem.h"
#include "src/include/lwip/pbuf.h"
#include "src/include/lwip/sys.h"
#include "src/include/lwip/stats.h"
#include "src/include/lwip/snmp.h"
#include "src/include/netif/etharp.h"
#include "src/include/netif/ppp_oe.h"
#include "src/include/lwip/err.h"
#include "ports/am1808/include/netif/sitaraif.h"
#include "ports/am1808/include/arch/cc.h"
/* Sitara DriverLib Header Files required for this interface driver. */
#include "hw_types.h"
#include "emac.h"
#include "mdio.h"
#include "interrupt.h"
#include "lan8710a.h"
/* EMAC Control RAM size in bytes */
#ifndef SIZE_EMAC_CTRL_RAM
#define SIZE_EMAC_CTRL_RAM 0x2000
#endif
/* MDIO input and output frequencies in Hz */
#define MDIO_FREQ_INPUT 75000000
#define MDIO_FREQ_OUTPUT 1000000
#define EMAC_BUF_DESC_OWNER 0x20000000
#define EMAC_BUF_DESC_SOP 0x80000000
#define EMAC_BUF_DESC_EOP 0x40000000
#define EMAC_BUF_DESC_EOQ 0x10000000
#define MAX_TRANSFER_UNIT 1500
#define PBUF_LEN_MAX MAX_TRANSFER_UNIT
/* Base Addresses */
#define EMAC_CTRL_RAM_0_BASE 0x01E20000
#define EMAC_0_BASE 0x01E23000
#define EMAC_CTRL_0_BASE 0x01E22000
#define MDIO_0_BASE 0x01E24000
#define MAX_RX_PBUF_ALLOC 10
#define MIN_PKT_LEN 60
/* Define those to better describe the network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'
/* EMAC TX Buffer descriptor data structure */
struct emac_tx_bd {
volatile struct emac_tx_bd *next;
volatile u32_t bufptr;
volatile u32_t bufoff_len;
volatile u32_t flags_pktlen;
/* helper to know which pbuf this tx bd corresponds to */
volatile struct pbuf *pbuf;
}emac_tx_bd;
/* EMAC RX Buffer descriptor data structure */
struct emac_rx_bd {
volatile struct emac_rx_bd *next;
volatile u32_t bufptr;
volatile u32_t bufoff_len;
volatile u32_t flags_pktlen;
/* helper to know which pbuf this rx bd corresponds to */
volatile struct pbuf *pbuf;
}emac_rx_bd;
/**
* Helper struct to hold the data used to operate on a particular
* receive channel
*/
struct rxch {
volatile struct emac_rx_bd *free_head;
volatile struct emac_rx_bd *active_head;
volatile struct emac_rx_bd *active_tail;
u32_t freed_pbuf_len;
}rxch;
/**
* Helper struct to hold the data used to operate on a particular
* transmit channel
*/
struct txch {
volatile struct emac_tx_bd *free_head;
volatile struct emac_tx_bd *active_tail;
volatile struct emac_tx_bd *next_bd_to_process;
}txch;
/**
* Helper struct to hold private data used to operate the ethernet interface.
*/
struct sitaraif {
/* emac instance number */
u32_t inst_num;
u8_t mac_addr[6];
/* emac base address */
u32_t emac_base;
/* emac controller base address */
volatile u32_t emac_ctrl_base;
volatile u32_t emac_ctrl_ram;
/* mdio base address */
volatile u32_t mdio_base;
/* phy parameters for this instance - for future use */
u32_t phy_addr;
u32_t (*phy_autoneg)(u32_t, u32_t, u16_t);
u32_t (*phy_partnerability)(u32_t, u32_t, u16_t*);
/* The tx/rx channels for the interface */
struct txch txch;
struct rxch rxch;
}sitaraif;
/* Defining interface for all the emac instances */
static struct sitaraif sitaraif_data[MAX_EMAC_INSTANCE];
/**
* Function to set the MAC address to the interface
* @param inst_num the instance number
* @return none.
*/
void
sitaraif_macaddrset(u32_t inst_num, u8_t *mac_addr) {
struct sitaraif *sitaraif;
u32_t temp;
sitaraif = &sitaraif_data[inst_num];
/* set MAC hardware address */
for(temp = 0; temp < ETHARP_HWADDR_LEN; temp++) {
sitaraif->mac_addr[temp] = mac_addr[(ETHARP_HWADDR_LEN - 1) - temp];
}
}
/**
* Function to setup the instance parameters inside the interface
* @param sitaraif
* @return none.
*/
static void
sitaraif_inst_config(struct sitaraif *sitaraif) {
if(sitaraif->inst_num == 0) {
sitaraif->emac_base = EMAC_0_BASE;
sitaraif->emac_ctrl_base = EMAC_CTRL_0_BASE;
sitaraif->emac_ctrl_ram = EMAC_CTRL_RAM_0_BASE;
sitaraif->mdio_base = MDIO_0_BASE;
#if defined(lcdkOMAPL138) || defined(lcdkC6748)
sitaraif->phy_addr = 7;
#else
sitaraif->phy_addr = 0;
#endif
sitaraif->phy_autoneg = Lan8710aAutoNegotiate;
sitaraif->phy_partnerability = Lan8710aPartnerAbilityGet;
}
}
/**
* Function to setup the link. AutoNegotiates with the phy for link
* setup and set the EMAC with the result of autonegotiation.
* @param sitaraif
* @return ERR_OK if everything passed
* others if not passed
*/
static err_t
sitaraif_link_setup(struct sitaraif *sitaraif)
{
err_t linkstat = ERR_CONN;
u16_t partnr_ablty;
u32_t phyduplex = EMAC_DUPLEX_HALF;
volatile unsigned int delay = 0xFFFFF;
if(sitaraif->inst_num == 0) {
if(Lan8710aAutoNegotiate(sitaraif->mdio_base, sitaraif->phy_addr,
(LAN8710A_100BTX | LAN8710A_100BTX_FD
| LAN8710A_10BT | LAN8710A_10BT_FD)) == TRUE) {
linkstat = ERR_OK;
Lan8710aPartnerAbilityGet(sitaraif->mdio_base, sitaraif->phy_addr,
&partnr_ablty);
/* Check for 100 Mbps and duplex capability */
if(partnr_ablty & LAN8710A_100BTX_FD) {
phyduplex = EMAC_DUPLEX_FULL;
}
}
else {
linkstat = ERR_CONN;
}
}
else {
linkstat = ERR_CONN;
}
/* Set the EMAC with the negotiation results if it is successful */
if(linkstat == ERR_OK) {
EMACDuplexSet(sitaraif->emac_base, phyduplex);
}
/* Wait for the MII to settle down */
while(delay--);
return linkstat;
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf might be
* chained. That is, one pbuf can span more than one tx buffer descriptors
*
* @param sitaraif the network interface state for this ethernetif
* @param pbuf the pbuf which is to be sent over EMAC
* @return None
*/
static void
sitaraif_transmit(struct sitaraif *sitaraif, struct pbuf *pbuf) {
struct pbuf *q;
struct txch *txch;
volatile struct emac_tx_bd *curr_bd, *active_head, *bd_end;
txch = &(sitaraif->txch);
/* Get the buffer descriptor which is free to transmit */
curr_bd = txch->free_head;
active_head = curr_bd;
/* Update the total packet length */
curr_bd->flags_pktlen &= ~0xFFFF;
curr_bd->flags_pktlen |= pbuf->tot_len;
/* Indicate the start of the packet */
curr_bd->flags_pktlen |= (EMAC_BUF_DESC_SOP | EMAC_BUF_DESC_OWNER);
/* Copy pbuf information into TX buffer descriptors */
for(q = pbuf; q != NULL; q = q->next) {
/* Intialize the buffer pointer and length */
curr_bd->bufptr = (u32_t)(q->payload);
curr_bd->bufoff_len = (q->len) & 0xFFFF;
bd_end = curr_bd;
curr_bd->pbuf = pbuf;
curr_bd = curr_bd->next;
}
/* Indicate the end of the packet */
bd_end->next = NULL;
bd_end->flags_pktlen |= EMAC_BUF_DESC_EOP;
txch->free_head = curr_bd;
/* For the first time, write the HDP with the filled bd */
if(txch->active_tail == NULL) {
EMACTxHdrDescPtrWrite(sitaraif->emac_base, (unsigned int)(active_head), 0);
}
/*
* Chain the bd's. If the DMA engine, already reached the end of the chain,
* the EOQ will be set. In that case, the HDP shall be written again.
*/
else {
curr_bd = txch->active_tail;
curr_bd->next = active_head;
if(curr_bd->flags_pktlen & EMAC_BUF_DESC_EOQ) {
/* Write the Header Descriptor Pointer and start DMA */
EMACTxHdrDescPtrWrite(sitaraif->emac_base, (unsigned int)(active_head), 0);
}
}
txch->active_tail = bd_end;
}
/**
* This function will send a packet through the emac if the channel is
* available. Otherwise, the packet will be queued in a pbuf queue.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
*/
static err_t
sitaraif_output(struct netif *netif, struct pbuf *p) {
SYS_ARCH_DECL_PROTECT(lev);
/**
* This entire function must run within a "critical section" to preserve
* the integrity of the transmit pbuf queue.
*
*/
SYS_ARCH_PROTECT(lev);
/* adjust the packet length if less than minimum required */
if(p->tot_len < MIN_PKT_LEN) {
p->tot_len = MIN_PKT_LEN;
p->len = MIN_PKT_LEN;
}
/**
* Bump the reference count on the pbuf to prevent it from being
* freed till we are done with it.
*
*/
pbuf_ref(p);
/* call the actual transmit function */
sitaraif_transmit(netif->state, p);
/* Return to prior interrupt state and return. */
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
/**
* In this function, the hardware should be initialized.
* Called from sitaraif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
unsigned int check = 0;
static err_t
sitaraif_hw_init(struct netif *netif)
{
u32_t temp, channel;
u32_t num_bd, pbuf_cnt = 0;
#if defined(lcdkOMAPL138) || defined(lcdkC6748)
volatile u32_t delay = 0xfffff;
#else
volatile u32_t delay = 0xfff;
#endif
volatile struct emac_tx_bd *curr_txbd, *last_txbd;
volatile struct emac_rx_bd *curr_bd, *last_bd;
struct sitaraif *sitaraif;
struct txch *txch;
struct rxch *rxch;
struct pbuf *p, *q;
sitaraif = netif->state;
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
for(temp = 0; temp < ETHARP_HWADDR_LEN; temp++) {
netif->hwaddr[temp] = sitaraif->mac_addr[(ETHARP_HWADDR_LEN - 1) - temp];
}
/* maximum transfer unit */
netif->mtu = MAX_TRANSFER_UNIT;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
EMACInit(sitaraif->emac_ctrl_base, sitaraif->emac_base);
MDIOInit(sitaraif->mdio_base, MDIO_FREQ_INPUT, MDIO_FREQ_OUTPUT);
while(delay--);
EMACRxBroadCastEnable(sitaraif->emac_base, 0);
/* Set the MAC Addresses in EMAC hardware */
EMACMACSrcAddrSet(sitaraif->emac_base, sitaraif->mac_addr);
for(channel = 0; channel < 8; channel++) {
EMACMACAddrSet(sitaraif->emac_base, channel, sitaraif->mac_addr, EMAC_MACADDR_MATCH);
}
if(!((MDIOPhyAliveStatusGet(sitaraif->mdio_base)
>> sitaraif->phy_addr) & 0x01 ))
{
return ERR_CONN;
}
if(!Lan8710aLinkStatusGet(sitaraif->mdio_base, sitaraif->phy_addr, 10000)) {
return ERR_CONN;
}
if(sitaraif_link_setup(sitaraif) != ERR_OK) {
return ERR_CONN;
}
txch = &(sitaraif->txch);
/**
* Initialize the Descriptor Memory For TX and RX
* Only Channel 0 is supported for both TX and RX
*/
txch->free_head = (volatile struct emac_tx_bd*)(sitaraif->emac_ctrl_ram);
txch->next_bd_to_process = txch->free_head;
txch->active_tail = NULL;
/* Set the number of descriptors for the channel */
num_bd = (SIZE_EMAC_CTRL_RAM >> 1) / sizeof(emac_tx_bd);
curr_txbd = txch->free_head;
/* Initialize all the TX buffer Descriptors */
while(num_bd--) {
curr_txbd->next = curr_txbd + 1;
curr_txbd->flags_pktlen = 0;
last_txbd = curr_txbd;
curr_txbd = curr_txbd->next;
}
last_txbd->next = txch->free_head;
/* Initialize the descriptors for the RX channel */
rxch = &(sitaraif->rxch);
rxch->active_head = (volatile struct emac_rx_bd*)(curr_txbd + 1);
rxch->free_head = NULL;
rxch->freed_pbuf_len = 0;
num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(emac_rx_bd) - 1);
curr_bd = rxch->active_head;
last_bd = curr_bd;
/*
** Allocate the pbufs for the maximum count permitted or till the
** number of buffer desceriptors expire, which ever is earlier.
*/
while(pbuf_cnt < MAX_RX_PBUF_ALLOC) {
p = pbuf_alloc(PBUF_RAW, PBUF_LEN_MAX, PBUF_POOL);
pbuf_cnt++;
if(p != NULL) {
/* write the descriptors if there are enough numbers to hold the pbuf*/
if(((u32_t)pbuf_clen(p)) <= num_bd) {
for(q = p; q != NULL; q = q->next) {
curr_bd->bufptr = (u32_t)(q->payload);
curr_bd->bufoff_len = q->len;
curr_bd->next = curr_bd + 1;
curr_bd->flags_pktlen = EMAC_BUF_DESC_OWNER;
/* Save the pbuf */
curr_bd->pbuf = q;
last_bd = curr_bd;
curr_bd = curr_bd->next;
num_bd--;
}
}
/* free the allocated pbuf if no free descriptors are left */
else {
pbuf_free(p);
break;
}
}
else {
break;
}
}
last_bd->next = NULL;
rxch->active_tail = last_bd;
/* Acknowledge receive and transmit interrupts for proper interrupt pulsing*/
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_RX);
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_TX);
EMACRxUnicastSet(sitaraif->emac_base, 0);
EMACNumFreeBufSet(sitaraif->emac_base, 0, 10);
EMACTxEnable(sitaraif->emac_base);
EMACRxEnable(sitaraif->emac_base);
/* Write the RX HDP for channel 0 */
EMACRxHdrDescPtrWrite(sitaraif->emac_base, (u32_t)rxch->active_head, 0);
EMACMIIEnable(sitaraif->emac_base);
/**
* Enable the Transmission and reception, enable the interrupts for
* channel 0 and for control core 0
*/
EMACTxIntPulseEnable(sitaraif->emac_base, sitaraif->emac_ctrl_base, 0, 0);
EMACRxIntPulseEnable(sitaraif->emac_base, sitaraif->emac_ctrl_base, 0, 0);
return ERR_OK;
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function sitaraif_hw_init() to do the
* low level initializations.
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t
sitaraif_init(struct netif *netif)
{
/* Get the instance number first */
unsigned int inst_num = *(unsigned int*)(netif->state);
struct sitaraif *sitaraif;
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
sitaraif = &sitaraif_data[inst_num];
netif->state = sitaraif;
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
sitaraif->inst_num = inst_num;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->num = (u8_t)inst_num;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...)
*/
netif->output = etharp_output;
netif->linkoutput = sitaraif_output;
/* initialize the hardware */
sitaraif_inst_config(sitaraif);
return (sitaraif_hw_init(netif));
}
/**
* Handler for Receive interrupt. Packet processing is done in this
* interrupt handler itself.
*
* @param netif the lwip network interface structure for this ethernetif
* @return none
*/
void
sitaraif_rx_inthandler(struct netif *netif) {
struct sitaraif *sitaraif;
struct rxch *rxch;
volatile struct emac_rx_bd *curr_bd, *processed_bd, *curr_tail, *last_bd;
volatile struct pbuf *pbuf, *q, *new_pbuf;
u32_t ex_len = 0, len_to_alloc = 0;
u16_t tot_len;
sitaraif = netif->state;
rxch = &(sitaraif->rxch);
/* Get the bd which contains the earliest filled data */
curr_bd = rxch->active_head;
last_bd = rxch->active_tail;
/**
* Process the descriptors as long as data is available
* when the DMA is receiving data, SOP flag will be set
*/
while(curr_bd->flags_pktlen & EMAC_BUF_DESC_SOP) {
ex_len = 0;
len_to_alloc = 0;
/* Start processing once the packet is loaded */
if((curr_bd->flags_pktlen & EMAC_BUF_DESC_OWNER)
!= EMAC_BUF_DESC_OWNER) {
if(rxch->free_head == NULL) {
/* this bd chain will be freed after processing */
rxch->free_head = curr_bd;
}
/* Get the total length of the packet. curr_bd points to the start
* of the packet.
*/
tot_len = (curr_bd->flags_pktlen) & 0xFFFF;
/* Get the start of the pbuf queue */
q = curr_bd->pbuf;
do {
/* Get the pbuf pointer which is associated with the current bd */
pbuf = curr_bd->pbuf;
/* If the earlier pbuf ended, update the chain */
if(pbuf->next == NULL) {
pbuf->next = (struct pbuf*)(curr_bd->next)->pbuf;
}
len_to_alloc += pbuf->len;
/* Update the len and tot_len fields for the pbuf in the chain*/
pbuf->len = (curr_bd->bufoff_len) & 0xFFFF;
pbuf->tot_len = tot_len - ex_len ;
processed_bd = curr_bd;
ex_len += pbuf->len;
curr_bd = curr_bd->next;
} while((processed_bd->flags_pktlen & EMAC_BUF_DESC_EOP)
!= EMAC_BUF_DESC_EOP);
/**
* Close the chain for this pbuf. A full packet is received in
* this pbuf chain. Now this pbuf can be given to upper layers for
* processing. The start of the pbuf chain is now 'q'.
*/
pbuf->next = NULL;
/* Adjust the link statistics */
LINK_STATS_INC(link.recv);
/* Process the packet */
if(ethernet_input((struct pbuf *)q, netif) != ERR_OK) {
/* Adjust the link statistics */
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
}
/* Acknowledge that this packet is processed */
EMACRxCPWrite(sitaraif->emac_base, 0, (unsigned int)processed_bd);
rxch->active_head = curr_bd;
/**
* The earlier pbuf chain is freed from the upper layer. So, we need to
* allocate a new pbuf chain and update the descriptors with the pbuf info.
* To support chaining, the total length freed by the upper layer is tracked.
* Care should be taken even if the allocation fails.
*/
/**
* now len_to_alloc will contain the length of the pbuf which was freed
* from the upper layer
*/
rxch->freed_pbuf_len += len_to_alloc;
new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL);
/* Write the descriptors with the pbuf info till either of them expires */
if(new_pbuf != NULL) {
curr_bd = rxch->free_head;
for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next) {
curr_bd->bufptr = (u32_t)(q->payload);
/* no support for buf_offset. RXBUFFEROFFEST register is 0 */
curr_bd->bufoff_len = (q->len) & 0xFFFF;
curr_bd->flags_pktlen = EMAC_BUF_DESC_OWNER;
rxch->freed_pbuf_len -= q->len;
/* Save the pbuf */
curr_bd->pbuf = q;
last_bd = curr_bd;
curr_bd = curr_bd->next;
}
/**
* At this point either pbuf expired or no rxbd to allocate. If
* there are no, enough rx bds to allocate all pbufs in the chain,
* free the rest of the pbuf
*/
if(q != NULL) {
pbuf_free((struct pbuf *)q);
}
curr_tail = rxch->active_tail;
last_bd->next = NULL;
curr_tail->next = rxch->free_head;
/**
* Check if the reception has ended. If the EOQ flag is set, the NULL
* Pointer is taken by the DMA engine. So we need to write the RX HDP
* with the next descriptor.
*/
if(curr_tail->flags_pktlen & EMAC_BUF_DESC_EOQ) {
EMACRxHdrDescPtrWrite(sitaraif->emac_base, (u32_t)(rxch->free_head), 0);
}
rxch->free_head = curr_bd;
rxch->active_tail = last_bd;
}
}
curr_bd = rxch->active_head;
}
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_RX);
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_TX);
}
/**
* Handler for EMAC Transmit interrupt
*
* @param netif the lwip network interface structure for this ethernetif
* @return none
*/
void
sitaraif_tx_inthandler(struct netif *netif) {
struct txch *txch;
struct sitaraif *sitaraif;
volatile struct emac_tx_bd *curr_bd, *next_bd_to_process;
sitaraif = netif->state;
txch = &(sitaraif->txch);
next_bd_to_process = txch->next_bd_to_process;
curr_bd = next_bd_to_process;
/* Check for correct start of packet */
while((curr_bd->flags_pktlen) & EMAC_BUF_DESC_SOP) {
/* Make sure that the transmission is over */
while((curr_bd->flags_pktlen & EMAC_BUF_DESC_OWNER)
== EMAC_BUF_DESC_OWNER);
/* Traverse till the end of packet is reached */
while(((curr_bd->flags_pktlen) & EMAC_BUF_DESC_EOP) != EMAC_BUF_DESC_EOP) {
curr_bd = curr_bd->next;
}
next_bd_to_process->flags_pktlen &= ~(EMAC_BUF_DESC_SOP);
curr_bd->flags_pktlen &= ~(EMAC_BUF_DESC_EOP);
/**
* If there are no more data transmitted, the next interrupt
* shall happen with the pbuf associated with the free_head
*/
if(curr_bd->next == NULL) {
txch->next_bd_to_process = txch->free_head;
}
else {
txch->next_bd_to_process = curr_bd->next;
}
/* Acknowledge the EMAC and free the corresponding pbuf */
EMACTxCPWrite(sitaraif->emac_base, 0, (u32_t)curr_bd);
pbuf_free((struct pbuf *)curr_bd->pbuf);
LINK_STATS_INC(link.xmit);
next_bd_to_process = txch->next_bd_to_process;
curr_bd = next_bd_to_process;
}
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_RX);
EMACCoreIntAck(sitaraif->emac_base, EMAC_INT_CORE0_TX);
}
/**
* Gets the netif status
*
* @param the netif whoes status to be checked
* @return the status
*/
u32_t
sitaraif_netif_status(struct netif *netif) {
return (netif_is_up(netif));
}
/**
* returns the link status
*
* @param the netif whoes link to be checked
* @return the status
*/
u32_t
sitaraif_link_status(struct netif *netif) {
struct sitaraif *sitaraif = netif->state;
return (Lan8710aLinkStatusGet(sitaraif->mdio_base,
sitaraif->phy_addr,
10000));
}

