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

4.104.115
Last change on this file since 949166d was 949166d, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 02/27/09 at 12:12:08

added missing files

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