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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [eth/] [current/] [src/] [net/] [eth_drv.c] - Blame information for rev 825

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/net/eth_drv.c
4
//
5
//      Hardware independent ethernet driver
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:         2000-01-10
45
// Purpose:      Hardware independent ethernet driver
46
// Description:  
47
//              
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
// High-level ethernet driver
54
 
55
#include <sys/param.h>
56
#include <sys/errno.h>
57
#include <sys/ioctl.h>
58
#include <sys/mbuf.h>
59
#include <sys/socket.h>
60
 
61
#include <net/if.h>
62
#include <net/if_dl.h>
63
#include <net/if_types.h>
64
#include <net/netisr.h>
65
 
66
#ifdef INET
67
#include <netinet/in.h>
68
#include <netinet/in_systm.h>
69
#include <netinet/in_var.h>
70
#include <netinet/ip.h>
71
#include <netinet/if_ether.h>
72
#endif
73
 
74
#ifndef NBPFILTER
75
#define NBPFILTER 0
76
#endif
77
 
78
#if NBPFILTER > 0
79
#include <net/bpf.h>
80
#include <net/bpfdesc.h>
81
#endif
82
 
83
#include <cyg/infra/cyg_ass.h>
84
#include <cyg/hal/drv_api.h>
85
#include <pkgconf/hal.h>
86
#include <cyg/hal/hal_if.h>
87
#include <pkgconf/io_eth_drivers.h> // module configury; SIMULATED_FAILURES
88
#include <pkgconf/net.h>            // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS?
89
 
90
#include <cyg/io/eth/eth_drv.h>
91
#include <cyg/io/eth/netdev.h>
92
 
93
#ifndef min
94
#define min( _x_, _y_ ) ((_x_) < (_y_) ? (_x_) : (_y_))
95
#endif
96
 
97
// ------------------------------------------------------------------------
98
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
99
 
100
#define noLOG_RANDOM 32 // so you can tell this is really being random
101
#ifdef LOG_RANDOM
102
static struct {
103
    unsigned int *which;
104
    unsigned int random;
105
    unsigned int r100;
106
} random_log[LOG_RANDOM];
107
 
108
static int random_index = 0;
109
#endif
110
 
111
static unsigned int
112
randomize( unsigned int *p )
113
{
114
    unsigned int r100;
115
    HAL_CLOCK_READ( &r100 );
116
    r100 ^= *p;
117
    *p = (r100 * 1103515245) + 12345;
118
    r100 &= 127;
119
    if ( r100 >= 100 ) // spread the overflow around evenly
120
        r100 = 4 * (r100 - 100);
121
    if ( r100 >= 100 ) // and again - (125,126,127=>100,104,108)
122
        r100 = 12 * (r100 - 100); // =>(0,48,96)
123
#ifdef LOG_RANDOM
124
    random_log[random_index].which  = p;
125
    random_log[random_index].random = *p;
126
    random_log[random_index].r100   = r100;
127
    random_index++;
128
    random_index &= (LOG_RANDOM-1);
129
#endif
130
    return r100;
131
}
132
 
133
#define SIMULATE_FAIL_SEND     1
134
#define SIMULATE_FAIL_RECV     2
135
#define SIMULATE_FAIL_CORRUPT  3
136
 
137
static struct simulated_failure_state {
138
    struct eth_drv_sc *sc;
139
    unsigned int r_tx_fail;
140
    unsigned int r_rx_fail;
141
    unsigned int r_rx_corrupt;
142
    cyg_tick_count_t droptime;
143
    cyg_tick_count_t passtime;
144
} simulated_failure_states[2] = {{0},{0}};
145
 
146
static int
147
simulate_fail( struct eth_drv_sc *sc, int which )
148
{
149
    struct simulated_failure_state *s;
150
 
151
    for ( s = &simulated_failure_states[0]; s < &simulated_failure_states[2];
152
          s++ ) {
153
        if ( 0 == s->sc ) {
154
            s->sc = sc;
155
            s->r_tx_fail    = (unsigned int)sc;
156
            s->r_rx_fail    = (unsigned int)sc ^ 0x01234567;
157
            s->r_rx_corrupt = (unsigned int)sc ^ 0xdeadbeef;
158
            s->droptime = 0;
159
            s->passtime = 0;
160
        }
161
        if ( sc == s->sc )
162
            break;
163
    }
164
    if ( &simulated_failure_states[2] == s ) {
165
        CYG_FAIL( "No free slot in simulated_failure_states[]" );
166
        return 1; // always fail
167
    }
168
 
169
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_LINE_CUT
170
    // Regardless of the question, we say "yes" during the period of
171
    // unpluggedness...
172
    {
173
        cyg_tick_count_t now = cyg_current_time();
174
        if ( now > s->droptime && 0 == s->passtime ) { // [initial condition]
175
            s->droptime = 0; // go into a passing phase
176
            (void)randomize( &s->r_tx_fail );
177
            (void)randomize( &s->r_rx_fail );
178
            (void)randomize( &s->r_rx_corrupt );
179
            s->passtime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt;
180
            s->passtime &= 0x3fff; // 16k cS is up to 160S, about 2.5 minutes
181
            s->passtime += now;
182
        }
183
        else if ( now > s->passtime && 0 == s->droptime ) {
184
            s->passtime = 0; // go into a dropping phase
185
            (void)randomize( &s->r_tx_fail );
186
            (void)randomize( &s->r_rx_fail );
187
            (void)randomize( &s->r_rx_corrupt );
188
            s->droptime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt;
189
            s->droptime &= 0x0fff; // 4k cS is up to 40S, about 1/2 a minute
190
            s->droptime += now;
191
        }
192
 
193
        if ( now < s->droptime )
194
            return 1; // Say "no"
195
    }
196
#endif
197
 
198
    switch ( which ) {
199
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX
200
    case SIMULATE_FAIL_SEND: {
201
        unsigned int z = randomize( &s->r_tx_fail );
202
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX;
203
    }
204
#endif
205
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX
206
    case SIMULATE_FAIL_RECV: {
207
        unsigned int z = randomize( &s->r_rx_fail );
208
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX;
209
    }
210
#endif
211
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX
212
    case SIMULATE_FAIL_CORRUPT: {
213
        unsigned int z = randomize( &s->r_rx_corrupt );
214
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX;
215
    }
216
#endif
217
    default:
218
        // do nothing - for when options above are not enabled.
219
    }
220
    return 0;
221
}
222
 
223
#define noLOG_CORRUPTION 32 // so you can tell this is really being random
224
#ifdef LOG_CORRUPTION
225
static struct {
226
    int len;
227
    int thislen;
228
    int off;
229
    unsigned char xor;
230
    unsigned char idx;
231
} corruption_log[LOG_CORRUPTION];
232
 
233
static int corruption_index = 0;
234
#endif
235
 
236
static void
237
simulate_fail_corrupt_sglist( struct eth_drv_sg *sg_list, int sg_len )
238
{
239
    unsigned int z, len, i, off;
240
    HAL_CLOCK_READ( &z );
241
    z += simulated_failure_states[0].r_rx_corrupt;
242
    z += simulated_failure_states[1].r_rx_corrupt;
243
 
244
    CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow in corrupt" );
245
 
246
    for ( i = 0, len = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ )
247
        len =+ sg_list[i].len;
248
 
249
    CYG_ASSERT( 1500 >= len, "sg...len > ether MTU" );
250
    if ( 14 >= len ) // normal ether header
251
        return;
252
 
253
    off = z & 2047; // next (2^N-1) > MTU
254
    while ( off > len )
255
        off -= len;
256
 
257
    for ( i = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ ) {
258
        if ( off < sg_list[i].len ) { // corrupt this one
259
            unsigned char *p = (unsigned char *)sg_list[i].buf;
260
            p[off] ^= (0xff & (z >> 11));
261
#ifdef LOG_CORRUPTION
262
            corruption_log[corruption_index].len = len;
263
            corruption_log[corruption_index].thislen = sg_list[i].len;
264
            corruption_log[corruption_index].off = off;
265
            corruption_log[corruption_index].xor = (0xff & (z >> 11));
266
            corruption_log[corruption_index].idx = i;
267
            corruption_index++;
268
            corruption_index &= (LOG_CORRUPTION-1);
269
#endif
270
            return;
271
        }
272
        off -= sg_list[i].len;
273
    }
274
    CYG_FAIL( "Didn't corrupt anything" );
275
}
276
 
277
#endif // CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
278
// ------------------------------------------------------------------------
279
 
280
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
281
 
282
#include <cyg/hal/hal_if.h>
283
 
284
// Use with care!  Local variable defined!
285
#define START_CONSOLE()                                                                 \
286
{   /* NEW BLOCK */                                                                     \
287
    int _cur_console =                                                                  \
288
        CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);      \
289
    {                                                                                   \
290
        int i;                                                                          \
291
        if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,                 \
292
                                          "info_console_force", &i,                     \
293
                                          CYGNUM_FLASH_CFG_TYPE_CONFIG_BOOL ) ) {       \
294
            if ( i ) {                                                                  \
295
                if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,         \
296
                                                  "info_console_number", &i,            \
297
                                                  CYGNUM_FLASH_CFG_TYPE_CONFIG_INT ) ){ \
298
                    /* Then i is the console to force it to: */                         \
299
                    CYGACC_CALL_IF_SET_CONSOLE_COMM( i );                               \
300
                }                                                                       \
301
            }                                                                           \
302
        }                                                                               \
303
    }
304
 
305
#define END_CONSOLE()                                   \
306
    CYGACC_CALL_IF_SET_CONSOLE_COMM(_cur_console);      \
307
}   /* END BLOCK */
308
 
309
#else
310
#define START_CONSOLE()
311
#define END_CONSOLE()
312
#endif
313
// ------------------------------------------------------------------------
314
 
315
#ifdef CYGPKG_NET_FREEBSD_STACK
316
extern char *_ioctl_name(u_long cmd);
317
typedef void void_fun(void *);
318
#endif
319
 
320
static int  eth_drv_ioctl(struct ifnet *, u_long, caddr_t);
321
static void eth_drv_send(struct ifnet *);
322
static void eth_drv_start(struct eth_drv_sc *sc);
323
 
324
#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG 
325
int cyg_io_eth_net_debug = CYGDBG_IO_ETH_DRIVERS_DEBUG_VERBOSITY;
326
#endif
327
 
328
// Interfaces exported to drivers
329
 
330
static void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr);
331
static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);
332
static void eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRESS key, int status);
333
 
334
struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};
335
 
336
//
337
// This function is called during system initialization to register a
338
// network interface with the system.
339
//
340
static void
341
eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
342
{
343
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
344
#ifdef CYGPKG_NET_FREEBSD_STACK
345
    int unit;
346
    char *np, *xp;
347
#endif
348
 
349
    // Set up hardware address
350
    if (NULL != enaddr)
351
        bcopy(enaddr, &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
352
 
353
    // Initialize ifnet structure
354
    ifp->if_softc = sc;
355
    ifp->if_start = eth_drv_send;
356
    ifp->if_ioctl = eth_drv_ioctl;
357
    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
358
#ifdef IFF_NOTRAILERS
359
    ifp->if_flags |= IFF_NOTRAILERS;
360
#endif
361
#ifdef CYGPKG_NET_FREEBSD_STACK
362
    ifp->if_name = xp = ifp->if_xname;
363
    np = (char *)sc->dev_name;
364
    unit = 0;
365
    while (*np && !((*np >= '0') && (*np <= '9'))) *xp++ = *np++;
366
    if (*np) {
367
        *xp = '\0';
368
        while (*np) {
369
            unit = (unit * 10) + (*np++ - '0');
370
        }
371
        ifp->if_unit = unit;
372
    }
373
    ifp->if_init = (void_fun *)eth_drv_start;
374
    ifp->if_output = ether_output;
375
#else
376
    bcopy((void *)sc->dev_name, ifp->if_xname, IFNAMSIZ);
377
#endif
378
    sc->state = 0;
379
 
380
    // Attach the interface
381
#ifdef CYGPKG_NET_FREEBSD_STACK
382
    ether_ifattach(ifp, 0);
383
#else
384
    if_attach(ifp);
385
    ether_ifattach(ifp);
386
#endif
387
 
388
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
389
// Set up interfaces so debug environment can share this device
390
    {
391
        void *dbg = CYGACC_CALL_IF_DBG_DATA();
392
        if (!dbg) {
393
            CYGACC_CALL_IF_DBG_DATA_SET((void *)sc);
394
        }
395
    }
396
#endif
397
}
398
 
399
//
400
// This [internal] function will be called to stop activity on an interface.
401
//
402
static void
403
eth_drv_stop(struct eth_drv_sc *sc)
404
{
405
    (sc->funs->stop)(sc);
406
    sc->state &= ~ETH_DRV_STATE_ACTIVE;
407
}
408
 
409
//
410
// This [internal] function will be called to start activity on an interface.
411
//
412
static void
413
eth_drv_start(struct eth_drv_sc *sc)
414
{
415
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
416
 
417
    // Perform any hardware initialization
418
    (sc->funs->start)(sc, (unsigned char *)&sc->sc_arpcom.ac_enaddr, 0);
419
#ifdef CYGPKG_NET_FREEBSD_STACK
420
    // resend multicast addresses if present
421
    if(ifp->if_multiaddrs.lh_first && ifp->if_ioctl) {
422
        int s = splimp();
423
        ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
424
        splx(s);
425
    }
426
#endif
427
    // Set 'running' flag, and clear output active flag.
428
    ifp->if_flags |= IFF_RUNNING;
429
    ifp->if_flags &= ~IFF_OACTIVE;
430
    sc->state |= ETH_DRV_STATE_ACTIVE;
431
    eth_drv_send(ifp);  // Try and start up transmit
432
}
433
 
434
//
435
// This function supports "I/O control" operations on an interface.
436
//
437
static int
438
eth_drv_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
439
{
440
    struct eth_drv_sc *sc = ifp->if_softc;
441
#ifndef CYGPKG_NET_FREEBSD_STACK
442
    struct ifaddr *ifa = (struct ifaddr *) data;
443
#endif
444
    struct ifreq *ifr = (struct ifreq *)data;
445
    int     s, error = 0;
446
 
447
// DEBUG
448
#ifdef CYGPKG_NET_FREEBSD_STACK
449
    log(LOG_IOCTL, "%s: cmd: %s, data:\n", __FUNCTION__, _ioctl_name(cmd));
450
    log_dump(LOG_IOCTL, data, 32);
451
#endif
452
// DEBUG
453
 
454
    s = splnet();
455
 
456
#ifdef CYGPKG_NET_FREEBSD_STACK
457
    if ((error = ether_ioctl(ifp, cmd, data)) > 0) {
458
#else
459
    if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
460
#endif
461
        splx(s);
462
        return error;
463
    }
464
 
465
    switch (cmd) {
466
 
467
    case SIOCSIFADDR:
468
#ifndef CYGPKG_NET_FREEBSD_STACK // Now in if_ethersubr.c
469
        ifp->if_flags |= IFF_UP;
470
 
471
        switch (ifa->ifa_addr->sa_family) {
472
#ifdef INET
473
        case AF_INET:
474
            eth_drv_start(sc);
475
            arp_ifinit(&sc->sc_arpcom, ifa);
476
            break;
477
#endif
478
        default:
479
            eth_drv_start(sc);
480
            break;
481
        }
482
#endif // CYGPKG_NET_FREEBSD_STACK
483
        break;
484
 
485
    case SIOCGIFHWADDR:
486
        // Get hardware (MAC) address
487
        ifr->ifr_hwaddr.sa_family = AF_INET;
488
        bcopy(&sc->sc_arpcom.ac_enaddr, &ifr->ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
489
        break;
490
 
491
    case SIOCSIFHWADDR:
492
        // Set hardware (MAC) address
493
        bcopy(&ifr->ifr_hwaddr.sa_data, &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
494
        if ((sc->funs->control)(sc, ETH_DRV_SET_MAC_ADDRESS,
495
                                &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN)) {
496
            error = EINVAL;
497
        }
498
        break;
499
 
500
#ifdef SIOCGIFSTATS
501
    case SIOCGIFSTATS:
502
#ifdef SIOCGIFSTATSUD
503
    case SIOCGIFSTATSUD:
504
#endif
505
        // Get interface statistics:
506
        if ((sc->funs->control)(sc, (cmd == SIOCGIFSTATS)
507
                                ? ETH_DRV_GET_IF_STATS
508
                                : ETH_DRV_GET_IF_STATS_UD,
509
                                data, 0 ) ) {
510
            error = EINVAL;
511
        }
512
        break;
513
#endif // SIOCGIFSTATS
514
 
515
    case SIOCSIFFLAGS:
516
        if ((ifp->if_flags & IFF_UP) == 0 &&
517
            (ifp->if_flags & IFF_RUNNING) != 0) {
518
            /*
519
             * If interface is marked down and it is running, then
520
             * stop it.
521
             */
522
            eth_drv_stop(sc);
523
            ifp->if_flags &= ~IFF_RUNNING;
524
        } else
525
            if ((ifp->if_flags & IFF_UP) != 0 &&
526
                (ifp->if_flags & IFF_RUNNING) == 0) {
527
                /*
528
                 * If interface is marked up and it is stopped, then
529
                 * start it.
530
                 */
531
                eth_drv_start(sc);
532
            } else {
533
                /*
534
                 * Reset the interface to pick up changes in any other
535
                 * flags that affect hardware registers.
536
                 */
537
                eth_drv_stop(sc);
538
                eth_drv_start(sc);
539
            }
540
        break;
541
 
542
#ifdef CYGPKG_NET_FREEBSD_STACK
543
    case SIOCADDMULTI:
544
    case SIOCDELMULTI:
545
    {
546
        struct ifmultiaddr *ifma;
547
        struct eth_drv_mc_list mc_list;
548
        int mode = (ifp->if_flags & IFF_ALLMULTI) ? ETH_DRV_SET_MC_ALL :
549
                                                    ETH_DRV_SET_MC_LIST;
550
 
551
#ifdef DEBUG
552
        log(LOG_ADDR, "%s Multi\n",(cmd == SIOCADDMULTI) ? "Add" : "Del");
553
#endif
554
        mc_list.len = 0;
555
        LIST_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
556
            if (ifma->ifma_addr->sa_family != AF_LINK) {
557
              continue;
558
            }
559
#ifdef DEBUG
560
            log_dump(LOG_ADDR, LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 6);
561
#endif
562
            if ((LLADDR((struct sockaddr_dl *)ifma->ifma_addr)[0] & 0x01) == 0) {
563
#ifdef DEBUG
564
                log(LOG_ADDR, "** Not a multicast address - ignored\n");
565
#endif
566
                continue;
567
            }
568
            if (mc_list.len < ETH_DRV_MAX_MC) {
569
                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
570
                      mc_list.addrs[mc_list.len], ETHER_ADDR_LEN);
571
                mc_list.len++;
572
            } else {
573
                mode = ETH_DRV_SET_MC_ALL;
574
            }
575
        }
576
        // Note: drivers may behave like IFF_ALLMULTI if the list is 
577
        // more than their hardware can handle, e.g. some can only handle 1.
578
        if ((sc->funs->control)(sc, mode, &mc_list, sizeof(mc_list))) {
579
            diag_printf( "[%s] Warning: Driver can't set multi-cast mode\n",
580
                         __FUNCTION__ );
581
            error = EINVAL;
582
        }
583
        break;
584
    }
585
#endif
586
 
587
    default:
588
        error = EINVAL;
589
        break;
590
    }
591
 
592
    splx(s);
593
    return (error);
594
}
595
 
596
//
597
// Control whether any special locking needs to take place if we intend to
598
// cooperate with a ROM monitor (e.g. RedBoot) using this hardware.  
599
//
600
#if defined(CYGSEM_HAL_USE_ROM_MONITOR) && \
601
    defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) && \
602
   !defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)
603
 
604
// Indicate that special locking precautions are warranted.
605
#define _LOCK_WITH_ROM_MONITOR
606
 
607
// This defines the [well known] channel that RedBoot will use when it is
608
// using the network hardware for the debug channel.
609
#define RedBoot_TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
610
 
611
// Define this if you ever need to call 'diag_printf()' from interrupt level
612
// code (ISR) and the debug channel might be using the network hardware. If
613
// this is not the case, then disabling interrupts here is over-kill.
614
//#define _LOCK_USING_INTERRUPTS
615
#endif
616
 
617
//
618
// This routine is called to start transmitting if there is data
619
// available.
620
//
621
static void
622
eth_drv_send(struct ifnet *ifp)
623
{
624
    struct eth_drv_sc *sc = ifp->if_softc;
625
#if MAX_ETH_DRV_SG > 64
626
    static  // Avoid large stack requirements
627
#endif
628
    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
629
    int sg_len;
630
    struct mbuf *m0, *m;
631
    int len, total_len;
632
    unsigned char *data;
633
#ifdef _LOCK_WITH_ROM_MONITOR
634
#ifdef _LOCK_USING_INTERRUPTS
635
    cyg_uint32 ints;
636
#endif
637
    bool need_lock = false;
638
    int debug_chan;
639
#endif // _LOCK_WITH_ROM_MONITOR
640
 
641
    // This is now only called from network threads, so no guarding is
642
    // required; locking is in place via the splfoo() mechanism already.
643
 
644
    if ((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) {
645
         return;
646
    }
647
 
648
    // If nothing on the queue, no need to bother hardware
649
    if (IF_IS_EMPTY(&ifp->if_snd)) {
650
        return;
651
    }
652
 
653
    while ((sc->funs->can_send)(sc) > 0) {
654
        IF_DEQUEUE(&ifp->if_snd, m0);
655
        if (m0 == 0) {
656
            break;
657
        }
658
 
659
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
660
        if ( simulate_fail( sc, SIMULATE_FAIL_SEND ) ) {
661
            // must free the mbufs
662
            m_freem(m0);
663
            continue; // next packet to send
664
        }
665
#endif
666
 
667
#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
668
        if (cyg_io_eth_net_debug) {
669
            START_CONSOLE();
670
            diag_printf("Sending %d bytes\n", m0->m_pkthdr.len);
671
            END_CONSOLE();
672
        }
673
#endif
674
 
675
        /* We need to use m->m_pkthdr.len, so require the header */
676
        if ((m0->m_flags & M_PKTHDR) == 0)
677
            panic("eth_drv_send: no header mbuf");
678
 
679
#if NBPFILTER > 0
680
        /* Tap off here if there is a BPF listener. */
681
        if (ifp->if_bpf)
682
            bpf_mtap(ifp->if_bpf, m0);
683
#endif
684
 
685
        // Extract data pointers (don't actually move data here)
686
        sg_len = 0;  total_len = 0;
687
        for (m = m0; m ; m = m->m_next) {
688
            data = mtod(m, u_char *);
689
            len = m->m_len;
690
            total_len += len;
691
            sg_list[sg_len].buf = (CYG_ADDRESS)data;
692
            sg_list[sg_len].len = len;
693
            if ( len )
694
                sg_len++;
695
#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
696
            if (cyg_io_eth_net_debug) {
697
                START_CONSOLE();
698
                diag_printf("xmit %d bytes at %p sg[%d]\n", len, data, sg_len);
699
                if ( cyg_io_eth_net_debug > 1)
700
                    diag_dump_buf(data, len);
701
                END_CONSOLE();
702
            }
703
#endif
704
            if (m->m_next && (MAX_ETH_DRV_SG <= sg_len)) {
705
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
706
                int needed = 0;
707
                struct mbuf *m1;
708
                for (m1 = m0; m1 ; m1 = m1->m_next) needed++;
709
                START_CONSOLE();
710
                diag_printf("too many mbufs to tx, %d > %d, need %d\n",
711
                            sg_len, MAX_ETH_DRV_SG, needed );
712
                END_CONSOLE();
713
#endif
714
                sg_len = 0;
715
                break; // drop it on the floor
716
            }
717
        }
718
 
719
#ifdef _LOCK_WITH_ROM_MONITOR
720
        // Firm lock on this portion of the driver.  Since we are about to
721
        // start messing with the actual hardware, it is imperative that the
722
        // current thread not loose control of the CPU at this time.  Otherwise,
723
        // the hardware could be left in an unusable state.  This caution is
724
        // only warranted if there is a possibility of some other thread trying
725
        // to use the hardware simultaneously.  The network stack would prevent
726
        // this implicitly since all accesses are controlled by the "splX()"
727
        // locks, but if there is a ROM monitor, such as RedBoot, also using
728
        // the hardware, all bets are off.
729
 
730
        // Note: these operations can be avoided if it were well known that
731
        // RedBoot was not using the network hardware for diagnostic I/O.  This
732
        // can be inferred by checking which I/O channel RedBoot is currently
733
        // hooked to.
734
        debug_chan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
735
        if (debug_chan == RedBoot_TCP_CHANNEL) {
736
            need_lock = true;
737
#ifdef _LOCK_USING_INTERRUPTS
738
            HAL_DISABLE_INTERRUPTS(ints);
739
#endif
740
            cyg_drv_dsr_lock();
741
        }
742
#endif // _LOCK_WITH_ROM_MONITOR
743
 
744
        // Tell hardware to send this packet
745
        if ( sg_len )
746
            (sc->funs->send)(sc, sg_list, sg_len, total_len, (unsigned long)m0);
747
 
748
#ifdef _LOCK_WITH_ROM_MONITOR
749
        // Unlock the driver & hardware.  It can once again be safely shared.
750
        if (need_lock) {
751
            cyg_drv_dsr_unlock();
752
#ifdef _LOCK_USING_INTERRUPTS
753
            HAL_RESTORE_INTERRUPTS(ints);
754
#endif
755
        }
756
#endif // _LOCK_WITH_ROM_MONITOR
757
#undef _LOCK_WITH_ROM_MONITOR
758
    }
759
}
760
 
761
//
762
// This function is called from the hardware driver when an output operation
763
// has completed - i.e. the packet has been sent.
764
//
765
static struct mbuf *mbuf_key;
766
 
767
static void
768
eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRESS key, int status)
769
{
770
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
771
    struct mbuf *m0 = (struct mbuf *)key;
772
    CYGARC_HAL_SAVE_GP();
773
 
774
    // Check for errors here (via 'status')
775
    ifp->if_opackets++;
776
    // Done with packet
777
 
778
    // Guard against a NULL return - can be caused by race conditions in
779
    // the driver, this is the neatest fixup:
780
    if (m0) {
781
        mbuf_key = m0;
782
        m_freem(m0);
783
    }
784
    // Start another if possible
785
    eth_drv_send(ifp);
786
    CYGARC_HAL_RESTORE_GP();
787
}
788
 
789
//
790
// This function is called from a hardware driver to indicate that an input
791
// packet has arrived.  The routine will set up appropriate network resources
792
// (mbuf's) to hold the data and call back into the driver to retrieve the data.
793
//
794
static void
795
eth_drv_recv(struct eth_drv_sc *sc, int total_len)
796
{
797
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
798
    struct ether_header _eh, *eh=&_eh;
799
    struct mbuf *top, **mp, *m;
800
    int mlen;
801
    caddr_t data;
802
#if MAX_ETH_DRV_SG > 64
803
    static  // Avoid large stack requirements
804
#endif
805
    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
806
    int sg_len;
807
 
808
    if ((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) {
809
        return;  // Interface not up, ignore this request
810
    }
811
 
812
    CYG_ASSERT( 0 != total_len, "total_len is zero!" );
813
    CYG_ASSERT( 0 <= total_len, "total_len is negative!" );
814
    CYG_ASSERT( sizeof( struct ether_header ) <= total_len,
815
                "No ether header here!" );
816
 
817
    if ( total_len < sizeof( struct ether_header ) )
818
        // Our arithmetic below would go wrong
819
        return;
820
 
821
    CYGARC_HAL_SAVE_GP();  // This is down here to make matching restore neat
822
 
823
    /* Pull packet off interface. */
824
    MGETHDR(m, M_DONTWAIT, MT_DATA);
825
    if (m == 0) {
826
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
827
        START_CONSOLE();
828
        diag_printf("warning: eth_recv out of MBUFs\n");
829
#ifdef CYGDBG_NET_SHOW_MBUFS        
830
        cyg_net_show_mbufs();
831
#endif
832
        END_CONSOLE();
833
#endif
834
    }
835
 
836
    // Set up buffers
837
    // Unload ethernet header separately so IP/UDP/TCP headers are aligned
838
    sg_list[0].buf = (CYG_ADDRESS)eh;
839
    sg_list[0].len = sizeof(*eh);
840
    sg_len = 1;
841
 
842
    // Compute total length (minus ethernet header)
843
    total_len -= sizeof(*eh);
844
 
845
    top = 0;
846
    mlen = MHLEN;
847
    mp = &top;
848
 
849
    if (m) {
850
        m->m_pkthdr.rcvif = ifp;
851
        m->m_pkthdr.len = total_len;
852
    } else {
853
        sg_list[sg_len].buf = (CYG_ADDRESS)0;
854
        sg_list[sg_len].len = total_len;
855
        sg_len++;
856
        total_len = 0;
857
    }
858
 
859
    while (total_len > 0) {
860
        if (top) {
861
            MGET(m, M_DONTWAIT, MT_DATA);
862
            if (m == 0) {
863
                m_freem(top);
864
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
865
                START_CONSOLE();
866
                diag_printf("out of MBUFs [2]");
867
#ifdef CYGDBG_NET_SHOW_MBUFS                
868
                cyg_net_show_mbufs();
869
#endif
870
                END_CONSOLE();
871
#endif
872
                sg_list[sg_len].buf = (CYG_ADDRESS)0;
873
                sg_list[sg_len].len = total_len;
874
                sg_len++;
875
                top = 0;
876
                break;
877
            }
878
            mlen = MLEN;
879
        }
880
        if (total_len >= MINCLSIZE) {
881
            MCLGET(m, M_DONTWAIT);
882
            if ((m->m_flags & M_EXT) == 0) {
883
                m_freem(top);
884
                m_free(m);
885
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
886
                START_CONSOLE();
887
                diag_printf("warning: eth_recv out of MBUFs\n");
888
#ifdef CYGDBG_NET_SHOW_MBUFS                
889
                cyg_net_show_mbufs();
890
#endif
891
                END_CONSOLE();
892
#endif
893
                sg_list[sg_len].buf = (CYG_ADDRESS)0;
894
                sg_list[sg_len].len = total_len;
895
                sg_len++;
896
                top = 0;
897
                break;
898
            }
899
            mlen = MCLBYTES;
900
        }
901
        m->m_len = mlen = min(total_len, mlen);
902
        total_len -= mlen;
903
        data = mtod(m, caddr_t);
904
        sg_list[sg_len].buf = (CYG_ADDRESS)data;
905
        sg_list[sg_len].len = mlen;
906
        sg_len++;
907
        *mp = m;
908
        mp = &m->m_next;
909
    } // endwhile
910
 
911
    // Ask hardware to unload buffers
912
    (sc->funs->recv)(sc, sg_list, sg_len);
913
 
914
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
915
    if ( simulate_fail( sc, SIMULATE_FAIL_RECV ) ) {
916
        // toss the packet - note that some hardware gets
917
        // fussy if the packet isn't "unloaded", thus we
918
        // have to wait until now to throw it away
919
        if (top) {
920
            m_free(top);
921
        }
922
        ifp->if_ierrors++;
923
        return;
924
    }
925
 
926
    if ( simulate_fail( sc, SIMULATE_FAIL_CORRUPT ) ) {
927
        // Corrupt the data
928
        simulate_fail_corrupt_sglist( sg_list, sg_len );
929
    }
930
#endif
931
 
932
#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
933
    if (cyg_io_eth_net_debug) {
934
        int i;
935
        START_CONSOLE();
936
        for (i = 0;  i < sg_len;  i++) {
937
            if (sg_list[i].buf) {
938
                diag_printf("rx %d bytes at %x sg[%d]\n", sg_list[i].len, sg_list[i].buf, i);
939
                if ( cyg_io_eth_net_debug > 1 )
940
                    diag_dump_buf((void *)sg_list[i].buf, sg_list[i].len);
941
            }
942
        }
943
        END_CONSOLE();
944
    }
945
#endif
946
    m = top;
947
    if (m == 0) {
948
        ifp->if_ierrors++;
949
    }
950
    else {
951
        ifp->if_ipackets++;
952
 
953
#if NBPFILTER > 0
954
#error FIXME - Need mbuf with ethernet header attached
955
        /*
956
         * Check if there's a BPF listener on this interface.
957
         * If so, hand off the raw packet to bpf.
958
         */
959
        if (ifp->if_bpf)
960
            bpf_mtap(ifp->if_bpf, m);
961
#endif
962
 
963
        // Push data into protocol stacks
964
        ether_input(ifp, eh, m);
965
    }
966
    CYGARC_HAL_RESTORE_GP();
967
}
968
 
969
 
970
// ------------------------------------------------------------------------
971
// DSR to schedule network delivery thread
972
 
973
extern void ecos_synch_eth_drv_dsr(void); // from ecos/timeout.c in net stack
974
 
975
void
976
eth_drv_dsr(cyg_vector_t vector,
977
            cyg_ucount32 count,
978
            cyg_addrword_t data)
979
{
980
    struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
981
 
982
#ifdef CYGDBG_USE_ASSERTS
983
    // then check that this really is a "sc"
984
    {
985
        cyg_netdevtab_entry_t *t;
986
        for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++)
987
            if ( ((struct eth_drv_sc *)t->device_instance) == sc )
988
                break; // found it
989
        CYG_ASSERT( t != &__NETDEVTAB_END__, "eth_drv_dsr: Failed to find sc in NETDEVTAB" );
990
    }
991
#endif // Checking code
992
 
993
    sc->state |= ETH_DRV_NEEDS_DELIVERY;
994
 
995
    ecos_synch_eth_drv_dsr(); // [request] run delivery function for this dev
996
}
997
 
998
// This is called from the delivery thread, to do just that:
999
void eth_drv_run_deliveries( void )
1000
{
1001
    cyg_netdevtab_entry_t *t;
1002
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
1003
        struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance;
1004
        if ( ETH_DRV_NEEDS_DELIVERY & sc->state ) {
1005
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
1006
            cyg_bool was_ctrlc_int;
1007
#endif
1008
            sc->state &=~ETH_DRV_NEEDS_DELIVERY;
1009
#if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
1010
            was_ctrlc_int = HAL_CTRLC_CHECK((*sc->funs->int_vector)(sc), (int)sc);
1011
            if (!was_ctrlc_int) // Fall through and run normal code
1012
#endif
1013
            (*sc->funs->deliver)(sc);
1014
        }
1015
    }
1016
}
1017
 
1018
// This is called from the delivery thread, to unstick devices if there is
1019
// no network activity.
1020
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
1021
void eth_drv_tickle_devices( void )
1022
{
1023
    cyg_netdevtab_entry_t *t;
1024
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
1025
        struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance;
1026
        if ( ETH_DRV_STATE_ACTIVE & sc->state ) {
1027
            struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1028
            // Try to dequeue a packet for this interface, if we can.  This
1029
            // will call can_send() for active interfaces.  It is calls to
1030
            // this function from tx_done() which normally provide
1031
            // continuous transmissions; otherwise we do not get control.
1032
            // This call fixes that.
1033
            if (!IF_IS_EMPTY(&ifp->if_snd)) {
1034
                eth_drv_send(ifp);
1035
            }
1036
        }
1037
    }
1038
}
1039
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
1040
 
1041
// ------------------------------------------------------------------------
1042
 
1043
#ifdef CYGPKG_IO_PCMCIA
1044
// Lookup a 'netdev' entry, assuming that it is an ethernet device.
1045
cyg_netdevtab_entry_t *
1046
eth_drv_netdev(char *name)
1047
{
1048
    cyg_netdevtab_entry_t *t;
1049
    struct eth_drv_sc *sc;
1050
    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
1051
        sc = (struct eth_drv_sc *)t->device_instance;
1052
        if (strcmp(sc->dev_name, name) == 0) {
1053
            return t;
1054
        }
1055
    }
1056
    return (cyg_netdevtab_entry_t *)NULL;
1057
}
1058
#endif // CYGPKG_IO_PCMCIA
1059
 
1060
// EOF src/net/eth_drv.c

powered by: WebSVN 2.1.0

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