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

4.104.114.84.95
Last change on this file since a2117cd6 was a2117cd6, checked in by Joel Sherrill <joel.sherrill@…>, on 09/07/02 at 23:09:47

2002-09-07 Chris Johns <ccj@…>

  • network/Makefile.am, network/README.cs8900, network/cs8900.c, network/cs8900.h: Significant update which corrects the problem where the cs8900.c file was actually the BSP glue. Joel did some hacking so this file will compile. Previously it required providing a target.h file to compile.
  • network/cs8900.c.bsp: New file.
  • Property mode set to 100644
File size: 28.5 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   
265  if (((status & CS8900_SELF_STATUS_INITD) == 0) ||
266      ((status & CS8900_SELF_STATUS_INITD) &&
267       (status & CS8900_SELF_STATUS_EEPROM_PRESENT) &&
268       (status & CS8900_SELF_STATUS_SIBUST)))
269  {
270    printf ("CS8900: %s. Initialisation aborted.\n",
271            (status & CS8900_SELF_STATUS_INITD) ?
272            "EEPROM read/write failed to complete" :
273            "Failed to complete to reset");     
274    return;
275  }
276 
277  /* Probe the device for its ID */
278
279  prod_id = io_pp_get_reg_32 (dev, CS8900_PP_PROD_ID);
280
281  if ((prod_id >> 16) != CS8900_ESIA_ID)
282  {
283    printf ("CS9800: Invalid EISA ID, read product code 0x%08lx\n", prod_id);
284    return;
285  }
286
287  if ((prod_id & 0x000000ff) != 0)
288  {
289    printf ("CS9800: Unsupported product id, read product code 0x%08lx\n",
290            prod_id);
291    return;
292  }
293
294  printf ("CS8900 Rev %ld, %s, %s.\n",
295          (prod_id >> 8) & 0x1f,
296          status & CS8900_SELF_STATUS_3_3_V ? "3.3V" : "5.0V",
297          status & CS8900_SELF_STATUS_EEPROM_PRESENT ?
298          "EEPROM present" : "no EEPROM");
299
300  /*
301   * Switch to memory base accesses as they are faster. No indirect access.
302   */
303 
304  io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE, CS8900_MEMORY_BASE);
305  io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE + 2, (CS8900_MEMORY_BASE >> 16) & 0xf);
306 
307  io_pp_set_reg_16 (dev,
308                    CS8900_PP_BusCTL,
309                    CS8900_BUS_CTRL_RESET_RX_DMA |
310                    CS8900_BUS_CTRL_USE_SA |
311                    CS8900_BUS_CTRL_MEMORY_ENABLE);
312  io_pp_set_reg_16 (dev,
313                    CS8900_PP_BusCTL,
314                    CS8900_BUS_CTRL_USE_SA |
315                    CS8900_BUS_CTRL_MEMORY_ENABLE);
316
317  /*
318   * We are now in memory mapped mode.
319   */
320
321  /*
322   * Program the Line Control register with the mode we want.
323   *
324   * No auto detect support at the moment. Only 10BaseT.
325   */
326
327  mem_pp_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET);
328 
329  /*
330   * Ask the user for the MAC address, the program into the device.
331   */
332
333#define MACO(o) cs->arpcom.ac_enaddr[o]
334 
335  mem_pp_set_reg (dev, CS8900_PP_IA,
336                  (((unsigned int) MACO (1)) << 8) |
337                  ((unsigned int) MACO (0)));
338  mem_pp_set_reg (dev, CS8900_PP_IA + 2,
339                  (((unsigned int) MACO (3)) << 8) |
340                  ((unsigned int) MACO (2)));
341  mem_pp_set_reg (dev, CS8900_PP_IA + 4,
342                  (((unsigned int) MACO (5)) << 8) |
343                  ((unsigned int) MACO (4)));
344
345  /*
346   * Set the Buffer configuration.
347   */
348
349  mem_pp_set_reg (dev, CS8900_PP_BufCFG,
350                  CS8900_BUFFER_CONFIG_RDY_FOR_TX |
351                  CS8900_BUFFER_CONFIG_TX_UNDERRUN |
352                  CS8900_BUFFER_CONFIG_TX_COL_OVF |
353                  CS8900_BUFFER_CONFIG_RX_MISSED_OVF);
354
355  /*
356   * Set the Receiver configuration.
357   */
358
359  mem_pp_set_reg (dev, CS8900_PP_RxCFG,
360                  CS8900_RX_CONFIG_RX_OK |
361                  CS8900_RX_CONFIG_CRC_ERROR |
362                  CS8900_RX_CONFIG_RUNT|
363                  CS8900_RX_CONFIG_EXTRA_DATA);
364
365  /*
366   * Set the Receiver control.
367   */
368
369  mem_pp_set_reg (dev, CS8900_PP_RxCTL,
370                  CS8900_RX_CTRL_RX_OK |
371                  CS8900_RX_CTRL_MULTICAST |
372                  CS8900_RX_CTRL_INDIVIDUAL |
373                  CS8900_RX_CTRL_BROADCAST);
374 
375  /*
376   * Set the Transmitter configuration.
377   */
378
379  mem_pp_set_reg (dev, CS8900_PP_TxCFG,
380                  CS8900_TX_CONFIG_TX_OK |
381                  CS8900_TX_CONFIG_OUT_OF_WINDOW |
382                  CS8900_TX_CONFIG_JABBER |
383                  CS8900_TX_CONFIG_16_COLLISION);
384
385  /*
386   * Attach the interrupt handler.
387   */
388
389  cs8900_attach_interrupt (dev, cs);
390 
391  /*
392   * Program the interrupt level we require then enable interrupts.
393   */
394
395  mem_pp_set_reg (dev, CS8900_PP_INT, 0);
396
397  mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
398                      CS8900_BUS_CTRL_ENABLE_INT);
399}
400
401rtems_isr
402cs8900_interrupt (rtems_vector_number v, void *csp)
403{
404  cs8900_device  *cs = csp;
405  int            dev = cs->dev;
406  unsigned short isq = 0;
407  struct mbuf    *m;
408  unsigned char  *p;
409
410  ++cs->eth_stats.interrupts;
411
412  while (1)
413  {
414    isq = mem_pp_get_reg (dev, CS8900_PP_ISQ);
415
416    cs8900_trace (cs, CS8900_T_INT, isq);
417
418    WATCHDOG_TOGGLE ();
419   
420    /*
421     * No more interrupts to service.
422     */
423
424    if (isq == 0)
425      return;
426   
427    switch (isq & 0x1f)
428    {
429      case 0x04:
430
431        /*
432         * RxEvent.
433         */
434
435        ++cs->eth_stats.rx_interrupts;
436
437        if (isq & CS8900_RX_EVENT_RX_OK)
438        {
439          m = cs->rx_ready_head;
440          if (m)
441          {
442            cs->rx_ready_head = m->m_nextpkt;
443            if (cs->rx_ready_head == 0)
444              cs->rx_ready_tail = 0;
445            m->m_nextpkt = 0;
446            cs->rx_ready_len--;
447           
448            p = mtod (m, unsigned char *);
449     
450            m->m_pkthdr.len = cs8900_get_data_block (dev, p);
451
452            if (cs->rx_loaded_tail == 0)
453              cs->rx_loaded_head = m;
454            else
455              cs->rx_loaded_tail->m_nextpkt = m;
456            cs->rx_loaded_tail = m;
457            cs->rx_loaded_len++;
458
459            if (cs->rx_loaded_len == 1)
460            {
461              cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len);
462              rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
463            }
464          }
465          else
466          {
467            ++cs->eth_stats.rx_dropped;
468           
469            cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len);     
470
471            if (cs->rx_loaded_len == 0)
472              rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
473          }
474        }
475        else
476        {
477          if (isq & CS8900_RX_EVENT_CRC_ERROR)
478            ++cs->eth_stats.rx_crc_errors;
479
480          if (isq & CS8900_RX_EVENT_RUNT)
481            ++cs->eth_stats.rx_runt_errors;
482         
483          if (isq & CS8900_RX_EVENT_EXTRA_DATA)
484            ++cs->eth_stats.rx_oversize_errors;
485        }
486        break;
487
488      case 0x08:
489       
490        /*
491         * TxEvent.
492         */
493
494        ++cs->eth_stats.tx_interrupts;
495
496        if (cs->tx_active)
497        {
498          if (isq & CS8900_TX_EVENT_TX_OK)
499            ++cs->eth_stats.tx_ok;
500
501          cs->tx_active = 0;
502       
503          rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
504        }
505        break;
506
507      case 0x0c:
508       
509        /*
510         * BufEvent.
511         */
512       
513        if (isq & CS8900_BUFFER_EVENT_RDY_FOR_TX)
514        {
515          if (cs->tx_active)
516          {
517            ++cs->eth_stats.tx_rdy4tx;
518            rtems_event_send (cs->tx_task, CS8900_TX_WAIT_EVENT);
519          }
520        }
521        else if (isq & CS8900_BUFFER_EVENT_TX_UNDERRUN)
522        {
523          ++cs->eth_stats.tx_underrun_errors;
524          if (cs->tx_active)
525            rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
526        }
527        else if (isq & CS8900_BUFFER_EVENT_SW_INT)
528        {
529          ++cs->eth_stats.int_swint_res;
530        }
531        break;
532
533      case 0x10:
534       
535        /*
536         * RxMiss.
537         */
538       
539        cs->eth_stats.rx_missed_errors +=
540          mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
541        break;
542
543      case 0x12:
544       
545        /*
546         * TxCol.
547         */
548
549        cs->eth_stats.tx_collisions +=
550          mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
551        break;
552
553      default:
554        break;
555    }
556  }
557 
558}
559
560int
561cs8900_link_active (int dev)
562{
563  return ((mem_pp_get_reg (dev, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ?
564          1 : 0);
565}
566
567static inline void
568cs8900_rx_refill_queue (cs8900_device *cs)
569{
570  struct ifnet          *ifp = &cs->arpcom.ac_if;
571  struct mbuf           *m;
572  rtems_interrupt_level level;
573 
574  /*
575   * Hold a single queue of mbuf's at the interface. This
576   * will lower the latency of the driver.
577   */
578
579  while (cs->rx_ready_len < CS8900_RX_QUEUE_SIZE)
580  {
581    MGETHDR (m, M_DONTWAIT, MT_DATA);
582   
583    if (!m)
584    {
585      ++cs->eth_stats.rx_no_mbufs;
586      cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs);     
587      return;
588    }
589         
590    MCLGET (m, M_DONTWAIT);
591   
592    if (!m->m_ext.ext_buf)
593    {
594      ++cs->eth_stats.rx_no_clusters;
595      cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters);     
596      m_free (m);
597      return;
598    }
599    m->m_pkthdr.rcvif = ifp;
600    m->m_nextpkt = 0;
601
602    rtems_interrupt_disable (level);
603   
604    if (cs->rx_ready_tail == 0)
605      cs->rx_ready_head = m;
606    else
607      cs->rx_ready_tail->m_nextpkt = m;
608    cs->rx_ready_tail = m;
609    cs->rx_ready_len++;
610
611    rtems_interrupt_enable (level);
612  }
613}
614
615static void
616cs8900_rx_task (void *arg)
617{
618  cs8900_device         *cs = arg;
619  int                   dev = cs->dev;
620  struct ifnet          *ifp = &cs->arpcom.ac_if;
621  rtems_event_set       events;
622  struct mbuf           *m;
623  struct ether_header   *eh;
624  rtems_status_code     sc;
625  rtems_interrupt_level level;
626
627  /*
628   * Turn the receiver and transmitter on.
629   */
630 
631  mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
632                      CS8900_LINE_CTRL_RX_ON |
633                      CS8900_LINE_CTRL_TX_ON);
634 
635  /*
636   * Start the software interrupt watchdog.
637   */
638 
639  rtems_interrupt_disable (level);
640  mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
641                      CS8900_BUFFER_CONFIG_SW_INT);
642  ++cs->eth_stats.int_swint_req;
643  rtems_interrupt_enable (level);
644 
645  /*
646   * Loop reading packets.
647   */
648
649  while (1)
650  {
651    cs8900_rx_refill_queue (cs);
652   
653    sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT,
654                                     RTEMS_WAIT | RTEMS_EVENT_ANY,
655                                     TOD_MILLISECONDS_TO_TICKS (250),
656                                     &events);
657
658    cs8900_rx_refill_queue (cs);
659   
660    if (sc == RTEMS_TIMEOUT)
661    {
662      /*
663       * We need to check the interrupt hardware in the cs8900a
664       * has not locked up. It seems this occurs if the ISQ
665       * queue fills up.
666       * To test we generate a software interrupt and watch
667       * a counter go up. If the counter does not go for 2
668       * software interrupts requests we flush the ISQ queue.
669       */
670
671      if ((cs->eth_stats.int_swint_req - cs->eth_stats.int_swint_res) > 1)
672      {
673        printf ("cs8900: int lockup, isq flush\n");
674
675        mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
676                              CS8900_BUS_CTRL_ENABLE_INT);
677       
678        while (mem_pp_get_reg (dev, CS8900_PP_ISQ) != 0);
679       
680        cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0;
681        ++cs->eth_stats.int_lockup;
682       
683        mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
684                            CS8900_BUS_CTRL_ENABLE_INT);
685      }
686     
687      rtems_interrupt_disable (level);
688      mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
689                          CS8900_BUFFER_CONFIG_SW_INT);
690      ++cs->eth_stats.int_swint_req;
691      rtems_interrupt_enable (level);
692    }
693
694    cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len);
695   
696    while (cs->rx_loaded_len)
697    {
698      rtems_interrupt_disable (level);
699   
700      m = cs->rx_loaded_head;
701      if (m)
702      {
703        cs->rx_loaded_head = m->m_nextpkt;
704        if (cs->rx_loaded_head == 0)
705          cs->rx_loaded_tail = 0;
706        m->m_nextpkt = 0;
707        cs->rx_loaded_len--;
708       
709        rtems_interrupt_enable (level);
710       
711        m->m_pkthdr.rcvif = ifp;
712       
713        cs->eth_stats.rx_bytes += m->m_pkthdr.len;
714       
715        m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header);
716       
717        eh = mtod (m, struct ether_header *);
718        m->m_data += sizeof (struct ether_header);
719     
720        ++cs->eth_stats.rx_packets;
721       
722        ether_input (ifp, eh, m);
723      }
724      else
725      {
726        rtems_interrupt_enable (level);
727      }
728    }
729    cs8900_trace (cs, CS8900_T_RX_END, cs->rx_loaded_len);
730  }
731}
732
733static void
734cs8900_tx_task (void *arg)
735{
736  cs8900_device     *cs = arg;
737  int               dev = cs->dev;
738  struct ifnet      *ifp = &cs->arpcom.ac_if;
739  rtems_event_set   events;
740  struct mbuf       *m;
741  rtems_status_code sc;
742
743  /*
744   * Wait for the link to come up.
745   */
746
747  rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (750));
748
749  /*
750   * Loop processing the tx queue.
751   */
752
753  while (1)
754  {
755    /*
756     * Fetch the mbuf list from the interface's queue.
757     */
758
759    IF_DEQUEUE (&ifp->if_snd, m);
760
761    /*
762     * If something actually is present send it.
763     */
764
765    if (!m)
766    {
767      ifp->if_flags &= ~IFF_OACTIVE;
768
769      rtems_bsdnet_event_receive (CS8900_TX_START_EVENT,
770                                  RTEMS_WAIT | RTEMS_EVENT_ANY,
771                                  RTEMS_NO_TIMEOUT,
772                                  &events);
773    }
774    else
775    {
776      if (cs8900_link_active (dev))
777      {
778        int resending;
779       
780        do
781        {
782          unsigned short buf_status;
783
784          resending = 0;
785         
786          cs->tx_active = 1;
787         
788          mem_pp_set_reg (dev, CS8900_PP_TxCMD,
789                          CS8900_TX_CMD_STATUS_TX_START_ENTIRE |
790                          CS8900_TX_CMD_STATUS_FORCE);
791          mem_pp_set_reg (dev, CS8900_PP_TxLength, m->m_pkthdr.len);
792         
793          buf_status = mem_pp_get_reg (dev, CS8900_PP_BusST);
794
795          /*
796           * If the bid for memory in the device fails trash the
797           * transmit and try again next time.
798           */
799
800          if (buf_status & CS8900_BUS_STATUS_TX_BID_ERROR)
801            ++cs->eth_stats.tx_bid_errors;
802          else
803          {
804            /*
805             * If the buffer is not read enable the interrupt and then wait.
806             */
807           
808            if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0)
809            {
810              cs->eth_stats.tx_wait_for_rdy4tx++;
811              sc = rtems_bsdnet_event_receive (CS8900_TX_WAIT_EVENT,
812                                               RTEMS_WAIT | RTEMS_EVENT_ANY,
813                                               TOD_MILLISECONDS_TO_TICKS (750),
814                                               &events);
815              if (sc == RTEMS_TIMEOUT)
816              {
817                /*
818                 * For some reason the wait request has been dropped,
819                 * so lets resend from the start.
820                 */
821
822                printf ("tx resend\n");
823                ++cs->eth_stats.tx_resends;
824                resending = 1;
825              }
826            }
827
828            if (!resending)
829            {
830              cs8900_tx_load (dev, m);
831              cs->eth_stats.tx_packets++;
832              cs->eth_stats.tx_bytes += m->m_pkthdr.len;
833            }
834          }
835        }
836        while (resending);
837       
838        m_freem (m);
839       
840        do
841        {
842          rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT,
843                                      RTEMS_WAIT | RTEMS_EVENT_ANY,
844                                      RTEMS_NO_TIMEOUT,
845                                      &events);
846        }
847        while (cs->tx_active);
848      }
849      else
850      {
851        ++cs->eth_stats.tx_dropped;
852        m_freem (m);
853      }
854    }
855  }
856}
857
858static void
859cs8900_start (struct ifnet *ifp)
860{
861  cs8900_device *cs = ifp->if_softc;
862
863  /*
864   * Tell the transmit daemon to wake up and send a packet.
865   */
866
867  ifp->if_flags |= IFF_OACTIVE;
868
869  rtems_event_send (cs->tx_task, CS8900_TX_START_EVENT);
870}
871
872static void
873cs8900_stop (cs8900_device *cs)
874{
875  int dev = cs->dev;
876
877  mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG,
878                        CS8900_LINE_CTRL_RX_ON |
879                        CS8900_LINE_CTRL_TX_ON);
880 
881  mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
882                        CS8900_BUS_CTRL_ENABLE_INT);
883}
884
885static const char *eth_statistics_labels[] =
886{
887  "rx packets",
888  "tx packets",
889  "rx bytes",
890  "tx bytes",
891  "rx interrupts",
892  "tx interrupts",
893  "rx dropped",
894  "rx no mbuf",
895  "rx no custers",
896  "rx oversize errors",
897  "rx crc errors",
898  "rx runt errors",
899  "rx missed errors",
900  "tx ok",
901  "tx collisions",
902  "tx bid errors",
903  "tx wait for rdy4tx",
904  "tx rdy4tx",
905  "tx underrun errors",
906  "tx dropped",
907  "tx resends",
908  "int swint req",
909  "int swint res",
910  "int lockup",
911  "interrupts"
912};
913
914static void
915cs8900_stats (cs8900_device *cs)
916{
917  int           dev = cs->dev;
918  int           i;
919  int           max_label = 0;
920  int           len;
921  unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets;
922
923  cs->eth_stats.rx_missed_errors +=
924    mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
925   
926  cs->eth_stats.tx_collisions +=
927    mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
928 
929  printf ("Network Driver Stats for CS8900 :\n");
930
931  for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++)
932  {
933    len = strlen (eth_statistics_labels[i]);
934    if (len > max_label)
935      max_label = len;
936  }
937
938  max_label += 2;
939
940  printf ("%*s - %10u %*s - %10u\n",
941          max_label, "rx ready len", cs->rx_ready_len,
942          max_label, "rx loaded len", cs->rx_loaded_len);
943 
944  for (i = 0;
945       i < (sizeof (eth_statistics_labels) / sizeof (const char *));
946       i++)
947  {
948    printf ("%*s - %10lu",
949            max_label, eth_statistics_labels[i], value[i]);
950   
951    i++;
952   
953    if (i < (sizeof (eth_statistics_labels) / sizeof (const char *)))
954      printf (" %*s - %10lu",
955              max_label, eth_statistics_labels[i], value[i]);
956    printf ("\n");
957  }
958
959#if CS8900_TRACE
960 
961  for (i = 0; i < cs->trace_in; i++)
962  {
963    printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000);
964   
965    if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*))
966      printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]);
967    else
968      printf ("unknown trace key, %d : ", cs->trace_key[i]);
969
970    if (cs->trace_key[i] == CS8900_T_INT)
971    {
972      printf ("0x%04lx ", cs->trace_var[i]);
973      if (cs->trace_var[i] == 0)
974        printf ("end");
975      else
976      {
977        switch (cs->trace_var[i] & 0x1f)
978        {
979          case 0x04:
980            printf ("rx event");
981            break;
982
983          case 0x08:
984            printf ("tx event");
985            break;
986
987          case 0x0c:
988            printf ("buffer event");
989            break;
990
991          case 0x10:
992            printf ("rx missed");
993            break;
994
995          case 0x12:
996            printf ("tx collisions");
997            break;
998
999          case 0x1f:
1000            printf ("tx request");
1001            break;
1002         
1003          case 0x1e:
1004            printf ("tx wait 4 tx");
1005            break;
1006         
1007          case 0x1d:
1008            printf ("tx already active");
1009            break;
1010         
1011          default:
1012            printf ("unknown event");
1013            break;
1014        }
1015      }
1016    }
1017    else
1018      printf ("0x%08lx", cs->trace_var[i]);
1019   
1020    printf ("\n");
1021  }
1022
1023  cs->trace_in = 0;
1024 
1025#endif
1026}
1027
1028static void
1029cs8900_init (void *arg)
1030{
1031  cs8900_device *cs  = arg;
1032  int           dev  = cs->dev;
1033  struct ifnet  *ifp = &cs->arpcom.ac_if;
1034
1035  if (cs->rx_task == 0)
1036  {
1037
1038    /*
1039     * Set up the hardware.
1040     */
1041   
1042    cs8900_hardware_init (cs);
1043
1044    /*
1045     * Start driver task. We have only one task.
1046     */
1047   
1048    cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs);
1049    cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs);
1050  }
1051
1052#ifdef todo
1053  /*
1054   * Set flags appropriately
1055   */
1056  if (ifp->if_flags & IFF_PROMISC)
1057  else
1058#endif
1059 
1060  /*
1061   * Tell the world that we're running.
1062   */
1063 
1064  ifp->if_flags |= IFF_RUNNING;
1065
1066  /*
1067   * Set the Line Control to bring the receive and transmitter online.
1068   */
1069
1070  mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
1071                      CS8900_LINE_CTRL_RX_ON |
1072                      CS8900_LINE_CTRL_TX_ON);
1073
1074  mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
1075                      CS8900_BUS_CTRL_ENABLE_INT);
1076}
1077
1078static int
1079cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
1080{
1081  cs8900_device *cs = ifp->if_softc;
1082  int           error = 0;
1083
1084  switch (cmd)
1085  {
1086    case SIOCGIFADDR:
1087    case SIOCSIFADDR:
1088     
1089      error = ether_ioctl (ifp, cmd, data);
1090      break;
1091
1092    case SIOCSIFFLAGS:
1093     
1094      switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1095      {
1096        case IFF_RUNNING:
1097         
1098          cs8900_stop (cs);
1099          break;
1100
1101        case IFF_UP:
1102         
1103          cs8900_init (cs);
1104          break;
1105
1106        case IFF_UP | IFF_RUNNING:
1107         
1108          cs8900_stop (cs);
1109          cs8900_init (cs);
1110          break;
1111
1112        default:
1113          break;
1114      }
1115      break;
1116
1117    case SIO_RTEMS_SHOW_STATS:
1118     
1119      cs8900_stats (cs);
1120      break;
1121
1122      /* FIXME: Multicast commands must be added here.  */
1123
1124    default:
1125      error = EINVAL;
1126      break;
1127  }
1128
1129  return error;
1130}
1131
1132int
1133cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
1134{
1135  cs8900_device *cs;
1136  struct ifnet  *ifp;
1137  int           mtu;
1138  int           unit;
1139  char          *name;
1140
1141  /*
1142    * Parse driver name
1143   */
1144 
1145  if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
1146    return 0;
1147 
1148  /*
1149   * Is driver free?
1150   */
1151 
1152  if (unit >= CS8900_DEVICES)
1153  {
1154    printf ("Bad CS8900 unit number for device `%s'.\n", config->name);
1155    return 0;
1156  }
1157 
1158  cs      = &cs8900[unit];
1159  cs->dev = unit;
1160  ifp     = &cs->arpcom.ac_if;
1161
1162  if (attaching)
1163  {
1164    if (ifp->if_softc)
1165    {
1166      printf ("Driver `%s' already in use.\n", config->name);
1167      return 0;
1168    }
1169
1170    /*
1171     * Process options
1172     */
1173   
1174    if (config->hardware_address)
1175      memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1176    else
1177      cs8900_get_mac_addr (unit, cs->arpcom.ac_enaddr);
1178 
1179    if (config->mtu)
1180      mtu = config->mtu;
1181    else
1182      mtu = ETHERMTU;
1183   
1184    cs->accept_bcast = !config->ignore_broadcast;
1185   
1186    /*
1187     * Set up network interface values.
1188     */
1189   
1190    ifp->if_softc  = cs;
1191    ifp->if_unit   = unit;
1192    ifp->if_name   = name;
1193    ifp->if_mtu    = mtu;
1194    ifp->if_init   = cs8900_init;
1195    ifp->if_ioctl  = cs8900_ioctl;
1196    ifp->if_start  = cs8900_start;
1197    ifp->if_output = ether_output;
1198    ifp->if_flags  = IFF_BROADCAST | IFF_SIMPLEX;
1199   
1200    if (ifp->if_snd.ifq_maxlen == 0)
1201      ifp->if_snd.ifq_maxlen = ifqmaxlen;
1202   
1203    /*
1204     * Attach the interface to the stack.
1205     */
1206   
1207    if_attach (ifp);
1208    ether_ifattach (ifp);
1209  }
1210  else
1211  {
1212    if (!ifp->if_softc)
1213    {
1214      printf ("Driver `%s' not found.\n", config->name);
1215      return 0;
1216    }
1217
1218    cs8900_stop (cs);
1219    cs8900_detach_interrupt (unit);
1220  }
1221 
1222  return 1;
1223 
1224}
Note: See TracBrowser for help on using the repository browser.