/* Number of EMAC Instances */
#define MAX_EMAC_INSTANCE 1
-/* config whether only one task for driver will be used *//* this controls, whether there will be one task handling interrupts for receive, send bd handeling or link status change or even receive threshold */
-/* only one task should be used due to stability of system (it seems that LwIP doesn't handle it well when it has separate tasks for receive and send bd handler) / memory savings (in fact it ate so much memory, that it fell often) */
-#define ONE_DRIVER_TASK 0
-
-/*
- * if this is set, the link value is set only once upon start/cable connection
- * it this is not set, then each time cable is plugged or unplugged, the interface link status is updated
- * and when dhcp is enabled, it is negotiated
- */
-#define ONCE_LINK_SETUP 1
-
#define DEFAULT_PHY_ADDR 0x1
#define FIND_FIRST_PHY_ALIVE 1 /* or use default (phy_address: 1) */
#define NUM_OF_PHYs 32
/* rpp startup init indicator */
static boolean_t initialized = FALSE, postInitialized = FALSE;
+boolean_t sendDone = TRUE;
+
/* free pbuf notification */
#if !NO_SYS
xSemaphoreHandle pbufFreed;
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)
{
*/
err_t rpp_eth_hw_init_postInit(struct netif *netif);
-#if ONE_DRIVER_TASK
-/*
- * Task which handles driver's stuff
- */
-void rpp_eth_driver(void *arg);
-#endif
-
-#if PHY_LINK_MONITOR_INT
-/*
- * function which handles changes of link status
- */
-void linkStatusChanged(void *arg);
-#endif
-
/********************************************** utility functions **********************************************/
/*
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
/* ----- lwIP stuff ----- */
struct ip_addr ip_addr;
hdkif = (struct hdkif *) netif->state;
#if !NO_SYS
- /* TODO: rewrite these to functions from sys_arch.* not only here for compatibility with other systems then freeRTOS if it is possible (does not seem likely now) */
/* ----- freeRTOS elements ----- */
/* semaphore blocking receive task (rpp_eth_recv_raw) from receive operation, till RX interrupt occurs and notify it */
vSemaphoreCreateBinary(hdkif->goRX);
vSemaphoreCreateBinary(hdkif->goTX);
-#if PHY_LINK_MONITOR_INT
- vSemaphoreCreateBinary(hdkif->goLink);
-#endif
- /* create semaphore notificating that pbuf was freed FIXME: bad solution */
- vSemaphoreCreateBinary(pbufFreed);/*
- if( pbufFreed == NULL ){
- rpp_debug_printf((const char *) "Insufficient memory.");
- }*/
-#if ONE_DRIVER_TASK
- xTaskCreate( rpp_eth_driver, "ethDriver", 250, netif, 0, NULL);
-#else /* ONE_DRIVER_TASK */
+ /* create semaphore notificating that pbuf was freed */
+ vSemaphoreCreateBinary(pbufFreed);
/* 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 );
-#if PHY_LINK_MONITOR_INT
- /* run task handling link status changes */
- xTaskCreate( linkStatusChanged, "LNKHandler", 100, netif, 0, NULL );
- /* enable linkint on vim level */
-#endif /* PHY_LINK_MONITOR_INT */
-#endif /* ONE_DRIVER_TASK */
/* ----- end - freeRTOS ----- */
#endif /* !NO_SYS */
- vim_mask_set(LNKInterruptVectorNumber);
- /* TODO: copy this to link interrupt handler/ it must be done, so we do it here when link interrupt handler is not used */
+ /* 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))
{
#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");
-#endif
while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--))/*sys_check_timeouts()*/;
-#ifdef DEBUG
if(!dhcpBindWait)
rpp_debug_printf((const char *) "dhcp binding timeout...\r\n");
-#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
+ uint8_t ipString[16];
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 *)"cable not connected\r\n");
retVal = PHY_LINK_DOWN;
}
+
+#else /* !PHY_LINK_MONITOR_INT */
+ /* 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 controle module */
+ HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_LINKINT0ENB;
+
#endif /* !PHY_LINK_MONITOR_INT */
/* ----- end - lwIP stuff ----- */
/* 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);
- /* don't run link status change interrupt yet - there is not yet prepared all the stuff we need */
- vim_mask_clr(LNKInterruptVectorNumber);
-
/* initializes EMAC control module and EMAC module */
EMACInit(hdkif->emac_ctrl_base, hdkif->emac_base);
/* initializes MDIO module (reset) */
}
if(!physAlive)
{
-#ifdef DEBUG
rpp_debug_printf((const char *) "no phy found, phys: %d\r\n", physAlive);
-#endif
return NO_PHY_ALIVE;
}
#else
-#ifdef DEBUG
rpp_debug_printf((const char *) "default phy not alive\r\n");
-#endif
return DFLT_PHY_NOT_ALIVE;
#endif
}
/* 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);
/* sets which channel will receive broadcasts */
EMACRxBroadCastEnable(hdkif->emac_base, CHANNEL);
EMACTxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
EMACRxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
+ /* switch of send bd handling and when sending, just wait till send was done and then return (making the driver simple) */
+ //vim_mask_clr(TXinterruptVectorNumber);
+
return SUCCESS;
}
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
/*
pbuf_cnt++;
}
-#ifdef DEBUG
if(!pbuf_cnt)rpp_debug_printf((const char *) "no pbufs attached to rx buffer descriptors during init\n");
-#endif
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 );
-#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 flow control or QoS - there could be set an interrupt when we reach preset amount of receive descriptors remaining - see RXBUFFERFLOWEN */
/* EMACNumFreeBufSet(hdkif->emac_base, CHANNEL, num_bd); */ /* not used */
while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && autonegFinishWait--); /* wait till aneg done */
#endif
-#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
/* provide informations retrieved from autoneg to EMAC module */
hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, ®Content);
} 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;
}
+#endif /* !PHY_LINK_MONITOR_INT */
- /* TODO: reorganize code for linkint handling and maybe add functions for it */
-#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 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 /* !PHY_LINK_MONITOR_INT */
+ /* 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);
return SUCCESS;
}
-/********************************************** send and receive functions / ISRs **********************************************/
-/* function to find out, whether LwIP does not mind more threads */
-/* this one handles all interrupts comming */
-#if ONE_DRIVER_TASK
-void rpp_eth_driver(void *arg)
-{
- boolean_t active;
- struct netif *netif = (struct netif *) arg;
- struct hdkif *hdkif = (struct hdkif *) netif->state;
- for(;;)
- {
- active = FALSE;
- if (sys_arch_sem_wait(&(hdkif->goTX), 1) != SYS_ARCH_TIMEOUT){
- SYS_ARCH_DECL_PROTECT(lev);
- SYS_ARCH_PROTECT(lev);
- rpp_eth_send_bd_handler(hdkif);
- SYS_ARCH_UNPROTECT(lev);
- vim_mask_set(TXinterruptVectorNumber);
- active = TRUE;
- }
- if (sys_arch_sem_wait(&(hdkif->goRX), 1) != SYS_ARCH_TIMEOUT){
- SYS_ARCH_DECL_PROTECT(lev);
- SYS_ARCH_PROTECT(lev);
- rpp_eth_recv_raw(netif);
- SYS_ARCH_UNPROTECT(lev);
- vim_mask_set(RXinterruptVectorNumber);
- active = TRUE;
- }
-#if PHY_LINK_MONITOR_INT
- if (sys_arch_sem_wait(&(hdkif->goLink), 1) != SYS_ARCH_TIMEOUT){
- linkStatusChanged(netif);
- vim_mask_set(LNKInterruptVectorNumber);
- }
-#endif
- if(active)continue;
- taskYIELD(); /* if there is no request to be handled let other tasks work */
- }
-}
-#endif
+
+
+
+
+
+
+
+
+
+
+
+
+/********************************************** send and receive functions / ISRs **********************************************/
err_t rpp_eth_send(struct netif * netif, struct pbuf *p)
{
*/
SYS_ARCH_PROTECT(lev);
+ /* protect from access receive acces from interrupt */
+#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;
}
- /**
- * Bump the reference count on the pbuf to prevent it from being
- * freed till we are done with it.
- *
- */
- pbuf_ref(p);
-
/* call the actual transmit function */
retVal = rpp_eth_send_raw(netif, p);
/* Return to prior interrupt state and return. */
SYS_ARCH_UNPROTECT(lev);
+#if !SYS_LIGHTWEIGHT_PROT
+ if(!prevProt)_enable_IRQ();
+#endif
+
return retVal;
}
+/**
+ * send packet, blocks till it is sent
+ * every send uses bds on the beginning of CPPI RAM
+ */
err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
- volatile struct emac_tx_bd *curr_bd, *active_head, *bd_end;
+ volatile struct emac_tx_bd *curr_bd, *bd_end;
struct hdkif *hdkif;
- struct txch *txch;
- err_t retVal = SUCCESS;
hdkif = (struct hdkif *) netif->state;
- txch = &(hdkif->txch);
+ curr_bd = (struct emac_tx_bd *) hdkif->emac_ctrl_ram;
-#if RPP_ETH_STATS
- preparedTxPBUFs++;
- preparedTxPBUFChains += pbuf_clen(p);
-#endif
-
- /* Get the buffer descriptor which is free to transmit */
- curr_bd = txch->free_head;
-
- active_head = curr_bd;
-
- /* Update the total packet length */
- curr_bd->flags_pktlen &= ~0xFFFF;
- curr_bd->flags_pktlen |= p->tot_len;
+ /* destroy all flags previously set and update the total packet length */
+ 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);
bd_end = curr_bd;
curr_bd->pbuf = p;
curr_bd = curr_bd->next;
-#if RPP_ETH_STATS
- filledTXbds++;
-#endif
+ curr_bd->flags_pktlen = 0x0; /* destroy all previously set flags */
}
/* Indicate the end of the packet */
bd_end->next = NULL;
bd_end->flags_pktlen |= EMAC_DSC_FLAG_EOP;
-#if RPP_ETH_STATS
- filledTXPKTs++;
-#endif
+ /* don't write to hdp till it turns zero */
+ while (0 != *((volatile uint32_t *) (hdkif->emac_base + EMAC_TXHDP(CHANNEL)) ));
+ /* notify hw where to start transmission from */
+ HWREG(hdkif->emac_base + EMAC_TXHDP(CHANNEL)) = hdkif->emac_ctrl_ram;
+ //EMACTxHdrDescPtrWrite(hdkif->emac_base, hdkif->emac_ctrl_ram, CHANNEL);
- txch->free_head = curr_bd;
+ /* wait till queued pkt is sent */
- /* 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;
- /* 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)); /* 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;
- if (EMAC_DSC_FLAG_EOQ == (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ)) {
- /* Write the Header Descriptor Pointer and start DMA */
- EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), 0);
- curr_bd->flags_pktlen &= ~EMAC_DSC_FLAG_EOQ;
- }
- /*
- 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);
- curr_bd->flags_pktlen &= ~EMAC_DSC_FLAG_EOQ;
- }*/
- }
+ while (!(bd_end->flags_pktlen & EMAC_DSC_FLAG_EOQ) || (((struct emac_tx_bd *)(hdkif->emac_ctrl_ram))->flags_pktlen & EMAC_DSC_FLAG_OWNER));
- txch->active_tail = bd_end;
+ EMACTxCPWrite(hdkif->emac_base, CHANNEL, (uint32_t) 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
+ EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
- return retVal;
+ /* restore bds chain */
+ bd_end->next = curr_bd;
+
+ LINK_STATS_INC(link.xmit);
+ return SUCCESS;
}
void rpp_eth_recv_raw(void *arg)
#if !NO_SYS && !ONE_DRIVER_TASK
- //SYS_ARCH_DECL_PROTECT(lev);
+ SYS_ARCH_DECL_PROTECT(lev);
for(;;)
{
vim_mask_set(RXinterruptVectorNumber);
sys_arch_sem_wait(&(hdkif->goRX), 0);
- //SYS_ARCH_PROTECT(lev);
+ 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;
-#ifdef DEBUG
if(curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP != EMAC_DSC_FLAG_SOP)rpp_debug_printf((const char *) "ERR: Active head is not SOP!\n");
-#endif
/**
* Process the descriptors as long as data is available
/* 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;
}
#ifdef DEBUG
if(curr_bd == NULL)rpp_debug_printf((const char *) "rx curr_bd set to zero!\n");
#endif
- /* FIXME: curr_bd here could be NULL - a solution could be: we need to keep at least TCP_MSS bytes, so allocate at least that if not possible block */
+ /* FIXME: curr_bd here could be NULL - (currently solved by having always allocated enough pbufs -> waiting for pbuf_free() function) a solution could be: we need to keep at least TCP_MSS bytes, so allocate at least that if not possible block */
} while((processed_bd->flags_pktlen & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP);
/**
*/
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);
* from the upper layer
*/
rxch->freed_pbuf_len += len_to_alloc;
- /* FIXME: this does not work well */
#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
}
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);
- }
-#endif
-}
-
-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;
-
-#if !NO_SYS && !ONE_DRIVER_TASK
- SYS_ARCH_DECL_PROTECT(lev);
- for(;;){
- vim_mask_set(TXinterruptVectorNumber);
- sys_arch_sem_wait(&(hdkif->goTX), 0);
- SYS_ARCH_PROTECT(lev);
-#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); /* XXX: place where it stucks sometimes */
-
- /* 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;
-#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);
- 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;
- }
-
- 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
-}
-
-#if PHY_LINK_MONITOR_INT
-void linkStatusChanged(void *arg)
-{
- struct netif *netif = (struct netif*) arg;
- struct hdkif *hdkif = (struct hdkif*) netif->state;
- uint8_t instNum = hdkif->inst_num;
-#if !NO_SYS && !ONE_DRIVER_TASK
- for(;;){
- vim_mask_set(LNKInterruptVectorNumber);
- sys_arch_sem_wait(&(hdkif->goLink), 0);
-#else
-#endif
- rpp_sci_printf((const char *) "link is %s\n",rpp_eth_phylinkstat(instNum)?"UP":"DOWN");
- /* do whatever necessary for link status change here */
-
- /* 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);
-#if !NO_SYS && !ONE_DRIVER_TASK
}
#endif
}
-#endif /* PHY_LINK_MONITOR_INT */
void RxIntHandler(u32_t instNum)
{
void TxIntHandler(u32_t instNum)
{
+ //struct hdkif *hdkif = &hdkif_data[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]);
+ //sendDone = TRUE;
+ //rpp_eth_send_bd_handler((void *) &hdkif_data[instNum]);
#endif
}
+/**
+ * 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, errFound = FALSE;
+ uint32_t reg;
+ struct hdkif *hdkif;
+
+ while(index){
+ hdkif = &hdkif_data[--index];
+ if(EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_HOSTPEND)errFound = TRUE;
+ }
+ if(!errFound)return FALSE; /* this is not the cause of the interrupt */
+ rpp_sci_printk((const char *) "HOSTPEND err\n");
+ reg = HWREG(hdkif->emac_base + EMAC_MACSTATUS);
+ rpp_sci_printk((const char *) "TXCHERR: %d at CH: %d\n", ((reg >> EMAC_MACSTATUS_TXERRCODE_SHIFT) & 0x7), ((reg >> EMAC_MACSTATUS_TXERRCH_SHIFT) & 0x7));
+ rpp_sci_printk((const char *) "RXCHERR: %d at CH: %d\n", ((reg >> EMAC_MACSTATUS_RXERRCODE_SHIFT) & 0x7), ((reg >> EMAC_MACSTATUS_RXERRCH_SHIFT) & 0x7));
+ /* no acknowledge - emac module has to be restarted */
+ return TRUE; /* this was the reason of interrupt */
+}
+
#if PHY_LINK_MONITOR_INT
boolean_t LinkIntHandler(void)
{
uint8_t index = MAX_EMAC_INSTANCE, phyFound = FALSE;
struct hdkif *hdkif;
+ uint16_t regContent;
+ volatile unsigned int autonegFinishWait = 0xFFFFFFF;
+ volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
/* 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) && (HWREG(hdkif->emac_base + EMAC_MACINVECTOR) & EMAC_MACINVECTOR_LINKINT0) )phyFound = TRUE;
+ if( hdkif->phy_addr == (HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) & 0x1f) && EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_LINKINT0 )phyFound = TRUE;
}
if(!phyFound)return FALSE;
-#if !NO_SYS
- vim_mask_clr(LNKInterruptVectorNumber); /* see sys_startup.c */
- xSemaphoreGiveFromISR(hdkif->goLink, NULL);
-#else
+ struct netif *netif = &hdkNetIF[hdkif->inst_num];
+
/* we handles here connection of cable after startup, not changes of linkstatus */
- /* do whatever necessary for link status change here */
+ /* 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, ®Content);
+ 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;
/* acknowledge EMAC control module by writing appropriate key to MACEOIVECTOR */
EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
-#endif
+
return TRUE;
}
-#endif
+#endif /* PHY_LINK_MONITOR_INT */
#endif /* rppCONFIG_INCLUDE_ETH */