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

4.104.115
Last change on this file since ba938b8d was ba938b8d, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 09/18/09 at 08:05:40

Changes throughout.

  • Property mode set to 100644
File size: 32.2 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    /* Enable module power */
903    lpc24xx_module_enable(
904      LPC24XX_MODULE_ETHERNET,
905      0,
906      LPC24XX_MODULE_PCLK_DEFAULT
907    );
908
909    /* Module IO configuration */
910    #ifdef LPC24XX_ETHERNET_RMII
911        lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 0, 0);
912    #else
913        lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 0, 1);
914    #endif
915
916    /* Soft reset */
917
918    /* Do soft reset */
919    MAC_COMMAND = 0x38;
920    MAC_MAC1 = 0xcf00;
921
922    /* Initialize PHY */
923    /* TODO */
924
925    /* Reinitialize registers */
926    MAC_MAC2 = 0x31;
927    MAC_IPGT = 0x15;
928    MAC_IPGR = 0x12;
929    MAC_CLRT = 0x370f;
930    MAC_MAXF = 0x0600;
931    MAC_SUPP = 0x0100;
932    MAC_TEST = 0;
933    #ifdef LPC24XX_ETHERNET_RMII
934      MAC_COMMAND = 0x0400;
935    #else
936      MAC_COMMAND = 0x0600;
937    #endif
938    MAC_INTENABLE = 0;
939    MAC_INTCLEAR = 0x30ff;
940    MAC_POWERDOWN = 0;
941
942    /* MAC address */
943    MAC_SA0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8)
944      | (uint32_t) e->arpcom.ac_enaddr [4];
945    MAC_SA1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8)
946      | (uint32_t) e->arpcom.ac_enaddr [2];
947    MAC_SA2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8)
948      | (uint32_t) e->arpcom.ac_enaddr [0];
949
950    /* Enable receiver */
951    MAC_MAC1 = 0x03;
952
953    /* Start receive task */
954    if (e->receive_task == RTEMS_ID_NONE) {
955      e->receive_task = rtems_bsdnet_newproc(
956        "ntrx",
957        4096,
958        lpc24xx_eth_receive_task,
959        e
960      );
961      sc = rtems_event_send(e->receive_task, LPC24XX_ETH_EVENT_INITIALIZE);
962      RTEMS_SYSLOG_ERROR_SC(sc, "send receive initialize event");
963    }
964
965    /* Start transmit task */
966    if (e->transmit_task == RTEMS_ID_NONE) {
967      e->transmit_task = rtems_bsdnet_newproc(
968        "nttx",
969        4096,
970        lpc24xx_eth_transmit_task,
971        e
972      );
973      sc = rtems_event_send(e->transmit_task, LPC24XX_ETH_EVENT_INITIALIZE);
974      RTEMS_SYSLOG_ERROR_SC(sc, "send transmit initialize event");
975    }
976
977    /* Change state */
978    if (
979      e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE
980    ) {
981      e->state = LPC24XX_ETH_STARTED;
982    }
983  }
984
985  if (e->state == LPC24XX_ETH_STARTED) {
986    /* Enable fatal interrupts */
987    MAC_INTENABLE = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN;
988
989    /* Enable promiscous mode */
990    lpc24xx_eth_enable_promiscous_mode(
991      IS_FLAG_SET(ifp->if_flags, IFF_PROMISC)
992    );
993
994    /* Start watchdog timer */
995    ifp->if_timer = 1;
996
997    /* Set interface to running state */
998    ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING);
999
1000    /* Change state */
1001    e->state = LPC24XX_ETH_RUNNING;
1002  }
1003}
1004
1005static void lpc24xx_eth_interface_stats(const lpc24xx_eth_driver_entry *e)
1006{
1007  rtems_bsdnet_semaphore_release();
1008
1009  printf("received frames:                     %u\n", e->received_frames);
1010  printf("receive interrupts:                  %u\n", e->receive_interrupts);
1011  printf("transmitted frames:                  %u\n", e->transmitted_frames);
1012  printf("transmit interrupts:                 %u\n", e->transmit_interrupts);
1013  printf("receive overrun errors:              %u\n", e->receive_overrun_errors);
1014  printf("receive fragment errors:             %u\n", e->receive_fragment_errors);
1015  printf("receive CRC errors:                  %u\n", e->receive_crc_errors);
1016  printf("receive symbol errors:               %u\n", e->receive_symbol_errors);
1017  printf("receive length errors:               %u\n", e->receive_length_errors);
1018  printf("receive alignment errors:            %u\n", e->receive_alignment_errors);
1019  printf("receive no descriptor errors:        %u\n", e->receive_no_descriptor_errors);
1020  printf("receive fatal errors:                %u\n", e->receive_fatal_errors);
1021  printf("transmit underrun errors:            %u\n", e->transmit_underrun_errors);
1022  printf("transmit late collision errors:      %u\n", e->transmit_late_collision_errors);
1023  printf("transmit excessive collision errors: %u\n", e->transmit_excessive_collision_errors);
1024  printf("transmit excessive defer errors:     %u\n", e->transmit_excessive_defer_errors);
1025  printf("transmit no descriptor errors:       %u\n", e->transmit_no_descriptor_errors);
1026  printf("transmit overflow errors:            %u\n", e->transmit_overflow_errors);
1027  printf("transmit fatal errors:               %u\n", e->transmit_fatal_errors);
1028
1029  rtems_bsdnet_semaphore_obtain();
1030}
1031
1032static int lpc24xx_eth_interface_ioctl(
1033  struct ifnet *ifp,
1034  ioctl_command_t command,
1035  caddr_t data
1036)
1037{
1038  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1039  int rv = 0;
1040
1041  LPC24XX_ETH_PRINTF("%s\n", __func__);
1042
1043  switch (command)  {
1044    case SIOCGIFMEDIA:
1045    case SIOCSIFMEDIA:
1046      rtems_mii_ioctl(&e->mdio_info, e, (int) command, (int *) data);
1047      break;
1048    case SIOCGIFADDR:
1049    case SIOCSIFADDR:
1050      ether_ioctl(ifp, command, data);
1051      break;
1052    case SIOCSIFFLAGS:
1053      if (ifp->if_flags & IFF_RUNNING) {
1054        /* TODO: off */
1055      }
1056      if (ifp->if_flags & IFF_UP) {
1057        ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING);
1058        /* TODO: init */
1059      }
1060      break;
1061    case SIO_RTEMS_SHOW_STATS:
1062      lpc24xx_eth_interface_stats(e);
1063      break;
1064    default:
1065      rv = EINVAL;
1066      break;
1067  }
1068
1069  return rv;
1070}
1071
1072static void lpc24xx_eth_interface_start(struct ifnet *ifp)
1073{
1074  rtems_status_code sc = RTEMS_SUCCESSFUL;
1075  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1076
1077  ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_OACTIVE);
1078
1079  sc = rtems_event_send(e->transmit_task, LPC24XX_ETH_EVENT_START);
1080  RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event");
1081}
1082
1083static void lpc24xx_eth_interface_watchdog(struct ifnet *ifp)
1084{
1085  lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc;
1086
1087  LPC24XX_ETH_PRINTF("%s\n", __func__);
1088}
1089
1090static int lpc24xx_eth_attach(struct rtems_bsdnet_ifconfig *config)
1091{
1092  rtems_status_code sc = RTEMS_SUCCESSFUL;
1093  lpc24xx_eth_driver_entry *e = &lpc24xx_eth_driver_data;
1094  struct ifnet *ifp = &e->arpcom.ac_if;
1095  char *unit_name = NULL;
1096  int unit_number = rtems_bsdnet_parse_driver_name(config, &unit_name);
1097  uint32_t reg = 0;
1098
1099  /* Check parameter */
1100  if (unit_number < 0) {
1101    RTEMS_SYSLOG_ERROR("parse error for interface name\n");
1102    return 0;
1103  }
1104  if (unit_number != 0) {
1105    RTEMS_DO_CLEANUP(cleanup, "unexpected unit number");
1106  }
1107  if (config->hardware_address == NULL) {
1108    RTEMS_DO_CLEANUP(cleanup, "MAC address missing");
1109  }
1110  if (e->state != LPC24XX_ETH_NOT_INITIALIZED) {
1111    RTEMS_DO_CLEANUP(cleanup, "already attached");
1112  }
1113
1114  /* Interrupt number */
1115  config->irno = LPC24XX_IRQ_ETHERNET;
1116
1117  /* Device control */
1118  config->drv_ctrl = e;
1119
1120  /* Receive unit number */
1121  if (
1122    config->rbuf_count <= 0
1123      || config->rbuf_count > LPC24XX_ETH_RECEIVE_UNIT_NUMBER
1124  ) {
1125    config->rbuf_count = LPC24XX_ETH_RECEIVE_UNIT_NUMBER;
1126  }
1127  e->receive_unit_number = (unsigned) config->rbuf_count;
1128
1129  /* Transmit unit number */
1130  if (
1131    config->xbuf_count <= 0
1132      || config->xbuf_count > LPC24XX_ETH_TRANSMIT_UNIT_NUMBER
1133  ) {
1134    config->xbuf_count = LPC24XX_ETH_TRANSMIT_UNIT_NUMBER;
1135  }
1136  e->transmit_unit_number = (unsigned) config->xbuf_count;
1137
1138  /* Disable interrupts */
1139  MAC_INTENABLE = 0;
1140
1141  /* Install interrupt handler */
1142  sc = rtems_interrupt_handler_install(
1143    config->irno,
1144    "Ethernet",
1145    RTEMS_INTERRUPT_UNIQUE,
1146    lpc24xx_eth_interrupt_handler,
1147    e
1148  );
1149  RTEMS_CLEANUP_SC(sc, cleanup, "install interrupt handler");
1150
1151  /* Copy MAC address */
1152  memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1153
1154  /* Clear Ethernet RAM */
1155  memset((void *) LPC24XX_ETH_RAM_START, 0, (size_t) LPC24XX_ETH_RAM_SIZE);
1156
1157  /* Set interface data */
1158  ifp->if_softc = e;
1159  ifp->if_unit = (short) unit_number;
1160  ifp->if_name = unit_name;
1161  ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU;
1162  ifp->if_init = lpc24xx_eth_interface_init;
1163  ifp->if_ioctl = lpc24xx_eth_interface_ioctl;
1164  ifp->if_start = lpc24xx_eth_interface_start;
1165  ifp->if_output = ether_output;
1166  ifp->if_watchdog = lpc24xx_eth_interface_watchdog;
1167  ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST;
1168  ifp->if_snd.ifq_maxlen = ifqmaxlen;
1169  ifp->if_timer = 0;
1170
1171  /* Change status */
1172  e->state = LPC24XX_ETH_INITIALIZED;
1173
1174  /* Attach the interface */
1175  if_attach(ifp);
1176  ether_ifattach(ifp);
1177
1178  return 1;
1179
1180cleanup:
1181
1182  /* FIXME: Type */
1183  free(unit_name, (int) 0xdeadbeef);
1184
1185  return 0;
1186}
1187
1188static int lpc24xx_eth_detach(struct rtems_bsdnet_ifconfig *config)
1189{
1190  /* FIXME: Detach the interface from the upper layers? */
1191
1192  /* Module soft reset */
1193  MAC_COMMAND = 0x38;
1194  MAC_MAC1 = 0xcf00;
1195
1196  /* FIXME: More cleanup */
1197
1198  return 0;
1199}
1200
1201int lpc24xx_eth_attach_detach(
1202  struct rtems_bsdnet_ifconfig *config,
1203  int attaching
1204)
1205{
1206  /* FIXME: Return value */
1207
1208  if (attaching) {
1209    return lpc24xx_eth_attach(config);
1210  } else {
1211    return lpc24xx_eth_detach(config);
1212  }
1213}
Note: See TracBrowser for help on using the repository browser.