2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27 * This file is part of the lwIP TCP/IP stack.
29 * Author: Adam Dunkels <adam@sics.se>
34 * Copyright (c) 2010 Texas Instruments Incorporated
36 * This file is dervied from the "ethernetif.c" skeleton Ethernet network
37 * interface driver for lwIP.
40 /* Copyright (C) 2013 Czech Technical University in Prague
43 * - Carlos Jenkins <carlos@jenkins.co.cr>
45 * - Jan Doležal <pm.jenik@gmail.com>
47 * This program is free software; you can redistribute it and/or modify
48 * it under the terms of the GNU General Public License as published by
49 * the Free Software Foundation; either version 2 of the License, or
50 * (at your option) any later version.
52 * This program is distributed in the hope that it will be useful,
53 * but WITHOUT ANY WARRANTY; without even the implied warranty of
54 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 * GNU General Public License for more details.
57 * You should have received a copy of the GNU General Public License
58 * along with this program. If not, see <http://www.gnu.org/licenses/>.
62 * Ethernet Communication RPP API implementation file. Using one PHY.
66 * RPP API documentation.
70 #include "lwip/init.h"
71 #include "lwip/timers.h" /* for DHCP binding in NO_SYS mode */
72 #include "lwip/sys.h" /* includes - lwip/opt.h, lwip/err.h, arch/sys_arch.h */
73 #include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */
74 #include "lwip/stats.h" /* includes - lwip/mem.h, lwip/memp.h, lwip/opt.h */
75 #include "netif/etharp.h" /* includes - lwip/ip.h, lwip/netif.h, lwip/ip_addr.h, lwip/pbuf.h */
77 #include "lwip/snmp.h"
78 #include "lwip/dhcp.h"
79 #include "lwip/autoip.h"
80 #include "netif/ppp_oe.h"
81 /* end - lwIP headers */
85 #include "sys/sys.h" /* includes - sys/phy_dp83848h.h */
91 #if rppCONFIG_INCLUDE_ETH == 1
95 /* Number of EMAC Instances */
96 #define MAX_EMAC_INSTANCE 1
98 /* config whether only one task for driver will be used *//* this controls, whether there will be one task handling interrupts for receive, send bd handeling or link status change or even receive threshold */
99 /* only one task should be used due to stability of system (it seems that LwIP doesn't handle it well when it has separate tasks for receive and send bd handler) / memory savings (in fact it ate so much memory, that it fell often) */
100 #define ONE_DRIVER_TASK 0
103 * if this is set, the link value is set only once upon start/cable connection
104 * it this is not set, then each time cable is plugged or unplugged, the interface link status is updated
105 * and when dhcp is enabled, it is negotiated
107 #define ONCE_LINK_SETUP 1
109 #define DEFAULT_PHY_ADDR 0x1
110 #define FIND_FIRST_PHY_ALIVE 1 /* or use default (phy_address: 1) */
111 #define NUM_OF_PHYs 32
112 #define SIZE_OF_DESC 16 /* in bytes */
113 #define CHANNEL 0 /* channel number for everything - for rx, tx, unicast, broadcast or damaged frames ; there are different channels for rx and tx operations */
115 #define MAX_TRANSFER_UNIT 1500 /* take in account oversized frames */
116 #define PBUF_LEN_MAX MAX_TRANSFER_UNIT
117 #define MAX_RX_PBUF_ALLOC 10
118 #define MIN_PKT_LEN 60
120 /* Define those to better describe the network interface. */
125 /* Defining interface for all the emac instances */
126 static struct hdkif hdkif_data[MAX_EMAC_INSTANCE];
129 ** The lwIP network interface structure for the HDK Ethernet MAC.
131 static struct netif hdkNetIF[MAX_EMAC_INSTANCE];
133 /* rpp startup init indicator */
134 static boolean_t initialized = FALSE, postInitialized = FALSE;
136 /* free pbuf notification */
138 xSemaphoreHandle pbufFreed;
141 /**********************************************testing functions**********************************************/
143 uint32_t rpp_eth_phylinkstat(uint32_t instNum)
145 struct hdkif *hdkif = &hdkif_data[instNum];
146 return PHY_link_status_get(hdkif->mdio_base, hdkif->phy_addr, 1);
149 #define BYTE_BUFF_SIZE 2
150 #define OFFSET_MAC_LETTERS (MAC_BIG_LETTERS ? 'A' : 'a')
151 /* puts string of MAC address assigned to EMAC instance reffered by instNum into *mac */
152 void rpp_eth_get_macAddrStr(uint32_t instNum, uint8_t *macStr)
154 uint8_t index, outindex = 0;
155 char buff[BYTE_BUFF_SIZE];
156 struct hdkif *hdkif = &hdkif_data[instNum];
157 for(index = 0; index < MAC_ADDR_LEN; index++) {
158 if(index)macStr[outindex++] = ':';
159 buff[0] = (hdkif->mac_addr[(MAC_ADDR_LEN - 1) - index] >> 4);
160 buff[1] = (hdkif->mac_addr[(MAC_ADDR_LEN - 1) - index] & 0xf);
161 macStr[outindex++] = (buff[0]<10) ? (buff[0] + '0') : (buff[0] - '\012' + OFFSET_MAC_LETTERS);
162 macStr[outindex++] = (buff[1]<10) ? (buff[1] + '0') : (buff[1] - '\012' + OFFSET_MAC_LETTERS);
164 macStr[outindex] = '\0';
167 /* prepares an IP address to ipStr in form of null terminated string; each byte of ip is converted to one of 4 field in IPv4 IP address format 0xAABBCCDD -> "aaa.bbb.ccc.ddd" */
168 inline void rpp_eth_getIPDecimalStr(ip_addr_t ip, uint8_t *ipStr)
170 snprintf((char *)ipStr, 16, "%d.%d.%d.%d",(ip.addr >> 24),((ip.addr >> 16) & 0xff),((ip.addr >> 8) & 0xff),(ip.addr & 0xff));
173 /* @param ip will be filled accroding to content of ipstr */
174 err_t rpp_eth_stringToIP(ip_addr_t * ip, uint8_t * ipstr)
176 uint8_t charProccessed, index = 0, dotindex = 0xff, tmp = 0, dots = 0, fldEdit = 0;
178 for(charProccessed = ipstr[index]; (charProccessed >= '0' && charProccessed <= '9') || charProccessed == '.' ; charProccessed = ipstr[++index])
180 if(charProccessed == '.')
182 if(++dotindex == index)
189 ipaddr = (ipaddr << 8) + tmp;
200 tmp = tmp*10 + charProccessed - '0';
203 if(dots != 3 || !fldEdit)
205 /* if unsuccesful, don't modify previous content */
208 ipaddr = (ipaddr << 8) + tmp;
213 /* returns number in range 0-65535 where 0 is error */
214 uint16_t rpp_eth_portStrToInt(uint8_t *string)
218 for(index = 0;string[index] != '\0';index++)
220 if(string[index] < '0' || string[index] > '9')
225 portNO = portNO * 10 + string[index] - '0';
230 struct netif *rpp_eth_get_netif(uint32_t instNum)
232 return &hdkNetIF[instNum];
235 /********************************************** forward declares **********************************************/
238 * interface initializes
240 err_t rpp_eth_lwip_init(struct netif *netif);
243 * Initializes hw such as PHY, MDIO, EMAC, EMAC control module
245 * @return SUCCESS if initialization successful.\n
246 * FAILURE if initialization not successful.
248 err_t rpp_eth_hw_init(struct hdkif *hdkif);
251 * Initializes hw, after lwIP was initialized and
252 * OS was initialized in case OS is used.
254 err_t rpp_eth_hw_init_postInit(struct netif *netif);
258 * Task which handles driver's stuff
260 void rpp_eth_driver(void *arg);
263 #if PHY_LINK_MONITOR_INT
265 * function which handles changes of link status
267 void linkStatusChanged(void *arg);
270 /********************************************** utility functions **********************************************/
273 * Function to set the MAC address to the interface
274 * @param inst_num the instance number
276 * @note mac_addr[0] is considered MSB
279 hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) {
283 hdkif = &hdkif_data[inst_num];
285 /* set MAC hardware address */
286 for(temp = 0; temp < MAC_ADDR_LEN; temp++) {
287 hdkif->mac_addr[temp] = mac_addr[(MAC_ADDR_LEN - 1) - temp];
291 rpp_eth_get_macAddrStr(inst_num, macStr);
292 rpp_debug_printf((const char *) "Setting MAC... %s\r\n", macStr);
297 * Function to setup the instance parameters inside the interface
302 hdkif_inst_config(struct hdkif *hdkif) {
303 if(hdkif->inst_num == 0)
305 hdkif->emac_base = EMAC_BASE_m(0);
306 hdkif->emac_ctrl_base = EMAC_CTRL_BASE_m(0);
307 hdkif->emac_ctrl_ram = EMAC_CTRL_RAM_BASE_m(0);
308 hdkif->mdio_base = MDIO_BASE_m(0);
309 hdkif->phy_addr = DEFAULT_PHY_ADDR; /* Default address of PHY on "MDIO bus" (depends on PHY hw configuration) */
310 hdkif->phy_autoneg = PHY_auto_negotiate;
311 hdkif->phy_autoneg_start = PHY_start_auto_negotiate;
312 hdkif->phy_autoneg_is_done = PHY_is_done_auto_negotiate;
313 hdkif->phy_partnerability = PHY_partner_ability_get;
317 /********************************************** initializing functions **********************************************/
319 int8_t rpp_eth_init()
322 int8_t retVal = SUCCESS;
327 /* config of EMAC instances and other stuff */
328 for(instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++)
330 hdkif_data[instNum].inst_num = instNum;
331 hdkif_inst_config(&hdkif_data[instNum]); /* hdkif_inst_config must contain instNum specific settings */
332 if(rpp_eth_hw_init(&hdkif_data[instNum]))retVal = FAILURE;
335 /* when one of instances was not initialized correctly return FAILURE without setting initialized variable to TRUE */
336 if(retVal)return FAILURE;
349 int8_t rpp_eth_init_postInit(uint32_t instNum, uint8_t *macArray)
351 if(postInitialized) {
354 int8_t retVal = SUCCESS;
355 struct netif *netif = &hdkNetIF[instNum];
356 u8_t mac_addr[MAC_ADDR_LEN] = RPP_MAC_ADDR;
358 uint8_t ipString[16];
361 /* ----- lwIP stuff ----- */
362 struct ip_addr ip_addr;
363 struct ip_addr net_mask;
364 struct ip_addr gw_addr;
365 volatile unsigned int dhcpBindWait = 0x3FFFFFFF;
369 macArray = mac_addr; /* use default MAC */
371 hdkif_macaddrset(instNum, macArray);
377 /* this can be called only within post OS init */
378 tcpip_init(NULL,NULL); /* calls lwip_init() implicitly, starts lwIP task (thread), when started function given to tcpip_init is executed first */
381 #if STATIC_IP_ADDRESS
382 ip_addr.addr = htonl(RPP_IP_ADDR);
383 net_mask.addr = htonl(RPP_NETMASK);
384 gw_addr.addr = htonl(RPP_GW);
385 #else /* STATIC_IP_ADDRESS */
389 #endif /* STATIC_IP_ADDRESS */
391 /* init and add new netif */
392 /* add new network interface to lwIP list of ifaces and initialize netif with specific function */
394 if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, ethernet_input) == NULL )
396 if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, tcpip_input) == NULL )
399 return NETIF_ADD_ERR;
402 netif_set_default(netif);
404 hdkif = (struct hdkif *) netif->state;
406 /* TODO: rewrite these to functions from sys_arch.* not only here for compatibility with other systems then freeRTOS if it is possible (does not seem likely now) */
407 /* ----- freeRTOS elements ----- */
408 /* semaphore blocking receive task (rpp_eth_recv_raw) from receive operation, till RX interrupt occurs and notify it */
409 vSemaphoreCreateBinary(hdkif->goRX);
410 vSemaphoreCreateBinary(hdkif->goTX);
411 #if PHY_LINK_MONITOR_INT
412 vSemaphoreCreateBinary(hdkif->goLink);
414 /* create semaphore notificating that pbuf was freed FIXME: bad solution */
415 vSemaphoreCreateBinary(pbufFreed);/*
416 if( pbufFreed == NULL ){
417 rpp_debug_printf((const char *) "Insufficient memory.");
420 xTaskCreate( rpp_eth_driver, "ethDriver", 250, netif, 0, NULL);
421 #else /* ONE_DRIVER_TASK */
422 /* run task rpp_eth_recv_raw */
423 xTaskCreate( rpp_eth_recv_raw, "RXHandler", 200, netif, 0, NULL );
424 /* run task handling transmitted buffer descriptors */
425 xTaskCreate( rpp_eth_send_bd_handler, "TXHandler", 200, hdkif, 0, NULL );
426 #if PHY_LINK_MONITOR_INT
427 /* run task handling link status changes */
428 xTaskCreate( linkStatusChanged, "LNKHandler", 100, netif, 0, NULL );
429 /* enable linkint on vim level */
430 #endif /* PHY_LINK_MONITOR_INT */
431 #endif /* ONE_DRIVER_TASK */
432 /* ----- end - freeRTOS ----- */
434 vim_mask_set(LNKInterruptVectorNumber);
436 /* TODO: copy this to link interrupt handler/ it must be done, so we do it here when link interrupt handler is not used */
437 #if !PHY_LINK_MONITOR_INT
438 if(rpp_eth_phylinkstat(hdkif->inst_num))
440 rpp_debug_printf((const char *)"cable connected ... setting IP params\r\n");
441 #if STATIC_IP_ADDRESS
443 #elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
444 if(dhcp_start(netif) != ERR_OK)
447 rpp_debug_printf((const char *) "dhcp mem err\r\n");
452 rpp_debug_printf((const char *) "binding DHCP\r");
454 while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--))/*sys_check_timeouts()*/;
457 rpp_debug_printf((const char *) "dhcp binding timeout...\r\n");
459 #else /* LWIP_DHCP-LWIP_AUTOIP FIXME: there should be some kind of waiting till ip is assigned */
461 #endif /* STATIC_IP_ADDRESS-LWIP_DHCP-LWIP_AUTOIP */
463 rpp_eth_getIPDecimalStr(netif->ip_addr, ipString);
464 rpp_debug_printf((const char *) "Address: %s\r\n", ipString);
465 rpp_eth_getIPDecimalStr(netif->netmask, ipString);
466 rpp_debug_printf((const char *) "Netmask: %s\r\n", ipString);
467 rpp_eth_getIPDecimalStr(netif->gw, ipString);
468 rpp_debug_printf((const char *) "Gateway: %s\r\n", ipString);
473 rpp_debug_printf((const char *)"cable not connected\r\n");
474 retVal = PHY_LINK_DOWN;
476 #endif /* !PHY_LINK_MONITOR_INT */
477 /* ----- end - lwIP stuff ----- */
479 postInitialized = TRUE;
483 err_t rpp_eth_lwip_init(struct netif *netif)
485 #if LWIP_NETIF_HOSTNAME
486 /* Initialize interface hostname */
487 netif->hostname = "rpp";
488 #endif /* LWIP_NETIF_HOSTNAME */
490 uint32_t instNum = (uint32_t)netif->state;
491 /*netif->num = instNum; - auto-initiated when netif_add is called */
493 /* netif->state contained instNum, we replace it with corresponding hdkif */
494 struct hdkif *hdkif = &hdkif_data[instNum];
495 netif->state = hdkif;
497 netif->name[0] = IFNAME0;
498 netif->name[1] = IFNAME1;
501 hdkif->waitTicksForPHYAneg = TICKS_PHY_AUTONEG;
505 * Initialize the snmp variables and counters inside the struct netif.
506 * The last argument should be replaced with your link speed, in units
507 * of bits per second.
509 NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
511 /* We directly use etharp_output() here to save a function call.
512 * You can instead declare yo_SKIP_TO_HWur own function an call etharp_output()
513 * from it if you have to do some checks before sending (e.g. if link
516 netif->output = etharp_output;
517 netif->linkoutput = rpp_eth_send;
518 return rpp_eth_hw_init_postInit(netif);
521 #define INIT_ONLY_AFTER_RESET 1
522 err_t rpp_eth_hw_init(struct hdkif *hdkif)
528 /* Deactivate reset pin of PHY */
529 /* for hw reset of PHY, it is necessary that PIN_NAME_ETHRST is 1us logical low state, before putting it to logical high */
530 #if !INIT_ONLY_AFTER_RESET
532 uint8_t index = 80; /* Initially used to hw reset of PHY connected to GIO pin. This means 1us - for 80MHz clock. */
534 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. */
536 hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),0);
538 #endif /* !INIT_ONLY_AFTER_RESET */
539 /* we have pull-down resistor, so after reset, we only need to put ETHRST pin to log. high */
540 hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),1);
542 /* don't run link status change interrupt yet - there is not yet prepared all the stuff we need */
543 vim_mask_clr(LNKInterruptVectorNumber);
545 /* initializes EMAC control module and EMAC module */
546 EMACInit(hdkif->emac_ctrl_base, hdkif->emac_base);
547 /* initializes MDIO module (reset) */
548 MDIOInit(hdkif->mdio_base, 0x0, 0x0);
550 /* enable used receive channel if necessary */
553 /* try to read random register from defaultPhy to make MDIO fill alive bit for this one if it returned
554 ACK bit in msg response - this must be done, because MDIO has not set alive bit of PHY after that
555 short time after MDIOInit() */
556 MDIOPhyRegRead(hdkif->mdio_base, hdkif->phy_addr, PHY_BMSR, ®Content);
558 /* find first alive PHY - or use default if alive */
559 physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base);
560 if(!(physAlive & (1 << hdkif->phy_addr)))
562 #if FIND_FIRST_PHY_ALIVE
563 for(index = 0;index < NUM_OF_PHYs;index++) /* i..PHY tested */
565 if(physAlive && (1 << index))
567 hdkif->phy_addr = index;
572 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 */
573 physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base); /* get updated register */
574 if(physAlive && (1 << index))
576 hdkif->phy_addr = index;
584 rpp_debug_printf((const char *) "no phy found, phys: %d\r\n", physAlive);
590 rpp_debug_printf((const char *) "default phy not alive\r\n");
592 return DFLT_PHY_NOT_ALIVE;
596 /* start autonegotiation and check on completion later or when complete link register will be updated */
597 hdkif->phy_autoneg_start(hdkif->mdio_base, hdkif->phy_addr, PHY_100BASETXDUPL_m | PHY_100BASETX_m | PHY_10BASETDUPL_m | PHY_10BASET_m);
599 /* TODO: you can implement init of receive flow control somewhere here if desired - set RXBUFFERFLOWEN in MACCONTROL */
602 /* acknowledge EMAC control module RX and TX interrupts */
603 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
604 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
606 /* sets which channel will receive broadcasts */
607 EMACRxBroadCastEnable(hdkif->emac_base, CHANNEL);
608 /* 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 */
609 EMACRxPromiscEnable(hdkif->emac_base, CHANNEL);
610 /* enables unicast */
611 EMACRxUnicastSet(hdkif->emac_base, CHANNEL);
613 /* enable TX and RX interrupts in both EMAC module and EMAC control module */
614 EMACTxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
615 EMACRxIntPulseEnable(hdkif->emac_base, hdkif->emac_ctrl_base, 0, CHANNEL);
620 err_t rpp_eth_hw_init_postInit(struct netif *netif)
622 volatile unsigned int autonegFinishWait = 0x3FFFFFFF; /* 0x3FFFFFFF is for 80MHz aproximately 13s */
624 uint32_t num_bd, pbuf_cnt = 0;
625 volatile struct emac_tx_bd *curr_txbd, *last_txbd;
626 volatile struct emac_rx_bd *curr_rxbd, *last_rxbd;
631 struct hdkif *hdkif = (struct hdkif *) netif->state;
633 rxch = &(hdkif->rxch);
634 txch = &(hdkif->txch);
637 rpp_debug_printf((const char *) "autoneg started - check on cable if it's connected!\r\n");
642 * Initialize the Descriptor Memory For TX and RX
643 * Only Channel 0 is supported for both TX and RX
645 txch->free_head = ((volatile struct emac_tx_bd *) hdkif->emac_ctrl_ram);
646 txch->next_bd_to_process = txch->free_head;
647 txch->active_tail = NULL;
649 /* Set the number of descriptors for the channel */
650 num_bd = (SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_tx_bd); /* take half of CPPI ram for TX BDs */
652 curr_txbd = txch->free_head;
654 /* Initialize all the TX buffer Descriptors */
656 curr_txbd->next = curr_txbd + 1;
657 curr_txbd->flags_pktlen = 0;
658 last_txbd = curr_txbd;
659 curr_txbd = curr_txbd->next;
661 last_txbd->next = txch->free_head;
663 /* Initialize the descriptors for the RX channel */
664 rxch->active_head = (volatile struct emac_rx_bd*)(curr_txbd);
665 rxch->free_head = NULL;
666 rxch->freed_pbuf_len = 0;
667 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) */
668 curr_rxbd = rxch->active_head;
669 last_rxbd = curr_rxbd;
672 ** Allocate the pbufs for the maximum count permitted or till the
673 ** number of buffer desceriptors expire, which ever is earlier.
675 while(pbuf_cnt < MAX_RX_PBUF_ALLOC) {
676 p = pbuf_alloc(PBUF_RAW, PBUF_LEN_MAX, PBUF_POOL);
679 /* write the descriptors if there are enough numbers to hold the pbuf*/
680 if(((uint32_t)pbuf_clen(p)) <= num_bd) {
681 for(q = p; q != NULL; q = q->next) {
682 curr_rxbd->bufptr = (uint8_t *)(q->payload);
683 curr_rxbd->bufoff_len = q->len;
684 curr_rxbd->next = curr_rxbd + 1;
685 curr_rxbd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
689 last_rxbd = curr_rxbd;
690 curr_rxbd = curr_rxbd->next;
695 /* free the allocated pbuf if no free descriptors are left */
708 if(!pbuf_cnt)rpp_debug_printf((const char *) "no pbufs attached to rx buffer descriptors during init\n");
711 last_rxbd->next = NULL;
712 rxch->active_tail = last_rxbd;
714 num_bd = ( ((uint32_t)rxch->active_tail - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd) + 1 );
716 preparedRxPBUFs = filledRXbds = num_bd;
717 preparedRxPBUFChains = pbuf_cnt;
720 rpp_debug_printf((const char *) "%d pbuf chains allocated for %d rx buffer descriptors\n", pbuf_cnt, num_bd);
722 /* for flow control or QoS - there could be set an interrupt when we reach preset amount of receive descriptors remaining - see RXBUFFERFLOWEN */
723 /* EMACNumFreeBufSet(hdkif->emac_base, CHANNEL, num_bd); */ /* not used */
725 /* set header descriptor pointers - this shows EMAC which descriptor is beginning one for writing received frames/packets */
726 EMACRxHdrDescPtrWrite(hdkif->emac_base, (uint32_t)rxch->active_head, CHANNEL);
730 /* set length of MAC address */
731 netif->hwaddr_len = MAC_ADDR_LEN;
733 /* set MAC address */
734 for(regContent = 0; regContent < MAC_ADDR_LEN; regContent++) {
735 netif->hwaddr[regContent] = hdkif->mac_addr[(MAC_ADDR_LEN - 1) - regContent];
738 /* maximum transfer unit */
739 netif->mtu = MAX_TRANSFER_UNIT;
741 /* device capabilities */
742 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
743 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
745 /* lwIP stuff - end */
747 /* for flow control frames */
748 EMACMACSrcAddrSet(hdkif->emac_base, hdkif->mac_addr);
750 /* Be sure to program all eight MAC address registers -
751 * whether the receive channel is to be enabled or not.
753 for (regContent = 0; regContent < 8; regContent++) /* i..channel_number */
754 EMACMACAddrSet(hdkif->emac_base, regContent, hdkif->mac_addr, EMAC_MACADDR_NO_MATCH_NO_FILTER);
756 #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 */
757 /* wait for autonegotiation to be done or continue, when delay was reached */
759 uint32_t timeToWake = hdkif->waitTicksForPHYAneg + sys_jiffies();
760 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 */
762 while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && autonegFinishWait--); /* wait till aneg done */
766 if(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) != FALSE)
767 rpp_debug_printf((const char *) "aneg finished \r\n");
769 rpp_debug_printf((const char *) "aneg timeout \r\n");
772 /* provide informations retrieved from autoneg to EMAC module */
773 hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, ®Content);
774 if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) {
775 EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_FULL);
776 /* this is right place to implement transmit flow control if desired - set TXFLOWEN in MACCONTROL */
777 } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) {
778 EMACDuplexSet(hdkif->emac_base, EMAC_DUPLEX_HALF);
781 rpp_debug_printf((const char *) "Unknown duplex mode\r\n");
783 return UNKN_DUPLEX_MODE;
786 /* TODO: reorganize code for linkint handling and maybe add functions for it */
787 #else /* !PHY_LINK_MONITOR_INT */
788 /* set PHY number which is monitored for link changes in MDIO and enable interrupt */
789 HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) = ((hdkif->phy_addr && 0x1f) | MDIO_USERPHYSEL0_LINKINTENB);
791 /* enable MISC interrupt for link monitoring in EMAC controle module */
792 HWREG(hdkif->emac_ctrl_base + EMAC_CTRL_CnMISCEN(0)) |= EMAC_CTRL_MISC_LINKINT0ENB;
793 #endif /* !PHY_LINK_MONITOR_INT */
795 /* enable EMAC's Media Independent Interface TX and RX */
796 EMACMIIEnable(hdkif->emac_base);
797 /* enable EMAC transmit */
798 EMACTxEnable(hdkif->emac_base);
799 /* enable EMAC receive */
800 EMACRxEnable(hdkif->emac_base);
805 /********************************************** send and receive functions / ISRs **********************************************/
807 /* function to find out, whether LwIP does not mind more threads */
808 /* this one handles all interrupts comming */
810 void rpp_eth_driver(void *arg)
813 struct netif *netif = (struct netif *) arg;
814 struct hdkif *hdkif = (struct hdkif *) netif->state;
818 if (sys_arch_sem_wait(&(hdkif->goTX), 1) != SYS_ARCH_TIMEOUT){
819 SYS_ARCH_DECL_PROTECT(lev);
820 SYS_ARCH_PROTECT(lev);
821 rpp_eth_send_bd_handler(hdkif);
822 SYS_ARCH_UNPROTECT(lev);
823 vim_mask_set(TXinterruptVectorNumber);
826 if (sys_arch_sem_wait(&(hdkif->goRX), 1) != SYS_ARCH_TIMEOUT){
827 SYS_ARCH_DECL_PROTECT(lev);
828 SYS_ARCH_PROTECT(lev);
829 rpp_eth_recv_raw(netif);
830 SYS_ARCH_UNPROTECT(lev);
831 vim_mask_set(RXinterruptVectorNumber);
834 #if PHY_LINK_MONITOR_INT
835 if (sys_arch_sem_wait(&(hdkif->goLink), 1) != SYS_ARCH_TIMEOUT){
836 linkStatusChanged(netif);
837 vim_mask_set(LNKInterruptVectorNumber);
841 taskYIELD(); /* if there is no request to be handled let other tasks work */
846 err_t rpp_eth_send(struct netif * netif, struct pbuf *p)
848 err_t retVal = SUCCESS;
849 SYS_ARCH_DECL_PROTECT(lev);
852 * This entire function must run within a "critical section" to preserve
853 * the integrity of the transmit pbuf queue.
856 SYS_ARCH_PROTECT(lev);
858 /* adjust the packet length if less than minimum required */
859 if(p->tot_len < MIN_PKT_LEN) {
860 p->tot_len = MIN_PKT_LEN;
861 p->len = MIN_PKT_LEN;
865 * Bump the reference count on the pbuf to prevent it from being
866 * freed till we are done with it.
871 /* call the actual transmit function */
872 retVal = rpp_eth_send_raw(netif, p);
874 /* Return to prior interrupt state and return. */
875 SYS_ARCH_UNPROTECT(lev);
880 err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *p)
883 volatile struct emac_tx_bd *curr_bd, *active_head, *bd_end;
886 err_t retVal = SUCCESS;
888 hdkif = (struct hdkif *) netif->state;
889 txch = &(hdkif->txch);
893 preparedTxPBUFChains += pbuf_clen(p);
896 /* Get the buffer descriptor which is free to transmit */
897 curr_bd = txch->free_head;
899 active_head = curr_bd;
901 /* Update the total packet length */
902 curr_bd->flags_pktlen &= ~0xFFFF;
903 curr_bd->flags_pktlen |= p->tot_len;
905 /* Indicate the start of the packet */
906 curr_bd->flags_pktlen |= (EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_OWNER);
908 /* Copy pbuf information into TX buffer descriptors */
909 for(q = p; q != NULL; q = q->next) {
911 /* Intialize the buffer pointer and length */
912 curr_bd->bufptr = (uint8_t *)(q->payload);
913 curr_bd->bufoff_len = (q->len) & 0xFFFF;
916 curr_bd = curr_bd->next;
922 /* Indicate the end of the packet */
924 bd_end->flags_pktlen |= EMAC_DSC_FLAG_EOP;
930 txch->free_head = curr_bd;
932 /* For the first time, write the HDP with the filled bd */
933 if(txch->active_tail == NULL) {
934 EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), CHANNEL);
937 * Chain the bd's. If the DMA engine, already reached the end of the chain,
938 * the EOQ will be set. In that case, the HDP shall be written again.
941 curr_bd = txch->active_tail;
942 /* TODO: (This is a workaround) Wait for the EOQ bit is set */
943 while (EMAC_DSC_FLAG_EOQ != (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ)); /* XXX: it stucked here, when calling from recv interrupt - ICMP ping to the board running and nc -d */
944 /* TODO: (This is a workaround) Don't write to TXHDP0 until it turns to zero */
945 while (0 != *((u32_t *)0xFCF78600));
946 curr_bd->next = active_head;
947 if (EMAC_DSC_FLAG_EOQ == (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ)) {
948 /* Write the Header Descriptor Pointer and start DMA */
949 EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), 0);
950 curr_bd->flags_pktlen &= ~EMAC_DSC_FLAG_EOQ;
953 curr_bd = txch->active_tail;
954 curr_bd->next = active_head;*/ /* first chain new stuff to transmit */
955 /* Test if the EOQ bit is set, if it is, set TXnHDP */
956 /*if(EMAC_DSC_FLAG_EOQ == (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ))
958 /* Don't write to TX0HDP until it turns to zero - because EOQ was set, it should be zero already */
959 /*while (0 != *((uint32_t *) (hdkif->emac_base + EMAC_TXHDP(CHANNEL)) ));*/
960 /* Write the Header Descriptor Pointer and start DMA */
961 /*EMACTxHdrDescPtrWrite(hdkif->emac_base, (unsigned int)(active_head), CHANNEL);
962 curr_bd->flags_pktlen &= ~EMAC_DSC_FLAG_EOQ;
966 txch->active_tail = bd_end;
969 tx_bd_handled = FALSE;
970 beforeHandled.active_tail = txch->active_tail;
971 beforeHandled.free_head = txch->free_head;
972 beforeHandled.next_bd_to_process = txch->next_bd_to_process;
978 void rpp_eth_recv_raw(void *arg)
980 volatile struct emac_rx_bd *curr_bd, *processed_bd, *curr_tail, *last_bd;
981 volatile struct pbuf *pbuf, *q, *new_pbuf;
982 uint32_t ex_len, len_to_alloc;
984 struct netif *netif = (struct netif *) arg;
985 struct hdkif *hdkif = (struct hdkif *) netif->state;
988 rxch = &(hdkif->rxch);
991 #if !NO_SYS && !ONE_DRIVER_TASK
992 //SYS_ARCH_DECL_PROTECT(lev);
995 vim_mask_set(RXinterruptVectorNumber);
996 sys_arch_sem_wait(&(hdkif->goRX), 0);
997 //SYS_ARCH_PROTECT(lev);
1003 beforeRecv.active_head = rxch->active_head;
1004 beforeRecv.active_tail = rxch->active_tail;
1005 beforeRecv.free_head = rxch->free_head;
1006 beforeRecv.freed_pbuf_len = rxch->freed_pbuf_len;
1009 /* Get the bd which contains the earliest filled data */
1010 curr_bd = rxch->active_head;
1011 last_bd = rxch->active_tail;
1014 if(curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP != EMAC_DSC_FLAG_SOP)rpp_debug_printf((const char *) "ERR: Active head is not SOP!\n");
1018 * Process the descriptors as long as data is available
1019 * when the DMA is receiving data, SOP flag will be set
1021 while(curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP)
1025 /* Start processing once the packet is loaded */
1026 if((curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) != EMAC_DSC_FLAG_OWNER)
1028 if(rxch->free_head == NULL)
1030 /* this bd chain will be freed after processing */
1031 rxch->free_head = curr_bd;
1034 /* Get the total length of the packet. curr_bd points to the start
1037 tot_len = (curr_bd->flags_pktlen) & 0xFFFF;
1039 /* Get the start of the pbuf queue */
1043 /* Get the pbuf pointer which is associated with the current bd */
1044 pbuf = curr_bd->pbuf;
1046 /* If the earlier pbuf ended, update the chain */
1047 if(pbuf->next == NULL)
1050 preparedRxPBUFChains--;
1051 filledRxPBUFChains++;
1053 pbuf->next = (struct pbuf*)(curr_bd->next)->pbuf;
1056 len_to_alloc += pbuf->len;
1057 /* Update the len and tot_len fields for the pbuf in the chain*/
1058 pbuf->len = (curr_bd->bufoff_len) & 0xFFFF;
1059 pbuf->tot_len = tot_len - ex_len ;
1060 processed_bd = curr_bd;
1061 ex_len += pbuf->len;
1062 curr_bd = curr_bd->next;
1064 if(curr_bd == NULL)rpp_debug_printf((const char *) "rx curr_bd set to zero!\n");
1066 /* FIXME: curr_bd here could be NULL - a solution could be: we need to keep at least TCP_MSS bytes, so allocate at least that if not possible block */
1067 } while((processed_bd->flags_pktlen & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP);
1070 * Close the chain for this pbuf. A full packet is received in
1071 * this pbuf chain. Now this pbuf can be given to upper layers for
1072 * processing. The start of the pbuf chain is now 'q'.
1078 filledRXbds -= ((((uint32_t)curr_bd - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd)) + 1);
1079 filledRxPBUFs += pbuf_clen(pbuf);
1080 preparedRxPBUFs -= pbuf_clen(pbuf);
1083 /* Adjust the link statistics */
1084 LINK_STATS_INC(link.recv);
1086 /* Process the packet - this function is specified while adding netif using netif_add() function */
1087 if(netif->input((struct pbuf *)q, netif) != ERR_OK)
1089 /* Adjust the link statistics */
1090 LINK_STATS_INC(link.memerr);
1091 LINK_STATS_INC(link.drop);
1094 /* Acknowledge that this packet is processed */
1095 EMACRxCPWrite(hdkif->emac_base, CHANNEL, (unsigned int)processed_bd);
1099 rxch->active_head = curr_bd;
1103 rxch->active_head = processed_bd + 1; //todo:reconsider
1107 * The earlier pbuf chain is freed from the upper layer. So, we need to
1108 * allocate a new pbuf chain and update the descriptors with the pbuf info.
1109 * To support chaining, the total length freed by the upper layer is tracked.
1110 * Care should be taken even if the allocation fails.
1113 * now len_to_alloc will contain the length of the pbuf which was freed
1114 * from the upper layer
1116 rxch->freed_pbuf_len += len_to_alloc;
1117 /* FIXME: this does not work well */
1119 /* if there is not enough pbufs predefined, we need application to process them and return them back to pool -> YIELD */
1120 /* 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
1121 * from pool, then in *bd pointing to NULL might be such values (EMAC_DSC_FLAG_SOP == 1 &| EMAC_DSC_FLAG_OWNER == 0), that we
1122 * stay cycling around */
1126 new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL);
1128 if(new_pbuf != NULL)
1131 xSemaphoreTake(pbufFreed, 0);
1132 xSemaphoreTake(pbufFreed, portMAX_DELAY);
1136 /* Write the descriptors with the pbuf info till either of them expires */
1137 if(new_pbuf != NULL)
1139 curr_bd = rxch->free_head;
1141 for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next)
1143 curr_bd->bufptr = (uint8_t *)(q->payload);
1145 /* no support for buf_offset. RXBUFFEROFFSET register is 0 */
1146 curr_bd->bufoff_len = (q->len) & 0xFFFF;
1147 curr_bd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
1149 rxch->freed_pbuf_len -= q->len;
1154 curr_bd = curr_bd->next;
1158 * At this point either pbuf expired or no rxbd to allocate. If
1159 * there are no, enough rx bds to allocate all pbufs in the chain,
1160 * free the rest of the pbuf
1164 pbuf_free((struct pbuf *)q);
1167 curr_tail = rxch->active_tail;
1168 last_bd->next = NULL;
1170 curr_tail->next = rxch->free_head;
1173 * Check if the reception has ended. If the EOQ flag is set, the NULL
1174 * Pointer is taken by the DMA engine. So we need to write the RX HDP
1175 * with the next descriptor.
1177 if(curr_tail->flags_pktlen & EMAC_DSC_FLAG_EOQ)
1179 EMACRxHdrDescPtrWrite(hdkif->emac_base, (u32_t)(rxch->free_head), CHANNEL);
1182 rxch->free_head = curr_bd;
1183 rxch->active_tail = last_bd;
1186 curr_bd = rxch->active_head;
1188 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
1192 afterRecv.active_head = rxch->active_head;
1193 afterRecv.active_tail = rxch->active_tail;
1194 afterRecv.free_head = rxch->free_head;
1195 afterRecv.freed_pbuf_len = rxch->freed_pbuf_len;
1197 #if !NO_SYS && !ONE_DRIVER_TASK
1198 //SYS_ARCH_UNPROTECT(lev);
1203 void rpp_eth_send_bd_handler(void *arg)
1205 struct hdkif *hdkif = (struct hdkif *) arg;
1206 struct txch *txch = &(hdkif->txch);
1207 volatile struct emac_tx_bd *curr_bd, *next_bd_to_process;
1209 #if !NO_SYS && !ONE_DRIVER_TASK
1210 SYS_ARCH_DECL_PROTECT(lev);
1212 vim_mask_set(TXinterruptVectorNumber);
1213 sys_arch_sem_wait(&(hdkif->goTX), 0);
1214 SYS_ARCH_PROTECT(lev);
1217 next_bd_to_process = txch->next_bd_to_process;
1218 curr_bd = next_bd_to_process;
1220 /* Check for correct start of packet */
1221 while((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_SOP)
1224 /* Make sure that the transmission is over */
1225 while((curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) == EMAC_DSC_FLAG_OWNER); /* XXX: place where it stucks sometimes */
1227 /* Traverse till the end of packet is reached */
1228 while(((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP)
1230 curr_bd = curr_bd->next;
1232 if(!inCPPI((uint32_t)curr_bd))rpp_sci_printk((const char *) "tx handl traverse to EOP - bad bd->next ptr\n");
1236 next_bd_to_process->flags_pktlen &= ~(EMAC_DSC_FLAG_SOP);
1237 curr_bd->flags_pktlen &= ~(EMAC_DSC_FLAG_EOP);
1240 * If there are no more data transmitted, the next interrupt
1241 * shall happen with the pbuf associated with the free_head
1243 if(curr_bd->next == NULL)
1245 txch->next_bd_to_process = txch->free_head;
1249 txch->next_bd_to_process = curr_bd->next;
1252 /* Acknowledge the EMAC and free the corresponding pbuf */
1253 EMACTxCPWrite(hdkif->emac_base, CHANNEL, (uint32_t)curr_bd);
1255 pbuf_free((struct pbuf *)curr_bd->pbuf);
1257 LINK_STATS_INC(link.xmit);
1259 next_bd_to_process = txch->next_bd_to_process;
1260 curr_bd = next_bd_to_process;
1263 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
1266 tx_bd_handled = TRUE;
1267 afterHandled.active_tail = txch->active_tail;
1268 afterHandled.free_head = txch->free_head;
1269 afterHandled.next_bd_to_process = txch->next_bd_to_process;
1271 #if !NO_SYS && !ONE_DRIVER_TASK
1272 SYS_ARCH_UNPROTECT(lev);
1277 #if PHY_LINK_MONITOR_INT
1278 void linkStatusChanged(void *arg)
1280 struct netif *netif = (struct netif*) arg;
1281 struct hdkif *hdkif = (struct hdkif*) netif->state;
1282 uint8_t instNum = hdkif->inst_num;
1283 #if !NO_SYS && !ONE_DRIVER_TASK
1285 vim_mask_set(LNKInterruptVectorNumber);
1286 sys_arch_sem_wait(&(hdkif->goLink), 0);
1289 rpp_sci_printf((const char *) "link is %s\n",rpp_eth_phylinkstat(instNum)?"UP":"DOWN");
1290 /* do whatever necessary for link status change here */
1292 /* acknowledge MDIO module */
1293 HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) = MDIO_LINKINTMASKED_USERPHY0;
1294 HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) = MDIO_LINKINTMASKED_USERPHY0;
1296 /* acknowledge EMAC control module by writing appropriate key to MACEOIVECTOR */
1297 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
1298 #if !NO_SYS && !ONE_DRIVER_TASK
1302 #endif /* PHY_LINK_MONITOR_INT */
1304 void RxIntHandler(u32_t instNum)
1307 vim_mask_clr(RXinterruptVectorNumber);
1309 static portBASE_TYPE xHigherPriorityTaskWoken;
1310 xHigherPriorityTaskWoken = pdFALSE;
1312 /* 'Give' the semaphore to unblock the task. */
1313 xSemaphoreGiveFromISR(hdkif_data[instNum].goRX, NULL); // whenever there is time to process received packets, wake up task processing them
1315 if( xHigherPriorityTaskWoken == pdTRUE )
1318 /* Giving the semaphore unblocked a task, and the priority of the
1319 unblocked task is higher than or equal to the currently running task
1320 - force a context switch to ensure that the interrupt returns directly
1321 to the unblocked (higher priority) task.
1322 NOTE: The actual macro to use to force a context switch from an
1323 ISR is dependent on the port. This is the correct macro for the
1324 Open Watcom DOS port. Other ports may require different syntax.
1325 Refer to the examples provided for the port being used to determine
1326 the syntax required. */
1328 portSWITCH_CONTEXT();
1332 rpp_eth_recv_raw((void *) &hdkNetIF[instNum]);
1336 void TxIntHandler(u32_t instNum)
1339 vim_mask_clr(TXinterruptVectorNumber); /* see sys_startup.c */
1340 xSemaphoreGiveFromISR(hdkif_data[instNum].goTX, NULL);
1342 rpp_eth_send_bd_handler((void *) &hdkif_data[instNum]);
1346 #if PHY_LINK_MONITOR_INT
1347 boolean_t LinkIntHandler(void)
1349 uint8_t index = MAX_EMAC_INSTANCE, phyFound = FALSE;
1350 struct hdkif *hdkif;
1352 /* check each instance, whether this interrupt was meant for this function, if not return FALSE so other function may be tried */
1354 hdkif = &hdkif_data[--index];
1355 if( hdkif->phy_addr == (HWREG(hdkif->mdio_base + MDIO_USERPHYSEL0) & 0x1f) && (HWREG(hdkif->emac_base + EMAC_MACINVECTOR) & EMAC_MACINVECTOR_LINKINT0) )phyFound = TRUE;
1357 if(!phyFound)return FALSE;
1359 vim_mask_clr(LNKInterruptVectorNumber); /* see sys_startup.c */
1360 xSemaphoreGiveFromISR(hdkif->goLink, NULL);
1362 /* we handles here connection of cable after startup, not changes of linkstatus */
1363 /* do whatever necessary for link status change here */
1366 /* acknowledge MDIO module */
1367 HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) = MDIO_LINKINTMASKED_USERPHY0;
1368 HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) = MDIO_LINKINTMASKED_USERPHY0;
1370 /* acknowledge EMAC control module by writing appropriate key to MACEOIVECTOR */
1371 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
1377 #endif /* rppCONFIG_INCLUDE_ETH */