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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [i386/] [pc386/] [wd8003/] [wd8003.c] - Blame information for rev 602

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

Line No. Rev Author Line
1 30 unneback
/*
2
 * RTEMS driver for WD800x
3
 *
4
 *  Based on the 68360 Network Driver by:
5
 *    W. Eric Norum
6
 *    Saskatchewan Accelerator Laboratory
7
 *    University of Saskatchewan
8
 *    Saskatoon, Saskatchewan, CANADA
9
 *    eric@skatter.usask.ca
10
 *
11
 *  $Id: wd8003.c,v 1.2 2001-09-27 11:59:49 chris Exp $
12
 */
13
 
14
#include <bsp.h>
15
#include <wd80x3.h>
16
 
17
#include <stdio.h>
18
#include <stdarg.h>
19
#include <rtems/error.h>
20
#include <rtems/rtems_bsdnet.h>
21
 
22
#include <sys/param.h>
23
#include <sys/mbuf.h>
24
#include <sys/socket.h>
25
#include <sys/sockio.h>
26
 
27
#include <net/if.h>
28
 
29
#include <netinet/in.h>
30
#include <netinet/if_ether.h>
31
 
32
#include <irq.h>
33
 
34
#define ET_MINLEN 60            /* minimum message length */
35
 
36
/*
37
 * Number of WDs supported by this driver
38
 */
39
#define NWDDRIVER       1
40
 
41
/*
42
 * Default number of buffer descriptors set aside for this driver.
43
 * The number of transmit buffer descriptors has to be quite large
44
 * since a single frame often uses four or more buffer descriptors.
45
 */
46
#define RX_BUF_COUNT     15
47
#define TX_BUF_COUNT     4
48
#define TX_BD_PER_BUF    4
49
 
50
/*
51
 * RTEMS event used by interrupt handler to signal driver tasks.
52
 * This must not be any of the events used by the network task synchronization.
53
 */
54
#define INTERRUPT_EVENT RTEMS_EVENT_1
55
 
56
/*
57
 * RTEMS event used to start transmit daemon.
58
 * This must not be the same as INTERRUPT_EVENT.
59
 */
60
#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
61
 
62
/*
63
 * Receive buffer size -- Allow for a full ethernet packet including CRC
64
 */
65
#define RBUF_SIZE       1520
66
 
67
#if (MCLBYTES < RBUF_SIZE)
68
# error "Driver must have MCLBYTES > RBUF_SIZE"
69
#endif
70
 
71
/*
72
 * Per-device data
73
 */
74
struct wd_softc {
75
  struct arpcom                 arpcom;
76
  rtems_irq_connect_data        irqInfo;
77
  struct mbuf                   **rxMbuf;
78
  struct mbuf                   **txMbuf;
79
  int                           acceptBroadcast;
80
  int                           rxBdCount;
81
  int                           txBdCount;
82
  int                           txBdHead;
83
  int                           txBdTail;
84
  int                           txBdActiveCount;
85
  rtems_id                      rxDaemonTid;
86
  rtems_id                      txDaemonTid;
87
 
88
  unsigned int                  port;
89
  unsigned char                 *base;
90
  unsigned long                 bpar;
91
 
92
  /*
93
   * Statistics
94
   */
95
  unsigned long rxInterrupts;
96
  unsigned long rxNotFirst;
97
  unsigned long rxNotLast;
98
  unsigned long rxGiant;
99
  unsigned long rxNonOctet;
100
  unsigned long rxRunt;
101
  unsigned long rxBadCRC;
102
  unsigned long rxOverrun;
103
  unsigned long rxCollision;
104
 
105
  unsigned long txInterrupts;
106
  unsigned long txDeferred;
107
  unsigned long txHeartbeat;
108
  unsigned long txLateCollision;
109
  unsigned long txRetryLimit;
110
  unsigned long txUnderrun;
111
  unsigned long txLostCarrier;
112
  unsigned long txRawWait;
113
};
114
 
115
#define RO 0x10
116
 
117
#define SHATOT (8*1024)         /* size of shared memory */
118
#define SHAPAGE 256             /* shared memory information */
119
#define MAXSIZ  1536            /*(MAXBUF - MESSH_SZ)*/
120
#define OUTPAGE ((SHATOT-(MAXSIZ+SHAPAGE-1))/SHAPAGE)
121
 
122
static volatile unsigned long overrun;
123
static volatile unsigned long resend;
124
static struct wd_softc wd_softc[NWDDRIVER];
125
 
126
/*
127
 * WD interrupt handler
128
 */
129
static void
130
wd8003Enet_interrupt_handler (void)
131
{
132
  unsigned int tport;
133
  unsigned char status, status2;
134
 
135
  tport = wd_softc[0].port ;
136
 
137
  /*
138
   * Read status
139
   */
140
  inport_byte(tport+ISR, status);
141
  outport_byte(tport+IMR, 0x00);
142
 
143
  /*
144
   * Ring overwrite
145
   */
146
 
147
  if (status & MSK_OVW){
148
    outport_byte(tport+CMDR, MSK_STP + MSK_RD2);        /* stop 8390 */
149
    Wait_X_ms(2);
150
    outport_byte(tport+RBCR0, 0);                        /* clear byte count */
151
    outport_byte(tport+RBCR1, 0);
152
    inport_byte(tport+ISR, status2);
153
    status |= (status2 & (MSK_PTX+MSK_TXE)) ;   /* TX status */
154
    outport_byte(tport+TCR, MSK_LOOP);          /* loopback mode */
155
    outport_byte(tport+CMDR, MSK_STA + MSK_RD2);        /* start */
156
    overrun = 1 ;
157
    if ((status & (MSK_PTX+MSK_TXE)) == 0)
158
        resend = 1;
159
  }
160
 
161
  /*
162
   * Frame received?
163
   */
164
  if (status & (MSK_PRX+MSK_RXE)) {
165
    outport_byte(tport+ISR, status & (MSK_PRX+MSK_RXE));
166
    wd_softc[0].rxInterrupts++;
167
    rtems_event_send (wd_softc[0].rxDaemonTid, INTERRUPT_EVENT);
168
  }
169
 
170
}
171
 
172
static void nopOn(const rtems_irq_connect_data* notUsed)
173
{
174
  /*
175
   * code should be moved from wd8003Enet_initialize_hardware
176
   * to this location
177
   */
178
}
179
 
180
static int wdIsOn(const rtems_irq_connect_data* irq)
181
{
182
  return BSP_irq_enabled_at_i8259s (irq->name);
183
}
184
 
185
/*
186
 * Initialize the ethernet hardware
187
 */
188
static void
189
wd8003Enet_initialize_hardware (struct wd_softc *sc)
190
{
191
  int  i1, ultra;
192
  char cc1, cc2;
193
  unsigned char  temp;
194
  rtems_status_code st;
195
  unsigned int tport;
196
  unsigned char *hwaddr;
197
 
198
  tport = sc->port;
199
 
200
  /* address from board ROM */
201
  inport_byte(tport+0x04, temp);
202
  outport_byte(tport+0x04, temp & 0x7f);
203
 
204
  hwaddr = sc->arpcom.ac_enaddr;
205
  for (i1=cc2=0; i1<8; i1++) {
206
    inport_byte(tport + ADDROM + i1, cc1);
207
    cc2 += cc1;
208
    if (i1 < 6)
209
      hwaddr[i1] = cc1;
210
  }
211
 
212
  inport_byte(tport+0x04, temp);
213
  outport_byte(tport+0x04, temp | 0x80);        /* alternate registers */
214
  outport_byte(tport+W83CREG, MSK_RESET);       /* reset board, set buffer */
215
  outport_byte(tport+W83CREG, 0);
216
  outport_byte(tport+W83CREG, MSK_ENASH + (int)((sc->bpar>>13)&0x3f));
217
 
218
  outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2);
219
  cc1 = MSK_BMS + MSK_FT10; /* configure 8 or 16 bits */
220
 
221
  inport_byte(tport+0x07, temp) ;
222
 
223
  ultra = ((temp & 0xf0) == 0x20 || (temp & 0xf0) == 0x40);
224
  if (ultra)
225
    cc1 = MSK_WTS + MSK_BMS + MSK_FT10;
226
  outport_byte(tport+DCR, cc1);
227
  outport_byte(tport+RBCR0, 0);
228
  outport_byte(tport+RBCR1, 0);
229
  outport_byte(tport+RCR, MSK_MON);             /* disable the rxer */
230
  outport_byte(tport+TCR, 0);                    /* normal operation */
231
  outport_byte(tport+PSTOP, OUTPAGE);           /* init PSTOP */
232
  outport_byte(tport+PSTART, 0);         /* init PSTART */
233
  outport_byte(tport+BNRY, -1);                 /* init BNRY */
234
  outport_byte(tport+ISR, -1);                  /* clear IR's */
235
  outport_byte(tport+IMR, 0x15);                /* enable interrupt */
236
 
237
  outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2);
238
 
239
  for (i1=0; i1<6; i1++)                 /* initial physical addr */
240
    outport_byte(tport+PAR+i1, hwaddr[i1]);
241
 
242
  for (i1=0; i1<MARsize; i1++)                   /* clear multicast */
243
    outport_byte(tport+MAR+i1, 0);
244
  outport_byte(tport+CURR, 0);                   /* init current packet */
245
 
246
  outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2);
247
  outport_byte(tport+CMDR, MSK_STA + MSK_RD2);  /* put 8390 on line */
248
  outport_byte(tport+RCR, MSK_AB);              /* MSK_AB accept broadcast */
249
 
250
  if (ultra) {
251
    inport_byte(tport+0x0c, temp);
252
    outport_byte(tport+0x0c, temp | 0x80);
253
    outport_byte(tport+0x05, 0x80);
254
    outport_byte(tport+0x06, 0x01);
255
  }
256
 
257
  /*
258
   * Set up interrupts
259
   */
260
  sc->irqInfo.hdl = wd8003Enet_interrupt_handler;
261
  sc->irqInfo.on  = nopOn;
262
  sc->irqInfo.off = nopOn;
263
  sc->irqInfo.isOn = wdIsOn;
264
 
265
  st = BSP_install_rtems_irq_handler (&sc->irqInfo);
266
  if (!st)
267
    rtems_panic ("Can't attach WD interrupt handler for irq %d\n",
268
                  sc->irqInfo.name);
269
}
270
 
271
static void
272
wd_rxDaemon (void *arg)
273
{
274
  unsigned int tport;
275
  struct ether_header *eh;
276
  struct wd_softc *dp = (struct wd_softc *)&wd_softc[0];
277
  struct ifnet *ifp = &dp->arpcom.ac_if;
278
  struct mbuf *m;
279
  unsigned int i2;
280
  unsigned int len;
281
  volatile unsigned char start, next, current;
282
  char *shp, *temp;
283
  rtems_event_set events;
284
 
285
  tport = wd_softc[0].port ;
286
 
287
  for (;;){
288
 
289
 
290
    rtems_bsdnet_event_receive (INTERRUPT_EVENT,
291
                                RTEMS_WAIT|RTEMS_EVENT_ANY,
292
                                RTEMS_NO_TIMEOUT,
293
                                &events);
294
 
295
    for (;;){
296
      inport_byte(tport+BNRY, start);
297
 
298
      outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2);
299
      inport_byte(tport+CURR, current);
300
      outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2);
301
 
302
      start += 1;
303
      if (start >= OUTPAGE){
304
        start = 0;
305
      }
306
 
307
      if (current == start)
308
        break;
309
 
310
      shp = dp->base + 1 + (SHAPAGE * start);
311
      next = *shp++;
312
      len = *((short *)shp)++ - 4;
313
 
314
      if (next >= OUTPAGE){
315
        next = 0;
316
      }
317
 
318
      MGETHDR (m, M_WAIT, MT_DATA);
319
      MCLGET (m, M_WAIT);
320
      m->m_pkthdr.rcvif = ifp;
321
 
322
      temp = m->m_data;
323
      m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
324
 
325
      if ((i2 = (OUTPAGE - start) * SHAPAGE - 4) < len){
326
        memcpy(temp, shp, i2);
327
        len -= i2;
328
        temp += i2;
329
        shp = dp->base;
330
      }
331
      memcpy(temp, shp, len);
332
 
333
      eh = mtod (m, struct ether_header *);
334
      m->m_data += sizeof(struct ether_header);
335
      ether_input (ifp, eh, m);
336
 
337
      outport_byte(tport+BNRY, next-1);
338
    }
339
 
340
  /*
341
   * Ring overwrite
342
   */
343
    if (overrun){
344
      outport_byte(tport+ISR, MSK_OVW);         /* reset IR */
345
      outport_byte(tport+TCR, 0);                /* out of loopback */
346
      if (resend  == 1)
347
        outport_byte(tport+CMDR, MSK_TXP + MSK_RD2);    /* resend */
348
      resend = 0;
349
      overrun = 0;
350
    }
351
 
352
    outport_byte(tport+IMR, 0x15);  /* re-enable IT rx */
353
  }
354
}
355
 
356
static void
357
sendpacket (struct ifnet *ifp, struct mbuf *m)
358
{
359
        struct wd_softc *dp = ifp->if_softc;
360
        struct mbuf *n;
361
        unsigned int len, tport;
362
        char *shp, txReady;
363
 
364
        tport = dp->port;
365
 
366
  /*
367
   * Waiting for Transmitter ready
368
   */
369
  inport_byte(tport+CMDR, txReady);
370
  while(txReady & MSK_TXP)
371
    inport_byte(tport+CMDR, txReady);
372
 
373
  len = 0;
374
  shp = dp->base + (SHAPAGE * OUTPAGE);
375
 
376
  n = m;
377
 
378
  for (;;){
379
    len += m->m_len;
380
    memcpy(shp, (char *)m->m_data, m->m_len);
381
    shp += m->m_len ;
382
    if ((m = m->m_next) == NULL)
383
      break;
384
  }
385
 
386
  m_freem(n);
387
 
388
  if (len < ET_MINLEN) len = ET_MINLEN;
389
  outport_byte(tport+TBCR0, len);
390
  outport_byte(tport+TBCR1, (len >> 8) );
391
  outport_byte(tport+TPSR, OUTPAGE);
392
  outport_byte(tport+CMDR, MSK_TXP + MSK_RD2);
393
}
394
 
395
/*
396
 * Driver transmit daemon
397
 */
398
void
399
wd_txDaemon (void *arg)
400
{
401
        struct wd_softc *sc = (struct wd_softc *)arg;
402
        struct ifnet *ifp = &sc->arpcom.ac_if;
403
        struct mbuf *m;
404
        rtems_event_set events;
405
 
406
        for (;;) {
407
                /*
408
                 * Wait for packet
409
                 */
410
                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
411
 
412
                /*
413
                 * Send packets till queue is empty
414
                 */
415
                for (;;) {
416
                        /*
417
                         * Get the next mbuf chain to transmit.
418
                         */
419
                        IF_DEQUEUE(&ifp->if_snd, m);
420
                        if (!m)
421
                                break;
422
                        sendpacket (ifp, m);
423
                }
424
                ifp->if_flags &= ~IFF_OACTIVE;
425
        }
426
}
427
 
428
/*
429
 * Send packet (caller provides header).
430
 */
431
static void
432
wd_start (struct ifnet *ifp)
433
{
434
        struct wd_softc *sc = ifp->if_softc;
435
 
436
        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
437
        ifp->if_flags |= IFF_OACTIVE;
438
}
439
 
440
/*
441
 * Initialize and start the device
442
 */
443
static void
444
wd_init (void *arg)
445
{
446
  struct wd_softc *sc = arg;
447
  struct ifnet *ifp = &sc->arpcom.ac_if;
448
 
449
  if (sc->txDaemonTid == 0) {
450
 
451
    /*
452
     * Set up WD hardware
453
     */
454
    wd8003Enet_initialize_hardware (sc);
455
 
456
    /*
457
     * Start driver tasks
458
     */
459
    sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, wd_txDaemon, sc);
460
    sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, wd_rxDaemon, sc);
461
  }
462
 
463
  /*
464
   * Tell the world that we're running.
465
   */
466
  ifp->if_flags |= IFF_RUNNING;
467
 
468
}
469
 
470
/*
471
 * Stop the device
472
 */
473
static void
474
wd_stop (struct wd_softc *sc)
475
{
476
  unsigned int tport;
477
  unsigned char temp;
478
  struct ifnet *ifp = &sc->arpcom.ac_if;
479
 
480
  ifp->if_flags &= ~IFF_RUNNING;
481
 
482
  /*
483
   * Stop the transmitter
484
   */
485
  tport=wd_softc[0].port ;
486
  inport_byte(tport+0x04,temp);
487
  outport_byte(tport+0x04, temp & 0x7f);
488
  outport_byte(tport + CMDR, MSK_STP + MSK_RD2);
489
 
490
}
491
 
492
 
493
/*
494
 * Show interface statistics
495
 */
496
static void
497
wd_stats (struct wd_softc *sc)
498
{
499
        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
500
        printf ("       Not First:%-8lu", sc->rxNotFirst);
501
        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
502
        printf ("              Giant:%-8lu", sc->rxGiant);
503
        printf ("            Runt:%-8lu", sc->rxRunt);
504
        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
505
        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
506
        printf ("         Overrun:%-8lu", sc->rxOverrun);
507
        printf ("       Collision:%-8lu\n", sc->rxCollision);
508
 
509
        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
510
        printf ("        Deferred:%-8lu", sc->txDeferred);
511
        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
512
        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
513
        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
514
        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
515
        printf ("           Underrun:%-8lu", sc->txUnderrun);
516
        printf (" Raw output wait:%-8lu\n", sc->txRawWait);
517
}
518
 
519
/*
520
 * Driver ioctl handler
521
 */
522
static int
523
wd_ioctl (struct ifnet *ifp, int command, caddr_t data)
524
{
525
        struct wd_softc *sc = ifp->if_softc;
526
        int error = 0;
527
 
528
        switch (command) {
529
        case SIOCGIFADDR:
530
        case SIOCSIFADDR:
531
                ether_ioctl (ifp, command, data);
532
                break;
533
 
534
        case SIOCSIFFLAGS:
535
                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
536
                case IFF_RUNNING:
537
                        wd_stop (sc);
538
                        break;
539
 
540
                case IFF_UP:
541
                        wd_init (sc);
542
                        break;
543
 
544
                case IFF_UP | IFF_RUNNING:
545
                        wd_stop (sc);
546
                        wd_init (sc);
547
                        break;
548
 
549
                default:
550
                        break;
551
                }
552
                break;
553
 
554
        case SIO_RTEMS_SHOW_STATS:
555
                wd_stats (sc);
556
                break;
557
 
558
        /*
559
         * FIXME: All sorts of multicast commands need to be added here!
560
         */
561
        default:
562
                error = EINVAL;
563
                break;
564
        }
565
        return error;
566
}
567
 
568
/*
569
 * Attach an WD driver to the system
570
 */
571
int
572
rtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *config)
573
{
574
        struct wd_softc *sc;
575
        struct ifnet *ifp;
576
        int mtu;
577
        int i;
578
 
579
        /*
580
         * Find a free driver
581
         */
582
        for (i = 0 ; i < NWDDRIVER ; i++) {
583
                sc = &wd_softc[i];
584
                ifp = &sc->arpcom.ac_if;
585
                if (ifp->if_softc == NULL)
586
                        break;
587
        }
588
        if (i >= NWDDRIVER) {
589
                printf ("Too many WD drivers.\n");
590
                return 0;
591
        }
592
 
593
        /*
594
         * Process options
595
         */
596
        if (config->hardware_address) {
597
          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
598
                  ETHER_ADDR_LEN);
599
        }
600
        else {
601
          memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
602
        }
603
        if (config->mtu)
604
                mtu = config->mtu;
605
        else
606
                mtu = ETHERMTU;
607
 
608
 
609
        if (config->irno)
610
                sc->irqInfo.name = config->irno;
611
        else
612
                sc->irqInfo.name = 5;
613
 
614
        if (config->port)
615
                sc->port = config->port;
616
        else
617
                sc->port = 0x240;
618
 
619
        if (config->bpar) {
620
                sc->bpar = config->bpar;
621
                sc->base = (unsigned char*) config->bpar;
622
        }
623
        else {
624
                sc->bpar = 0xD0000;
625
                sc->base = (unsigned char*) 0xD0000;
626
        }
627
 
628
        sc->acceptBroadcast = !config->ignore_broadcast;
629
 
630
        /*
631
         * Set up network interface values
632
         */
633
        ifp->if_softc = sc;
634
        ifp->if_unit = i + 1;
635
        ifp->if_name = "wd";
636
        ifp->if_mtu = mtu;
637
        ifp->if_init = wd_init;
638
        ifp->if_ioctl = wd_ioctl;
639
        ifp->if_start = wd_start;
640
        ifp->if_output = ether_output;
641
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
642
        if (ifp->if_snd.ifq_maxlen == 0)
643
                ifp->if_snd.ifq_maxlen = ifqmaxlen;
644
 
645
        /*
646
         * init some variables
647
         */
648
        overrun = 0;
649
        resend = 0;
650
 
651
        /*
652
         * Attach the interface
653
         */
654
        if_attach (ifp);
655
        ether_ifattach (ifp);
656
        return 1;
657
};

powered by: WebSVN 2.1.0

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