source: edk_user_repository/WARP/sw_services/WARPxilnet_v3_01_a/src/xilnet_eth.c

Last change on this file was 1929, checked in by murphpo, 11 years ago

Adding updated WARPxilnet, required for WARPLab 7 ref design

File size: 11.0 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2004 Xilinx, Inc.  All rights reserved.
3//
4// Xilinx, Inc.
5// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
6// COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
7// ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
8// STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
9// IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
10// FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
11// XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
12// THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
13// ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
14// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS FOR A PARTICULAR PURPOSE.
16//
17// File   : eth.c
18// Date   : 2002, March 20.
19// Author : Sathya Thammanur
20// Company: Xilinx
21// Group  : Emerging Software Technologies
22//
23// Summary:
24// Ethernet layer specific functions
25//
26// $Id: eth.c,v 1.2.8.6 2005/11/15 23:41:10 salindac Exp $
27//
28////////////////////////////////////////////////////////////////////////////////
29
30////////////////////////////////////////////////////////////////////////////////
31// see copyright.txt for Rice University/Mango Communications modifications
32////////////////////////////////////////////////////////////////////////////////
33
34#include <string.h>
35#include <xilnet_config.h>
36#include <xilnet_xilsock.h>
37#ifdef _CONFIG_TEMAC_
38#include "xlltemac.h"
39#include "xllfifo.h"
40#include "xdmacentral.h"
41#include "xdmacentral_l.h"
42#endif
43
44#ifdef _CONFIG_AXI_ETHERNET_FIFO
45#include "xaxiethernet.h"   /* defines Axi Ethernet APIs */
46#include "xllfifo.h"
47#endif
48#include "xio.h"
49#include "stdio.h"
50struct xilnet_hw_addr_table xilnet_hw_tbl[HW_ADDR_TBL_ENTRIES];
51unsigned char ishwaddrinit = 0;
52static unsigned long long curr_age = 0;
53
54
55/*
56 * initialize xilnet hardware address
57 */
58void xilnet_eth_init_hw_addr(unsigned char* addr) {
59   int k = 0;
60   int j;
61   int sum = 0;
62   int val = 0;
63   
64   for (j = 0; j < 5; j++) {
65   
66      // parse input for colon separated hw address
67      while(addr[k] != ':') {
68         if (addr[k] >= 'a' && addr[k] <= 'f') 
69            val = addr[k] - 'a' + 10;
70         else if (addr[k] >= 'A' && addr[k] <= 'F')
71            val = addr[k] - 'A' + 10;
72         else
73            val = addr[k] - '0';
74         sum = sum * 16 + val;
75         k++;
76      }
77   
78      k++; // move over the colon
79      node_hw_addr[j] = (unsigned char) sum;
80      sum = 0;   
81   }
82   
83   // read last byte of hw address
84   while (addr[k] != '\0') {
85      if (addr[k] >= 'a' && addr[k] <= 'f') 
86         val = addr[k] - 'a' + 10;
87      else if (addr[k] >= 'A' && addr[k] <= 'F')
88         val = addr[k] - 'A' + 10;
89      else
90         val = addr[k] - '0';
91      sum = sum * 16 + val;
92      k++;
93   } 
94   node_hw_addr[5] = (unsigned char) sum;
95}
96
97#ifdef _CONFIG_TEMAC_
98inline void waitForDMA()
99{
100
101    int RegValue;
102
103    //Wait until the DMA transfer is done by checking the Status register
104    do {RegValue = XDmaCentral_GetStatus((XDmaCentral *)DMA_CENTRAL_INST);}
105    while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
106
107    return;
108}
109#endif
110
111/*
112 * Receive frame
113 */
114int xilnet_eth_recv_frame(unsigned char *buf, int len) {
115
116   struct xilnet_eth_hdr *eth;
117   //unsigned short RxPktLength;
118   int size = -1;
119   void* pktBufPtr;
120
121   pktBufPtr = buf;
122   
123   //device specific routine for getting a frame
124
125#ifdef _CONFIG_EMACLITE_
126   size = XEmacLite_RecvFrame(MYMAC_BASEADDR, buf);
127#endif
128#ifdef _CONFIG_TEMAC_
129   if(XLlFifo_IsRxEmpty((XLlFifo *)FIFO_INST))
130    {
131        size=-1;
132    }
133    else
134    {
135        if(XLlFifo_RxOccupancy((XLlFifo *)FIFO_INST))
136        {
137            waitForDMA();
138             //Set DMA to non-increment source, increment dest addresses
139             XDmaCentral_SetControl((XDmaCentral *)DMA_CENTRAL_INST, XDMC_DMACR_DEST_INCR_MASK);
140            size = XLlFifo_RxGetLen((XLlFifo *)FIFO_INST);
141            XDmaCentral_Transfer((XDmaCentral *)DMA_CENTRAL_INST,
142                                (u8 *)(((XLlFifo *)FIFO_INST)->BaseAddress+XLLF_RDFD_OFFSET),
143                                (u8 *)pktBufPtr,
144                                size);
145        }
146    }
147#endif
148#ifdef _CONFIG_AXI_ETHERNET_FIFO
149   if(XLlFifo_IsRxEmpty((XLlFifo *)FIFO_INST))
150    {
151        size=-1;
152    }
153    else
154    {
155        if(XLlFifo_RxOccupancy((XLlFifo *)FIFO_INST))
156        {
157            size = XLlFifo_RxGetLen((XLlFifo *)FIFO_INST);
158            XLlFifo_Read((XLlFifo *)FIFO_INST, pktBufPtr, size);
159        }
160    }
161#endif
162
163#ifdef _DEBUG_
164    xil_printf("Ethernet Recvd Frame of size %d...\r\n", size);
165    xil_printf("src : %d%d%d%d%d%d...\r\n", buf[0], buf[1],buf[2],buf[3],buf[4],buf[5]);
166    xil_printf("dst : %d%d%d%d%d%d...\r\n", buf[6], buf[7],buf[8],buf[9],buf[10],buf[11]);
167    xil_printf("type : %d%d...\r\n", buf[12], buf[13]);
168#endif
169
170//}
171
172 
173  // Strip off the FCS(or CRC) from the received frame
174  //buf[size-1] = 0;
175  //buf[size-2] = 0;
176  //buf[size-3] = 0;
177  //buf[size-4] = 0;
178  size -= 4;
179 
180
181  if(size>0){
182  eth = (struct xilnet_eth_hdr*) buf; 
183   
184  switch (Xil_Ntohs(eth->type)) {
185  case ETH_PROTO_IP:
186     return (xilnet_ip(buf, size));
187  case ETH_PROTO_ARP:
188     return (xilnet_arp(buf, size));
189  default:
190#ifdef _DEBUG_
191     xil_printf("Unknown protocol %x...\r\n", eth->type);
192#endif
193     break;
194  }
195  }
196  return -1;
197}
198
199
200/*
201 * Send frame to peer ip addr, peer hw addr
202 */
203 
204
205int xilnet_eth_send_frame(unsigned char *pkt, int len, unsigned char *dip_addr,
206                          void *dhw_addr, unsigned short type)
207{
208   int i;
209   int hw_tbl_index = 0;
210   
211   for (i = 0; i < ETH_ADDR_LEN; i++) {
212      ((struct xilnet_eth_hdr*)pkt)->src_addr[i] = node_hw_addr[i];
213   }           
214   
215   if (dhw_addr) 
216      memcpy(((struct xilnet_eth_hdr*)pkt)->dest_addr, dhw_addr, ETH_ADDR_LEN);
217   else {
218      // find the hw tbl entry index corr to dip_addr
219      hw_tbl_index = xilnet_eth_get_hw_addr(dip_addr);
220     
221      for (i = 0; i < ETH_ADDR_LEN; i++) {
222         ((struct xilnet_eth_hdr*)pkt)->dest_addr[i] = xilnet_hw_tbl[hw_tbl_index].hw_addr[i];
223      }
224   }
225   ((struct xilnet_eth_hdr*)pkt)->type = Xil_Htons(type);
226   
227   // pad the ethernet frame if < 60 bytes
228   if (len < 60) { 
229      for(i = len; i < ETH_MIN_FRAME_LEN; i++) {
230         pkt[i] = 0;
231      }
232      len = ETH_MIN_FRAME_LEN;
233   }
234    // Write to MAC
235#ifdef _CONFIG_EMACLITE_
236   XEmacLite_SendFrame(MYMAC_BASEADDR, pkt, len);
237#endif
238#ifdef _CONFIG_TEMAC_
239    waitForDMA();
240   //Set DMA to increment src, non-increment dest addresses
241   XDmaCentral_SetControl((XDmaCentral *)DMA_CENTRAL_INST, XDMC_DMACR_SOURCE_INCR_MASK);
242   //Transfer the packet into the LLFIFO
243   XDmaCentral_Transfer((XDmaCentral *)DMA_CENTRAL_INST,
244                            (u8 *)(pkt),
245                            (u8 *)(((XLlFifo *)FIFO_INST)->BaseAddress + XLLF_TDFD_OFFSET),
246                            len);
247   waitForDMA();
248   //Write the length to the LL_FIFO; this write initiates the TEMAC transmission
249  //    XIo_Out32( (FIFO_BASEADDR + XLLF_TLF_OFFSET), len);
250   XLlFifo_TxSetLen((XLlFifo *)FIFO_INST, len);
251   
252    //xil_printf("xilnet_eth_send_frame(), len = %d \r\n",len);
253#endif
254#ifdef _CONFIG_AXI_ETHERNET_FIFO
255
256   XLlFifo_Write((XLlFifo *)FIFO_INST, pkt, len);
257
258   //Write the length to the LL_FIFO; this write initiates the TEMAC transmission
259  //    XIo_Out32( (FIFO_BASEADDR + XLLF_TLF_OFFSET), len);
260   XLlFifo_TxSetLen((XLlFifo *)FIFO_INST, len);
261
262    //xil_printf("xilnet_eth_send_frame(), len = %d \r\n",len);
263#endif
264
265 
266   return len;
267}
268
269
270/*
271 * Update Hardware Address Table
272 */
273
274void xilnet_eth_update_hw_tbl(unsigned char *buf, int proto) {
275   
276   unsigned char ip[IP_VERSION];
277   unsigned char hw[ETH_ADDR_LEN];
278   int i, j;
279   //struct xilnet_eth_hdr *eth = (struct xilnet_eth_hdr*) buf;
280
281   // Update the current age
282   curr_age++;
283   
284   // get hw addr
285   for (i = 0; i < ETH_ADDR_LEN; i++) {
286      hw[i] = ((struct xilnet_eth_hdr*)buf)->src_addr[i];
287   }     
288
289   // get ip addr
290   switch (proto) {
291   case ETH_PROTO_ARP:
292      for (i = 0; i < IP_VERSION; i++) {
293         ip[i] = (buf+ETH_HDR_LEN)[ARP_SIP_OFFSET+i];
294      }
295      break;
296   case ETH_PROTO_IP:
297      for (i = 0; i < IP_VERSION; i++) {
298         ip[i] = (buf+ETH_HDR_LEN)[IP_SADDR_BASE+i];
299      }
300      break;
301   }
302
303   // update the hw addr table
304   
305   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
306      if (xilnet_hw_tbl[i].flag) {
307         if ( (hw[0] == xilnet_hw_tbl[i].hw_addr[0]) &&
308              (hw[1] == xilnet_hw_tbl[i].hw_addr[1]) &&
309              (hw[2] == xilnet_hw_tbl[i].hw_addr[2]) &&
310              (hw[3] == xilnet_hw_tbl[i].hw_addr[3]) &&
311              (hw[4] == xilnet_hw_tbl[i].hw_addr[4]) &&
312              (hw[5] == xilnet_hw_tbl[i].hw_addr[5])
313              ) {
314            for (j = 0; j < IP_VERSION; j++)
315               xilnet_hw_tbl[i].ip_addr[j] = ip[j];;
316            xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
317            xilnet_hw_tbl[i].age = curr_age;
318            return;
319         }
320      }
321   }
322   xilnet_add_hw_tbl_entry(ip, hw);
323}
324
325
326/*
327 * Add an entry into Hw Addr table
328 */
329
330void xilnet_add_hw_tbl_entry(unsigned char *ip, unsigned char *hw)
331{
332   int i, j;
333   
334   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
335      if (!xilnet_hw_tbl[i].flag) {
336         for (j = 0; j < ETH_ADDR_LEN; j++) {
337            xilnet_hw_tbl[i].hw_addr[j] = hw[j];
338         }
339         for (j = 0; j < IP_VERSION; j++)  {
340            xilnet_hw_tbl[i].ip_addr[j] = ip[j];
341         }
342         xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
343         xilnet_hw_tbl[i].age = curr_age;
344         return;
345      }
346   }
347   
348   // Find an old entry to be eliminated from hw tbl
349   i = xilnet_eth_find_old_entry();
350   for (j = 0; j < ETH_ADDR_LEN; j++) {
351      xilnet_hw_tbl[i].hw_addr[j] = hw[j];
352   }
353   for (j = 0; j < IP_VERSION; j++)  {
354      xilnet_hw_tbl[i].ip_addr[j] = ip[j];
355   }
356   xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
357   xilnet_hw_tbl[i].age = curr_age;
358   
359}
360
361
362/*
363 * Get index into hw tbl for ip_addr
364 */
365
366int xilnet_eth_get_hw_addr(unsigned char *ip) {
367   
368   int i;
369   
370   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
371      if (xilnet_hw_tbl[i].flag) 
372         if ( (ip[0] == xilnet_hw_tbl[i].ip_addr[0]) &&
373              (ip[1] == xilnet_hw_tbl[i].ip_addr[1]) &&
374              (ip[2] == xilnet_hw_tbl[i].ip_addr[2]) &&
375              (ip[3] == xilnet_hw_tbl[i].ip_addr[3]) ) {
376            return i;
377         }
378   }
379   
380   xil_printf("Hw Addr Not found for IP \r\n");
381   return -1;
382   
383}
384
385
386/* 
387 * Init the hw addr table
388 */
389
390void xilnet_eth_init_hw_addr_tbl() {
391   
392  int i;
393 
394  for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
395     xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_FALSE;
396     xilnet_hw_tbl[i].age = 0;
397  }
398 
399  ishwaddrinit = 1;
400}
401
402/*
403 * Find the oldest entry in the Hw Table and
404 * return its index
405 */
406
407int xilnet_eth_find_old_entry()
408{
409   int i;
410   int oldest_age = 0;
411   int oldest = 0;
412   
413   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
414     
415      if (curr_age - xilnet_hw_tbl[i].age > HW_ADDR_TBL_MAXAGE) {
416         oldest = i;
417         break;
418      }
419      else {
420         if (( curr_age - xilnet_hw_tbl[i].age) > oldest_age) {
421            oldest_age = curr_age - xilnet_hw_tbl[i].age;
422            oldest = i;
423         }
424      }
425   }
426   
427   return oldest;
428   
429}
Note: See TracBrowser for help on using the repository browser.