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

4.115
Last change on this file since 7f5ab84e was 7f5ab84e, checked in by Sebastian Huber <sebastian.huber@…>, on 09/28/12 at 11:48:32

bsps/arm: Fix rtems_mii_ioctl() usage

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