X-Git-Url: http://rtime.felk.cvut.cz/gitweb/pes-rpp/rpp-lib.git/blobdiff_plain/c5eb1843dec801a3da118585f2e5bbb921174c63..49901f543393051038bf8dd7fb1cffb0ee9a7be8:/rpp/src/rpp/eth.c diff --git a/rpp/src/rpp/eth.c b/rpp/src/rpp/eth.c index 36dd4e9..6eb21b0 100644 --- a/rpp/src/rpp/eth.c +++ b/rpp/src/rpp/eth.c @@ -1,5 +1,6 @@ /** * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (C) 2013-2015 Czech Technical University in Prague * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,6 +28,9 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels + * Carlos Jenkins + * Rostislav Lisovy + * Jan Doležal * */ @@ -37,34 +41,10 @@ * interface driver for lwIP. * */ -/* Copyright (C) 2013 Czech Technical University in Prague - * - * Authors: - * - Carlos Jenkins - * - Rostislav Lisový - * - Jan Doležal - * - * 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 . - * - * 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" @@ -80,69 +60,84 @@ #include "netif/ppp_oe.h" /* end - lwIP headers */ -#include "hal/hal.h" -#include "rpp/rpp.h" +#include "drv/gio.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; @@ -151,6 +146,7 @@ boolean_t isPostInitialized() uint32_t rpp_eth_phylinkstat(uint32_t instNum) { struct hdkif *hdkif = &hdkif_data[instNum]; + return PHY_link_status_get(hdkif->mdio_base, hdkif->phy_addr, 1); } @@ -191,7 +187,7 @@ err_t rpp_eth_stringToIP(ip_addr_t * ip, uint8_t * ipstr) ipaddr = (ipaddr << 8) + tmp; dots++; - if(dots > 3)break; + if (dots > 3)break; tmp = 0; fldEdit = FALSE; @@ -234,7 +230,7 @@ struct netif *rpp_eth_get_netif(uint32_t instNum) return &hdkNetIF[instNum]; } -/********************************************** forward declares **********************************************/ +/***** forward declarations **********************************************/ /* * interface initializes @@ -255,7 +251,7 @@ err_t rpp_eth_hw_init(struct hdkif *hdkif); */ err_t rpp_eth_hw_init_postInit(struct netif *netif); -/********************************************** utility functions **********************************************/ +/***** utility functions **********************************************/ /* * Function to set the MAC address to the interface @@ -263,21 +259,21 @@ err_t rpp_eth_hw_init_postInit(struct netif *netif); * * @note mac_addr[0] is considered MSB */ -void -hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) { - struct hdkif *hdkif; - u32_t temp; +static void hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) +{ + struct hdkif *hdkif; + u32_t temp; - hdkif = &hdkif_data[inst_num]; + hdkif = &hdkif_data[inst_num]; - /* set MAC hardware address */ - for(temp = 0; temp < MAC_ADDR_LEN; temp++) { - hdkif->mac_addr[temp] = mac_addr[(MAC_ADDR_LEN - 1) - temp]; - } + /* set MAC hardware address */ + for (temp = 0; temp < MAC_ADDR_LEN; temp++) { + hdkif->mac_addr[temp] = mac_addr[(MAC_ADDR_LEN - 1) - temp]; + } #ifdef DEBUG - uint8_t macStr[18]; - rpp_eth_get_macAddrStr(inst_num, macStr); - rpp_debug_printf("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 } @@ -286,416 +282,469 @@ hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) { * @param hdkif * @return none. */ -static void -hdkif_inst_config(struct hdkif *hdkif) { - if(hdkif->inst_num == 0) - { - hdkif->emac_base = EMAC_BASE_m(0); - hdkif->emac_ctrl_base = EMAC_CTRL_BASE_m(0); - hdkif->emac_ctrl_ram = EMAC_CTRL_RAM_BASE_m(0); - hdkif->mdio_base = MDIO_BASE_m(0); - hdkif->phy_addr = DEFAULT_PHY_ADDR; /* Default address of PHY on "MDIO bus" (depends on PHY hw configuration) */ - hdkif->phy_autoneg = PHY_auto_negotiate; - hdkif->phy_autoneg_start = PHY_start_auto_negotiate; - hdkif->phy_autoneg_is_done = PHY_is_done_auto_negotiate; - hdkif->phy_partnerability = PHY_partner_ability_get; - } +static void hdkif_inst_config(struct hdkif *hdkif) +{ + if (hdkif->inst_num == 0) { + hdkif->emac_base = EMAC_BASE_m(0); + hdkif->emac_ctrl_base = EMAC_CTRL_BASE_m(0); + hdkif->emac_ctrl_ram = EMAC_CTRL_RAM_BASE_m(0); + hdkif->mdio_base = MDIO_BASE_m(0); + + /* Default address of PHY on "MDIO bus" + * (depends on PHY hw configuration) + */ + hdkif->phy_addr = DEFAULT_PHY_ADDR; + hdkif->phy_autoneg = PHY_auto_negotiate; + hdkif->phy_autoneg_start = PHY_start_auto_negotiate; + hdkif->phy_autoneg_is_done = PHY_is_done_auto_negotiate; + hdkif->phy_partnerability = PHY_partner_ability_get; + } } -/********************************************** initializing functions **********************************************/ - +/***** initializing functions **********************************************/ int8_t rpp_eth_init() { - uint8_t instNum; + unsigned int instNum; int8_t retVal = SUCCESS; - if(initialized) { - return FAILURE; - } - - /* config of EMAC instances and other stuff */ - for(instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++) - { - hdkif_data[instNum].inst_num = instNum; - hdkif_inst_config(&hdkif_data[instNum]); /* hdkif_inst_config must contain instNum specific settings */ - if(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 (initialized) + return FAILURE; -#if NO_SYS + /* Config each EMAC instance */ + for (instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++) { + struct hdkif *hdkif = &hdkif_data[instNum]; -#else /* NO_SYS */ + hdkif->inst_num = instNum; + hdkif_inst_config(hdkif); -#endif /* NO_SYS */ - - 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_pin_set(*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); - - /* 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 + */ + gio_set(PIN_ETHRST, 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; + + uint16_t regContent; + uint32_t num_bd, pbuf_cnt = 0; + volatile struct emac_tx_bd *curr_txbd, *last_txbd; + volatile struct emac_rx_bd *curr_rxbd, *last_rxbd; + struct pbuf *p, *q; + struct rxch *rxch; + struct txch *txch; - struct hdkif *hdkif = (struct hdkif *) netif->state; + struct hdkif *hdkif = (struct hdkif *)netif->state; - rxch = &(hdkif->rxch); - txch = &(hdkif->txch); + rxch = &(hdkif->rxch); + txch = &(hdkif->txch); - rpp_debug_printf("autoneg started - check on cable if it's connected!\r\n"); + rpp_debug_printf("autoneg started -- check on cable if it's connected!\r\n"); + /* + * Use the CPPI RAM to store RX/TX Buffer Descriptors (= BD). + * 1/2 of CPPI RAM is used for TX BDs, another 1/2 for RX BDs. + * All the TX BDs are 'owned' by the software. They are initialized + * as a linked-list forming a ring. They are awaiting the application + * to append pbuf payload to the them and correctly configure for + * actual transmission. + * Only such number of RX BDs is configured that the pbufs can be + * allocated for (i.e. MAX_RX_PBUF_ALLOC). Pbufs are allocated from + * the PBUF_POOL (thus the allocated pbufs might be chained). + * Each payload part of a payload is them used to initialize single + * RX BD. The RX BDs are then configured to be 'owned' bythe EMAC + */ /* - * Initialize the Descriptor Memory For TX and RX - * Only Channel 0 is supported for both TX and RX - */ - txch->free_head = ((volatile struct emac_tx_bd *) hdkif->emac_ctrl_ram); + * Initialize the Descriptor Memory For TX and RX + * Only Channel 0 is supported for both TX and RX + */ + txch->free_head = (volatile struct emac_tx_bd *)hdkif->emac_ctrl_ram; txch->next_bd_to_process = txch->free_head; txch->active_tail = NULL; /* Set the number of descriptors for the channel */ - num_bd = (SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_tx_bd); /* take half of CPPI ram for TX BDs */ + /* take half of CPPI ram for TX BDs */ + num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_tx_bd)); curr_txbd = txch->free_head; /* Initialize all the TX buffer Descriptors */ - while(num_bd--) { - curr_txbd->next = curr_txbd + 1; - curr_txbd->flags_pktlen = 0; - last_txbd = curr_txbd; - curr_txbd = curr_txbd->next; + while (num_bd--) { + curr_txbd->next = curr_txbd + 1; + curr_txbd->flags_pktlen = 0; + last_txbd = curr_txbd; + curr_txbd = curr_txbd->next; } last_txbd->next = txch->free_head; + /* curr_txbd now points to the BD that is the first BD + * after the last_txbd -- this will be the first RX BD + */ /* Initialize the descriptors for the RX channel */ - rxch->active_head = (volatile struct emac_rx_bd*)(curr_txbd); - rxch->free_head = NULL; + rxch->active_head = (volatile struct emac_rx_bd*)curr_txbd; + rxch->free_head = NULL; /* Not used */ rxch->freed_pbuf_len = 0; - num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_rx_bd)); /* when using 20B emac_bd structs, u can allocate one more ;) ( 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 */ @@ -705,546 +754,684 @@ err_t rpp_eth_hw_init_postInit(struct netif *netif) /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - /* lwIP stuff - end */ - /* for flow control frames */ - EMACMACSrcAddrSet(hdkif->emac_base, hdkif->mac_addr); + /* 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); @@ -1252,5 +1439,4 @@ boolean_t LinkIntHandler(void) return TRUE; } #endif /* PHY_LINK_MONITOR_INT */ - -#endif /* rppCONFIG_INCLUDE_ETH */ +#endif /* FREERTOS_POSIX */