source: rtems/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c @ c193baad

4.104.11
Last change on this file since c193baad was c193baad, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Apr 9, 2010 at 8:24:57 PM

unify irq data types and code, merge s3c2400/s3c2410 support

  • Property mode set to 100644
File size: 37.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc_eth
5 *
6 * @brief Ethernet driver.
7 */
8
9/*
10 * Copyright (c) 2009
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
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
23#define __BSD_VISIBLE 1
24
25#include <errno.h>
26#include <inttypes.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
31#include <rtems.h>
32#include <rtems/rtems_bsdnet.h>
33#include <rtems/rtems_mii_ioctl.h>
34
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <sys/sockio.h>
38#include <sys/mbuf.h>
39
40#include <net/if.h>
41#include <net/if_arp.h>
42#include <netinet/in.h>
43#include <netinet/if_ether.h>
44#include <netinet/in_systm.h>
45#include <netinet/ip.h>
46
47#include <bsp.h>
48#include <bsp/irq.h>
49#include <bsp/lpc-ethernet-config.h>
50
51#include <rtems/status-checks.h>
52
53#if MCLBYTES > (2 * 1024)
54  #error "MCLBYTES to large"
55#endif
56
57#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
58  #define LPC_ETH_CONFIG_TX_BUF_SIZE sizeof(struct mbuf *)
59#else
60  #define LPC_ETH_CONFIG_TX_BUF_SIZE 1518U
61#endif
62
63typedef struct {
64  uint32_t start;
65  uint32_t control;
66} lpc_eth_transfer_descriptor;
67
68typedef struct {
69  uint32_t info;
70  uint32_t hash_crc;
71} lpc_eth_receive_status;
72
73typedef struct {
74  uint32_t mac1;
75  uint32_t mac2;
76  uint32_t ipgt;
77  uint32_t ipgr;
78  uint32_t clrt;
79  uint32_t maxf;
80  uint32_t supp;
81  uint32_t test;
82  uint32_t mcfg;
83  uint32_t mcmd;
84  uint32_t madr;
85  uint32_t mwtd;
86  uint32_t mrdd;
87  uint32_t mind;
88  uint32_t reserved_0 [2];
89  uint32_t sa0;
90  uint32_t sa1;
91  uint32_t sa2;
92  uint32_t reserved_1 [45];
93  uint32_t command;
94  uint32_t status;
95  uint32_t rxdescriptor;
96  uint32_t rxstatus;
97  uint32_t rxdescriptornum;
98  uint32_t rxproduceindex;
99  uint32_t rxconsumeindex;
100  uint32_t txdescriptor;
101  uint32_t txstatus;
102  uint32_t txdescriptornum;
103  uint32_t txproduceindex;
104  uint32_t txconsumeindex;
105  uint32_t reserved_2 [10];
106  uint32_t tsv0;
107  uint32_t tsv1;
108  uint32_t rsv;
109  uint32_t reserved_3 [3];
110  uint32_t flowcontrolcnt;
111  uint32_t flowcontrolsts;
112  uint32_t reserved_4 [34];
113  uint32_t rxfilterctrl;
114  uint32_t rxfilterwolsts;
115  uint32_t rxfilterwolclr;
116  uint32_t reserved_5 [1];
117  uint32_t hashfilterl;
118  uint32_t hashfilterh;
119  uint32_t reserved_6 [882];
120  uint32_t intstatus;
121  uint32_t intenable;
122  uint32_t intclear;
123  uint32_t intset;
124  uint32_t reserved_7 [1];
125  uint32_t powerdown;
126} lpc_eth_controller;
127
128static volatile lpc_eth_controller *const lpc_eth = 
129  (volatile lpc_eth_controller *) LPC_ETH_CONFIG_REG_BASE;
130
131/* ETH_RX_CTRL */
132
133#define ETH_RX_CTRL_SIZE_MASK 0x000007ffU
134#define ETH_RX_CTRL_INTERRUPT 0x80000000U
135
136/* ETH_RX_STAT */
137
138#define ETH_RX_STAT_RXSIZE_MASK 0x000007ffU
139#define ETH_RX_STAT_BYTES 0x00000100U
140#define ETH_RX_STAT_CONTROL_FRAME 0x00040000U
141#define ETH_RX_STAT_VLAN 0x00080000U
142#define ETH_RX_STAT_FAIL_FILTER 0x00100000U
143#define ETH_RX_STAT_MULTICAST 0x00200000U
144#define ETH_RX_STAT_BROADCAST 0x00400000U
145#define ETH_RX_STAT_CRC_ERROR 0x00800000U
146#define ETH_RX_STAT_SYMBOL_ERROR 0x01000000U
147#define ETH_RX_STAT_LENGTH_ERROR 0x02000000U
148#define ETH_RX_STAT_RANGE_ERROR 0x04000000U
149#define ETH_RX_STAT_ALIGNMENT_ERROR 0x08000000U
150#define ETH_RX_STAT_OVERRUN 0x10000000U
151#define ETH_RX_STAT_NO_DESCRIPTOR 0x20000000U
152#define ETH_RX_STAT_LAST_FLAG 0x40000000U
153#define ETH_RX_STAT_ERROR 0x80000000U
154
155/* ETH_TX_CTRL */
156
157#define ETH_TX_CTRL_SIZE_MASK 0x7ffU
158#define ETH_TX_CTRL_SIZE_SHIFT 0
159#define ETH_TX_CTRL_OVERRIDE 0x04000000U
160#define ETH_TX_CTRL_HUGE 0x08000000U
161#define ETH_TX_CTRL_PAD 0x10000000U
162#define ETH_TX_CTRL_CRC 0x20000000U
163#define ETH_TX_CTRL_LAST 0x40000000U
164#define ETH_TX_CTRL_INTERRUPT 0x80000000U
165
166/* ETH_TX_STAT */
167
168#define ETH_TX_STAT_COLLISION_COUNT_MASK 0x01e00000U
169#define ETH_TX_STAT_DEFER 0x02000000U
170#define ETH_TX_STAT_EXCESSIVE_DEFER 0x04000000U
171#define ETH_TX_STAT_EXCESSIVE_COLLISION 0x08000000U
172#define ETH_TX_STAT_LATE_COLLISION 0x10000000U
173#define ETH_TX_STAT_UNDERRUN 0x20000000U
174#define ETH_TX_STAT_NO_DESCRIPTOR 0x40000000U
175#define ETH_TX_STAT_ERROR 0x80000000U
176
177/* ETH_INT */
178
179#define ETH_INT_RX_OVERRUN 0x00000001U
180#define ETH_INT_RX_ERROR 0x00000002U
181#define ETH_INT_RX_FINISHED 0x00000004U
182#define ETH_INT_RX_DONE 0x00000008U
183#define ETH_INT_TX_UNDERRUN 0x00000010U
184#define ETH_INT_TX_ERROR 0x00000020U
185#define ETH_INT_TX_FINISHED 0x00000040U
186#define ETH_INT_TX_DONE 0x00000080U
187#define ETH_INT_SOFT 0x00001000U
188#define ETH_INT_WAKEUP 0x00002000U
189
190/* ETH_RX_FIL_CTRL */
191
192#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST 0x00000001U
193#define ETH_RX_FIL_CTRL_ACCEPT_BROADCAST 0x00000002U
194#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST 0x00000004U
195#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST_HASH 0x00000008U
196#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH 0x00000010U
197#define ETH_RX_FIL_CTRL_ACCEPT_PERFECT 0x00000020U
198#define ETH_RX_FIL_CTRL_MAGIC_PACKET_WOL 0x00001000U
199#define ETH_RX_FIL_CTRL_RX_FILTER_WOL 0x00002000U
200
201/* ETH_CMD */
202
203#define ETH_CMD_RX_ENABLE 0x00000001U
204#define ETH_CMD_TX_ENABLE 0x00000002U
205#define ETH_CMD_REG_RESET 0x00000008U
206#define ETH_CMD_TX_RESET 0x00000010U
207#define ETH_CMD_RX_RESET 0x00000020U
208#define ETH_CMD_PASS_RUNT_FRAME 0x00000040U
209#define ETH_CMD_PASS_RX_FILTER 0X00000080U
210#define ETH_CMD_TX_FLOW_CONTROL 0x00000100U
211#define ETH_CMD_RMII 0x00000200U
212#define ETH_CMD_FULL_DUPLEX 0x00000400U
213
214/* ETH_STAT */
215
216#define ETH_STAT_RX_ACTIVE 0x00000001U
217#define ETH_STAT_TX_ACTIVE 0x00000002U
218
219/* Events */
220
221#define LPC_ETH_EVENT_INITIALIZE RTEMS_EVENT_1
222
223#define LPC_ETH_EVENT_START RTEMS_EVENT_2
224
225#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3
226
227/* Status */
228
229#define LPC_ETH_INTERRUPT_RECEIVE \
230  (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE)
231
232#define LPC_ETH_INTERRUPT_TRANSMIT \
233  (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR)
234
235#define LPC_ETH_RX_STAT_ERRORS \
236  (ETH_RX_STAT_CRC_ERROR \
237    | ETH_RX_STAT_SYMBOL_ERROR \
238    | ETH_RX_STAT_LENGTH_ERROR \
239    | ETH_RX_STAT_ALIGNMENT_ERROR \
240    | ETH_RX_STAT_OVERRUN \
241    | ETH_RX_STAT_NO_DESCRIPTOR)
242
243#define LPC_ETH_LAST_FRAGMENT_FLAGS \
244  (ETH_TX_CTRL_OVERRIDE \
245    | ETH_TX_CTRL_PAD \
246    | ETH_TX_CTRL_CRC \
247    | ETH_TX_CTRL_INTERRUPT \
248    | ETH_TX_CTRL_LAST)
249
250/* Debug */
251
252#ifdef DEBUG
253  #define LPC_ETH_PRINTF(...) printf(__VA_ARGS__)
254  #define LPC_ETH_PRINTK(...) printk(__VA_ARGS__)
255#else
256  #define LPC_ETH_PRINTF(...)
257  #define LPC_ETH_PRINTK(...)
258#endif
259
260typedef enum {
261  LPC_ETH_NOT_INITIALIZED,
262  LPC_ETH_INITIALIZED,
263  LPC_ETH_STARTED,
264  LPC_ETH_RUNNING
265} lpc_eth_state;
266
267typedef struct {
268  struct arpcom arpcom;
269  struct rtems_mdio_info mdio_info;
270  lpc_eth_state state;
271  rtems_id receive_task;
272  rtems_id transmit_task;
273  unsigned rx_unit_count;
274  unsigned tx_unit_count;
275  volatile lpc_eth_transfer_descriptor *rx_desc_table;
276  volatile lpc_eth_receive_status *rx_status_table;
277  struct mbuf **rx_mbuf_table;
278  volatile lpc_eth_transfer_descriptor *tx_desc_table;
279  volatile uint32_t *tx_status_table;
280  void *tx_buf_table;
281  unsigned received_frames;
282  unsigned receive_interrupts;
283  unsigned transmitted_frames;
284  unsigned transmit_interrupts;
285  unsigned receive_overrun_errors;
286  unsigned receive_fragment_errors;
287  unsigned receive_crc_errors;
288  unsigned receive_symbol_errors;
289  unsigned receive_length_errors;
290  unsigned receive_alignment_errors;
291  unsigned receive_no_descriptor_errors;
292  unsigned receive_fatal_errors;
293  unsigned transmit_underrun_errors;
294  unsigned transmit_late_collision_errors;
295  unsigned transmit_excessive_collision_errors;
296  unsigned transmit_excessive_defer_errors;
297  unsigned transmit_no_descriptor_errors;
298  unsigned transmit_overflow_errors;
299  unsigned transmit_fatal_errors;
300} lpc_eth_driver_entry;
301
302static lpc_eth_driver_entry lpc_eth_driver_data = {
303  .state = LPC_ETH_NOT_INITIALIZED,
304  .receive_task = RTEMS_ID_NONE,
305  .transmit_task = RTEMS_ID_NONE
306};
307
308static inline uint32_t lpc_eth_increment(
309  uint32_t value,
310  uint32_t cycle
311)
312{
313  if (value < cycle) {
314    return ++value;
315  } else {
316    return 0;
317  }
318}
319
320static void lpc_eth_enable_promiscous_mode(bool enable)
321{
322  if (enable) {
323    lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_PERFECT
324      | ETH_RX_FIL_CTRL_ACCEPT_UNICAST
325      | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST
326      | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
327  } else {
328    lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_PERFECT
329      | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
330  }
331}
332
333static void lpc_eth_interrupt_handler(void *arg)
334{
335  lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg;
336  rtems_event_set re = 0;
337  rtems_event_set te = 0;
338  uint32_t ie = 0;
339
340  /* Get interrupt status */
341  uint32_t im = lpc_eth->intenable;
342  uint32_t is = lpc_eth->intstatus & im;
343
344  /* Check receive interrupts */
345  if ((is & ETH_INT_RX_OVERRUN) != 0) {
346    re = LPC_ETH_EVENT_INITIALIZE;
347    ++e->receive_fatal_errors;
348  } else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) {
349    re = LPC_ETH_EVENT_INTERRUPT;
350    ie |= LPC_ETH_INTERRUPT_RECEIVE;
351  }
352
353  /* Send events to receive task */
354  if (re != 0) {
355    ++e->receive_interrupts;
356    (void) rtems_event_send(e->receive_task, re);
357  }
358
359  /* Check transmit interrupts */
360  if ((is & ETH_INT_TX_UNDERRUN) != 0) {
361    te = LPC_ETH_EVENT_INITIALIZE;
362    ++e->transmit_fatal_errors;
363  } else if ((is & LPC_ETH_INTERRUPT_TRANSMIT) != 0) {
364    te = LPC_ETH_EVENT_INTERRUPT;
365    ie |= LPC_ETH_INTERRUPT_TRANSMIT;
366  }
367
368  /* Send events to transmit task */
369  if (te != 0) {
370    ++e->transmit_interrupts;
371    (void) rtems_event_send(e->transmit_task, te);
372  }
373
374  LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te);
375
376  /* Update interrupt mask */
377  lpc_eth->intenable = im & ~ie;
378
379  /* Clear interrupts */
380  lpc_eth->intclear = is;
381}
382
383static void lpc_eth_enable_receive_interrupts(void)
384{
385  rtems_interrupt_level level;
386
387  rtems_interrupt_disable(level);
388  lpc_eth->intenable |= LPC_ETH_INTERRUPT_RECEIVE;
389  rtems_interrupt_enable(level);
390}
391
392static void lpc_eth_disable_receive_interrupts(void)
393{
394  rtems_interrupt_level level;
395
396  rtems_interrupt_disable(level);
397  lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_RECEIVE;
398  rtems_interrupt_enable(level);
399}
400
401static void lpc_eth_enable_transmit_interrupts(void)
402{
403  rtems_interrupt_level level;
404
405  rtems_interrupt_disable(level);
406  lpc_eth->intenable |= LPC_ETH_INTERRUPT_TRANSMIT;
407  rtems_interrupt_enable(level);
408}
409
410static void lpc_eth_disable_transmit_interrupts(void)
411{
412  rtems_interrupt_level level;
413
414  rtems_interrupt_disable(level);
415  lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_TRANSMIT;
416  rtems_interrupt_enable(level);
417}
418
419#define LPC_ETH_RX_DATA_OFFSET 2
420
421static struct mbuf *lpc_eth_new_mbuf(struct ifnet *ifp, bool wait)
422{
423  struct mbuf *m = NULL;
424  int mw = wait ? M_WAIT : M_DONTWAIT;
425
426  MGETHDR(m, mw, MT_DATA);
427  if (m != NULL) {
428    MCLGET(m, mw);
429    if ((m->m_flags & M_EXT) != 0) {
430      /* Set receive interface */
431      m->m_pkthdr.rcvif = ifp;
432
433      /* Adjust by two bytes for proper IP header alignment */
434      m->m_data = mtod(m, char *) + LPC_ETH_RX_DATA_OFFSET;
435
436      return m;
437    } else {
438      m_free(m);
439    }
440  }
441
442  return NULL;
443}
444
445static bool lpc_eth_add_new_mbuf(
446  struct ifnet *ifp,
447  volatile lpc_eth_transfer_descriptor *desc,
448  struct mbuf **mbufs,
449  uint32_t i,
450  bool wait
451)
452{
453  /* New mbuf */
454  struct mbuf *m = lpc_eth_new_mbuf(ifp, wait);
455
456  /* Check mbuf */
457  if (m != NULL) {
458    /* Cache invalidate */
459    rtems_cache_invalidate_multiple_data_lines(
460      mtod(m, void *),
461      MCLBYTES - LPC_ETH_RX_DATA_OFFSET
462    );
463
464    /* Add mbuf to queue */
465    desc [i].start = mtod(m, uint32_t);
466    desc [i].control = (MCLBYTES - LPC_ETH_RX_DATA_OFFSET - 1)
467      | ETH_RX_CTRL_INTERRUPT;
468
469    /* Cache flush of descriptor  */
470    rtems_cache_flush_multiple_data_lines((void *)&desc [i], 
471                                          sizeof(desc [0]));
472
473    /* Add mbuf to table */
474    mbufs [i] = m;
475
476    return true;
477  } else {
478    return false;
479  }
480}
481
482static void lpc_eth_receive_task(void *arg)
483{
484  rtems_status_code sc = RTEMS_SUCCESSFUL;
485  rtems_event_set events = 0;
486  lpc_eth_driver_entry *const e = (lpc_eth_driver_entry *) arg;
487  struct ifnet *const ifp = &e->arpcom.ac_if;
488  volatile lpc_eth_transfer_descriptor *const desc = e->rx_desc_table;
489  volatile lpc_eth_receive_status *const status = e->rx_status_table;
490  struct mbuf **const mbufs = e->rx_mbuf_table;
491  uint32_t const index_max = e->rx_unit_count - 1;
492  uint32_t produce_index = 0;
493  uint32_t consume_index = 0;
494  uint32_t receive_index = 0;
495
496  LPC_ETH_PRINTF("%s\n", __func__);
497
498  /* Main event loop */
499  while (true) {
500    bool wait_for_mbuf = false;
501
502    /* Wait for events */
503    sc = rtems_bsdnet_event_receive(
504      LPC_ETH_EVENT_INITIALIZE | LPC_ETH_EVENT_INTERRUPT,
505      RTEMS_EVENT_ANY | RTEMS_WAIT,
506      RTEMS_NO_TIMEOUT,
507      &events
508    );
509    RTEMS_CLEANUP_SC(sc, cleanup, "wait for events");
510
511    LPC_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events);
512
513    /* Initialize receiver? */
514    if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
515      /* Disable receive interrupts */
516      lpc_eth_disable_receive_interrupts();
517
518      /* Disable receiver */
519      lpc_eth->command &= ~ETH_CMD_RX_ENABLE;
520
521      /* Wait for inactive status */
522      while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) {
523        /* Wait */
524      }
525
526      /* Reset */
527      lpc_eth->command |= ETH_CMD_RX_RESET;
528
529      /* Clear receive interrupts */
530      lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE;
531
532      /* Move existing mbufs to the front */
533      consume_index = 0;
534      for (produce_index = 0; produce_index <= index_max; ++produce_index) {
535        if (mbufs [produce_index] != NULL) {
536          mbufs [consume_index] = mbufs [produce_index];
537          ++consume_index;
538        }
539      }
540
541      /* Fill receive queue */
542      for (
543        produce_index = consume_index;
544        produce_index <= index_max;
545        ++produce_index
546      ) {
547        lpc_eth_add_new_mbuf(ifp, desc, mbufs, produce_index, true);
548      }
549
550      /* Receive descriptor table */
551      lpc_eth->rxdescriptornum = index_max;
552      lpc_eth->rxdescriptor = (uint32_t) desc;
553      lpc_eth->rxstatus = (uint32_t) status;
554
555      /* Initialize indices */
556      produce_index = lpc_eth->rxproduceindex;
557      consume_index = lpc_eth->rxconsumeindex;
558      receive_index = consume_index;
559
560      /* Enable receiver */
561      lpc_eth->command |= ETH_CMD_RX_ENABLE;
562
563      /* Enable receive interrupts */
564      lpc_eth_enable_receive_interrupts();
565
566      /* Wait for events */
567      continue;
568    }
569
570    while (true) {
571      /* Clear receive interrupt status */
572      lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE;
573
574      /* Get current produce index */
575      produce_index = lpc_eth->rxproduceindex;
576
577      if (receive_index != produce_index) {
578        uint32_t stat = 0;
579
580        /* Fragment mbuf */
581        struct mbuf *m = mbufs [receive_index];
582
583        /* Fragment status */
584        rtems_cache_invalidate_multiple_data_lines
585          ((void *)&status [receive_index],
586           sizeof(status [0])
587           );
588        stat = status [receive_index].info;
589
590        /* Remove mbuf from table */
591        mbufs [receive_index] = NULL;
592
593        if (
594          (stat & ETH_RX_STAT_LAST_FLAG) != 0
595            && (stat & LPC_ETH_RX_STAT_ERRORS) == 0
596        ) {
597          /* Ethernet header */
598          struct ether_header *eh = mtod(m, struct ether_header *);
599
600          /* Discard Ethernet header and CRC */
601          int sz = (int) (stat & ETH_RX_STAT_RXSIZE_MASK) + 1
602            - ETHER_HDR_LEN - ETHER_CRC_LEN;
603
604          /* Update mbuf */
605          m->m_len = sz;
606          m->m_pkthdr.len = sz;
607          m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
608
609          LPC_ETH_PRINTF("rx: %02" PRIu32 ": %u\n", receive_index, sz);
610
611          /* Hand over */
612          ether_input(ifp, eh, m);
613
614          /* Increment received frames counter */
615          ++e->received_frames;
616        } else {
617          /* Release mbuf */
618          m_free(m);
619
620          /* Update error counters */
621          if ((stat & ETH_RX_STAT_OVERRUN) != 0) {
622            ++e->receive_overrun_errors;
623          }
624          if ((stat & ETH_RX_STAT_LAST_FLAG) == 0) {
625            ++e->receive_fragment_errors;
626          }
627          if ((stat & ETH_RX_STAT_CRC_ERROR) != 0) {
628            ++e->receive_crc_errors;
629          }
630          if ((stat & ETH_RX_STAT_SYMBOL_ERROR) != 0) {
631            ++e->receive_symbol_errors;
632          }
633          if ((stat & ETH_RX_STAT_LENGTH_ERROR) != 0) {
634            ++e->receive_length_errors;
635          }
636          if ((stat & ETH_RX_STAT_ALIGNMENT_ERROR) != 0) {
637            ++e->receive_alignment_errors;
638          }
639          if ((stat & ETH_RX_STAT_NO_DESCRIPTOR) != 0) {
640            ++e->receive_no_descriptor_errors;
641          }
642        }
643
644        /* Increment receive index */
645        receive_index = lpc_eth_increment(receive_index, index_max);
646      } else {
647        /* Nothing to do, enable receive interrupts */
648        lpc_eth_enable_receive_interrupts();
649        break;
650      }
651    }
652
653    /* Wait for mbuf? */
654    wait_for_mbuf =
655      lpc_eth_increment(produce_index, index_max) == consume_index;
656
657    /* Fill queue with new mbufs */
658    while (consume_index != produce_index) {
659      /* Add new mbuf to queue */
660      if (
661        !lpc_eth_add_new_mbuf(ifp, desc, mbufs, consume_index, wait_for_mbuf)
662      ) {
663        break;
664      }
665
666      /* We wait for at most one mbuf */
667      wait_for_mbuf = false;
668
669      /* Increment consume index */
670      consume_index = lpc_eth_increment(consume_index, index_max);
671
672      /* Update consume indices */
673      lpc_eth->rxconsumeindex = consume_index;
674    }
675  }
676
677cleanup:
678
679  /* Clear task ID */
680  e->receive_task = RTEMS_ID_NONE;
681
682  /* Release network semaphore */
683  rtems_bsdnet_semaphore_release();
684
685  /* Terminate self */
686  (void) rtems_task_delete(RTEMS_SELF);
687}
688
689static struct mbuf *lpc_eth_next_fragment(
690  struct ifnet *ifp,
691  struct mbuf *m,
692  uint32_t *ctrl
693)
694{
695  struct mbuf *n = NULL;
696  int size = 0;
697
698  while (true) {
699    if (m == NULL) {
700      /* Dequeue first fragment of the next frame */
701      IF_DEQUEUE(&ifp->if_snd, m);
702
703      /* Empty queue? */
704      if (m == NULL) {
705        return m;
706      }
707    }
708
709    /* Get fragment size */
710    size = m->m_len;
711
712    if (size > 0) {
713      /* Now we have a not empty fragment */
714      break;
715    } else {
716      /* Discard empty fragments */
717      m = m_free(m);
718    }
719  }
720
721  /* Set fragment size */
722  *ctrl = (uint32_t) (size - 1);
723
724  /* Discard empty successive fragments */
725  n = m->m_next;
726  while (n != NULL && n->m_len <= 0) {
727    n = m_free(n);
728  }
729  m->m_next = n;
730
731  /* Is our fragment the last in the frame? */
732  if (n == NULL) {
733    *ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS;
734  }
735
736  return m;
737}
738
739static void lpc_eth_transmit_task(void *arg)
740{
741  rtems_status_code sc = RTEMS_SUCCESSFUL;
742  rtems_event_set events = 0;
743  lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg;
744  struct ifnet *ifp = &e->arpcom.ac_if;
745  volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table;
746  volatile uint32_t *const status = e->tx_status_table;
747  #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
748    struct mbuf **const mbufs = e->tx_buf_table;
749  #else
750    char *const buf = e->tx_buf_table;
751  #endif
752  struct mbuf *m = NULL;
753  uint32_t const index_max = e->tx_unit_count - 1;
754  uint32_t produce_index = 0;
755  uint32_t consume_index = 0;
756  uint32_t ctrl = 0;
757  #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
758    uint32_t frame_length = 0;
759    char *frame_buffer = NULL;
760  #endif
761
762  LPC_ETH_PRINTF("%s\n", __func__);
763
764  #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
765    /* Initialize descriptor table */
766    for (produce_index = 0; produce_index <= index_max; ++produce_index) {
767      desc [produce_index].start =
768        (uint32_t) (buf + produce_index * LPC_ETH_CONFIG_TX_BUF_SIZE);
769    }
770  #endif
771
772  /* Main event loop */
773  while (true) {
774    /* Wait for events */
775    sc = rtems_bsdnet_event_receive(
776      LPC_ETH_EVENT_INITIALIZE
777        | LPC_ETH_EVENT_START
778        | LPC_ETH_EVENT_INTERRUPT,
779      RTEMS_EVENT_ANY | RTEMS_WAIT,
780      RTEMS_NO_TIMEOUT,
781      &events
782    );
783    RTEMS_CLEANUP_SC(sc, cleanup, "wait for events");
784
785    LPC_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events);
786
787    /* Initialize transmitter? */
788    if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
789      /* Disable transmit interrupts */
790      lpc_eth_disable_transmit_interrupts();
791
792      /* Disable transmitter */
793      lpc_eth->command &= ~ETH_CMD_TX_ENABLE;
794
795      /* Wait for inactive status */
796      while ((lpc_eth->status & ETH_STAT_TX_ACTIVE) != 0) {
797        /* Wait */
798      }
799
800      /* Reset */
801      lpc_eth->command |= ETH_CMD_TX_RESET;
802
803      /* Clear transmit interrupts */
804      lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT;
805
806      /* Transmit descriptors */
807      lpc_eth->txdescriptornum = index_max;
808      lpc_eth->txdescriptor = (uint32_t) desc;
809      lpc_eth->txstatus = (uint32_t) status;
810
811      #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
812        /* Discard outstanding fragments (= data loss) */
813        for (produce_index = 0; produce_index <= index_max; ++produce_index) {
814          struct mbuf *victim = mbufs [produce_index];
815
816          if (victim != NULL) {
817            m_free(victim);
818            mbufs [produce_index] = NULL;
819          }
820        }
821      #endif
822
823      /* Initialize indices */
824      produce_index = lpc_eth->txproduceindex;
825      consume_index = lpc_eth->txconsumeindex;
826
827      #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
828        /* Fresh frame length and buffer start */
829        frame_length = 0;
830        frame_buffer = (char *) desc [produce_index].start;
831      #endif
832
833      /* Enable transmitter */
834      lpc_eth->command |= ETH_CMD_TX_ENABLE;
835    }
836
837    /* Free consumed fragments */
838    while (true) {
839      /* Save last known consume index */
840      uint32_t c = consume_index;
841
842      /* Clear transmit interrupt status */
843      lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT;
844
845      /* Get new consume index */
846      consume_index = lpc_eth->txconsumeindex;
847
848      /* Nothing consumed in the meantime? */
849      if (c == consume_index) {
850        break;
851      }
852
853      while (c != consume_index) {
854        uint32_t s = status [c];
855
856        /* Update error counters */
857        if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) {
858          if ((s & ETH_TX_STAT_UNDERRUN) != 0) {
859            ++e->transmit_underrun_errors;
860          }
861          if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) {
862            ++e->transmit_late_collision_errors;
863          }
864          if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) {
865            ++e->transmit_excessive_collision_errors;
866          }
867          if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) {
868            ++e->transmit_excessive_defer_errors;
869          }
870          if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) {
871            ++e->transmit_no_descriptor_errors;
872          }
873        }
874
875        #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
876          /* Release mbuf */
877          m_free(mbufs [c]);
878          mbufs [c] = NULL;
879        #endif
880
881        /* Next consume index */
882        c = lpc_eth_increment(c, index_max);
883      }
884    }
885
886    /* Transmit new fragments */
887    while (true) {
888      /* Compute next produce index */
889      uint32_t p = lpc_eth_increment(produce_index, index_max);
890
891      /* Get next fragment and control value */
892      m = lpc_eth_next_fragment(ifp, m, &ctrl);
893
894      /* Queue full? */
895      if (p == consume_index) {
896        LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m);
897
898        /* The queue is full, wait for transmit interrupt */
899        break;
900      }
901
902      /* New fragment? */
903      if (m != NULL) {
904        #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
905          /* Set the transfer data */
906          rtems_cache_flush_multiple_data_lines(
907            mtod(m, const void *),
908            (size_t) m->m_len
909          );
910          desc [produce_index].start = mtod(m, uint32_t);
911          desc [produce_index].control = ctrl;
912          rtems_cache_flush_multiple_data_lines
913            ((void *)&desc [produce_index],
914             sizeof(desc [0])
915             );
916          mbufs [produce_index] = m;
917
918          LPC_ETH_PRINTF(
919            "tx: %02" PRIu32 ": %u %s\n",
920            produce_index, m->m_len,
921            (ctrl & ETH_TX_CTRL_LAST) != 0 ? "L" : ""
922          );
923
924          /* Next produce index */
925          produce_index = p;
926
927          /* Last fragment of a frame? */
928          if ((ctrl & ETH_TX_CTRL_LAST) != 0) {
929            /* Update the produce index */
930            lpc_eth->txproduceindex = produce_index;
931
932            /* Increment transmitted frames counter */
933            ++e->transmitted_frames;
934          }
935
936          /* Next fragment of the frame */
937          m = m->m_next;
938        #else
939          size_t fragment_length = (size_t) m->m_len;
940          void *fragment_start = mtod(m, void *);
941          uint32_t new_frame_length = frame_length + fragment_length;
942
943          /* Check buffer size */
944          if (new_frame_length > LPC_ETH_CONFIG_TX_BUF_SIZE) {
945            LPC_ETH_PRINTF("tx: overflow\n");
946
947            /* Discard overflow data */
948            new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE;
949            fragment_length = new_frame_length - frame_length;
950
951            /* Finalize frame */
952            ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS;
953
954            /* Update error counter */
955            ++e->transmit_overflow_errors;
956          }
957
958          LPC_ETH_PRINTF(
959            "tx: copy: %" PRIu32 "%s%s\n",
960            fragment_length,
961            (m->m_flags & M_EXT) != 0 ? ", E" : "",
962            (m->m_flags & M_PKTHDR) != 0 ? ", H" : ""
963          );
964
965          /* Copy fragment to buffer in Ethernet RAM */
966          memcpy(frame_buffer, fragment_start, fragment_length);
967
968          if ((ctrl & ETH_TX_CTRL_LAST) != 0) {
969            /* Finalize descriptor */
970            desc [produce_index].control = (ctrl & ~ETH_TX_CTRL_SIZE_MASK)
971              | (new_frame_length - 1);
972
973            LPC_ETH_PRINTF(
974              "tx: %02" PRIu32 ": %" PRIu32 "\n",
975              produce_index,
976              new_frame_length
977            );
978
979            /* Cache flush of data */
980            rtems_cache_flush_multiple_data_lines(
981              (const void *) desc [produce_index].start,
982              new_frame_length
983            );
984
985            /* Cache flush of descriptor  */
986            rtems_cache_flush_multiple_data_lines
987              ((void *)&desc [produce_index],
988               sizeof(desc [0])
989               );
990
991            /* Next produce index */
992            produce_index = p;
993
994            /* Update the produce index */
995            lpc_eth->txproduceindex = produce_index;
996
997            /* Fresh frame length and buffer start */
998            frame_length = 0;
999            frame_buffer = (char *) desc [produce_index].start;
1000
1001            /* Increment transmitted frames counter */
1002            ++e->transmitted_frames;
1003          } else {
1004            /* New frame length */
1005            frame_length = new_frame_length;
1006
1007            /* Update current frame buffer start */
1008            frame_buffer += fragment_length;
1009          }
1010
1011          /* Free mbuf and get next */
1012          m = m_free(m);
1013        #endif
1014      } else {
1015        /* Nothing to transmit */
1016        break;
1017      }
1018    }
1019
1020    /* No more fragments? */
1021    if (m == NULL) {
1022      /* Interface is now inactive */
1023      ifp->if_flags &= ~IFF_OACTIVE;
1024    } else {
1025      LPC_ETH_PRINTF("tx: enable interrupts\n");
1026
1027      /* Enable transmit interrupts */
1028      lpc_eth_enable_transmit_interrupts();
1029    }
1030  }
1031
1032cleanup:
1033
1034  /* Clear task ID */
1035  e->transmit_task = RTEMS_ID_NONE;
1036
1037  /* Release network semaphore */
1038  rtems_bsdnet_semaphore_release();
1039
1040  /* Terminate self */
1041  (void) rtems_task_delete(RTEMS_SELF);
1042}
1043
1044static void lpc_eth_interface_init(void *arg)
1045{
1046  rtems_status_code sc = RTEMS_SUCCESSFUL;
1047  lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg;
1048  struct ifnet *ifp = &e->arpcom.ac_if;
1049
1050  LPC_ETH_PRINTF("%s\n", __func__);
1051
1052  if (e->state == LPC_ETH_INITIALIZED) {
1053    lpc_eth_config_module_enable();
1054
1055    /* Soft reset */
1056
1057    /* Do soft reset */
1058    lpc_eth->command = 0x38;
1059    lpc_eth->mac1 = 0xcf00;
1060    lpc_eth->mac1 = 0x0;
1061
1062    /* Initialize PHY */
1063    /* TODO */
1064
1065    /* Reinitialize registers */
1066    lpc_eth->mac2 = 0x31;
1067    lpc_eth->ipgt = 0x15;
1068    lpc_eth->ipgr = 0x12;
1069    lpc_eth->clrt = 0x370f;
1070    lpc_eth->maxf = 0x0600;
1071    lpc_eth->supp = 0x0100;
1072    lpc_eth->test = 0;
1073    #ifdef LPC_ETH_CONFIG_RMII
1074      lpc_eth->command = 0x0600;
1075    #else
1076      lpc_eth->command = 0x0400;
1077    #endif
1078    lpc_eth->intenable = 0;
1079    lpc_eth->intclear = 0x30ff;
1080    lpc_eth->powerdown = 0;
1081
1082    /* MAC address */
1083    lpc_eth->sa0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8)
1084      | (uint32_t) e->arpcom.ac_enaddr [4];
1085    lpc_eth->sa1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8)
1086      | (uint32_t) e->arpcom.ac_enaddr [2];
1087    lpc_eth->sa2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8)
1088      | (uint32_t) e->arpcom.ac_enaddr [0];
1089
1090    /* Enable receiver */
1091    lpc_eth->mac1 = 0x03;
1092
1093    /* Start receive task */
1094    if (e->receive_task == RTEMS_ID_NONE) {
1095      e->receive_task = rtems_bsdnet_newproc(
1096        "ntrx",
1097        4096,
1098        lpc_eth_receive_task,
1099        e
1100      );
1101      sc = rtems_event_send(e->receive_task, LPC_ETH_EVENT_INITIALIZE);
1102      RTEMS_SYSLOG_ERROR_SC(sc, "send receive initialize event");
1103    }
1104
1105    /* Start transmit task */
1106    if (e->transmit_task == RTEMS_ID_NONE) {
1107      e->transmit_task = rtems_bsdnet_newproc(
1108        "nttx",
1109        4096,
1110        lpc_eth_transmit_task,
1111        e
1112      );
1113      sc = rtems_event_send(e->transmit_task, LPC_ETH_EVENT_INITIALIZE);
1114      RTEMS_SYSLOG_ERROR_SC(sc, "send transmit initialize event");
1115    }
1116
1117    /* Change state */
1118    if (
1119      e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE
1120    ) {
1121      e->state = LPC_ETH_STARTED;
1122    }
1123  }
1124
1125  if (e->state == LPC_ETH_STARTED) {
1126    /* Enable fatal interrupts */
1127    lpc_eth->intenable = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN;
1128
1129    /* Enable promiscous mode */
1130    lpc_eth_enable_promiscous_mode((ifp->if_flags & IFF_PROMISC) != 0);
1131
1132    /* Start watchdog timer */
1133    ifp->if_timer = 1;
1134
1135    /* Set interface to running state */
1136    ifp->if_flags |= IFF_RUNNING;
1137
1138    /* Change state */
1139    e->state = LPC_ETH_RUNNING;
1140  }
1141}
1142
1143static void lpc_eth_interface_stats(const lpc_eth_driver_entry *e)
1144{
1145  rtems_bsdnet_semaphore_release();
1146
1147  printf("received frames:                     %u\n", e->received_frames);
1148  printf("receive interrupts:                  %u\n", e->receive_interrupts);
1149  printf("transmitted frames:                  %u\n", e->transmitted_frames);
1150  printf("transmit interrupts:                 %u\n", e->transmit_interrupts);
1151  printf("receive overrun errors:              %u\n", e->receive_overrun_errors);
1152  printf("receive fragment errors:             %u\n", e->receive_fragment_errors);
1153  printf("receive CRC errors:                  %u\n", e->receive_crc_errors);
1154  printf("receive symbol errors:               %u\n", e->receive_symbol_errors);
1155  printf("receive length errors:               %u\n", e->receive_length_errors);
1156  printf("receive alignment errors:            %u\n", e->receive_alignment_errors);
1157  printf("receive no descriptor errors:        %u\n", e->receive_no_descriptor_errors);
1158  printf("receive fatal errors:                %u\n", e->receive_fatal_errors);
1159  printf("transmit underrun errors:            %u\n", e->transmit_underrun_errors);
1160  printf("transmit late collision errors:      %u\n", e->transmit_late_collision_errors);
1161  printf("transmit excessive collision errors: %u\n", e->transmit_excessive_collision_errors);
1162  printf("transmit excessive defer errors:     %u\n", e->transmit_excessive_defer_errors);
1163  printf("transmit no descriptor errors:       %u\n", e->transmit_no_descriptor_errors);
1164  printf("transmit overflow errors:            %u\n", e->transmit_overflow_errors);
1165  printf("transmit fatal errors:               %u\n", e->transmit_fatal_errors);
1166
1167  rtems_bsdnet_semaphore_obtain();
1168}
1169
1170static int lpc_eth_interface_ioctl(
1171  struct ifnet *ifp,
1172  ioctl_command_t command,
1173  caddr_t data
1174)
1175{
1176  lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
1177  int rv = 0;
1178
1179  LPC_ETH_PRINTF("%s\n", __func__);
1180
1181  switch (command)  {
1182    case SIOCGIFMEDIA:
1183    case SIOCSIFMEDIA:
1184      rtems_mii_ioctl(&e->mdio_info, e, (int) command, (int *) data);
1185      break;
1186    case SIOCGIFADDR:
1187    case SIOCSIFADDR:
1188      ether_ioctl(ifp, command, data);
1189      break;
1190    case SIOCSIFFLAGS:
1191      if (ifp->if_flags & IFF_RUNNING) {
1192        /* TODO: off */
1193      }
1194      if (ifp->if_flags & IFF_UP) {
1195        ifp->if_flags |= IFF_RUNNING;
1196        /* TODO: init */
1197      }
1198      break;
1199    case SIO_RTEMS_SHOW_STATS:
1200      lpc_eth_interface_stats(e);
1201      break;
1202    default:
1203      rv = EINVAL;
1204      break;
1205  }
1206
1207  return rv;
1208}
1209
1210static void lpc_eth_interface_start(struct ifnet *ifp)
1211{
1212  rtems_status_code sc = RTEMS_SUCCESSFUL;
1213  lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
1214
1215  ifp->if_flags |= IFF_OACTIVE;
1216
1217  sc = rtems_event_send(e->transmit_task, LPC_ETH_EVENT_START);
1218  RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event");
1219}
1220
1221static void lpc_eth_interface_watchdog(struct ifnet *ifp __attribute__((unused)))
1222{
1223  LPC_ETH_PRINTF("%s\n", __func__);
1224}
1225
1226static unsigned lpc_eth_fixup_unit_count(int count, int default_value, int max)
1227{
1228  if (count <= 0) {
1229    count = default_value;
1230  } else if (count > max) {
1231    count = max;
1232  }
1233
1234  return LPC_ETH_CONFIG_UNIT_MULTIPLE
1235    + (((unsigned) count - 1U) & ~(LPC_ETH_CONFIG_UNIT_MULTIPLE - 1U));
1236}
1237
1238static int lpc_eth_attach(struct rtems_bsdnet_ifconfig *config)
1239{
1240  rtems_status_code sc = RTEMS_SUCCESSFUL;
1241  lpc_eth_driver_entry *e = &lpc_eth_driver_data;
1242  struct ifnet *ifp = &e->arpcom.ac_if;
1243  char *unit_name = NULL;
1244  int unit_index = rtems_bsdnet_parse_driver_name(config, &unit_name);
1245  size_t table_area_size = 0;
1246  char *table_area = NULL;
1247  char *table_location = NULL;
1248
1249  /* Check parameter */
1250  if (unit_index < 0) {
1251    RTEMS_SYSLOG_ERROR("parse error for interface name\n");
1252    return 0;
1253  }
1254  if (unit_index != 0) {
1255    RTEMS_DO_CLEANUP(cleanup, "unexpected unit number");
1256  }
1257  if (config->hardware_address == NULL) {
1258    RTEMS_DO_CLEANUP(cleanup, "MAC address missing");
1259  }
1260  if (e->state != LPC_ETH_NOT_INITIALIZED) {
1261    RTEMS_DO_CLEANUP(cleanup, "already attached");
1262  }
1263
1264  /* Interrupt number */
1265  config->irno = LPC_ETH_CONFIG_INTERRUPT;
1266
1267  /* Device control */
1268  config->drv_ctrl = e;
1269
1270  /* Receive unit count */
1271  e->rx_unit_count = lpc_eth_fixup_unit_count(
1272    config->rbuf_count,
1273    LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT,
1274    LPC_ETH_CONFIG_RX_UNIT_COUNT_MAX
1275  );
1276  config->rbuf_count = (int) e->rx_unit_count;
1277
1278  /* Transmit unit count */
1279  e->tx_unit_count = lpc_eth_fixup_unit_count(
1280    config->xbuf_count,
1281    LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT,
1282    LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX
1283  );
1284  config->xbuf_count = (int) e->tx_unit_count;
1285
1286  /* Disable interrupts */
1287  lpc_eth->intenable = 0;
1288
1289  /* Install interrupt handler */
1290  sc = rtems_interrupt_handler_install(
1291    config->irno,
1292    "Ethernet",
1293    RTEMS_INTERRUPT_UNIQUE,
1294    lpc_eth_interrupt_handler,
1295    e
1296  );
1297  RTEMS_CLEANUP_SC(sc, cleanup, "install interrupt handler");
1298
1299  /* Copy MAC address */
1300  memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1301
1302  /* Allocate and clear table area */
1303  table_area_size =
1304    e->rx_unit_count
1305      * (sizeof(lpc_eth_transfer_descriptor)
1306        + sizeof(lpc_eth_receive_status)
1307        + sizeof(struct mbuf *))
1308    + e->tx_unit_count
1309      * (sizeof(lpc_eth_transfer_descriptor)
1310        + sizeof(uint32_t)
1311        + LPC_ETH_CONFIG_TX_BUF_SIZE);
1312  table_area = lpc_eth_config_alloc_table_area(table_area_size);
1313  if (table_area == NULL) {
1314    RTEMS_DO_CLEANUP(cleanup, "no memory for table area");
1315  }
1316  memset(table_area, 0, table_area_size);
1317
1318  table_location = table_area;
1319
1320  /*
1321   * The receive status table must be the first one since it has the strictest
1322   * alignment requirements.
1323   */
1324  e->rx_status_table = (volatile lpc_eth_receive_status *) table_location;
1325  table_location += e->rx_unit_count * sizeof(e->rx_status_table [0]);
1326
1327  e->rx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location;
1328  table_location += e->rx_unit_count * sizeof(e->rx_desc_table [0]);
1329
1330  e->rx_mbuf_table = (struct mbuf **) table_location;
1331  table_location += e->rx_unit_count * sizeof(e->rx_mbuf_table [0]);
1332
1333  e->tx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location;
1334  table_location += e->tx_unit_count * sizeof(e->tx_desc_table [0]);
1335
1336  e->tx_status_table = (volatile uint32_t *) table_location;
1337  table_location += e->tx_unit_count * sizeof(e->tx_status_table [0]);
1338
1339  e->tx_buf_table = table_location;
1340
1341  /* Set interface data */
1342  ifp->if_softc = e;
1343  ifp->if_unit = (short) unit_index;
1344  ifp->if_name = unit_name;
1345  ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU;
1346  ifp->if_init = lpc_eth_interface_init;
1347  ifp->if_ioctl = lpc_eth_interface_ioctl;
1348  ifp->if_start = lpc_eth_interface_start;
1349  ifp->if_output = ether_output;
1350  ifp->if_watchdog = lpc_eth_interface_watchdog;
1351  ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST;
1352  ifp->if_snd.ifq_maxlen = ifqmaxlen;
1353  ifp->if_timer = 0;
1354
1355  /* Change status */
1356  e->state = LPC_ETH_INITIALIZED;
1357
1358  /* Attach the interface */
1359  if_attach(ifp);
1360  ether_ifattach(ifp);
1361
1362  return 1;
1363
1364cleanup:
1365
1366  lpc_eth_config_free_table_area(table_area);
1367
1368  /* FIXME: Type */
1369  free(unit_name, (int) 0xdeadbeef);
1370
1371  return 0;
1372}
1373
1374static int lpc_eth_detach(
1375  struct rtems_bsdnet_ifconfig *config __attribute__((unused))
1376)
1377{
1378  /* FIXME: Detach the interface from the upper layers? */
1379
1380  /* Module soft reset */
1381  lpc_eth->command = 0x38;
1382  lpc_eth->mac1 = 0xcf00;
1383
1384  /* FIXME: More cleanup */
1385
1386  return 0;
1387}
1388
1389int lpc_eth_attach_detach(
1390  struct rtems_bsdnet_ifconfig *config,
1391  int attaching
1392)
1393{
1394  /* FIXME: Return value */
1395
1396  if (attaching) {
1397    return lpc_eth_attach(config);
1398  } else {
1399    return lpc_eth_detach(config);
1400  }
1401}
Note: See TracBrowser for help on using the repository browser.