summaryrefslogtreecommitdiff
path: root/bsp/nuvoton/libraries/ma35/rtt_port/gmac/synopGMAC_network_interface.c
blob: 48dc0070e80ffd84c4a67b5e8118b88bb2db942b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
/* ===================================================================================
 * Copyright (c) <2009> Synopsys, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software annotated with this license and associated documentation files
 * (the "Software"), to deal in the Software without restriction, including without
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * =================================================================================== */


/** \file
 * This is the network dependent layer to handle network related functionality.
 * This file is tightly coupled to neworking frame work of linux 2.6.xx kernel.
 * The functionality carried out in this file should be treated as an example only
 * if the underlying operating system is not Linux.
 *
 * \note Many of the functions other than the device specific functions
 *  changes for operating system other than Linux 2.6.xx
 * \internal
 *-----------------------------REVISION HISTORY-----------------------------------
 * Synopsys         01/Aug/2007             Created
 */

#include "NuMicro.h"
#include "synopGMAC_network_interface.h"


void synopGMAC_powerup_mac(synopGMACdevice *gmacdev)
{
    gmacdev->GMAC_Power_down = 0;    // Let ISR know that MAC is out of power down now
    if (synopGMAC_is_magic_packet_received(gmacdev))
        TR("GMAC wokeup due to Magic Pkt Received\n");
    if (synopGMAC_is_wakeup_frame_received(gmacdev))
        TR("GMAC wokeup due to Wakeup Frame Received\n");
    //Disable the assertion of PMT interrupt
    synopGMAC_pmt_int_disable(gmacdev);
    //Enable the mac and Dma rx and tx paths
    synopGMAC_rx_enable(gmacdev);
    synopGMAC_enable_dma_rx(gmacdev);

    synopGMAC_tx_enable(gmacdev);
    synopGMAC_enable_dma_tx(gmacdev);

    return;
}

void synopGMAC_powerdown_mac(synopGMACdevice *gmacdev)
{
    TR("Put the GMAC to power down mode..\n");

    // Disable the Dma engines in tx path
    gmacdev->GMAC_Power_down = 1;    // Let ISR know that Mac is going to be in the power down mode
    synopGMAC_disable_dma_tx(gmacdev);
    plat_delay(DEFAULT_LOOP_VARIABLE);      //allow any pending transmission to complete
    // Disable the Mac for both tx and rx
    synopGMAC_tx_disable(gmacdev);
    synopGMAC_rx_disable(gmacdev);
    plat_delay(DEFAULT_LOOP_VARIABLE);      //Allow any pending buffer to be read by host
    //Disable the Dma in rx path
    synopGMAC_disable_dma_rx(gmacdev);

    //enable the power down mode
    //synopGMAC_pmt_unicast_enable(gmacdev);

    //prepare the gmac for magic packet reception and wake up frame reception
    synopGMAC_magic_packet_enable(gmacdev);

    //gate the application and transmit clock inputs to the code. This is not done in this driver :).

    //enable the Mac for reception
    synopGMAC_rx_enable(gmacdev);

    //Enable the assertion of PMT interrupt
    synopGMAC_pmt_int_enable(gmacdev);

    //enter the power down mode
    synopGMAC_power_down_enable(gmacdev);

    return;
}

#if 0
void synopGMAC_powerdown_mac(synopGMACdevice *gmacdev)
{
    TR0("Put the GMAC to power down mode..\n");
    // Disable the Dma engines in tx path
    GMAC_Power_down = 1;    // Let ISR know that Mac is going to be in the power down mode
    synopGMAC_disable_dma_tx(gmacdev);
    plat_delay(DEFAULT_LOOP_VARIABLE);      //allow any pending transmission to complete
    // Disable the Mac for both tx and rx
    synopGMAC_tx_disable(gmacdev);
    synopGMAC_rx_disable(gmacdev);
    plat_delay(DEFAULT_LOOP_VARIABLE);      //Allow any pending buffer to be read by host
    //Disable the Dma in rx path
    synopGMAC_disable_dma_rx(gmacdev);

    //enable the power down mode
    //synopGMAC_pmt_unicast_enable(gmacdev);

    //prepare the gmac for magic packet reception and wake up frame reception
    synopGMAC_magic_packet_enable(gmacdev);

    //gate the application and transmit clock inputs to the code. This is not done in this driver :).

    //enable the Mac for reception
    synopGMAC_rx_enable(gmacdev);

    //Enable the assertion of PMT interrupt
    synopGMAC_pmt_int_enable(gmacdev);
    //enter the power down mode
    synopGMAC_power_down_enable(gmacdev);
    return;
}

void synopGMAC_powerup_mac(synopGMACdevice *gmacdev)
{
    GMAC_Power_down = 0;    // Let ISR know that MAC is out of power down now
    if (synopGMAC_is_magic_packet_received(gmacdev))
        TR("GMAC wokeup due to Magic Pkt Received\n");
    if (synopGMAC_is_wakeup_frame_received(gmacdev))
        TR("GMAC wokeup due to Wakeup Frame Received\n");
    //Disable the assertion of PMT interrupt
    synopGMAC_pmt_int_disable(gmacdev);
    //Enable the mac and Dma rx and tx paths
    synopGMAC_rx_enable(gmacdev);
    synopGMAC_enable_dma_rx(gmacdev);

    synopGMAC_tx_enable(gmacdev);
    synopGMAC_enable_dma_tx(gmacdev);
    return;
}
#endif

/**
  * This sets up the transmit Descriptor queue in ring or chain mode.
  * This function is tightly coupled to the platform and operating system
  * Device is interested only after the descriptors are setup. Therefore this function
  * is not included in the device driver API. This function should be treated as an
  * example code to design the descriptor structures for ring mode or chain mode.
  * This function depends on the pcidev structure for allocation consistent dma-able memory in case of linux.
  * This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
  * - Allocates the memory for the descriptors.
  * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
  * - Initialize the Busy and Next descriptors to first descriptor address.
  *     - Initialize the last descriptor with the endof ring in case of ring mode.
  * - Initialize the descriptors in chain mode.
  * @param[in] pointer to synopGMACdevice.
  * @param[in] pointer to pci_device structure.
  * @param[in] number of descriptor expected in tx descriptor queue.
  * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
  * \return 0 upon success. Error code upon failure.
  * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
  *  function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
  *  user should for gmacdev->TxDescCount to see how many descriptors are there in the chain. Should continue further
  *  only if the number of descriptors in the chain meets the requirements
  */

s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice *gmacdev, DmaDesc *first_desc, u32 no_of_desc, u32 desc_mode)
{
    s32 i;

    TR("Total size of memory required for Tx Descriptors in Ring Mode = 0x%08x\n", ((sizeof(DmaDesc) * no_of_desc)));

    gmacdev->TxDescCount = no_of_desc;

#ifdef CACHE_ON
    gmacdev->TxDesc      = (DmaDesc *)((u32)first_desc | UNCACHEABLE) ;
#else
    gmacdev->TxDesc      = first_desc;
#endif

    gmacdev->TxDescDma   = (dma_addr_t)first_desc;

    for (i = 0; i < gmacdev -> TxDescCount; i++)
    {
        synopGMAC_tx_desc_init_ring((DmaDesc *)gmacdev->TxDesc + i, i == gmacdev->TxDescCount - 1);

        TR("%02d %08x \n", i, (unsigned int)(gmacdev->TxDesc + i));
        TR("status: %08x\n", (unsigned int)((gmacdev->TxDesc + i))->status);
        TR("length: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->length));
        TR("buffer1: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->buffer1));
        TR("buffer2: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->buffer2));
        TR("extstatus: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->extstatus));
        TR("reserved1: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->reserved1));
        TR("timestamplow: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->timestamplow));
        TR("timestamphigh: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->timestamphigh));
//        TR("data1: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->data1));
//        TR("data2: %08x\n", (unsigned int)((gmacdev->TxDesc + i)->data2));
    }

    gmacdev->TxNext = 0;
    gmacdev->TxBusy = 0;
    gmacdev->TxNextDesc = gmacdev->TxDesc;
    gmacdev->TxBusyDesc = gmacdev->TxDesc;
    gmacdev->BusyTxDesc  = 0;

    return 0;
}


/**
  * This sets up the receive Descriptor queue in ring or chain mode.
  * This function is tightly coupled to the platform and operating system
  * Device is interested only after the descriptors are setup. Therefore this function
  * is not included in the device driver API. This function should be treated as an
  * example code to design the descriptor structures in ring mode or chain mode.
  * This function depends on the pcidev structure for allocation of consistent dma-able memory in case of linux.
  * This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
  * - Allocates the memory for the descriptors.
  * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
  * - Initialize the Busy and Next descriptors to first descriptor address.
  *     - Initialize the last descriptor with the endof ring in case of ring mode.
  * - Initialize the descriptors in chain mode.
  * @param[in] pointer to synopGMACdevice.
  * @param[in] pointer to pci_device structure.
  * @param[in] number of descriptor expected in rx descriptor queue.
  * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
  * \return 0 upon success. Error code upon failure.
  * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
  *  function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
  *  user should for gmacdev->RxDescCount to see how many descriptors are there in the chain. Should continue further
  *  only if the number of descriptors in the chain meets the requirements
  */
s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice *gmacdev, DmaDesc *first_desc, u32 no_of_desc, u32 desc_mode)
{
    s32 i;

    TR("total size of memory required for Rx Descriptors in Ring Mode = 0x%08x\n", ((sizeof(DmaDesc) * no_of_desc)));

    gmacdev->RxDescCount = no_of_desc;
#ifdef CACHE_ON
    gmacdev->RxDesc      = (DmaDesc *)((u32)first_desc | UNCACHEABLE) ;
#else
    gmacdev->RxDesc      = first_desc;
#endif
    gmacdev->RxDescDma   = (dma_addr_t)((u32)first_desc);

    for (i = 0; i < gmacdev -> RxDescCount; i++)
    {
        synopGMAC_rx_desc_init_ring((DmaDesc *)gmacdev->RxDesc + i, i == gmacdev->RxDescCount - 1);
        TR("%02d %08x \n", i, (unsigned int)(gmacdev->RxDesc + i));
    }


    gmacdev->RxNext = 0;
    gmacdev->RxBusy = 0;
    gmacdev->RxNextDesc = gmacdev->RxDesc;
    gmacdev->RxBusyDesc = gmacdev->RxDesc;

    gmacdev->BusyRxDesc   = 0;

    return 0;
}

/**
  * This gives up the receive Descriptor queue in ring or chain mode.
  * This function is tightly coupled to the platform and operating system
  * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
  * is completely handled by the operating system, this call is kept outside the device driver Api.
  * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
  * and network buffer deallocation.
  * This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
  * network buffer memory under linux.
  * The responsibility of this function is to
  *     - Free the network buffer memory if any.
  * - Fee the memory allocated for the descriptors.
  * @param[in] pointer to synopGMACdevice.
  * @param[in] pointer to pci_device structure.
  * @param[in] number of descriptor expected in rx descriptor queue.
  * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
  * \return 0 upon success. Error code upon failure.
  * \note No referece should be made to descriptors once this function is called. This function is invoked when the device is closed.
  */
void synopGMAC_giveup_rx_desc_queue(synopGMACdevice *gmacdev, u32 desc_mode)
{
    gmacdev->RxDesc    = NULL;
    gmacdev->RxDescDma = 0;
    return;
}

/**
  * This gives up the transmit Descriptor queue in ring or chain mode.
  * This function is tightly coupled to the platform and operating system
  * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
  * is completely handled by the operating system, this call is kept outside the device driver Api.
  * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
  * and network buffer deallocation.
  * This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
  * network buffer memory under linux.
  * The responsibility of this function is to
  *     - Free the network buffer memory if any.
  * - Fee the memory allocated for the descriptors.
  * @param[in] pointer to synopGMACdevice.
  * @param[in] pointer to pci_device structure.
  * @param[in] number of descriptor expected in tx descriptor queue.
  * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
  * \return 0 upon success. Error code upon failure.
  * \note No reference should be made to descriptors once this function is called. This function is invoked when the device is closed.
  */
void synopGMAC_giveup_tx_desc_queue(synopGMACdevice *gmacdev, u32 desc_mode)
{


    gmacdev->TxDesc    = NULL;
    gmacdev->TxDescDma = 0;
    return;
}

void synopGMAC_set_speed(synopGMACdevice *gmacdev)
{
    switch (gmacdev->Speed)
    {
    case SPEED1000:
        synopGMACClearBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        break;
    case SPEED100:
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacFESpeed100);
        break;
    case SPEED10:
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        synopGMACClearBits(gmacdev->MacBase, GmacConfig, GmacFESpeed100);
    default:
        break;
    }
}

/**
 * Function to transmit a given packet on the wire.
 * Whenever Linux Kernel has a packet ready to be transmitted, this function is called.
 * The function prepares a packet and prepares the descriptor and
 * enables/resumes the transmission.
 * @param[in] pointer to sk_buff structure.
 * @param[in] pointer to net_device structure.
 * \return Returns 0 on success and Error code on failure.
 * \note structure sk_buff is used to hold packet in Linux networking stacks.
 */
s32 synopGMAC_xmit_frames(synopGMACdevice *gmacdev, u8 *pkt_data, u32 pkt_len, u32 offload_needed, u32 ts)
{
    s32 status = 0;
    u32 dma_addr = (u32)pkt_data;

    /*Now we have skb ready and OS invoked this function. Lets make our DMA know about this*/
    status = synopGMAC_set_tx_qptr(gmacdev, dma_addr, pkt_len, dma_addr, offload_needed, ts);
    if (status < 0)
    {
        TR0("%s No More Free Tx Descriptors\n", __FUNCTION__);
        return -1;
    }

    /*Now force the DMA to start transmission*/
    synopGMAC_resume_dma_tx(gmacdev);

    return 0;
}


/**
 * Function to handle housekeeping after a packet is transmitted over the wire.
 * After the transmission of a packet DMA generates corresponding interrupt
 * (if it is enabled). It takes care of returning the sk_buff to the linux
 * kernel, updating the networking statistics and tracking the descriptors.
 * @param[in] pointer to net_device structure.
 * \return void.
 * \note This function runs in interrupt context
 */
void synop_handle_transmit_over(synopGMACdevice *gmacdev)
{
    s32 desc_index;
    u32 data1;
    u32 status;
    u32 length1;
    u32 dma_addr1;

    u32 ext_status;
    //u16 time_stamp_higher;
    u32 time_stamp_high;
    u32 time_stamp_low;

    /*Handle the transmit Descriptors*/
    do
    {
        desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1, &ext_status, &time_stamp_high, &time_stamp_low);
        //synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);

        if (desc_index >= 0 /*&& data1 != 0*/)
        {
            TR("Finished Transmit at Tx Descriptor %d for buffer = %08x whose status is %08x \n", desc_index, dma_addr1, status);

            if (synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status))
            {
                TR("Harware Failed to Insert IPV4 Header Checksum\n");
                gmacdev->synopGMACNetStats.tx_ip_header_errors++;
            }
            if (synopGMAC_is_tx_payload_checksum_error(gmacdev, status))
            {
                TR("Harware Failed to Insert Payload Checksum\n");
                gmacdev->synopGMACNetStats.tx_ip_payload_errors++;
            }

            if (synopGMAC_is_desc_valid(status))
            {
                gmacdev->synopGMACNetStats.tx_bytes += length1;
                gmacdev->synopGMACNetStats.tx_packets++;
                if (status & DescTxTSStatus)
                {
                    gmacdev->tx_sec = time_stamp_high;
                    gmacdev->tx_subsec = time_stamp_low;
                }
                else
                {
                    gmacdev->tx_sec = 0;
                    gmacdev->tx_subsec = 0;
                }
            }
            else
            {
                TR("Error in Status %08x\n", status);
                gmacdev->synopGMACNetStats.tx_errors++;
                gmacdev->synopGMACNetStats.tx_aborted_errors += synopGMAC_is_tx_aborted(status);
                gmacdev->synopGMACNetStats.tx_carrier_errors += synopGMAC_is_tx_carrier_error(status);
            }
        }
        gmacdev->synopGMACNetStats.collisions += synopGMAC_get_tx_collision_count(status);
    }
    while (desc_index >= 0);
}

/**
 * Function to Receive a packet from the interface.
 * After Receiving a packet, DMA transfers the received packet to the system memory
 * and generates corresponding interrupt (if it is enabled). This function prepares
 * the sk_buff for received packet after removing the ethernet CRC, and hands it over
 * to linux networking stack.
 *  - Updataes the networking interface statistics
 *  - Keeps track of the rx descriptors
 * @param[in] pointer to net_device structure.
 * \return void.
 * \note This function runs in interrupt context.
 */
extern DmaDesc *prevtx;   // for CRC test
s32 synop_handle_received_data(synopGMACdevice *gmacdev, PKT_FRAME_T **ppsPktFrame)
{
    u32 data1;
    u32 len;
    u32 status;
    u32 dma_addr1;

    u32 ext_status;
    //u16 time_stamp_higher;
    u32 time_stamp_high;
    u32 time_stamp_low;

    /* Handle the Receive Descriptors */
    if (synopGMAC_get_rx_qptr(gmacdev, &status,
                              &dma_addr1, NULL, &data1,
                              &ext_status, &time_stamp_high, &time_stamp_low) >= 0)
    {
        //synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
        //TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x TSHW:%08x \n",status,ext_status,dma_addr1, data1,time_stamp_high,time_stamp_low,time_stamp_higher);
        TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x\n", status, ext_status, dma_addr1, data1, time_stamp_high, time_stamp_low);

        TR("Received Data at Rx Descriptor for skb 0x%08x whose status is %08x\n", data1, status);

        if (synopGMAC_is_rx_desc_valid(status))
        {
            // Always enter this loop. synopGMAC_is_rx_desc_valid() also report invalid descriptor
            // if there's packet error generated by test code and drop it. But we need to execute ext_status
            // check code to tell what's going on.                                          --ya

            len =  synopGMAC_get_rx_desc_frame_length(status) - 4; //Not interested in Ethernet CRC bytes


            // Now lets check for the IPC offloading
            /*  Since we have enabled the checksum offloading in hardware, lets inform the kernel
                not to perform the checksum computation on the incoming packet. Note that ip header
                checksum will be computed by the kernel immaterial of what we inform. Similary TCP/UDP/ICMP
                pseudo header checksum will be computed by the stack. What we can inform is not to perform
                payload checksum.
                When CHECKSUM_UNNECESSARY is set kernel bypasses the checksum computation.
            */

            TR("Checksum Offloading will be done now\n");

            if (synopGMAC_is_ext_status(gmacdev, status))  // extended status present indicates that the RDES4 need to be probed
            {
                TR("Extended Status present\n");
                if (synopGMAC_ES_is_IP_header_error(gmacdev, ext_status))      // IP header (IPV4) checksum error
                {
                    //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
                    TR("(EXTSTS)Error in IP header error\n");
                    gmacdev->synopGMACNetStats.rx_ip_header_errors++;
                }
                if (synopGMAC_ES_is_rx_checksum_bypassed(gmacdev, ext_status))  // Hardware engine bypassed the checksum computation/checking
                {
                    TR("(EXTSTS)Hardware bypassed checksum computation\n");
                }
                if (synopGMAC_ES_is_IP_payload_error(gmacdev, ext_status))      // IP payload checksum is in error (UDP/TCP/ICMP checksum error)
                {
                    TR("(EXTSTS) Error in EP payload\n");
                    gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
                }
            }
            else     // No extended status. So relevant information is available in the status itself
            {
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxNoChkError)
                {
                    TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 4>  \n");
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrChkError)
                {
                    //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
                    TR(" Error in 16bit IPV4 Header Checksum <Chk Status = 6>  \n");
                    gmacdev->synopGMACNetStats.rx_ip_header_errors++;
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxLenLT600)
                {
                    TR("IEEE 802.3 type frame with Length field Lesss than 0x0600 <Chk Status = 0> \n");
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkBypass)
                {
                    TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 1>\n");
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxChkBypass)
                {
                    TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 3>  \n");
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxPayLoadChkError)
                {
                    TR(" TCP/UDP payload checksum Error <Chk Status = 5>  \n");
                    gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
                }
                if (synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkError)
                {
                    //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
                    TR(" Both IP header and Payload Checksum Error <Chk Status = 7>  \n");
                    gmacdev->synopGMACNetStats.rx_ip_header_errors++;
                    gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
                }
            }
            *ppsPktFrame = (PKT_FRAME_T *)dma_addr1;
#if 0
#ifdef CACHE_ON
            memcpy((void *)pu8rb, (void *)((u32)dma_addr1 | UNCACHEABLE), len);
#else
            memcpy((void *)pu8rb, (void *)((u32)dma_addr1), len);
#endif
            if (prevtx != NULL)
            {
#ifdef CACHE_ON
                memcpy((void *)pu8rb + len, (void *)((u32)(dma_addr1 | UNCACHEABLE) + len), 4);
#else
                memcpy((void *)pu8rb + len, (void *)((u32)dma_addr1 + len), 4);
#endif
            }
//            rb->rdy = 1;
//            rb->len = len;
#endif
            gmacdev->synopGMACNetStats.rx_packets++;
            gmacdev->synopGMACNetStats.rx_bytes += len;
            if (status & DescRxTSAvailable)
            {
                gmacdev->rx_sec = time_stamp_high;
                gmacdev->rx_subsec = time_stamp_low;
            }
            else
            {
                gmacdev->rx_sec = 0;
                gmacdev->rx_subsec = 0;
            }
            return len;
        } // if ( synopGMAC_is_rx_desc_valid(status) )
        else
        {
            /*Now the present skb should be set free*/
            TR("s: %08x\n", status);
            gmacdev->synopGMACNetStats.rx_errors++;
            gmacdev->synopGMACNetStats.collisions       += synopGMAC_is_rx_frame_collision(status);
            gmacdev->synopGMACNetStats.rx_crc_errors    += synopGMAC_is_rx_crc(status);
            gmacdev->synopGMACNetStats.rx_frame_errors  += synopGMAC_is_frame_dribbling_errors(status);
            gmacdev->synopGMACNetStats.rx_length_errors += synopGMAC_is_rx_frame_length_errors(status);
        }

    } //    /*Handle the Receive Descriptors*/

    return 0;
}

// mode 0: 1000Mbps, 1: 100Mbps, 2: 10Mbps
void synopGMAC_set_mode(synopGMACdevice *gmacdev, int mode)
{
    // Must stop Tx/Rx before change speed/mode
    synopGMAC_tx_disable(gmacdev);
    synopGMAC_rx_disable(gmacdev);
    switch (mode)
    {
    case SPEED1000:
        synopGMACClearBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        gmacdev->Speed = SPEED1000;
        break;
    case SPEED100:
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacFESpeed100);
        gmacdev->Speed = SPEED100;
        break;
    case SPEED10:
        synopGMACSetBits(gmacdev->MacBase, GmacConfig, GmacMiiGmii);
        synopGMACClearBits(gmacdev->MacBase, GmacConfig, GmacFESpeed100);
        gmacdev->Speed = SPEED10;
    default:
        break;
    }
    synopGMAC_tx_enable(gmacdev);
    synopGMAC_rx_enable(gmacdev);
}