source: rtems/bsps/shared/net/cs8900.c @ 762fa62

5
Last change on this file since 762fa62 was 27de4e1f, checked in by Sebastian Huber <sebastian.huber@…>, on 04/03/18 at 05:20:11

bsps: Move libchip to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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