source: rtems/c/src/lib/libbsp/i386/pc386/dec21140/dec21140.c @ 1094cf0d

4.104.114.84.95
Last change on this file since 1094cf0d was 1094cf0d, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/99 at 21:06:17

Patch from Emmanuel RAGUET <raguet@…> to add files
that were accidentally not committed earlier. The DECNet driver
is being added as its own directory to avoid forcing the driver to
have to pull in the complete set of network drivers.

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/*
2 * RTEMS driver for TULIP based Ethernet Controller
3 *
4 *  $Header$
5 */
6
7#include <bsp.h>
8#include <pcibios.h>
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <stdarg.h>
13#include <rtems/error.h>
14#include <rtems/rtems_bsdnet.h>
15
16#include <libcpu/cpu.h>
17
18#include <sys/param.h>
19#include <sys/mbuf.h>
20
21#include <sys/socket.h>
22#include <sys/sockio.h>
23#include <net/if.h>
24#include <netinet/in.h>
25#include <netinet/if_ether.h>
26 
27#include <irq.h>
28
29#ifdef malloc
30#undef malloc
31#endif
32#ifdef free
33#undef free
34#endif
35
36#define PCI_VENDOR_ID_DEC 0x1011
37#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
38
39#define IO_MASK  0x3
40#define MEM_MASK  0xF
41
42/* command and status registers, 32-bit access, only if IO-ACCESS */
43#define ioCSR0  0x00    /* bus mode register */
44#define ioCSR1  0x08    /* transmit poll demand */
45#define ioCSR2  0x10    /* receive poll demand */
46#define ioCSR3  0x18    /* receive list base address */
47#define ioCSR4  0x20    /* transmit list base address */
48#define ioCSR5  0x28    /* status register */
49#define ioCSR6  0x30    /* operation mode register */
50#define ioCSR7  0x38    /* interrupt mask register */
51#define ioCSR8  0x40    /* missed frame counter */
52#define ioCSR9  0x48    /* Ethernet ROM register */
53#define ioCSR10 0x50    /* reserved */
54#define ioCSR11 0x58    /* full-duplex register */
55#define ioCSR12 0x60    /* SIA status register */
56#define ioCSR13 0x68
57#define ioCSR14 0x70
58#define ioCSR15 0x78    /* SIA general register */
59
60/* command and status registers, 32-bit access, only if MEMORY-ACCESS */
61#define memCSR0  0x00   /* bus mode register */
62#define memCSR1  0x02   /* transmit poll demand */
63#define memCSR2  0x04   /* receive poll demand */
64#define memCSR3  0x06   /* receive list base address */
65#define memCSR4  0x08   /* transmit list base address */
66#define memCSR5  0x0A   /* status register */
67#define memCSR6  0x0C   /* operation mode register */
68#define memCSR7  0x0E   /* interrupt mask register */
69#define memCSR8  0x10   /* missed frame counter */
70#define memCSR9  0x12   /* Ethernet ROM register */
71#define memCSR10 0x14   /* reserved */
72#define memCSR11 0x16   /* full-duplex register */
73#define memCSR12 0x18   /* SIA status register */
74#define memCSR13 0x1A
75#define memCSR14 0x1C
76#define memCSR15 0x1E   /* SIA general register */
77
78#define DEC_REGISTER_SIZE    0x100   /* to reserve virtual memory */
79
80#define RESET_CHIP   0x00000001
81#define CSR0_MODE    0x01a08000   /* 01a08000 */
82#define ROM_ADDRESS  0x00004800
83#define CSR6_INIT    0x020c0000   /* 020c0000 */ 
84#define CSR6_TX      0x00002000   
85#define CSR6_TXRX    0x00002002   
86#define IT_SETUP     0x00010040   /* 0001ebef */
87#define CLEAR_IT     0xFFFFFFFF   
88#define NO_IT        0x00000000   
89
90#define NRXBUFS 7       /* number of receive buffers */
91#define NTXBUFS 1       /* number of transmit buffers */
92
93/* message descriptor entry */
94struct MD {
95    volatile unsigned long status;
96    volatile unsigned long counts;
97    unsigned long buf1, buf2;   
98};
99
100/*
101 * Number of WDs supported by this driver
102 */
103#define NDECDRIVER      1
104
105/*
106 * Receive buffer size -- Allow for a full ethernet packet including CRC
107 */
108#define RBUF_SIZE       1520
109
110#define ET_MINLEN 60            /* minimum message length */
111
112/*
113 * RTEMS event used by interrupt handler to signal driver tasks.
114 * This must not be any of the events used by the network task synchronization.
115 */
116#define INTERRUPT_EVENT RTEMS_EVENT_1
117
118/*
119 * RTEMS event used to start transmit daemon.
120 * This must not be the same as INTERRUPT_EVENT.
121 */
122#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
123
124#if (MCLBYTES < RBUF_SIZE)
125# error "Driver must have MCLBYTES > RBUF_SIZE"
126#endif
127
128/*
129 * Per-device data
130 */
131 struct dec21140_softc {
132  struct arpcom                 arpcom;
133  rtems_irq_connect_data        irqInfo;
134  struct MD                     *MDbase;
135  char                          *bufferBase;
136  int                           acceptBroadcast;
137  int                           rxBdCount;
138  int                           txBdCount;
139  rtems_id                      rxDaemonTid;
140  rtems_id                      txDaemonTid;
141
142  unsigned int                  port;
143  unsigned int                  *base;
144  unsigned long                 bpar;
145   
146  /*
147   * Statistics
148   */
149  unsigned long rxInterrupts;
150  unsigned long rxNotFirst;
151  unsigned long rxNotLast;
152  unsigned long rxGiant;
153  unsigned long rxNonOctet;
154  unsigned long rxRunt;
155  unsigned long rxBadCRC;
156  unsigned long rxOverrun;
157  unsigned long rxCollision;
158 
159  unsigned long txInterrupts;
160  unsigned long txDeferred;
161  unsigned long txHeartbeat;
162  unsigned long txLateCollision;
163  unsigned long txRetryLimit;
164  unsigned long txUnderrun;
165  unsigned long txLostCarrier;
166  unsigned long txRawWait;
167};
168
169static struct dec21140_softc dec21140_softc[NDECDRIVER];
170
171/*
172 * DEC21140 interrupt handler
173 */
174static rtems_isr
175dec21140Enet_interrupt_handler (rtems_vector_number v)
176{
177  unsigned int *tbase;
178  unsigned long status;
179
180  unsigned int sc;
181 
182  tbase = dec21140_softc[0].base ;
183
184  /*
185   * Read status
186   */
187  *(tbase+memCSR7) = NO_IT;
188  status = *(tbase+memCSR5);
189  *(tbase+memCSR5) = CLEAR_IT;
190
191  /*
192   * Frame received?
193   */
194  if (status & 0x00000040){
195    dec21140_softc[0].rxInterrupts++;
196    sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT);
197  }
198}
199
200static void nopOn(const rtems_irq_connect_data* notUsed)
201{
202  /*
203   * code should be moved from dec21140Enet_initialize_hardware
204   * to this location
205   */
206}
207
208static int dec21140IsOn(const rtems_irq_connect_data* irq)
209{
210  return BSP_irq_enabled_at_i8259s (irq->name);
211}
212
213/*
214 * Read and write the MII registers using software-generated serial
215 * MDIO protocol.
216 */
217#define MDIO_SHIFT_CLK          0x10000
218#define MDIO_DATA_WRITE0        0x00000
219#define MDIO_DATA_WRITE1        0x20000
220#define MDIO_ENB                0x00000 
221#define MDIO_ENB_IN             0x40000
222#define MDIO_DATA_READ          0x80000
223
224static int mdio_read(unsigned int *ioaddr, int phy_id, int location)
225{
226        int i, i3;
227        int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
228        unsigned short retval = 0;
229
230        /* Establish sync by sending at least 32 logic ones. */
231        for (i = 32; i >= 0; i--) {
232                *ioaddr = MDIO_ENB | MDIO_DATA_WRITE1;
233                for(i3=0; i3<1000; i3++);
234                *ioaddr =  MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK;
235                for(i3=0; i3<1000; i3++);
236        }
237        /* Shift the read command bits out. */
238        for (i = 17; i >= 0; i--) {
239                int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
240                *ioaddr =  dataval;
241                for(i3=0; i3<1000; i3++);
242                *ioaddr =  dataval | MDIO_SHIFT_CLK;
243                for(i3=0; i3<1000; i3++);
244                *ioaddr =  dataval;
245                for(i3=0; i3<1000; i3++);
246        }
247        *ioaddr =  MDIO_ENB_IN | MDIO_SHIFT_CLK;
248        for(i3=0; i3<1000; i3++);
249        *ioaddr =  MDIO_ENB_IN;
250
251        for (i = 16; i > 0; i--) {
252                *ioaddr =  MDIO_ENB_IN | MDIO_SHIFT_CLK;
253                for(i3=0; i3<1000; i3++);
254                retval = (retval << 1) | ((*ioaddr & MDIO_DATA_READ) ? 1 : 0);
255                *ioaddr =  MDIO_ENB_IN;
256                for(i3=0; i3<1000; i3++);
257        }
258        /* Clear out extra bits. */
259        for (i = 16; i > 0; i--) {
260                *ioaddr =  MDIO_ENB_IN | MDIO_SHIFT_CLK;
261                for(i3=0; i3<1000; i3++);
262                *ioaddr =  MDIO_ENB_IN;
263                for(i3=0; i3<1000; i3++);
264        }
265        return retval;
266}
267
268static int mdio_write(unsigned int *ioaddr, int phy_id, int location, int value)
269{
270        int i, i3;
271        int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
272
273        /* Establish sync by sending at least 32 logic ones. */
274        for (i = 32; i >= 0; i--) {
275                *ioaddr =  MDIO_ENB | MDIO_DATA_WRITE1;
276                for(i3=0; i3<1000; i3++);
277                *ioaddr = MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK;
278                for(i3=0; i3<1000; i3++);
279        }
280        /* Shift the read command bits out. */
281        for (i = 31; i >= 0; i--) {
282                int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
283                *ioaddr =  dataval;
284                for(i3=0; i3<1000; i3++);
285                *ioaddr =  dataval | MDIO_SHIFT_CLK;
286                for(i3=0; i3<1000; i3++);
287        }
288
289        /* Clear out extra bits. */
290        for (i = 2; i > 0; i--) {
291                *ioaddr =  MDIO_ENB_IN;
292                for(i3=0; i3<1000; i3++);
293                *ioaddr = MDIO_ENB_IN | MDIO_SHIFT_CLK;
294                for(i3=0; i3<1000; i3++);
295        }
296        return 0;
297
298
299}
300
301/*
302 * This routine reads a word (16 bits) from the serial EEPROM.
303 */
304/*  EEPROM_Ctrl bits. */
305#define EE_SHIFT_CLK            0x02    /* EEPROM shift clock. */
306#define EE_CS                   0x01    /* EEPROM chip select. */
307#define EE_DATA_WRITE           0x04    /* EEPROM chip data in. */
308#define EE_WRITE_0              0x01
309#define EE_WRITE_1              0x05
310#define EE_DATA_READ            0x08    /* EEPROM chip data out. */
311#define EE_ENB                  (0x4800 | EE_CS)
312
313/* The EEPROM commands include the alway-set leading bit. */
314#define EE_WRITE_CMD    (5 << 6)
315#define EE_READ_CMD     (6 << 6)
316#define EE_ERASE_CMD    (7 << 6)
317
318static int eeget16(unsigned int *ioaddr, int location)
319{
320        int i, i3;
321        unsigned short retval = 0;
322        int read_cmd = location | EE_READ_CMD;
323       
324        *ioaddr = EE_ENB & ~EE_CS;
325        *ioaddr = EE_ENB;
326       
327        /* Shift the read command bits out. */
328        for (i = 10; i >= 0; i--) {
329                short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
330                *ioaddr = EE_ENB | dataval;
331                for (i3=0; i3<1000; i3++) ;
332                *ioaddr = EE_ENB | dataval | EE_SHIFT_CLK;
333                for (i3=0; i3<1000; i3++) ;
334                *ioaddr = EE_ENB | dataval; /* Finish EEPROM a clock tick. */
335                for (i3=0; i3<1000; i3++) ;
336        }
337        *ioaddr = EE_ENB;
338       
339        for (i = 16; i > 0; i--) {
340                *ioaddr = EE_ENB | EE_SHIFT_CLK;
341                for (i3=0; i3<1000; i3++) ;
342                retval = (retval << 1) | ((*ioaddr & EE_DATA_READ) ? 1 : 0);
343                *ioaddr = EE_ENB;
344                for (i3=0; i3<1000; i3++) ;
345        }
346
347        /* Terminate the EEPROM access. */
348        *ioaddr = EE_ENB & ~EE_CS;
349        return retval;
350}
351
352/*
353 * Initialize the ethernet hardware
354 */
355static void
356dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
357{
358  rtems_status_code st;
359  unsigned int *tbase;
360  union {char c[64]; unsigned short s[32];} rombuf;
361  int i, i2, i3;
362  char *cp, direction, *setup_frm, *eaddrs;
363  unsigned long csr12_val, mii_reg0;
364  unsigned char *buffer;
365  struct MD *rmd;
366
367 
368  tbase = sc->base;
369
370  /*
371   * WARNING : First write in CSR6
372   *           Then Reset the chip ( 1 in CSR0)
373   */
374
375  *(tbase+memCSR6) = CSR6_INIT; 
376  *(tbase+memCSR0) = RESET_CHIP; 
377  for(i3=0; i3<1000; i3++);
378
379  /*
380   * Init CSR0
381   */
382  *(tbase+memCSR0) = CSR0_MODE; 
383
384  csr12_val = *(tbase+memCSR8);
385 
386  for (i=0; i<32; i++)
387    rombuf.s[i] = eeget16(tbase+memCSR9, i);
388  memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
389
390
391  mii_reg0 = mdio_read(tbase+memCSR9, 0, 0);
392  mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000);
393 
394#ifdef DEC_DEBUG
395  printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n",
396         sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],
397         sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],
398         sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],
399         sc->irqInfo.name, sc->port, sc->base);
400#endif
401 
402  /*
403   * Init RX ring
404   */
405  sc->rxBdCount = 0;
406 
407  cp = (char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PG_SIZE);
408  sc->bufferBase = cp;
409  cp += (PG_SIZE - (int)cp) & MASK_OFFSET ;
410  if (_CPU_is_paging_enabled())
411    _CPU_change_memory_mapping_attribute
412                   (NULL, cp,
413                    (NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE),
414                    PTE_CACHE_DISABLE | PTE_WRITABLE);
415  rmd = (struct MD*)cp;
416  sc->MDbase = rmd;
417  buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD));
418 
419  *(tbase+memCSR3) = (long)(sc->MDbase);
420  for (i=0 ; i<NRXBUFS; i++){
421    rmd->buf2 = 0;
422    rmd->buf1 = (unsigned long)(buffer + (i*RBUF_SIZE)); 
423    if (i == NRXBUFS-1)
424      rmd->counts = 0xfec00000 | (RBUF_SIZE);
425    else
426      rmd->counts = 0xfcc00000 | (RBUF_SIZE);
427    rmd->status = 0x80000000;
428    rmd++;
429  }
430
431  /*
432   * Init TX ring
433   */
434  sc->txBdCount = 0;
435  *(tbase+memCSR4) = (long)(rmd);
436  rmd->buf2 = 0;
437  rmd->buf1 = (unsigned long)(buffer + (NRXBUFS*RBUF_SIZE));
438  rmd->counts = 0x62000000;
439  rmd->status = 0x0;
440 
441  /*
442   * Set up interrupts
443   */
444  *(tbase+memCSR5) = IT_SETUP;
445  *(tbase+memCSR7) = IT_SETUP;
446
447  sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler;
448  sc->irqInfo.on  = nopOn;
449  sc->irqInfo.off = nopOn;
450  sc->irqInfo.isOn = dec21140IsOn; 
451  st = BSP_install_rtems_irq_handler (&sc->irqInfo);
452  if (!st)
453    rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n",
454                  sc->irqInfo.name);
455
456  /*
457   * Start TX for setup frame
458   */
459  *(tbase+memCSR6) = CSR6_INIT | CSR6_TX;
460
461  /*
462   * Build setup frame
463   */
464  setup_frm = (char *)(rmd->buf1);
465  eaddrs = (char *)(sc->arpcom.ac_enaddr);
466  /* Fill the buffer with our physical address. */
467  for (i = 1; i < 16; i++) {
468        *setup_frm++ = eaddrs[0];
469        *setup_frm++ = eaddrs[1];
470        setup_frm += 2;
471        *setup_frm++ = eaddrs[2];
472        *setup_frm++ = eaddrs[3];
473        setup_frm += 2;
474        *setup_frm++ = eaddrs[4];
475        *setup_frm++ = eaddrs[5];
476        setup_frm += 2;
477  }
478  /* Add the broadcast address when doing perfect filtering */
479  memset(setup_frm, 0xff, 12);
480  rmd->counts = 0x0a000000 | 192 ;
481  rmd->status = 0x80000000;
482  *(tbase+memCSR1) = 1;
483  while (rmd->status != 0x7fffffff);
484
485  /*
486   * Enable RX and TX
487   */
488  *(tbase+memCSR6) = CSR6_INIT | CSR6_TXRX;
489 
490  /*
491   * Set up PHY
492   */
493 
494  i = rombuf.c[27];
495  i+=2;
496  direction = rombuf.c[i];
497  i +=4;
498  *(tbase+memCSR12) = direction | 0x100;
499  for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){
500    *(tbase + memCSR12) = rombuf.c[(i+3) + rombuf.c[i+1] + i2];
501  }
502  for (i2 = 0; i2 < rombuf.c[i+1]; i2++){
503    *(tbase + memCSR12) = rombuf.c[(i+2) + i2];
504  }
505}
506
507static void
508dec21140_rxDaemon (void *arg)
509{
510  unsigned int *tbase;
511  struct ether_header *eh;
512  struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0];
513  struct ifnet *ifp = &dp->arpcom.ac_if;
514  struct mbuf *m;
515  struct MD *rmd;
516  unsigned int len;
517  char *temp;
518  rtems_event_set events;
519  int nbMD;
520 
521  tbase = dec21140_softc[0].base ;
522
523  for (;;){
524
525    rtems_bsdnet_event_receive (INTERRUPT_EVENT,
526                                RTEMS_WAIT|RTEMS_EVENT_ANY,
527                                RTEMS_NO_TIMEOUT,
528                                &events);
529    rmd = dec21140_softc[0].MDbase;
530    nbMD = 0;
531   
532    while (nbMD < NRXBUFS){
533      if ( (rmd->status & 0x80000000) == 0){
534        len = (rmd->status >> 16) & 0x7ff;
535        MGETHDR (m, M_WAIT, MT_DATA);
536        MCLGET (m, M_WAIT);
537        m->m_pkthdr.rcvif = ifp;
538        temp = m->m_data;
539        m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
540        memcpy(temp, (char *)rmd->buf1, len);
541        rmd->status = 0x80000000;
542        eh = mtod (m, struct ether_header *);
543        m->m_data += sizeof(struct ether_header);
544        ether_input (ifp, eh, m);
545      }
546      rmd++;
547      nbMD++;
548    }
549    *(tbase+memCSR7) = IT_SETUP;
550  }     
551}
552
553static void
554sendpacket (struct ifnet *ifp, struct mbuf *m)
555{
556  struct dec21140_softc *dp = ifp->if_softc;
557  volatile struct MD *tmd;
558  unsigned char *temp;
559  struct mbuf *n;
560  unsigned int len;
561  unsigned int *tbase;
562
563  tbase = dp->base;
564
565  /*
566   * Waiting for Transmitter ready
567   */   
568  tmd = dec21140_softc[0].MDbase + NRXBUFS;
569  while ( (tmd->status & 0x80000000) != 0 );
570  len = 0;
571  n = m;
572  temp = (char *)(tmd->buf1);
573 
574  for (;;){
575    len += m->m_len;
576    memcpy(temp, (char *)m->m_data, m->m_len);
577    temp += m->m_len ;
578    if ((m = m->m_next) == NULL)
579      break;
580  }
581
582  if (len < ET_MINLEN) len = ET_MINLEN;
583  tmd->counts = 0xe2000000 | len;
584  tmd->status = 0x80000000;
585
586  *(tbase+memCSR1) = 0x1;
587
588  m_freem(n);
589}
590
591/*
592 * Driver transmit daemon
593 */
594void
595dec21140_txDaemon (void *arg)
596{
597  struct dec21140_softc *sc = (struct dec21140_softc *)arg;
598  struct ifnet *ifp = &sc->arpcom.ac_if;
599  struct mbuf *m;
600  rtems_event_set events;
601
602  for (;;) {
603    /*
604     * Wait for packet
605     */
606
607    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
608
609    /*
610     * Send packets till queue is empty
611     */
612    for (;;) {
613      /*
614       * Get the next mbuf chain to transmit.
615       */
616      IF_DEQUEUE(&ifp->if_snd, m);
617      if (!m)
618        break;
619      sendpacket (ifp, m);
620    }
621    ifp->if_flags &= ~IFF_OACTIVE;
622  }
623}       
624
625
626static void
627dec21140_start (struct ifnet *ifp)
628{
629        struct dec21140_softc *sc = ifp->if_softc;
630
631        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
632        ifp->if_flags |= IFF_OACTIVE;
633}
634
635/*
636 * Initialize and start the device
637 */
638static void
639dec21140_init (void *arg)
640{
641  struct dec21140_softc *sc = arg;
642  struct ifnet *ifp = &sc->arpcom.ac_if;
643
644  if (sc->txDaemonTid == 0) {
645   
646    /*
647     * Set up DEC21140 hardware
648     */
649    dec21140Enet_initialize_hardware (sc);
650   
651    /*
652     * Start driver tasks
653     */
654    sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
655                                            dec21140_rxDaemon, sc);
656    sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
657                                            dec21140_txDaemon, sc);
658  }
659
660  /*
661   * Tell the world that we're running.
662   */
663  ifp->if_flags |= IFF_RUNNING;
664
665}
666
667/*
668 * Stop the device
669 */
670static void
671dec21140_stop (struct dec21140_softc *sc)
672{
673  unsigned int *tbase;
674  struct ifnet *ifp = &sc->arpcom.ac_if;
675
676  ifp->if_flags &= ~IFF_RUNNING;
677
678  /*
679   * Stop the transmitter
680   */
681  tbase=dec21140_softc[0].base ;
682  *(tbase+memCSR7) = NO_IT;
683  *(tbase+memCSR6) = CSR6_INIT;
684  free(sc->bufferBase);
685}
686
687
688/*
689 * Show interface statistics
690 */
691static void
692dec21140_stats (struct dec21140_softc *sc)
693{
694        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
695        printf ("       Not First:%-8lu", sc->rxNotFirst);
696        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
697        printf ("              Giant:%-8lu", sc->rxGiant);
698        printf ("            Runt:%-8lu", sc->rxRunt);
699        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
700        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
701        printf ("         Overrun:%-8lu", sc->rxOverrun);
702        printf ("       Collision:%-8lu\n", sc->rxCollision);
703
704        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
705        printf ("        Deferred:%-8lu", sc->txDeferred);
706        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
707        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
708        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
709        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
710        printf ("           Underrun:%-8lu", sc->txUnderrun);
711        printf (" Raw output wait:%-8lu\n", sc->txRawWait);
712}
713
714/*
715 * Driver ioctl handler
716 */
717static int
718dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data)
719{
720        struct dec21140_softc *sc = ifp->if_softc;
721        int error = 0;
722
723        switch (command) {
724        case SIOCGIFADDR:
725        case SIOCSIFADDR:
726                ether_ioctl (ifp, command, data);
727                break;
728
729        case SIOCSIFFLAGS:
730                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
731                case IFF_RUNNING:
732                        dec21140_stop (sc);
733                        break;
734
735                case IFF_UP:
736                        dec21140_init (sc);
737                        break;
738
739                case IFF_UP | IFF_RUNNING:
740                        dec21140_stop (sc);
741                        dec21140_init (sc);
742                        break;
743
744                default:
745                        break;
746                }
747                break;
748
749        case SIO_RTEMS_SHOW_STATS:
750                dec21140_stats (sc);
751                break;
752               
753        /*
754         * FIXME: All sorts of multicast commands need to be added here!
755         */
756        default:
757                error = EINVAL;
758                break;
759        }
760        return error;
761}
762
763/*
764 * Attach an DEC21140 driver to the system
765 */
766int
767rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config)
768{
769        struct dec21140_softc *sc;
770        struct ifnet *ifp;
771        int mtu;
772        int i;
773        int signature;
774        int value;
775        char interrupt;
776        int diag;
777       
778        /*
779         * Initialise PCI module
780         */
781        if (pcib_init() == PCIB_ERR_NOTPRESENT)
782          rtems_panic("PCI BIOS not found !!");
783       
784        /*
785         * First, find a DEC board
786         */
787        if ((diag = pcib_find_by_devid(PCI_VENDOR_ID_DEC,
788                                       PCI_DEVICE_ID_DEC_TULIP_FAST,
789                                       0,
790                                       &signature)) != PCIB_ERR_SUCCESS)
791          rtems_panic("DEC PCI board not found !! (%d)\n", diag);
792        else {
793          printk("DEC PCI Device found\n");
794        }
795       
796        /*
797         * Find a free driver
798         */
799        for (i = 0 ; i < NDECDRIVER ; i++) {
800                sc = &dec21140_softc[i];
801                ifp = &sc->arpcom.ac_if;
802                if (ifp->if_softc == NULL)
803                        break;
804        }
805        if (i >= NDECDRIVER) {
806                printk ("Too many DEC drivers.\n");
807                return 0;
808        }
809
810        /*
811         * Process options
812         */
813
814        pcib_conf_read32(signature, 16, &value);
815        sc->port = value & ~IO_MASK;
816       
817        pcib_conf_read32(signature, 20, &value);
818        if (_CPU_is_paging_enabled())
819          _CPU_map_phys_address(&(sc->base),
820                                (void *)(value & ~MEM_MASK),
821                                DEC_REGISTER_SIZE ,
822                                PTE_CACHE_DISABLE | PTE_WRITABLE);
823        else
824          sc->base = (unsigned int *)(value & ~MEM_MASK);
825       
826        pcib_conf_read8(signature, 60, &interrupt);
827          sc->irqInfo.name = (rtems_irq_symbolic_name)interrupt;
828       
829        if (config->hardware_address) {
830          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
831                  ETHER_ADDR_LEN);
832        }
833        else {
834          memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
835        }
836        if (config->mtu)
837                mtu = config->mtu;
838        else
839                mtu = ETHERMTU;
840
841        sc->acceptBroadcast = !config->ignore_broadcast;
842
843        /*
844         * Set up network interface values
845         */
846        ifp->if_softc = sc;
847        ifp->if_unit = i + 1;
848        ifp->if_name = "dc";
849        ifp->if_mtu = mtu;
850        ifp->if_init = dec21140_init;
851        ifp->if_ioctl = dec21140_ioctl;
852        ifp->if_start = dec21140_start;
853        ifp->if_output = ether_output;
854        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
855        if (ifp->if_snd.ifq_maxlen == 0)
856                ifp->if_snd.ifq_maxlen = ifqmaxlen;
857
858        /*
859         * Attach the interface
860         */
861        if_attach (ifp);
862        ether_ifattach (ifp);
863
864        return 1;
865};
866
867
868
869
870
871
872
873
874
875
876
Note: See TracBrowser for help on using the repository browser.