source: rtems/c/src/libchip/network/sonic.c @ 1f25c77

4.115
Last change on this file since 1f25c77 was 1f25c77, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/09/11 at 15:37:53

2011-10-09 Ralf Corsépius <ralf.corsepius@…>

  • libchip/network/greth.c, libchip/network/open_eth.c libchip/network/sonic.c: Eliminate evil typecasts.
  • libchip/network/greth.h, libchip/network/open_eth.h, libchip/network/sonic.h: Use void* for addresses.
  • Property mode set to 100644
File size: 43.8 KB
RevLine 
[c932d85]1/*
[c9c67390]2 *       RTEMS NETWORK DRIVER FOR NATIONAL DP83932 `SONIC'
3 *         SYSTEMS-ORIENTED NETWORK INTERFACE CONTROLLER
4 *
5 *                     REUSABLE CHIP DRIVER
6 *
[c932d85]7 * References:
8 *
[c9c67390]9 *  1) DP83932C-20/25/33 MHz SONIC(TM) Systems-Oriented Network Interface
10 *     Controller data sheet.  TL/F/10492, RRD-B30M105, National Semiconductor,
11 *     1995.
[c932d85]12 *
[c9c67390]13 *  2) Software Driver Programmer's Guide for the DP83932 SONIC(TM),
14 *     Application Note 746, Wesley Lee and Mike Lui, TL/F/11140,
15 *     RRD-B30M75, National Semiconductor, March, 1991.
16 *
17 *  COPYRIGHT (c) 1989-1997.
18 *  On-Line Applications Research Corporation (OAR).
19 *
20 *  The license and distribution terms for this file may be
21 *  found in the file LICENSE in this distribution or at
[94365d9]22 *  http://www.rtems.com/license/LICENSE.
[c9c67390]23 *
24 *  $Id$
[f1f42b4]25 *
26 *  This driver was originally written and tested on a DY-4 DMV177,
27 *  which had a 100 Mhz PPC603e.
28 *
29 *  This driver also works with DP83934CVUL-20/25 MHz, tested on
[a3d3d9a]30 *  Tharsys ERC32 VME board.
[f1f42b4]31 *
[a3d3d9a]32 *  Rehaul to fix lost interrupts and buffers, and to use to use
[f1f42b4]33 *  interrupt-free transmission by Jiri, 22/03/1999.
[c932d85]34 */
[7fc5d54e]35
[c9c67390]36#include <rtems.h>
[811115de]37#include <rtems/rtems_bsdnet.h>
[c9c67390]38#include <libchip/sonic.h>
[13cc89e1]39
[bfcf4cb3]40#include <stdio.h>
[9c6a99f]41#include <string.h>
[bfcf4cb3]42
43#include <errno.h>
[c932d85]44#include <rtems/error.h>
[bfcf4cb3]45
46#include <sys/param.h>
47#include <sys/mbuf.h>
48#include <sys/socket.h>
49#include <sys/sockio.h>
50#include <sys/sockio.h>
51
52#include <net/if.h>
53
54#include <netinet/in.h>
55#include <netinet/if_ether.h>
[c932d85]56
[7f247f3]57#if defined(__m68k__)
58extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
59#else
60extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
61#endif
[c9c67390]62
[7dbab720]63#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_MBUFS)
64#include <rtems/dumpbuf.h>
65#endif
[e995f3a1]66
[7fc5d54e]67/*
68 *  Use the top line if you want more symbols.
69 */
70
[a3d3d9a]71#define SONIC_STATIC
[7fc5d54e]72/* #define SONIC_STATIC static */
73
[c932d85]74/*
75 * Number of devices supported by this driver
76 */
77#ifndef NSONIC
78# define NSONIC 1
79#endif
80
81/*
[a3d3d9a]82 *
[c932d85]83 * As suggested by National Application Note 746, make the
84 * receive resource area bigger than the receive descriptor area.
[811115de]85 *
86 * NOTE:  Changing this may break this driver since it currently
87 *        assumes a 1<->1 mapping.
[c932d85]88 */
[9693fac4]89#define RRA_EXTRA_COUNT  0
[c932d85]90
91/*
92 * RTEMS event used by interrupt handler to signal daemons.
93 */
94#define INTERRUPT_EVENT  RTEMS_EVENT_1
95
[bfcf4cb3]96/*
97 * RTEMS event used to start transmit daemon.
98 * This must not be the same as INTERRUPT_EVENT.
99 */
100#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
101
[c932d85]102/*
103 * Largest Ethernet frame.
104 */
105#define MAXIMUM_FRAME_SIZE  1518
106
107/*
108 * Receive buffer size.
109 * Allow for a pointer, plus a full ethernet frame (including Frame
110 * Check Sequence) rounded up to a 4-byte boundary.
111 */
112#define RBUF_SIZE  ((sizeof (void *) + (MAXIMUM_FRAME_SIZE) + 3) & ~3)
[811115de]113/* #define RBUF_WC    ((((MAXIMUM_FRAME_SIZE) + 3) & ~3) / 2) */
114#define RBUF_WC    (RBUF_SIZE / 2)
[c932d85]115
116/*
117 * Macros for manipulating 32-bit pointers as 16-bit fragments
118 */
[509fec9c]119#define LSW(p)   ((uint16_t)((uint32_t)(p)))
120#define MSW(p)   ((uint16_t)((uint32_t)(p) >> 16))
121#define PTR(m,l) ((void*)(((uint16_t)(m)<<16)|(uint16_t)(l)))
[c932d85]122
123/*
124 * Hardware-specific storage
125 */
[bfcf4cb3]126struct sonic_softc {
[c932d85]127  /*
[bfcf4cb3]128   * Connection to networking code
129   * This entry *must* be the first in the sonic_softc structure.
[c932d85]130   */
[bfcf4cb3]131  struct arpcom                    arpcom;
[c932d85]132
133  /*
134   * Default location of device registers
135   * ===CACHE===
136   * This area must be non-cacheable, guarded.
137   */
[7fc5d54e]138  void                             *sonic;
[c932d85]139
[13cc89e1]140  /*
[a3d3d9a]141   *  Register access routines
[13cc89e1]142   */
143  sonic_write_register_t           write_register;
144  sonic_read_register_t            read_register;
[a3d3d9a]145
[c932d85]146  /*
147   * Interrupt vector
148   */
149  rtems_vector_number             vector;
150
[13cc89e1]151  /*
152   * Data Configuration Register values
153   */
[ee4f57d]154  uint32_t                  dcr_value;
155  uint32_t                  dc2_value;
[13cc89e1]156
[c932d85]157  /*
[bfcf4cb3]158   *  Indicates configuration
[c932d85]159   */
[bfcf4cb3]160  int                             acceptBroadcast;
161
162  /*
163   * Task waiting for interrupts
164   */
165  rtems_id                        rxDaemonTid;
166  rtems_id                        txDaemonTid;
[c932d85]167
168  /*
169   * Receive resource area
170   */
171  int                             rdaCount;
172  ReceiveResourcePointer_t        rsa;
[4f38b713]173  ReceiveResourcePointer_t        rea;
[301a2a3c]174  CamDescriptorPointer_t          cdp;
[e70a8f16]175  ReceiveDescriptorPointer_t      rda;
[dddc0557]176  ReceiveDescriptorPointer_t      rdp_last;
[c932d85]177
178  /*
179   * Transmit descriptors
180   */
[e70a8f16]181  int                             tdaCount;
[c932d85]182  TransmitDescriptorPointer_t     tdaHead;  /* Last filled */
183  TransmitDescriptorPointer_t     tdaTail;  /* Next to retire */
184
185  /*
186   * Statistics
187   */
[c153a7b]188  unsigned long                   Interrupts;
[c932d85]189  unsigned long                   rxInterrupts;
190  unsigned long                   rxMissed;
191  unsigned long                   rxGiant;
192  unsigned long                   rxNonOctet;
193  unsigned long                   rxBadCRC;
194  unsigned long                   rxCollision;
195
196  unsigned long                   txInterrupts;
197  unsigned long                   txSingleCollision;
198  unsigned long                   txMultipleCollision;
199  unsigned long                   txCollision;
200  unsigned long                   txDeferred;
201  unsigned long                   txUnderrun;
202  unsigned long                   txLateCollision;
203  unsigned long                   txExcessiveCollision;
204  unsigned long                   txExcessiveDeferral;
205  unsigned long                   txLostCarrier;
206  unsigned long                   txRawWait;
207};
[bfcf4cb3]208SONIC_STATIC struct sonic_softc sonic_softc[NSONIC];
[c932d85]209
[811115de]210
211/*
212 ******************************************************************
213 *                                                                *
214 *                         Debug Routines                         *
215 *                                                                *
216 ******************************************************************
217 */
218
219#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
220void sonic_print_tx_descriptor(
221  TransmitDescriptorPointer_t tdp
222)
223{
224  printf( "TXD ==> %p", tdp );
225  printf( "  pkt_config = 0x%04x", tdp->pkt_config & 0xffff);
226  printf( "  pkt_size = 0x%04x\n", tdp->pkt_size & 0xffff );
227  printf( "  frag_count = %d", tdp->frag_count & 0xffff );
228  /* could print all the fragments */
229  printf( "  next = %p", tdp->next );
230  printf( "  linkp = %p\n", tdp->linkp );
231  printf( "  mbufp = %p", tdp->mbufp );
232  if ( tdp->mbufp )
233    printf( "  mbufp->data = %p", mtod ( tdp->mbufp, void *) );
234  puts("");
235}
236
237void sonic_print_rx_descriptor(
238  ReceiveDescriptorPointer_t rdp
239)
240{
241  printf( "RXD ==> %p\n", rdp );
242  printf( "  status = 0x%04x", rdp->status & 0xffff );
243  printf( "  byte_count = 0x%04x\n", rdp->byte_count & 0xffff );
244  printf( "  pkt = 0x%04x%04x", rdp->pkt_msw, rdp->pkt_lsw );
245  printf( "  seq_no = %d", rdp->seq_no );
246  printf( "  link = %d\n", rdp->link );
247  printf( "  in_use = %d", rdp->in_use );
248  printf( "  next = %p", rdp->next );
249  printf( "  mbufp = %p", rdp->mbufp );
250  if ( rdp->mbufp )
251    printf( "  mbufp->data = %p", mtod ( rdp->mbufp, void *) );
252  puts("");
253}
254#endif
255
[c932d85]256/*
257 ******************************************************************
258 *                                                                *
259 *                        Support Routines                        *
260 *                                                                *
261 ******************************************************************
262 */
263
[9693fac4]264void sonic_enable_interrupts(
[13cc89e1]265  struct sonic_softc *sc,
[ee4f57d]266  uint32_t    mask
[9693fac4]267)
268{
[13cc89e1]269  void *rp = sc->sonic;
[9693fac4]270  rtems_interrupt_level level;
271
272  rtems_interrupt_disable( level );
[13cc89e1]273      (*sc->write_register)(
[9693fac4]274         rp,
275         SONIC_REG_IMR,
[13cc89e1]276         (*sc->read_register)(rp, SONIC_REG_IMR) | mask
[9693fac4]277      );
278  rtems_interrupt_enable( level );
279}
280
[f1f42b4]281void sonic_disable_interrupts(
282  struct sonic_softc *sc,
[ee4f57d]283  uint32_t    mask
[f1f42b4]284)
285{
286  void *rp = sc->sonic;
287  rtems_interrupt_level level;
288
289  rtems_interrupt_disable( level );
290  (*sc->write_register)(
291         rp,
292         SONIC_REG_IMR,
293         (*sc->read_register)(rp, SONIC_REG_IMR) & ~mask
294      );
295  rtems_interrupt_enable( level );
296}
297
298void sonic_clear_interrupts(
299  struct sonic_softc *sc,
[ee4f57d]300  uint32_t    mask
[f1f42b4]301)
302{
303  void *rp = sc->sonic;
304  rtems_interrupt_level level;
305
306  rtems_interrupt_disable( level );
307  (*sc->write_register)( rp, SONIC_REG_ISR, mask);
308  rtems_interrupt_enable( level );
309}
310
311void sonic_command(
312  struct sonic_softc *sc,
[ee4f57d]313  uint32_t    mask
[f1f42b4]314)
315{
316  void *rp = sc->sonic;
317  rtems_interrupt_level level;
318
319  rtems_interrupt_disable( level );
320  (*sc->write_register)( rp, SONIC_REG_CR, mask);
321  rtems_interrupt_enable( level );
322}
323
[c932d85]324/*
325 * Allocate non-cacheable memory on a single 64k page.
326 * Very simple minded -- just keeps trying till the memory is on a single page.
327 */
[301a2a3c]328SONIC_STATIC void * sonic_allocate(unsigned int nbytes)
[c932d85]329{
330  void *p;
331  unsigned long a1, a2;
332
333  for (;;) {
334    /*
335     * ===CACHE===
336     * Change malloc to malloc_noncacheable_guarded.
337     */
[bfcf4cb3]338    p = malloc( nbytes, M_MBUF, M_NOWAIT );
[c932d85]339    if (p == NULL)
340      rtems_panic ("No memory!");
[7dbab720]341    memset (p, '\0', nbytes);
[c932d85]342    a1 = (unsigned long)p;
343    a2 = a1 + nbytes - 1;
344    if ((a1 >> 16) == (a2 >> 16))
345      break;
346  }
[e70a8f16]347#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_ALLOCATE)
[dddc0557]348  printf( "sonic_allocate %d bytes at %p\n", nbytes, p );
349#endif
[c932d85]350  return p;
351}
352
353/*
354 * Shut down the interface.
355 */
[7fc5d54e]356
[bfcf4cb3]357SONIC_STATIC void sonic_stop (struct sonic_softc *sc)
[c932d85]358{
[bfcf4cb3]359  struct ifnet *ifp = &sc->arpcom.ac_if;
360
361  ifp->if_flags &= ~IFF_RUNNING;
[c932d85]362
363  /*
364   * Stop the transmitter and receiver.
365   */
[f1f42b4]366  sonic_command(sc, CR_HTX | CR_RXDIS );
[c932d85]367}
368
369/*
370 * Show interface statistics
371 */
[bfcf4cb3]372SONIC_STATIC void sonic_stats (struct sonic_softc *sc)
[c932d85]373{
[bfcf4cb3]374  printf (" Total Interrupts:%-8lu", sc->Interrupts);
375  printf ("    Rx Interrupts:%-8lu", sc->rxInterrupts);
376  printf ("            Giant:%-8lu", sc->rxGiant);
377  printf ("        Non-octet:%-8lu\n", sc->rxNonOctet);
378  printf ("          Bad CRC:%-8lu", sc->rxBadCRC);
379  printf ("        Collision:%-8lu", sc->rxCollision);
380  printf ("           Missed:%-8lu\n", sc->rxMissed);
381
382  printf (    "    Tx Interrupts:%-8lu", sc->txInterrupts);
383  printf (  "           Deferred:%-8lu", sc->txDeferred);
384  printf ("        Lost Carrier:%-8lu\n", sc->txLostCarrier);
385  printf (   "Single Collisions:%-8lu", sc->txSingleCollision);
386  printf ( "Multiple Collisions:%-8lu", sc->txMultipleCollision);
387  printf ("Excessive Collisions:%-8lu\n", sc->txExcessiveCollision);
388  printf (   " Total Collisions:%-8lu", sc->txCollision);
389  printf ( "     Late Collision:%-8lu", sc->txLateCollision);
390  printf ("            Underrun:%-8lu\n", sc->txUnderrun);
391  printf (   "  Raw output wait:%-8lu\n", sc->txRawWait);
[c932d85]392}
393
394/*
395 ******************************************************************
396 *                                                                *
397 *                        Interrupt Handler                       *
398 *                                                                *
399 ******************************************************************
400 */
[7fc5d54e]401
402SONIC_STATIC rtems_isr sonic_interrupt_handler (rtems_vector_number v)
[c932d85]403{
[bfcf4cb3]404  struct sonic_softc *sc = sonic_softc;
[ee4f57d]405  uint32_t   isr, imr;
[7fc5d54e]406  void *rp;
[c932d85]407
408#if (NSONIC > 1)
409  /*
410   * Find the device which requires service
411   */
412  for (;;) {
[bfcf4cb3]413    if (sc->vector == v)
[c932d85]414      break;
[bfcf4cb3]415    if (++sc == &sonic[NSONIC])
[c932d85]416      return;  /* Spurious interrupt? */
417  }
418#endif /* NSONIC > 1 */
419
420  /*
421   * Get pointer to SONIC registers
422   */
[bfcf4cb3]423  rp = sc->sonic;
[c932d85]424
[bfcf4cb3]425  sc->Interrupts++;
[1253f39]426
[13cc89e1]427  isr = (*sc->read_register)( rp, SONIC_REG_ISR );
428  imr = (*sc->read_register)( rp, SONIC_REG_IMR );
[7dbab720]429
[c932d85]430  /*
431   * Packet received or receive buffer area exceeded?
432   */
[f1f42b4]433  if (imr & isr & (IMR_PRXEN | IMR_RBAEEN)) {
[7dbab720]434    imr &= ~(IMR_PRXEN | IMR_RBAEEN);
[bfcf4cb3]435    sc->rxInterrupts++;
436    rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT);
[f1f42b4]437    (*sc->write_register)( rp, SONIC_REG_IMR, imr );
438    (*sc->write_register)( rp, SONIC_REG_ISR, isr & ISR_PKTRX );
[c932d85]439  }
440
441  /*
442   * Packet started, transmitter done or transmitter error?
[f1f42b4]443   * TX interrupts only occur after an error or when all TDA's are
444   * exhausted and we are waiting for buffer to come free.
[c932d85]445   */
[f1f42b4]446  if (imr & isr & (IMR_PINTEN | IMR_TXEREN)) {
[bfcf4cb3]447    sc->txInterrupts++;
448    rtems_event_send (sc->txDaemonTid, INTERRUPT_EVENT);
[f1f42b4]449    (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PINT | ISR_TXDN | ISR_TXER );
[c932d85]450  }
[7dbab720]451
[c932d85]452}
453
454/*
455 ******************************************************************
456 *                                                                *
457 *                      Transmitter Routines                      *
458 *                                                                *
459 ******************************************************************
460 */
461
462/*
463 * Soak up transmit descriptors that have been sent.
464 */
[7fc5d54e]465
[bfcf4cb3]466SONIC_STATIC void sonic_retire_tda (struct sonic_softc *sc)
[c932d85]467{
[ee4f57d]468  uint16_t   status;
[c932d85]469  unsigned int collisions;
[bfcf4cb3]470  struct mbuf *m, *n;
[c932d85]471
472  /*
473   * Repeat for all completed transmit descriptors.
474   */
[f1f42b4]475  while ((status = sc->tdaTail->status) != 0) {
[301a2a3c]476
[7d07970]477#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS)
[bfcf4cb3]478    printf( "retire TDA %p (0x%04x)\n", sc->tdaTail, status );
[7d07970]479#endif
480
[9693fac4]481#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
[7397638]482    /*
[a3d3d9a]483     *  If there is an error that was not a collision,
[7397638]484     *  then someone may want to see it.
485     */
486
487    if ( (status & ~(TDA_STATUS_COLLISION_MASK|TDA_STATUS_DEF)) != 0x0001 )
[811115de]488      printf( "ERROR: retire TDA %p (0x%08x)\n",
489                sc->tdaTail, sc->tdaTail->status );
[9693fac4]490#endif
491
[c932d85]492    /*
493     * Check for errors which stop the transmitter.
494     */
495    if (status & (TDA_STATUS_EXD |
496        TDA_STATUS_EXC |
497        TDA_STATUS_FU |
498        TDA_STATUS_BCM)) {
499      /*
500       * Restart the transmitter if there are
501       * packets waiting to go.
502       */
[ee4f57d]503      uint16_t   link;
[7397638]504#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
505      printf("restarting sonic after error\n");
506#endif
507
[bfcf4cb3]508      link = *(sc->tdaTail->linkp);
[c932d85]509
510      if ((link & TDA_LINK_EOL) == 0) {
[bfcf4cb3]511        void *rp = sc->sonic;
[c932d85]512
[13cc89e1]513        (*sc->write_register)( rp, SONIC_REG_CTDA, link );
[f1f42b4]514        sonic_command(sc, CR_TXP );
[c932d85]515      }
516    }
517
518    /*
519     * Update network statistics
520     */
521    collisions = (status & TDA_STATUS_COLLISION_MASK) >> TDA_STATUS_COLLISION_SHIFT;
522    if (collisions) {
523      if (collisions == 1)
[bfcf4cb3]524        sc->txSingleCollision++;
[c932d85]525      else
[bfcf4cb3]526        sc->txMultipleCollision++;
527      sc->txCollision += collisions;
[c932d85]528    }
529    if (status & TDA_STATUS_EXC)
[bfcf4cb3]530      sc->txExcessiveCollision++;
[c932d85]531    if (status & TDA_STATUS_OWC)
[bfcf4cb3]532      sc->txLateCollision++;
[c932d85]533    if (status & TDA_STATUS_EXD)
[bfcf4cb3]534      sc->txExcessiveDeferral++;
[c932d85]535    if (status & TDA_STATUS_DEF)
[bfcf4cb3]536      sc->txDeferred++;
[c932d85]537    if (status & TDA_STATUS_FU)
[bfcf4cb3]538      sc->txUnderrun++;
[c932d85]539    if (status & TDA_STATUS_CRSL)
[bfcf4cb3]540      sc->txLostCarrier++;
[c932d85]541
542    /*
[ae320e0]543     *  Free the packet and reset a couple of fields
[c932d85]544     */
[811115de]545    m = sc->tdaTail->mbufp;
546    while ( m ) {
547      MFREE(m, n);
548      m = n;
549    }
[c932d85]550
[f1f42b4]551    /*
[bfcf4cb3]552    sc->tdaTail->frag[0].frag_link = LSW(sc->tdaTail->link_pad);
553    sc->tdaTail->frag_count        = 0;
[f1f42b4]554    */
555    sc->tdaTail->status        = 0;
[339737b]556
[c932d85]557    /*
558     * Move to the next transmit descriptor
559     */
[bfcf4cb3]560    sc->tdaTail = sc->tdaTail->next;
[7d07970]561#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS)
[bfcf4cb3]562    printf( "next TDA %p\n", sc->tdaTail );
[7d07970]563#endif
[c932d85]564  }
565}
566
567/*
[bfcf4cb3]568 * Send packet
[c932d85]569 */
[bfcf4cb3]570SONIC_STATIC void sonic_sendpacket (struct ifnet *ifp, struct mbuf *m)
[c932d85]571{
[bfcf4cb3]572  struct sonic_softc *sc = ifp->if_softc;
573  struct mbuf *l = NULL;
[c932d85]574  TransmitDescriptorPointer_t tdp;
575  volatile struct TransmitDescriptorFragLink *fp;
576  unsigned int packetSize;
577  int i;
[f1f42b4]578  rtems_event_set events;
[c932d85]579  static char padBuf[64];
580
[7397638]581  /* printf( "sonic_sendpacket %p\n", m ); */
[f1f42b4]582
583
[c932d85]584  /*
[f1f42b4]585   * Wait for transmit descriptor to become available. Only retire TDA's
586   * if there are no more free buffers to minimize TX latency. Retire TDA'a
587   * on the way out.
[c932d85]588   */
589
[f1f42b4]590  while (sc->tdaHead->next->status != 0) {
[a3d3d9a]591
[c932d85]592  /*
[f1f42b4]593   * Free up transmit descriptors
[c932d85]594   */
[bfcf4cb3]595    sonic_retire_tda (sc);
[f1f42b4]596
[a3d3d9a]597    if (sc->tdaHead->next->status == 0)
[f1f42b4]598      break;
[7397638]599
600#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
[f1f42b4]601    printf("blocking until TDAs are available\n");
[7397638]602#endif
[c932d85]603      /*
[f1f42b4]604       * Enable PINT interrupts.
605    sonic_clear_interrupts( sc, ISR_PINT );
606    sonic_enable_interrupts( sc, IMR_PINTEN );
[c932d85]607       */
608
609      /*
[f1f42b4]610       * Wait for PINT TX interrupt. Every fourth TX buffer will raise PINT.
[c932d85]611       */
[f1f42b4]612    rtems_bsdnet_event_receive (INTERRUPT_EVENT,
[c932d85]613            RTEMS_WAIT|RTEMS_EVENT_ANY,
[bfcf4cb3]614            RTEMS_NO_TIMEOUT,
615            &events);
[f1f42b4]616    sonic_disable_interrupts( sc, IMR_PINTEN );
617    sonic_retire_tda (sc);
[c932d85]618  }
619
620  /*
621   * Fill in the transmit descriptor fragment descriptors.
622   * ===CACHE===
623   * If data cache is operating in write-back mode, flush cached
624   * data to memory.
625   */
[bfcf4cb3]626  tdp = sc->tdaHead->next;
627  tdp->mbufp = m;
[c932d85]628  packetSize = 0;
629  fp = tdp->frag;
630  for (i = 0 ; i < MAXIMUM_FRAGS_PER_DESCRIPTOR ; i++, fp++) {
[bfcf4cb3]631    /*
632     * Throw away empty mbufs
633     */
634    if (m->m_len) {
635      void *p = mtod (m, void *);
636      fp->frag_lsw = LSW(p);
637      fp->frag_msw = MSW(p);
638      fp->frag_size = m->m_len;
639      packetSize += m->m_len;
[301a2a3c]640#if (SONIC_DEBUG & SONIC_DEBUG_FRAGMENTS)
[7dbab720]641      printf( "fp %p 0x%04x%04x %d=%d .. %d\n",
642        fp, fp->frag_msw, fp->frag_lsw, fp->frag_size, m->m_len, packetSize );
[301a2a3c]643#endif
[7dbab720]644#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_TX_MBUFS)
[d6236b41]645      rtems_print_buffer(
[7dbab720]646        p,
647        (fp->frag_size > MAXIMUM_FRAME_SIZE) ? MAXIMUM_FRAME_SIZE : fp->frag_size
648      );
649#endif
650      l = m;
651      m = m->m_next;
[bfcf4cb3]652    }
653    else {
654      struct mbuf *n;
655      MFREE (m, n);
656      m = n;
657      if (l != NULL)
658        l->m_next = m;
659    }
[c932d85]660    /*
661     * Break out of the loop if this mbuf is the last in the frame.
662     */
[bfcf4cb3]663    if (m == NULL)
[c932d85]664      break;
665  }
666
667  /*
668   * Pad short packets.
669   */
670  if  ((packetSize < 64) && (i < MAXIMUM_FRAGS_PER_DESCRIPTOR)) {
671    int padSize = 64 - packetSize;
[301a2a3c]672    fp++;
[c932d85]673    fp->frag_lsw = LSW(padBuf);
674    fp->frag_msw = MSW(padBuf);
675    fp->frag_size = padSize;
[301a2a3c]676#if (SONIC_DEBUG & SONIC_DEBUG_FRAGMENTS)
677    printf( "PAD fp %p 0x%04x%04x %d\n",
678         fp, fp->frag_msw, fp->frag_lsw, fp->frag_size );
679#endif
[c932d85]680    packetSize += padSize;
681    i++;
682  }
683
684  /*
685   * Fill Transmit Descriptor
686   */
687  tdp->pkt_size = packetSize;
[301a2a3c]688  tdp->frag_count = i + 1;
[c932d85]689  tdp->status = 0;
690
691  /*
692   * Chain onto list and start transmission.
693   */
[339737b]694
[301a2a3c]695  tdp->linkp = &(fp+1)->frag_link;
[c932d85]696  *tdp->linkp = LSW(tdp->next) | TDA_LINK_EOL;
[bfcf4cb3]697  if ( sc->tdaHead->frag_count )
698    *sc->tdaHead->linkp &= ~TDA_LINK_EOL;
699  sc->tdaHead = tdp;
[0c0419a1]700
[f1f42b4]701  /* Start transmission */
702
703  sonic_command(sc, CR_TXP );
704
705  /*
706   * Free up transmit descriptors on the way out.
707   */
708  sonic_retire_tda (sc);
[bfcf4cb3]709}
[c932d85]710
[bfcf4cb3]711/*
712 * Driver transmit daemon
713 */
714SONIC_STATIC void sonic_txDaemon (void *arg)
715{
716  struct sonic_softc *sc = (struct sonic_softc *)arg;
717  struct ifnet *ifp = &sc->arpcom.ac_if;
718  struct mbuf *m;
719  rtems_event_set events;
720
721  for (;;) {
722    /*
723     * Wait for packet
724     */
725    rtems_bsdnet_event_receive (
726       START_TRANSMIT_EVENT,
727       RTEMS_EVENT_ANY | RTEMS_WAIT,
728       RTEMS_NO_TIMEOUT,
729       &events
730    );
[c153a7b]731
[bfcf4cb3]732    /*
733     * Send packets till queue is empty
734     */
735    for (;;) {
736      /*
737       * Get the next mbuf chain to transmit.
738       */
739      IF_DEQUEUE(&ifp->if_snd, m);
740      if (!m)
741        break;
742      sonic_sendpacket (ifp, m);
743    }
744    ifp->if_flags &= ~IFF_OACTIVE;
745  }
[c932d85]746}
747
748/*
749 ******************************************************************
750 *                                                                *
751 *                        Receiver Routines                       *
752 *                                                                *
753 ******************************************************************
754 */
755
756/*
757 * Wait for SONIC to hand over a Receive Descriptor.
758 */
[7fc5d54e]759
760SONIC_STATIC void sonic_rda_wait(
[bfcf4cb3]761  struct sonic_softc *sc,
[7fc5d54e]762  ReceiveDescriptorPointer_t rdp
763)
[c932d85]764{
765  int i;
[bfcf4cb3]766  void *rp = sc->sonic;
767  rtems_event_set events;
[c932d85]768
769  /*
770   * Wait for Receive Descriptor.
771   * The order of the tests is very important.
772   *    The RDA is checked after RBAE is detected.  This ensures that
773   *    the driver processes all RDA entries before reusing the RRA
774   *    entry holding the giant packet.
775   *    The event wait is done after the RDA and RBAE checks.  This
776   *    catches the possibility that a Receive Descriptor became ready
777   *    between the call to this function and the clearing of the
778   *    interrupt status register bit.
779   */
780  for (;;) {
781    /*
782     * Has a giant packet arrived?
783     * The National DP83932C data sheet is very vague on what
784     * happens under this condition.  The description of the
785     * Interrupt Status Register (Section 4.3.6) states,
786     * ``Reception is aborted and the SONIC fetches the next
787     * available resource descriptors in the RRA.  The buffer
788     * space is not re-used and an RDA is not setup for the
789     * truncated packet.''
790     * I take ``Reception is aborted''  to mean that the RXEN
791     * bit in the Command Register is cleared and must be set
792     * by the driver to begin reception again.
793     * Unfortunately, an alternative interpretation could be
794     * that only reception of the current packet is aborted.
795     * This would be more difficult to recover from....
796     */
[13cc89e1]797    if ((*sc->read_register)( rp, SONIC_REG_ISR ) & ISR_RBAE) {
[9693fac4]798
799#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
800      printf( "ERROR: looks like a giant packet -- RBAE\n" );
801#endif
802
[c932d85]803      /*
804       * One more check to soak up any Receive Descriptors
805       * that may already have been handed back to the driver.
806       */
[9693fac4]807      if (rdp->in_use == RDA_IN_USE) {
808#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
809      printf( "ERROR: nope just an RBAE\n" );
810#endif
[c932d85]811        break;
[9693fac4]812      }
[c932d85]813
814      /*
815       * Check my interpretation of the SONIC manual.
816       */
[13cc89e1]817      if ((*sc->read_register)( rp, SONIC_REG_CR ) & CR_RXEN)
[c932d85]818        rtems_panic ("SONIC RBAE/RXEN");
819
820      /*
821       * Update statistics
822       */
[bfcf4cb3]823      sc->rxGiant++;
[c932d85]824
825      /*
826       * Reuse receive buffer.
827       * Again, the manual is subject to interpretation.  The
828       * RRP register is described as, `the lower address of
829       * the next descriptor the SONIC will read.''
830       * Since, acording to the ISR/RBAE notes, the SONIC has
831       * ``fetched the next available resource descriptor in
832       * the RRA'', I interpret this to mean that that the
833       * driver has to move the RRP back *two* entries to
834       * reuse the receive buffer holding the giant packet.
835       */
836      for (i = 0 ; i < 2 ; i++) {
[13cc89e1]837        if ((*sc->read_register)( rp, SONIC_REG_RRP ) ==
838            (*sc->read_register)( rp, SONIC_REG_RSA ))
839          (*sc->write_register)(
[7fc5d54e]840            rp,
841            SONIC_REG_RRP,
[13cc89e1]842            (*sc->read_register)( rp, SONIC_REG_REA )
[7fc5d54e]843          );
[13cc89e1]844          (*sc->write_register)(
[7fc5d54e]845             rp,
846             SONIC_REG_RRP,
[13cc89e1]847             (*sc->read_register)(rp, SONIC_REG_RRP) - sizeof(ReceiveResource_t)
[7fc5d54e]848          );
[c932d85]849      }
850
851      /*
852       * Restart reception
853       */
[f1f42b4]854      sonic_clear_interrupts( sc, ISR_RBAE );
855      sonic_command( sc, CR_RXEN );
[c932d85]856    }
857
858    /*
859     * Has Receive Descriptor become available?
860     */
[e70a8f16]861    if (rdp->in_use == RDA_IN_USE)
[c932d85]862      break;
863
864    /*
865     * Enable interrupts.
866     */
[13cc89e1]867    sonic_enable_interrupts( sc, (IMR_PRXEN | IMR_RBAEEN) );
[c932d85]868
869    /*
870     * Wait for interrupt.
871     */
[bfcf4cb3]872    rtems_bsdnet_event_receive(
873      INTERRUPT_EVENT,
874      RTEMS_WAIT|RTEMS_EVENT_ANY,
875      RTEMS_NO_TIMEOUT,
876      &events
877    );
[c932d85]878  }
[4f38b713]879#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS)
880  printf( "RDA %p\n", rdp );
881#endif
[9693fac4]882
883#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS)
884    if (rdp->status & 0x000E)
885      printf( "ERROR: RDA %p (0x%04x)\n", rdp, rdp->status );
886#endif
887
[c932d85]888}
889
[f6ef823a]890#ifdef CPU_U32_FIX
891
892/*
893 * Routine to align the received packet so that the ip header
894 * is on a 32-bit boundary. Necessary for cpu's that do not
895 * allow unaligned loads and stores and when the 32-bit DMA
[a3d3d9a]896 * mode is used.
897 *
898 * Transfers are done on word basis to avoid possibly slow byte
[f6ef823a]899 * and half-word writes.
900 */
[a3d3d9a]901
[f6ef823a]902void ipalign(struct mbuf *m)
903{
904  unsigned int *first, *last, data;
905  unsigned int tmp = 0;
906
907  if ((((int) m->m_data) & 2) && (m->m_len)) {
908    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
909    first = (unsigned int *) (((int) m->m_data) & ~3);
910    tmp = *first << 16;
911    first++;
912    do {
913      data = *first;
914      *first = tmp | (data >> 16);
915      tmp = data << 16;
916      first++;
917    } while (first <= last);
918
919    m->m_data = (caddr_t)(((int) m->m_data) + 2);
920  }
921}
922#endif
923
[c932d85]924/*
[bfcf4cb3]925 * SONIC reader task
[c932d85]926 */
[bfcf4cb3]927SONIC_STATIC void sonic_rxDaemon (void *arg)
[c932d85]928{
[bfcf4cb3]929  struct sonic_softc *sc = (struct sonic_softc *)arg;
930  struct ifnet *ifp = &sc->arpcom.ac_if;
931  void *rp = sc->sonic;
932  struct mbuf *m;
[ee4f57d]933  uint16_t   status;
[dddc0557]934  ReceiveDescriptorPointer_t rdp;
[c932d85]935  ReceiveResourcePointer_t rwp, rea;
[ee4f57d]936  uint16_t   newMissedTally, oldMissedTally;
[c932d85]937
[bfcf4cb3]938  rwp = sc->rsa;
939  rea = sc->rea;
940  rdp = sc->rda;
[c932d85]941
942  /*
943   * Start the receiver
944   */
[13cc89e1]945  oldMissedTally = (*sc->read_register)( rp, SONIC_REG_MPT );
[c932d85]946
947  /*
948   * Input packet handling loop
949   */
950  for (;;) {
951    /*
952     * Wait till SONIC supplies a Receive Descriptor.
953     */
[e70a8f16]954    if (rdp->in_use == RDA_FREE) {
[bfcf4cb3]955      sonic_rda_wait (sc, rdp);
[c932d85]956    }
957
[4f38b713]958#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS)
959    printf( "Incoming packet %p status=0x%04x\n", rdp, rdp->status );
960#endif
[e70a8f16]961
[c932d85]962    /*
963     * Check that packet is valid
964     */
965    status = rdp->status;
966    if (status & RDA_STATUS_PRX) {
[bfcf4cb3]967      struct ether_header *eh;
[c932d85]968      void *p;
969
970      /*
971       * Pass the packet up the chain.
972       * The mbuf count is reduced to remove
973       * the frame check sequence at the end
974       * of the packet.
975       * ===CACHE===
976       * Invalidate cache entries for this memory.
977       */
[811115de]978#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
979      sonic_print_rx_descriptor( rdp );
[f1f42b4]980      if ((LSW(rdp->mbufp->m_data) != rdp->pkt_lsw)
981       || (MSW(rdp->mbufp->m_data) != rdp->pkt_msw))
[a3d3d9a]982        printf ("SONIC RDA/RRA %p, %08x\n",rdp->mbufp->m_data,(rdp->pkt_msw << 16) |
[f1f42b4]983        (rdp->pkt_lsw & 0x0ffff));
[811115de]984#endif
[f1f42b4]985      rdp->byte_count &= 0x0ffff;    /* ERC32 pollutes msb of byte_count */
[7dbab720]986      m = rdp->mbufp;
[bfcf4cb3]987      m->m_len = m->m_pkthdr.len = rdp->byte_count -
[509fec9c]988                          sizeof(uint32_t) -
[bfcf4cb3]989                          sizeof(struct ether_header);
990      eh = mtod (m, struct ether_header *);
991      m->m_data += sizeof(struct ether_header);
[a3d3d9a]992
[f1f42b4]993#ifdef CPU_U32_FIX
994      ipalign(m);       /* Align packet on 32-bit boundary */
995#endif
996
[7dbab720]997#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_RX_MBUFS)
[d6236b41]998      rtems_print_buffer( (void *) eh, sizeof(struct ether_header) );
999      rtems_print_buffer( (void *) m, 96 /* m->m_len*/ );
[7dbab720]1000#endif
1001
[7397638]1002      /* printf( "ether_input %p\n", m ); */
[f1f42b4]1003      /*
1004      printf( "pkt %p, seq %04x, mbuf %p, m_data %p\n", rdp, rdp->seq_no, m, m->m_data );
1005      printf( "%u, %u\n", ((int*)m->m_data)[6], ((int*)m->m_data)[7]);
1006      */
[bfcf4cb3]1007      ether_input (ifp, eh, m);
[f1f42b4]1008      /*
1009      */
[c932d85]1010
1011      /*
1012       * Sanity check that Receive Resource Area is
1013       * still in sync with Receive Descriptor Area
1014       * The buffer reported in the Receive Descriptor
1015       * should be the same as the buffer in the Receive
1016       * Resource we are about to reuse.
1017       */
[dddc0557]1018/* XXX figure out whether this is valid or not */
1019#if 0
[c932d85]1020      if ((LSW(p) != rwp->buff_ptr_lsw)
1021       || (MSW(p) != rwp->buff_ptr_msw))
1022        rtems_panic ("SONIC RDA/RRA");
[dddc0557]1023#endif
[c932d85]1024
1025      /*
1026       * Allocate a new mbuf.
1027       */
[7dbab720]1028
[bfcf4cb3]1029      MGETHDR (m, M_WAIT, MT_DATA);
1030      MCLGET (m, M_WAIT);
1031      m->m_pkthdr.rcvif = ifp;
[7dbab720]1032      rdp->mbufp = m;
[bfcf4cb3]1033      p = mtod (m, void *);
[c932d85]1034
1035      /*
1036       * Reuse Receive Resource.
1037       */
[7dbab720]1038
[bfcf4cb3]1039      rwp->buff_ptr_lsw = LSW(p);
1040      rwp->buff_ptr_msw = MSW(p);
[7dbab720]1041      rwp->buff_wc_lsw = RBUF_WC;
1042      rwp->buff_wc_msw = 0;
[c932d85]1043      rwp++;
[7dbab720]1044
[4f38b713]1045      if (rwp == rea) {
1046#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
[bfcf4cb3]1047        printf( "Wrapping RWP from %p to %p\n", rwp, sc->rsa );
[4f38b713]1048#endif
[bfcf4cb3]1049        rwp = sc->rsa;
[4f38b713]1050      }
[13cc89e1]1051      (*sc->write_register)( rp, SONIC_REG_RWP , LSW(rwp) );
[c932d85]1052
1053      /*
1054       * Tell the SONIC to reread the RRA.
1055       */
[13cc89e1]1056      if ((*sc->read_register)( rp, SONIC_REG_ISR ) & ISR_RBE)
[f1f42b4]1057      sonic_clear_interrupts( sc, ISR_RBE );
[c932d85]1058    }
1059    else {
1060      if (status & RDA_STATUS_COL)
[bfcf4cb3]1061        sc->rxCollision++;
[c932d85]1062      if (status & RDA_STATUS_FAER)
[bfcf4cb3]1063        sc->rxNonOctet++;
[c932d85]1064      else if (status & RDA_STATUS_CRCR)
[bfcf4cb3]1065        sc->rxBadCRC++;
[c932d85]1066    }
1067
1068    /*
1069     * Count missed packets
1070     */
[13cc89e1]1071    newMissedTally = (*sc->read_register)( rp, SONIC_REG_MPT );
[c932d85]1072    if (newMissedTally != oldMissedTally) {
[bfcf4cb3]1073      sc->rxMissed += (newMissedTally - oldMissedTally) & 0xFFFF;
[c932d85]1074      newMissedTally = oldMissedTally;
1075    }
1076
1077    /*
[f1f42b4]1078     * Move to next receive descriptor and update EOL
[c932d85]1079     */
[7dbab720]1080
[f1f42b4]1081    rdp->link |= RDA_LINK_EOL;
[e70a8f16]1082    rdp->in_use = RDA_FREE;
[f1f42b4]1083    sc->rdp_last->link &= ~RDA_LINK_EOL;
1084    sc->rdp_last = rdp;
[c932d85]1085    rdp = rdp->next;
[7dbab720]1086
[c932d85]1087  }
1088}
1089
1090/*
1091 ******************************************************************
1092 *                                                                *
1093 *                     Initialization Routines                    *
1094 *                                                                *
1095 ******************************************************************
1096 */
1097
1098/*
1099 * Initialize the SONIC hardware
1100 */
[bfcf4cb3]1101SONIC_STATIC void sonic_initialize_hardware(struct sonic_softc *sc)
[c932d85]1102{
[bfcf4cb3]1103  void *rp = sc->sonic;
[c932d85]1104  int i;
1105  unsigned char *hwaddr;
[339737b]1106  TransmitDescriptorPointer_t tdp;
[dddc0557]1107  ReceiveDescriptorPointer_t ordp, rdp;
[4f38b713]1108  ReceiveResourcePointer_t rwp;
[bfcf4cb3]1109  struct mbuf *m;
1110  void *p;
[301a2a3c]1111  CamDescriptorPointer_t cdp;
[c932d85]1112
[e70a8f16]1113  /*
1114   *  The Revision B SONIC has a horrible bug known as the "Zero
1115   *  Length Packet bug".  The initial board used to develop this
1116   *  driver had a newer revision of the SONIC so there was no reason
1117   *  to check for this.  If you have the Revision B SONIC chip, then
1118   *  you need to add some code to the RX path to handle this weirdness.
1119   */
1120
[f1f42b4]1121  if ( (*sc->read_register)( rp, SONIC_REG_SR ) <= SONIC_REVISION_B ) {
[e70a8f16]1122    rtems_fatal_error_occurred( 0x0BADF00D );  /* don't eat this part :) */
1123  }
[a3d3d9a]1124
[c932d85]1125  /*
[dddc0557]1126   *  Set up circular linked list in Transmit Descriptor Area.
1127   *  Use the PINT bit in the transmit configuration field to
1128   *  request an interrupt on every other transmitted packet.
1129   *
1130   *  NOTE: sonic_allocate() zeroes all of the memory allocated.
[c932d85]1131   */
[dddc0557]1132
[bfcf4cb3]1133  sc->tdaTail = sonic_allocate(sc->tdaCount * sizeof *tdp);
[e995f3a1]1134#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
[bfcf4cb3]1135  printf( "tdaTail = %p\n", sc->tdaTail );
[e995f3a1]1136#endif
[bfcf4cb3]1137  tdp = sc->tdaTail;
1138  for (i = 0 ; i < sc->tdaCount ; i++) {
[7dbab720]1139    /*
[a3d3d9a]1140     *  Start off with the table of outstanding mbuf's
[7dbab720]1141     */
1142
[301a2a3c]1143    /*
[a3d3d9a]1144     *  status, pkt_config, pkt_size, and all fragment fields
[301a2a3c]1145     *  are set to zero by sonic_allocate.
1146     */
1147
[ae320e0]1148/* XXX not used by the BSD drivers
[f1f42b4]1149    tdp->frag[0].frag_link = LSW(tdp + 1);
[7397638]1150*/
[f1f42b4]1151    if (i & 3)
[dddc0557]1152      tdp->pkt_config = TDA_CONFIG_PINT;
[301a2a3c]1153
[f1f42b4]1154    tdp->status         = 0;
1155    tdp->frag_count     = 0;
1156    tdp->link_pad       = LSW(tdp + 1) | TDA_LINK_EOL;
1157    tdp->linkp          = &((tdp + 1)->frag[0].frag_link);
1158    tdp->next           = (TransmitDescriptor_t *)(tdp + 1);
[811115de]1159#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
1160    sonic_print_tx_descriptor( tdp );
1161#endif
[301a2a3c]1162    tdp++;
[dddc0557]1163  }
[339737b]1164  tdp--;
[bfcf4cb3]1165  sc->tdaHead = tdp;
1166  tdp->link_pad = LSW(sc->tdaTail) | TDA_LINK_EOL;
1167  tdp->next = (TransmitDescriptor_t *)sc->tdaTail;
1168  tdp->linkp = &sc->tdaTail->frag[0].frag_link;
[dddc0557]1169
1170  /*
1171   *  Set up circular linked list in Receive Descriptor Area.
[bfcf4cb3]1172   *  Leaves sc->rda pointing at the `beginning' of the list.
[301a2a3c]1173   *
1174   *  NOTE: The RDA and CDP must have the same MSW for their addresses.
[dddc0557]1175   */
1176
[bfcf4cb3]1177  sc->rda = sonic_allocate(
[a3d3d9a]1178              (sc->rdaCount * sizeof(ReceiveDescriptor_t)) +
[301a2a3c]1179                sizeof(CamDescriptor_t) );
[bfcf4cb3]1180  sc->cdp = (CamDescriptorPointer_t) ((unsigned char *)sc->rda +
1181        (sc->rdaCount * sizeof(ReceiveDescriptor_t)));
[e995f3a1]1182#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
[bfcf4cb3]1183  printf( "rda area = %p\n", sc->rda );
1184  printf( "cdp area = %p\n", sc->cdp );
[e995f3a1]1185#endif
[e70a8f16]1186
[bfcf4cb3]1187  ordp = rdp = sc->rda;
1188  for (i = 0 ; i < sc->rdaCount ; i++) {
[dddc0557]1189    /*
[e70a8f16]1190     *  status, byte_count, pkt_ptr0, pkt_ptr1, and seq_no are set
1191     *  to zero by sonic_allocate.
[dddc0557]1192     */
[e70a8f16]1193    rdp->link   = LSW(rdp + 1);
1194    rdp->in_use = RDA_FREE;
1195    rdp->next   = (ReceiveDescriptor_t *)(rdp + 1);
[dddc0557]1196    ordp = rdp;
[e70a8f16]1197    rdp++;
[dddc0557]1198  }
[e70a8f16]1199  /*
1200   *  Link the last desriptor to the 1st one and mark it as the end
1201   *  of the list.
1202   */
[bfcf4cb3]1203  ordp->next   = sc->rda;
1204  ordp->link   = LSW(sc->rda) | RDA_LINK_EOL;
[f1f42b4]1205  sc->rdp_last = ordp;
[a3d3d9a]1206
[dddc0557]1207  /*
1208   * Allocate the receive resource area.
1209   * In accordance with National Application Note 746, make the
1210   * receive resource area bigger than the receive descriptor area.
1211   * This has the useful side effect of making the receive resource
1212   * area big enough to hold the CAM descriptor area.
1213   */
[e995f3a1]1214
[bfcf4cb3]1215  sc->rsa = sonic_allocate((sc->rdaCount + RRA_EXTRA_COUNT) * sizeof *sc->rsa);
[e995f3a1]1216#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
[bfcf4cb3]1217  printf( "rsa area = %p\n", sc->rsa );
[dddc0557]1218#endif
1219
1220  /*
1221   *  Set up list in Receive Resource Area.
1222   *  Allocate space for incoming packets.
1223   */
1224
[bfcf4cb3]1225  rwp = sc->rsa;
1226  for (i = 0 ; i < (sc->rdaCount + RRA_EXTRA_COUNT) ; i++, rwp++) {
[dddc0557]1227
1228    /*
1229     * Allocate memory for buffer.
1230     * Place a pointer to the mbuf at the beginning of the buffer
1231     * so we can find the mbuf when the SONIC returns the buffer
1232     * to the driver.
1233     */
[a3d3d9a]1234
[bfcf4cb3]1235    MGETHDR (m, M_WAIT, MT_DATA);
1236    MCLGET (m, M_WAIT);
1237    m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
[7dbab720]1238    sc->rda[i].mbufp = m;
[bfcf4cb3]1239
1240    p = mtod (m, void *);
[dddc0557]1241
1242    /*
1243     * Set up RRA entry
1244     */
[bfcf4cb3]1245    rwp->buff_ptr_lsw = LSW(p);
1246    rwp->buff_ptr_msw = MSW(p);
[dddc0557]1247    rwp->buff_wc_lsw = RBUF_WC;
1248    rwp->buff_wc_msw = 0;
[811115de]1249#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)
1250    sonic_print_rx_descriptor( &sc->rda[i] );
1251#endif
[dddc0557]1252  }
[bfcf4cb3]1253  sc->rea = rwp;
[4f38b713]1254#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY)
[bfcf4cb3]1255  printf( "rea area = %p\n", sc->rea );
[4f38b713]1256#endif
1257
[dddc0557]1258
1259  /*
1260   * Issue a software reset.
1261   */
[13cc89e1]1262  (*sc->write_register)( rp, SONIC_REG_CR, CR_RST | CR_STP | CR_RXDIS | CR_HTX );
[c932d85]1263
1264  /*
1265   * Set up data configuration registers.
1266   */
[13cc89e1]1267  (*sc->write_register)( rp, SONIC_REG_DCR, sc->dcr_value );
1268  (*sc->write_register)( rp, SONIC_REG_DCR2, sc->dc2_value );
[dddc0557]1269
[13cc89e1]1270  (*sc->write_register)( rp, SONIC_REG_CR, CR_STP | CR_RXDIS | CR_HTX );
[c932d85]1271
1272  /*
[7fc5d54e]1273   * Mask all interrupts
[c932d85]1274   */
[13cc89e1]1275  (*sc->write_register)( rp, SONIC_REG_IMR, 0x0 ); /* XXX was backwards */
[7fc5d54e]1276
[c932d85]1277  /*
1278   * Clear outstanding interrupts.
1279   */
[13cc89e1]1280  (*sc->write_register)( rp, SONIC_REG_ISR, 0x7FFF );
[c932d85]1281
[7fc5d54e]1282  /*
[dddc0557]1283   *  Clear the tally counters
[7fc5d54e]1284   */
[dddc0557]1285
[13cc89e1]1286  (*sc->write_register)( rp, SONIC_REG_CRCT, 0xFFFF );
1287  (*sc->write_register)( rp, SONIC_REG_FAET, 0xFFFF );
1288  (*sc->write_register)( rp, SONIC_REG_MPT, 0xFFFF );
1289  (*sc->write_register)( rp, SONIC_REG_RSC, 0 );
[dddc0557]1290
[c932d85]1291  /*
[dddc0557]1292   *  Set the Receiver mode
1293   *
1294   *  Enable/disable reception of broadcast packets
[c932d85]1295   */
[dddc0557]1296
[bfcf4cb3]1297  if (sc->acceptBroadcast)
[13cc89e1]1298    (*sc->write_register)( rp, SONIC_REG_RCR, RCR_BRD );
[dddc0557]1299  else
[13cc89e1]1300    (*sc->write_register)( rp, SONIC_REG_RCR, 0 );
[dddc0557]1301
1302  /*
1303   * Set up Resource Area pointers
1304   */
[301a2a3c]1305
[13cc89e1]1306  (*sc->write_register)( rp, SONIC_REG_URRA, MSW(sc->rsa) );
1307  (*sc->write_register)( rp, SONIC_REG_RSA, LSW(sc->rsa) );
[dddc0557]1308
[13cc89e1]1309  (*sc->write_register)( rp, SONIC_REG_REA, LSW(sc->rea) );
[dddc0557]1310
[13cc89e1]1311  (*sc->write_register)( rp, SONIC_REG_RRP, LSW(sc->rsa) );
1312  (*sc->write_register)( rp, SONIC_REG_RWP, LSW(sc->rsa) ); /* XXX was rea */
[dddc0557]1313
[13cc89e1]1314  (*sc->write_register)( rp, SONIC_REG_URDA, MSW(sc->rda) );
1315  (*sc->write_register)( rp, SONIC_REG_CRDA, LSW(sc->rda) );
[dddc0557]1316
[13cc89e1]1317  (*sc->write_register)( rp, SONIC_REG_UTDA, MSW(sc->tdaTail) );
1318  (*sc->write_register)( rp, SONIC_REG_CTDA, LSW(sc->tdaTail) );
[dddc0557]1319
1320  /*
1321   * Set End Of Buffer Count register to the value recommended
1322   * in Note 1 of Section 3.4.4.4 of the SONIC data sheet.
1323   */
1324
[13cc89e1]1325  (*sc->write_register)( rp, SONIC_REG_EOBC, RBUF_WC - 2 );
[dddc0557]1326
1327  /*
1328   *  Issue the load RRA command
1329   */
1330
[13cc89e1]1331  (*sc->write_register)( rp, SONIC_REG_CR, CR_RRRA );
1332  while ((*sc->read_register)( rp, SONIC_REG_CR ) & CR_RRRA)
[dddc0557]1333    continue;
1334
1335  /*
1336   * Remove device reset
1337   */
1338
[13cc89e1]1339  (*sc->write_register)( rp, SONIC_REG_CR, 0 );
[c932d85]1340
1341  /*
[7344fba9]1342   *  Set up the SONIC CAM with our hardware address.
[c932d85]1343   */
[7344fba9]1344
[bfcf4cb3]1345  hwaddr = sc->arpcom.ac_enaddr;
1346  cdp = sc->cdp;
[301a2a3c]1347
1348#if (SONIC_DEBUG & SONIC_DEBUG_CAM)
1349  printf( "hwaddr: %2x:%2x:%2x:%2x:%2x:%2x\n",
1350     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5] );
1351#endif
[dddc0557]1352
[7344fba9]1353  cdp->cep  = 0;                     /* Fill first and only entry in CAM */
1354  cdp->cap0 = hwaddr[1] << 8 | hwaddr[0];
1355  cdp->cap1 = hwaddr[3] << 8 | hwaddr[2];
1356  cdp->cap2 = hwaddr[5] << 8 | hwaddr[4];
1357  cdp->ce   = 0x0001;                /* Enable first entry in CAM */
1358
[13cc89e1]1359  (*sc->write_register)( rp, SONIC_REG_CDC, 1 );      /* 1 entry in CDA */
1360  (*sc->write_register)( rp, SONIC_REG_CDP, LSW(cdp) );
1361  (*sc->write_register)( rp, SONIC_REG_CR,  CR_LCAM );  /* Load the CAM */
[7344fba9]1362
[13cc89e1]1363  while ((*sc->read_register)( rp, SONIC_REG_CR ) & CR_LCAM)
[c932d85]1364    continue;
1365
1366  /*
1367   * Verify that CAM was properly loaded.
1368   */
[e70a8f16]1369
[13cc89e1]1370  (*sc->write_register)( rp, SONIC_REG_CR, CR_RST | CR_STP | CR_RXDIS | CR_HTX );
[e70a8f16]1371
[301a2a3c]1372#if (SONIC_DEBUG & SONIC_DEBUG_CAM)
[13cc89e1]1373  (*sc->write_register)( rp, SONIC_REG_CEP, 0 );  /* Select first entry in CAM */
[301a2a3c]1374    printf ("Loaded Ethernet address into SONIC CAM.\n"
1375      "  Wrote %04x%04x%04x - %#x\n"
[a3d3d9a]1376      "   Read %04x%04x%04x - %#x\n",
[7344fba9]1377        cdp->cap2, cdp->cap1, cdp->cap0, cdp->ce,
[13cc89e1]1378        (*sc->read_register)( rp, SONIC_REG_CAP2 ),
1379        (*sc->read_register)( rp, SONIC_REG_CAP1 ),
1380        (*sc->read_register)( rp, SONIC_REG_CAP0 ),
1381        (*sc->read_register)( rp, SONIC_REG_CE ));
[301a2a3c]1382
[13cc89e1]1383  (*sc->write_register)( rp, SONIC_REG_CEP, 0 );  /* Select first entry in CAM */
1384  if (((*sc->read_register)( rp, SONIC_REG_CAP2 ) != cdp->cap2)
1385   || ((*sc->read_register)( rp, SONIC_REG_CAP1 ) != cdp->cap1)
1386   || ((*sc->read_register)( rp, SONIC_REG_CAP0 ) != cdp->cap0)
1387   || ((*sc->read_register)( rp, SONIC_REG_CE ) != cdp->ce)) {
[c932d85]1388    printf ("Failed to load Ethernet address into SONIC CAM.\n"
1389      "  Wrote %04x%04x%04x - %#x\n"
[a3d3d9a]1390      "   Read %04x%04x%04x - %#x\n",
[7344fba9]1391        cdp->cap2, cdp->cap1, cdp->cap0, cdp->ce,
[13cc89e1]1392        (*sc->read_register)( rp, SONIC_REG_CAP2 ),
1393        (*sc->read_register)( rp, SONIC_REG_CAP1 ),
1394        (*sc->read_register)( rp, SONIC_REG_CAP0 ),
1395        (*sc->read_register)( rp, SONIC_REG_CE ));
[c932d85]1396    rtems_panic ("SONIC LCAM");
[e70a8f16]1397  }
[f1f42b4]1398#endif
[e70a8f16]1399
[13cc89e1]1400  (*sc->write_register)(rp, SONIC_REG_CR, /* CR_TXP | */CR_RXEN | CR_STP);
[c932d85]1401
1402  /*
1403   * Attach SONIC interrupt handler
1404   */
[7dbab720]1405/* XXX
[13cc89e1]1406  (*sc->write_register)( rp, SONIC_REG_IMR, 0 );
[7dbab720]1407*/
[a818530b]1408
1409  /* Ignore returned old handler */
1410  (void) set_vector(sonic_interrupt_handler, sc->vector, 1);
[c932d85]1411
1412  /*
1413   * Remainder of hardware initialization is
1414   * done by the receive and transmit daemons.
1415   */
1416}
1417
[bfcf4cb3]1418/*
1419 * Send packet (caller provides header).
1420 */
1421
1422SONIC_STATIC void sonic_start(struct ifnet *ifp)
1423{
1424  struct sonic_softc *sc = ifp->if_softc;
1425
1426  rtems_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
1427  ifp->if_flags |= IFF_OACTIVE;
1428}
1429
1430/*
1431 * Initialize and start the device
1432 */
1433
1434SONIC_STATIC void sonic_init (void *arg)
1435{
1436  struct sonic_softc *sc = arg;
1437  struct ifnet *ifp = &sc->arpcom.ac_if;
1438  void *rp = sc->sonic;
1439  int rcr;
1440
1441  if (sc->txDaemonTid == 0) {
1442
1443    /*
1444     * Set up SONIC hardware
1445     */
1446    sonic_initialize_hardware (sc);
1447
1448    /*
1449     * Start driver tasks
1450     */
1451    sc->rxDaemonTid = rtems_bsdnet_newproc ("SNrx", 4096, sonic_rxDaemon, sc);
[f1f42b4]1452    sc->txDaemonTid = rtems_bsdnet_newproc ("SNtx", 4096, sonic_txDaemon, sc);
[bfcf4cb3]1453  }
1454
1455  /*
1456   * Set flags appropriately
1457   */
[13cc89e1]1458  rcr = (*sc->read_register)( rp, SONIC_REG_RCR );
[bfcf4cb3]1459  if (ifp->if_flags & IFF_PROMISC)
1460    rcr |= RCR_PRO;
1461  else
1462    rcr &= ~RCR_PRO;
[13cc89e1]1463  (*sc->write_register)( rp, SONIC_REG_RCR, rcr);
[bfcf4cb3]1464
1465  /*
1466   * Tell the world that we're running.
1467   */
1468  ifp->if_flags |= IFF_RUNNING;
1469
1470  /*
1471   * Enable receiver and transmitter
1472   */
[f1f42b4]1473  sonic_enable_interrupts( sc, IMR_TXEREN | (IMR_PRXEN | IMR_RBAEEN) );
1474  sonic_command( sc, CR_RXEN );
[bfcf4cb3]1475}
1476
1477/*
1478 * Driver ioctl handler
1479 */
1480static int
[a612b50]1481sonic_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
[bfcf4cb3]1482{
1483  struct sonic_softc *sc = ifp->if_softc;
1484  int error = 0;
1485
1486  switch (command) {
[f3e13a1e]1487    case SIOCGIFADDR:
1488    case SIOCSIFADDR:
1489      ether_ioctl (ifp, command, data);
[bfcf4cb3]1490      break;
1491
[f3e13a1e]1492    case SIOCSIFFLAGS:
1493      switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1494        case IFF_RUNNING:
1495          sonic_stop (sc);
1496          break;
[bfcf4cb3]1497
[f3e13a1e]1498        case IFF_UP:
1499          sonic_init (sc);
1500          break;
[bfcf4cb3]1501
[f3e13a1e]1502        case IFF_UP | IFF_RUNNING:
1503          sonic_stop (sc);
1504          sonic_init (sc);
1505          break;
1506
1507        default:
1508          break;
1509        }
[bfcf4cb3]1510      break;
1511
[f3e13a1e]1512    case SIO_RTEMS_SHOW_STATS:
1513      sonic_stats (sc);
1514      break;
[a3d3d9a]1515
[f3e13a1e]1516    /*
1517     * FIXME: All sorts of multicast commands need to be added here!
1518     */
1519    default:
1520      error = EINVAL;
1521      break;
[bfcf4cb3]1522  }
1523  return error;
1524}
1525
[c932d85]1526/*
1527 * Attach an SONIC driver to the system
1528 * This is the only `extern' function in the driver.
1529 */
[13cc89e1]1530
[c932d85]1531int
[c9c67390]1532rtems_sonic_driver_attach (
[13cc89e1]1533  struct rtems_bsdnet_ifconfig *config,
1534  sonic_configuration_t *chip
1535)
[c932d85]1536{
[bfcf4cb3]1537  struct sonic_softc *sc;
1538  struct ifnet *ifp;
1539  int mtu;
[367cc5e]1540  int unitNumber;
1541  char *unitName;
[c932d85]1542
1543  /*
[367cc5e]1544   * Parse driver name
[c932d85]1545   */
[367cc5e]1546  if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1547    return 0;
1548
1549  /*
1550   * Is driver free?
1551   */
1552  if ((unitNumber <= 0) || (unitNumber > NSONIC)) {
1553    printf ("Bad SONIC unit number.\n");
1554     return 0;
1555  }
1556  sc = &sonic_softc[unitNumber - 1];
1557  ifp = &sc->arpcom.ac_if;
1558  if (ifp->if_softc != NULL) {
1559    printf ("Driver already in use.\n");
1560    return 0;
[c932d85]1561  }
1562
[c153a7b]1563  /*
1564   *  zero out the control structure
1565   */
1566
[bfcf4cb3]1567  memset( sc, 0, sizeof(*sc) );
[c932d85]1568
1569
1570  /*
[bfcf4cb3]1571   * Process options
[c932d85]1572   */
[bfcf4cb3]1573  if (config->hardware_address) {
1574    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
[c932d85]1575  }
[bfcf4cb3]1576  else {
1577    memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
1578  }
1579  if (config->mtu)
1580    mtu = config->mtu;
1581  else
1582    mtu = ETHERMTU;
1583  if (config->rbuf_count)
1584    sc->rdaCount = config->rbuf_count;
1585  else
[13cc89e1]1586    sc->rdaCount = chip->rda_count;
[bfcf4cb3]1587  if (config->xbuf_count)
1588    sc->tdaCount = config->xbuf_count;
1589  else
[13cc89e1]1590    sc->tdaCount = chip->tda_count;
[bfcf4cb3]1591  sc->acceptBroadcast = !config->ignore_broadcast;
[c932d85]1592
[1f25c77]1593  sc->sonic = chip->base_address;
[13cc89e1]1594  sc->vector = chip->vector;
1595  sc->dcr_value = chip->dcr_value;
1596  sc->dc2_value  = chip->dc2_value;
1597  sc->write_register = chip->write_register;
1598  sc->read_register  = chip->read_register;
[7dbab720]1599
[c932d85]1600  /*
[bfcf4cb3]1601   * Set up network interface values
[c932d85]1602   */
[bfcf4cb3]1603  ifp->if_softc = sc;
[367cc5e]1604  ifp->if_unit = unitNumber;
1605  ifp->if_name = unitName;
[bfcf4cb3]1606  ifp->if_mtu = mtu;
1607  ifp->if_init = sonic_init;
1608  ifp->if_ioctl = sonic_ioctl;
1609  ifp->if_start = sonic_start;
1610  ifp->if_output = ether_output;
1611  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1612  if (ifp->if_snd.ifq_maxlen == 0)
1613    ifp->if_snd.ifq_maxlen = ifqmaxlen;
[c932d85]1614
1615  /*
[bfcf4cb3]1616   * Attach the interface
[c932d85]1617   */
[bfcf4cb3]1618  if_attach (ifp);
1619  ether_ifattach (ifp);
1620  return 1;
[c932d85]1621}
[7fc5d54e]1622
[e995f3a1]1623#if (SONIC_DEBUG & SONIC_DEBUG_PRINT_REGISTERS)
[7fc5d54e]1624#include <stdio.h>
1625
[dddc0557]1626char SONIC_Reg_name[64][6]= {
1627    "CR",         /* 0x00 */
1628    "DCR",        /* 0x01 */
1629    "RCR",        /* 0x02 */
1630    "TCR",        /* 0x03 */
1631    "IMR",        /* 0x04 */
1632    "ISR",        /* 0x05 */
1633    "UTDA",       /* 0x06 */
1634    "CTDA",       /* 0x07 */
1635    "0x08",       /* 0x08 */
1636    "0x09",       /* 0x09 */
1637    "0x0A",       /* 0x0A */
1638    "0x0B",       /* 0x0B */
1639    "0x0C",       /* 0x0C */
1640    "URDA",       /* 0x0D */
1641    "CRDA",       /* 0x0E */
1642    "0x0F",       /* 0x0F */
1643    "0x10",       /* 0x10 */
1644    "0x11",       /* 0x11 */
1645    "0x12",       /* 0x12 */
1646    "EOBC",       /* 0x13 */
1647    "URRA",       /* 0x14 */
1648    "RSA",        /* 0x15 */
1649    "REA",        /* 0x16 */
1650    "RRP",        /* 0x17 */
1651    "RWP",        /* 0x18 */
1652    "0x19",       /* 0x19 */
1653    "0x1A",       /* 0x1A */
1654    "0x1B",       /* 0x1B */
1655    "0x1C",       /* 0x1C */
1656    "0x0D",       /* 0x1D */
1657    "0x1E",       /* 0x1E */
1658    "0x1F",       /* 0x1F */
1659    "0x20",       /* 0x20 */
1660    "CEP",        /* 0x21 */
1661    "CAP2",       /* 0x22 */
1662    "CAP1",       /* 0x23 */
1663    "CAP0",       /* 0x24 */
1664    "CE",         /* 0x25 */
1665    "CDP",        /* 0x26 */
1666    "CDC",        /* 0x27 */
1667    "SR",         /* 0x28 */
1668    "WT0",        /* 0x29 */
1669    "WT1",        /* 0x2A */
1670    "RSC",        /* 0x2B */
1671    "CRCT",       /* 0x2C */
1672    "FAET",       /* 0x2D */
1673    "MPT",        /* 0x2E */
1674    "MDT",        /* 0x2F */
1675    "0x30",       /* 0x30 */
1676    "0x31",       /* 0x31 */
1677    "0x32",       /* 0x32 */
1678    "0x33",       /* 0x33 */
1679    "0x34",       /* 0x34 */
1680    "0x35",       /* 0x35 */
1681    "0x36",       /* 0x36 */
1682    "0x37",       /* 0x37 */
1683    "0x38",       /* 0x38 */
1684    "0x39",       /* 0x39 */
1685    "0x3A",       /* 0x3A */
1686    "0x3B",       /* 0x3B */
1687    "0x3C",       /* 0x3C */
1688    "0x3D",       /* 0x3D */
1689    "0x3E",       /* 0x3E */
1690    "DCR2"        /* 0x3F */
1691};
1692#endif
Note: See TracBrowser for help on using the repository browser.