]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blobdiff - rpp/src/rpp/eth.c
Merge port and gpio definitions into one file in the DRV layer
[pes-rpp/rpp-lib.git] / rpp / src / rpp / eth.c
index 8a540b6394071870a24ac7561d544adade7e1af8..0d3fd7230e6fc59c8a15e68514a0fec677eb6506 100644 (file)
@@ -1,5 +1,6 @@
 /**
  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * Copyright (C) 2013-2015 Czech Technical University in Prague
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification,
@@ -27,6 +28,9 @@
  * This file is part of the lwIP TCP/IP stack.
  *
  * Author: Adam Dunkels <adam@sics.se>
+ *         Carlos Jenkins <carlos@jenkins.co.cr>
+ *         Rostislav Lisovy <lisovy@gmail.com>
+ *         Jan Doležal <pm.jenik@gmail.com>
  *
  */
 
  * interface driver for lwIP.
  *
  */
-/* Copyright (C) 2013 Czech Technical University in Prague
- *
- * Authors:
- *     - Carlos Jenkins <carlos@jenkins.co.cr>
- *     - Rostislav Lisový
- *     - Jan Doležal <pm.jenik@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * File : eth.c
- * Abstract:
- *     Ethernet Communication RPP API implementation file. Using one PHY.
- *
- * References:
- *     eth.h
- *     RPP API documentation.
- */
+
+#include "rpp/rpp.h"
+
+#ifndef FREERTOS_POSIX
 
 /* lwIP headers */
 #include "lwip/init.h"
+#include "lwip/timers.h" /* for DHCP binding in NO_SYS mode */
 #include "lwip/sys.h" /* includes - lwip/opt.h, lwip/err.h, arch/sys_arch.h */
 #include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */
 #include "lwip/stats.h" /* includes - lwip/mem.h, lwip/memp.h, lwip/opt.h */
 #include "netif/ppp_oe.h"
 /* end - lwIP headers */
 
-#include "hal/hal.h"
-#include "rpp/rpp.h"
+#include "drv/digital_io.h"
 #include "sys/sys.h" /* includes - sys/phy_dp83848h.h */
+#include "drv/emac.h"
 #include "os/os.h"
 #include "types.h"
 
 
-#if rppCONFIG_INCLUDE_ETH == 1
-
-/* options */
-
 /* Number of EMAC Instances */
-#define MAX_EMAC_INSTANCE         1
-
-#define EMAC_CTRL_RAM_BASE_m(x)     EMAC_CTRL_RAM_##x##_BASE
-#define EMAC_BASE_m(x)              EMAC_##x##_BASE
-#define EMAC_CTRL_BASE_m(x)         EMAC_CTRL_##x##_BASE
-#define MDIO_BASE_m(x)              MDIO_##x##_BASE
-/* -EMAC0- */
-#define EMAC_CTRL_RAM_0_BASE      EMAC_CTRL_RAM_BASE
-#define EMAC_0_BASE               EMAC_BASE
-#define EMAC_CTRL_0_BASE          EMAC_CTRL_BASE
-#define MDIO_0_BASE               MDIO_BASE
-/* -EMAC0- end */
-/* EMAC Control RAM size in bytes */
-#ifndef SIZE_EMAC_CTRL_RAM
-#define SIZE_EMAC_CTRL_RAM        0x2000U
-#endif
-
-#define DEFAULT_PHY_ADDR          0x1
-#define FIND_FIRST_PHY_ALIVE      1 /* or use default (phy_address: 1) */
-#define NUM_OF_PHYs               32
-#define SIZE_OF_DESC              16 /* in bytes */
-#define CHANNEL                   0 /* channel number for everything - for rx, tx, unicast, broadcast or damaged frames ; there are different channels for rx and tx operations */
-#define PHY_LINK_MONITOR_INT      0 /* turn on handling interrupt risen when link status is changed (cable out or in) */
+#define MAX_EMAC_INSTANCE                      1
+
+#define DEFAULT_PHY_ADDR                       0x1
+#define FIND_FIRST_PHY_ALIVE                   1 /* or use default (phy_address: 1) */
+#define NUM_OF_PHYs                            32
+
+/* Size of the Buffer descriptor defined by the EMAC in bytes */
+#define SIZE_OF_DESC                           16
+
+/* Channel number used for for RX, TX, unicast, broadcast or damaged frames;
+ * there are different channels for rx and tx operations (i.e. RXCH0 != TXCH0) */
+#define CHANNEL                                        0
+
+/* take in account oversized frames */
+#define MAX_TRANSFER_UNIT                      1500
+
+/* WARNING!
+ * Be very carefull when setting this value. We have to keep in mind
+ * that pbuf_alloc(..., PBUF_POOL) will usualy return a chain of PBUFs
+ * pointing to the statically preallocated buffers (of the same size).
+ * The problem is that if we ask to allocate 300 bytes whereby the size
+ * of the statically preallocated PBUFs (PBUF_POOL_BUFSIZE) is 256, we
+ * will get a chain containing two PBUFs -- one *reporting* its size to
+ * be 256 bytes, the other one 44 bytes.
+ * Everything seems to be just fine however during RX, after we call
+ * netif->input(pbuf, netif) we have to newly allocate the PBUF(s) and
+ * properly set the apropriate BDs. This will however work only if the
+ * number of the freed BDs is the same as the number of the BDs newly
+ * initialized. One possible situation when this may fail is when multiple
+ * non-256 byte sized PBUFs will move near to each other, i.e. 3 BDs:
+ * 256 B, 44 B, 44 B -- 344 bytes will be freed (3 BDs) but the new call
+ * to pbuf_alloc(...) will return a chain comprising only two PBUFs
+ * (256 B, 88 B).
+ * This is the implementation limitation. The PBUF_LEN_MAX should therefore
+ * be multiple of PBUF_POOL_BUFSIZE
+ */
+#define PBUF_LEN_MAX                           (PBUF_POOL_BUFSIZE * 6)
 
-#define MAX_TRANSFER_UNIT         1500 /* take in account oversized frames */
-#define PBUF_LEN_MAX              MAX_TRANSFER_UNIT
-#define MAX_RX_PBUF_ALLOC         15 /* no need to limit it here -> it's better to do it in lwipopts.h */
-#define MIN_PKT_LEN               60
+/* Maximum number of PBUFs preallocated in the driver
+ * init function to be used for the RX
+ */
+#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'
-/* end options */
-
-#define MAC_ADDR_LEN              ETHARP_HWADDR_LEN
-
-
-/* Packet Flags EMAC_Desc - tx and rx */
-#define EMAC_DSC_FLAG_SOP        0x80000000u
-#define EMAC_DSC_FLAG_EOP        0x40000000u
-#define EMAC_DSC_FLAG_OWNER      0x20000000u
-#define EMAC_DSC_FLAG_EOQ        0x10000000u
-#define EMAC_DSC_FLAG_TDOWNCMPLT 0x08000000u
-#define EMAC_DSC_FLAG_PASSCRC    0x04000000u
-/* Packet Flags - in addition to rx */
-#define EMAC_DSC_FLAG_JABBER     0x02000000u
-#define EMAC_DSC_FLAG_OVERSIZE   0x01000000u
-#define EMAC_DSC_FLAG_FRAGMENT   0x00800000u
-#define EMAC_DSC_FLAG_UNDERSIZED 0x00400000u
-#define EMAC_DSC_FLAG_CONTROL    0x00200000u
-#define EMAC_DSC_FLAG_OVERRUN    0x00100000u
-#define EMAC_DSC_FLAG_CODEERROR  0x00080000u
-#define EMAC_DSC_FLAG_ALIGNERROR 0x00040000u
-#define EMAC_DSC_FLAG_CRCERROR   0x00020000u
-#define EMAC_DSC_FLAG_NOMATCH    0x00010000u
-
-/********** TI structs ***********/
-
-/* EMAC TX Buffer descriptor data structure */
-struct emac_tx_bd {
-  volatile struct emac_tx_bd *next;
-  volatile u8_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 RX Buffer descriptor data structure */
-struct emac_rx_bd {
-  volatile struct emac_rx_bd *next;
-  volatile u8_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;
-};
+#define IFNAME0                                        'e'
+#define IFNAME1                                        'n'
 
-/**
- * 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;
-};
+/* Time to wait for autonegotiation in ticks. */
+#define TICKS_PHY_AUTONEG                      4000
 
 /**
- * Helper struct to hold the data used to operate on a particular
- * transmit channel
+ * TODO -- not implemented
+ * When cable is connected (link status goes up)
+ * autonegotiation and/or dhcp is started.
  */
-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;
-};
+#define PHY_LINK_MONITOR_INT                   0
 
-/**
- * Helper struct to hold private data used to operate the ethernet interface.
- */
-struct hdkif {
-  /* emac instance number */
-  u32_t inst_num;
-
-  u8_t mac_addr[MAC_ADDR_LEN];
-
-  /* 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_autoneg_start)(u32_t, u32_t, u16_t);
-  u32_t (*phy_autoneg_is_done)(u32_t, u32_t);
-  u32_t (*phy_partnerability)(u32_t, u32_t, u16_t*);
-
-  /* The tx/rx channels for the interface */
-  struct txch txch;
-  struct rxch rxch;
-#if !NO_SYS
-  sys_sem_t goRX;
-  sys_sem_t goTX;
-  uint32_t waitTicksForPHYAneg;
-#endif
-};
-
-/********** end of TI structs ***********/
 
-/* Defining interface for all the emac instances */
+/* Statically allocated structure describing interface state -- one per instance */
 static struct hdkif hdkif_data[MAX_EMAC_INSTANCE];
 
-/*
-** The lwIP network interface structure for the HDK Ethernet MAC.
-*/
+/* The lwIP network interface structure for the HDK Ethernet MAC. */
 static struct netif hdkNetIF[MAX_EMAC_INSTANCE];
 
-/* rpp startup init indicator */
-static boolean_t initialized = FALSE, postInitialized = FALSE;
-
-/**********************************************Vector Interrupt Manager registers modification functions**********************************************/
-/* see sys_startup.c */
-#define TXinterruptVectorNumber 77
-#define RXinterruptVectorNumber 79
+/* RPP startup init indicator */
+static boolean_t initialized = FALSE;
+static boolean_t postInitialized = FALSE;
 
-inline void vim_mask_clr(uint32_t vecNum)
+/***testing functions**********************************************/
+boolean_t isPostInitialized()
 {
-       volatile uint32_t *reg = &(vimREG->REQMASKCLR0);
-       reg[vecNum >> 5] = 1 << (vecNum & 0x1f);
-}
-inline void vim_mask_set(uint32_t vecNum)
-{
-       volatile uint32_t *reg = &(vimREG->REQMASKSET0);
-       reg[vecNum >> 5] = 1 << (vecNum & 0x1f);
+       return postInitialized;
 }
 
-/**********************************************testing functions**********************************************/
-
 uint32_t rpp_eth_phylinkstat(uint32_t instNum)
 {
        struct hdkif *hdkif = &hdkif_data[instNum];
@@ -283,12 +167,6 @@ void rpp_eth_get_macAddrStr(uint32_t instNum, uint8_t *macStr)
        macStr[outindex] = '\0';
 }
 
-/* prepares an IP address to ipStr in form of null terminated string; each byte of ip is converted to one of 4 field in IPv4 IP address format 0xAABBCCDD -> "aaa.bbb.ccc.ddd" */
-inline void rpp_eth_getIPDecimalStr(ip_addr_t ip, uint8_t *ipStr)
-{
-       snprintf((char *)ipStr, 16, "%d.%d.%d.%d",(ip.addr >> 24),((ip.addr >> 16) & 0xff),((ip.addr >> 8) & 0xff),(ip.addr & 0xff));
-}
-
 /* @param ip will be filled accroding to content of ipstr */
 err_t rpp_eth_stringToIP(ip_addr_t * ip, uint8_t * ipstr)
 {
@@ -351,7 +229,7 @@ struct netif *rpp_eth_get_netif(uint32_t instNum)
        return &hdkNetIF[instNum];
 }
 
-/********************************************** forward declares **********************************************/
+/***** forward declarations **********************************************/
 
 /*
  * interface initializes
@@ -372,7 +250,7 @@ err_t rpp_eth_hw_init(struct hdkif *hdkif);
  */
 err_t rpp_eth_hw_init_postInit(struct netif *netif);
 
-/********************************************** utility functions **********************************************/
+/***** utility functions **********************************************/
 
 /*
 * Function to set the MAC address to the interface
@@ -380,21 +258,21 @@ err_t rpp_eth_hw_init_postInit(struct netif *netif);
 *
 * @note    mac_addr[0] is considered MSB
 */
-void
-hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) {
-  struct hdkif *hdkif;
-  u32_t temp;
+static void hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr)
+{
+       struct hdkif *hdkif;
+       u32_t temp;
 
-  hdkif = &hdkif_data[inst_num];
+       hdkif = &hdkif_data[inst_num];
 
-  /* set MAC hardware address */
-  for(temp = 0; temp < MAC_ADDR_LEN; temp++) {
-    hdkif->mac_addr[temp] = mac_addr[(MAC_ADDR_LEN - 1) - temp];
-  }
+       /* set MAC hardware address */
+       for (temp = 0; temp < MAC_ADDR_LEN; temp++) {
+               hdkif->mac_addr[temp] = mac_addr[(MAC_ADDR_LEN - 1) - temp];
+       }
 #ifdef DEBUG
-  uint8_t macStr[18];
-  rpp_eth_get_macAddrStr(inst_num, macStr);
-  rpp_debug_printf((const char *) "Setting MAC... %s\r\n", macStr);
+       uint8_t macStr[18];
+       rpp_eth_get_macAddrStr(inst_num, macStr);
+       rpp_debug_printf("Setting MAC... %s\r\n", macStr);
 #endif
 }
 
@@ -403,402 +281,474 @@ hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) {
 * @param   hdkif
 * @return  none.
 */
-static void
-hdkif_inst_config(struct hdkif *hdkif) {
-  if(hdkif->inst_num == 0)
-  {
-    hdkif->emac_base = EMAC_BASE_m(0);
-    hdkif->emac_ctrl_base = EMAC_CTRL_BASE_m(0);
-    hdkif->emac_ctrl_ram = EMAC_CTRL_RAM_BASE_m(0);
-    hdkif->mdio_base = MDIO_BASE_m(0);
-    hdkif->phy_addr = DEFAULT_PHY_ADDR; /* Default address of PHY on "MDIO bus" (depends on PHY hw configuration) */
-    hdkif->phy_autoneg = PHY_auto_negotiate;
-    hdkif->phy_autoneg_start = PHY_start_auto_negotiate;
-    hdkif->phy_autoneg_is_done = PHY_is_done_auto_negotiate;
-    hdkif->phy_partnerability = PHY_partner_ability_get;
-  }
+static void hdkif_inst_config(struct hdkif *hdkif)
+{
+       if (hdkif->inst_num == 0)
+       {
+               hdkif->emac_base = EMAC_BASE_m(0);
+               hdkif->emac_ctrl_base = EMAC_CTRL_BASE_m(0);
+               hdkif->emac_ctrl_ram = EMAC_CTRL_RAM_BASE_m(0);
+               hdkif->mdio_base = MDIO_BASE_m(0);
+
+               /* Default address of PHY on "MDIO bus"
+                * (depends on PHY hw configuration)
+                */
+               hdkif->phy_addr = DEFAULT_PHY_ADDR;
+               hdkif->phy_autoneg = PHY_auto_negotiate;
+               hdkif->phy_autoneg_start = PHY_start_auto_negotiate;
+               hdkif->phy_autoneg_is_done = PHY_is_done_auto_negotiate;
+               hdkif->phy_partnerability = PHY_partner_ability_get;
+       }
 }
 
-/********************************************** initializing functions **********************************************/
-
+/***** initializing functions **********************************************/
 int8_t rpp_eth_init()
 {
-    uint8_t instNum;
+       unsigned int instNum;
        int8_t retVal = SUCCESS;
-    if(initialized) {
-        return FAILURE;
-    }
 
-    /* config of EMAC instances and other stuff */
-    for(instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++)
-    {
-       hdkif_data[instNum].inst_num = instNum;
-       hdkif_inst_config(&hdkif_data[instNum]); /* hdkif_inst_config must contain instNum specific settings */
-       if(rpp_eth_hw_init(&hdkif_data[instNum]))retVal = FAILURE;
-    }
-
-    /* when one of instances was not initialized correctly return FAILURE without setting initialized variable to TRUE */
-    if(retVal)return FAILURE;
-
-#if NO_SYS
+       if (initialized)
+               return FAILURE;
 
-#else /* NO_SYS */
+       /* Config each EMAC instance */
+       for (instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++)
+       {
+               struct hdkif *hdkif = &hdkif_data[instNum];
 
-#endif /* NO_SYS */
+               hdkif->inst_num = instNum;
+               hdkif_inst_config(hdkif);
 
-    initialized = TRUE;
+               retVal = rpp_eth_hw_init(hdkif);
+               if (retVal != SUCCESS) {
+                       rpp_debug_printf("rpp_eth_hw_init: %d", retVal);
+                       return FAILURE;
+               }
+       }
 
-    return retVal;
+       initialized = TRUE;
+       return retVal;
 }
 
 int8_t rpp_eth_init_postInit(uint32_t instNum, uint8_t *macArray)
 {
-    if(postInitialized) {
-        return FAILURE;
-    }
-    int8_t retVal = SUCCESS;
-    struct netif *netif = &hdkNetIF[instNum];
-    u8_t mac_addr[MAC_ADDR_LEN] = RPP_MAC_ADDR;
-#ifdef DEBUG
-    uint8_t ipString[16];
-#endif
+       volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
+       struct ip_addr ip_addr;
+       struct ip_addr net_mask;
+       struct ip_addr gw_addr;
+       int8_t retVal = SUCCESS;
+       struct netif *netif = &hdkNetIF[instNum];
+       struct netif *netif_tmp;
+       u8_t mac_addr[MAC_ADDR_LEN] = RPP_MAC_ADDR;
+       struct hdkif *hdkif;
 
-    /* ----- lwIP stuff ----- */
-    struct ip_addr ip_addr;
-    struct ip_addr net_mask;
-    struct ip_addr gw_addr;
-    volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
+       if (postInitialized)
+               return FAILURE;
 
-    if(macArray == NULL)
-    {
-       macArray = mac_addr; /* use default MAC */
-    }
-    hdkif_macaddrset(instNum, macArray);
+       if (macArray == NULL)
+               macArray = mac_addr; /* use default MAC */
 
-    struct hdkif *hdkif;
-#if NO_SYS
-    lwip_init();
-#else /* NO_SYS */
-    /* this can be called only within post OS init */
-    tcpip_init(NULL,NULL); /* calls lwip_init() implicitly, starts lwIP task (thread), when started function given to tcpip_init is executed first */
-#endif /* NO_SYS */
+       hdkif_macaddrset(instNum, macArray);
 
-#if STATIC_IP_ADDRESS
-    ip_addr.addr = htonl(RPP_IP_ADDR);
-    net_mask.addr = htonl(RPP_NETMASK);
-    gw_addr.addr = htonl(RPP_GW);
-#else /* STATIC_IP_ADDRESS */
-    ip_addr.addr = 0;
-    net_mask.addr = 0;
-    gw_addr.addr = 0;
-#endif /* STATIC_IP_ADDRESS */
-
-    /* init and add new netif */
-    /* add new network interface to lwIP list of ifaces and initialize netif with specific function */
 #if NO_SYS
-    if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, ethernet_input) == NULL )
-#else /* NO_SYS */
-    if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, tcpip_input) == NULL )
-#endif /* NO_SYS */
-    {
-       return NETIF_ADD_ERR;
-    }
+       lwip_init();
+#else
+       /* This can be called only within post OS init */
 
-    netif_set_default(netif);
+       /*
+        * calls lwip_init() implicitly, starts lwIP task (thread),
+        * when started function given to tcpip_init is executed first
+        */
+       tcpip_init(NULL, NULL);
+#endif
 
-    hdkif = (struct hdkif *) netif->state;
-#if !NO_SYS
-    /* ----- freeRTOS elements ----- */
-    /* TODO: rewrite these to functions from sys_arch.* for compatibility with other systems then freeRTOS */
-    /* semaphore blocking receive task (rpp_eth_recv_raw) from receive operation, till RX interrupt occurs and notify it */
-    vSemaphoreCreateBinary(hdkif->goRX);
-    vSemaphoreCreateBinary(hdkif->goTX);
-    /* run task rpp_eth_recv_raw */
-    xTaskCreate( rpp_eth_recv_raw, "RXHandler", 200, netif, 0, NULL );
-    /* run task handling transmitted buffer descriptors */
-    xTaskCreate( rpp_eth_send_bd_handler, "TXHandler", 200, hdkif, 0, NULL );
-    /* ----- end - freeRTOS ----- */
-#endif /* !NO_SYS */
-
-    if(rpp_eth_phylinkstat(hdkif->inst_num))
-    {
-       rpp_debug_printf((const char *)"cable connected ... setting IP params\r\n");
 #if STATIC_IP_ADDRESS
-       netif_set_up(netif);
-#elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
-       if(dhcp_start(netif) != ERR_OK)
-       {
-#ifdef DEBUG
-               rpp_debug_printf((const char *) "dhcp mem err\r\n");
-#endif
-               return DHCP_MEM_ERR;
-       }
-#ifdef DEBUG
-       rpp_debug_printf((const char *) "binding DHCP\r");
+       ip_addr.addr = htonl(RPP_IP_ADDR);
+       net_mask.addr = htonl(RPP_NETMASK);
+       gw_addr.addr = htonl(RPP_GW);
+#else
+       ip_addr.addr = 0;
+       net_mask.addr = 0;
+       gw_addr.addr = 0;
 #endif
-       while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--));
-#ifdef DEBUG
-       if(!dhcpBindWait)
-               rpp_debug_printf((const char *) "dhcp binding timeout...\r\n");
+
+#if NO_SYS
+       /* Add new network interface to lwIP list of ifaces
+        * and initialize netif with specific function
+        */
+       netif_tmp = netif_add(netif, &ip_addr, &net_mask, &gw_addr,
+                             &hdkif_data[instNum], rpp_eth_lwip_init,
+                             ethernet_input);
+#else
+       netif_tmp = netif_add(netif, &ip_addr, &net_mask, &gw_addr,
+                             &hdkif_data[instNum], rpp_eth_lwip_init,
+                             tcpip_input);
 #endif
-#else /* LWIP_DHCP-LWIP_AUTOIP FIXME: there should be some kind of waiting till ip is assigned */
-       autoip_start(netif);
-#endif /* STATIC_IP_ADDRESS-LWIP_DHCP-LWIP_AUTOIP */
-#ifdef DEBUG
-       rpp_eth_getIPDecimalStr(netif->ip_addr, ipString);
-       rpp_debug_printf((const char *) "Address: %s\r\n", ipString);
-       rpp_eth_getIPDecimalStr(netif->netmask, ipString);
-       rpp_debug_printf((const char *) "Netmask: %s\r\n", ipString);
-       rpp_eth_getIPDecimalStr(netif->gw, ipString);
-       rpp_debug_printf((const char *) "Gateway: %s\r\n", ipString);
+       if (netif_tmp == NULL)
+               return NETIF_ADD_ERR;
+
+       netif_set_default(netif);
+
+       hdkif = netif->state;
+
+#if !NO_SYS
+       /* Semaphores used to block/unblock RX/TX threads doing the
+        * 'deferred' RX/TX handling -- semgive is callend in RX/TX ISR
+        */
+       vSemaphoreCreateBinary(hdkif->goRX);
+       vSemaphoreCreateBinary(hdkif->goTX);
+
+       xTaskCreate(rpp_eth_recv_raw_thr, "RXHandler", 500, netif, 0, NULL);
+       xTaskCreate(rpp_eth_send_raw_thr, "TXHandler", 500, netif, 0, NULL);
 #endif
-    }
-    else
-    {
-       rpp_debug_printf((const char *)"cable not connected\r\n");
-        retVal = PHY_LINK_DOWN;
-    }
-    /* ----- end - lwIP stuff ----- */
-
-    postInitialized = TRUE;
+
+       /* If we don't use link int change, then it must be done here */
+#if !PHY_LINK_MONITOR_INT
+       if (rpp_eth_phylinkstat(hdkif->inst_num)) {
+               rpp_debug_printf("cable connected ... setting IP params\r\n");
+
+  #if STATIC_IP_ADDRESS
+               netif_set_up(netif);
+  #elif LWIP_DHCP
+               int ret = dhcp_start(netif);
+               if (ret != ERR_OK) {
+                       rpp_debug_printf("dhcp mem err\r\n");
+                       return DHCP_MEM_ERR;
+               }
+
+               rpp_debug_printf("binding DHCP\r");
+               while ((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--))
+                       ; /* FIXME: sys_check_timeouts()*/
+
+               if (!dhcpBindWait)
+                       rpp_debug_printf("dhcp binding timeout...\r\n");
+  #else /* FIXME there should be some kind of waiting until IP address is assigned */
+               autoip_start(netif);
+  #endif
+
+  #ifdef DEBUG
+               uint8_t ipString[16]; // FIXME change the functions to use char
+               rpp_eth_getIPDecimalStr(netif->ip_addr, ipString);
+               rpp_debug_printf("Address: %s\n", ipString);
+               rpp_eth_getIPDecimalStr(netif->netmask, ipString);
+               rpp_debug_printf("Netmask: %s\n", ipString);
+               rpp_eth_getIPDecimalStr(netif->gw, ipString);
+               rpp_debug_printf("Gateway: %s\n", ipString);
+  #endif
+
+       } else {
+               rpp_debug_printf("cable not connected\r\n");
+               retVal = PHY_LINK_DOWN;
+       }
+
+#else /* !PHY_LINK_MONITOR_INT */
+       /* Link Status change handled in an interrupt -- NOT IMPLEMENTED */
+
+       /*
+        * Now when we established environment needed for phy link status
+        * change we can allow it. Set PHY number which is monitored for
+        * link changes in MDIO and enable interrupt
+        */
+       HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) =
+               ((hdkif->phy_addr && 0x1f) | MDIO_USERPHYSEL0_LINKINTENB);
+
+       /* Enable MISC interrupt - link monitoring in EMAC control module */
+       HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |=
+               EMAC_CTRL_MISC_LINKINT0ENB;
+
+#endif /* !PHY_LINK_MONITOR_INT */
+
+       postInitialized = TRUE;
        return retVal;
 }
 
 err_t rpp_eth_lwip_init(struct netif *netif)
 {
-#if LWIP_NETIF_HOSTNAME
-    /* Initialize interface hostname */
-    netif->hostname = "rpp";
-#endif /* LWIP_NETIF_HOSTNAME */
+       struct hdkif *hdkif = netif->state;
 
-    uint32_t instNum = (uint32_t)netif->state;
-    /*netif->num = instNum; - auto-initiated when netif_add is called */
-
-    /* netif->state contained instNum, we replace it with corresponding hdkif */
-    struct hdkif *hdkif = &hdkif_data[instNum];
-    netif->state = hdkif;
+#if LWIP_NETIF_HOSTNAME
+       netif->hostname = "rpp";
+#endif
+       netif->state = hdkif;
 
-    netif->name[0] = IFNAME0;
-    netif->name[1] = IFNAME1;
+       netif->name[0] = IFNAME0;
+       netif->name[1] = IFNAME1;
 
 #if !NO_SYS
-    hdkif->waitTicksForPHYAneg = TICKS_PHY_AUTONEG;
+       hdkif->waitTicksForPHYAneg = TICKS_PHY_AUTONEG;
 #endif
 
-    /*
-     * 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);
-
-    /* We directly use etharp_output() here to save a function call.
-     * You can instead declare yo_SKIP_TO_HWur 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 = rpp_eth_send;
-    return rpp_eth_hw_init_postInit(netif);
+       /*
+        * 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);
+
+       /* We directly use etharp_output() here to save a function call.
+        * You can instead declare yo_SKIP_TO_HWur 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 = rpp_eth_send;
+
+       return rpp_eth_hw_init_postInit(netif);
 }
 
-#define INIT_ONLY_AFTER_RESET 1
-err_t rpp_eth_hw_init(struct hdkif *hdkif)
+#define INIT_ONLY_AFTER_RESET 1 // FIXME Why? Wat? Wut? For future implementation?
+static err_t rpp_eth_hw_init(struct hdkif *hdkif)
 {
-    uint8_t index = configCPU_CLOCK_HZ/1000000;; /* Initially used to hw reset of PHY connected to GIO pin 'rpp project only'; 1us - according to PHY specification. */
-    uint16_t regContent;
-    uint32_t physAlive;
+       uint8_t index;
+       uint16_t regContent;
+       uint32_t physAlive;
 
-    /* Deactivate reset pin of PHY */
-    /* for hw reset of PHY, it is necessary that PIN_NAME_ETHRST is 1us logical low state, before putting it to logical high */
+       /* Deactivate reset pin of PHY */
+       /*
+        * For hw reset of PHY, it is necessary that PIN_NAME_ETHRST is 1us
+        * logical low state, before putting it to logical high
+        */
 #if !INIT_ONLY_AFTER_RESET
-    hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),0);
-    while(index--);
-#endif
-    /* we have pull-down resistor, so after reset, we only need to put ETHRST pin to log. high */
-    hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),1);
-
-    /* initializes EMAC control module and EMAC module */
-    EMACInit(hdkif->emac_ctrl_base, hdkif->emac_base);
-    /* initializes MDIO module (reset) */
-    MDIOInit(hdkif->mdio_base, 0x0, 0x0);
+#if NO_SYS
+       /*
+        * Initially used to hw reset of PHY connected to GIO pin.
+        * This means 1us - for 80MHz clock.
+        */
+       index = 80;
+#else /* NO_SYS */
+       /*
+        * Initially used to hw reset of PHY connected to GIO pin
+        * 'rpp project only'; 1us - according to PHY specification.
+        */
+       index = configCPU_CLOCK_HZ/1000000;
+#endif /* NO_SYS */
+       dio_gpio_pin_set_value(*dio_gpio_pin_get_dsc(PIN_NAME_ETHRST, -1), 0);
+       while (index--) ;
+#endif /* !INIT_ONLY_AFTER_RESET */
+          /* we have pull-down resistor, so after reset, we only need to put ETHRST pin to log. high */
+       dio_gpio_pin_set_value(*dio_gpio_pin_get_dsc(DIO_PIN_NAME_ETHRST, -1), 1);
 
-    /* enable used receive channel if necessary */
+       /*
+        * We have pull-down resistor, so after reset, we only need
+        * to put ETHRST pin to log. high
+        */
+       dio_gpio_pin_set_value(*dio_gpio_pin_get_dsc(DIO_PIN_NAME_ETHRST, -1), 1);
 
+       /* Initialize EMAC control module and EMAC module */
+       EMACInit(hdkif->emac_ctrl_base, hdkif->emac_base);
+       /* Initialize MDIO module (reset) */
+       MDIOInit(hdkif->mdio_base, 0x0, 0x0);
 
-    /* try to read random register from defaultPhy to make MDIO fill alive bit for this one if it returned
-       ACK bit in msg response - this must be done, because MDIO has not set alive bit of PHY after that
-       short time after MDIOInit() */
+       /*
+        * Try to read random register from defaultPhy to make MDIO fill alive
+        * bit for this one if it returned ACK bit in msg response -- this must
+        * be done, because MDIO has not set alive bit of PHY after that
+        * short time after MDIOInit()
+        */
        MDIOPhyRegRead(hdkif->mdio_base, hdkif->phy_addr, PHY_BMSR, &regContent);
 
-    /* find first alive PHY - or use default if alive */
-    physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base);
-    if(!(physAlive & (1 << hdkif->phy_addr)))
-    {
+       /* Find first alive PHY -- or use default if alive */
+       physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base);
+       if (!(physAlive & (1 << hdkif->phy_addr))) {
 #if FIND_FIRST_PHY_ALIVE
-        for(index = 0;index < NUM_OF_PHYs;index++) /* i..PHY tested */
-        {
-            if(physAlive && (1 << index))
-            {
-               hdkif->phy_addr = index;
-                break;
-            }
-            else
-            {
-               MDIOPhyRegRead(hdkif->mdio_base, index, PHY_BMCR, &regContent); /* try to 'wake up' PHY on 'index' address by reading random register, making MDIO set alive bit for current PHY */
-               physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base); /* get updated register */
-               if(physAlive && (1 << index))
-               {
-                   hdkif->phy_addr = index;
-                   break;
-               }
-            }
-        }
-        if(!physAlive)
-        {
-#ifdef DEBUG
-            rpp_debug_printf((const char *) "no phy found, phys: %d\r\n", physAlive);
-#endif
-               return NO_PHY_ALIVE;
-        }
+               for (index = 0; index < NUM_OF_PHYs; index++) {
+                       if (physAlive && (1 << index)) {
+                               hdkif->phy_addr = index;
+                               break;
+                       } else {
+                               /*
+                                * Try to 'wake up' PHY on 'index' address by
+                                * reading random register, making MDIO set
+                                * alive bit for current PHY
+                                */
+                               MDIOPhyRegRead(hdkif->mdio_base, index,
+                                               PHY_BMCR, &regContent);
+
+                               /* Get updated register */
+                               physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base);
+                               if (physAlive && (1 << index)) {
+                                       hdkif->phy_addr = index;
+                                       break;
+                               }
+                       }
+               }
+
+               if (!physAlive) { /* FIXME je to ok? */
+                       rpp_debug_printf("no phy found, phys: %d\n", physAlive);
+                       return NO_PHY_ALIVE;
+               }
 #else
-#ifdef DEBUG
-        rpp_debug_printf((const char *) "default phy not alive\r\n");
+               rpp_debug_printf("default phy not alive\n");
+               return DFLT_PHY_NOT_ALIVE;
 #endif
-       return DFLT_PHY_NOT_ALIVE;
-#endif
-    }
+       }
 
-    /* start autonegotiation and check on completion later or when complete link register will be updated */
-    hdkif->phy_autoneg_start(hdkif->mdio_base, hdkif->phy_addr, PHY_100BASETXDUPL_m | PHY_100BASETX_m | PHY_10BASETDUPL_m | PHY_10BASET_m);
+       /*
+        * Start autonegotiation and check on completion later or
+        * when complete link register will be updated
+        */
+       hdkif->phy_autoneg_start(hdkif->mdio_base, hdkif->phy_addr,
+                       PHY_100BASETXDUPL_m | PHY_100BASETX_m |
+                       PHY_10BASETDUPL_m | PHY_10BASET_m);
 
-    /* TODO: you can implement init of receive flow control somewhere here if desired - set RXBUFFERFLOWEN in MACCONTROL */
+       /*
+        * TODO: you can implement init of receive flow control somewhere
+        * here if desired - set RXBUFFERFLOWEN in MACCONTROL
+        */
 
 
-    /* acknowledge EMAC control module RX and TX interrupts */
+       /* Acknowledge EMAC control module RX, TX and MISC interrupts */
        EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
        EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
+       EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
 
-       /* FIXME: probably just remove PromiscEnable later, if your desire is not to filter packets manualy */
-    /* sets which channel will receive broadcasts */
+       /* Sets which channel will receive broadcasts */
        EMACRxBroadCastEnable(hdkif->emac_base, CHANNEL);
-       /* sets channel where all frames will be copied to - either with MAC address different from local device address, either packets with error will be copied; appropriate error will be set in the frame EOP buffer descriptor */
+
+       /*
+        * Sets channel where all frames will be copied to --
+        * either with MAC address different from local device address,
+        * either packets with error will be copied; appropriate error
+        * will be set in the frame EOP buffer descriptor
+        */
        EMACRxPromiscEnable(hdkif->emac_base, CHANNEL);
-       /* enables unicast */
+
+       /* Enable unicast */
        EMACRxUnicastSet(hdkif->emac_base, CHANNEL);
 
-    /* enable TX and RX interrupts in both EMAC module and EMAC control module */
+       /* Enable TX and RX interrupts in both EMAC module and EMAC control module */
        EMACTxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
        EMACRxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
 
        return SUCCESS;
 }
 
-err_t rpp_eth_hw_init_postInit(struct netif *netif)
+static err_t rpp_eth_hw_init_postInit(struct netif *netif)
 {
-       volatile unsigned int autonegFinishWait = 0x3FFFFFFF; /* for 80MHz aproximately 13s */
-    uint16_t regContent;
-    uint32_t num_bd, pbuf_cnt = 0;
-    volatile struct emac_tx_bd *curr_txbd, *last_txbd;
-    volatile struct emac_rx_bd *curr_rxbd, *last_rxbd;
-    struct pbuf *p, *q;
-    struct rxch *rxch;
-    struct txch *txch;
+       /* 0x3FFFFFFF is for 80MHz aproximately 13s */
+       volatile unsigned int autonegFinishWait = 0x3FFFFFFF;
+
+       uint16_t regContent;
+       uint32_t num_bd, pbuf_cnt = 0;
+       volatile struct emac_tx_bd *curr_txbd, *last_txbd;
+       volatile struct emac_rx_bd *curr_rxbd, *last_rxbd;
+       struct pbuf *p, *q;
+       struct rxch *rxch;
+       struct txch *txch;
 
-    struct hdkif *hdkif = (struct hdkif *) netif->state;
+       struct hdkif *hdkif = (struct hdkif *)netif->state;
 
-    rxch = &(hdkif->rxch);
-    txch = &(hdkif->txch);
+       rxch = &(hdkif->rxch);
+       txch = &(hdkif->txch);
 
-#ifdef DEBUG
-    rpp_debug_printf((const char *) "autoneg started - check on cable if it's connected!\r\n");
-#endif
+       rpp_debug_printf("autoneg started -- check on cable if it's connected!\r\n");
 
+       /*
+        * Use the CPPI RAM to store RX/TX Buffer Descriptors (= BD).
+        * 1/2 of CPPI RAM is used for TX BDs, another 1/2 for RX BDs.
+        * All the TX BDs are 'owned' by the software. They are initialized
+        * as a linked-list forming a ring. They are awaiting the application
+        * to append pbuf payload to the them and correctly configure for
+        * actual transmission.
+        * Only such number of RX BDs is configured that the pbufs can be
+        * allocated for (i.e. MAX_RX_PBUF_ALLOC). Pbufs are allocated from
+        * the PBUF_POOL (thus the allocated pbufs might be chained).
+        * Each payload part of a payload is them used to initialize single
+        * RX BD. The RX BDs are then configured to be 'owned' bythe EMAC
+        */
 
        /*
-       * 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 *) hdkif->emac_ctrl_ram);
+        * 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 *)hdkif->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(struct emac_tx_bd); /* take half of CPPI ram for TX BDs */
+       /* take half of CPPI ram for TX BDs */
+       num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct 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;
+       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;
+       /* curr_txbd now points to the BD that is the first BD
+        * after the last_txbd -- this will be the first RX BD
+        */
 
        /* Initialize the descriptors for the RX channel */
-       rxch->active_head = (volatile struct emac_rx_bd*)(curr_txbd);
-       rxch->free_head = NULL;
+       rxch->active_head = (volatile struct emac_rx_bd*)curr_txbd;
+       rxch->free_head = NULL; /* Not used */
        rxch->freed_pbuf_len = 0;
-       num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_rx_bd)); /* when using 20B emac_bd structs, u can allocate one more ;) (405 together rx and tx and there is still 12 bytes remaining) */
+
+       num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_rx_bd));
        curr_rxbd = rxch->active_head;
        last_rxbd = curr_rxbd;
 
-       /*
-       ** 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);
-
-           if(p != NULL) {
-               /* write the descriptors if there are enough numbers to hold the pbuf*/
-               if(((uint32_t)pbuf_clen(p)) <= num_bd) {
-                   for(q = p; q != NULL; q = q->next) {
-                       curr_rxbd->bufptr = (uint8_t *)(q->payload);
-                       curr_rxbd->bufoff_len = q->len;
-                       curr_rxbd->next = curr_rxbd + 1;
-                       curr_rxbd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
-
-                       /* Save the pbuf */
-                       curr_rxbd->pbuf = q;
-                       last_rxbd = curr_rxbd;
-                       curr_rxbd = curr_rxbd->next;
-                       num_bd--;
-                   }
-               }
-
-               /* free the allocated pbuf if no free descriptors are left */
-               else {
-                   pbuf_free(p);
-                   break;
-               }
-           }
-           else {
-               break;
-           }
-           pbuf_cnt++;
+        /* Allocate the pbufs for the maximum count permitted or
+         * till the number of buffer descriptors expire,
+         * whichever is earlier.
+         */
+       while (pbuf_cnt < MAX_RX_PBUF_ALLOC) {
+               /* Sidenote -- remember that the PBUF might be chained */
+               p = pbuf_alloc(PBUF_RAW, PBUF_LEN_MAX, PBUF_POOL);
+               if (p != NULL) {
+                       /* Watch out not to excede the number of available BDs */
+                       if (((uint32_t)pbuf_clen(p)) <= num_bd) {
+                               /* Fill in the BD to reference the allocated pbuf */
+                               /* for each PBUF chunk */
+                               for (q = p; q != NULL; q = q->next) {
+                                       curr_rxbd->bufptr = (uint8_t *)q->payload;
+                                       curr_rxbd->bufoff_len = q->len;
+                                       curr_rxbd->next = curr_rxbd + 1;
+                                       curr_rxbd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
+
+                                       /* Save the pbuf */
+                                       curr_rxbd->pbuf = q;
+                                       last_rxbd = curr_rxbd;
+                                       curr_rxbd = curr_rxbd->next;
+                                       num_bd--;
+                               }
+                       } else {
+                               /* free the allocated pbuf if no free
+                                * descriptors are left */
+                               pbuf_free(p);
+                               break;
+                       }
+               } else {
+                       break;
+               }
+               pbuf_cnt++;
        }
+       if (!pbuf_cnt)
+               rpp_sci_printf("No pbufs attached to RX BD during init\n");
 
        last_rxbd->next = NULL;
        rxch->active_tail = last_rxbd;
 
-       num_bd = (((uint32_t)rxch->active_tail - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd) + 1);
-       /* for flow control - there could be set an interrupt when we reach preset amount of receive descriptors remaining - see RXBUFFERFLOWEN */
-       EMACNumFreeBufSet(hdkif->emac_base, CHANNEL, num_bd);
+#ifdef DEBUG
+       num_bd = (((uintptr_t)rxch->active_tail - (uintptr_t)rxch->active_head)
+                       / sizeof(struct emac_rx_bd)) + 1;
+       rpp_debug_printf("%d pbuf chains allocated for %d rx buffer descriptors\n",
+                        pbuf_cnt, num_bd);
+#endif
 
-       /* set header descriptor pointers - this shows EMAC which descriptor is beginning one for writing received frames/packets  */
+       /* Set header descriptor pointers -- this shows EMAC which descriptor
+        * is the first one for writing received frames/packets
+        */
        EMACRxHdrDescPtrWrite(hdkif->emac_base, (uint32_t)rxch->active_head, CHANNEL);
 
-       /* lwIP stuff */
-
-       /* set length of MAC address */
-       netif->hwaddr_len = MAC_ADDR_LEN;
-
        /* set MAC address */
-       for(regContent = 0; regContent < MAC_ADDR_LEN; regContent++) {
-           netif->hwaddr[regContent] = hdkif->mac_addr[(MAC_ADDR_LEN - 1) - regContent];
+       netif->hwaddr_len = MAC_ADDR_LEN;
+       for (regContent = 0; regContent < MAC_ADDR_LEN; regContent++) {
+               netif->hwaddr[regContent] =
+                       hdkif->mac_addr[(MAC_ADDR_LEN - 1) - regContent];
        }
 
        /* maximum transfer unit */
@@ -808,89 +758,100 @@ err_t rpp_eth_hw_init_postInit(struct netif *netif)
        /* 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;
 
-       /* lwIP stuff - end */
-
-    /* for flow control frames */
-    EMACMACSrcAddrSet(hdkif->emac_base, hdkif->mac_addr);
 
-    /*  Be sure to program all eight MAC address registers -
-     *  whether the receive channel is to be enabled or not.
-     */
-    for (regContent = 0; regContent < 8; regContent++) /* i..channel_number */
-       EMACMACAddrSet(hdkif->emac_base, regContent, hdkif->mac_addr, EMAC_MACADDR_NO_MATCH_NO_FILTER);
+       /* for flow control frames */
+       EMACMACSrcAddrSet(hdkif->emac_base, hdkif->mac_addr);
 
-    /* wait for autonegotiation to be done or continue, when delay was reached */
-#if !NO_SYS
-    uint32_t timeToWake = hdkif->waitTicksForPHYAneg + sys_jiffies();
-    while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && timeToWake > sys_jiffies())vTaskDelay(20); /* XXX: if init is not done at the startup, but couple days later, this might cause troubles */
-#else
-    while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && autonegFinishWait--); /* wait till aneg done */
-#endif
+       /*  Be sure to program all eight MAC address registers -
+        *  whether the receive channel is to be enabled or not.
+        */
+       for (regContent = 0; regContent < 8; regContent++) {
+               EMACMACAddrSet(hdkif->emac_base, regContent, hdkif->mac_addr,
+                              EMAC_MACADDR_NO_MATCH_NO_FILTER);
+       }
 
-#ifdef DEBUG
-    if(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) != FALSE)
-       rpp_debug_printf((const char *) "aneg finished \r\n");
-    else
-       rpp_debug_printf((const char *) "aneg timeout \r\n");
-#endif
+#if !PHY_LINK_MONITOR_INT
+       /* In case we don't use interrupt when phy link status changes,
+        * we need to try to finish autoneg in here
+        */
+       /* wait for autonegotiation to be done or continue, when delay was reached */
+  #if !NO_SYS
+       uint32_t timeToWake = hdkif->waitTicksForPHYAneg + sys_jiffies();
+       while (hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE &&
+              timeToWake > sys_jiffies())
+       {
+               vTaskDelay(20);
+               /* XXX: if init is not done at the startup,
+                * but couple days later, this might cause troubles */
+       }
 
-    /* provide informations retrieved from autoneg to EMAC module */
-    hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, &regContent);
-    if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) {
-       EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_FULL);
-       /* this is right place to implement transmit flow control if desired - set TXFLOWEN in MACCONTROL */
-    } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) {
-       EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_HALF);
-    } else {
-#ifdef DEBUG
-       rpp_debug_printf((const char *) "Unknown duplex mode\r\n");
-#endif
-       return UNKN_DUPLEX_MODE;
-    }
+  #else
+       while (hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE &&
+              autonegFinishWait--)
+               ; /* wait till aneg done */
+  #endif
+
+       if (hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) != FALSE)
+               rpp_debug_printf("autoneg finished\n");
+       else
+               rpp_debug_printf("autoneg timeout\n");
+
+       /* provide informations retrieved from autoneg to EMAC module */
+       hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, &regContent);
+       if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) {
+               EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_FULL);
+               /* this is right place to implement transmit flow control if desired --
+                * set TXFLOWEN in MACCONTROL
+                */
+       } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) {
+               EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_HALF);
+       } else {
+               rpp_debug_printf("Unknown duplex mode\r\n");
+               return UNKN_DUPLEX_MODE;
+       }
+#endif /* !PHY_LINK_MONITOR_INT */
 
-    /* TODO: reorganize code for linkint handling and maybe add functions for it */
-#if PHY_LINK_MONITOR_INT
-    /* set PHY number which is monitored for link changes in MDIO and enable interrupt */
-    HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) = ((hdkif->phy_addr && 0x1f) | MDIO_USERPHYSEL0_LINKINTENB);
+       /* enable hostpend interrupts in emac module */
+       HWREG(hdkif->emac_base + EMAC_MACINTMASKSET) |=
+               EMAC_MACINTMASKSET_HOSTMASK;
 
-    /* enable MISC interrupt for link monitoring in EMAC controle module */
-    HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_LINKINT0ENB;
-#endif
+       /* enable hostpend interrupts in emac control module */
+       HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |=
+               EMAC_CTRL_MISC_HOSTPENDENB;
 
-       /* enable EMAC's Media Independent Interface TX and RX */
        EMACMIIEnable(hdkif->emac_base);
-       /* enable EMAC transmit */
        EMACTxEnable(hdkif->emac_base);
-       /* enable EMAC receive */
        EMACRxEnable(hdkif->emac_base);
 
        return SUCCESS;
 }
 
-/********************************************** send and receive functions / ISRs **********************************************/
+/* send and receive functions / ISRs ******************************************/
 
-err_t rpp_eth_send(struct netif * netif, struct pbuf *p)
+err_t rpp_eth_send(struct netif *netif, struct pbuf *p)
 {
        err_t retVal = SUCCESS;
        SYS_ARCH_DECL_PROTECT(lev);
 
        /**
-        * This entire function must run within a "critical section" to preserve
+        * This entire function must be protected to preserve
         * the integrity of the transmit pbuf queue.
-        *
         */
        SYS_ARCH_PROTECT(lev);
+#if !SYS_LIGHTWEIGHT_PROT
+       uint32_t prevProt = (uint32_t) _get_CPSR() & 0x80;
+       _disable_IRQ();
+#endif
 
        /* 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;
+       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.
-        *
+        * freed until we are done with it.
         */
        pbuf_ref(p);
 
@@ -899,396 +860,586 @@ err_t rpp_eth_send(struct netif * netif, struct pbuf *p)
 
        /* Return to prior interrupt state and return. */
        SYS_ARCH_UNPROTECT(lev);
+#if !SYS_LIGHTWEIGHT_PROT
+       if (!prevProt)
+               _enable_IRQ();
+#endif
 
        return retVal;
 }
 
-err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *p)
+/**
+ * When called from rpp_eth_send(), the 'lev' lock is held
+ */
+static err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *pbuf)
 {
        struct pbuf *q;
-       volatile struct emac_tx_bd *curr_bd, *active_head, *bd_end;
-       struct hdkif *hdkif;
        struct txch *txch;
-       err_t retVal = SUCCESS;
+       struct hdkif *hdkif;
+       volatile struct emac_tx_bd *curr_bd;
+       /* Head of the BD chain representing 'active' BDs --
+        * those that are modified/added in this function
+        */
+       volatile struct emac_tx_bd *active_head;
+       /* Same as active_head, but this is the tail of the list */
+       volatile struct emac_tx_bd *active_tail;
 
-    hdkif = (struct hdkif *) netif->state;
+       hdkif = (struct hdkif *)netif->state;
        txch = &(hdkif->txch);
 
-
-       /* Get the buffer descriptor which is free to transmit */
+       /* Get the first BD that is unused and will be used for TX */
        curr_bd = txch->free_head;
-
        active_head = curr_bd;
 
-       /* Update the total packet length */
-       curr_bd->flags_pktlen &= ~0xFFFF;
-       curr_bd->flags_pktlen |= p->tot_len;
-
-       /* Indicate the start of the packet */
-       curr_bd->flags_pktlen |= (EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_OWNER);
+       /* Be sure that the free_head didn't wrap around the chain
+        * of all BDs pointing to the BD being processed by the EMAC
+        * (in such case txch->free_head would be the same as
+        * txch->next_bd_to_process)
+        */
+       while (curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER)
+               ;
 
-       /* Copy pbuf information into TX buffer descriptors */
-       for(q = p; q != NULL; q = q->next) {
+       /* First 'part' of packet flags */
+       curr_bd->flags_pktlen = pbuf->tot_len |
+                               EMAC_DSC_FLAG_SOP |
+                               EMAC_DSC_FLAG_OWNER;
 
-           /* Intialize the buffer pointer and length */
-           curr_bd->bufptr = (uint8_t *)(q->payload);
-           curr_bd->bufoff_len = (q->len) & 0xFFFF;
-           bd_end = curr_bd;
-           curr_bd->pbuf = p;
-           curr_bd = curr_bd->next;
+       /* Copy pbuf information into TX BDs --
+        * remember that the pbuf for a single packet might be chained!
+        */
+       for (q = pbuf; q != NULL; q = q->next) {
+               curr_bd->bufptr = (uint8_t *)(q->payload);
+               curr_bd->bufoff_len = (q->len) & 0xFFFF;
+
+               active_tail = curr_bd;
+               /* This is an extra field that is not par of the in-HW BD.
+                * This is used when freeing the pbuf after the TX processing
+                * is done in EMAC
+                */
+               curr_bd->pbuf = pbuf;
+
+               curr_bd = curr_bd->next;
+               curr_bd->flags_pktlen = 0x0;
        }
-
        /* Indicate the end of the packet */
-       bd_end->next = NULL;
-       bd_end->flags_pktlen |= EMAC_DSC_FLAG_EOP;
+       active_tail->next = NULL;
+       active_tail->flags_pktlen |= EMAC_DSC_FLAG_EOP;
 
+       /* Since we used the txch->free_head as the first BD for our purpose,
+        * set the new free_head just behind the active_tail
+        */
        txch->free_head = curr_bd;
 
        /* For the first time, write the HDP with the filled bd */
-       if(txch->active_tail == NULL) {
-           EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), CHANNEL);
-       }
-       /*
-        * 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; /* first chain new stuff to transmit */
-           /* Test if the EOQ bit is set, if it is, set TXnHDP */
-           if(EMAC_DSC_FLAG_EOQ == (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ))
-           {
-               /* Don't write to TX0HDP until it turns to zero - because EOQ was set, it should be zero already */
-               while (0 != *((uint32_t *) (hdkif->emac_base + EMAC_TXHDP(CHANNEL)) ));
-               /* Write the Header Descriptor Pointer and start DMA */
-               EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), CHANNEL);
-           }
+       if (txch->active_tail == NULL) {
+               EMACTxHdrDescPtrWrite(hdkif->emac_base,
+                       (unsigned int)(active_head), CHANNEL);
+       } else {
+               /* 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.
+                */
+               curr_bd = txch->active_tail;
+               curr_bd->next = active_head;
+
+#if 0
+               /* Just a workaround in case "appending" to
+                * the last active BD will not work
+                */
+               while (!(curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ))
+                       ;
+#endif
+
+               /* We were too slow and the EMAC already read the
+                * 'pNext = NULL' of the former txch->active_tail. In this
+                * case the transmission stopped and we need to write the
+                * pointer to newly added BDs to the TX HDP
+                */
+               if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ) {
+                       /* Writes to TX HDP are allowed only when it is 0 */
+                       while (HWREG(hdkif->emac_base + EMAC_TXHDP(CHANNEL)) != 0)
+                               ;
+                       EMACTxHdrDescPtrWrite(hdkif->emac_base,
+                                       (unsigned int)(active_head), CHANNEL);
+               }
        }
+       txch->active_tail = active_tail;
+
+       return SUCCESS;
+}
 
-       txch->active_tail = bd_end;
+void rpp_eth_send_raw_thr(void *arg)
+{
+       struct hdkif *hdkif;
+       struct txch *txch;
+       volatile struct emac_tx_bd *curr_bd;
+       volatile struct emac_tx_bd *next_bd_to_process;
+       struct netif *netif = (struct netif*)arg;
 
-       return retVal;
+       hdkif = netif->state;
+       txch = &(hdkif->txch);
+
+       for (;;) {
+               /* Block if there is nothing to do.
+                * Wake up if an TX interrupt occured.
+                */
+               xSemaphoreTake(hdkif->goTX, portMAX_DELAY);
+
+               next_bd_to_process = txch->next_bd_to_process;
+               curr_bd = next_bd_to_process;
+
+               /* Traverse the list of BDs used for transmission --
+                * stop on the first unused
+                */
+               while (curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP) {
+                       /* Make sure the transmission is over */
+                       while (curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER)
+                               ;
+
+                       /* Find the last chunk of the packet */
+                       while (!(curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP))
+                               curr_bd = curr_bd->next;
+
+                       /* Remove flags for the transmitted BDs */
+                       next_bd_to_process->flags_pktlen &= (~EMAC_DSC_FLAG_SOP);
+                       curr_bd->flags_pktlen &= (~EMAC_DSC_FLAG_EOP);
+
+                       /* Point the txch->next_bd_to_process to the BDs
+                        * following the 'last BD belonging to the packet
+                        * being processed'
+                        */
+                       if (curr_bd->next == NULL)
+                               txch->next_bd_to_process = txch->free_head;
+                       else
+                               txch->next_bd_to_process = curr_bd->next;
+
+                       /* Ack the Interrupt in the EMAC peripheral */
+                       EMACTxCPWrite(hdkif->emac_base, CHANNEL,
+                                     (uint32_t)curr_bd);
+
+                       /* Free the corresponding pbuf
+                        * Sidenote: Each fragment of the single packet points
+                        * to the same pbuf // FIXME is it true?
+                        */
+                       pbuf_free(curr_bd->pbuf);
+
+                       LINK_STATS_INC(link.xmit);
+
+                       /* Move to the next packet */
+                       next_bd_to_process = txch->next_bd_to_process;
+                       curr_bd = next_bd_to_process;
+               }
+
+               /* Ack the Interrupt in the EMAC peripheral */
+               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
+               //EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX); // Proc?
+               /* Enable the interrupt in the VIM */
+               vim_mask_set(TXinterruptVectorNumber);
+       }
 }
 
-void rpp_eth_recv_raw(void *arg)
+void rpp_eth_recv_raw_thr(void *arg)
 {
-    volatile struct emac_rx_bd *curr_bd, *processed_bd, *curr_tail, *last_bd;
-    volatile struct pbuf *pbuf, *q, *new_pbuf;
-    uint32_t ex_len, len_to_alloc;
-    uint16_t tot_len;
-       struct netif *netif = (struct netif *) arg;
-       struct hdkif *hdkif = (struct hdkif *) netif->state;
+       struct hdkif *hdkif;
        struct rxch *rxch;
+       struct netif *netif = (struct netif*)arg;
+       volatile struct emac_rx_bd *curr_bd;
+       volatile struct emac_rx_bd *curr_tail;
+       volatile struct emac_rx_bd *curr_head;
+       struct pbuf *pbuf;
+       struct pbuf *new_pbuf;
+       struct pbuf *q;
 
+       hdkif = netif->state;
        rxch = &(hdkif->rxch);
-#if !NO_SYS
-    for(;;)
-    {
-       vim_mask_set(RXinterruptVectorNumber);
-       sys_arch_sem_wait(&(hdkif->goRX), 0);
-       /* TODO: this place is candidate for LINKINT polling (if not solved through interrupt later) */
-#endif
 
-           /* 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_DSC_FLAG_SOP)
-        {
-               ex_len = 0;
-               len_to_alloc = 0;
-               /* Start processing once the packet is loaded */
-               if((curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) != EMAC_DSC_FLAG_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;
-                       /* FIXME: curr_bd here could be NULL */
-                   } while((processed_bd->flags_pktlen & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_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(netif->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(hdkif->emac_base, CHANNEL, (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;
-#if !NO_SYS
-                   /* if there is not enough pbufs predefined, we need application to process them and return them back to pool -> YIELD */
-                   /* XXX: this is not fixed in NO_SYS version - problem is when curr_bd is set to NULL (see above), and we don't obtain new_pbuf
-                    * from pool, then in *bd pointing to NULL might be such values (EMAC_DSC_FLAG_SOP == 1 &| EMAC_DSC_FLAG_OWNER == 0), that we
-                    * stay cycling around */
-                   do
-                   {
-#endif
-                           new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL);
-#if !NO_SYS
-                           if(new_pbuf != NULL)
-                               break;
-                           else
-                               vTaskDelay(2);
-                   }while(1);
+       for (;;) {
+               /* Block if there is nothing to do.
+                * Wake up if an RX interrupt occured.
+                */
+#if 0
+               sys_arch_sem_wait(&(hdkif->goRX), 0);
 #endif
+               xSemaphoreTake(hdkif->goRX, portMAX_DELAY);
+
+               /* Get the bd which contains the earliest filled data */
+               curr_bd = rxch->active_head;
+
+               /* For each valid frame */
+               while (curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP) {
+                       unsigned int total_rx_len;
+                       unsigned int processed_rx_len = 0;
+
+                       /* Start processing once the packet is released by the EMAC. */
+                       while (curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER)
+                               ;
+
+                       pbuf = curr_bd->pbuf;
+                       total_rx_len = curr_bd->flags_pktlen & 0xFFFF;
+
+                       /* The received frame might be fragmented into muliple
+                        * pieces -- each one referenced by a separate BD.
+                        * To further process the data, we need to 'make' a
+                        * proper PBUF out of it -- that means linking each
+                        * buffer together, copy the length information form
+                        * the DB to PBUF, calculate the 'tot_len' etc.
+                        */
+                       for (;;) {
+                               q = curr_bd->pbuf;
+                               /* Since this pbuf will be freed, we need to
+                                * keep track of its size to be able to
+                                * allocate it back again
+                                */
+                               rxch->freed_pbuf_len += q->len;
+
+                               /* This is the size of the "received data" not the PBUF */
+                               q->tot_len = total_rx_len - processed_rx_len;
+                               q->len = curr_bd->bufoff_len & 0xFFFF;
+
+                               if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP)
+                                       break;
+                               /*
+                                * If we are executing here, it means this
+                                * packet is being split over multiple BDs
+                                */
+
+                               /* chain the pbufs since they belong
+                                * to the same packet
+                                */
+                               q->next = (curr_bd->next)->pbuf;
+
+                               processed_rx_len += q->len;
+                               curr_bd = curr_bd->next;
+                       }
+                       /* Close the chain */
+                       q->next = NULL;
 
-                   /* 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 = (uint8_t *)(q->payload);
-
-                           /* no support for buf_offset. RXBUFFEROFFSET register is 0 */
-                           curr_bd->bufoff_len = (q->len) & 0xFFFF;
-                           curr_bd->flags_pktlen = EMAC_DSC_FLAG_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_DSC_FLAG_EOQ)
-                       {
-                           EMACRxHdrDescPtrWrite(hdkif->emac_base, (u32_t)(rxch->free_head), CHANNEL);
-                       }
-
-                       rxch->free_head  = curr_bd;
-                       rxch->active_tail = last_bd;
-                   }
-            }
-               curr_bd = rxch->active_head;
-           }
-               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
-#if !NO_SYS
-    }
-#endif
-}
+                       LINK_STATS_INC(link.recv);
 
-void rpp_eth_send_bd_handler(void *arg)
-{
-       struct hdkif *hdkif = (struct hdkif *) arg;
-       struct txch *txch = &(hdkif->txch);
-       volatile struct emac_tx_bd *curr_bd, *next_bd_to_process;
+                       /* Process the packet */
+                       /* ethernet_input((struct pbuf *)pbuf, netif) */
+                       if (netif->input((struct pbuf *)pbuf, netif) != ERR_OK) {
+                               LINK_STATS_INC(link.memerr);
+                               LINK_STATS_INC(link.drop);
+                       }
 
-#if !NO_SYS
-       for(;;){
-       vim_mask_set(TXinterruptVectorNumber);
-       sys_arch_sem_wait(&(hdkif->goTX), 0);
-#else
-#endif
-           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_DSC_FLAG_SOP)
-           {
-
-               /* Make sure that the transmission is over */
-               while((curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) == EMAC_DSC_FLAG_OWNER);
-
-               /* Traverse till the end of packet is reached */
-               while(((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP)
-               {
-                   curr_bd = curr_bd->next;
-               }
-
-               next_bd_to_process->flags_pktlen &= ~(EMAC_DSC_FLAG_SOP);
-               curr_bd->flags_pktlen &= ~(EMAC_DSC_FLAG_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(hdkif->emac_base, CHANNEL, (uint32_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;
+                       /* Acknowledge that this packet is processed */
+                       EMACRxCPWrite(hdkif->emac_base, 0, (unsigned int)curr_bd);
+
+                       curr_head = rxch->active_head;
+                       rxch->active_head = curr_bd->next;
+
+                       /* 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.
+                        * Care should be taken even if the allocation fails.
+                        */
+                       for (;;) {
+                               new_pbuf = pbuf_alloc(PBUF_RAW,
+                                                     rxch->freed_pbuf_len,
+                                                     PBUF_POOL);
+                               if (new_pbuf == NULL) {
+                                       /* Cycle until the pbuf is
+                                        * succesfully allocated
+                                        */
+                                       /* Actively poll to decrease the time
+                                        * when the RX interrupts are disabled
+                                        */
+                                       continue;
+                               } else {
+                                       curr_tail = curr_bd;
+                                       curr_tail->next = NULL;
+                                       curr_bd = curr_head;
+
+                                       q = new_pbuf;
+                                       curr_bd = curr_head;
+                                       for (;;) {
+                                               if (q == NULL)
+                                                       break;
+                                               if (curr_bd == NULL)
+                                                       break;
+
+                                               curr_bd->bufptr = (uint8_t *)q->payload;
+                                               curr_bd->bufoff_len = q->len;
+                                               curr_bd->flags_pktlen =
+                                                       EMAC_DSC_FLAG_OWNER;
+                                               curr_bd->pbuf = q;
+
+                                               rxch->freed_pbuf_len -= q->len;
+                                               q = q->next;
+                                               curr_bd = curr_bd->next;
+                                       }
+
+                                       /* At this point either the whole pbuf
+                                        * was used or there are no RX BDs left.
+                                        * If there is not enough RX BDs to assign
+                                        * all pbufs in the chain, free the
+                                        * rest of the pbufs.
+                                        */
+                                       if (q != NULL)
+                                               pbuf_free((struct pbuf *)q);
+
+                                       /* Add the newly allocated BDs to the
+                                        * end of the list
+                                        */
+                                       rxch->active_tail->next = curr_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 (rxch->active_tail->flags_pktlen &
+                                           EMAC_DSC_FLAG_EOQ)
+                                       {
+                                               /* Writes to RX HDP are allowed
+                                                * only when it is 0
+                                                */
+                                               while (HWREG(hdkif->emac_base +
+                                                      EMAC_RXHDP(CHANNEL)) != 0)
+                                                       ;
+
+                                               EMACRxHdrDescPtrWrite(
+                                                       hdkif->emac_base,
+                                                       (uint32_t)curr_head,
+                                                       CHANNEL);
+                                       }
+
+                                       rxch->active_tail = curr_tail;
+                                       break;
+                               }
+                       }
+                       curr_bd = rxch->active_head;
                }
 
-               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
-#if !NO_SYS
+               /* Ack the Interrupt in the EMAC peripheral */
+               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
+               //EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
+               /* Enable the interrupt in the VIM */
+               vim_mask_set(RXinterruptVectorNumber);
        }
-#endif
 }
 
 void RxIntHandler(u32_t instNum)
 {
-#if !NO_SYS
        vim_mask_clr(RXinterruptVectorNumber);
-       /*
-       static portBASE_TYPE xHigherPriorityTaskWoken;
-       xHigherPriorityTaskWoken = pdFALSE;
-       */
-       /* 'Give' the semaphore to unblock the task. */
-       xSemaphoreGiveFromISR(hdkif_data[instNum].goRX, NULL); // whenever there is time to process received packets, wake up task processing them
-       /*
-    if( xHigherPriorityTaskWoken == pdTRUE )
-    {
-    */
-    /* Giving the semaphore unblocked a task, and the priority of the
-    unblocked task is higher than or equal to the currently running task
-    - force a context switch to ensure that the interrupt returns directly
-    to the unblocked (higher priority) task.
-    NOTE: The actual macro to use to force a context switch from an
-    ISR is dependent on the port. This is the correct macro for the
-    Open Watcom DOS port. Other ports may require different syntax.
-        Refer to the examples provided for the port being used to determine
-    the syntax required. */
-       /*
-    portSWITCH_CONTEXT();
-    }
-       */
-#else
-       rpp_eth_recv_raw((void *) &hdkNetIF[instNum]);
-#endif
+       /* Unblock the RX task. */
+       xSemaphoreGiveFromISR(hdkif_data[instNum].goRX, NULL);
 }
 
 void TxIntHandler(u32_t instNum)
 {
-#if !NO_SYS
        vim_mask_clr(TXinterruptVectorNumber); /* see sys_startup.c */
        xSemaphoreGiveFromISR(hdkif_data[instNum].goTX, NULL);
-#else
-       rpp_eth_send_bd_handler((void *) &hdkif_data[instNum]);
-#endif
 }
 
-#if PHY_LINK_MONITOR_INT
-boolean_t LinkIntHandler(void)
+/**
+ * TX err codes:
+ * 0   No error
+ * 1h  SOP error; the buffer is the first buffer in a packet,
+ *     but the SOP bit is not set in software.
+ * 2h  Ownership bit not set in SOP buffer
+ * 3h  Zero next buffer descriptor pointer without EOP
+ * 4h  Zero buffer pointer
+ * 5h  Zero buffer length
+ * 6h  Packet length error (sum of buffers is less than packet length)
+ *
+ * RX err codes:
+ * 0   No error
+ * 1h  Reserved
+ * 2h  Ownership bit not set in SOP buffer
+ * 3h  Reserved
+ * 4h  Zero buffer pointer
+ */
+boolean_t HostPendErrHandler(void)
 {
-       uint8_t index = MAX_EMAC_INSTANCE, phyFound = FALSE;
+       uint8_t index = MAX_EMAC_INSTANCE;
+       uint8_t errFound = FALSE;
+       uint32_t reg;
        struct hdkif *hdkif;
 
-       /* check each instance, whether this interrupt was meant for this function */
-       while(index--){
-       hdkif = &hdkif_data[index];
-           if( hdkif->phy_addr == (HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) & 0x1f) && (HWREG(hdkif->emac_base + EMAC_MACINVECTOR) & EMAC_MACINVECTOR_LINKINT0) )phyFound = TRUE;
+       while (index) {
+               hdkif = &hdkif_data[--index];
+
+               if (EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_HOSTPEND)
+                       errFound = TRUE;
        }
-    if(!phyFound)return FALSE;
 
-    rpp_sci_printk((const char *) "PHY link %s", rpp_eth_phylinkstat(index)?"UP":"DOWN");
-    rpp_sci_printk((const char *) "\r\n");
+       if (!errFound)
+               return FALSE; /* this is not the cause of the interrupt */
+
+       rpp_sci_printk("HOSTPEND err\n");
+       reg = HWREG(hdkif->emac_base + EMAC_MACSTATUS);
+       rpp_sci_printk("TXCHERR: %d at CH: %d\n",
+                       ((reg >> EMAC_MACSTATUS_TXERRCODE_SHIFT) & 0x7),
+                       ((reg >> EMAC_MACSTATUS_TXERRCH_SHIFT) & 0x7));
+       rpp_sci_printk("RXCHERR: %d at CH: %d\n",
+                       ((reg >> EMAC_MACSTATUS_RXERRCODE_SHIFT) & 0x7),
+                       ((reg >> EMAC_MACSTATUS_RXERRCH_SHIFT) & 0x7));
+
+       { /* Print out all the RX BDs */
+               struct rxch *rxch;
+               volatile struct emac_rx_bd *curr_bd;
+               rxch = &(hdkif->rxch);
+               int glob_len = 0;
+
+               rpp_sci_printk("rxch->active_head: %p\n", rxch->active_head);
+               rpp_sci_printk("rxch->active_tail: %p\n", rxch->active_tail);
+               rpp_sci_printk("rxch->freed_pbuf_len: %p\n", rxch->freed_pbuf_len);
+               rpp_sci_printk("RXCP: 0x%x\n", *((uint32_t*)(hdkif->emac_base + EMAC_RXCP(0))));
+
+               for (curr_bd = rxch->active_head; curr_bd != 0; curr_bd = curr_bd->next) {
+                       glob_len += curr_bd->pbuf->len;
+
+                       rpp_sci_printk("[%p: buf: %p buffoff_len: 0x%x "
+                                       "\tflags: 0x%x pktlen: 0x%x]",
+                                       curr_bd,
+                                       curr_bd->bufptr,
+                                       curr_bd->bufoff_len,
+                                       (curr_bd->flags_pktlen >> 16) & 0xFFFF,
+                                       curr_bd->flags_pktlen & 0xFFFF);
+                       rpp_sci_printk(" pbuf: tot_len: 0x%x \tlen: 0x%x ref: 0x%x\n",
+                                       curr_bd->pbuf->tot_len,
+                                       curr_bd->pbuf->len,
+                                       curr_bd->pbuf->ref);
+               }
+               rpp_sci_printk("glob_len: %d\n", glob_len);
+       }
+
+       /* no acknowledge - emac module has to be restarted */
+
+       /* this was the reason of interrupt */
+       return TRUE;
+}
+
+#if PHY_LINK_MONITOR_INT
+boolean_t LinkIntHandler(void)
+{
+       uint8_t index = MAX_EMAC_INSTANCE;
+       uint8_t phyFound = FALSE;
+       struct hdkif *hdkif;
+       uint16_t regContent;
+       volatile unsigned int autonegFinishWait = 0xFFFFFFF;
+       volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
 
-    /* do whatever necessary for link status change here */
+       /* check each instance, whether this interrupt was meant for this
+        * function, if not return FALSE so other function may be tried
+        */
+       while (index) {
+               hdkif = &hdkif_data[--index];
+               if ((hdkif->phy_addr ==
+                    (HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) & 0x1f)) &&
+                   (EMACIntVectorGet(hdkif->emac_base) &
+                    EMAC_MACINVECTOR_LINKINT0))
+                       phyFound = TRUE;
+       }
+       if (!phyFound)
+               return FALSE;
+       struct netif *netif = &hdkNetIF[hdkif->inst_num];
+
+       /* we handle here connection of cable after startup, not changes of linkstatus */
+
+       /* wait for autonegotiation to be done */
+#if ONCE_LINK_SETUP
+       while (hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) ==
+              FALSE)
+               ;
+#else /* ONCE_LINK_SETUP */
+       while (hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) ==
+              FALSE & autonegFinishWait--)
+               ;
+#endif /* ONCE_LINK_SETUP */
+
+       /* provide informations retrieved from autoneg to EMAC module */
+       hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, &regContent);
+       if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) {
+               EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_FULL);
+               /* this is right place to implement transmit flow control
+                * if desired - set TXFLOWEN in MACCONTROL
+                */
+       } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) {
+               EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_HALF);
+       } else {
+               /* acknowledge MDIO module */
+               HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) =
+                       MDIO_LINKINTMASKED_USERPHY0;
+               HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) =
+                       MDIO_LINKINTMASKED_USERPHY0;
+
+               /* acknowledge EMAC control module by writing
+                * appropriate key to MACEOIVECTOR
+                */
+               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
+               return FALSE;
+       }
+       /* if link is up configure lwip struct netif */
+       if (rpp_eth_phylinkstat(hdkif->inst_num)) {
+#if STATIC_IP_ADDRESS
+               netif_set_up(netif);
+#elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
+               if (dhcp_start(netif) != ERR_OK) { /* XXX: can't be used from ISR (mem_malloc()) */
+                       return DHCP_MEM_ERR;
+               }
+#if ONCE_LINK_SETUP
+               while (netif->dhcp->state != DHCP_BOUND)
+                       ;
+#else
+               while (netif->dhcp->state != DHCP_BOUND & dhcpBindWait--)
+                       ;
+               if (!dhcpBindWait) {
+                       /* acknowledge MDIO module */
+                       HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) =
+                               MDIO_LINKINTMASKED_USERPHY0;
+                       HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) =
+                               MDIO_LINKINTMASKED_USERPHY0;
+
+                       /* acknowledge EMAC control module by writing
+                        * appropriate key to MACEOIVECTOR
+                        */
+                       EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
+                       return FALSE;
+               }
+#endif
+#else /* LWIP_DHCP-LWIP_AUTOIP FIXME: there should be some kind of waiting till ip is assigned */
+               autoip_start(netif);
+#endif /* STATIC_IP_ADDRESS-LWIP_DHCP-LWIP_AUTOIP */
+#if ONCE_LINK_SETUP
+               /* turn this interrupt off */
+               HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) &=
+                       (~EMAC_CTRL_MISC_LINKINT0ENB & 0xf);
+#endif /* ONCE_LINK_SETUP */
+       } else {
+#if ONCE_LINK_SETUP
+               /* acknowledge MDIO module */
+               HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) =
+                       MDIO_LINKINTMASKED_USERPHY0;
+               HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) =
+                       MDIO_LINKINTMASKED_USERPHY0;
+
+               /* acknowledge EMAC control module by writing
+                * appropriate key to MACEOIVECTOR
+                */
+               EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
+               return FALSE;
+#else
+#if STATIC_IP_ADDRESS
+               netif_set_down(netif);
+#elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
+               dhcp_stop(netif);
+#endif /* STATIC_IP_ADDRESS-LWIP_DHCP-LWIP_AUTOIP */
+#endif
+       }
 
        /* acknowledge MDIO module */
-       HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) = MDIO_LINKINTMASKED_USERPHY0;
-       HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) = MDIO_LINKINTMASKED_USERPHY0;
+       HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) =
+               MDIO_LINKINTMASKED_USERPHY0;
+       HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) =
+               MDIO_LINKINTMASKED_USERPHY0;
 
        /* acknowledge EMAC control module by writing appropriate key to MACEOIVECTOR */
        EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
 
        return TRUE;
 }
-#endif
-
-
-/*      --- EMAC DESCRIPTOR FORMAT ---
- *                                         bit fields
- * WORD   |
- * OFFSET | 31                               16 | 15                                 0
- * ------------------------------------------------------------------------------------
- *    0   |                          Next Descriptor Pointer
- *    1   |                              Buffer Pointer
- *    2   |            Buffer Offset            |            Buffer Length
- *    3   |                Flags                |            Packet Length
- */
-
-#endif /* rppCONFIG_INCLUDE_ETH */
+#endif /* PHY_LINK_MONITOR_INT */
+#endif /* FREERTOS_POSIX */