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