/**
* 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,
* 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 "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 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 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 10
-#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'
+#define IFNAME0 'e'
+#define IFNAME1 'n'
+/* Time to wait for autonegotiation in ticks. */
+#define TICKS_PHY_AUTONEG 4000
/**
- * Time to wait for autonegotiation in ticks.
+ * TODO -- not implemented
+ * When cable is connected (link status goes up)
+ * autonegotiation and/or dhcp is started.
*/
-#define TICKS_PHY_AUTONEG 4000
+#define PHY_LINK_MONITOR_INT 0
-/**
- * NOT IMPLEMENTED
- * When cable is connected (link status goes up) autonegotiation and/or dhcp is started.
- */
-#define PHY_LINK_MONITOR_INT 0 /* turn on handling interrupt - not implemented now */
-/* end options */
-/* 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;
-
-boolean_t sendDone = TRUE;
-
-/* free pbuf notification */
-#if !NO_SYS
-xSemaphoreHandle pbufFreed;
-#endif
-
-/**********************************************testing functions**********************************************/
+/* RPP startup init indicator */
+static boolean_t initialized = FALSE;
+static boolean_t postInitialized = FALSE;
+/***testing functions**********************************************/
boolean_t isPostInitialized()
{
return postInitialized;
return &hdkNetIF[instNum];
}
-/********************************************** forward declares **********************************************/
+/***** forward declarations **********************************************/
/*
* interface initializes
*/
err_t rpp_eth_hw_init_postInit(struct netif *netif);
-/********************************************** utility functions **********************************************/
+/***** utility functions **********************************************/
/*
* Function to set the MAC address to the interface
*
* @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("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
}
* @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(retVal = rpp_eth_hw_init(&hdkif_data[instNum]))
- {
-#ifdef DEBUG
- rpp_sci_printk("rpp_eth_hw_init: %d", retVal);
-#endif
- 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;
-
- /* ----- lwIP stuff ----- */
- struct ip_addr ip_addr;
- struct ip_addr net_mask;
- struct ip_addr gw_addr;
- volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
-
- if(macArray == NULL)
- {
- macArray = mac_addr; /* use default MAC */
- }
- hdkif_macaddrset(instNum, macArray);
-
- struct hdkif *hdkif;
+ 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;
+
+ if (postInitialized)
+ return FAILURE;
+
+ if (macArray == NULL)
+ macArray = mac_addr; /* use default MAC */
+
+ hdkif_macaddrset(instNum, macArray);
+
#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 */
+ lwip_init();
+#else
+ /* This can be called only within post OS init */
+
+ /*
+ * calls lwip_init() implicitly, starts lwIP task (thread),
+ * when started function given to tcpip_init is executed first
+ */
+ tcpip_init(NULL, NULL);
+#endif
#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 */
+ 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
+
#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;
- }
+ /* 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
+ if (netif_tmp == NULL)
+ return NETIF_ADD_ERR;
+
+ netif_set_default(netif);
- netif_set_default(netif);
+ hdkif = netif->state;
- hdkif = (struct hdkif *) netif->state;
#if !NO_SYS
- /* ----- 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);
- /* 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 );
- /* ----- end - freeRTOS ----- */
-#endif /* !NO_SYS */
-
- /* 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((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)
- {
- 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--))/*sys_check_timeouts()*/;
- if(!dhcpBindWait)
- rpp_debug_printf("dhcp binding timeout...\r\n");
-#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("Address: %s\r\n", ipString);
- rpp_eth_getIPDecimalStr(netif->netmask, ipString);
- rpp_debug_printf("Netmask: %s\r\n", ipString);
- rpp_eth_getIPDecimalStr(netif->gw, ipString);
- rpp_debug_printf("Gateway: %s\r\n", ipString);
+ /* 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;
- }
+
+ /* 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 */
- /* 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);
+ /* 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 controle module */
- HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_LINKINT0ENB;
+ /* 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 */
- /* ----- end - lwIP stuff ----- */
- postInitialized = TRUE;
+ 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 */
-
- uint32_t instNum = (uint32_t)netif->state;
- /*netif->num = instNum; - auto-initiated when netif_add is called */
+ struct hdkif *hdkif = netif->state;
- /* 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;
- uint16_t regContent;
- uint32_t physAlive;
+ 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
#if NO_SYS
- uint8_t index = 80; /* Initially used to hw reset of PHY connected to GIO pin. This means 1us - for 80MHz clock. */
+ /*
+ * Initially used to hw reset of PHY connected to GIO pin.
+ * This means 1us - for 80MHz clock.
+ */
+ index = 80;
#else /* NO_SYS */
- 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. */
+ /*
+ * 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 */
- hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),0);
- while(index--);
+ 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 */
- hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),1);
+ /* 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);
- /* 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);
-
- /* 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, ®Content);
- /* 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, ®Content); /* 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)
- {
- rpp_debug_printf("no phy found, phys: %d\r\n", physAlive);
- 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, ®Content);
+
+ /* 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
- rpp_debug_printf("default phy not alive\r\n");
- return DFLT_PHY_NOT_ALIVE;
+ rpp_debug_printf("default phy not alive\n");
+ 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, TX and MISC 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 */
+ /* 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);
- /* 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;
}
-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; /* 0x3FFFFFFF is 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;
- struct hdkif *hdkif = (struct hdkif *) netif->state;
+ 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;
- rxch = &(hdkif->rxch);
- txch = &(hdkif->txch);
+ struct hdkif *hdkif = (struct hdkif *)netif->state;
- rpp_debug_printf("autoneg started - check on cable if it's connected!\r\n");
+ rxch = &(hdkif->rxch);
+ txch = &(hdkif->txch);
+ rpp_debug_printf("autoneg started -- check on cable if it's connected!\r\n");
/*
- * 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);
+ * 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;
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 ;) ( 8192/20 = 409 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_debug_printf("no pbufs attached to rx buffer descriptors during init\n");
+ 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 );
- rpp_debug_printf("%d pbuf chains allocated for %d rx buffer descriptors\n", pbuf_cnt, num_bd);
- /* 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 */
+#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 */
/* 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);
+ /* 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);
+ /* 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);
+ }
-#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 */
-#else
- while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && autonegFinishWait--); /* wait till aneg done */
-#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 */
+ }
- if(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) != FALSE)
- rpp_debug_printf("aneg finished \r\n");
- else
- rpp_debug_printf("aneg timeout \r\n");
-
- /* 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 {
- rpp_debug_printf("Unknown duplex mode\r\n");
- 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, ®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 {
+ rpp_debug_printf("Unknown duplex mode\r\n");
+ return UNKN_DUPLEX_MODE;
+ }
#endif /* !PHY_LINK_MONITOR_INT */
- /* enable hostpend interrupts in emac module */
- HWREG(hdkif->emac_base + EMAC_MACINTMASKSET) |= EMAC_MACINTMASKSET_HOSTMASK;
+ /* enable hostpend interrupts in emac module */
+ HWREG(hdkif->emac_base + EMAC_MACINTMASKSET) |=
+ EMAC_MACINTMASKSET_HOSTMASK;
- /* enable hostpend interrupts in emac control module */
- HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_HOSTPENDENB;
+ /* 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);
-
- /* 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;
+ 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 until 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();
+ if (!prevProt)
+ _enable_IRQ();
#endif
return retVal;
}
/**
- * send packet, blocks till it is sent
- * every send uses bds on the beginning of CPPI RAM
+ * When called from rpp_eth_send(), the 'lev' lock is held
*/
-err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *p)
+static err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *pbuf)
{
struct pbuf *q;
- volatile struct emac_tx_bd *curr_bd, *bd_end;
+ struct txch *txch;
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;
- curr_bd = (struct emac_tx_bd *) hdkif->emac_ctrl_ram;
+ hdkif = (struct hdkif *)netif->state;
+ txch = &(hdkif->txch);
- /* destroy all flags previously set and update the total packet length */
- curr_bd->flags_pktlen = p->tot_len;
+ /* Get the first BD that is unused and will be used for TX */
+ curr_bd = txch->free_head;
+ active_head = curr_bd;
- /* 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;
- curr_bd->flags_pktlen = 0x0; /* destroy all previously set flags */
+ /* 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;
- /* 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);
-
- /* wait till queued pkt is sent */
- vim_mask_set(TXinterruptVectorNumber);
- xSemaphoreTake(hdkif->goTX, portMAX_DELAY);
- while (!(bd_end->flags_pktlen & EMAC_DSC_FLAG_EOQ) || (((struct emac_tx_bd *)(hdkif->emac_ctrl_ram))->flags_pktlen & EMAC_DSC_FLAG_OWNER))rpp_sci_printk("!");
+ /* 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);
+ } 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
- EMACTxCPWrite(hdkif->emac_base, CHANNEL, (uint32_t) bd_end);
+ /* 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;
- EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
+ return SUCCESS;
+}
- /* restore bds chain */
- bd_end->next = curr_bd;
+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;
+
+ 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;
+ }
- LINK_STATS_INC(link.xmit);
- return SUCCESS;
+ /* 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 && !ONE_DRIVER_TASK
- SYS_ARCH_DECL_PROTECT(lev);
- for(;;)
- {
- vim_mask_set(RXinterruptVectorNumber);
- sys_arch_sem_wait(&(hdkif->goRX), 0);
- SYS_ARCH_PROTECT(lev);
+ 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;
+ LINK_STATS_INC(link.recv);
- /* Get the bd which contains the earliest filled data */
- curr_bd = rxch->active_head;
- last_bd = rxch->active_tail;
-
- if(curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP != EMAC_DSC_FLAG_SOP)rpp_debug_printf("ERR: Active head is not SOP!\n");
-
- /**
- * 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;
-#ifdef DEBUG
- if(curr_bd == NULL)rpp_debug_printf("rx curr_bd set to zero!\n");
-#endif
- /* 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);
-
- /**
- * 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 - this function is specified while adding netif using netif_add() function */
- 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);
-
- if(curr_bd != NULL)
- {
- rxch->active_head = curr_bd;
- }
- else
- {
- rxch->active_head = processed_bd + 1; //todo:reconsider
- }
-
- /**
- * 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
- xSemaphoreTake(pbufFreed, 0);
- xSemaphoreTake(pbufFreed, portMAX_DELAY);
- }while(1);
-#endif
+ /* 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);
+ }
- /* 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);
+ /* 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;
+ }
-#if !NO_SYS && !ONE_DRIVER_TASK
- SYS_ARCH_UNPROTECT(lev);
- }
-#endif
+ /* 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);
+ }
}
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)
{
- //struct hdkif *hdkif = &hdkif_data[instNum];
-#if !NO_SYS
vim_mask_clr(TXinterruptVectorNumber); /* see sys_startup.c */
xSemaphoreGiveFromISR(hdkif_data[instNum].goTX, NULL);
-#else
- //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)
- *
+ * 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
+ * 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;
+ uint8_t index = MAX_EMAC_INSTANCE;
+ uint8_t errFound = FALSE;
uint32_t reg;
struct hdkif *hdkif;
- while(index){
+ while (index) {
hdkif = &hdkif_data[--index];
- if(EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_HOSTPEND)errFound = TRUE;
+
+ if (EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_HOSTPEND)
+ errFound = TRUE;
}
- if(!errFound)return FALSE; /* this is not the cause of the interrupt */
+
+ 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));
+ 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 */
- return TRUE; /* this was the reason of interrupt */
+
+ /* this was the reason of interrupt */
+ return TRUE;
}
#if PHY_LINK_MONITOR_INT
boolean_t LinkIntHandler(void)
{
- uint8_t index = MAX_EMAC_INSTANCE, phyFound = FALSE;
+ 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;
+ 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) && EMACIntVectorGet(hdkif->emac_base) & EMAC_MACINVECTOR_LINKINT0 )phyFound = TRUE;
+ /* 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];
+ if (!phyFound)
+ return FALSE;
+ struct netif *netif = &hdkNetIF[hdkif->inst_num];
- /* we handles here connection of cable after startup, not changes of linkstatus */
+ /* we handle here connection of cable after startup, not changes of linkstatus */
- /* wait for autonegotiation to be done */
+ /* wait for autonegotiation to be done */
#if ONCE_LINK_SETUP
- while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE);
+ 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--);
+ 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))
- {
+ /* 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);
+ 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 (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);
+ 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;
- }
+ 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);
+ 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);
+ /* turn this interrupt off */
+ HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) &=
+ (~EMAC_CTRL_MISC_LINKINT0ENB & 0xf);
#endif /* ONCE_LINK_SETUP */
- }
- else
- {
+ } 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;
+ /* 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);
+ netif_set_down(netif);
#elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
- dhcp_stop(netif);
+ 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 /* PHY_LINK_MONITOR_INT */
-
-#endif /* rppCONFIG_INCLUDE_ETH */
+#endif /* FREERTOS_POSIX */