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

4.115
Last change on this file since 369bb13b was 369bb13b, checked in by Pavel Pisa <ppisa@…>, on 02/21/14 at 13:08:03

bsps/arm: Reset MII management in LPC Ethernet

Reduce MII clock to support LPC17XX.

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