This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OMAP-L138: LAN8710A PHY issue

Other Parts Discussed in Thread: OMAPL138, AM1808, OMAP-L138

6874.sitaraif.c
/**
 * @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));
}


I am Using EVM OMAPL138 Development kit for Ethernet Interface between PC and Development Kit..I extracted the whole project from TI's official site.(From OMAPL138_StarterWare_1_10_04_01 /build/armv5/cgt_css/omapl138/evmOMAPL138/enet_lwip).But the PHY LAN8710a fails to acknowledge the access while reading ALIVE status register using MDIO bus.How is it resolved????

  • sitaraif.c
    /**
     * @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));
    }
    
    
    

  • Hi,

    As I see from your code, it is for Sitara devices (AM1808). Note that OMAP-L138 is a different device.

    Best Regards,
    Yordan
  • lwiplib.c
    /**
    *  \file lwiplib.c
    *
    *  \brief lwip related initializations
    */
    /*
     * 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 - http://www.ti.com/
    ** ALL RIGHTS RESERVED
    */
    
    /*
    ** lwIP Compile Time Options for SitaraWare.
    */
    #include "lwiplib.h"
    
    /*
    ** lwIP high-level API/Stack/IPV4/SNMP/Network Interface/PPP codes
    */
    #include "src/api/api_lib.c"
    #include "src/api/api_msg.c"
    #include "src/api/err.c"
    #include "src/api/netbuf.c"
    #include "src/api/netdb.c"
    #include "src/api/netifapi.c"
    #include "src/api/tcpip.c"
    #include "src/api/sockets.c"
    
    #include "src/core/dhcp.c"
    #include "src/core/dns.c"
    #include "src/core/init.c"
    #include "src/core/mem.c"
    #include "src/core/memp.c"
    #include "src/core/netif.c"
    #include "src/core/pbuf.c"
    #include "src/core/raw.c"
    #include "src/core/stats.c"
    #include "src/core/sys.c"
    #include "src/core/tcp.c"
    #include "src/core/tcp_in.c"
    #include "src/core/tcp_out.c"
    #include "src/core/udp.c"
    
    #include "src/core/ipv4/autoip.c"
    #include "src/core/ipv4/icmp.c"
    #include "src/core/ipv4/igmp.c"
    #include "src/core/ipv4/inet.c"
    #include "src/core/ipv4/inet_chksum.c"
    #include "src/core/ipv4/ip.c"
    #include "src/core/ipv4/ip_addr.c"
    #include "src/core/ipv4/ip_frag.c"
    
    #include "src/core/snmp/asn1_dec.c"
    #include "src/core/snmp/asn1_enc.c"
    #include "src/core/snmp/mib2.c"
    #include "src/core/snmp/mib_structs.c"
    #include "src/core/snmp/msg_in.c"
    #include "src/core/snmp/msg_out.c"
    
    #include "src/netif/etharp.c"
    #include "src/netif/loopif.c"
    
    #include "src/netif/ppp/auth.c"
    #include "src/netif/ppp/chap.c"
    #include "src/netif/ppp/chpms.c"
    #include "src/netif/ppp/fsm.c"
    #include "src/netif/ppp/ipcp.c"
    #include "src/netif/ppp/lcp.c"
    #include "src/netif/ppp/magic.c"
    #include "src/netif/ppp/md5.c"
    #include "src/netif/ppp/pap.c"
    #include "src/netif/ppp/ppp.c"
    #include "src/netif/ppp/ppp_oe.c"
    #include "src/netif/ppp/randm.c"
    #include "src/netif/ppp/vj.c"
    
    /*
    ** Sitara-specific lwIP interface/porting layer code.
    */
    #include "ports/am1808/perf.c"
    #include "ports/am1808/sys_arch.c"
    #include "ports/am1808/netif/sitaraif.c"
    #include "locator.c"
    
    /******************************************************************************
    **                       INTERNAL VARIABLE DEFINITIONS
    ******************************************************************************/
    /*
    ** The lwIP network interface structure for the Sitara Ethernet MAC.
    */
    static struct netif sitaraNetIF[MAX_EMAC_INSTANCE];
    
    /******************************************************************************
    **                          FUNCTION DEFINITIONS
    ******************************************************************************/
    /**
     *
     * \brief Initializes the lwIP TCP/IP stack.
     *
     * \param instNum  The instance index of the EMAC module
     * \param macArray Pointer to the MAC Address
     * \param ipAddr   The IP address to be used 
     * \param netMask  The network mask to be used 
     * \param gwAddr   The Gateway address to be used 
     * \param ipMode   The IP Address Mode.
     *        ipMode can take the following values\n
     *             IPADDR_USE_STATIC - force static IP addressing to be used \n
     *             IPADDR_USE_DHCP - force DHCP with fallback to Link Local \n
     *             IPADDR_USE_AUTOIP - force  Link Local only
     *
     * This function performs initialization of the lwIP TCP/IP stack for the
     * Sitara EMAC, including DHCP and/or AutoIP, as configured.
     *
     * \return IP Address.
    */
    unsigned int lwIPInit(unsigned int instNum, unsigned char *macArray,
                          unsigned int ipAddr, unsigned int netMask, 
                          unsigned int gwAddr, unsigned int ipMode)
    {
        struct ip_addr ip_addr;
        struct ip_addr net_mask;
        struct ip_addr gw_addr;
        volatile unsigned char *state;
        unsigned int *ipAddrPtr;
        volatile unsigned int cnt = 0x3FFFFFFF;
     
        lwip_init();
    
        /* Setup the network address values. */
        if(ipMode == IPADDR_USE_STATIC)
        {
            ip_addr.addr = htonl(ipAddr);
            net_mask.addr = htonl(netMask);
            gw_addr.addr = htonl(gwAddr);
        }
       
        else
        {
            ip_addr.addr = 0;
            net_mask.addr = 0;
            gw_addr.addr = 0;
        }
    
        sitaraif_macaddrset(instNum, macArray);
    
        /*
        ** Create, configure and add the Ethernet controller interface with
        ** default settings.  ip_input should be used to send packets directly to
        ** the stack. The lwIP will internaly call the sitaraif_init function. 
        */
        if(NULL ==
           netif_add(&sitaraNetIF[instNum], &ip_addr, &net_mask, &gw_addr, &instNum, 
                  sitaraif_init, ip_input))
        {
            return 0;
        };
    
        netif_set_default(&sitaraNetIF[instNum]);
    
        /* Start DHCP, if enabled. */
    #if LWIP_DHCP
        if(ipMode == IPADDR_USE_DHCP)
        {
            dhcp_start(&sitaraNetIF[instNum]);
        }
    #endif
    
        /* Start AutoIP, if enabled and DHCP is not. */
    #if LWIP_AUTOIP
        if(ipMode == IPADDR_USE_AUTOIP)
        {
            autoip_start(&sitaraNetIF[instNum]);
        }
    #endif
    
        if(ipMode != IPADDR_USE_STATIC) 
        {
            /* wait till the dynamic IP address is properly assigned */
            state = &(sitaraNetIF[instNum].dhcp->state);
          
            while((*state != DHCP_BOUND) && (cnt--));
    
            if(0 == cnt)
            {
                return 0;
            }
        }
        
        else
        {
           /* Bring the interface up */
           netif_set_up(&sitaraNetIF[instNum]);
        }
      
        ipAddrPtr = (unsigned int*)&(sitaraNetIF[instNum].ip_addr);
    
        return (*ipAddrPtr);
    }
    
    /*
     * \brief   Checks if the ethernet link is up
     *
     * \param   instNum  The instance number of EMAC module 
     *
     * \return  Interface status.
    */
    unsigned int lwIPNetIfStatusGet(unsigned int instNum) 
    {
        
        return (sitaraif_netif_status(&sitaraNetIF[instNum]));
    }
    
    /*
     * \brief   Checks if the ethernet link is up
     *
     * \param   instNum  The instance number of EMAC module 
     *
     * \return  The link status.
    */
    unsigned int lwIPLinkStatusGet(unsigned int instNum) 
    {
        return (sitaraif_link_status(&sitaraNetIF[instNum]));     
    }
    
    /**
     * \brief   Interrupt handler for Receive Interrupt. Directly calls the
     *          sitara interface receive interrupt handler.
     *
     * \param   instNum  The instance number of EMAC module for which receive 
     *                   interrupt happened
     *
     * \return  None.
    */
    void lwIPRxIntHandler(unsigned int instNum) 
    {
        sitaraif_rx_inthandler(&sitaraNetIF[instNum]);
    }
    
    /**
     * \brief   Interrupt handler for Transmit Interrupt. Directly calls the 
     *          sitara interface transmit interrupt handler.
     *
     * \param   instNum  The instance number of EMAC module for which transmit
     *                   interrupt happened
     *
     * \return  None.
    */
    void lwIPTxIntHandler(unsigned int instNum)
    {
        sitaraif_tx_inthandler(&sitaraNetIF[instNum]);
    }
    
    /***************************** End Of File ***********************************/
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    Hi Yordan,

                    Thanks for your reply.

                                                                      In  the project i have mentioned above (OMAPL138_StarterWare_1_10_04_01 /build/armv5/cgt_css/omapl138/evmOMAPL138/enet_lwip),there is a file named lwiplib.c . In this,  there is some include files for sitara AM1808

    devices.Then why is the need for this include files in evmOMAPL138 project. I will attach  lwiplib.c file.

  • Hi yordan,

    The project i mentioned above will work both on AM1808 board and EVM OMAPL138 board. The software configuration is same for both devices .

    But my problem is below.

    if(!((MDIOPhyAliveStatusGet(sitaraif->mdio_base)

    >> sitaraif->

    phy_addr) & 0x01 )) {

    return ERR_CONN;

    }

    in the sitaraif.c file it returns true making an error in the connection, as if there was no link. I changedthe staic ip in the lwipopts.h file. what might be the reason???
  • Hi,

    I've notified the RTOS team. They will post their feedback directly here.

    Best Regards,
    Yordan
  • Hi Arun,

    Can you confirm that you are using the OMAP-L138 EVM and NOT the OMAP-L138 LCDK (shown below)?

  • Hi sahin,

    The board i have been using is attached above.This is EVM Omapl138.

    Regards
    Arun kumar
  • Hi Arun,

    I have not been able to reproduce this issue with the board I have here. Have you made any changes to the example code? Are you seeing anything over UART either before/after changing to static IP?

    Also, make sure your DIP switches are set to the "EMU Debug" configuration as shown below when loading over CCS.


  • Hi sahin,

    Thanks for your reply.

                 DIP switches are set to the "EMU Debug" configuration in my board.U can see in my development board that i have attached above. Can u please conform is there any switches for enabling lan8710a in development board.

              

    Regards.

    Arun kumar 

              

  • Hi Arun,

    There aren't any switches on the EVM for enabling/disabling the PHY. Can you confirm that you have not made any changes to the example?
  • Hi Sahin,
    Finally the problem is solved. some hardware problem in my SOM chip. Anyway thanks a lot for your valuable replies.

    Regards
    Arun Kumar