source: edk_user_repository/WARP/sw_services/WARP_ip_udp_v1_00_a/src/WARP_ip_udp_eth.c

Last change on this file was 6011, checked in by chunter, 7 years ago

changed the type of bd_count to an int to make the comparison against -1 valid in error checking

File size: 60.5 KB
Line 
1/** @file  WARP_ip_udp_eth.c
2 *  @brief WARP IP/UDP Library (Ethernet)
3 *
4 *  @copyright Copyright 2015, Mango Communications. All rights reserved.
5 *          Distributed under the WARP license  (http://warpproject.org/license)
6 *
7 *  @author Chris Hunter (chunter [at] mangocomm.com)
8 *  @author Patrick Murphy (murphpo [at] mangocomm.com)
9 *  @author Erik Welsh (welsh [at] mangocomm.com)
10 */
11
12/***************************** Include Files *********************************/
13
14// Xilinx / Standard library includes
15#include <xparameters.h>
16#include <xstatus.h>
17#include <xil_io.h>
18#include <stdlib.h>
19#include <stdio.h>
20
21// Xilinx Hardware includes
22#include <xaxidma.h>
23#include <xaxiethernet.h>
24
25// WARP IP/UDP Library includes
26#include "WARP_ip_udp.h"
27#include "WARP_ip_udp_internal.h"
28
29
30/*************************** Constant Definitions ****************************/
31
32// Ethernet Device Error Message Numbers
33#define WARP_IP_UDP_ETH_ERROR_NUM_DEV                      0                   // Ethernet device out of range
34#define WARP_IP_UDP_ETH_ERROR_INTIALIZED                   1                   // Ethernet device not initialized
35#define WARP_IP_UDP_ETH_ERROR_CODE                         2                   // Other error (see error code for more information)
36
37
38// Ethernet Error Codes
39#define ETH_ERROR_CODE_ETH_DEVICE_INIT                     0x00000000          // Error initializing Ethernet device
40#define ETH_ERROR_CODE_ETH_CFG_INIT                        0x00000001          // Error initializing Ethernet config
41#define ETH_ERROR_CODE_ETH_CLR_OPT                         0x00000002          // Error clearing Ethernet options
42#define ETH_ERROR_CODE_ETH_SET_OPT                         0x00000003          // Error setting Ethernet options
43
44#define ETH_ERROR_CODE_DMA_INIT                            0x00000100          // Error initializing DMA
45#define ETH_ERROR_CODE_DMA_CFG_INIT                        0x00000101          // Error initializing DMA config
46
47#define ETH_ERROR_CODE_DMA_RX_ERROR                        0x00000110          // Error in DMA RX BD
48#define ETH_ERROR_CODE_DMA_RX_BD_RING_CREATE               0x00000111          // Error creating RX BD ring
49#define ETH_ERROR_CODE_DMA_RX_BD_RING_CLONE                0x00000112          // Error cloning RX BD ring
50#define ETH_ERROR_CODE_DMA_RX_BD_RING_ALLOC                0x00000113          // Error allocating RX BD ring
51#define ETH_ERROR_CODE_DMA_RX_BD_RING_TO_HW                0x00000114          // Error submitting RX BD ring to hardware
52#define ETH_ERROR_CODE_DMA_RX_BD_RING_START                0x00000115          // Error starting RX BD ring
53#define ETH_ERROR_CODE_DMA_RX_BD_RING_FREE                 0x00000116          // Error freeing RX BD ring
54
55#define ETH_ERROR_CODE_DMA_TX_ERROR                        0x00000120          // Error in DMA TX BD
56#define ETH_ERROR_CODE_DMA_TX_BD_RING_CREATE               0x00000121          // Error creating TX BD ring
57#define ETH_ERROR_CODE_DMA_TX_BD_RING_CLONE                0x00000122          // Error cloning TB BD ring
58#define ETH_ERROR_CODE_DMA_TX_BD_RING_ALLOC                0x00000123          // Error allocating TX BD ring
59#define ETH_ERROR_CODE_DMA_TX_BD_RING_TO_HW                0x00000124          // Error submitting TX BD ring to hardware
60#define ETH_ERROR_CODE_DMA_TX_BD_RING_START                0x00000125          // Error starting TX BD ring
61#define ETH_ERROR_CODE_DMA_TX_BD_RING_FREE                 0x00000126          // Error freeing TX BD ring
62
63#define ETH_ERROR_CODE_DMA_BD_SET_BUF_ADDR                 0x00000130          // Error setting BD address
64#define ETH_ERROR_CODE_DMA_BD_SET_LENGTH                   0x00000131          // Error setting BD length
65
66#define ETH_ERROR_CODE_TX_BD_CNT                           0x00000200          // Not enough TX BDs to complete transfer
67#define ETH_ERROR_CODE_TX_HANG                             0x00000201          // Hang in the DMA while trying to transmit buffer
68#define ETH_ERROR_CODE_TX_DESCRIPTOR_ERR                   0x00000202          // Error trying to allocate Tx descriptors
69#define ETH_ERROR_CODE_TX_LENGTH_MISMATCH                  0x00000203          // Length of processed descriptors does not match length of submitted descriptors
70
71
72
73
74/*********************** Global Variable Definitions *************************/
75
76
77
78/*************************** Variable Definitions ****************************/
79
80volatile eth_int_enable_func_ptr_t     interrupt_enable_callback;              // Interrupt enable callback
81volatile eth_int_disable_func_ptr_t    interrupt_disable_callback;             // Interrupt disable callback
82
83
84/*************************** Function Prototypes *****************************/
85
86int           eth_init_dma(u32 eth_dev_num, u32 verbose);
87int           eth_init_device(u32 eth_dev_num, u32 verbose);
88
89int           eth_null_interrupt_callback(int param);
90
91int           eth_check_device(u32 eth_dev_num);
92void          eth_check_dma(u32 eth_dev_num);
93
94inline int    eth_process_tx_descriptors(u32 eth_dev_num, XAxiDma_BdRing * dma_tx_ring_ptr);
95
96void          eth_print_err_msg(u32 eth_dev_num, u32 msg_num, u32 error_code, void * data, u32 data_length);
97
98
99#if _DEBUG_
100
101void print_pkt(u8 * buf, int size);
102void print_XAxiDma_Bd(XAxiDma_Bd * bd_ptr);
103
104#endif
105
106/******************************** Functions **********************************/
107
108
109/*****************************************************************************/
110/**
111 * Initialize the Ethernet subsystem
112 *
113 * @param   eth_dev_num      - Ethernet device number
114 * @param   hw_addr          - u8 pointer of MAC address of the Ethernet device
115 * @param   ip_addr          - u8 pointer of IP address of the Ethernet device
116 * @param   verbose          - Print initialization message(s)
117 *
118 * @return  int              - Status of the command:
119 *                                 XST_SUCCESS - Command completed successfully
120 *                                 XST_FAILURE - There was an error in the command
121 *
122 ******************************************************************************/
123int eth_init(u32 eth_dev_num, u8 * hw_addr, u8 * ip_addr, u32 verbose) {
124
125    int                 status;
126   
127    // NOTE:  In this instance we need to split the eth_device_check() since we
128    //        are initializing the Ethernet device info that is used as part of the check
129   
130    // Check to see if we are sending on a valid interface
131    if (eth_dev_num >= WARP_IP_UDP_NUM_ETH_DEVICES) {
132        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_NUM_DEV, 0, NULL, 0);
133        return XST_FAILURE;
134    }
135
136    // Initialize callbacks
137    interrupt_enable_callback  = (eth_int_enable_func_ptr_t)  eth_null_interrupt_callback;
138    interrupt_disable_callback = (eth_int_disable_func_ptr_t) eth_null_interrupt_callback;
139   
140    // Initialize the Ethernet device structure
141    eth_init_device_info(eth_dev_num);
142   
143    // Check if Ethernet device has been initialized
144    if (!eth_device[eth_dev_num].initialized) {
145        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_INTIALIZED, 0, NULL, 0);
146        return XST_FAILURE;
147    }
148
149    // Set the IP / HW address information in the Ethernet device structure
150    eth_set_ip_addr(eth_dev_num, ip_addr);
151    eth_set_hw_addr(eth_dev_num, hw_addr);
152
153    // Print initialization information (if required)
154    if (verbose) {
155        u32 num_recv_buffers = eth_device[eth_dev_num].num_recv_buffers;
156       
157        xil_printf("  Configuring ETH %c with %d byte buffers (%d receive, %d send)\n",
158                   warp_conv_eth_dev_num(eth_dev_num), WARP_IP_UDP_ETH_BUF_SIZE, num_recv_buffers, WARP_IP_UDP_ETH_NUM_SEND_BUF);
159    }
160   
161    // Initialize the DMA
162    status = eth_init_dma(eth_dev_num, verbose);
163   
164    if(status != XST_SUCCESS) {
165        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_INIT, &status, 1);
166        return XST_FAILURE;
167    }
168   
169    // Initialize the Ethernet device
170    status = eth_init_device(eth_dev_num, verbose);
171
172    if(status != XST_SUCCESS) {
173        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_ETH_DEVICE_INIT, &status, 1);
174        return XST_FAILURE;
175    }
176   
177    return XST_SUCCESS;
178}
179
180
181
182/*****************************************************************************/
183/**
184 * Initialize the Ethernet DMA
185 *
186 * @param   eth_dev_num      - Ethernet device number
187 * @param   verbose          - Print initialization message(s)
188 *
189 * @return  int              - Status of the command:
190 *                                 XST_SUCCESS - Command completed successfully
191 *                                 XST_FAILURE - There was an error in the command
192 *
193 ******************************************************************************/
194int eth_init_dma(u32 eth_dev_num, u32 verbose) {
195
196    int                      i;
197    int                      status;
198   
199    XAxiDma                * dma_ptr;
200    XAxiDma_Config         * dma_config_ptr;
201   
202    XAxiDma_BdRing         * dma_rx_ring_ptr;
203    u32                      dma_rx_bd_ptr;
204    u32                      dma_rx_bd_cnt;
205
206    XAxiDma_BdRing         * dma_tx_ring_ptr;   
207    u32                      dma_tx_bd_ptr;
208    u32                      dma_tx_bd_cnt;
209
210    XAxiDma_Bd               bd_template;
211    XAxiDma_Bd             * bd_ptr              = NULL;
212   
213    u32                      num_recv_buffers;
214    warp_ip_udp_buffer     * recv_buffers;
215
216    // Get DMA info from Ethernet device structure
217    dma_ptr           = (XAxiDma *) eth_device[eth_dev_num].dma_ptr;
218    dma_config_ptr    = (XAxiDma_Config *) eth_device[eth_dev_num].dma_cfg_ptr;
219   
220    dma_rx_ring_ptr   = (XAxiDma_BdRing *) eth_device[eth_dev_num].dma_rx_ring_ptr;
221    dma_rx_bd_ptr     = (u32) eth_device[eth_dev_num].dma_rx_bd_ptr;
222    dma_rx_bd_cnt     = eth_device[eth_dev_num].dma_rx_bd_cnt;
223   
224    dma_tx_ring_ptr   = (XAxiDma_BdRing *) eth_device[eth_dev_num].dma_tx_ring_ptr;
225    dma_tx_bd_ptr     = (u32) eth_device[eth_dev_num].dma_tx_bd_ptr;
226    dma_tx_bd_cnt     = eth_device[eth_dev_num].dma_tx_bd_cnt;
227   
228    num_recv_buffers  = eth_device[eth_dev_num].num_recv_buffers;
229    recv_buffers      = eth_device[eth_dev_num].recv_buffers;
230   
231    // Initialize AXI DMA engine. AXI DMA engine must be initialized before AXI Ethernet.
232    // During AXI DMA engine initialization, AXI DMA hardware is reset, and since AXI DMA
233    // reset line is connected to the AXI Ethernet, this would ensure a reset of the AXI
234    // Ethernet.
235    //
236    status = XAxiDma_CfgInitialize(dma_ptr, dma_config_ptr);
237   
238    if(status != XST_SUCCESS) {
239        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_CFG_INIT, &status, 1);
240        return XST_FAILURE;
241    }
242
243    // Set up the buffer descriptor template that will be copied to all the buffer descriptors
244    // in the TX / RX rings
245    //
246    XAxiDma_BdClear(&bd_template);
247   
248    // Setup the RX Buffer Descriptor space:
249    //   - RX buffer descriptor space is a properly aligned area of memory
250    //   - No MMU is being used so the physical and virtual addresses are the same.
251    //
252    // Create the RX ring
253    status = XAxiDma_BdRingCreate(dma_rx_ring_ptr, dma_rx_bd_ptr, dma_rx_bd_ptr, WARP_IP_UDP_BD_ALIGNMENT, dma_rx_bd_cnt);
254   
255    if (status != XST_SUCCESS) {
256        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_CREATE, &status, 1);
257        return XST_FAILURE;
258    }
259
260    // Initialize the RX ring using the descriptor template
261    status = XAxiDma_BdRingClone(dma_rx_ring_ptr, &bd_template);
262   
263    if (status != XST_SUCCESS) {
264        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_CLONE, &status, 1);
265        return XST_FAILURE;
266    }
267
268    // Setup the TX Buffer Descriptor space:
269    //   - TX buffer descriptor space is a properly aligned area of memory
270    //   - No MMU is being used so the physical and virtual addresses are the same.
271    //
272    // Create the TX BD ring
273    status = XAxiDma_BdRingCreate(dma_tx_ring_ptr, dma_tx_bd_ptr, dma_tx_bd_ptr, WARP_IP_UDP_BD_ALIGNMENT, dma_tx_bd_cnt);
274   
275    if (status != XST_SUCCESS) {
276        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_BD_RING_CREATE, &status, 1);
277        return XST_FAILURE;
278    }
279
280    // Initialize the TX ring using the descriptor template
281    status = XAxiDma_BdRingClone(dma_tx_ring_ptr, &bd_template);
282   
283    if (status != XST_SUCCESS) {
284        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_BD_RING_CLONE, &status, 1);
285        return XST_FAILURE;
286    }
287
288    // Initialize RX descriptor space:
289    //   - Allocate 1 buffer descriptor for each receive buffer
290    //   - Set up each descriptor to use a portion of the allocated receive buffer
291    //
292    // Allocate receive buffers
293    status = XAxiDma_BdRingAlloc(dma_rx_ring_ptr, num_recv_buffers, &bd_ptr);
294   
295    if (status != XST_SUCCESS) {
296        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_ALLOC, &status, 1);
297        return XST_FAILURE;
298    }
299   
300    for ( i = 0; i < num_recv_buffers; i++ ){   
301        XAxiDma_BdSetBufAddr(bd_ptr, (u32)(recv_buffers[i].data));
302        XAxiDma_BdSetLength(bd_ptr, WARP_IP_UDP_ETH_BUF_SIZE, dma_rx_ring_ptr->MaxTransferLen);
303        XAxiDma_BdSetCtrl(bd_ptr, 0);
304        XAxiDma_BdSetId(bd_ptr, (u32)(recv_buffers[i].data));
305
306        bd_ptr = XAxiDma_BdRingNext(dma_rx_ring_ptr, bd_ptr);
307    }
308
309    // Enqueue buffer descriptors to hardware
310    status = XAxiDma_BdRingToHw(dma_rx_ring_ptr, num_recv_buffers, bd_ptr);
311   
312    if (status != XST_SUCCESS) {
313        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_TO_HW, &status, 1);
314        return XST_FAILURE;
315    }
316
317    //   
318    // NOTE:  We do not need to do any additional setup for the transmit buffer descriptors
319    //        since those will be allocated and processed as part of the send process.
320    //
321
322    return XST_SUCCESS; 
323}
324
325
326
327/*****************************************************************************/
328/**
329 * Initialize the Ethernet device
330 *
331 * @param   eth_dev_num      - Ethernet device number
332 * @param   verbose          - Print initialization message(s)
333 *
334 * @return  int              - Status of the command:
335 *                                 XST_SUCCESS - Command completed successfully
336 *                                 XST_FAILURE - There was an error in the command
337 *
338 ******************************************************************************/
339int eth_init_device(u32 eth_dev_num, u32 verbose) {
340
341    int                      status;
342   
343    XAxiEthernet           * eth_ptr;
344    XAxiEthernet_Config    * eth_config_ptr;
345
346    // Get Ethernet info from Ethernet device structure
347    eth_ptr           = (XAxiEthernet *) eth_device[eth_dev_num].eth_ptr;
348    eth_config_ptr    = (XAxiEthernet_Config *) eth_device[eth_dev_num].eth_cfg_ptr;
349   
350    // Initialize Ethernet Device
351    status = XAxiEthernet_CfgInitialize(eth_ptr, eth_config_ptr, eth_config_ptr->BaseAddress);
352   
353    if (status != XST_SUCCESS) {
354        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_ETH_CFG_INIT, &status, 1);
355        return XST_FAILURE;
356    }
357
358    // Disable Ethernet options: (found in xaxiethernet.h)
359    //     - XAE_LENTYPE_ERR_OPTION specifies the Axi Ethernet device to enable Length/Type error checking (mismatched type/length field) for received frames.
360    //     - XAE_FLOW_CONTROL_OPTION specifies the Axi Ethernet device to recognize received flow control frames.
361    //     - XAE_FCS_STRIP_OPTION specifies the Axi Ethernet device to strip FCS and PAD from received frames.
362    //
363    status = XAxiEthernet_ClearOptions(eth_ptr, XAE_LENTYPE_ERR_OPTION | XAE_FLOW_CONTROL_OPTION | XAE_FCS_STRIP_OPTION);
364   
365    if (status != XST_SUCCESS) {
366        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_ETH_CLR_OPT, &status, 1);
367        return XST_FAILURE;
368    }
369
370    // Enable Ethernet options: (found in xaxiethernet.h)
371    //     - XAE_PROMISC_OPTION specifies the Axi Ethernet device to accept all incoming packets.
372    //     - XAE_MULTICAST_OPTION specifies the Axi Ethernet device to receive frames sent to Ethernet addresses that are programmed into the Multicast Address Table (MAT).
373    //     - XAE_BROADCAST_OPTION specifies the Axi Ethernet device to receive frames sent to the broadcast Ethernet address.
374    //     - XAE_RECEIVER_ENABLE_OPTION specifies the Axi Ethernet device receiver to be enabled.
375    //     - XAE_TRANSMITTER_ENABLE_OPTION specifies the Axi Ethernet device transmitter to be enabled.
376    //     - XAE_JUMBO_OPTION specifies the Axi Ethernet device to accept jumbo frames for transmit and receive.
377    //   
378    status = XAxiEthernet_SetOptions(eth_ptr, XAE_PROMISC_OPTION | XAE_MULTICAST_OPTION | XAE_BROADCAST_OPTION | XAE_RECEIVER_ENABLE_OPTION | XAE_TRANSMITTER_ENABLE_OPTION | XAE_JUMBO_OPTION);
379   
380    if (status != XST_SUCCESS) {
381        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_ETH_SET_OPT, &status, 1);
382        return XST_FAILURE;
383    }
384
385    return XST_SUCCESS;
386}
387
388
389
390/*****************************************************************************/
391/**
392 * Start the Ethernet device
393 *
394 * @param   eth_dev_num      - Ethernet device number
395 *
396 * @return  int              - Status of the command:
397 *                                 XST_SUCCESS - Command completed successfully
398 *                                 XST_FAILURE - There was an error in the command
399 *
400 ******************************************************************************/
401int eth_start_device(u32 eth_dev_num) {
402
403    int                      status;
404
405    XAxiEthernet           * eth_ptr;
406    XAxiDma_BdRing         * dma_rx_ring_ptr;
407   
408    // Check the Ethernet device
409    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
410        return XST_FAILURE;
411    }
412
413    // Get Ethernet / DMA info from Ethernet device structure
414    eth_ptr           = (XAxiEthernet *) eth_device[eth_dev_num].eth_ptr;
415    dma_rx_ring_ptr   = (XAxiDma_BdRing *) eth_device[eth_dev_num].dma_rx_ring_ptr;
416
417    // Start the Ethernet device
418    XAxiEthernet_Start(eth_ptr);
419   
420    // Start DMA RX channel
421    status = XAxiDma_BdRingStart(dma_rx_ring_ptr);
422   
423    if (status != XST_SUCCESS) {
424        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_START, &status, 1);
425        return XST_FAILURE;
426    }
427
428    // NOTE:  Now Ethernet subsystem is ready to receive data
429
430    return XST_SUCCESS;
431}
432
433
434
435/********************************************************************
436 * Ethernet Null Callback
437 *
438 * This function is part of the callback system for processing Ethernet packets.
439 *
440 * @param   int  param       - Parameters for the callback
441 *
442 * @return  int              - Status of the command:
443 *                                 XST_SUCCESS  - Command successful
444 *
445 ********************************************************************/
446int eth_null_interrupt_callback(int param){
447    return XST_SUCCESS;
448}
449
450
451
452/*****************************************************************************/
453/**
454 * Set the Ethernet callbacks
455 *
456 * @param   void * callback  - Pointer to the callback function
457 *
458 * @return  None
459 *
460 *****************************************************************************/
461void eth_set_interrupt_enable_callback(void(*callback)()){
462    interrupt_enable_callback = (eth_int_enable_func_ptr_t) callback;
463}
464
465
466void eth_set_interrupt_disable_callback(void(*callback)()){
467    interrupt_disable_callback = (eth_int_disable_func_ptr_t) callback;
468}
469
470
471
472/*****************************************************************************/
473/**
474 * Send Ethernet frame
475 *
476 * @note    Sending Ethernet frames is not interrupt safe.  Since the library does not know
477 *          if it will be included in a system that contains interrupts, the library implements
478 *          two callback functions to control interrupts.  These functions follow the following
479 *          conventions:
480 *              status = interrupt_disable_callback();
481 *              interrupt_enable_callback(status);
482 *          where the interrupt disable callback returns a status integer that is then used to
483 *          selectively re-enable interrupts.  If these callbacks are not set in user code, then
484 *          they will just call the eth_null_interrupt_callback and do nothing.
485 *
486 * @param   eth_dev_num       - Ethernet device number
487 * @param   socket            - Socket used for this transmission
488 * @param   buffers           - Pointer to an array of IP/UDP buffers for the transmission
489 * @param   num_buffers       - Number IP/UDP buffers in the transmission
490 * @param   use_socket_header - Use the header in the socket or ignore it (because IP/UDP buffers contain the header)
491 *
492 * @return  int               - Number of bytes transmitted
493 *                                 WARP_IP_UDP_FAILURE - There was an error in the command
494 *
495 *****************************************************************************/
496int eth_send_frame(u32 eth_dev_num, warp_ip_udp_socket * socket, warp_ip_udp_buffer ** buffers, u32 num_buffers, u32 use_socket_header) {
497
498    int                      i;
499    int                      status;
500    int                      int_status;
501   
502    warp_ip_udp_buffer       socket_hdr;
503    warp_ip_udp_buffer       padding_buffer;
504    u32                      eth_frame_length              = 0;
505   
506    warp_ip_udp_buffer     * buffers_to_process[WARP_IP_UDP_TXBD_CNT + 2];
507    u32                      total_buffers                 = 0;
508    int                      bd_count;
509
510    u32                      buffer_addr;
511    u32                      buffer_size;
512   
513    XAxiDma_BdRing         * dma_tx_ring_ptr               = NULL;
514    XAxiDma_Bd             * bd_set_ptr                    = NULL;
515    XAxiDma_Bd             * bd_ptr                        = NULL;
516   
517    // Check the Ethernet device
518    if (eth_check_device(eth_dev_num) != XST_SUCCESS) {
519        return WARP_IP_UDP_FAILURE; 
520    }
521   
522    // Try to disable the interrupts through the callback
523    int_status = interrupt_disable_callback();
524   
525    // Get info from Ethernet device structure
526    dma_tx_ring_ptr = (XAxiDma_BdRing *) eth_device[eth_dev_num].dma_tx_ring_ptr;
527
528    // Create the array of IP/UDP buffers to be processed:
529    //     - If the socket header is used, then put that as buffer[0], otherwise skip
530    //     - Process the command arguments as normal
531    //     - If the packet is not long enough, then append an additional buffer with zeros
532    //
533    if (use_socket_header == 1) {
534        // Create a IP/UDP buffer for the header (only need to fill in data and size)
535        socket_hdr.size         = sizeof(warp_ip_udp_header);
536        socket_hdr.data         = (u8 *) socket->hdr;
537
538        // Add the buffer to the array of buffers to be processed
539        buffers_to_process[0]   = &socket_hdr;
540       
541        // Increment counters / indexes
542        eth_frame_length       += sizeof(warp_ip_udp_header);
543        total_buffers          += 1;
544    }
545
546    // Process the command line arguments
547    for (i = 0; i < num_buffers; i++) {
548        // Only add buffers that have a non-zero length
549        if (buffers[i]->size > 0) {
550            // Add the buffer to the array of buffers to be processed
551            buffers_to_process[total_buffers] = buffers[i];
552
553            // Increment counters / indexes
554            eth_frame_length       += buffers[i]->size;
555            total_buffers          += 1;
556        }
557    }
558
559    // If the packet is less than the ETH_MIN_FRAME_LEN, then we need to pad the
560    // transaction with zeros.  To do this, we use the dummy minimum Ethernet frame
561    // provided by the driver.
562    //
563    if (eth_frame_length < ETH_MIN_FRAME_LEN) {
564        // Create a IP/UDP buffer for the padding (only need to fill in data and size)
565        padding_buffer.size     = ETH_MIN_FRAME_LEN - eth_frame_length;
566        padding_buffer.data     = ETH_dummy_frame;
567       
568        // Add the buffer to the array of buffers to be processed
569        buffers_to_process[total_buffers] = &padding_buffer;
570       
571        // Increment counters / indexes
572        eth_frame_length        = ETH_MIN_FRAME_LEN;
573        total_buffers          += 1;
574    }
575
576    //
577    // NOTE:  At this point in the code, we have:
578    //     - total_buffers is the number of buffers we need to process
579    //     - buffers_to_process contains all the necessary pointers to IP/UDP buffers
580    //
581
582    // Sanity check:  Do we have enough buffer descriptors to transmit the frame
583    if (total_buffers > WARP_IP_UDP_TXBD_CNT) {
584        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_TX_BD_CNT, &status, 1);
585       
586        // Re-enable the interrupts
587        interrupt_enable_callback(int_status);
588       
589        return WARP_IP_UDP_FAILURE;
590    }
591
592    // Check that there are currently no DMA errors (restarts DMA on error)
593    eth_check_dma(eth_dev_num);
594   
595    //
596    // NOTE:  In order to allow for the the maximum number of packets to be queued up waiting on
597    //   the Ethernet module (ie to create the maximum buffer to allow for the CPU to be occupied
598    //   by other things), we want to allocate as many buffer descriptors as possible and only
599    //   free them when necessary or convenient.  Therefore, only if we cannot allocate buffer
600    //   descriptors will we try to free the already processed buffer descriptors.
601    //
602
603    // Allocate buffer descriptors for the Frame   
604    status = XAxiDma_BdRingAlloc(dma_tx_ring_ptr, total_buffers, &bd_set_ptr);
605
606    // We cannot allocate buffer descriptors so we need to free up some
607    //
608    //     NOTE:  This loop is where the transport needs the function will block if all the descriptors
609    //         are in use.  We do not want to exit the loop prematurely unless there is an unrecoverable
610    //         error.  Otherwise, we will drop packets that need to be transmitted.
611    //
612    //     NOTE:  By keeping this loop simple, we avoid many potential race conditions that could arise
613    //         between the processing code and the DMA peripheral.
614    //
615    while (status != XST_SUCCESS) {
616
617        // Process any completed BDs
618        bd_count = eth_process_tx_descriptors(eth_dev_num, dma_tx_ring_ptr);
619
620        // Check that we processed the tx descriptors successfully
621        if (bd_count == WARP_IP_UDP_FAILURE) {
622            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, 0xDEADBEEF, &status, 1);  // !!! FIX !!!
623           
624            // Re-enable the interrupts
625            interrupt_enable_callback(int_status);
626       
627            return WARP_IP_UDP_FAILURE;
628
629        } else {
630            // Allocate buffer descriptors for the Frame
631            status = XAxiDma_BdRingAlloc(dma_tx_ring_ptr, total_buffers, &bd_set_ptr);
632        }
633    }
634
635    // Get the first descriptor in the set
636    bd_ptr = bd_set_ptr;
637
638    // Set up all of the buffer descriptors
639    for (i = 0; i < total_buffers; i++) {
640
641        // Clear the buffer descriptor
642        XAxiDma_BdClear(bd_ptr);
643   
644        // Get the buffer address / size
645        buffer_addr = (u32) buffers_to_process[i]->data;
646        buffer_size = buffers_to_process[i]->size;
647   
648        // Set the descriptor address to the start of the buffer
649        status = XAxiDma_BdSetBufAddr(bd_ptr, buffer_addr);
650       
651        if (status != XST_SUCCESS) {
652            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_BD_SET_BUF_ADDR, &status, 1);
653           
654            // Re-enable the interrupts
655            interrupt_enable_callback(int_status);
656       
657            return WARP_IP_UDP_FAILURE;
658        }
659
660        // Set the descriptor length to the length of the buffer
661        status = XAxiDma_BdSetLength(bd_ptr, buffer_size, dma_tx_ring_ptr->MaxTransferLen);
662       
663        if (status != XST_SUCCESS) {
664            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_BD_SET_LENGTH, &status, 1);
665           
666            // Re-enable the interrupts
667            interrupt_enable_callback(int_status);
668       
669            return WARP_IP_UDP_FAILURE;
670        }
671
672        // Set the flags for first / last descriptor
673        //    NOTE:  Since this is a "set" command, if there is only one buffer, then we need to set both bits in one write
674        //
675        if (i == 0) {
676            if (total_buffers == 1) {
677                XAxiDma_BdSetCtrl(bd_ptr, (XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK));
678            } else {
679                XAxiDma_BdSetCtrl(bd_ptr, XAXIDMA_BD_CTRL_TXSOF_MASK);
680            }
681        } else if (i == (total_buffers - 1)) {
682
683            XAxiDma_BdSetCtrl(bd_ptr, XAXIDMA_BD_CTRL_TXEOF_MASK);
684        }
685
686        // Get next descriptor
687        bd_ptr = XAxiDma_BdRingNext(dma_tx_ring_ptr, bd_ptr);
688    }
689
690    // Enqueue to the HW
691    status = XAxiDma_BdRingToHw(dma_tx_ring_ptr, total_buffers, bd_set_ptr);
692   
693    if (status != XST_SUCCESS) {
694        // Undo descriptor allocation and exit
695        XAxiDma_BdRingUnAlloc(dma_tx_ring_ptr, total_buffers, bd_set_ptr);
696       
697        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_BD_RING_TO_HW, &status, 1);
698       
699        // Re-enable the interrupts
700        interrupt_enable_callback(int_status);
701       
702        return WARP_IP_UDP_FAILURE;
703    }
704
705    // Start the transmission, if necessary
706    //     NOTE:  If the channel is already started, then the XAxiDma_BdRingToHw() call will start the transmission
707    if (dma_tx_ring_ptr->RunState == AXIDMA_CHANNEL_HALTED) {
708   
709        status = XAxiDma_BdRingStart(dma_tx_ring_ptr);
710       
711        if (status != XST_SUCCESS) {
712            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_BD_RING_START, &status, 1);
713           
714            // Re-enable the interrupts
715            interrupt_enable_callback(int_status);
716           
717            return WARP_IP_UDP_FAILURE;
718        }
719    }
720
721    //
722    // Check if the HW is done processing some buffer descriptors
723    //
724    //   NOTE:  Since it takes some time to begin the Ethernet transfer (see NOTE below), it is convenient to try
725    //       to process completed buffer descriptors here.  Unfortunately, it requires a non-trivial amount of time
726    //       to even check if there are buffer descriptors to process due to interactions with the hardware.  Hence,
727    //       there is a tradeoff between calling eth_process_tx_descriptors() in each iteration of this loop vs
728    //       waiting until there are more buffer descriptors to process since the incremental cost of processing
729    //       a buffer descriptor is much less than checking if there are buffer descriptors to process.  The down side
730    //       of waiting to process more descriptors is that this makes the time it takes to process the packet to
731    //       send less consistent.  Currently, we are opting for timing consistency and eating the overhead required
732    //       to check that descriptors are ready to process.  However, this decision should be revisited in future
733    //       revisions to this library.
734    //
735    //   NOTE:  The Ethernet controller requires that all data to be sent in a given packet be located in the
736    //       Ethernet controller local memory.  Therefore, the AXI DMA attached to the Ethernet controller must
737    //       transfer all necessary data to the Ethernet controller before the Ethernet transfer can begin.
738    //       Unfortunately, the time of this transfer is bounded by the AXI stream channel between the AXI DMA and
739    //       Ethernet controller which is only 32 bits @ 160 MHz.  As of WARPLab 7.5.1, the Ethernet controller and
740    //       AXI DMA did not allow the AXI stream interface to be configured so 640 MBps is the maximum throughput
741    //       attainable through that link.
742    //
743    //   NOTE:  Based on empirical measurements, here is the rough timing for processing tx descriptors.  In this
744    //       experiment, we were using Read IQ, which requires 2 buffer descriptors per Ethernet packet, and measuring
745    //       timing using debug GPIO calls (WARP_IP_UDP_TXBD_CNT = 10):
746    //
747    //       HwCnt > X     Time to process    Num Loops            Avg Time per Loop
748    //         0             4   us              1                      4    us
749    //         4             6.4 us              2                      3.2  us
750    //         6             8.8 us              3                      2.9  us
751    //         8            11.2 us              4                      2.8  us
752    //
753    //       For a full packet, there is approximately 14.5 us between the start of the DMA and the start of the
754    //       Ethernet packet.  If we decide to change the decision to wait to process buffer descriptors, then
755    //       uncomment the following line and choose the appropriate value:
756    //
757    // if (dma_tx_ring_ptr->HwCnt > 4) {
758
759        // Process any completed BDs
760        bd_count = eth_process_tx_descriptors(eth_dev_num, dma_tx_ring_ptr);
761
762        // Check that we processed the tx descriptors successfully
763        if (bd_count == WARP_IP_UDP_FAILURE) {
764            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, 0xDEADBEEF, &status, 1);  // !!! FIX !!!
765           
766            // Re-enable the interrupts
767            interrupt_enable_callback(int_status);
768           
769            return WARP_IP_UDP_FAILURE;
770        }
771    //}
772
773    // Re-enable the interrupts
774    interrupt_enable_callback(int_status);
775   
776    return eth_frame_length;
777}
778
779
780
781/*****************************************************************************/
782/**
783 * Process TX buffer descriptors
784 *
785 * @param   dma_tx_ring_ptr   - Pointer to DMA Tx BD ring
786 *
787 * @return  int               - Number of descriptors processed
788 *                                 WARP_IP_UDP_FAILURE - There was an error in the command
789 *
790 *****************************************************************************/
791inline int eth_process_tx_descriptors(u32 eth_dev_num, XAxiDma_BdRing * dma_tx_ring_ptr) {
792
793    int                      i;
794       int                      status;
795
796    int                      processed_bd_count;
797
798    XAxiDma_Bd             * bd_set_ptr                    = NULL;
799    XAxiDma_Bd             * bd_ptr                        = NULL;
800
801    // Check how many buffer descriptors have been processed
802    processed_bd_count = XAxiDma_BdRingFromHw(dma_tx_ring_ptr, WARP_IP_UDP_TXBD_CNT, &bd_set_ptr);
803
804    // Initialize the working descriptor pointer
805    bd_ptr = bd_set_ptr;
806
807    for (i = 0; i < processed_bd_count; i++) {
808
809        // Get the status of the descriptor
810        status = XAxiDma_BdGetSts(bd_ptr);
811
812        // Check the status
813        if ((status & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(status & XAXIDMA_BD_STS_COMPLETE_MASK))) {
814            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_ERROR, &status, 1);
815        }
816
817        // NOTE:  No need to clear out all the control / status information before freeing the buffer
818        //     descriptor, since we clear them when they are allocated.
819
820        // Get next descriptor
821        bd_ptr = XAxiDma_BdRingNext(dma_tx_ring_ptr, bd_ptr);
822    }
823
824    // Free all processed RX BDs for future transmission
825    status = XAxiDma_BdRingFree(dma_tx_ring_ptr, processed_bd_count, bd_set_ptr);
826
827    if (status != XST_SUCCESS) {
828        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_BD_RING_FREE, &status, 1);
829        return WARP_IP_UDP_FAILURE;
830    }
831
832    return processed_bd_count;
833}
834
835
836
837/*****************************************************************************/
838/**
839 * Receive an Ethernet Frame
840 *
841 * Will try to receive an Ethernet frame and perform initial IP / UDP processing on it.
842 * This function is non-blocking and will have populated the warp_ip_udp_buffer if
843 * the return value is greater than 0 (ie > 0).
844 *
845 * @param   eth_dev_num - Ethernet device to receive Ethernet frame on
846 * @param   eth_frame   - WARP IP/UDP Buffer to populate with Ethernet data
847 *
848 * @return  int         - Number of bytes of data in the received packet
849 *                            0 if there is no packet received
850 *                            WARP_IP_UDP_FAILURE if there was a library failure
851 *
852 ******************************************************************************/
853int eth_recv_frame(u32 eth_dev_num, warp_ip_udp_buffer * eth_frame) {
854
855    int                      status;
856
857    int                      processed_bd_count  = 0;
858    int                      size                = 0;
859    int                      length              = 0;
860
861    XAxiDma_BdRing         * dma_rx_ring_ptr;
862    XAxiDma_Bd             * bd_ptr;
863    ethernet_header        * header;
864    u8                     * data;
865
866    u32                      node_addr_match;
867    u32                      bcast_addr_match;
868   
869    u32                    * temp_ptr_0;
870    u32                    * temp_ptr_1;
871    u32                      temp_32_0;
872    u32                      temp_32_1;
873    u16                      temp_16_0;
874    u16                      temp_16_1;
875
876
877    // Check the Ethernet device (optional - this is checked in many other places; removing for performance reasons)
878    // if (eth_check_device(eth_dev_num) != XST_SUCCESS) { return WARP_IP_UDP_FAILURE; }
879
880    // Get the RX Buffer Descriptor Ring pointer
881    dma_rx_ring_ptr = (XAxiDma_BdRing *)(eth_device[eth_dev_num].dma_rx_ring_ptr);
882
883    // Check to see that the HW is started
884    //     - If it is not started, we must have gotten an error somewhere, so we need to reset and restart the DMA
885    //
886    if (!XAxiDma_BdRingHwIsStarted(dma_rx_ring_ptr)) {
887
888        // Check that there are no DMA errors (restarts DMA on error)
889        eth_check_dma(eth_dev_num);
890   
891        // Start DMA RX channel
892        status = XAxiDma_BdRingStart(dma_rx_ring_ptr);
893       
894        if (status != XST_SUCCESS) {
895            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_START, &status, 1);
896            return WARP_IP_UDP_FAILURE;
897        }
898    }
899   
900    // See if we have any data to process
901    //     NOTE:  We will only process one buffer descriptor at a time in this function call
902    processed_bd_count = XAxiDma_BdRingFromHw(dma_rx_ring_ptr, 0x1, &bd_ptr);
903
904    // If we have data, then we need process the buffer
905    if (processed_bd_count > 0) {
906
907        // Get the status of the buffer descriptor
908        status = XAxiDma_BdGetSts(bd_ptr);
909
910        if ((status & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(status & XAXIDMA_BD_STS_COMPLETE_MASK))) {
911            eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_ERROR, &status, 1);
912            return WARP_IP_UDP_FAILURE;
913        } else {
914            size = (XAxiDma_BdRead(bd_ptr, XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF;
915        }
916
917        // Get the address of the buffer data
918        data = (u8 *)XAxiDma_BdGetId(bd_ptr);                        // BD ID was set to the base address of the buffer
919       
920        // Strip off the FCS (or CRC) from the received frame
921        size -= 4;
922       
923        // Populate the IP/UDP buffer
924        eth_frame->max_size   = WARP_IP_UDP_ETH_BUF_SIZE;            // Max buffer size (Should not be changed for received packets)
925        eth_frame->size       = size;                                // Current buffer size (Should not be changed for received packets)
926        eth_frame->data       = data;                                // Address of buffer data
927        eth_frame->offset     = data + ETH_HEADER_LEN;               // Initialize offset after Ethernet header
928        eth_frame->length     = size - ETH_HEADER_LEN;               // Initialize the length after the Ethernet header
929        eth_frame->descriptor = (void *) bd_ptr;                     // Populate the descriptor pointer to be freed later
930
931        // Process the packet
932        if ( size > 0 ) {
933
934            // Get a pointer to the Ethernet header
935            header           = (ethernet_header *) data;
936
937            // Check Ethernet header to see if packet is destined for the node
938            //     NOTE:  The code below implements the same function as:
939            //
940            //         node_addr_match  = ~(memcmp(header->dest_mac_addr, eth_device[eth_dev_num].hw_addr, ETH_MAC_ADDR_LEN));
941            //         bcast_addr_match = ~(memcmp(header->dest_mac_addr, eth_bcast_addr, ETH_MAC_ADDR_LEN));
942            //
943            //     However, it is optimized for the fewest number of system reads since those take a
944            //     significant amount of time (time difference is ~0.9 us).
945            //
946            temp_ptr_0 = (u32 *) header->dest_mac_addr;
947            temp_32_0  = temp_ptr_0[0];
948            temp_16_0  = temp_ptr_0[1] & 0x0000FFFF;
949
950            temp_ptr_1 = (u32 *) eth_device[eth_dev_num].hw_addr;
951            temp_32_1  = temp_ptr_1[0];
952            temp_16_1  = temp_ptr_1[1] & 0x0000FFFF;
953
954            node_addr_match  = ((temp_32_0 == temp_32_1) & (temp_16_0 == temp_16_1));
955            bcast_addr_match = ((temp_32_0 == 0xFFFFFFFF) & (temp_16_0 == 0xFFFF));
956
957            // Process the packet based on the EtherType
958            if (node_addr_match | bcast_addr_match) {
959                switch (Xil_Ntohs(header->ethertype)) {
960                    // IP packet
961                    case ETHERTYPE_IP_V4:
962                        length = ipv4_process_packet(eth_dev_num, eth_frame);
963                    break;
964
965                    // ARP packet
966                    case ETHERTYPE_ARP:
967                        length = arp_process_packet(eth_dev_num, eth_frame);
968                    break;
969
970                    // NOTE:  The library does not include a default case because there are a number of
971                    //     Ethernet packets that the node will receive that the library will not process.
972                    //     Since the library doesn't know at this point if the packet is destined for the
973                    //     given node, having an error message here would be a distraction.
974                    //
975                }
976
977                // Need to adjust the buffer for the library delimiter to 32-bit align the buffer data
978                //
979                // ASSUMPTION:
980                //     The buffer descriptor used for this packet will be freed when it is done being processed.
981                //
982                if (length > 0) {
983                    eth_frame->offset += WARP_IP_UDP_DELIM_LEN;
984                    eth_frame->length -= WARP_IP_UDP_DELIM_LEN;
985                    length            -= WARP_IP_UDP_DELIM_LEN;
986                } else {
987                    // Library is done with the Ethernet frame, need to free buffer descriptor
988                    eth_free_recv_buffers(eth_dev_num, eth_frame->descriptor, 0x1);
989                }
990
991            } else {
992                // Ethernet frame not intended for node, need to free buffer descriptor
993                eth_free_recv_buffers(eth_dev_num, eth_frame->descriptor, 0x1);
994            }
995        }
996    }
997    // }
998
999    return length;
1000}
1001
1002
1003
1004/*****************************************************************************/
1005/**
1006 * Free receive buffer so they can be used again
1007 *
1008 * @param   eth_dev_num      - Ethernet device number
1009 * @param   descriptors      - Pointer to receive buffer descriptor to be freed
1010 * @param   num_descriptors  - Number of buffers to be freed
1011 *
1012 * @return  int              - Status of the command:
1013 *                                 XST_SUCCESS - Command completed successfully
1014 *                                 XST_FAILURE - There was an error in the command
1015 *
1016 *****************************************************************************/
1017int eth_free_recv_buffers(u32 eth_dev_num, void * descriptors, u32 num_descriptors) {
1018
1019    int                      status;
1020    u32                      free_bd_cnt;
1021
1022    XAxiDma_BdRing         * dma_rx_ring_ptr;
1023    XAxiDma_Bd             * bd_ptr;
1024 
1025    // Check the Ethernet device
1026    if (eth_check_device(eth_dev_num) == XST_FAILURE) { return XST_FAILURE; }
1027
1028    // Get DMA info from Ethernet device structure
1029    dma_rx_ring_ptr   = (XAxiDma_BdRing *) eth_device[eth_dev_num].dma_rx_ring_ptr;
1030   
1031    // Cast the buffer descriptor pointer
1032    bd_ptr = (XAxiDma_Bd *)(descriptors);
1033
1034    // Free processed RX descriptors for future receptions
1035    status = XAxiDma_BdRingFree(dma_rx_ring_ptr, num_descriptors, bd_ptr);
1036
1037    if (status != XST_SUCCESS) {
1038        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_FREE, &status, 1);
1039        return XST_FAILURE;
1040    }
1041
1042    // Return processed descriptors to RX channel so they are ready to receive new packets
1043    free_bd_cnt = XAxiDma_BdRingGetFreeCnt(dma_rx_ring_ptr);
1044
1045    status = XAxiDma_BdRingAlloc(dma_rx_ring_ptr, free_bd_cnt, &bd_ptr);
1046
1047    if (status != XST_SUCCESS) {
1048        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_ALLOC, &status, 1);
1049        return XST_FAILURE;
1050    }
1051
1052    status = XAxiDma_BdRingToHw(dma_rx_ring_ptr, free_bd_cnt, bd_ptr);
1053
1054    if (status != XST_SUCCESS) {
1055        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_BD_RING_TO_HW, &status, 1);
1056        return XST_FAILURE;
1057    }
1058
1059    return XST_SUCCESS;
1060}
1061
1062
1063
1064/*****************************************************************************/
1065/**
1066 * Read the contents of the Ethernet Phy
1067 *
1068 * @param   eth_dev_num      - Ethernet device number
1069 * @param   phy_addr         - Address of the PHY to read
1070 * @param   reg_addr         - Address of register within the PHY to read
1071 * @param   reg_value        - Pointer to where data will be returned
1072 *
1073 * @return  int              - Status of the command:
1074 *                                 XST_SUCCESS - Command completed successfully
1075 *                                 XST_FAILURE - There was an error in the command
1076 *
1077 *****************************************************************************/
1078int eth_read_phy_reg(u32 eth_dev_num, u32 phy_addr, u32 reg_addr, u16 * reg_value) {
1079
1080    // Check the Ethernet device
1081    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1082        return XST_FAILURE;
1083    }
1084
1085    // Check if the Ethernet PHY reports a valid link
1086    XAxiEthernet_PhyRead(eth_device[eth_dev_num].eth_ptr, phy_addr, reg_addr, reg_value);
1087
1088    return XST_SUCCESS;
1089}
1090
1091
1092
1093/*****************************************************************************/
1094/**
1095 * Write a value to the Ethernet Phy
1096 *
1097 * @param   eth_dev_num      - Ethernet device number
1098 * @param   phy_addr         - Address of the PHY to write
1099 * @param   reg_addr         - Address of register within the PHY to write
1100 * @param   reg_value        - u16 value to write
1101 *
1102 * @return  int              - Status of the command:
1103 *                                 XST_SUCCESS - Command completed successfully
1104 *                                 XST_FAILURE - There was an error in the command
1105 *
1106 *****************************************************************************/
1107int eth_write_phy_reg(u32 eth_dev_num, u32 phy_addr, u32 reg_addr, u16 reg_value) {
1108
1109    // Check the Ethernet device
1110    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1111        return XST_FAILURE;
1112    }
1113
1114    // Check if the Ethernet PHY reports a valid link
1115    XAxiEthernet_PhyWrite(eth_device[eth_dev_num].eth_ptr, phy_addr, reg_addr, reg_value);
1116
1117    return XST_SUCCESS;
1118}
1119
1120
1121
1122/*****************************************************************************/
1123/**
1124 * Set the operating speed of the Ethernet device
1125 *
1126 * @param   eth_dev_num      - Ethernet device number
1127 * @param   speed            - Speed of the device in Mbps
1128 *
1129 * @return  int              - Status of the command:
1130 *                                 XST_SUCCESS - Command completed successfully
1131 *                                 XST_FAILURE - There was an error in the command
1132 *
1133 *****************************************************************************/
1134int eth_set_operating_speed(u32 eth_dev_num, u32 speed) {
1135   
1136    // Check the Ethernet device
1137    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1138        return XST_FAILURE;
1139    }
1140
1141    return XAxiEthernet_SetOperatingSpeed(eth_device[eth_dev_num].eth_ptr, speed);
1142}
1143
1144
1145
1146/*****************************************************************************/
1147/**
1148 * Set / Get MAC Address
1149 *
1150 * @param   eth_dev_num      - Ethernet device number
1151 * @param   hw_addr          - u8 pointer of MAC address to set / get
1152 *
1153 * @return  int              - Status of the command:
1154 *                                 XST_SUCCESS - Command completed successfully
1155 *                                 XST_FAILURE - There was an error in the command
1156 *
1157 ******************************************************************************/
1158int eth_set_hw_addr(u32 eth_dev_num, u8 * hw_addr) {
1159
1160    int i;
1161
1162    // Check the Ethernet device
1163    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1164        return XST_FAILURE;
1165    }
1166   
1167    // Update the MAC Address
1168    for (i = 0; i < ETH_MAC_ADDR_LEN; i++) {
1169        eth_device[eth_dev_num].hw_addr[i] = hw_addr[i];
1170    }
1171
1172    return XST_SUCCESS;
1173}
1174
1175
1176
1177int eth_get_hw_addr(u32 eth_dev_num, u8 * hw_addr) {
1178
1179    int i;
1180
1181    // Check the Ethernet device
1182    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1183        return XST_FAILURE;
1184    }
1185   
1186    // Populate the MAC Address
1187    for ( i = 0; i < ETH_MAC_ADDR_LEN; i++ ) {
1188        hw_addr[i] = eth_device[eth_dev_num].hw_addr[i];
1189    }
1190
1191    return XST_SUCCESS;
1192}
1193
1194
1195
1196/*****************************************************************************/
1197/**
1198 * Set / Get IP Address
1199 *
1200 * @param   eth_dev_num      - Ethernet device number
1201 * @param   ip_addr          - u8 pointer of IP address to set / get
1202 *
1203 * @return  int              - Status of the command:
1204 *                                 XST_SUCCESS - Command completed successfully
1205 *                                 XST_FAILURE - There was an error in the command
1206 *
1207 ******************************************************************************/
1208int eth_set_ip_addr(u32 eth_dev_num, u8 * ip_addr) {
1209
1210    int i;
1211   
1212    // Check the Ethernet device
1213    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1214        return XST_FAILURE;
1215    }
1216   
1217    // Update the IP Address
1218    for (i = 0; i < IP_ADDR_LEN; i++) {
1219        eth_device[eth_dev_num].ip_addr[i] = ip_addr[i];
1220    }
1221
1222    return XST_SUCCESS;
1223}
1224   
1225
1226
1227int eth_get_ip_addr(u32 eth_dev_num, u8 * ip_addr) {
1228
1229    int i;
1230
1231    // Check the Ethernet device
1232    if (eth_check_device(eth_dev_num) == XST_FAILURE) {
1233        return XST_FAILURE;
1234    }
1235   
1236    // Populate the IP Address
1237    for ( i = 0; i < IP_ADDR_LEN; i++) {
1238        ip_addr[i] = eth_device[eth_dev_num].ip_addr[i];
1239    }
1240
1241    return XST_SUCCESS;
1242}
1243
1244
1245
1246/*****************************************************************************/
1247/**
1248 * Get Internal Constants
1249 *
1250 * NOTE:  Can expand this section if more constants in WARP_ip_udp_config.h and
1251 *     WARP_ip_udp_device.h are needed outside the transport.
1252 *
1253 * @param   None
1254 *
1255 * @return  int              - Value of the constant
1256 *
1257 ******************************************************************************/
1258int eth_get_num_tx_descriptors() {
1259
1260    return WARP_IP_UDP_TXBD_CNT;
1261}
1262
1263
1264
1265/*****************************************************************************/
1266/**
1267 * Initialize the Ethernet Header
1268 *
1269 * @param   header           - Pointer to the Ethernet header
1270 * @param   src_hw_addr      - Source MAC address for Ethernet packet
1271 *
1272 * @return  None
1273 *
1274 ******************************************************************************/
1275void eth_init_header(ethernet_header * header, u8 * src_hw_addr) {
1276
1277    u32 i;
1278
1279    // Update the following static fields for a socket:
1280    //   - Source MAC address
1281    //
1282    if (src_hw_addr != NULL) { 
1283        for (i = 0; i < ETH_MAC_ADDR_LEN; i++) {   
1284            header->src_mac_addr[i] = src_hw_addr[i];
1285        }
1286    }
1287}
1288
1289
1290
1291/*****************************************************************************/
1292/**
1293 * Update the Ethernet Header
1294 *
1295 * @param   header           - Pointer to the Ethernet header
1296 * @param   dest_hw_addr     - Destination MAC address for Ethernet packet (big-endian)
1297 * @param   ethertype        - EtherType of the Ethernet packet (little-endian)
1298 *
1299 * @return  None
1300 *
1301 ******************************************************************************/
1302void eth_update_header(ethernet_header * header, u8 * dest_hw_addr, u16 ethertype) {
1303
1304    u32 i;
1305
1306    // Update the following fields:
1307    //   - Destination MAC address
1308    //   - EtherType
1309    //
1310    // NOTE:  We do not need to update the following fields because they are static for the socket:
1311    //   - Source MAC address
1312    //
1313    if (dest_hw_addr != NULL) { 
1314        for (i = 0; i < ETH_MAC_ADDR_LEN; i++) {   
1315            header->dest_mac_addr[i] = dest_hw_addr[i];
1316        }
1317    }
1318
1319    header->ethertype = Xil_Htons(ethertype);
1320}
1321
1322
1323
1324
1325/*****************************************************************************/
1326/**
1327 * Check memory range
1328 *
1329 * This will return whether any of the DMA accessible control structures for the
1330 * given Ethernet device are in the given memory range.  The structures are:
1331 *     - rx_bd_ptr
1332 *     - tx_bd_ptr
1333 *     - recv_buffers
1334 *     - send_buffers         (global structure)
1335 *     - socket_headers       (global structure)
1336 *     - dummy Ethernet frame (global structure)
1337 *
1338 * @param   eth_dev_num      - Ethernet device number
1339 * @param   hi_addr          - Maximum address of the memory range
1340 * @param   lo_addr          - Minimum address of the memory range
1341 *
1342 * @return  int              - Result
1343 *                                 WARP_IP_UDP_SUCCESS - No control structures in memory range
1344 *                                 WARP_IP_UDP_FAILURE - A control structure in memory range
1345 *
1346 ******************************************************************************/
1347int eth_not_in_memory_range(u32 eth_dev_num, u32 hi_addr, u32 lo_addr) {
1348
1349    u32 i;
1350    u32 temp   = 0;
1351    int status = WARP_IP_UDP_SUCCESS;
1352
1353    // If the Ethernet device is not initialized, then do not perform any checks
1354    if (eth_device[eth_dev_num].initialized) {
1355
1356        if (((u32)(eth_device[eth_dev_num].dma_rx_bd_ptr) >= lo_addr) && ((u32)(eth_device[eth_dev_num].dma_rx_bd_ptr) <= hi_addr)) { temp++; }
1357        if (((u32)(eth_device[eth_dev_num].dma_tx_bd_ptr) >= lo_addr) && ((u32)(eth_device[eth_dev_num].dma_tx_bd_ptr) <= hi_addr)) { temp++; }
1358
1359        for (i = 0; i < WARP_IP_UDP_ETH_0_NUM_RECV_BUF; i++) {
1360            if (((u32)(eth_device[eth_dev_num].recv_buffers[0].data) >= lo_addr) && ((u32)(eth_device[eth_dev_num].recv_buffers[0].data) <= hi_addr)) { temp++; }
1361        }
1362
1363        if (temp != 0) {
1364            status = WARP_IP_UDP_FAILURE;
1365        }
1366    }
1367
1368    return status;
1369}
1370
1371
1372
1373
1374/**********************************************************************************************************************/
1375/**
1376 * @brief Internal Methods
1377 *
1378 **********************************************************************************************************************/
1379 
1380 
1381/*****************************************************************************/
1382/**
1383 * Check the Ethernet device
1384 *
1385 * @param   eth_dev_num      - Ethernet device number
1386 *
1387 * @return  int              - Status of the command:
1388 *                                 XST_SUCCESS - Command completed successfully
1389 *                                 XST_FAILURE - There was an error in the command
1390 *
1391 ******************************************************************************/
1392int eth_check_device(u32 eth_dev_num) {
1393
1394    // Check to see if we are sending on a valid interface
1395    if (eth_dev_num >= WARP_IP_UDP_NUM_ETH_DEVICES) {
1396        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_NUM_DEV, 0, NULL, 0);
1397        return XST_FAILURE;
1398    }
1399   
1400    // Check if Ethernet device has been initialized
1401    if (!eth_device[eth_dev_num].initialized) {
1402        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_INTIALIZED, 0, NULL, 0);
1403        return XST_FAILURE;
1404    }
1405   
1406    return XST_SUCCESS;
1407}
1408
1409
1410
1411/*****************************************************************************/
1412/**
1413 * Check the Ethernet DMA for TX / RX error
1414 *
1415 * @param   eth_dev_num      - Ethernet device number
1416 *
1417 * @return  None
1418 *
1419 * @note    If there is a DMA error, then this function will reset the DMA.
1420 *
1421 ******************************************************************************/
1422void eth_check_dma(u32 eth_dev_num) {
1423
1424    XAxiDma_BdRing    * rx_ring_ptr;
1425    XAxiDma_BdRing    * tx_ring_ptr;
1426    u32                 rx_dma_error   = 0;
1427    u32                 tx_dma_error   = 0;
1428
1429    // Get the RX Buffer Descriptor Ring pointer
1430    rx_ring_ptr = (XAxiDma_BdRing *)eth_device[eth_dev_num].dma_rx_ring_ptr;
1431
1432    // Get the TX Buffer Descriptor Ring pointer
1433    tx_ring_ptr = (XAxiDma_BdRing *)eth_device[eth_dev_num].dma_tx_ring_ptr;
1434   
1435    // Check to see if we have a RX error
1436    rx_dma_error = XAxiDma_BdRingGetError(rx_ring_ptr);
1437   
1438    if (rx_dma_error) {
1439        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_RX_ERROR, &rx_dma_error, 1);
1440    }
1441   
1442    // Check to see if we have a TX error
1443    tx_dma_error = XAxiDma_BdRingGetError(tx_ring_ptr);
1444   
1445    if (tx_dma_error) {
1446        eth_print_err_msg(eth_dev_num, WARP_IP_UDP_ETH_ERROR_CODE, ETH_ERROR_CODE_DMA_TX_ERROR, &tx_dma_error, 1);
1447    }
1448       
1449    // If there is an error, reset the DMA
1450    if (rx_dma_error || tx_dma_error) {
1451        xil_printf("\n!!! Resetting the DMA !!!\n\n");
1452        XAxiDma_Reset((XAxiDma *)(eth_device[eth_dev_num].dma_ptr));
1453    }
1454}
1455
1456
1457
1458/*****************************************************************************/
1459/**
1460 * Consolidate error messages to reduce code overhead
1461 *
1462 * @param   eth_dev_num      - Ethernet device number
1463 * @param   msg_num          - Message number
1464 * @param   data             - Pointer to message data
1465 * @param   data_length      - Number of elements in data
1466 *
1467 * @return  None
1468 *
1469 ******************************************************************************/
1470void eth_print_err_msg(u32 eth_dev_num, u32 msg_num, u32 error_code, void * data, u32 data_length) {
1471
1472    u32 i;
1473
1474    xil_printf("ERROR in Ethernet %c:\n", warp_conv_eth_dev_num(eth_dev_num));
1475
1476    switch(msg_num) {
1477        case WARP_IP_UDP_ETH_ERROR_NUM_DEV:
1478            xil_printf("    Ethernet device number out of range:  %d\n", eth_dev_num);
1479            xil_printf("    Currently, there are %d supported Ethernet devices.\n", WARP_IP_UDP_NUM_ETH_DEVICES);
1480        break;
1481       
1482        case WARP_IP_UDP_ETH_ERROR_INTIALIZED:
1483            xil_printf("    WARP IP/UDP Library not configured to use Ethernet device.\n");
1484            xil_printf("    Please check library configuration in the BSP.\n" );
1485        break;
1486
1487        case WARP_IP_UDP_ETH_ERROR_CODE:
1488            xil_printf("    WARP IP/UDP transport error:  0x%08x\n", error_code);
1489            xil_printf("    See documentation for more information.\n");
1490        break;
1491    }
1492
1493    if (data_length > 0) {
1494        for (i = 0; i < data_length; i++) {
1495            xil_printf("        0x%08x\n", ((u32 *)data)[i]);
1496        }
1497    }
1498   
1499    xil_printf("\n");
1500}
1501
1502
1503
1504
1505/*****************************************************************************/
1506/**
1507 * Debug print functions
1508 *
1509 ******************************************************************************/
1510
1511#ifdef _DEBUG_
1512
1513void print_pkt(u8 * buf, int size) {
1514
1515    int i;
1516
1517    xil_printf("Ethernet Packet: (0x%x bytes)\n", size);
1518
1519    for (i = 0; i < size; i++) {
1520        xil_printf("%2x ", buf[i]);
1521        if ((((i + 1) % 16) == 0) && ((i + 1) != size)) {
1522            xil_printf("\n");
1523        }
1524    }
1525    xil_printf("\n\n");
1526}
1527
1528
1529void print_XAxiDma_Bd(XAxiDma_Bd * bd_ptr) {
1530
1531    int i;
1532
1533    xil_printf("Buffer Descriptor: 0x%x\n", bd_ptr);
1534   
1535    for ( i = 0; i < XAXIDMA_BD_NUM_WORDS; i++ ) {
1536        xil_printf("  Value[%2d]:        0x%x \n", i, (*bd_ptr)[i]);
1537    }
1538    xil_printf("\n");
1539}
1540
1541#endif
1542
1543
1544
Note: See TracBrowser for help on using the repository browser.