]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blob - rpp/src/rpp/eth.c
eth.c driver separated to more files
[pes-rpp/rpp-lib.git] / rpp / src / rpp / eth.c
1 /**
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
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.
15  *
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
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  *
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  */
32
33 /**
34  * Copyright (c) 2010 Texas Instruments Incorporated
35  *
36  * This file is dervied from the "ethernetif.c" skeleton Ethernet network
37  * interface driver for lwIP.
38  *
39  */
40 /* Copyright (C) 2013 Czech Technical University in Prague
41  *
42  * Authors:
43  *     - Carlos Jenkins <carlos@jenkins.co.cr>
44  *     - Rostislav Lisový
45  *     - Jan Doležal <pm.jenik@gmail.com>
46  *
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.
51  *
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.
56  *
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/>.
59  *
60  * File : eth.c
61  * Abstract:
62  *     Ethernet Communication RPP API implementation file. Using one PHY.
63  *
64  * References:
65  *     eth.h
66  *     RPP API documentation.
67  */
68
69 /* lwIP headers */
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 */
76 #include "lwip/def.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 */
82
83 #include "hal/hal.h"
84 #include "rpp/rpp.h"
85 #include "sys/sys.h" /* includes - sys/phy_dp83848h.h */
86 #include "drv/emac.h"
87 #include "os/os.h"
88 #include "types.h"
89
90
91 #if rppCONFIG_INCLUDE_ETH == 1
92
93 /* options */
94
95 /* Number of EMAC Instances */
96 #define MAX_EMAC_INSTANCE         1
97
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
101
102 /*
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
106  */
107 #define ONCE_LINK_SETUP            1
108
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 */
114
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
119
120 /* Define those to better describe the network interface. */
121 #define IFNAME0                   'e'
122 #define IFNAME1                   'n'
123 /* end options */
124
125 /* Defining interface for all the emac instances */
126 static struct hdkif hdkif_data[MAX_EMAC_INSTANCE];
127
128 /*
129 ** The lwIP network interface structure for the HDK Ethernet MAC.
130 */
131 static struct netif hdkNetIF[MAX_EMAC_INSTANCE];
132
133 /* rpp startup init indicator */
134 static boolean_t initialized = FALSE, postInitialized = FALSE;
135
136 /* free pbuf notification */
137 #if !NO_SYS
138 xSemaphoreHandle pbufFreed;
139 #endif
140
141 /**********************************************testing functions**********************************************/
142
143 uint32_t rpp_eth_phylinkstat(uint32_t instNum)
144 {
145         struct hdkif *hdkif = &hdkif_data[instNum];
146         return PHY_link_status_get(hdkif->mdio_base, hdkif->phy_addr, 1);
147 }
148
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)
153 {
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);
163         }
164         macStr[outindex] = '\0';
165 }
166
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)
169 {
170         snprintf((char *)ipStr, 16, "%d.%d.%d.%d",(ip.addr >> 24),((ip.addr >> 16) & 0xff),((ip.addr >> 8) & 0xff),(ip.addr & 0xff));
171 }
172
173 /* @param ip will be filled accroding to content of ipstr */
174 err_t rpp_eth_stringToIP(ip_addr_t * ip, uint8_t * ipstr)
175 {
176         uint8_t charProccessed, index = 0, dotindex = 0xff, tmp = 0, dots = 0, fldEdit = 0;
177         uint32_t ipaddr = 0;
178         for(charProccessed = ipstr[index]; (charProccessed >= '0' && charProccessed <= '9') || charProccessed == '.' ; charProccessed = ipstr[++index])
179         {
180                 if(charProccessed == '.')
181                 {
182                         if(++dotindex == index)
183                         {
184                                 dots = 0;
185                                 break;
186                         }
187                         dotindex = index;
188
189                         ipaddr = (ipaddr << 8) + tmp;
190
191                         dots++;
192                         if(dots > 3)break;
193
194                         tmp = 0;
195                         fldEdit = FALSE;
196                 }
197                 else
198                 {
199                         fldEdit = TRUE;
200                         tmp = tmp*10 + charProccessed - '0';
201                 }
202         }
203         if(dots != 3 || !fldEdit)
204         {
205                 /* if unsuccesful, don't modify previous content */
206                 return FAILURE;
207         }
208         ipaddr = (ipaddr << 8) + tmp;
209         ip->addr = ipaddr;
210         return SUCCESS;
211 }
212
213 /* returns number in range 0-65535 where 0 is error */
214 uint16_t rpp_eth_portStrToInt(uint8_t *string)
215 {
216         uint8_t index;
217         uint16_t portNO = 0;
218         for(index = 0;string[index] != '\0';index++)
219         {
220                 if(string[index] < '0' || string[index] > '9')
221                 {
222                         portNO = 0;
223                         break;
224                 }
225                 portNO = portNO * 10 + string[index] - '0';
226         }
227         return portNO;
228 }
229
230 struct netif *rpp_eth_get_netif(uint32_t instNum)
231 {
232         return &hdkNetIF[instNum];
233 }
234
235 /********************************************** forward declares **********************************************/
236
237 /*
238  * interface initializes
239  */
240 err_t rpp_eth_lwip_init(struct netif *netif);
241
242 /*
243  * Initializes hw such as PHY, MDIO, EMAC, EMAC control module
244  *
245  * @return SUCCESS if initialization successful.\n
246  *         FAILURE if initialization not successful.
247  */
248 err_t rpp_eth_hw_init(struct hdkif *hdkif);
249
250 /*
251  * Initializes hw, after lwIP was initialized and
252  * OS was initialized in case OS is used.
253  */
254 err_t rpp_eth_hw_init_postInit(struct netif *netif);
255
256 #if ONE_DRIVER_TASK
257 /*
258  * Task which handles driver's stuff
259  */
260 void rpp_eth_driver(void *arg);
261 #endif
262
263 #if PHY_LINK_MONITOR_INT
264 /*
265  * function which handles changes of link status
266  */
267 void linkStatusChanged(void *arg);
268 #endif
269
270 /********************************************** utility functions **********************************************/
271
272 /*
273 * Function to set the MAC address to the interface
274 * @param   inst_num the instance number
275 *
276 * @note    mac_addr[0] is considered MSB
277 */
278 void
279 hdkif_macaddrset(u32_t inst_num, u8_t *mac_addr) {
280   struct hdkif *hdkif;
281   u32_t temp;
282
283   hdkif = &hdkif_data[inst_num];
284
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];
288   }
289 #ifdef DEBUG
290   uint8_t macStr[18];
291   rpp_eth_get_macAddrStr(inst_num, macStr);
292   rpp_debug_printf((const char *) "Setting MAC... %s\r\n", macStr);
293 #endif
294 }
295
296 /**
297 * Function to setup the instance parameters inside the interface
298 * @param   hdkif
299 * @return  none.
300 */
301 static void
302 hdkif_inst_config(struct hdkif *hdkif) {
303   if(hdkif->inst_num == 0)
304   {
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;
314   }
315 }
316
317 /********************************************** initializing functions **********************************************/
318
319 int8_t rpp_eth_init()
320 {
321     uint8_t instNum;
322         int8_t retVal = SUCCESS;
323     if(initialized) {
324         return FAILURE;
325     }
326
327     /* config of EMAC instances and other stuff */
328     for(instNum = 0; instNum < MAX_EMAC_INSTANCE; instNum++)
329     {
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;
333     }
334
335     /* when one of instances was not initialized correctly return FAILURE without setting initialized variable to TRUE */
336     if(retVal)return FAILURE;
337
338 #if NO_SYS
339
340 #else /* NO_SYS */
341
342 #endif /* NO_SYS */
343
344     initialized = TRUE;
345
346     return retVal;
347 }
348
349 int8_t rpp_eth_init_postInit(uint32_t instNum, uint8_t *macArray)
350 {
351     if(postInitialized) {
352         return FAILURE;
353     }
354     int8_t retVal = SUCCESS;
355     struct netif *netif = &hdkNetIF[instNum];
356     u8_t mac_addr[MAC_ADDR_LEN] = RPP_MAC_ADDR;
357 #ifdef DEBUG
358     uint8_t ipString[16];
359 #endif
360
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;
366
367     if(macArray == NULL)
368     {
369         macArray = mac_addr; /* use default MAC */
370     }
371     hdkif_macaddrset(instNum, macArray);
372
373     struct hdkif *hdkif;
374 #if NO_SYS
375     lwip_init();
376 #else /* NO_SYS */
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 */
379 #endif /* NO_SYS */
380
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 */
386     ip_addr.addr = 0;
387     net_mask.addr = 0;
388     gw_addr.addr = 0;
389 #endif /* STATIC_IP_ADDRESS */
390
391     /* init and add new netif */
392     /* add new network interface to lwIP list of ifaces and initialize netif with specific function */
393 #if NO_SYS
394     if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, ethernet_input) == NULL )
395 #else /* NO_SYS */
396     if( netif_add(netif, &ip_addr, &net_mask, &gw_addr, (void *) instNum, rpp_eth_lwip_init, tcpip_input) == NULL )
397 #endif /* NO_SYS */
398     {
399         return NETIF_ADD_ERR;
400     }
401
402     netif_set_default(netif);
403
404     hdkif = (struct hdkif *) netif->state;
405 #if !NO_SYS
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);
413 #endif
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.");
418         }*/
419 #if ONE_DRIVER_TASK
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 ----- */
433 #endif /* !NO_SYS */
434     vim_mask_set(LNKInterruptVectorNumber);
435
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))
439     {
440         rpp_debug_printf((const char *)"cable connected ... setting IP params\r\n");
441 #if STATIC_IP_ADDRESS
442         netif_set_up(netif);
443 #elif LWIP_DHCP /* STATIC_IP_ADDRESS-LWIP_DHCP */
444         if(dhcp_start(netif) != ERR_OK)
445         {
446 #ifdef DEBUG
447                 rpp_debug_printf((const char *) "dhcp mem err\r\n");
448 #endif
449                 return DHCP_MEM_ERR;
450         }
451 #ifdef DEBUG
452         rpp_debug_printf((const char *) "binding DHCP\r");
453 #endif
454         while((netif->dhcp->state != DHCP_BOUND) && (dhcpBindWait--))/*sys_check_timeouts()*/;
455 #ifdef DEBUG
456         if(!dhcpBindWait)
457                 rpp_debug_printf((const char *) "dhcp binding timeout...\r\n");
458 #endif
459 #else /* LWIP_DHCP-LWIP_AUTOIP FIXME: there should be some kind of waiting till ip is assigned */
460         autoip_start(netif);
461 #endif /* STATIC_IP_ADDRESS-LWIP_DHCP-LWIP_AUTOIP */
462 #ifdef DEBUG
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);
469 #endif
470     }
471     else
472     {
473         rpp_debug_printf((const char *)"cable not connected\r\n");
474         retVal = PHY_LINK_DOWN;
475     }
476 #endif /* !PHY_LINK_MONITOR_INT */
477     /* ----- end - lwIP stuff ----- */
478
479     postInitialized = TRUE;
480         return retVal;
481 }
482
483 err_t rpp_eth_lwip_init(struct netif *netif)
484 {
485 #if LWIP_NETIF_HOSTNAME
486     /* Initialize interface hostname */
487     netif->hostname = "rpp";
488 #endif /* LWIP_NETIF_HOSTNAME */
489
490     uint32_t instNum = (uint32_t)netif->state;
491     /*netif->num = instNum; - auto-initiated when netif_add is called */
492
493     /* netif->state contained instNum, we replace it with corresponding hdkif */
494     struct hdkif *hdkif = &hdkif_data[instNum];
495     netif->state = hdkif;
496
497     netif->name[0] = IFNAME0;
498     netif->name[1] = IFNAME1;
499
500 #if !NO_SYS
501     hdkif->waitTicksForPHYAneg = TICKS_PHY_AUTONEG;
502 #endif
503
504     /*
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.
508     */
509     NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
510
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
514      * is available...)
515      */
516     netif->output = etharp_output;
517     netif->linkoutput = rpp_eth_send;
518     return rpp_eth_hw_init_postInit(netif);
519 }
520
521 #define INIT_ONLY_AFTER_RESET 1
522 err_t rpp_eth_hw_init(struct hdkif *hdkif)
523 {
524         uint8_t index;
525     uint16_t regContent;
526     uint32_t physAlive;
527
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
531 #if NO_SYS
532         uint8_t index = 80; /* Initially used to hw reset of PHY connected to GIO pin. This means 1us - for 80MHz clock. */
533 #else /* NO_SYS */
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. */
535 #endif /* NO_SYS */
536     hal_gpio_pin_set_value(*hal_gpio_pin_get_dsc(PIN_NAME_ETHRST,-1),0);
537     while(index--);
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);
541
542     /* don't run link status change interrupt yet - there is not yet prepared all the stuff we need */
543     vim_mask_clr(LNKInterruptVectorNumber);
544
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);
549
550     /* enable used receive channel if necessary */
551
552
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, &regContent);
557
558     /* find first alive PHY - or use default if alive */
559     physAlive = MDIOPhyAliveStatusGet(hdkif->mdio_base);
560     if(!(physAlive & (1 << hdkif->phy_addr)))
561     {
562 #if FIND_FIRST_PHY_ALIVE
563         for(index = 0;index < NUM_OF_PHYs;index++) /* i..PHY tested */
564         {
565             if(physAlive && (1 << index))
566             {
567                 hdkif->phy_addr = index;
568                 break;
569             }
570             else
571             {
572                 MDIOPhyRegRead(hdkif->mdio_base, index, PHY_BMCR, &regContent); /* 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))
575                 {
576                     hdkif->phy_addr = index;
577                     break;
578                 }
579             }
580         }
581         if(!physAlive)
582         {
583 #ifdef DEBUG
584             rpp_debug_printf((const char *) "no phy found, phys: %d\r\n", physAlive);
585 #endif
586                 return NO_PHY_ALIVE;
587         }
588 #else
589 #ifdef DEBUG
590         rpp_debug_printf((const char *) "default phy not alive\r\n");
591 #endif
592         return DFLT_PHY_NOT_ALIVE;
593 #endif
594     }
595
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);
598
599     /* TODO: you can implement init of receive flow control somewhere here if desired - set RXBUFFERFLOWEN in MACCONTROL */
600
601
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);
605
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);
612
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);
616
617         return SUCCESS;
618 }
619
620 err_t rpp_eth_hw_init_postInit(struct netif *netif)
621 {
622         volatile unsigned int autonegFinishWait = 0x3FFFFFFF; /* 0x3FFFFFFF is for 80MHz aproximately 13s */
623     uint16_t regContent;
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;
627     struct pbuf *p, *q;
628     struct rxch *rxch;
629     struct txch *txch;
630
631     struct hdkif *hdkif = (struct hdkif *) netif->state;
632
633     rxch = &(hdkif->rxch);
634     txch = &(hdkif->txch);
635
636 #ifdef DEBUG
637     rpp_debug_printf((const char *) "autoneg started - check on cable if it's connected!\r\n");
638 #endif
639
640
641         /*
642         * Initialize the Descriptor Memory For TX and RX
643         * Only Channel 0 is supported for both TX and RX
644         */
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;
648
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 */
651
652         curr_txbd = txch->free_head;
653
654         /* Initialize all the TX buffer Descriptors */
655         while(num_bd--) {
656             curr_txbd->next = curr_txbd + 1;
657             curr_txbd->flags_pktlen = 0;
658             last_txbd = curr_txbd;
659             curr_txbd = curr_txbd->next;
660         }
661         last_txbd->next = txch->free_head;
662
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;
670
671         /*
672         ** Allocate the pbufs for the maximum count permitted or till the
673         ** number of buffer desceriptors expire, which ever is earlier.
674         */
675         while(pbuf_cnt < MAX_RX_PBUF_ALLOC) {
676             p = pbuf_alloc(PBUF_RAW, PBUF_LEN_MAX, PBUF_POOL);
677
678             if(p != NULL) {
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;
686
687                         /* Save the pbuf */
688                         curr_rxbd->pbuf = q;
689                         last_rxbd = curr_rxbd;
690                         curr_rxbd = curr_rxbd->next;
691                         num_bd--;
692                     }
693                 }
694
695                 /* free the allocated pbuf if no free descriptors are left */
696                 else {
697                     pbuf_free(p);
698                     break;
699                 }
700             }
701             else {
702                 break;
703             }
704             pbuf_cnt++;
705         }
706
707 #ifdef DEBUG
708         if(!pbuf_cnt)rpp_debug_printf((const char *) "no pbufs attached to rx buffer descriptors during init\n");
709 #endif
710
711         last_rxbd->next = NULL;
712         rxch->active_tail = last_rxbd;
713
714         num_bd = ( ((uint32_t)rxch->active_tail - (uint32_t)rxch->active_head) / sizeof(struct emac_rx_bd) + 1 );
715 #if RPP_ETH_STATS
716         preparedRxPBUFs = filledRXbds = num_bd;
717         preparedRxPBUFChains = pbuf_cnt;
718 #endif
719 #ifdef DEBUG
720         rpp_debug_printf((const char *) "%d pbuf chains allocated for %d rx buffer descriptors\n", pbuf_cnt, num_bd);
721 #endif
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 */
724
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);
727
728         /* lwIP stuff */
729
730         /* set length of MAC address */
731         netif->hwaddr_len = MAC_ADDR_LEN;
732
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];
736         }
737
738         /* maximum transfer unit */
739         netif->mtu = MAX_TRANSFER_UNIT;
740
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;
744
745         /* lwIP stuff - end */
746
747     /* for flow control frames */
748     EMACMACSrcAddrSet(hdkif->emac_base, hdkif->mac_addr);
749
750     /*  Be sure to program all eight MAC address registers -
751      *  whether the receive channel is to be enabled or not.
752      */
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);
755
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 */
758 #if !NO_SYS
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 */
761 #else
762     while(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) == FALSE && autonegFinishWait--); /* wait till aneg done */
763 #endif
764
765 #ifdef DEBUG
766     if(hdkif->phy_autoneg_is_done(hdkif->mdio_base, hdkif->phy_addr) != FALSE)
767         rpp_debug_printf((const char *) "aneg finished \r\n");
768     else
769         rpp_debug_printf((const char *) "aneg timeout \r\n");
770 #endif
771
772     /* provide informations retrieved from autoneg to EMAC module */
773     hdkif->phy_partnerability(hdkif->mdio_base, hdkif->phy_addr, &regContent);
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);
779     } else {
780 #ifdef DEBUG
781         rpp_debug_printf((const char *) "Unknown duplex mode\r\n");
782 #endif
783         return UNKN_DUPLEX_MODE;
784     }
785
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);
790
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 */
794
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);
801
802         return SUCCESS;
803 }
804
805 /********************************************** send and receive functions / ISRs **********************************************/
806
807 /* function to find out, whether LwIP does not mind more threads */
808 /* this one handles all interrupts comming */
809 #if ONE_DRIVER_TASK
810 void rpp_eth_driver(void *arg)
811 {
812         boolean_t active;
813         struct netif *netif = (struct netif *) arg;
814         struct hdkif *hdkif = (struct hdkif *) netif->state;
815         for(;;)
816         {
817         active = FALSE;
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);
824                 active = TRUE;
825                 }
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);
832                 active = TRUE;
833                 }
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);
838         }
839 #endif
840         if(active)continue;
841         taskYIELD(); /* if there is no request to be handled let other tasks work */
842         }
843 }
844 #endif
845
846 err_t rpp_eth_send(struct netif * netif, struct pbuf *p)
847 {
848         err_t retVal = SUCCESS;
849         SYS_ARCH_DECL_PROTECT(lev);
850
851         /**
852          * This entire function must run within a "critical section" to preserve
853          * the integrity of the transmit pbuf queue.
854          *
855          */
856         SYS_ARCH_PROTECT(lev);
857
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;
862         }
863
864         /**
865          * Bump the reference count on the pbuf to prevent it from being
866          * freed till we are done with it.
867          *
868          */
869         pbuf_ref(p);
870
871         /* call the actual transmit function */
872         retVal = rpp_eth_send_raw(netif, p);
873
874         /* Return to prior interrupt state and return. */
875         SYS_ARCH_UNPROTECT(lev);
876
877         return retVal;
878 }
879
880 err_t rpp_eth_send_raw(struct netif *netif, struct pbuf *p)
881 {
882         struct pbuf *q;
883         volatile struct emac_tx_bd *curr_bd, *active_head, *bd_end;
884         struct hdkif *hdkif;
885         struct txch *txch;
886         err_t retVal = SUCCESS;
887
888     hdkif = (struct hdkif *) netif->state;
889         txch = &(hdkif->txch);
890
891 #if RPP_ETH_STATS
892         preparedTxPBUFs++;
893         preparedTxPBUFChains += pbuf_clen(p);
894 #endif
895
896         /* Get the buffer descriptor which is free to transmit */
897         curr_bd = txch->free_head;
898
899         active_head = curr_bd;
900
901         /* Update the total packet length */
902         curr_bd->flags_pktlen &= ~0xFFFF;
903         curr_bd->flags_pktlen |= p->tot_len;
904
905         /* Indicate the start of the packet */
906         curr_bd->flags_pktlen |= (EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_OWNER);
907
908         /* Copy pbuf information into TX buffer descriptors */
909         for(q = p; q != NULL; q = q->next) {
910
911             /* Intialize the buffer pointer and length */
912             curr_bd->bufptr = (uint8_t *)(q->payload);
913             curr_bd->bufoff_len = (q->len) & 0xFFFF;
914             bd_end = curr_bd;
915             curr_bd->pbuf = p;
916             curr_bd = curr_bd->next;
917 #if RPP_ETH_STATS
918             filledTXbds++;
919 #endif
920         }
921
922         /* Indicate the end of the packet */
923         bd_end->next = NULL;
924         bd_end->flags_pktlen |= EMAC_DSC_FLAG_EOP;
925
926 #if RPP_ETH_STATS
927         filledTXPKTs++;
928 #endif
929
930         txch->free_head = curr_bd;
931
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);
935         }
936         /*
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.
939          */
940         else {
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;
951             }
952             /*
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))
957             {*/
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;
963             }*/
964         }
965
966         txch->active_tail = bd_end;
967
968 #if RPP_ETH_STATS
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;
973 #endif
974
975         return retVal;
976 }
977
978 void rpp_eth_recv_raw(void *arg)
979 {
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;
983     uint16_t tot_len;
984         struct netif *netif = (struct netif *) arg;
985         struct hdkif *hdkif = (struct hdkif *) netif->state;
986         struct rxch *rxch;
987
988         rxch = &(hdkif->rxch);
989
990
991 #if !NO_SYS && !ONE_DRIVER_TASK
992         //SYS_ARCH_DECL_PROTECT(lev);
993     for(;;)
994     {
995         vim_mask_set(RXinterruptVectorNumber);
996         sys_arch_sem_wait(&(hdkif->goRX), 0);
997         //SYS_ARCH_PROTECT(lev);
998 #endif
999
1000
1001 #if RPP_ETH_STATS
1002         received = FALSE;
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;
1007 #endif
1008
1009             /* Get the bd which contains the earliest filled data */
1010             curr_bd = rxch->active_head;
1011             last_bd = rxch->active_tail;
1012
1013 #ifdef DEBUG
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");
1015 #endif
1016
1017             /**
1018              * Process the descriptors as long as data is available
1019              * when the DMA is receiving data, SOP flag will be set
1020              */
1021             while(curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP)
1022         {
1023                 ex_len = 0;
1024                 len_to_alloc = 0;
1025                 /* Start processing once the packet is loaded */
1026                 if((curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) != EMAC_DSC_FLAG_OWNER)
1027             {
1028                         if(rxch->free_head == NULL)
1029                         {
1030                                 /* this bd chain will be freed after processing */
1031                             rxch->free_head = curr_bd;
1032                         }
1033
1034                         /* Get the total length of the packet. curr_bd points to the start
1035                      * of the packet.
1036                      */
1037                     tot_len = (curr_bd->flags_pktlen) & 0xFFFF;
1038
1039                     /* Get the start of the pbuf queue */
1040                     q = curr_bd->pbuf;
1041
1042                     do {
1043                         /* Get the pbuf pointer which is associated with the current bd */
1044                         pbuf = curr_bd->pbuf;
1045
1046                         /* If the earlier pbuf ended, update the chain */
1047                         if(pbuf->next == NULL)
1048                         {
1049 #if RPP_ETH_STATS
1050                                 preparedRxPBUFChains--;
1051                                 filledRxPBUFChains++;
1052 #endif
1053                             pbuf->next = (struct pbuf*)(curr_bd->next)->pbuf;
1054                         }
1055
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;
1063 #ifdef DEBUG
1064                         if(curr_bd == NULL)rpp_debug_printf((const char *) "rx curr_bd set to zero!\n");
1065 #endif
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);
1068
1069                     /**
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'.
1073                     */
1074                     pbuf->next = NULL;
1075
1076 #if RPP_ETH_STATS
1077                     handledRXPKTs++;
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);
1081 #endif
1082
1083                     /* Adjust the link statistics */
1084                     LINK_STATS_INC(link.recv);
1085
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)
1088                     {
1089                         /* Adjust the link statistics */
1090                         LINK_STATS_INC(link.memerr);
1091                         LINK_STATS_INC(link.drop);
1092                     }
1093
1094                     /* Acknowledge that this packet is processed */
1095                     EMACRxCPWrite(hdkif->emac_base, CHANNEL, (unsigned int)processed_bd);
1096
1097                     if(curr_bd != NULL)
1098                     {
1099                         rxch->active_head = curr_bd;
1100                     }
1101                     else
1102                     {
1103                         rxch->active_head = processed_bd + 1; //todo:reconsider
1104                     }
1105
1106                     /**
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.
1111                      */
1112                     /**
1113                      * now len_to_alloc will contain the length of the pbuf which was freed
1114                      * from the upper layer
1115                      */
1116                     rxch->freed_pbuf_len += len_to_alloc;
1117                     /* FIXME: this does not work well */
1118 #if !NO_SYS
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 */
1123                     do
1124                     {
1125 #endif
1126                             new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL);
1127 #if !NO_SYS
1128                             if(new_pbuf != NULL)
1129                                 break;
1130                             else
1131                                 xSemaphoreTake(pbufFreed, 0);
1132                                 xSemaphoreTake(pbufFreed, portMAX_DELAY);
1133                     }while(1);
1134 #endif
1135
1136                     /* Write the descriptors with the pbuf info till either of them expires */
1137                     if(new_pbuf != NULL)
1138                     {
1139                         curr_bd = rxch->free_head;
1140
1141                         for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next)
1142                         {
1143                             curr_bd->bufptr = (uint8_t *)(q->payload);
1144
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;
1148
1149                             rxch->freed_pbuf_len -= q->len;
1150
1151                             /* Save the pbuf */
1152                             curr_bd->pbuf = q;
1153                             last_bd = curr_bd;
1154                             curr_bd = curr_bd->next;
1155                         }
1156
1157                         /**
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
1161                          */
1162                         if(q != NULL)
1163                         {
1164                             pbuf_free((struct pbuf *)q);
1165                         }
1166
1167                         curr_tail = rxch->active_tail;
1168                         last_bd->next = NULL;
1169
1170                         curr_tail->next = rxch->free_head;
1171
1172                         /**
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.
1176                          */
1177                         if(curr_tail->flags_pktlen & EMAC_DSC_FLAG_EOQ)
1178                         {
1179                             EMACRxHdrDescPtrWrite(hdkif->emac_base, (u32_t)(rxch->free_head), CHANNEL);
1180                         }
1181
1182                         rxch->free_head  = curr_bd;
1183                         rxch->active_tail = last_bd;
1184                     }
1185             }
1186                 curr_bd = rxch->active_head;
1187             }
1188                 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX);
1189
1190 #if RPP_ETH_STATS
1191         received = TRUE;
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;
1196 #endif
1197 #if !NO_SYS && !ONE_DRIVER_TASK
1198                 //SYS_ARCH_UNPROTECT(lev);
1199     }
1200 #endif
1201 }
1202
1203 void rpp_eth_send_bd_handler(void *arg)
1204 {
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;
1208
1209 #if !NO_SYS && !ONE_DRIVER_TASK
1210         SYS_ARCH_DECL_PROTECT(lev);
1211         for(;;){
1212         vim_mask_set(TXinterruptVectorNumber);
1213         sys_arch_sem_wait(&(hdkif->goTX), 0);
1214         SYS_ARCH_PROTECT(lev);
1215 #else
1216 #endif
1217             next_bd_to_process = txch->next_bd_to_process;
1218             curr_bd = next_bd_to_process;
1219
1220             /* Check for correct start of packet */
1221             while((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_SOP)
1222             {
1223
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 */
1226
1227                 /* Traverse till the end of packet is reached */
1228                 while(((curr_bd->flags_pktlen) & EMAC_DSC_FLAG_EOP) != EMAC_DSC_FLAG_EOP)
1229                 {
1230                     curr_bd = curr_bd->next;
1231 #ifdef DEBUG
1232                     if(!inCPPI((uint32_t)curr_bd))rpp_sci_printk((const char *) "tx handl traverse to EOP - bad bd->next ptr\n");
1233 #endif
1234                 }
1235
1236                 next_bd_to_process->flags_pktlen &= ~(EMAC_DSC_FLAG_SOP);
1237                 curr_bd->flags_pktlen &= ~(EMAC_DSC_FLAG_EOP);
1238
1239                 /**
1240                  * If there are no more data transmitted, the next interrupt
1241                  * shall happen with the pbuf associated with the free_head
1242                  */
1243                 if(curr_bd->next == NULL)
1244                 {
1245                     txch->next_bd_to_process = txch->free_head;
1246                 }
1247                 else
1248                 {
1249                     txch->next_bd_to_process = curr_bd->next;
1250                 }
1251
1252                 /* Acknowledge the EMAC and free the corresponding pbuf */
1253                 EMACTxCPWrite(hdkif->emac_base, CHANNEL, (uint32_t)curr_bd);
1254
1255                 pbuf_free((struct pbuf *)curr_bd->pbuf);
1256
1257                 LINK_STATS_INC(link.xmit);
1258
1259                 next_bd_to_process = txch->next_bd_to_process;
1260                 curr_bd = next_bd_to_process;
1261                 }
1262
1263                 EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX);
1264
1265 #if RPP_ETH_STATS
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;
1270 #endif
1271 #if !NO_SYS && !ONE_DRIVER_TASK
1272                 SYS_ARCH_UNPROTECT(lev);
1273         }
1274 #endif
1275 }
1276
1277 #if PHY_LINK_MONITOR_INT
1278 void linkStatusChanged(void *arg)
1279 {
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
1284         for(;;){
1285         vim_mask_set(LNKInterruptVectorNumber);
1286         sys_arch_sem_wait(&(hdkif->goLink), 0);
1287 #else
1288 #endif
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 */
1291
1292                 /* acknowledge MDIO module */
1293                 HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) = MDIO_LINKINTMASKED_USERPHY0;
1294                 HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) = MDIO_LINKINTMASKED_USERPHY0;
1295
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
1299     }
1300 #endif
1301 }
1302 #endif /* PHY_LINK_MONITOR_INT */
1303
1304 void RxIntHandler(u32_t instNum)
1305 {
1306 #if !NO_SYS
1307         vim_mask_clr(RXinterruptVectorNumber);
1308         /*
1309         static portBASE_TYPE xHigherPriorityTaskWoken;
1310         xHigherPriorityTaskWoken = pdFALSE;
1311         */
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
1314         /*
1315     if( xHigherPriorityTaskWoken == pdTRUE )
1316     {
1317     */
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. */
1327         /*
1328     portSWITCH_CONTEXT();
1329     }
1330         */
1331 #else
1332         rpp_eth_recv_raw((void *) &hdkNetIF[instNum]);
1333 #endif
1334 }
1335
1336 void TxIntHandler(u32_t instNum)
1337 {
1338 #if !NO_SYS
1339         vim_mask_clr(TXinterruptVectorNumber); /* see sys_startup.c */
1340         xSemaphoreGiveFromISR(hdkif_data[instNum].goTX, NULL);
1341 #else
1342         rpp_eth_send_bd_handler((void *) &hdkif_data[instNum]);
1343 #endif
1344 }
1345
1346 #if PHY_LINK_MONITOR_INT
1347 boolean_t LinkIntHandler(void)
1348 {
1349         uint8_t index = MAX_EMAC_INSTANCE, phyFound = FALSE;
1350         struct hdkif *hdkif;
1351
1352         /* check each instance, whether this interrupt was meant for this function, if not return FALSE so other function may be tried */
1353         while(index){
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;
1356         }
1357     if(!phyFound)return FALSE;
1358 #if !NO_SYS
1359     vim_mask_clr(LNKInterruptVectorNumber); /* see sys_startup.c */
1360     xSemaphoreGiveFromISR(hdkif->goLink, NULL);
1361 #else
1362     /* we handles here connection of cable after startup, not changes of linkstatus */
1363     /* do whatever necessary for link status change here */
1364
1365
1366         /* acknowledge MDIO module */
1367         HWREG(hdkif->mdio_base + MDIO_LINKINTRAW) = MDIO_LINKINTMASKED_USERPHY0;
1368         HWREG(hdkif->mdio_base + MDIO_LINKINTMASKED) = MDIO_LINKINTMASKED_USERPHY0;
1369
1370         /* acknowledge EMAC control module by writing appropriate key to MACEOIVECTOR */
1371         EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_MISC);
1372 #endif
1373         return TRUE;
1374 }
1375 #endif
1376
1377 #endif /* rppCONFIG_INCLUDE_ETH */