source: rtems/c/src/lib/libbsp/arm/lpc24xx/network/network.c @ 7ae2775

4.104.115
Last change on this file since 7ae2775 was 7ae2775, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 17, 2009 at 1:53:04 PM

ARM bsp maintenance

  • Property mode set to 100644
File size: 32.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx
5 *
6 * @brief Network driver.
7 */
8
9/*
10 * Copyright (c) 2008
11 * Embedded Brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * rtems@embedded-brains.de
16 *
17 * The license and distribution terms for this file may be found in the file
18 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
19 */
20
21#include <errno.h>
22#include <inttypes.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26
27#include <rtems.h>
28#include <rtems/rtems_bsdnet.h>
29#include <rtems/rtems_mii_ioctl.h>
30
31#include <sys/param.h>
32#include <sys/socket.h>
33#include <sys/sockio.h>
34#include <sys/mbuf.h>
35
36#include <net/if.h>
37#include <net/if_arp.h>
38#include <netinet/in.h>
39#include <netinet/if_ether.h>
40#include <netinet/in_systm.h>
41#include <netinet/ip.h>
42
43#include <bsp.h>
44#include <bsp/lpc24xx.h>
45#include <bsp/irq.h>
46#include <bsp/io.h>
47#include <bsp/utility.h>
48
49#include <rtems/status-checks.h>
50
51#if MCLBYTES > (2 * 1024)
52  #error "MCLBYTES to large"
53#endif
54
55#define LPC24XX_ETH_INTERFACE_NUMBER 1
56
57/**
58 * @brief Start address of the Ethernet RAM.
59 */
60#define LPC24XX_ETH_RAM_START 0x7fe00000U
61
62/**
63 * @brief Size of the Ethernet RAM.
64 */
65#define LPC24XX_ETH_RAM_SIZE (16 * 1024)
66
67#define LPC24XX_ETH_RAM_END \
68  (LPC24XX_ETH_RAM_START + LPC24XX_ETH_RAM_SIZE)
69
70#define LPC24XX_ETH_TRANSMIT_BUFFER_SIZE 1518
71
72#define LPC24XX_ETH_RECEIVE_UNIT_SIZE \
73  (ETH_TRANSFER_DESCRIPTOR_SIZE \
74    + ETH_RECEIVE_INFO_SIZE \
75    + 4)
76
77#define LPC24XX_ETH_TRANSMIT_UNIT_SIZE \
78  (ETH_TRANSFER_DESCRIPTOR_SIZE \
79    + ETH_TRANSMIT_STATUS_SIZE \
80    + LPC24XX_ETH_TRANSMIT_BUFFER_SIZE)
81
82#define LPC24XX_ETH_RECEIVE_UNIT_NUMBER 54
83
84#define LPC24XX_ETH_TRANSMIT_UNIT_NUMBER 10
85
86#define LPC24XX_ETH_RECEIVE_DATA_SIZE \
87  (LPC24XX_ETH_RECEIVE_UNIT_NUMBER \
88    * LPC24XX_ETH_RECEIVE_UNIT_SIZE)
89
90#define LPC24XX_ETH_RECEIVE_DATA_START \
91  LPC24XX_ETH_RAM_START
92
93#define LPC24XX_ETH_RECEIVE_DATA_END \
94  (LPC24XX_ETH_RECEIVE_DATA_START \
95    + LPC24XX_ETH_RECEIVE_DATA_SIZE)
96
97#define LPC24XX_ETH_TRANSMIT_DATA_SIZE \
98  (LPC24XX_ETH_TRANSMIT_UNIT_NUMBER \
99    * LPC24XX_ETH_TRANSMIT_UNIT_SIZE)
100
101#if 1
102
103#define LPC24XX_ETH_TRANSMIT_DATA_START \
104  LPC24XX_ETH_RECEIVE_DATA_END
105
106#else
107
108static char lpc24xx_eth_transmit_buffer [LPC24XX_ETH_TRANSMIT_DATA_SIZE];
109
110#define LPC24XX_ETH_TRANSMIT_DATA_START \
111  lpc24xx_eth_transmit_buffer
112
113#endif
114
115#define LPC24XX_ETH_TRANSMIT_DATA_END \
116  (LPC24XX_ETH_TRANSMIT_DATA_START \
117    + LPC24XX_ETH_TRANSMIT_DATA_SIZE)
118
119#if LPC24XX_ETH_TRANSMIT_DATA_END > LPC24XX_ETH_RAM_END && 0
120  #error "Ethernet RAM overflow"
121#endif
122
123#define LPC24XX_ETH_RECEIVE_DESC_START \
124  LPC24XX_ETH_RECEIVE_DATA_START
125
126#define LPC24XX_ETH_RECEIVE_INFO_START \
127  (LPC24XX_ETH_RECEIVE_DESC_START \
128    + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE)
129
130#define LPC24XX_ETH_RECEIVE_MBUF_START \
131  (LPC24XX_ETH_RECEIVE_INFO_START \
132    + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_RECEIVE_INFO_SIZE)
133
134#define LPC24XX_ETH_TRANSMIT_DESC_START \
135  LPC24XX_ETH_TRANSMIT_DATA_START
136
137#define LPC24XX_ETH_TRANSMIT_STATUS_START \
138  (LPC24XX_ETH_TRANSMIT_DATA_START \
139    + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE)
140
141#define LPC24XX_ETH_TRANSMIT_BUFFER_START \
142  (LPC24XX_ETH_TRANSMIT_STATUS_START \
143    + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSMIT_STATUS_SIZE)
144
145#define LPC24XX_ETH_EVENT_INITIALIZE RTEMS_EVENT_1
146
147#define LPC24XX_ETH_EVENT_START RTEMS_EVENT_2
148
149#define LPC24XX_ETH_EVENT_INTERRUPT RTEMS_EVENT_3
150
151#define LPC24XX_ETH_INTERRUPT_RECEIVE \
152  (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE)
153
154#define LPC24XX_ETH_INTERRUPT_TRANSMIT \
155  (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR)
156
157#define LPC24XX_ETH_RX_STAT_ERRORS \
158  (ETH_RX_STAT_CRC_ERROR \
159    | ETH_RX_STAT_SYMBOL_ERROR \
160    | ETH_RX_STAT_LENGTH_ERROR \
161    | ETH_RX_STAT_ALIGNMENT_ERROR \
162    | ETH_RX_STAT_OVERRUN \
163    | ETH_RX_STAT_NO_DESCRIPTOR)
164
165#define LPC24XX_ETH_LAST_FRAGMENT_FLAGS \
166  (ETH_TX_CTRL_OVERRIDE \
167    | ETH_TX_CTRL_PAD \
168    | ETH_TX_CTRL_CRC \
169    | ETH_TX_CTRL_INTERRUPT \
170    | ETH_TX_CTRL_LAST)
171
172#ifdef DEBUG
173  #define LPC24XX_ETH_PRINTF( ...) printf( __VA_ARGS__)
174  #define LPC24XX_ETH_PRINTK( ...) printk( __VA_ARGS__)
175#else
176  #define LPC24XX_ETH_PRINTF( ...)
177  #define LPC24XX_ETH_PRINTK( ...)
178#endif
179
180typedef enum {
181  LPC24XX_ETH_NOT_INITIALIZED,
182  LPC24XX_ETH_INITIALIZED,
183  LPC24XX_ETH_STARTED,
184  LPC24XX_ETH_RUNNING
185} lpc24xx_eth_state;
186
187typedef struct {
188  struct arpcom arpcom;
189  struct rtems_mdio_info mdio_info;
190  lpc24xx_eth_state state;
191  rtems_id receive_task;
192  rtems_id transmit_task;
193  unsigned receive_unit_number;
194  unsigned transmit_unit_number;
195  unsigned received_frames;
196  unsigned receive_interrupts;
197  unsigned transmitted_frames;
198  unsigned transmit_interrupts;
199  unsigned receive_overrun_errors;
200  unsigned receive_fragment_errors;
201  unsigned receive_crc_errors;
202  unsigned receive_symbol_errors;
203  unsigned receive_length_errors;
204  unsigned receive_alignment_errors;
205  unsigned receive_no_descriptor_errors;
206  unsigned receive_fatal_errors;
207  unsigned transmit_underrun_errors;
208  unsigned transmit_late_collision_errors;
209  unsigned transmit_excessive_collision_errors;
210  unsigned transmit_excessive_defer_errors;
211  unsigned transmit_no_descriptor_errors;
212  unsigned transmit_overflow_errors;
213  unsigned transmit_fatal_errors;
214} lpc24xx_eth_driver_entry;
215
216static lpc24xx_eth_driver_entry lpc24xx_eth_driver_data = {
217  .state = LPC24XX_ETH_NOT_INITIALIZED,
218  .receive_task = RTEMS_ID_NONE,
219  .transmit_task = RTEMS_ID_NONE
220};
221
222static inline uint32_t lpc24xx_eth_increment(
223  uint32_t value,
224  uint32_t cycle
225)
226{
227  if (value < cycle) {
228    return ++value;
229  } else {
230    return 0;
231  }
232}
233
234static void lpc24xx_eth_reset_filter( void)
235{
236  MAC_RXFILTERCTRL = 0;
237  MAC_RXFILTERWOLCLR = 0xcf;
238  MAC_HASHFILTERL = 0;
239  MAC_HASHFILTERH = 0;
240}
241
242static void lpc24xx_eth_enable_promiscous_mode( bool enable)
243{
244  if (enable) {
245    MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT
246      | ETH_RX_FIL_CTRL_ACCEPT_UNICAST
247      | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST
248      | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
249  } else {
250    MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT
251      | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
252  }
253}
254
255static void lpc24xx_eth_interrupt_handler(
256  rtems_vector_number vector,
257  void *arg
258)
259{
260  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg;
261  rtems_event_set re = 0;
262  rtems_event_set te = 0;
263  uint32_t ie = 0;
264
265  /* Get interrupt status */
266  uint32_t im = MAC_INTENABLE;
267  uint32_t is = MAC_INTSTATUS & im;
268
269  /* Check receive interrupts */
270  if (IS_FLAG_SET( is, ETH_INT_RX_OVERRUN)) {
271    re = LPC24XX_ETH_EVENT_INITIALIZE;
272    ++e->receive_fatal_errors;
273  } else if (IS_ANY_FLAG_SET( is, LPC24XX_ETH_INTERRUPT_RECEIVE)) {
274    re = LPC24XX_ETH_EVENT_INTERRUPT;
275    ie = SET_FLAGS( ie, LPC24XX_ETH_INTERRUPT_RECEIVE);
276  }
277
278  /* Send events to receive task */
279  if (re != 0) {
280    ++e->receive_interrupts;
281    (void) rtems_event_send( e->receive_task, re);
282  }
283
284  /* Check transmit interrupts */
285  if (IS_FLAG_SET( is, ETH_INT_TX_UNDERRUN)) {
286    te = LPC24XX_ETH_EVENT_INITIALIZE;
287    ++e->transmit_fatal_errors;
288  } else if (IS_ANY_FLAG_SET( is, LPC24XX_ETH_INTERRUPT_TRANSMIT)) {
289    te = LPC24XX_ETH_EVENT_INTERRUPT;
290    ie = SET_FLAGS( ie, LPC24XX_ETH_INTERRUPT_TRANSMIT);
291  }
292
293  /* Send events to transmit task */
294  if (te != 0) {
295    ++e->transmit_interrupts;
296    (void) rtems_event_send( e->transmit_task, te);
297  }
298
299  LPC24XX_ETH_PRINTK( "interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te);
300
301  /* Update interrupt mask */
302  MAC_INTENABLE = CLEAR_FLAGS( im, ie);
303
304  /* Clear interrupts */
305  MAC_INTCLEAR = is;
306}
307
308static void lpc24xx_eth_enable_receive_interrupts( void)
309{
310  rtems_interrupt_level level;
311
312  rtems_interrupt_disable( level);
313  MAC_INTENABLE = SET_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE);
314  rtems_interrupt_enable( level);
315}
316
317static void lpc24xx_eth_disable_receive_interrupts( void)
318{
319  rtems_interrupt_level level;
320
321  rtems_interrupt_disable( level);
322  MAC_INTENABLE = CLEAR_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE);
323  rtems_interrupt_enable( level);
324}
325
326static void lpc24xx_eth_enable_transmit_interrupts( void)
327{
328  rtems_interrupt_level level;
329
330  rtems_interrupt_disable( level);
331  MAC_INTENABLE = SET_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT);
332  rtems_interrupt_enable( level);
333}
334
335static void lpc24xx_eth_disable_transmit_interrupts( void)
336{
337  rtems_interrupt_level level;
338
339  rtems_interrupt_disable( level);
340  MAC_INTENABLE = CLEAR_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT);
341  rtems_interrupt_enable( level);
342}
343
344static struct mbuf *lpc24xx_eth_new_mbuf( struct ifnet *ifp, bool wait)
345{
346  struct mbuf *m = NULL;
347  int mw = wait ? M_WAIT : M_DONTWAIT;
348
349  MGETHDR( m, mw, MT_DATA);
350  if (m != NULL) {
351    MCLGET( m, mw);
352    if (IS_FLAG_SET( m->m_flags, M_EXT)) {
353      /* Set receive interface */
354      m->m_pkthdr.rcvif = ifp;
355
356      /* Adjust by two bytes for proper IP header alignment */
357      m->m_data = mtod( m, char *) + 2;
358
359      return m;
360    } else {
361      m_free( m);
362    }
363  }
364
365  return NULL;
366}
367
368static bool lpc24xx_eth_add_new_mbuf(
369  struct ifnet *ifp,
370  volatile lpc24xx_eth_transfer_descriptor *desc,
371  struct mbuf **mbuf_table,
372  uint32_t i,
373  bool wait
374)
375{
376  /* New mbuf */
377  struct mbuf *m = lpc24xx_eth_new_mbuf( ifp, wait);
378
379  /* Check mbuf */
380  if (m != NULL) {
381    /* Add mbuf to queue */
382    desc [i].start = mtod( m, uint32_t);
383    desc [i].control = SET_ETH_RX_CTRL_SIZE( 0, MCLBYTES - 1)
384      | ETH_RX_CTRL_INTERRUPT;
385
386    /* Add mbuf to table */
387    mbuf_table [i] = m;
388
389    return true;
390  } else {
391    return false;
392  }
393}
394
395static void lpc24xx_eth_receive_task( void *arg)
396{
397  rtems_status_code sc = RTEMS_SUCCESSFUL;
398  rtems_event_set events = 0;
399  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg;
400  struct ifnet *ifp = &e->arpcom.ac_if;
401  volatile lpc24xx_eth_transfer_descriptor *const desc =
402    (volatile lpc24xx_eth_transfer_descriptor *)
403      LPC24XX_ETH_RECEIVE_DESC_START;
404  volatile lpc24xx_eth_receive_info *const info = 
405    (volatile lpc24xx_eth_receive_info *)
406      LPC24XX_ETH_RECEIVE_INFO_START;
407  struct mbuf **const mbuf_table =
408    (struct mbuf **) LPC24XX_ETH_RECEIVE_MBUF_START;
409  uint32_t index_max = 0;
410  uint32_t produce_index = 0;
411  uint32_t consume_index = 0;
412  uint32_t receive_index = 0;
413
414  LPC24XX_ETH_PRINTF( "%s\n", __func__);
415
416  /* Main event loop */
417  while (true) {
418    bool wait_for_mbuf = false;
419
420    /* Wait for events */
421    sc = rtems_bsdnet_event_receive(
422      LPC24XX_ETH_EVENT_INITIALIZE | LPC24XX_ETH_EVENT_INTERRUPT, 
423      RTEMS_EVENT_ANY | RTEMS_WAIT,
424      RTEMS_NO_TIMEOUT,
425      &events
426    );
427    RTEMS_CLEANUP_SC( sc, cleanup, "wait for events");
428
429    LPC24XX_ETH_PRINTF( "rx: wake up: 0x%08" PRIx32 "\n", events);
430
431    /* Initialize receiver? */
432    if (IS_FLAG_SET( events, LPC24XX_ETH_EVENT_INITIALIZE)) {
433      /* Disable receive interrupts */
434      lpc24xx_eth_disable_receive_interrupts();
435
436      /* Disable receiver */
437      MAC_COMMAND = CLEAR_FLAG( MAC_COMMAND, ETH_CMD_RX_ENABLE);
438
439      /* Wait for inactive status */
440      while (IS_FLAG_SET( MAC_STATUS, ETH_STAT_RX_ACTIVE)) {
441        /* Wait */
442      }
443
444      /* Reset */
445      MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_RX_RESET);
446
447      /* Clear receive interrupts */
448      MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE;
449
450      /* Index maximum (determines queue size) */
451      index_max = e->receive_unit_number - 1;
452
453      /* Move existing mbufs to the front */
454      consume_index = 0;
455      for (produce_index = 0; produce_index <= index_max; ++produce_index) {
456        if (mbuf_table [produce_index] != NULL) {
457          mbuf_table [consume_index] = mbuf_table [produce_index];
458          ++consume_index;
459        }
460      }
461
462      /* Fill receive queue */
463      for (produce_index = consume_index; produce_index <= index_max; ++produce_index) {
464        if (
465          !lpc24xx_eth_add_new_mbuf( ifp, desc, mbuf_table, produce_index, false)
466        ) {
467          break;
468        }
469      }
470
471      /* Check if the queue is full */
472      if (produce_index == 0) {
473        RTEMS_DO_CLEANUP(
474          cleanup,
475          "no mbufs to fill receive queue: terminate receive task\n"
476        );
477      } else if (produce_index <= index_max) {
478        /* Reduce the queue size */
479        index_max = produce_index - 1;
480
481        RTEMS_SYSLOG_ERROR( "not enough mbufs to fill receive queue");
482      }
483
484      /* Receive descriptor table */
485      MAC_RXDESCRIPTORNUM = index_max;
486      MAC_RXDESCRIPTOR = (uint32_t) desc;
487      MAC_RXSTATUS = (uint32_t) info;
488
489      /* Initialize indices */
490      produce_index = MAC_RXPRODUCEINDEX;
491      consume_index = MAC_RXCONSUMEINDEX;
492      receive_index = consume_index;
493
494      /* Enable receiver */
495      MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_RX_ENABLE);
496
497      /* Enable receive interrupts */
498      lpc24xx_eth_enable_receive_interrupts();
499
500      /* Wait for events */
501      continue;
502    }
503
504    while (true) {
505      /* Clear receive interrupt status */
506      MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE;
507
508      /* Get current produce index */
509      produce_index = MAC_RXPRODUCEINDEX;
510
511      if (receive_index != produce_index) {
512        /* Fragment mbuf and status */
513        struct mbuf *m = mbuf_table [receive_index];
514        uint32_t stat = info [receive_index].status;
515
516        /* Remove mbuf from table */
517        mbuf_table [receive_index] = NULL;
518
519        if (
520          IS_FLAG_SET( stat, ETH_RX_STAT_LAST_FLAG)
521            && ARE_FLAGS_CLEARED( stat, LPC24XX_ETH_RX_STAT_ERRORS)
522        ) {
523          /* Ethernet header */
524          struct ether_header *eh = mtod( m, struct ether_header *);
525
526          /* Discard Ethernet header and CRC */
527          int sz = (int) GET_ETH_RX_STAT_RXSIZE( stat) + 1
528            - ETHER_HDR_LEN - ETHER_CRC_LEN;
529
530          /* Update mbuf */
531          m->m_len = sz;
532          m->m_pkthdr.len = sz;
533          m->m_data = mtod( m, char *) + ETHER_HDR_LEN;
534
535          LPC24XX_ETH_PRINTF( "rx: %02" PRIu32 ": %u\n", receive_index, sz);
536
537          /* Hand over */
538          ether_input( ifp, eh, m);
539
540          /* Increment received frames counter */
541          ++e->received_frames;
542        } else {
543          /* Release mbuf */
544          m_free( m);
545
546          /* Update error counters */
547          if (IS_FLAG_SET( stat, ETH_RX_STAT_OVERRUN)) {
548            ++e->receive_overrun_errors;
549          }
550          if (IS_FLAG_CLEARED( stat, ETH_RX_STAT_LAST_FLAG)) {
551            ++e->receive_fragment_errors;
552          }
553          if (IS_FLAG_SET( stat, ETH_RX_STAT_CRC_ERROR)) {
554            ++e->receive_crc_errors;
555          }
556          if (IS_FLAG_SET( stat, ETH_RX_STAT_SYMBOL_ERROR)) {
557            ++e->receive_symbol_errors;
558          }
559          if (IS_FLAG_SET( stat, ETH_RX_STAT_LENGTH_ERROR)) {
560            ++e->receive_length_errors;
561          }
562          if (IS_FLAG_SET( stat, ETH_RX_STAT_ALIGNMENT_ERROR)) {
563            ++e->receive_alignment_errors;
564          }
565          if (IS_FLAG_SET( stat, ETH_RX_STAT_NO_DESCRIPTOR)) {
566            ++e->receive_no_descriptor_errors;
567          }
568        }
569
570        /* Increment receive index */
571        receive_index = lpc24xx_eth_increment( receive_index, index_max);
572      } else {
573        /* Nothing to do, enable receive interrupts */
574        lpc24xx_eth_enable_receive_interrupts();
575        break;
576      }
577    }
578
579    /* Wait for mbuf? */
580    wait_for_mbuf =
581      lpc24xx_eth_increment( produce_index, index_max) == consume_index;
582
583    /* Fill queue with new mbufs */
584    while (consume_index != produce_index) {
585      /* Add new mbuf to queue */
586      if (
587        !lpc24xx_eth_add_new_mbuf(
588          ifp, desc, mbuf_table, consume_index, wait_for_mbuf
589        )
590      ) {
591        break;
592      }
593
594      /* We wait for at most one mbuf */
595      wait_for_mbuf = false;
596
597      /* Increment consume index */
598      consume_index = lpc24xx_eth_increment( consume_index, index_max);
599
600      /* Update consume indices */
601      MAC_RXCONSUMEINDEX = consume_index;
602    }
603  }
604
605cleanup:
606
607  /* Clear task ID */
608  e->receive_task = RTEMS_ID_NONE;
609
610  /* Release network semaphore */
611  rtems_bsdnet_semaphore_release();
612
613  /* Terminate self */
614  (void) rtems_task_delete( RTEMS_SELF);
615}
616
617static struct mbuf *lpc24xx_eth_next_fragment(
618  struct ifnet *ifp,
619  struct mbuf *m,
620  uint32_t *ctrl
621)
622{
623  struct mbuf *n = NULL;
624  int size = 0;
625
626  while (true) {
627    if (m == NULL) {
628      /* Dequeue first fragment of the next frame */
629      IF_DEQUEUE( &ifp->if_snd, m);
630
631      /* Empty queue? */
632      if (m == NULL) {
633        return m;
634      }
635    }
636
637    /* Get fragment size */
638    size = m->m_len;
639
640    if (size > 0) {
641      /* Now we have a not empty fragment */
642      break;
643    } else {
644      /* Discard empty fragments */
645      m = m_free( m);
646    }
647  }
648
649  /* Set fragment size */
650  *ctrl = SET_ETH_TX_CTRL_SIZE( 0, size - 1);
651
652  /* Discard empty successive fragments */
653  n = m->m_next;
654  while (n != NULL && n->m_len <= 0) {
655    n = m_free( n);
656  }
657  m->m_next = n;
658
659  /* Is our fragment the last in the frame? */
660  if (n == NULL) {
661    *ctrl = SET_FLAGS( *ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS);
662  }
663
664  return m;
665}
666
667static void lpc24xx_eth_transmit_task( void *arg)
668{
669  rtems_status_code sc = RTEMS_SUCCESSFUL;
670  rtems_event_set events = 0;
671  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg;
672  struct ifnet *ifp = &e->arpcom.ac_if;
673  volatile lpc24xx_eth_transfer_descriptor *const desc =
674    (volatile lpc24xx_eth_transfer_descriptor *)
675      LPC24XX_ETH_TRANSMIT_DESC_START;
676  volatile uint32_t *const status =
677    (volatile uint32_t *) LPC24XX_ETH_TRANSMIT_STATUS_START;
678  volatile char *const buf =
679    (volatile char *) LPC24XX_ETH_TRANSMIT_BUFFER_START;
680  struct mbuf *m = NULL;
681  uint32_t index_max = e->transmit_unit_number - 1;
682  uint32_t produce_index = 0;
683  uint32_t consume_index = 0;
684  uint32_t ctrl = 0;
685  uint32_t frame_length = 0;
686  char *frame_buffer = NULL;
687
688  LPC24XX_ETH_PRINTF( "%s\n", __func__);
689
690  /* Initialize descriptor table */
691  for (produce_index = 0; produce_index <= index_max; ++produce_index) {
692    desc [produce_index].start =
693      (uint32_t) (buf + produce_index * LPC24XX_ETH_TRANSMIT_BUFFER_SIZE);
694  }
695
696  /* Main event loop */
697  while (true) {
698    /* Wait for events */
699    sc = rtems_bsdnet_event_receive(
700      LPC24XX_ETH_EVENT_INITIALIZE
701        | LPC24XX_ETH_EVENT_START
702        | LPC24XX_ETH_EVENT_INTERRUPT,
703      RTEMS_EVENT_ANY | RTEMS_WAIT,
704      RTEMS_NO_TIMEOUT,
705      &events
706    );
707    RTEMS_CLEANUP_SC( sc, cleanup, "wait for events");
708
709    LPC24XX_ETH_PRINTF( "tx: wake up: 0x%08" PRIx32 "\n", events);
710
711    /* Initialize transmitter? */
712    if (IS_FLAG_SET( events, LPC24XX_ETH_EVENT_INITIALIZE)) {
713      /* Disable transmit interrupts */
714      lpc24xx_eth_disable_transmit_interrupts();
715
716      /* Disable transmitter */
717      MAC_COMMAND = CLEAR_FLAG( MAC_COMMAND, ETH_CMD_TX_ENABLE);
718
719      /* Wait for inactive status */
720      while (IS_FLAG_SET( MAC_STATUS, ETH_STAT_TX_ACTIVE)) {
721        /* Wait */
722      }
723
724      /* Reset */
725      MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_TX_RESET);
726
727      /* Clear transmit interrupts */
728      MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT;
729
730      /* Transmit descriptors */
731      MAC_TXDESCRIPTORNUM = index_max;
732      MAC_TXDESCRIPTOR = (uint32_t) desc;
733      MAC_TXSTATUS = (uint32_t) status;
734
735      /* Initialize indices */
736      produce_index = MAC_TXPRODUCEINDEX;
737      consume_index = MAC_TXCONSUMEINDEX;
738
739      /* Frame buffer start */
740      frame_buffer = (char *) desc [produce_index].start;
741
742      /* Enable transmitter */
743      MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_TX_ENABLE);
744    }
745
746    /* Free consumed fragments */
747    while (true) {
748      /* Save last known consume index */
749      uint32_t c = consume_index;
750
751      /* Clear transmit interrupt status */
752      MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT;
753
754      /* Get new consume index */
755      consume_index = MAC_TXCONSUMEINDEX;
756
757      /* Nothing consumed in the meantime? */
758      if (c == consume_index) {
759        break;
760      }
761
762      while (c != consume_index) {
763        uint32_t s = status [c];
764
765        /* Update error counters */
766        if (
767          IS_ANY_FLAG_SET( s, ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)
768        ) {
769          if (IS_FLAG_SET( s, ETH_TX_STAT_UNDERRUN)) {
770            ++e->transmit_underrun_errors;
771          }
772          if (IS_FLAG_SET( s, ETH_TX_STAT_LATE_COLLISION)) {
773            ++e->transmit_late_collision_errors;
774          }
775          if (IS_FLAG_SET( s, ETH_TX_STAT_EXCESSIVE_COLLISION)) {
776            ++e->transmit_excessive_collision_errors;
777          }
778          if (IS_FLAG_SET( s, ETH_TX_STAT_EXCESSIVE_DEFER)) {
779            ++e->transmit_excessive_defer_errors;
780          }
781          if (IS_FLAG_SET( s, ETH_TX_STAT_NO_DESCRIPTOR)) {
782            ++e->transmit_no_descriptor_errors;
783          }
784        }
785
786        /* Next consume index */
787        c = lpc24xx_eth_increment( c, index_max);
788      }
789    }
790
791    /* Transmit new fragments */
792    while (true) {
793      /* Compute next produce index */
794      uint32_t p = lpc24xx_eth_increment( produce_index, index_max);
795
796      /* Queue full? */
797      if (p == consume_index) {
798        /* The queue is full, wait for transmit interrupt */
799        break;
800      }
801
802      /* Get next fragment and control value */
803      m = lpc24xx_eth_next_fragment( ifp, m, &ctrl);
804
805      /* New fragment? */
806      if (m != NULL) {
807        size_t fragment_length = (size_t) m->m_len;
808        void *fragment_start = mtod( m, void *);
809        uint32_t new_frame_length = frame_length + fragment_length;
810
811        /* Check buffer size */
812        if (new_frame_length > LPC24XX_ETH_TRANSMIT_BUFFER_SIZE) {
813          LPC24XX_ETH_PRINTF( "tx: overflow\n");
814
815          /* Discard overflow data */
816          new_frame_length = LPC24XX_ETH_TRANSMIT_BUFFER_SIZE;
817          fragment_length = new_frame_length - frame_length;
818
819          /* Finalize frame */
820          ctrl = SET_FLAGS( ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS);
821
822          /* Update error counter */
823          ++e->transmit_overflow_errors;
824        }
825
826        LPC24XX_ETH_PRINTF(
827          "tx: copy: %" PRIu32 "%s%s\n",
828          fragment_length,
829          IS_FLAG_SET( m->m_flags, M_EXT) ? ", E" : "",
830          IS_FLAG_SET( m->m_flags, M_PKTHDR) ? ", H" : ""
831        );
832
833        /* Copy fragment to buffer in Ethernet RAM */
834        memcpy( frame_buffer, fragment_start, fragment_length);
835
836        if (IS_FLAG_SET( ctrl, ETH_TX_CTRL_LAST)) {
837          /* Finalize descriptor */
838          desc [produce_index].control =
839            SET_ETH_TX_CTRL_SIZE( ctrl, new_frame_length - 1);
840
841          LPC24XX_ETH_PRINTF( "tx: %02" PRIu32 ": %" PRIu32 "\n", produce_index, new_frame_length);
842
843          /* Next produce index */
844          produce_index = p;
845
846          /* Update the produce index */
847          MAC_TXPRODUCEINDEX = produce_index;
848
849          /* Reinitialize frame length and buffer start */
850          frame_length = 0;
851          frame_buffer = (char *) desc [produce_index].start;
852
853          /* Increment transmitted frames counter */
854          ++e->transmitted_frames;
855        } else {
856          /* New frame length */
857          frame_length = new_frame_length;
858
859          /* Update current frame buffer start */
860          frame_buffer += fragment_length;
861        }
862
863        /* Free mbuf and get next */
864        m = m_free( m);
865      } else {
866        /* Nothing to transmit */
867        break;
868      }
869    }
870
871    /* No more fragments? */
872    if (m == NULL) {
873      /* Interface is now inactive */
874      ifp->if_flags = CLEAR_FLAG( ifp->if_flags, IFF_OACTIVE);
875    } else {
876      /* Enable transmit interrupts */
877      lpc24xx_eth_enable_transmit_interrupts();
878    }
879  }
880
881cleanup:
882
883  /* Clear task ID */
884  e->transmit_task = RTEMS_ID_NONE;
885
886  /* Release network semaphore */
887  rtems_bsdnet_semaphore_release();
888
889  /* Terminate self */
890  (void) rtems_task_delete( RTEMS_SELF);
891}
892
893static void lpc24xx_eth_interface_init( void *arg)
894{
895  rtems_status_code sc = RTEMS_SUCCESSFUL;
896  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg;
897  struct ifnet *ifp = &e->arpcom.ac_if;
898
899  LPC24XX_ETH_PRINTF( "%s\n", __func__);
900
901  if (e->state == LPC24XX_ETH_INITIALIZED) {
902    #ifndef LPC24XX_HAS_UBOOT
903      /* Enable module power */
904      lpc24xx_module_enable(
905        LPC24XX_MODULE_ETHERNET,
906        0,
907        LPC24XX_MODULE_PCLK_DEFAULT
908      );
909
910      /* Module IO configuration */
911      #ifdef LPC24XX_ETHERNET_RMII
912        lpc24xx_io_config( LPC24XX_MODULE_ETHERNET, 0, 0);
913      #else
914        lpc24xx_io_config( LPC24XX_MODULE_ETHERNET, 0, 1);
915      #endif
916
917      /* Soft reset */
918
919      /* Do soft reset */
920      MAC_COMMAND = 0x38;
921      MAC_MAC1 = 0xcf00;
922
923      /* Initialize PHY */
924      /* TODO */
925
926      /* Reinitialize registers */
927      MAC_MAC2 = 0x31;
928      MAC_IPGT = 0x15;
929      MAC_IPGR = 0x12;
930      MAC_CLRT = 0x370f;
931      MAC_MAXF = 0x0600;
932      MAC_SUPP = 0x0100;
933      MAC_TEST = 0;
934      #ifdef LPC24XX_ETHERNET_RMII
935        MAC_COMMAND = 0x0400;
936      #else
937        MAC_COMMAND = 0x0600;
938      #endif
939      MAC_INTENABLE = 0;
940      MAC_INTCLEAR = 0x30ff;
941      MAC_POWERDOWN = 0;
942
943      /* MAC address */
944      MAC_SA0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8)
945        | (uint32_t) e->arpcom.ac_enaddr [4];
946      MAC_SA1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8)
947        | (uint32_t) e->arpcom.ac_enaddr [2];
948      MAC_SA2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8)
949        | (uint32_t) e->arpcom.ac_enaddr [0];
950
951      /* Enable receiver */
952      MAC_MAC1 = 0x03;
953    #else /* LPC24XX_HAS_UBOOT */
954      /* Reset receiver and transmitter */
955      MAC_COMMAND = SET_FLAGS(
956        MAC_COMMAND,
957        ETH_CMD_RX_RESET | ETH_CMD_TX_RESET | ETH_CMD_REG_RESET
958      );
959
960      /* MAC configuration */
961      MAC_MAC1 = 0x3;
962    #endif /* LPC24XX_HAS_UBOOT */
963
964    /* Start receive task */
965    if (e->receive_task == RTEMS_ID_NONE) {
966      e->receive_task = rtems_bsdnet_newproc(
967        "ntrx", 
968        4096, 
969        lpc24xx_eth_receive_task,
970        e
971      );
972      sc = rtems_event_send( e->receive_task, LPC24XX_ETH_EVENT_INITIALIZE);
973      RTEMS_SYSLOG_ERROR_SC( sc, "send receive initialize event");
974    }
975
976    /* Start transmit task */
977    if (e->transmit_task == RTEMS_ID_NONE) {
978      e->transmit_task = rtems_bsdnet_newproc(
979        "nttx", 
980        4096, 
981        lpc24xx_eth_transmit_task,
982        e
983      );
984      sc = rtems_event_send( e->transmit_task, LPC24XX_ETH_EVENT_INITIALIZE);
985      RTEMS_SYSLOG_ERROR_SC( sc, "send transmit initialize event");
986    }
987
988    /* Change state */
989    if (
990      e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE
991    ) {
992      e->state = LPC24XX_ETH_STARTED;
993    }
994  }
995
996  if (e->state == LPC24XX_ETH_STARTED) {
997    /* Enable fatal interrupts */
998    MAC_INTENABLE = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN;
999
1000    /* Enable promiscous mode */
1001    lpc24xx_eth_enable_promiscous_mode(
1002      IS_FLAG_SET( ifp->if_flags, IFF_PROMISC)
1003    );
1004
1005    /* Start watchdog timer */
1006    ifp->if_timer = 1;
1007
1008    /* Set interface to running state */
1009    ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_RUNNING);
1010
1011    /* Change state */
1012    e->state = LPC24XX_ETH_RUNNING;
1013  }
1014}
1015
1016static void lpc24xx_eth_interface_stats( const lpc24xx_eth_driver_entry *e)
1017{
1018  rtems_bsdnet_semaphore_release();
1019
1020  printf( "received frames:                     %u\n", e->received_frames);
1021  printf( "receive interrupts:                  %u\n", e->receive_interrupts);
1022  printf( "transmitted frames:                  %u\n", e->transmitted_frames);
1023  printf( "transmit interrupts:                 %u\n", e->transmit_interrupts);
1024  printf( "receive overrun errors:              %u\n", e->receive_overrun_errors);
1025  printf( "receive fragment errors:             %u\n", e->receive_fragment_errors);
1026  printf( "receive CRC errors:                  %u\n", e->receive_crc_errors);
1027  printf( "receive symbol errors:               %u\n", e->receive_symbol_errors);
1028  printf( "receive length errors:               %u\n", e->receive_length_errors);
1029  printf( "receive alignment errors:            %u\n", e->receive_alignment_errors);
1030  printf( "receive no descriptor errors:        %u\n", e->receive_no_descriptor_errors);
1031  printf( "receive fatal errors:                %u\n", e->receive_fatal_errors);
1032  printf( "transmit underrun errors:            %u\n", e->transmit_underrun_errors);
1033  printf( "transmit late collision errors:      %u\n", e->transmit_late_collision_errors);
1034  printf( "transmit excessive collision errors: %u\n", e->transmit_excessive_collision_errors);
1035  printf( "transmit excessive defer errors:     %u\n", e->transmit_excessive_defer_errors);
1036  printf( "transmit no descriptor errors:       %u\n", e->transmit_no_descriptor_errors);
1037  printf( "transmit overflow errors:            %u\n", e->transmit_overflow_errors);
1038  printf( "transmit fatal errors:               %u\n", e->transmit_fatal_errors);
1039
1040  rtems_bsdnet_semaphore_obtain();
1041}
1042
1043static int lpc24xx_eth_interface_ioctl(
1044  struct ifnet *ifp,
1045  ioctl_command_t command,
1046  caddr_t data
1047)
1048{
1049  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1050  int rv = 0;
1051
1052  LPC24XX_ETH_PRINTF( "%s\n", __func__);
1053
1054  switch (command)  {
1055    case SIOCGIFMEDIA:
1056    case SIOCSIFMEDIA:
1057      rtems_mii_ioctl( &e->mdio_info, e, (int) command, (int *) data);
1058      break;
1059    case SIOCGIFADDR:
1060    case SIOCSIFADDR:
1061      ether_ioctl( ifp, command, data);
1062      break;
1063    case SIOCSIFFLAGS:
1064      if (ifp->if_flags & IFF_RUNNING) {
1065        /* TODO: off */
1066      }
1067      if (ifp->if_flags & IFF_UP) {
1068        ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_RUNNING);
1069        /* TODO: init */
1070      }
1071      break;
1072    case SIO_RTEMS_SHOW_STATS:
1073      lpc24xx_eth_interface_stats( e);
1074      break;
1075    default:
1076      rv = EINVAL;
1077      break;
1078  }
1079
1080  return rv;
1081}
1082
1083static void lpc24xx_eth_interface_start( struct ifnet *ifp)
1084{
1085  rtems_status_code sc = RTEMS_SUCCESSFUL;
1086  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1087
1088  ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_OACTIVE);
1089
1090  sc = rtems_event_send( e->transmit_task, LPC24XX_ETH_EVENT_START);
1091  RTEMS_SYSLOG_ERROR_SC( sc, "send transmit start event");
1092}
1093
1094static void lpc24xx_eth_interface_watchdog( struct ifnet *ifp)
1095{
1096  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1097
1098  LPC24XX_ETH_PRINTF( "%s\n", __func__);
1099}
1100
1101static int lpc24xx_eth_attach( struct rtems_bsdnet_ifconfig *config)
1102{
1103  rtems_status_code sc = RTEMS_SUCCESSFUL;
1104  lpc24xx_eth_driver_entry *e = &lpc24xx_eth_driver_data;
1105  struct ifnet *ifp = &e->arpcom.ac_if;
1106  char *unit_name = NULL;
1107  int unit_number = rtems_bsdnet_parse_driver_name( config, &unit_name);
1108  uint32_t reg = 0;
1109
1110  /* Check parameter */
1111  if (unit_number < 0) {
1112    RTEMS_SYSLOG_ERROR( "parse error for interface name\n");
1113    return 0;
1114  }
1115  if (unit_number != 0) {
1116    RTEMS_DO_CLEANUP( cleanup, "unexpected unit number");
1117  }
1118  if (config->hardware_address == NULL) {
1119    RTEMS_DO_CLEANUP( cleanup, "MAC address missing");
1120  }
1121  if (e->state != LPC24XX_ETH_NOT_INITIALIZED) {
1122    RTEMS_DO_CLEANUP( cleanup, "already attached");
1123  }
1124
1125  /* Interrupt number */
1126  config->irno = LPC24XX_IRQ_ETHERNET;
1127
1128  /* Device control */
1129  config->drv_ctrl = e;
1130
1131  /* Receive unit number */
1132  if (
1133    config->rbuf_count <= 0
1134      || config->rbuf_count > LPC24XX_ETH_RECEIVE_UNIT_NUMBER
1135  ) {
1136    config->rbuf_count = LPC24XX_ETH_RECEIVE_UNIT_NUMBER;
1137  }
1138  e->receive_unit_number = (unsigned) config->rbuf_count;
1139
1140  /* Transmit unit number */
1141  if (
1142    config->xbuf_count <= 0
1143      || config->xbuf_count > LPC24XX_ETH_TRANSMIT_UNIT_NUMBER
1144  ) {
1145    config->xbuf_count = LPC24XX_ETH_TRANSMIT_UNIT_NUMBER;
1146  }
1147  e->transmit_unit_number = (unsigned) config->xbuf_count;
1148
1149  /* Disable interrupts */
1150  MAC_INTENABLE = 0;
1151
1152  /* Install interrupt handler */
1153  sc = rtems_interrupt_handler_install(
1154    config->irno,
1155    "Ethernet",
1156    RTEMS_INTERRUPT_UNIQUE,
1157    lpc24xx_eth_interrupt_handler,
1158    e
1159  );
1160  RTEMS_CLEANUP_SC( sc, cleanup, "install interrupt handler");
1161
1162  /* Copy MAC address */
1163  memcpy( e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1164
1165  /* Clear Ethernet RAM */
1166  memset( (void *) LPC24XX_ETH_RAM_START, 0, (size_t) LPC24XX_ETH_RAM_SIZE);
1167
1168  /* Set interface data */
1169  ifp->if_softc = e;
1170  ifp->if_unit = (short) unit_number;
1171  ifp->if_name = unit_name;
1172  ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU;
1173  ifp->if_init = lpc24xx_eth_interface_init;
1174  ifp->if_ioctl = lpc24xx_eth_interface_ioctl;
1175  ifp->if_start = lpc24xx_eth_interface_start;
1176  ifp->if_output = ether_output;
1177  ifp->if_watchdog = lpc24xx_eth_interface_watchdog;
1178  ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST;
1179  ifp->if_snd.ifq_maxlen = ifqmaxlen;
1180  ifp->if_timer = 0;
1181
1182  /* Change status */
1183  e->state = LPC24XX_ETH_INITIALIZED;
1184
1185  /* Attach the interface */
1186  if_attach( ifp);
1187  ether_ifattach( ifp);
1188
1189  return 1;
1190
1191cleanup:
1192
1193  /* FIXME: Type */
1194  free( unit_name, (int) 0xdeadbeef);
1195
1196  return 0;
1197}
1198
1199int lpc24xx_eth_attach_detach(
1200  struct rtems_bsdnet_ifconfig *config,
1201  int attaching
1202)
1203{
1204  /* FIXME: Return value */
1205
1206  if (attaching) {
1207    return lpc24xx_eth_attach( config);
1208  } else {
1209    /* TODO */
1210    return 0;
1211  }
1212}
Note: See TracBrowser for help on using the repository browser.