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

4.104.114.84.95
Last change on this file since d81d057 was 2697be56, checked in by Joel Sherrill <joel.sherrill@…>, on 03/12/07 at 11:19:21

2007-03-12 Joel Sherrill <joel@…>

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