--- /dev/null
+#ifndef EMAC_H_
+#define EMAC_H_
+
+#include "netif/etharp.h"
+#include "lwip/sys.h"
+#include "rpp/eth.h"
+#include "sys/hw_emac.h"
+
+#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 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;
+};
+
+/**
+ * Helper struct to hold the data used to operate on a particular
+ * receive channel
+ */
+struct rxch {
+ volatile struct emac_rx_bd *free_head; /* pointer to buffer descriptor which will be associated with new pbuf when new pbuf is obtained */
+ volatile struct emac_rx_bd *active_head; /* pointer to buffer descriptor which will be filled by EMAC this pointer is written to HDP (header descriptor pointer) */
+ volatile struct emac_rx_bd *active_tail; /* pointer to buffer descriptor which is the last one which has associated pbuf, next bd is NULL */
+ u32_t freed_pbuf_len; /* number of bytes which were freed (pbuf_free()) and so we need to allocate them again */
+};
+
+/**
+ * Helper struct to hold the data used to operate on a particular
+ * transmit channel
+ */
+struct txch {
+ volatile struct emac_tx_bd *free_head; /* pointer to buffer descriptor ready to be filled and sent */
+ volatile struct emac_tx_bd *active_tail; /* pointer to buffer descriptor which is end of packet */
+ volatile struct emac_tx_bd *next_bd_to_process; /* pointer to buffer descriptor which will be handled (cleared) when it's been processed (sent) by EMAC */
+};
+
+/**
+ * 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;
+#if PHY_LINK_MONITOR_INT
+ sys_sem_t goLink;
+#endif
+ uint32_t waitTicksForPHYAneg;
+#endif
+};
+
+/********** end of TI structs ***********/
+
+
+/********************************************** Statistics and Debugging **********************************************/
+#define RPP_ETH_STATS 0
+
+#if RPP_ETH_STATS
+
+#include "types.h"
+
+/* eth.c - hw stuff */
+extern volatile boolean_t tx_bd_handled, received;/* when true, bd was already handled after sent; when false, bd wasn't sent yet or it wasn't handled yet */
+extern volatile struct txch beforeHandled, afterHandled;
+extern volatile struct rxch beforeRecv, afterRecv;
+extern volatile unsigned portBASE_TYPE filledTXbds, handledTXbds, filledTXPKTs, handledTXPKTs;
+extern volatile unsigned portBASE_TYPE filledRXbds, handledRXbds, filledRXPKTs, handledRXPKTs;
+/* eth.c - lwip stuff */
+extern volatile uint32_t preparedRxPBUFs, preparedRxPBUFChains, preparedTxPBUFs, preparedTxPBUFChains;
+extern volatile uint32_t filledRxPBUFs, filledRxPBUFChains, filledTxPBUFs, filledTxPBUFChains;
+/* notification.c */
+extern volatile int countEMACCore0TxIsr = 0;
+extern volatile int countEMACCore0RxIsr = 0;
+
+#endif
+
+/*
+ * checks whether address is in range of CPPI RAM
+ */
+boolean_t inCPPI(uint32_t spot);
+
+/********************************************** End of Statistics **********************************************/
+
+#endif /* EMAC_H_ */
/* 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 "hal/hal.h"
#include "rpp/rpp.h"
#include "sys/sys.h" /* includes - sys/phy_dp83848h.h */
+#include "drv/emac.h"
#include "os/os.h"
#include "types.h"
*/
#define ONCE_LINK_SETUP 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 1 /* turn on handling interrupt risen when link status is changed (cable out or in) */
#define MAX_TRANSFER_UNIT 1500 /* take in account oversized frames */
#define PBUF_LEN_MAX MAX_TRANSFER_UNIT
#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;
-};
-
-/**
- * Helper struct to hold the data used to operate on a particular
- * receive channel
- */
-struct rxch {
- volatile struct emac_rx_bd *free_head; /* pointer to buffer descriptor where will be associated new pbuf when obtained */
- volatile struct emac_rx_bd *active_head; /* pointer to buffer descriptor which will be filled by EMAC this pointer is written to HDP (header descriptor pointer) */
- volatile struct emac_rx_bd *active_tail; /* pointer to buffer descriptor which is the last one which has associated pbuf, next bd is NULL */
- u32_t freed_pbuf_len; /* number of bytes which were freed (pbuf_free()) and so we need to allocate them again */
-};
-
-/**
- * Helper struct to hold the data used to operate on a particular
- * transmit channel
- */
-struct txch {
- volatile struct emac_tx_bd *free_head; /* pointer to buffer descriptor ready to be filled and sent */
- volatile struct emac_tx_bd *active_tail; /* pointer to buffer descriptor which is end of packet */
- volatile struct emac_tx_bd *next_bd_to_process; /* pointer to buffer descriptor which will be handled (cleared) when it's been processed (sent) by EMAC */
-};
-
-/**
- * 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;
-#if PHY_LINK_MONITOR_INT
- sys_sem_t goLink;
-#endif
- uint32_t waitTicksForPHYAneg;
-#endif
-};
-
-/********** end of TI structs ***********/
-
/* Defining interface for all the emac instances */
static struct hdkif hdkif_data[MAX_EMAC_INSTANCE];
xSemaphoreHandle pbufFreed;
#endif
-/********************************************** Statistics **********************************************/
-#define RPP_ETH_STATS 1
-
-
-/**********************************************Vector Interrupt Manager registers modification functions**********************************************/
-/* see sys_startup.c */
-#define LNKInterruptVectorNumber 76
-#define TXinterruptVectorNumber 77
-#define RXinterruptVectorNumber 79
-
-inline void vim_mask_clr(uint32_t vecNum)
-{
- 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);
-}
-
/**********************************************testing functions**********************************************/
uint32_t rpp_eth_phylinkstat(uint32_t instNum)
}*/
#if ONE_DRIVER_TASK
xTaskCreate( rpp_eth_driver, "ethDriver", 250, netif, 0, NULL);
- vim_mask_set(LNKInterruptVectorNumber);
#else /* ONE_DRIVER_TASK */
/* run task rpp_eth_recv_raw */
xTaskCreate( rpp_eth_recv_raw, "RXHandler", 200, netif, 0, NULL );
#endif /* ONE_DRIVER_TASK */
/* ----- end - freeRTOS ----- */
#endif /* !NO_SYS */
+ vim_mask_set(LNKInterruptVectorNumber);
- /* TODO: move this to link */
+ /* TODO: copy this to link interrupt handler/ it must be done, so we do it here when link interrupt handler is not used */
+#if !PHY_LINK_MONITOR_INT
if(rpp_eth_phylinkstat(hdkif->inst_num))
{
rpp_debug_printf((const char *)"cable connected ... setting IP params\r\n");
#ifdef DEBUG
rpp_debug_printf((const char *) "binding DHCP\r");
#endif
- while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--));
+ while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--))/*sys_check_timeouts()*/;
#ifdef DEBUG
if(!dhcpBindWait)
rpp_debug_printf((const char *) "dhcp binding timeout...\r\n");
rpp_debug_printf((const char *)"cable not connected\r\n");
retVal = PHY_LINK_DOWN;
}
+#endif /* !PHY_LINK_MONITOR_INT */
/* ----- end - lwIP stuff ----- */
postInitialized = TRUE;
EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
- /* FIXME: probably just remove PromiscEnable later, if your desire is not to filter packets manualy */
/* 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 */
rxch->active_tail = last_rxbd;
num_bd = ( ((uint32_t)rxch->active_tail - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd) + 1 );
+#if RPP_ETH_STATS
+ preparedRxPBUFs = filledRXbds = num_bd;
+ preparedRxPBUFChains = pbuf_cnt;
+#endif
#ifdef DEBUG
rpp_debug_printf((const char *) "%d pbuf chains allocated for %d rx buffer descriptors\n", pbuf_cnt, num_bd);
#endif
for (regContent = 0; regContent < 8; regContent++) /* i..channel_number */
EMACMACAddrSet(hdkif->emac_base, regContent, hdkif->mac_addr, EMAC_MACADDR_NO_MATCH_NO_FILTER);
+#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();
}
/* TODO: reorganize code for linkint handling and maybe add functions for it */
-#if PHY_LINK_MONITOR_INT
+#else /* !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 MISC interrupt for link monitoring in EMAC controle module */
HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_LINKINT0ENB;
-#endif
+#endif /* !PHY_LINK_MONITOR_INT */
/* enable EMAC's Media Independent Interface TX and RX */
EMACMIIEnable(hdkif->emac_base);
hdkif = (struct hdkif *) netif->state;
txch = &(hdkif->txch);
+#if RPP_ETH_STATS
+ preparedTxPBUFs++;
+ preparedTxPBUFChains += pbuf_clen(p);
+#endif
/* Get the buffer descriptor which is free to transmit */
curr_bd = txch->free_head;
bd_end = curr_bd;
curr_bd->pbuf = p;
curr_bd = curr_bd->next;
+#if RPP_ETH_STATS
+ filledTXbds++;
+#endif
}
/* Indicate the end of the packet */
bd_end->next = NULL;
bd_end->flags_pktlen |= EMAC_DSC_FLAG_EOP;
+#if RPP_ETH_STATS
+ filledTXPKTs++;
+#endif
+
txch->free_head = curr_bd;
/* For the first time, write the HDP with the filled bd */
else {
curr_bd = txch->active_tail;
/* TODO: (This is a workaround) Wait for the EOQ bit is set */
- while (EMAC_DSC_FLAG_EOQ != (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ));
+ while (EMAC_DSC_FLAG_EOQ != (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ)); /* XXX: it stucked here, when calling from recv interrupt - ICMP ping to the board running and nc -d */
/* TODO: (This is a workaround) Don't write to TXHDP0 until it turns to zero */
while (0 != *((u32_t *)0xFCF78600));
curr_bd->next = active_head;
txch->active_tail = bd_end;
+#if RPP_ETH_STATS
+ tx_bd_handled = FALSE;
+ beforeHandled.active_tail = txch->active_tail;
+ beforeHandled.free_head = txch->free_head;
+ beforeHandled.next_bd_to_process = txch->next_bd_to_process;
+#endif
+
return retVal;
}
//SYS_ARCH_PROTECT(lev);
#endif
+
+#if RPP_ETH_STATS
+ received = FALSE;
+ beforeRecv.active_head = rxch->active_head;
+ beforeRecv.active_tail = rxch->active_tail;
+ beforeRecv.free_head = rxch->free_head;
+ beforeRecv.freed_pbuf_len = rxch->freed_pbuf_len;
+#endif
+
/* Get the bd which contains the earliest filled data */
curr_bd = rxch->active_head;
last_bd = rxch->active_tail;
/* If the earlier pbuf ended, update the chain */
if(pbuf->next == NULL)
{
+#if RPP_ETH_STATS
+ preparedRxPBUFChains--;
+ filledRxPBUFChains++;
+#endif
pbuf->next = (struct pbuf*)(curr_bd->next)->pbuf;
}
*/
pbuf->next = NULL;
+#if RPP_ETH_STATS
+ handledRXPKTs++;
+ filledRXbds -= ((((uint32_t)curr_bd - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd)) + 1);
+ filledRxPBUFs += pbuf_clen(pbuf);
+ preparedRxPBUFs -= pbuf_clen(pbuf);
+#endif
+
/* Adjust the link statistics */
LINK_STATS_INC(link.recv);
}
else
{
- rxch->active_head = processed_bd + 1;
+ rxch->active_head = processed_bd + 1; //todo:reconsider
}
/**
curr_bd = rxch->active_head;
}
EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
+
+#if RPP_ETH_STATS
+ received = TRUE;
+ afterRecv.active_head = rxch->active_head;
+ afterRecv.active_tail = rxch->active_tail;
+ afterRecv.free_head = rxch->free_head;
+ afterRecv.freed_pbuf_len = rxch->freed_pbuf_len;
+#endif
#if !NO_SYS && !ONE_DRIVER_TASK
//SYS_ARCH_UNPROTECT(lev);
}
while(((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP)
{
curr_bd = curr_bd->next;
+#ifdef DEBUG
+ if(!inCPPI((uint32_t)curr_bd))rpp_sci_printk((const char *) "tx handl traverse to EOP - bad bd->next ptr\n");
+#endif
}
next_bd_to_process->flags_pktlen &= ~(EMAC_DSC_FLAG_SOP);
}
EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
+
+#if RPP_ETH_STATS
+ tx_bd_handled = TRUE;
+ afterHandled.active_tail = txch->active_tail;
+ afterHandled.free_head = txch->free_head;
+ afterHandled.next_bd_to_process = txch->next_bd_to_process;
+#endif
#if !NO_SYS && !ONE_DRIVER_TASK
SYS_ARCH_UNPROTECT(lev);
}
}
#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 */