source: rtems/c/src/libchip/network/cs8900.c @ 40a24661

4.115
Last change on this file since 40a24661 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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