source: rtems/c/src/libchip/network/cs8900.c @ a612b50

4.104.114.84.95
Last change on this file since a612b50 was a612b50, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 1, 2006 at 3:39:00 PM

2006-09-01 Joel Sherrill <joel@…>

  • libchip/network/cs8900.c, libchip/network/greth.c, libchip/network/i82586.c, libchip/network/open_eth.c, libchip/network/sonic.c: Remove warnings -- use uintptr_t, properly sized integers, and inttypes.h printf helpers.
  • Property mode set to 100644
File size: 27.8 KB
Line 
1/*
2  ------------------------------------------------------------------------
3  cs8900.c,v 1.5 2002/11/13 15:34:39 joel Exp
4  ------------------------------------------------------------------------
5
6  Copyright Cybertec Pty Ltd, 2000
7  All rights reserved Cybertec Pty Ltd, 2000
8
9  Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
10   This project has been assisted by the Commonwealth Government
11   through the Australia Council, its arts funding and advisory body.
12
13  COPYRIGHT (c) 1989-1998.
14  On-Line Applications Research Corporation (OAR).
15  Copyright assigned to U.S. Government, 1994.
16
17  The license and distribution terms for this file may be
18  found in the file LICENSE in this distribution or at
19  http://www.OARcorp.com/rtems/license.html.
20
21  ------------------------------------------------------------------------
22
23  CS8900 RTEMS driver.
24
25  See the header file for details.
26
27*/
28
29#include <errno.h>
30#include <string.h>
31#include <stdio.h>
32
33#include "cs8900.h"
34
35/*
36 * We expect to be able to read a complete packet into an mbuf.
37 */
38
39#if (MCLBYTES < 1520)
40#error "CS8900 Driver must have MCLBYTES >= 1520"
41#endif
42
43/*
44 * Task event usage.
45 */
46
47#define CS8900_RX_OK_EVENT    RTEMS_EVENT_1
48#define CS8900_TX_START_EVENT RTEMS_EVENT_1
49#define CS8900_TX_OK_EVENT    RTEMS_EVENT_2
50#define CS8900_TX_WAIT_EVENT  RTEMS_EVENT_3
51
52/*
53 * IO Packet Page inteface.
54 */
55
56static inline unsigned short
57io_pp_get_reg_16 (cs8900_device *cs, unsigned short reg)
58{
59  rtems_interrupt_level level;
60  unsigned short        data;
61  rtems_interrupt_disable (level);
62  cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
63                     0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
64  data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0);
65  rtems_interrupt_enable (level);
66  return data;
67}
68
69static inline unsigned long
70io_pp_get_reg_32 (cs8900_device *cs, unsigned short reg)
71{
72  rtems_interrupt_level level;
73  unsigned long         data;
74  rtems_interrupt_disable (level);
75  cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
76                     0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
77  data =  ((cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0) << 16) |
78           cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1));
79  rtems_interrupt_enable (level);
80  return data;
81}
82
83static inline void
84io_pp_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short data)
85{
86  rtems_interrupt_level level;
87  rtems_interrupt_disable (level);
88  cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
89                     0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
90  cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data);
91  rtems_interrupt_enable (level);
92}
93
94static inline void
95io_pp_set_reg_32 (cs8900_device *cs, unsigned short reg, unsigned long data)
96{
97  cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
98                     0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
99  cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data >> 16);
100  cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT1, data);
101}
102
103static inline void
104io_pp_bit_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask)
105{
106  rtems_interrupt_level level;
107  rtems_interrupt_disable (level);
108  io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) | mask);
109  rtems_interrupt_enable (level);
110}
111
112static inline void
113io_pp_bit_clear_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask)
114{
115  rtems_interrupt_level level;
116  rtems_interrupt_disable (level);
117  io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) & ~mask);
118  rtems_interrupt_enable (level);
119}
120
121/*
122 * Memory Mapped Packet Page interface.
123 *
124 * If the BSP does not configure mem_base use the I/O register accesses.
125 */
126
127static inline unsigned short
128mem_pp_get_reg (cs8900_device *cs, unsigned short reg)
129{
130  if (!cs->mem_base)
131    return io_pp_get_reg_16 (cs, reg);
132  return cs8900_mem_get_reg (cs, reg);
133}
134
135static inline void
136mem_pp_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data)
137{
138  if (!cs->mem_base)
139    io_pp_set_reg_16 (cs, reg, data);
140  else
141    cs8900_mem_set_reg (cs, reg, data);
142}
143
144static inline void
145mem_pp_bit_set_reg (cs8900_device *cs, unsigned short reg, unsigned short mask)
146{
147  if (!cs->mem_base)
148    io_pp_bit_set_reg_16 (cs, reg, mask);
149  else
150  {
151    rtems_interrupt_level level;
152    rtems_interrupt_disable (level);
153    mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) | mask);
154    rtems_interrupt_enable (level);
155  }
156}
157
158static inline void
159mem_pp_bit_clear_reg (cs8900_device *cs, unsigned short reg, unsigned short mask)
160{
161  if (!cs->mem_base)
162    io_pp_bit_clear_reg_16 (cs, reg, mask);
163  else
164  {
165    rtems_interrupt_level level;
166    rtems_interrupt_disable (level);
167    mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) & ~mask);
168    rtems_interrupt_enable (level);
169  }
170}
171
172/*
173 * Trace defines and control structures.
174 */
175
176#define CS8900_T_INT         (0)
177#define CS8900_T_RX_OK       (1)
178#define CS8900_T_RX_DROPPED  (2)
179#define CS8900_T_NO_MBUF     (3)
180#define CS8900_T_NO_CLUSTERS (4)
181#define CS8900_T_RX_BEGIN    (5)
182#define CS8900_T_RX_END      (6)
183
184#if CS8900_TRACE
185
186static const char *cs8900_trace_labels[] =
187{
188  "int",
189  "rx ok",
190  "rx dropped",
191  "no mbuf",
192  "no clusters",
193  "rx begin",
194  "rx end"
195};
196
197/*
198 * Assumes a micro-second timer such as the Coldfire.
199 */
200
201uint32_t   rtems_read_timer ();
202
203static inline void
204cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var)
205{
206  rtems_interrupt_level level;
207
208  rtems_interrupt_disable (level);
209
210  if (cs->trace_in < CS8900_TRACE_SIZE)
211  {
212    cs->trace_key[cs->trace_in]  = key;
213    cs->trace_var[cs->trace_in]  = var;
214    cs->trace_time[cs->trace_in] = rtems_read_timer ();
215    cs->trace_in++;
216  }
217
218  rtems_interrupt_enable (level);
219}
220#else
221#define cs8900_trace(c, k, v)
222#endif
223
224void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address)
225{
226  unsigned short ma;
227
228  /*
229   * Only ever use IO calls for this function as it can be
230   * called before memory mode has been enabled.
231   */
232
233  ma = io_pp_get_reg_16 (cs, CS8900_PP_IA);
234  mac_address[0] = ma >> 8;
235  mac_address[1] = ma;
236
237  ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 2);
238  mac_address[2] = ma >> 8;
239  mac_address[3] = ma;
240
241  ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 4);
242  mac_address[4] = ma >> 8;
243  mac_address[5] = ma;
244}
245
246/*
247 * Bring the chip online.
248 */
249
250static void
251cs8900_hardware_init (cs8900_device *cs)
252{
253  unsigned long  prod_id;
254  unsigned short status;
255
256  /*
257   * Do nothing while the device is calibrating and checking the EEPROM.
258   * We must wait 20msecs.
259   */
260
261  io_pp_bit_set_reg_16 (cs, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET);
262
263  rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (20));
264
265  status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST);
266  if (status == 0) {
267      printf("Reading status register again\n");
268      status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST);
269  }
270
271  if (((status & CS8900_SELF_STATUS_INITD) == 0) ||
272      ((status & CS8900_SELF_STATUS_INITD) &&
273       (status & CS8900_SELF_STATUS_EEPROM_PRESENT) &&
274       (status & CS8900_SELF_STATUS_SIBUST)))
275  {
276    printf ("CS8900: %s. Initialisation aborted.\n",
277            (status & CS8900_SELF_STATUS_INITD) ?
278            "EEPROM read/write failed to complete" :
279            "Failed to complete to reset");
280    return;
281  }
282
283  /* Set the RX queue size if not set by the BSP. */
284
285  if (cs->rx_queue_size == 0)
286    cs->rx_queue_size = 10;
287
288  /* Probe the device for its ID */
289
290  prod_id = io_pp_get_reg_32 (cs, CS8900_PP_PROD_ID);
291
292  if ((prod_id >> 16) != CS8900_ESIA_ID)
293  {
294    printf ("CS8900: Invalid EISA ID, read product code 0x%08lx\n", prod_id);
295    return;
296  }
297
298  if ((prod_id & 0x000000ff) != 0)
299  {
300    printf ("CS8900: Unsupported product id, read product code 0x%08lx\n",
301            prod_id);
302    return;
303  }
304
305  printf ("CS8900 Rev %ld, %s, %s.\n",
306          (prod_id >> 8) & 0x1f,
307          status & CS8900_SELF_STATUS_3_3_V ? "3.3V" : "5.0V",
308          status & CS8900_SELF_STATUS_EEPROM_PRESENT ?
309          "EEPROM present" : "no EEPROM");
310
311  /*
312   * Switch to memory base accesses as they are faster. No indirect access.
313   */
314
315  if (cs->mem_base)
316  {
317    io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE, cs->mem_base);
318    io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE + 2, (cs->mem_base >> 16) & 0xf);
319
320    io_pp_set_reg_16 (cs,
321                      CS8900_PP_BusCTL,
322                      CS8900_BUS_CTRL_RESET_RX_DMA |
323                      CS8900_BUS_CTRL_USE_SA |
324                      CS8900_BUS_CTRL_MEMORY_ENABLE);
325    io_pp_set_reg_16 (cs,
326                      CS8900_PP_BusCTL,
327                      CS8900_BUS_CTRL_USE_SA |
328                      CS8900_BUS_CTRL_MEMORY_ENABLE);
329  }
330
331  /*
332   * We are now in memory mapped mode.
333   */
334
335  /*
336   * Program the Line Control register with the mode we want.
337   *
338   * No auto detect support at the moment. Only 10BaseT.
339   */
340
341  mem_pp_set_reg (cs, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET);
342
343  /*
344   * Ask the user for the MAC address, the program into the device.
345   */
346
347#define MACO(o) cs->arpcom.ac_enaddr[o]
348
349  mem_pp_set_reg (cs, CS8900_PP_IA,
350                  (((unsigned int) MACO (1)) << 8) |
351                  ((unsigned int) MACO (0)));
352  mem_pp_set_reg (cs, CS8900_PP_IA + 2,
353                  (((unsigned int) MACO (3)) << 8) |
354                  ((unsigned int) MACO (2)));
355  mem_pp_set_reg (cs, CS8900_PP_IA + 4,
356                  (((unsigned int) MACO (5)) << 8) |
357                  ((unsigned int) MACO (4)));
358
359  /*
360   * Set the Buffer configuration.
361   */
362
363  mem_pp_set_reg (cs, CS8900_PP_BufCFG,
364                  CS8900_BUFFER_CONFIG_RDY_FOR_TX |
365                  CS8900_BUFFER_CONFIG_TX_UNDERRUN |
366                  CS8900_BUFFER_CONFIG_TX_COL_OVF |
367                  CS8900_BUFFER_CONFIG_RX_MISSED_OVF);
368
369  /*
370   * Set the Receiver configuration.
371   */
372
373  mem_pp_set_reg (cs, CS8900_PP_RxCFG,
374                  CS8900_RX_CONFIG_RX_OK |
375                  CS8900_RX_CONFIG_CRC_ERROR |
376                  CS8900_RX_CONFIG_RUNT|
377                  CS8900_RX_CONFIG_EXTRA_DATA);
378
379  /*
380   * Set the Receiver control.
381   */
382
383  mem_pp_set_reg (cs, CS8900_PP_RxCTL,
384                  CS8900_RX_CTRL_RX_OK |
385                  CS8900_RX_CTRL_MULTICAST |
386                  CS8900_RX_CTRL_INDIVIDUAL |
387                  CS8900_RX_CTRL_BROADCAST);
388
389  /*
390   * Set the Transmitter configuration.
391   */
392
393  mem_pp_set_reg (cs, CS8900_PP_TxCFG,
394                  CS8900_TX_CONFIG_TX_OK |
395                  CS8900_TX_CONFIG_OUT_OF_WINDOW |
396                  CS8900_TX_CONFIG_JABBER |
397                  CS8900_TX_CONFIG_16_COLLISION);
398
399  /*
400   * Attach the interrupt handler.
401   */
402
403  cs8900_attach_interrupt (cs);
404
405  /*
406   * Program the interrupt level we require then enable interrupts.
407   *
408   * Note, this will need to change to support other levels.
409   */
410
411  mem_pp_set_reg (cs, CS8900_PP_INT, cs->irq_level & 3);
412
413  mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
414                      CS8900_BUS_CTRL_ENABLE_INT);
415}
416
417rtems_isr
418cs8900_interrupt (rtems_vector_number v, void *csp)
419{
420  cs8900_device  *cs = csp;
421  unsigned short isq = 0;
422  struct mbuf    *m;
423  unsigned char  *p;
424
425  ++cs->eth_stats.interrupts;
426
427  while (1)
428  {
429    isq = mem_pp_get_reg (cs, CS8900_PP_ISQ);
430
431    cs8900_trace (cs, CS8900_T_INT, isq);
432
433    /*
434     * No more interrupts to service.
435     */
436
437    if (isq == 0)
438      return;
439
440    switch (isq & 0x1f)
441    {
442      case 0x04:
443
444        /*
445         * RxEvent.
446         */
447
448        ++cs->eth_stats.rx_interrupts;
449
450        if (isq & CS8900_RX_EVENT_RX_OK)
451        {
452          m = cs->rx_ready_head;
453          if (m)
454          {
455            cs->rx_ready_head = m->m_nextpkt;
456            if (cs->rx_ready_head == 0)
457              cs->rx_ready_tail = 0;
458            m->m_nextpkt = 0;
459            cs->rx_ready_len--;
460
461            p = mtod (m, unsigned char *);
462
463            m->m_pkthdr.len = cs8900_get_data_block (cs, p);
464
465            if (cs->rx_loaded_tail == 0)
466              cs->rx_loaded_head = m;
467            else
468              cs->rx_loaded_tail->m_nextpkt = m;
469            cs->rx_loaded_tail = m;
470            cs->rx_loaded_len++;
471
472            if (cs->rx_loaded_len == 1)
473            {
474              cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len);
475              rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
476            }
477          }
478          else
479          {
480            ++cs->eth_stats.rx_dropped;
481
482            cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len);
483
484            if (cs->rx_loaded_len == 0)
485              rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
486          }
487        }
488        else
489        {
490          if (isq & CS8900_RX_EVENT_CRC_ERROR)
491            ++cs->eth_stats.rx_crc_errors;
492
493          if (isq & CS8900_RX_EVENT_RUNT)
494            ++cs->eth_stats.rx_runt_errors;
495
496          if (isq & CS8900_RX_EVENT_EXTRA_DATA)
497            ++cs->eth_stats.rx_oversize_errors;
498        }
499        break;
500
501      case 0x08:
502
503        /*
504         * TxEvent.
505         */
506
507        ++cs->eth_stats.tx_interrupts;
508
509        if (cs->tx_active)
510        {
511          if (isq & CS8900_TX_EVENT_TX_OK)
512            ++cs->eth_stats.tx_ok;
513
514          cs->tx_active = 0;
515
516          rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
517        }
518        break;
519
520      case 0x0c:
521
522        /*
523         * BufEvent.
524         */
525
526        if (isq & CS8900_BUFFER_EVENT_RDY_FOR_TX)
527        {
528          if (cs->tx_active)
529          {
530            ++cs->eth_stats.tx_rdy4tx;
531            rtems_event_send (cs->tx_task, CS8900_TX_WAIT_EVENT);
532          }
533        }
534        else if (isq & CS8900_BUFFER_EVENT_TX_UNDERRUN)
535        {
536          ++cs->eth_stats.tx_underrun_errors;
537          if (cs->tx_active)
538            rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
539        }
540        else if (isq & CS8900_BUFFER_EVENT_SW_INT)
541        {
542          ++cs->eth_stats.int_swint_res;
543        }
544        break;
545
546      case 0x10:
547
548        /*
549         * RxMiss.
550         */
551
552        cs->eth_stats.rx_missed_errors +=
553          mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6;
554        break;
555
556      case 0x12:
557
558        /*
559         * TxCol.
560         */
561
562        cs->eth_stats.tx_collisions +=
563          mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6;
564        break;
565
566      default:
567        break;
568    }
569  }
570
571}
572
573int
574cs8900_link_active (cs8900_device *cs)
575{
576  return ((mem_pp_get_reg (cs, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ?
577          1 : 0);
578}
579
580static inline void
581cs8900_rx_refill_queue (cs8900_device *cs)
582{
583  struct ifnet          *ifp = &cs->arpcom.ac_if;
584  struct mbuf           *m;
585  rtems_interrupt_level level;
586
587  /*
588   * Hold a single queue of mbuf's at the interface. This
589   * will lower the latency of the driver.
590   */
591
592  while (cs->rx_ready_len < cs->rx_queue_size)
593  {
594    MGETHDR (m, M_DONTWAIT, MT_DATA);
595
596    if (!m)
597    {
598      ++cs->eth_stats.rx_no_mbufs;
599      cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs);
600      return;
601    }
602
603    MCLGET (m, M_DONTWAIT);
604
605    if (!m->m_ext.ext_buf)
606    {
607      ++cs->eth_stats.rx_no_clusters;
608      cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters);
609      m_free (m);
610      return;
611    }
612    m->m_pkthdr.rcvif = ifp;
613    m->m_nextpkt = 0;
614
615    rtems_interrupt_disable (level);
616
617    if (cs->rx_ready_tail == 0)
618      cs->rx_ready_head = m;
619    else
620      cs->rx_ready_tail->m_nextpkt = m;
621    cs->rx_ready_tail = m;
622    cs->rx_ready_len++;
623
624    rtems_interrupt_enable (level);
625  }
626}
627
628static void
629cs8900_rx_task (void *arg)
630{
631  cs8900_device         *cs = arg;
632  struct ifnet          *ifp = &cs->arpcom.ac_if;
633  rtems_event_set       events;
634  struct mbuf           *m;
635  struct ether_header   *eh;
636  rtems_status_code     sc;
637  rtems_interrupt_level level;
638
639  /*
640   * Turn the receiver and transmitter on.
641   */
642
643  mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG,
644                      CS8900_LINE_CTRL_RX_ON |
645                      CS8900_LINE_CTRL_TX_ON);
646
647  /*
648   * Start the software interrupt watchdog.
649   */
650
651  mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
652                      CS8900_BUFFER_CONFIG_SW_INT);
653  ++cs->eth_stats.int_swint_req;
654
655  /*
656   * Loop reading packets.
657   */
658
659  while (1)
660  {
661    cs8900_rx_refill_queue (cs);
662
663    sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT,
664                                     RTEMS_WAIT | RTEMS_EVENT_ANY,
665                                     TOD_MILLISECONDS_TO_TICKS (250),
666                                     &events);
667
668    cs8900_rx_refill_queue (cs);
669
670    if (sc == RTEMS_TIMEOUT)
671    {
672      /*
673       * We need to check the interrupt hardware in the cs8900a
674       * has not locked up. It seems this occurs if the ISQ
675       * queue fills up.
676       * To test we generate a software interrupt and watch
677       * a counter go up. If the counter does not go for 2
678       * software interrupts requests we flush the ISQ queue.
679       */
680
681      if ((cs->eth_stats.int_swint_req - cs->eth_stats.int_swint_res) > 1)
682      {
683        printf ("cs8900: int lockup, isq flush\n");
684
685        mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL,
686                              CS8900_BUS_CTRL_ENABLE_INT);
687
688        while (mem_pp_get_reg (cs, CS8900_PP_ISQ) != 0);
689
690        cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0;
691        ++cs->eth_stats.int_lockup;
692
693        mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
694                            CS8900_BUS_CTRL_ENABLE_INT);
695      }
696
697      mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
698                          CS8900_BUFFER_CONFIG_SW_INT);
699      ++cs->eth_stats.int_swint_req;
700    }
701
702    cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len);
703
704    while (cs->rx_loaded_len)
705    {
706      rtems_interrupt_disable (level);
707
708      m = cs->rx_loaded_head;
709      if (m)
710      {
711        cs->rx_loaded_head = m->m_nextpkt;
712        if (cs->rx_loaded_head == 0)
713          cs->rx_loaded_tail = 0;
714        m->m_nextpkt = 0;
715        cs->rx_loaded_len--;
716
717        rtems_interrupt_enable (level);
718
719        m->m_pkthdr.rcvif = ifp;
720
721        cs->eth_stats.rx_bytes += m->m_pkthdr.len;
722
723        m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header);
724
725        eh = mtod (m, struct ether_header *);
726        m->m_data += sizeof (struct ether_header);
727
728        ++cs->eth_stats.rx_packets;
729
730        ether_input (ifp, eh, m);
731      }
732      else
733      {
734        rtems_interrupt_enable (level);
735      }
736    }
737    cs8900_trace (cs, CS8900_T_RX_END, cs->rx_loaded_len);
738  }
739}
740
741static void
742cs8900_tx_task (void *arg)
743{
744  cs8900_device     *cs = arg;
745  struct ifnet      *ifp = &cs->arpcom.ac_if;
746  rtems_event_set   events;
747  struct mbuf       *m;
748  rtems_status_code sc;
749
750  /*
751   * Wait for the link to come up.
752   */
753
754  rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (750));
755
756  /*
757   * Loop processing the tx queue.
758   */
759
760  while (1)
761  {
762    /*
763     * Fetch the mbuf list from the interface's queue.
764     */
765
766    IF_DEQUEUE (&ifp->if_snd, m);
767
768    /*
769     * If something actually is present send it.
770     */
771
772    if (!m)
773    {
774      ifp->if_flags &= ~IFF_OACTIVE;
775
776      rtems_bsdnet_event_receive (CS8900_TX_START_EVENT,
777                                  RTEMS_WAIT | RTEMS_EVENT_ANY,
778                                  RTEMS_NO_TIMEOUT,
779                                  &events);
780    }
781    else
782    {
783      if (cs8900_link_active (cs))
784      {
785        int resending;
786
787        do
788        {
789          unsigned short buf_status;
790
791          resending = 0;
792
793          cs->tx_active = 1;
794
795          mem_pp_set_reg (cs, CS8900_PP_TxCMD,
796                          CS8900_TX_CMD_STATUS_TX_START_ENTIRE |
797                          CS8900_TX_CMD_STATUS_FORCE);
798          mem_pp_set_reg (cs, CS8900_PP_TxLength, m->m_pkthdr.len);
799
800          buf_status = mem_pp_get_reg (cs, CS8900_PP_BusST);
801
802          /*
803           * If the bid for memory in the device fails trash the
804           * transmit and try again next time.
805           */
806
807          if (buf_status & CS8900_BUS_STATUS_TX_BID_ERROR)
808            ++cs->eth_stats.tx_bid_errors;
809          else
810          {
811            /*
812             * If the buffer is not read enable the interrupt and then wait.
813             */
814
815            if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0)
816            {
817              cs->eth_stats.tx_wait_for_rdy4tx++;
818              sc = rtems_bsdnet_event_receive (CS8900_TX_WAIT_EVENT,
819                                               RTEMS_WAIT | RTEMS_EVENT_ANY,
820                                               TOD_MILLISECONDS_TO_TICKS (750),
821                                               &events);
822              if (sc == RTEMS_TIMEOUT)
823              {
824                /*
825                 * For some reason the wait request has been dropped,
826                 * so lets resend from the start.
827                 */
828
829                printf ("tx resend\n");
830                ++cs->eth_stats.tx_resends;
831                resending = 1;
832              }
833            }
834
835            if (!resending)
836            {
837              cs8900_tx_load (cs, m);
838              cs->eth_stats.tx_packets++;
839              cs->eth_stats.tx_bytes += m->m_pkthdr.len;
840            }
841          }
842        }
843        while (resending);
844
845        m_freem (m);
846
847        do
848        {
849          rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT,
850                                      RTEMS_WAIT | RTEMS_EVENT_ANY,
851                                      RTEMS_NO_TIMEOUT,
852                                      &events);
853        }
854        while (cs->tx_active);
855      }
856      else
857      {
858        ++cs->eth_stats.tx_dropped;
859        m_freem (m);
860      }
861    }
862  }
863}
864
865static void
866cs8900_start (struct ifnet *ifp)
867{
868  cs8900_device *cs = ifp->if_softc;
869
870  /*
871   * Tell the transmit daemon to wake up and send a packet.
872   */
873
874  ifp->if_flags |= IFF_OACTIVE;
875
876  rtems_event_send (cs->tx_task, CS8900_TX_START_EVENT);
877}
878
879static void
880cs8900_stop (cs8900_device *cs)
881{
882  mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG,
883                        CS8900_LINE_CTRL_RX_ON |
884                        CS8900_LINE_CTRL_TX_ON);
885
886  mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL,
887                        CS8900_BUS_CTRL_ENABLE_INT);
888}
889
890static const char *eth_statistics_labels[] =
891{
892  "rx packets",
893  "tx packets",
894  "rx bytes",
895  "tx bytes",
896  "rx interrupts",
897  "tx interrupts",
898  "rx dropped",
899  "rx no mbuf",
900  "rx no custers",
901  "rx oversize errors",
902  "rx crc errors",
903  "rx runt errors",
904  "rx missed errors",
905  "tx ok",
906  "tx collisions",
907  "tx bid errors",
908  "tx wait for rdy4tx",
909  "tx rdy4tx",
910  "tx underrun errors",
911  "tx dropped",
912  "tx resends",
913  "int swint req",
914  "int swint res",
915  "int lockup",
916  "interrupts"
917};
918
919static void
920cs8900_stats (cs8900_device *cs)
921{
922  int           i;
923  int           max_label = 0;
924  int           len;
925  unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets;
926
927  cs->eth_stats.rx_missed_errors +=
928    mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6;
929
930  cs->eth_stats.tx_collisions +=
931    mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6;
932
933  printf ("Network Driver Stats for CS8900 :\n");
934
935  for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++)
936  {
937    len = strlen (eth_statistics_labels[i]);
938    if (len > max_label)
939      max_label = len;
940  }
941
942  max_label += 2;
943
944  printf ("%*s - %10u %*s - %10u\n",
945          max_label, "rx ready len", cs->rx_ready_len,
946          max_label, "rx loaded len", cs->rx_loaded_len);
947
948  for (i = 0;
949       i < (sizeof (eth_statistics_labels) / sizeof (const char *));
950       i++)
951  {
952    printf ("%*s - %10lu",
953            max_label, eth_statistics_labels[i], value[i]);
954
955    i++;
956
957    if (i < (sizeof (eth_statistics_labels) / sizeof (const char *)))
958      printf (" %*s - %10lu",
959              max_label, eth_statistics_labels[i], value[i]);
960    printf ("\n");
961  }
962
963#if CS8900_TRACE
964
965  for (i = 0; i < cs->trace_in; i++)
966  {
967    printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000);
968
969    if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*))
970      printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]);
971    else
972      printf ("unknown trace key, %d : ", cs->trace_key[i]);
973
974    if (cs->trace_key[i] == CS8900_T_INT)
975    {
976      printf ("0x%04lx ", cs->trace_var[i]);
977      if (cs->trace_var[i] == 0)
978        printf ("end");
979      else
980      {
981        switch (cs->trace_var[i] & 0x1f)
982        {
983          case 0x04:
984            printf ("rx event");
985            break;
986
987          case 0x08:
988            printf ("tx event");
989            break;
990
991          case 0x0c:
992            printf ("buffer event");
993            break;
994
995          case 0x10:
996            printf ("rx missed");
997            break;
998
999          case 0x12:
1000            printf ("tx collisions");
1001            break;
1002
1003          case 0x1f:
1004            printf ("tx request");
1005            break;
1006
1007          case 0x1e:
1008            printf ("tx wait 4 tx");
1009            break;
1010
1011          case 0x1d:
1012            printf ("tx already active");
1013            break;
1014
1015          default:
1016            printf ("unknown event");
1017            break;
1018        }
1019      }
1020    }
1021    else
1022      printf ("0x%08lx", cs->trace_var[i]);
1023
1024    printf ("\n");
1025  }
1026
1027  cs->trace_in = 0;
1028
1029#endif
1030}
1031
1032static void
1033cs8900_init (void *arg)
1034{
1035  cs8900_device *cs  = arg;
1036  struct ifnet  *ifp = &cs->arpcom.ac_if;
1037
1038  if (cs->rx_task == 0)
1039  {
1040
1041    /*
1042     * Set up the hardware.
1043     */
1044
1045    cs8900_hardware_init (cs);
1046
1047    /*
1048     * Start driver task. We have only one task.
1049     */
1050
1051    cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs);
1052    cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs);
1053  }
1054
1055#ifdef todo
1056  /*
1057   * Set flags appropriately
1058   */
1059  if (ifp->if_flags & IFF_PROMISC)
1060  else
1061#endif
1062
1063  /*
1064   * Tell the world that we're running.
1065   */
1066
1067  ifp->if_flags |= IFF_RUNNING;
1068
1069  /*
1070   * Set the Line Control to bring the receive and transmitter online.
1071   */
1072
1073  mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG,
1074                      CS8900_LINE_CTRL_RX_ON |
1075                      CS8900_LINE_CTRL_TX_ON);
1076
1077  mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
1078                      CS8900_BUS_CTRL_ENABLE_INT);
1079}
1080
1081static int
1082cs8900_ioctl (struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
1083{
1084  cs8900_device *cs = ifp->if_softc;
1085  int           error = 0;
1086
1087  switch (cmd)
1088  {
1089    case SIOCGIFADDR:
1090    case SIOCSIFADDR:
1091
1092      error = ether_ioctl (ifp, cmd, data);
1093      break;
1094
1095    case SIOCSIFFLAGS:
1096
1097      switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1098      {
1099        case IFF_RUNNING:
1100
1101          cs8900_stop (cs);
1102          break;
1103
1104        case IFF_UP:
1105
1106          cs8900_init (cs);
1107          break;
1108
1109        case IFF_UP | IFF_RUNNING:
1110
1111          cs8900_stop (cs);
1112          cs8900_init (cs);
1113          break;
1114
1115        default:
1116          break;
1117      }
1118      break;
1119
1120    case SIO_RTEMS_SHOW_STATS:
1121
1122      cs8900_stats (cs);
1123      break;
1124
1125      /* FIXME: Multicast commands must be added here.  */
1126
1127    default:
1128      error = EINVAL;
1129      break;
1130  }
1131
1132  return error;
1133}
1134
1135int
1136cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
1137{
1138  cs8900_device *cs;
1139  struct ifnet  *ifp;
1140  int           mtu;
1141  int           unit;
1142  char          *name;
1143
1144  /*
1145    * Parse driver name
1146   */
1147
1148  if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
1149    return 0;
1150
1151  cs      = config->drv_ctrl;
1152  cs->dev = unit;
1153  ifp     = &cs->arpcom.ac_if;
1154
1155  if (attaching)
1156  {
1157    if (ifp->if_softc)
1158    {
1159      printf ("Driver `%s' already in use.\n", config->name);
1160      return 0;
1161    }
1162
1163    /*
1164     * Process options
1165     */
1166
1167    if (config->hardware_address)
1168      memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1169    else
1170      cs8900_get_mac_addr (cs, cs->arpcom.ac_enaddr);
1171
1172    if (config->mtu)
1173      mtu = config->mtu;
1174    else
1175      mtu = ETHERMTU;
1176
1177    cs->accept_bcast = !config->ignore_broadcast;
1178
1179    /*
1180     * Set up network interface values.
1181     */
1182
1183    ifp->if_softc  = cs;
1184    ifp->if_unit   = unit;
1185    ifp->if_name   = name;
1186    ifp->if_mtu    = mtu;
1187    ifp->if_init   = cs8900_init;
1188    ifp->if_ioctl  = cs8900_ioctl;
1189    ifp->if_start  = cs8900_start;
1190    ifp->if_output = ether_output;
1191    ifp->if_flags  = IFF_BROADCAST | IFF_SIMPLEX;
1192
1193    if (ifp->if_snd.ifq_maxlen == 0)
1194      ifp->if_snd.ifq_maxlen = ifqmaxlen;
1195
1196    /*
1197     * Attach the interface to the stack.
1198     */
1199
1200    if_attach (ifp);
1201    ether_ifattach (ifp);
1202  }
1203  else
1204  {
1205    if (!ifp->if_softc)
1206    {
1207      printf ("Driver `%s' not found.\n", config->name);
1208      return 0;
1209    }
1210
1211    cs8900_stop (cs);
1212    cs8900_detach_interrupt (cs);
1213  }
1214
1215  return 1;
1216}
Note: See TracBrowser for help on using the repository browser.