source: rtems/c/src/libchip/network/cs8900.c @ 1c36c3e4

4.104.114.84.95
Last change on this file since 1c36c3e4 was aae96a2, checked in by Joel Sherrill <joel.sherrill@…>, on 11/13/02 at 15:34:39

2002-11-13 Jay Monkman <jtm@…>

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