OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [eth/] [powerpc/] [fec/] [current/] [src/] [if_fec.c] - Blame information for rev 791

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      dev/if_fec.c
4
//
5
//      Fast ethernet device driver for PowerPC MPC8xxT boards
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas
44
// Date:         2001-01-21
45
// Purpose:      
46
// Description:  hardware driver for MPC8xxT FEC
47
//              
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
// Ethernet device driver for MPC8xx FEC
54
 
55
#include <pkgconf/system.h>
56
#include <pkgconf/devs_eth_powerpc_fec.h>
57
#include <pkgconf/io_eth_drivers.h>
58
#include CYGDAT_DEVS_FEC_ETH_INL
59
 
60
#ifdef CYGPKG_NET
61
#include <pkgconf/net.h>
62
#endif
63
 
64
#include <cyg/infra/cyg_type.h>
65
#include <cyg/infra/diag.h>
66
 
67
#include <cyg/hal/hal_arch.h>
68
#include <cyg/hal/hal_cache.h>
69
#include <cyg/hal/hal_intr.h>
70
#include <cyg/hal/drv_api.h>
71
#include <cyg/hal/hal_if.h>
72
#include <cyg/hal/ppc_regs.h>
73
 
74
#include <cyg/io/eth/netdev.h>
75
#include <cyg/io/eth/eth_drv.h>
76
 
77
#include "fec.h"
78
 
79
// Align buffers on a cache boundary
80
#define RxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE
81
#define TxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE
82
static unsigned char fec_eth_rxbufs[RxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
83
static unsigned char fec_eth_txbufs[TxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));
84
 
85
static struct fec_eth_info fec_eth0_info;
86
static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x7A, 0xBA};
87
static unsigned char enaddr[6];
88
#ifdef CYGPKG_REDBOOT
89
#include <pkgconf/redboot.h>
90
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
91
#include <redboot.h>
92
#include <flash_config.h>
93
RedBoot_config_option("Network hardware address [MAC]",
94
                      fec_esa,
95
                      ALWAYS_ENABLED, true,
96
                      CONFIG_ESA, 0
97
    );
98
#endif
99
#endif
100
 
101
#define os_printf diag_printf
102
 
103
// For fetching the ESA from RedBoot
104
#include <cyg/hal/hal_if.h>
105
#ifndef CONFIG_ESA
106
#define CONFIG_ESA 6
107
#endif
108
 
109
ETH_DRV_SC(fec_eth0_sc,
110
           &fec_eth0_info,   // Driver specific data
111
           "eth0",             // Name for this interface
112
           fec_eth_start,
113
           fec_eth_stop,
114
           fec_eth_control,
115
           fec_eth_can_send,
116
           fec_eth_send,
117
           fec_eth_recv,
118
           fec_eth_deliver,
119
           fec_eth_int,
120
           fec_eth_int_vector);
121
 
122
NETDEVTAB_ENTRY(fec_netdev,
123
                "fec_eth",
124
                fec_eth_init,
125
                &fec_eth0_sc);
126
 
127
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
128
#define _FEC_USE_INTS
129
#ifdef _FEC_USE_INTS
130
static cyg_interrupt fec_eth_interrupt;
131
static cyg_handle_t  fec_eth_interrupt_handle;
132
#else
133
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
134
static char fec_fake_int_stack[STACK_SIZE];
135
static cyg_thread fec_fake_int_thread_data;
136
static cyg_handle_t fec_fake_int_thread_handle;
137
static void fec_fake_int(cyg_addrword_t);
138
#endif // _FEC_USE_INTS
139
#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
140
static void          fec_eth_int(struct eth_drv_sc *data);
141
 
142
#ifndef FEC_ETH_INT
143
#error  FEC_ETH_INT must be defined
144
#endif
145
 
146
#ifndef FEC_ETH_PHY
147
#error  FEC_ETH_PHY must be defined
148
#endif
149
 
150
#ifndef FEC_ETH_RESET_PHY
151
#define FEC_ETH_RESET_PHY()
152
#endif
153
 
154
#ifndef FEC_EPPC_BD_OFFSET
155
#define FEC_EPPC_BD_OFFSET CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET
156
#endif
157
 
158
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_STATUS_LEDS
159
// LED activity [exclusive of hardware bits]
160
#ifndef _get_led
161
#define _get_led()  
162
#define _set_led(v) 
163
#endif
164
#ifndef LED_TxACTIVE
165
#define LED_TxACTIVE  7
166
#define LED_RxACTIVE  6
167
#define LED_IntACTIVE 5
168
#endif
169
 
170
static void
171
set_led(int bit)
172
{
173
  _set_led(_get_led() | (1<<bit));
174
}
175
 
176
static void
177
clear_led(int bit)
178
{
179
  _set_led(_get_led() & ~(1<<bit));
180
}
181
#else
182
#define set_led(b)
183
#define clear_led(b)
184
#endif
185
 
186
#ifdef _FEC_USE_INTS
187
// This ISR is called when the ethernet interrupt occurs
188
static int
189
fec_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
190
{
191
    cyg_drv_interrupt_mask(FEC_ETH_INT);
192
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
193
}
194
#endif
195
 
196
// Deliver function (ex-DSR) handles the ethernet [logical] processing
197
static void
198
fec_eth_deliver(struct eth_drv_sc * sc)
199
{
200
    fec_eth_int(sc);
201
#ifdef _FEC_USE_INTS
202
    // Allow interrupts to happen again
203
    cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
204
    cyg_drv_interrupt_unmask(FEC_ETH_INT);
205
#endif
206
}
207
 
208
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
209
//
210
// PHY unit access (via MII channel)
211
//
212
static void
213
phy_write(int reg, int addr, unsigned short data)
214
{
215
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
216
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
217
    int timeout = 0x100000;
218
 
219
    fec->iEvent = iEvent_MII;
220
    fec->MiiData = MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data;
221
    while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ;
222
}
223
 
224
static bool
225
phy_read(int reg, int addr, unsigned short *val)
226
{
227
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
228
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
229
    int timeout = 0x100000;
230
 
231
    fec->iEvent = iEvent_MII;
232
    fec->MiiData = MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA;
233
    while (!(fec->iEvent & iEvent_MII)) {
234
        if (--timeout <= 0) {
235
            return false;
236
        }
237
    }
238
    *val = fec->MiiData & 0x0000FFFF;
239
    return true;
240
}
241
#endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
242
 
243
//
244
// [re]Initialize the ethernet controller
245
//   Done separately since shutting down the device requires a 
246
//   full reconfiguration when re-enabling.
247
//   when 
248
static bool
249
fec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
250
{
251
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
252
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
253
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
254
    volatile struct fec_bd *rxbd, *txbd;
255
    unsigned char *RxBUF, *TxBUF;
256
    int cache_state, int_state;
257
    int i;
258
    int TxBD, RxBD;
259
 
260
    // Ignore unless device is idle/stopped
261
    if ((qi->fec->eControl & eControl_EN) != 0) {
262
        return true;
263
    }
264
 
265
    // Make sure interrupts are off while we mess with the device
266
    HAL_DISABLE_INTERRUPTS(int_state);
267
 
268
    // Ensure consistent state between cache and what the FEC sees
269
    HAL_DCACHE_IS_ENABLED(cache_state);
270
    if (cache_state) {
271
      HAL_DCACHE_SYNC();
272
      HAL_DCACHE_DISABLE();
273
    }
274
 
275
    // Shut down ethernet controller, in case it is already running
276
    fec->eControl = eControl_RESET;
277
    i = 0;
278
    while ((fec->eControl & eControl_RESET) != 0) {
279
      if (++i >= 500000) {
280
        os_printf("FEC Ethernet does not reset\n");
281
        if (cache_state)
282
          HAL_DCACHE_ENABLE();
283
        HAL_RESTORE_INTERRUPTS(int_state);
284
        return false;
285
      }
286
    }
287
 
288
    fec->iMask  = 0x0000000;  // Disables all interrupts
289
    fec->iEvent = 0xFFFFFFFF; // Clear all interrupts
290
    fec->iVector = (1<<29);   // Caution - must match FEC_ETH_INT above
291
 
292
    TxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM * sizeof(struct cp_bufdesc));
293
    RxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM * sizeof(struct cp_bufdesc));
294
    txbd = (struct fec_bd *)(TxBD + (cyg_uint32)eppc);
295
    rxbd = (struct fec_bd *)(RxBD + (cyg_uint32)eppc);
296
    qi->tbase = qi->txbd = qi->tnext = txbd;
297
    qi->rbase = qi->rxbd = qi->rnext = rxbd;
298
    qi->txactive = 0;
299
 
300
    RxBUF = &fec_eth_rxbufs[0];
301
    TxBUF = &fec_eth_txbufs[0];
302
 
303
    // setup buffer descriptors
304
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM;  i++) {
305
        rxbd->length = 0;
306
        rxbd->buffer = RxBUF;
307
        rxbd->ctrl   = FEC_BD_Rx_Empty;
308
        RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
309
        rxbd++;
310
    }
311
    rxbd--;
312
    rxbd->ctrl |= FEC_BD_Rx_Wrap;  // Last buffer
313
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM;  i++) {
314
        txbd->length = 0;
315
        txbd->buffer = TxBUF;
316
        txbd->ctrl   = 0;
317
        TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
318
        txbd++;
319
    }
320
    txbd--;
321
    txbd->ctrl |= FEC_BD_Tx_Wrap;  // Last buffer
322
 
323
    // Reset interrupts
324
    fec->iMask  = 0x00000000;  // No interrupts enabled
325
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
326
 
327
    // Initialize shared PRAM
328
    fec->RxRing = qi->rbase;
329
    fec->TxRing = qi->tbase;
330
 
331
    // Size of receive buffers
332
    fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;
333
 
334
    // Receiver control
335
    fec->RxControl = RxControl_MII | RxControl_DRT;
336
//    fec->RxControl = RxControl_MII | RxControl_LOOP | RxControl_PROM;
337
    fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame
338
 
339
    // Transmit control
340
    fec->TxControl = 4+0;
341
 
342
    // Use largest possible Tx FIFO
343
    fec->TxWater = 3;
344
 
345
    // DMA control
346
    fec->FunCode = ((2<<29) | (2<<27) | (0<<24));
347
 
348
    // MII speed control (50MHz)
349
    fec->MiiSpeed = 0x14;
350
 
351
    // Group address hash
352
    fec->hash[0] = 0;
353
    fec->hash[1] = 0;
354
 
355
    // Device physical address
356
    fec->addr[0] = *(unsigned long *)&enaddr[0];
357
    fec->addr[1] = *(unsigned long *)&enaddr[4];
358
    // os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]);
359
 
360
    // Enable device
361
    fec->eControl = eControl_EN | eControl_MUX;
362
    fec->RxUpdate = 0x0F0F0F0F;  // Any write tells machine to look for work
363
 
364
#ifdef _FEC_USE_INTS
365
    // Set up for interrupts
366
    fec->iMask = iEvent_TFINT | iEvent_TXB |
367
                 iEvent_RFINT | iEvent_RXB;
368
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
369
#endif
370
 
371
    if (cache_state)
372
        HAL_DCACHE_ENABLE();
373
 
374
    // Set LED state
375
    clear_led(LED_TxACTIVE);
376
    clear_led(LED_RxACTIVE);
377
 
378
    HAL_RESTORE_INTERRUPTS(int_state);
379
    return true;
380
}
381
 
382
//
383
// Initialize the interface - performed at system startup
384
// This function must set up the interface, including arranging to
385
// handle interrupts, etc, so that it may be "started" cheaply later.
386
//
387
static bool
388
fec_eth_init(struct cyg_netdevtab_entry *tab)
389
{
390
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
391
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
392
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
393
    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);
394
    int cache_state;
395
    unsigned long proc_rev;
396
    bool esa_ok;
397
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
398
    int phy_timeout = 5*1000;  // Wait 5 seconds max for link to clear
399
    bool phy_ok;
400
    unsigned short phy_state = 0;
401
#endif
402
 
403
    // Ensure consistent state between cache and what the FEC sees
404
    HAL_DCACHE_IS_ENABLED(cache_state);
405
    if (cache_state) {
406
      HAL_DCACHE_SYNC();
407
      HAL_DCACHE_DISABLE();
408
    }
409
 
410
    qi->fec = fec;
411
    fec_eth_stop(sc);  // Make sure it's not running yet
412
 
413
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
414
#ifdef _FEC_USE_INTS
415
    // Set up to handle interrupts
416
    cyg_drv_interrupt_create(FEC_ETH_INT,
417
                             CYGARC_SIU_PRIORITY_HIGH,
418
                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler
419
                             (cyg_ISR_t *)fec_eth_isr,
420
                             (cyg_DSR_t *)eth_drv_dsr,
421
                             &fec_eth_interrupt_handle,
422
                             &fec_eth_interrupt);
423
    cyg_drv_interrupt_attach(fec_eth_interrupt_handle);
424
    cyg_drv_interrupt_acknowledge(FEC_ETH_INT);
425
    cyg_drv_interrupt_unmask(FEC_ETH_INT);
426
#else // _FEC_USE_INTS
427
    // Hack - use a thread to simulate interrupts
428
    cyg_thread_create(1,                 // Priority
429
                      fec_fake_int,   // entry
430
                      (cyg_addrword_t)sc, // entry parameter
431
                      "CS8900 int",      // Name
432
                      &fec_fake_int_stack[0],         // Stack
433
                      STACK_SIZE,        // Size
434
                      &fec_fake_int_thread_handle,    // Handle
435
                      &fec_fake_int_thread_data       // Thread data structure
436
            );
437
    cyg_thread_resume(fec_fake_int_thread_handle);  // Start it
438
#endif
439
#endif
440
 
441
    // Set up parallel port for connection to ethernet tranceiver
442
    eppc->pio_pdpar = 0x1FFF;
443
    CYGARC_MFSPR( CYGARC_REG_PVR, proc_rev );
444
#define PROC_REVB 0x0020
445
    if ((proc_rev & 0x0000FFFF) == PROC_REVB) {
446
        eppc->pio_pddir = 0x1C58;
447
    } else {
448
        eppc->pio_pddir = 0x1FFF;
449
    }
450
 
451
    // Get physical device address
452
#ifdef CYGPKG_REDBOOT
453
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
454
    esa_ok = flash_get_config("fec_esa", enaddr, CONFIG_ESA);
455
#else
456
    esa_ok = false;
457
#endif
458
#else
459
    esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
460
                                         "fec_esa", enaddr, CONFIG_ESA);
461
#endif
462
    if (!esa_ok) {
463
        // Can't figure out ESA
464
        os_printf("FEC_ETH - Warning! ESA unknown\n");
465
        memcpy(&enaddr, &_default_enaddr, sizeof(enaddr));
466
    }
467
 
468
    // Configure the device
469
    if (!fec_eth_reset(sc, enaddr, 0)) {
470
        return false;
471
    }
472
 
473
    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
474
 
475
#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
476
    // Reset PHY (transceiver)
477
    FEC_ETH_RESET_PHY();
478
 
479
    phy_ok = 0;
480
    if (phy_read(PHY_BMSR, FEC_ETH_PHY, &phy_state)) {
481
        if ((phy_state & PHY_BMSR_LINK) !=  PHY_BMSR_LINK) {
482
            unsigned short reset_mode;
483
            int i;
484
            phy_write(PHY_BMCR, FEC_ETH_PHY, PHY_BMCR_RESET);
485
            for (i = 0;  i < 10;  i++) {
486
                phy_ok = phy_read(PHY_BMCR, FEC_ETH_PHY, &phy_state);
487
                if (!phy_ok) break;
488
                if (!(phy_state & PHY_BMCR_RESET)) break;
489
            }
490
            if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
491
                os_printf("FEC: Can't get PHY unit to soft reset: %x\n", phy_state);
492
                return false;
493
            }
494
 
495
            fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts
496
            reset_mode = PHY_BMCR_RESTART;
497
#ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_Auto
498
            reset_mode |= PHY_BMCR_AUTO_NEG;
499
#endif
500
#ifdef CYGNUM_DEVS_ETH_POWERPC_FEC_LINK_MODE_100Mb
501
            reset_mode |= PHY_BMCR_100MB;
502
#endif
503
            phy_write(PHY_BMCR, FEC_ETH_PHY, reset_mode);
504
            while (phy_timeout-- >= 0) {
505
                int ev = fec->iEvent;
506
                unsigned short state;
507
                fec->iEvent = ev;
508
                if (ev & iEvent_MII) {
509
                    phy_ok = phy_read(PHY_BMSR, FEC_ETH_PHY, &state);
510
                    if (phy_ok && (state & PHY_BMSR_LINK)) {
511
                        break;
512
                    } else {
513
                        CYGACC_CALL_IF_DELAY_US(10000);   // 10ms
514
                    }
515
                }
516
            }
517
            if (phy_timeout <= 0) {
518
                os_printf("** FEC Warning: PHY LINK UP failed\n");
519
            }
520
        }
521
        else {
522
            os_printf("** FEC Info: PHY LINK already UP \n");
523
        }
524
    }
525
#endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY
526
 
527
    // Initialize upper level driver
528
    (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
529
 
530
    if (cache_state)
531
      HAL_DCACHE_ENABLE();
532
 
533
    return true;
534
}
535
 
536
//
537
// This function is called to shut down the interface.
538
//
539
static void
540
fec_eth_stop(struct eth_drv_sc *sc)
541
{
542
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
543
 
544
    // Disable the device!
545
    qi->fec->eControl &= ~eControl_EN;
546
}
547
 
548
//
549
// This function is called to "start up" the interface.  It may be called
550
// multiple times, even when the hardware is already running.  It will be
551
// called whenever something "hardware oriented" changes and should leave
552
// the hardware ready to send/receive packets.
553
//
554
static void
555
fec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
556
{
557
    // Enable the device!
558
    fec_eth_reset(sc, enaddr, flags);
559
}
560
 
561
//
562
// This function is called for low level "control" operations
563
//
564
static int
565
fec_eth_control(struct eth_drv_sc *sc, unsigned long key,
566
                  void *data, int length)
567
{
568
#ifdef ETH_DRV_SET_MC_ALL
569
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
570
    volatile struct fec *fec = qi->fec;
571
#endif
572
 
573
    switch (key) {
574
    case ETH_DRV_SET_MAC_ADDRESS:
575
        return 0;
576
        break;
577
#ifdef ETH_DRV_SET_MC_ALL
578
    case ETH_DRV_SET_MC_ALL:
579
    case ETH_DRV_SET_MC_LIST:
580
        fec->RxControl &= ~RxControl_PROM;
581
        fec->hash[0] = 0xFFFFFFFF;
582
        fec->hash[1] = 0xFFFFFFFF;
583
        return 0;
584
        break;
585
#endif
586
    default:
587
        return 1;
588
        break;
589
    }
590
}
591
 
592
//
593
// This function is called to see if another packet can be sent.
594
// It should return the number of packets which can be handled.
595
// Zero should be returned if the interface is busy and can not send any more.
596
//
597
static int
598
fec_eth_can_send(struct eth_drv_sc *sc)
599
{
600
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
601
 
602
    return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM);
603
}
604
 
605
//
606
// This routine is called to send data to the hardware.
607
 
608
static void
609
fec_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
610
               int total_len, unsigned long key)
611
{
612
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
613
    volatile struct fec_bd *txbd, *txfirst;
614
    volatile char *bp;
615
    int i, txindex, cache_state;
616
 
617
    // Find a free buffer
618
    txbd = txfirst = qi->txbd;
619
    while (txbd->ctrl & FEC_BD_Tx_Ready) {
620
        // This buffer is busy, move to next one
621
        if (txbd->ctrl & FEC_BD_Tx_Wrap) {
622
            txbd = qi->tbase;
623
        } else {
624
            txbd++;
625
        }
626
        if (txbd == txfirst) {
627
#ifdef CYGPKG_NET
628
            panic ("No free xmit buffers");
629
#else
630
            os_printf("FEC Ethernet: No free xmit buffers\n");
631
#endif
632
        }
633
    }
634
    // Set up buffer
635
    bp = txbd->buffer;
636
    for (i = 0;  i < sg_len;  i++) {
637
        memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len);
638
        bp += sg_list[i].len;
639
    }
640
    txbd->length = total_len;
641
    txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
642
    qi->txkey[txindex] = key;
643
    // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
644
    HAL_DCACHE_IS_ENABLED(cache_state);
645
    if (cache_state) {
646
        HAL_DCACHE_FLUSH(txbd->buffer, txbd->length);  // Make sure no stale data
647
    }
648
    // Send it on it's way
649
    txbd->ctrl |= FEC_BD_Tx_Ready | FEC_BD_Tx_Last | FEC_BD_Tx_TC;
650
    qi->txactive++;
651
    qi->fec->TxUpdate = 0x01000000;  // Any write tells machine to look for work
652
    set_led(LED_TxACTIVE);
653
    // Remember the next buffer to try
654
    if (txbd->ctrl & FEC_BD_Tx_Wrap) {
655
        qi->txbd = qi->tbase;
656
    } else {
657
        qi->txbd = txbd+1;
658
    }
659
}
660
 
661
//
662
// This function is called when a packet has been received.  It's job is
663
// to prepare to unload the packet from the hardware.  Once the length of
664
// the packet is known, the upper layer of the driver can be told.  When
665
// the upper layer is ready to unload the packet, the internal function
666
// 'fec_eth_recv' will be called to actually fetch it from the hardware.
667
//
668
static void
669
fec_eth_RxEvent(struct eth_drv_sc *sc)
670
{
671
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
672
    volatile struct fec_bd *rxbd, *rxfirst;
673
 
674
    rxbd = rxfirst = qi->rnext;
675
    while (true) {
676
        if ((rxbd->ctrl & FEC_BD_Rx_Empty) == 0) {
677
            qi->rxbd = rxbd;  // Save for callback
678
            set_led(LED_RxACTIVE);     // Remove the CRC
679
            (sc->funs->eth_drv->recv)(sc, rxbd->length - 4);
680
        }
681
        if (rxbd->ctrl & FEC_BD_Rx_Wrap) {
682
            rxbd = qi->rbase;
683
        } else {
684
            rxbd++;
685
        }
686
        if (rxbd == rxfirst) {
687
            break;
688
        }
689
    }
690
    // Remember where we left off
691
    qi->rnext = (struct fec_bd *)rxbd;
692
    qi->fec->RxUpdate = 0x0F0F0F0F;  // Any write tells machine to look for work
693
}
694
 
695
//
696
// This function is called as a result of the "eth_drv_recv()" call above.
697
// It's job is to actually fetch data for a packet from the hardware once
698
// memory buffers have been allocated for the packet.  Note that the buffers
699
// may come in pieces, using a scatter-gather list.  This allows for more
700
// efficient processing in the upper layers of the stack.
701
//
702
static void
703
fec_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
704
{
705
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
706
    unsigned char *bp;
707
    int i, cache_state;
708
 
709
    bp = (unsigned char *)qi->rxbd->buffer;
710
    // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly!
711
    HAL_DCACHE_IS_ENABLED(cache_state);
712
    if (cache_state) {
713
        HAL_DCACHE_INVALIDATE(qi->rxbd->buffer, qi->rxbd->length);  // Make sure no stale data
714
    }
715
    for (i = 0;  i < sg_len;  i++) {
716
        if (sg_list[i].buf != 0) {
717
            memcpy((void *)sg_list[i].buf, bp, sg_list[i].len);
718
            bp += sg_list[i].len;
719
        }
720
    }
721
    qi->rxbd->ctrl |= FEC_BD_Rx_Empty;
722
    clear_led(LED_RxACTIVE);
723
}
724
 
725
static void
726
fec_eth_TxEvent(struct eth_drv_sc *sc)
727
{
728
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
729
    volatile struct fec_bd *txbd;
730
    int key, txindex;
731
 
732
    txbd = qi->tnext;
733
    // Note: TC field is used to indicate the buffer has/had data in it
734
    while ((txbd->ctrl & (FEC_BD_Tx_Ready|FEC_BD_Tx_TC)) == FEC_BD_Tx_TC) {
735
        txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
736
        if ((key = qi->txkey[txindex]) != 0) {
737
            qi->txkey[txindex] = 0;
738
            (sc->funs->eth_drv->tx_done)(sc, key, 0);
739
        }
740
        if (--qi->txactive == 0) {
741
          clear_led(LED_TxACTIVE);
742
        }
743
        txbd->ctrl &= ~FEC_BD_Tx_TC;
744
        if (txbd->ctrl & FEC_BD_Tx_Wrap) {
745
            txbd = qi->tbase;
746
        } else {
747
            txbd++;
748
        }
749
    }
750
    // Remember where we left off
751
    qi->tnext = (struct fec_bd *)txbd;
752
}
753
 
754
//
755
// Interrupt processing
756
//
757
static void
758
fec_eth_int(struct eth_drv_sc *sc)
759
{
760
    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;
761
    unsigned long event;
762
 
763
    while ((event = qi->fec->iEvent) != 0) {
764
        qi->fec->iEvent = event;  // Reset the bits we handled
765
        if ((event & iEvent_TFINT) != 0) {
766
            fec_eth_TxEvent(sc);
767
        }
768
        if ((event & iEvent_RFINT) != 0) {
769
            fec_eth_RxEvent(sc);
770
        }
771
    }
772
}
773
 
774
//
775
// Interrupt vector
776
//
777
static int
778
fec_eth_int_vector(struct eth_drv_sc *sc)
779
{
780
    return (FEC_ETH_INT);
781
}
782
 
783
#if defined(CYGINT_IO_ETH_INT_SUPPORT_REQUIRED) && ~defined(_FEC_USE_INTS)
784
void
785
fec_fake_int(cyg_addrword_t param)
786
{
787
    struct eth_drv_sc *sc = (struct eth_drv_sc *) param;
788
    int int_state;
789
 
790
    while (true) {
791
      cyg_thread_delay(1);  // 10ms
792
      HAL_DISABLE_INTERRUPTS(int_state);
793
      fec_eth_int(sc);
794
      HAL_RESTORE_INTERRUPTS(int_state);
795
    }
796
}
797
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.