source: rtems/c/src/libchip/network/dwmac.c @ d5f5432

4.115
Last change on this file since d5f5432 was d5f5432, checked in by Christian Mauderer <Christian.Mauderer@…>, on 08/22/14 at 06:53:10

libchip/dwmac: Make PHY address user configurable

This patch allows the user to configure the PHY address for the DWMAC
driver by giving a pointer to a dwmac_user_cfg structure to network
stack via rtems_bsdnet_ifconfig::drv_ctrl.

  • Property mode set to 100644
File size: 73.3 KB
Line 
1/**
2 * @file
3 *
4 * @brief DWMAC 10/100/1000 Network Interface Controller
5 *
6 * DWMAC 10/100/1000 on-chip Ethernet controllers are a Synopsys IP Core.
7 * This is the main mode for the network interface controller.
8 */
9
10/*
11 * Copyright (c) 2013-2014 embedded brains GmbH.  All rights reserved.
12 *
13 *  embedded brains GmbH
14 *  Dornierstr. 4
15 *  82178 Puchheim
16 *  Germany
17 *  <rtems@embedded-brains.de>
18 *
19 * The license and distribution terms for this file may be
20 * found in the file LICENSE in this distribution or at
21 * http://www.rtems.org/license/LICENSE.
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
29#include <bsp.h>
30#include <bsp/fatal.h>
31#include <rtems/endian.h>
32#include "dwmac-common.h"
33#include "dwmac-core.h"
34
35#ifdef BSP_FEATURE_IRQ_EXTENSION
36#include <bsp/irq.h>
37#endif
38
39/* PHY events which can be combined to an event set.
40 * The PHY can create an event for a corresponding status change */
41const dwmac_phy_event PHY_EVENT_JABBER                = 0x80;
42const dwmac_phy_event PHY_EVENT_RECEIVE_ERROR         = 0x40;
43const dwmac_phy_event PHY_EVENT_PAGE_RECEIVE          = 0x20;
44const dwmac_phy_event PHY_EVENT_PARALLEL_DETECT_FAULT = 0x10;
45const dwmac_phy_event PHY_EVENT_LINK_PARTNER_ACK      = 0x08;
46const dwmac_phy_event PHY_EVENT_LINK_DOWN             = 0x04;
47const dwmac_phy_event PHY_EVENT_REMOTE_FAULT          = 0x02;
48const dwmac_phy_event PHY_EVENT_LINK_UP               = 0x01;
49
50/* Default values for the number of DMA descriptors and mbufs to be used */
51#define DWMAC_CONFIG_RX_UNIT_COUNT_DEFAULT 64
52#define DWMAC_CONFIG_RX_UNIT_COUNT_MAX INT_MAX
53#define DWMAC_CONFIG_TX_UNIT_COUNT_DEFAULT 64
54#define DWMAC_CONFIG_TX_UNIT_COUNT_MAX INT_MAX
55
56/* Default values for the DMA configuration */
57#define DWMAC_DMA_BUS_MODE_PBL_DEFAULT DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_8
58#define DWMAC_DMA_BUS_MODE_FB_DEFAULT \
59  DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR
60#define DWMAC_DMA_BUS_MODE_MIXED_BURSTS_DEFAULT \
61  DWMAC_DMA_CFG_BUS_MODE_BURST_NOT_MIXED
62#define DWMAC_DMA_AXI_BURST_LENGTH_4_DEFAULT \
63  DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_NOT_SUPPORTED
64#define DWMAC_DMA_AXI_BURST_LENGTH_8_DEFAULT \
65  DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_NOT_SUPPORTED
66#define DWMAC_DMA_AXI_BURST_LENGTH_16_DEFAULT \
67  DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_NOT_SUPPORTED
68#define DWMAC_DMA_AXI_BURST_BOUNDARY_DEFAULT \
69  DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB
70
71/* CSR Frequency Access Defines*/
72#define DWCGNAC3504_CSR_F_35M 35000000
73#define DWCGNAC3504_CSR_F_60M 60000000
74#define DWCGNAC3504_CSR_F_100M 100000000
75#define DWCGNAC3504_CSR_F_150M 150000000
76#define DWCGNAC3504_CSR_F_250M 250000000
77#define DWCGNAC3504_CSR_F_300M 300000000
78
79/* MDC Clock Selection define*/
80#define DWCGNAC3504_CSR_60_100M 0x0 /* MDC = clk_scr_i/42 */
81#define DWCGNAC3504_CSR_100_150M 0x1 /* MDC = clk_scr_i/62 */
82#define DWCGNAC3504_CSR_20_35M 0x2 /* MDC = clk_scr_i/16 */
83#define DWCGNAC3504_CSR_35_60M 0x3 /* MDC = clk_scr_i/26 */
84#define DWCGNAC3504_CSR_150_250M 0x4 /* MDC = clk_scr_i/102 */
85#define DWCGNAC3504_CSR_250_300M 0x5 /* MDC = clk_scr_i/122 */
86
87#define DWMAC_ALIGN( value, num_bytes_to_align_to ) \
88  ( ( ( value ) + ( ( typeof( value ) )( num_bytes_to_align_to ) - 1 ) ) \
89    & ~( ( typeof( value ) )( num_bytes_to_align_to ) - 1 ) )
90
91#undef DWMAC_DEBUG
92#ifdef DWMAC_DEBUG
93#define DWMAC_PRINT_DBG( fmt, args ... )  printk( fmt, ## args )
94#else
95#define DWMAC_PRINT_DBG( fmt, args ... )  do { } while ( 0 )
96#endif
97
98#define DWMAC_DMA_THRESHOLD_CONTROL_DEFAULT 64
99
100#define DWMAC_GLOBAL_MBUF_CNT (rtems_bsdnet_config.mbuf_bytecount / sizeof(struct  mbuf))
101#define DWMAG_GLOBAL_MCLUST_CNT (rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES)
102
103static int dwmac_if_mdio_busy_wait( const volatile uint32_t *gmii_address )
104{
105  rtems_interval timeout = rtems_clock_get_ticks_per_second();
106  rtems_interval i       = 0;
107
108
109  while ( ( *gmii_address & MACGRP_GMII_ADDRESS_GMII_BUSY ) != 0
110          && i < timeout ) {
111    rtems_task_wake_after( 1 );
112    ++i;
113  }
114
115  return i < timeout ? 0 : EBUSY;
116}
117
118static int dwmac_if_mdio_read(
119  int       phy,
120  void     *arg,
121  unsigned  phy_reg,
122  uint32_t *val )
123{
124  int                   eno         = 0;
125  dwmac_common_context *self        = (dwmac_common_context *) arg;
126  volatile uint32_t    *mii_address = &self->macgrp->gmii_address;
127  volatile uint32_t    *mii_data    = &self->macgrp->gmii_data;
128  uint32_t              reg_value   = 0;
129
130
131  if ( phy == -1 ) {
132    reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET(
133      reg_value,
134      self->MDIO_BUS_ADDR
135      );
136  } else {
137    reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET(
138      reg_value,
139      phy
140      );
141  }
142
143  reg_value = MACGRP_GMII_ADDRESS_GMII_REGISTER_SET(
144    reg_value,
145    phy_reg
146    );
147  reg_value &= ~MACGRP_GMII_ADDRESS_GMII_WRITE;
148
149  /* For the 7111 GMAC, we must set BUSY bit  in the MII address register while
150   * accessing the PHY registers.
151   * Fortunately, it seems this has no drawback for the 7109 MAC. */
152  reg_value |= MACGRP_GMII_ADDRESS_GMII_BUSY;
153  reg_value  = MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_SET(
154    reg_value,
155    self->csr_clock
156    );
157
158  eno = dwmac_if_mdio_busy_wait( mii_address );
159
160  if ( eno == 0 ) {
161    *mii_address = reg_value;
162
163    if ( dwmac_if_mdio_busy_wait( mii_address ) ) {
164      eno = EBUSY;
165    } else {
166      /* Read the value from the MII data register */
167      *val = MACGRP_GMII_DATA_GMII_DATA_GET( *mii_data );
168    }
169  }
170
171  return eno;
172}
173
174static int dwmac_if_mdio_write(
175  int      phy,
176  void    *arg,
177  unsigned phy_reg,
178  uint32_t val )
179{
180  int                   eno         = 0;
181  dwmac_common_context *self        = (dwmac_common_context *) arg;
182  volatile uint32_t    *mii_address = &self->macgrp->gmii_address;
183  volatile uint32_t    *mii_data    = &self->macgrp->gmii_data;
184  uint32_t              reg_value   = *mii_address;
185
186
187  if ( phy == -1 ) {
188    reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET(
189      reg_value,
190      self->MDIO_BUS_ADDR
191      );
192  } else {
193    reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET(
194      reg_value,
195      phy
196      );
197  }
198
199  reg_value = MACGRP_GMII_ADDRESS_GMII_REGISTER_SET(
200    reg_value,
201    phy_reg
202    );
203  reg_value |= MACGRP_GMII_ADDRESS_GMII_WRITE;
204  reg_value |= MACGRP_GMII_ADDRESS_GMII_BUSY;
205  reg_value  = MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_SET(
206    reg_value,
207    self->csr_clock
208    );
209
210  /* Wait until any existing MII operation is complete */
211  eno = dwmac_if_mdio_busy_wait( mii_address );
212
213  if ( eno == 0 ) {
214    /* Set the MII address register to write */
215    *mii_data    = val;
216    *mii_address = reg_value;
217
218    /* Wait until any existing MII operation is complete */
219    eno = dwmac_if_mdio_busy_wait( mii_address );
220  }
221
222  return eno;
223}
224
225static int dwmac_get_phy_info(
226  dwmac_common_context *self,
227  const uint8_t         mdio_bus_addr,
228  uint32_t             *oui,
229  uint8_t              *model,
230  uint8_t              *revision )
231{
232  int      eno = 0;
233  uint32_t read;
234
235
236  eno = dwmac_if_mdio_read(
237    mdio_bus_addr,
238    self,
239    2,
240    &read );
241
242  if ( eno == 0 ) {
243    *oui = 0 | ( read << 6 );
244    eno  = dwmac_if_mdio_read(
245      mdio_bus_addr,
246      self,
247      3,
248      &read );
249
250    if ( eno == 0 ) {
251      *oui     |= ( read & 0xFC00 ) >> 10;
252      *model    = (uint8_t) ( ( read & 0x03F0 ) >> 4 );
253      *revision = read & 0x000F;
254    }
255  }
256
257  return eno;
258}
259
260static inline void dwmac_enable_irq_rx( dwmac_common_context *self )
261{
262  dwmac_core_enable_dma_irq_rx( self );
263}
264
265static inline void dwmac_enable_irq_tx_default( dwmac_common_context *self )
266{
267  dwmac_core_enable_dma_irq_tx_default( self );
268}
269
270static inline void dwmac_enable_irq_tx_transmitted( dwmac_common_context *self )
271{
272  dwmac_core_enable_dma_irq_tx_transmitted( self );
273}
274
275static inline void dwmac_disable_irq_rx( dwmac_common_context *self )
276{
277  dwmac_core_disable_dma_irq_rx( self );
278}
279
280static inline void dwmac_disable_irq_tx_all( dwmac_common_context *self )
281{
282  dwmac_core_disable_dma_irq_tx_all( self );
283}
284
285static inline void dwmac_disable_irq_tx_transmitted ( dwmac_common_context *self )
286{
287  dwmac_core_disable_dma_irq_tx_transmitted( self );
288}
289
290static void dwmac_control_request_complete( const dwmac_common_context *self )
291{
292  rtems_status_code sc = rtems_event_transient_send( self->task_id_control );
293
294  assert( sc == RTEMS_SUCCESSFUL );
295}
296
297static int dwmac_control_request(
298  dwmac_common_context *self,
299  rtems_id              task,
300  rtems_event_set       event )
301{
302  int               eno        = 0;
303  rtems_status_code sc         = RTEMS_SUCCESSFUL;
304  uint32_t          nest_count = 0;
305
306
307  self->task_id_control = rtems_task_self();
308
309  sc                    = rtems_bsdnet_event_send( task, event );
310
311  eno                   = rtems_status_code_to_errno( sc );
312
313  if ( eno == 0 ) {
314    nest_count = rtems_bsdnet_semaphore_release_recursive();
315    sc         = rtems_event_transient_receive( RTEMS_WAIT, RTEMS_NO_TIMEOUT );
316    eno        = rtems_status_code_to_errno( sc );
317    rtems_bsdnet_semaphore_obtain_recursive( nest_count );
318    self->task_id_control = 0;
319  }
320
321  return eno;
322}
323
324static bool dwmac_if_media_status(
325  dwmac_common_context *self,
326  int                  *media,
327  uint8_t               phy_address )
328{
329  struct ifnet *ifp = &self->arpcom.ac_if;
330
331
332  *media = (int) IFM_MAKEWORD( 0, 0, 0, phy_address );
333
334  return ( *ifp->if_ioctl )( ifp, SIOCGIFMEDIA, (caddr_t) media ) == 0;
335}
336
337#define DWMAC_PRINT_COUNTER( fmt, counter, args ... ) \
338  if ( counter != 0 ) { \
339    printf( fmt, counter, ## args ); \
340  }
341
342/* Print statistics. Get called via ioctl. */
343static int dwmac_if_interface_stats( void *arg )
344{
345  int                   eno      = 0;
346  dwmac_common_context *self     = arg;
347  volatile macgrp      *macgrp   = self->macgrp;
348  int                   media    = 0;
349  bool                  media_ok = dwmac_if_media_status(
350    self, &media, self->MDIO_BUS_ADDR );
351  uint32_t              oui;
352  uint8_t               model;
353  uint8_t               revision;
354  uint16_t              giant_frame_size = 1518;
355
356
357  if ( ( MACGRP_MAC_CONFIGURATION_JE & macgrp->mac_configuration ) != 0 ) {
358    /* Jumbo Frames are enabled */
359    giant_frame_size = 9018;
360  }
361
362  if ( media_ok ) {
363    rtems_ifmedia2str( media, NULL, 0 );
364    printf( "\n" );
365    eno = dwmac_get_phy_info(
366      self,
367      self->MDIO_BUS_ADDR,
368      &oui,
369      &model,
370      &revision );
371
372    if ( eno == 0 ) {
373      printf( "PHY 0x%02x: OUI = 0x%04" PRIX32 ", Model = 0x%02" PRIX8 ", Rev = "
374              "0x%02" PRIX8 "\n",
375              self->MDIO_BUS_ADDR,
376              oui,
377              model,
378              revision );
379      printf( "PHY status counters:\n" );
380      DWMAC_PRINT_COUNTER(
381        "%" PRIu32 " link down\n",
382        self->stats.phy_status_counts.link_down
383        );
384      DWMAC_PRINT_COUNTER(
385        "%" PRIu32 " link up\n",
386        self->stats.phy_status_counts.link_up
387        );
388    }
389  } else {
390    printf( "PHY %d communication error\n", self->MDIO_BUS_ADDR );
391  }
392
393  printf( "\nHardware counters:\n" );
394
395  if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 ) {
396    DWMAC_PRINT_COUNTER(
397      "%" PRIu32 " bytes transmitted, exclusive of preamble and retried bytes, "
398      "in good and bad frames\n",
399      macgrp->txoctetcount_gb
400      );
401    DWMAC_PRINT_COUNTER(
402      "%" PRIu32 " good and bad frames transmitted, exclusive of retried "
403      "frames\n",
404      macgrp->txframecount_gb
405      );
406    DWMAC_PRINT_COUNTER(
407      "%" PRIu32 " good broadcast frames transmitted\n",
408      macgrp->txbroadcastframes_g
409      );
410    DWMAC_PRINT_COUNTER(
411      "%" PRIu32 " good multicast frames transmitted\n",
412      macgrp->txmulticastframes_g
413      );
414    DWMAC_PRINT_COUNTER(
415      "%" PRIu32 " good and bad frames transmitted with length 64 bytes, "
416      "exclusive of preamble and retried frames\n",
417      macgrp->tx64octets_gb
418      );
419    DWMAC_PRINT_COUNTER(
420      "%" PRIu32 " good and bad frames transmitted with length between 65 and "
421      "127 (inclusive) bytes, exclusive of preamble and retried frames\n",
422      macgrp->tx65to127octets_gb
423      );
424    DWMAC_PRINT_COUNTER(
425      "%" PRIu32 " good and bad frames transmitted with length between 128 and "
426      "255 (inclusive) bytes, exclusive of preamble and retried frames\n",
427      macgrp->tx128to255octets_gb
428      );
429    DWMAC_PRINT_COUNTER(
430      "%" PRIu32 " good and bad frames transmitted with length between 256 and "
431      "511 (inclusive) bytes, exclusive of preamble and retried frames\n",
432      macgrp->tx256to511octets_gb
433      );
434    DWMAC_PRINT_COUNTER(
435      "%" PRIu32 " good and bad frames transmitted with length between 512 and "
436      "1,023 (inclusive) bytes, exclusive of preamble and retried frames\n",
437      macgrp->tx512to1023octets_gb
438      );
439    DWMAC_PRINT_COUNTER(
440      "%" PRIu32 " good and bad frames transmitted with length between 1,024 and"
441      " maxsize (inclusive) bytes, exclusive of preamble and retried frames\n",
442      macgrp->tx1024tomaxoctets_gb
443      );
444    DWMAC_PRINT_COUNTER(
445      "%" PRIu32 " good and bad unicast frames transmitted\n",
446      macgrp->txunicastframes_gb
447      );
448    DWMAC_PRINT_COUNTER(
449      "%" PRIu32 " good and bad multicast frames transmitted\n",
450      macgrp->txmulticastframes_gb
451      );
452    DWMAC_PRINT_COUNTER(
453      "%" PRIu32 " good and bad broadcast frames transmitted\n",
454      macgrp->txbroadcastframes_gb
455      );
456    DWMAC_PRINT_COUNTER(
457      "%" PRIu32 " frames aborted due to frame underflow error\n",
458      macgrp->txunderflowerror
459      );
460    DWMAC_PRINT_COUNTER(
461      "%" PRIu32 " successfully transmitted frames after a single collision in "
462      "Half-duplex mode\n",
463      macgrp->txsinglecol_g
464      );
465    DWMAC_PRINT_COUNTER(
466      "%" PRIu32 " successfully transmitted frames after more than a single"
467      " collision in Half-duplex mode\n",
468      macgrp->txmulticol_g
469      );
470    DWMAC_PRINT_COUNTER(
471      "%" PRIu32 " successfully transmitted frames after a deferral in "
472      "Halfduplex mode\n",
473      macgrp->txdeferred
474      );
475    DWMAC_PRINT_COUNTER(
476      "%" PRIu32 " frames aborted due to late collision error\n",
477      macgrp->txlatecol
478      );
479    DWMAC_PRINT_COUNTER(
480      "%" PRIu32 " frames aborted due to excessive (16) collision errors\n",
481      macgrp->txexesscol
482      );
483    DWMAC_PRINT_COUNTER(
484      "%" PRIu32 " frames aborted due to carrier sense error (no carrier or loss"
485      " of carrier)\n",
486      macgrp->txcarriererr
487      );
488    DWMAC_PRINT_COUNTER(
489      "%" PRIu32 " bytes transmitted, exclusive of preamble, in good frames "
490      "only\n",
491      macgrp->txoctetcnt
492      );
493    DWMAC_PRINT_COUNTER(
494      "%" PRIu32 " good frames transmitted\n",
495      macgrp->txframecount_g
496      );
497    DWMAC_PRINT_COUNTER(
498      "%" PRIu32 " frames aborted due to excessive deferral error (deferred for"
499      " more than two max-sized frame times)\n",
500      macgrp->txexcessdef
501      );
502    DWMAC_PRINT_COUNTER(
503      "%" PRIu32 " good PAUSE frames transmitted\n",
504      macgrp->txpauseframes
505      );
506    DWMAC_PRINT_COUNTER(
507      "%" PRIu32 " good VLAN frames transmitted, exclusive of retried frames\n",
508      macgrp->txvlanframes_g
509      );
510    DWMAC_PRINT_COUNTER(
511      "%" PRIu32 " good and bad frames received\n",
512      macgrp->txoversize_g
513      );
514    DWMAC_PRINT_COUNTER(
515      "%" PRIu32 " good and bad frames received\n",
516      macgrp->rxframecount_gb
517      );
518    DWMAC_PRINT_COUNTER(
519      "%" PRIu32 " bytes received, exclusive of preamble, in good and bad "
520      "frames\n",
521      macgrp->rxoctetcount_gb
522      );
523    DWMAC_PRINT_COUNTER(
524      "%" PRIu32 " bytes received, exclusive of preamble, only in good frames\n",
525      macgrp->rxoctetcount_g
526      );
527    DWMAC_PRINT_COUNTER(
528      "%" PRIu32 " good broadcast frames received\n",
529      macgrp->rxbroadcastframes_g
530      );
531    DWMAC_PRINT_COUNTER(
532      "%" PRIu32 " good multicast frames received\n",
533      macgrp->rxmulticastframes_g
534      );
535    DWMAC_PRINT_COUNTER(
536      "%" PRIu32 " frames received with CRC error\n",
537      macgrp->rxcrcerror
538      );
539    DWMAC_PRINT_COUNTER(
540      "%" PRIu32 " frames received with alignment (dribble) error. Valid only"
541      " in 10/100 mode\n",
542      macgrp->rxalignmenterror
543      );
544    DWMAC_PRINT_COUNTER(
545      "%" PRIu32 " frames received with runt (<64 bytes and CRC error) error\n",
546      macgrp->rxrunterror
547      );
548    DWMAC_PRINT_COUNTER(
549      "%" PRIu32 " giant frames received with length (including CRC) greater "
550      "than %" PRIu16 " bytes (%" PRIu16 " bytes for VLAN tagged) and with CRC"
551      " error\n",
552      macgrp->rxjabbererror, giant_frame_size, giant_frame_size + 4
553      );
554    DWMAC_PRINT_COUNTER(
555      "%" PRIu32 " frames received with length less than 64 bytes, without any"
556      " errors\n",
557      macgrp->rxundersize_g
558      );
559    DWMAC_PRINT_COUNTER(
560      "%" PRIu32 " frames received with length greater than the maxsize (1,518"
561      " or 1,522 for VLAN tagged frames), without errors\n",
562      macgrp->rxoversize_g
563      );
564    DWMAC_PRINT_COUNTER(
565      "%" PRIu32 " good and bad frames received with length 64 bytes, exclusive"
566      " of preamble\n",
567      macgrp->rx64octets_gb
568      );
569    DWMAC_PRINT_COUNTER(
570      "%" PRIu32 " good and bad frames received with length between 65 and 127"
571      " (inclusive) bytes, exclusive of preamble\n",
572      macgrp->rx65to127octets_gb
573      );
574    DWMAC_PRINT_COUNTER(
575      "%" PRIu32 " good and bad frames received with length between 128 and 255"
576      " (inclusive) bytes, exclusive of preamble\n",
577      macgrp->rx128to255octets_gb
578      );
579    DWMAC_PRINT_COUNTER(
580      "%" PRIu32 " good and bad frames received with length between 256 and 511"
581      " (inclusive) bytes, exclusive of preamble\n",
582      macgrp->rx256to511octets_gb
583      );
584    DWMAC_PRINT_COUNTER(
585      "%" PRIu32 " good and bad frames received with length between 512 and "
586      "1,023 (inclusive) bytes, exclusive of preamble\n",
587      macgrp->rx512to1023octets_gb
588      );
589    DWMAC_PRINT_COUNTER(
590      "%" PRIu32 " good and bad frames received with length between 1,024 and"
591      " maxsize (inclusive) bytes, exclusive of preamble and retried frames\n",
592      macgrp->rx1024tomaxoctets_gb
593      );
594    DWMAC_PRINT_COUNTER(
595      "%" PRIu32 " good unicast frames received\n",
596      macgrp->rxunicastframes_g
597      );
598    DWMAC_PRINT_COUNTER(
599      "%" PRIu32 " frames received with length error (length type field not "
600      "equal to frame size), for all frames with valid length field\n",
601      macgrp->rxlengtherror
602      );
603    DWMAC_PRINT_COUNTER(
604      "%" PRIu32 " frames received with length field not equal to the valid "
605      "frame size (greater than 1,500 but less than 1,536)\n",
606      macgrp->rxoutofrangetype
607      );
608    DWMAC_PRINT_COUNTER(
609      "%" PRIu32 " good and valid PAUSE frames received\n",
610      macgrp->rxpauseframes
611      );
612    DWMAC_PRINT_COUNTER(
613      "%" PRIu32 " missed received frames due to FIFO overflow\n",
614      macgrp->rxfifooverflow
615      );
616    DWMAC_PRINT_COUNTER(
617      "%" PRIu32 " good and bad VLAN frames received\n",
618      macgrp->rxvlanframes_gb
619      );
620    DWMAC_PRINT_COUNTER(
621      "%" PRIu32 " frames received with error due to watchdog timeout error "
622      "(frames with a data load larger than 2,048 bytes)\n",
623      macgrp->rxwatchdogerror
624      );
625    DWMAC_PRINT_COUNTER(
626      "%" PRIu32 " frames received with Receive error or Frame Extension error"
627      " on the GMII or MII interface\n",
628      macgrp->rxrcverror
629      );
630    DWMAC_PRINT_COUNTER(
631      "%" PRIu32 " received good control frames\n",
632      macgrp->rxctrlframes_g
633      );
634
635    printf( "\n" );
636
637    DWMAC_PRINT_COUNTER(
638      "%" PRIu32 " good IPv4 datagrams received with the TCP, UDP, or ICMP "
639      "payload\n",
640      macgrp->rxipv4_gd_frms
641      );
642    DWMAC_PRINT_COUNTER(
643      "%" PRIu32 " IPv4 datagrams received with header (checksum, length, or "
644      "version mismatch) errors\n",
645      macgrp->rxipv4_hdrerr_frms
646      );
647    DWMAC_PRINT_COUNTER(
648      "%" PRIu32 " IPv4 datagram frames received that did not have a TCP, UDP, "
649      "or ICMP payload processed by the Checksum engine\n",
650      macgrp->rxipv4_nopay_frms
651      );
652    DWMAC_PRINT_COUNTER(
653      "%" PRIu32 " good IPv4 datagrams with fragmentation\n",
654      macgrp->rxipv4_frag_frms
655      );
656    DWMAC_PRINT_COUNTER(
657      "%" PRIu32 " good IPv4 datagrams received that had a UDP payload with "
658      "checksum disabled\n",
659      macgrp->rxipv4_udsbl_frms
660      );
661    DWMAC_PRINT_COUNTER(
662      "%" PRIu32 " good IPv6 datagrams received with TCP, UDP, or ICMP "
663      "payloads\n",
664      macgrp->rxipv6_gd_frms
665      );
666    DWMAC_PRINT_COUNTER(
667      "%" PRIu32 " IPv6 datagrams received with header errors (length or "
668      "version mismatch)\n",
669      macgrp->rxipv6_hdrerr_frms
670      );
671    DWMAC_PRINT_COUNTER(
672      "%" PRIu32 " IPv6 datagram frames received that did not have a TCP, UDP,"
673      " or ICMP payload. This includes all IPv6 datagrams with fragmentation"
674      " or security extension headers\n",
675      macgrp->rxipv6_nopay_frms
676      );
677    DWMAC_PRINT_COUNTER(
678      "%" PRIu32 " good IP datagrams with a good UDP payload. This counter is "
679      "not updated when the counter is incremented\n",
680      macgrp->rxudp_gd_frms
681      );
682    DWMAC_PRINT_COUNTER(
683      "%" PRIu32 " good IP datagrams whose UDP payload has a checksum error\n",
684      macgrp->rxudp_err_frms
685      );
686    DWMAC_PRINT_COUNTER(
687      "%" PRIu32 " good IP datagrams with a good TCP payload\n",
688      macgrp->rxtcp_gd_frms
689      );
690    DWMAC_PRINT_COUNTER(
691      "%" PRIu32 " good IP datagrams whose TCP payload has a checksum error\n",
692      macgrp->rxtcp_err_frms
693      );
694    DWMAC_PRINT_COUNTER(
695      "%" PRIu32 " good IP datagrams with a good ICMP payload\n",
696      macgrp->rxicmp_gd_frms
697      );
698    DWMAC_PRINT_COUNTER(
699      "%" PRIu32 " good IP datagrams whose ICMP payload has a checksum error\n",
700      macgrp->rxicmp_err_frms
701      );
702    DWMAC_PRINT_COUNTER(
703      "%" PRIu32 " bytes received in good IPv4 datagrams encapsulating TCP, UDP,"
704      " or ICMP data\n",
705      macgrp->rxipv4_gd_octets
706      );
707    DWMAC_PRINT_COUNTER(
708      "%" PRIu32 " bytes received in IPv4 datagrams with header errors (checksum,"
709      " length, version mismatch). The value in the Length field of IPv4 "
710      "header is used to update this counter\n",
711      macgrp->rxipv4_hdrerr_octets
712      );
713    DWMAC_PRINT_COUNTER(
714      "%" PRIu32 " bytes received in IPv4 datagrams that did not have a TCP, UDP"
715      ", or ICMP payload. The value in the IPv4 headers Length field is used"
716      " to update this counter\n",
717      macgrp->rxipv4_nopay_octets
718      );
719    DWMAC_PRINT_COUNTER(
720      "%" PRIu32 " bytes received in fragmented IPv4 datagrams. The value in the"
721      " IPv4 headers Length field is used to update this counter\n",
722      macgrp->rxipv4_frag_octets
723      );
724    DWMAC_PRINT_COUNTER(
725      "%" PRIu32 " bytes received in a UDP segment that had the UDP checksum "
726      "disabled. This counter does not count IP Header bytes\n",
727      macgrp->rxipv4_udsbl_octets
728      );
729    DWMAC_PRINT_COUNTER(
730      "%" PRIu32 " bytes received in good IPv6 datagrams encapsulating TCP, UDP "
731      "or ICMPv6 data\n",
732      macgrp->rxipv6_gd_octets
733      );
734    DWMAC_PRINT_COUNTER(
735      "%" PRIu32 " bytes received in IPv6 datagrams with header errors (length, "
736      "version mismatch). The value in the IPv6 headers Length field is used "
737      "to update this counter\n",
738      macgrp->rxipv6_hdrerr_octets
739      );
740    DWMAC_PRINT_COUNTER(
741      "%" PRIu32 " bytes received in IPv6 datagrams that did not have a TCP, UDP"
742      ", or ICMP payload. The value in the IPv6 headers Length field is used "
743      "to update this counter\n",
744      macgrp->rxipv6_nopay_octets
745      );
746    DWMAC_PRINT_COUNTER(
747      "%" PRIu32 " bytes received in a good UDP segment. This counter does not "
748      "count IP header bytes\n",
749      macgrp->rxudp_gd_octets
750      );
751    DWMAC_PRINT_COUNTER(
752      "%" PRIu32 " bytes received in a UDP segment that had checksum errors\n",
753      macgrp->rxudp_err_octets
754      );
755    DWMAC_PRINT_COUNTER(
756      "%" PRIu32 " bytes received in a good TCP segment\n",
757      macgrp->rxtcp_gd_octets
758      );
759    DWMAC_PRINT_COUNTER(
760      "%" PRIu32 " bytes received in a TCP segment with checksum errors\n",
761      macgrp->rxtcperroctets
762      );
763    DWMAC_PRINT_COUNTER(
764      "%" PRIu32 " bytes received in a good ICMP segment\n",
765      macgrp->rxicmp_gd_octets
766      );
767    DWMAC_PRINT_COUNTER(
768      "%" PRIu32 " bytes received in an ICMP segment with checksum errors\n",
769      macgrp->rxicmp_err_octets
770      );
771  }
772
773  if ( eno == 0 ) {
774    printf( "\nInterrupt counts:\n" );
775    DWMAC_PRINT_COUNTER( "%" PRIu32 " receive interrputs\n",
776                         self->stats.dma_irq_counts.receive
777                         );
778    DWMAC_PRINT_COUNTER( "%" PRIu32 " transmit interrupts\n",
779                         self->stats.dma_irq_counts.transmit
780                         );
781    DWMAC_PRINT_COUNTER( "%" PRIu32 " tx jabber interrupts\n",
782                         self->stats.dma_irq_counts.tx_jabber
783                         );
784    DWMAC_PRINT_COUNTER( "%" PRIu32 " rx overflow interrupts\n",
785                         self->stats.dma_irq_counts.rx_overflow
786                         );
787    DWMAC_PRINT_COUNTER( "%" PRIu32 " rx early interrupts\n",
788                         self->stats.dma_irq_counts.rx_early
789                         );
790    DWMAC_PRINT_COUNTER( "%" PRIu32 " rx buffer unavailable interrupts\n",
791                         self->stats.dma_irq_counts.rx_buf_unav
792                         );
793    DWMAC_PRINT_COUNTER( "%" PRIu32 " rx process stopped interrupts\n",
794                         self->stats.dma_irq_counts.rx_process_stopped
795                         );
796    DWMAC_PRINT_COUNTER( "%" PRIu32 " rx watchdog interrupts\n",
797                         self->stats.dma_irq_counts.rx_watchdog
798                         );
799    DWMAC_PRINT_COUNTER( "%" PRIu32 " tx early interrupts\n",
800                         self->stats.dma_irq_counts.tx_early
801                         );
802    DWMAC_PRINT_COUNTER( "%" PRIu32 " tx buffer unavailable interrupts\n",
803                         self->stats.dma_irq_counts.tx_buf_unav
804                         );
805    DWMAC_PRINT_COUNTER( "%" PRIu32 " tx process stopped interrupts\n",
806                         self->stats.dma_irq_counts.tx_process_stopped
807                         );
808    DWMAC_PRINT_COUNTER( "%" PRIu32 " tx underflow interrupts\n",
809                         self->stats.dma_irq_counts.tx_underflow
810                         );
811    DWMAC_PRINT_COUNTER( "%" PRIu32 " fatal bus error interrupts\n",
812                         self->stats.dma_irq_counts.fatal_bus_error
813                         );
814    DWMAC_PRINT_COUNTER( "%" PRIu32 " unhandled interrupts\n",
815                         self->stats.dma_irq_counts.unhandled
816                         );
817
818    printf( "\nRX DMA status counts:\n" );
819    DWMAC_PRINT_COUNTER( "%" PRIu32 " CRC errors\n",
820                         self->stats.desc_status_counts_rx.crc_error
821                         );
822    DWMAC_PRINT_COUNTER(
823      "%" PRIu32 " late collision when receing in half duplex mode\n",
824      self->stats.desc_status_counts_rx.late_collision
825      );
826    DWMAC_PRINT_COUNTER(
827      "%" PRIu32 " giant frame or timestamp or checksum error\n",
828      self->stats.desc_status_counts_rx.giant_frame
829      );
830
831    if ( self->stats.desc_status_counts_rx.watchdog_timeout != 0
832         || self->stats.desc_status_counts_rx.receive_error != 0 ) {
833      printf( "  IP Header or IP Payload:\n" );
834      DWMAC_PRINT_COUNTER( "%" PRIu32 " receive watchdog timeout\n",
835                           self->stats.desc_status_counts_rx.watchdog_timeout
836                           );
837      DWMAC_PRINT_COUNTER( "%" PRIu32 " receive error\n",
838                           self->stats.desc_status_counts_rx.receive_error
839                           );
840    }
841
842    DWMAC_PRINT_COUNTER( "%" PRIu32 " buffer overflows in MTL\n",
843                         self->stats.desc_status_counts_rx.overflow_error
844                         );
845    DWMAC_PRINT_COUNTER( "%" PRIu32 " descriptor buffers too small\n",
846                         self->stats.desc_status_counts_rx.descriptor_error
847                         );
848    DWMAC_PRINT_COUNTER( "%" PRIu32 " length errors\n",
849                         self->stats.desc_status_counts_rx.length_error
850                         );
851    DWMAC_PRINT_COUNTER( "%" PRIu32 " dribble bit errors\n",
852                         self->stats.desc_status_counts_rx.dribble_bit_error
853                         );
854    DWMAC_PRINT_COUNTER( "%" PRIu32 " vlan tags\n",
855                         self->stats.desc_status_counts_rx.vlan_tag
856                         );
857    DWMAC_PRINT_COUNTER( "%" PRIu32 " ethernet frames\n",
858                         self->stats.desc_status_counts_rx.ethernet_frames
859                         );
860    DWMAC_PRINT_COUNTER( "%" PRIu32 " destination address filter failures\n",
861                         self->stats.desc_status_counts_rx.dest_addr_fail
862                         );
863    DWMAC_PRINT_COUNTER( "%" PRIu32 " source addresss filter failures\n",
864                         self->stats.desc_status_counts_rx.source_addr_fail
865                         );
866
867    printf( "\nTX DMA status counts:\n" );
868    DWMAC_PRINT_COUNTER( "%" PRIu32 " jabber time-outs\n",
869                         self->stats.desc_status_counts_tx.jabber
870                         );
871    DWMAC_PRINT_COUNTER( "%" PRIu32 " frame flushes\n",
872                         self->stats.desc_status_counts_tx.frame_flushed
873                         );
874    DWMAC_PRINT_COUNTER( "%" PRIu32 " losses of carrier\n",
875                         self->stats.desc_status_counts_tx.losscarrier
876                         );
877    DWMAC_PRINT_COUNTER( "%" PRIu32 " no carriers\n",
878                         self->stats.desc_status_counts_tx.no_carrier
879                         );
880    DWMAC_PRINT_COUNTER( "%" PRIu32 " excessive collisions\n",
881                         self->stats.desc_status_counts_tx.excessive_collisions
882                         );
883    DWMAC_PRINT_COUNTER( "%" PRIu32 " excessive deferrals\n",
884                         self->stats.desc_status_counts_tx.excessive_deferral
885                         );
886    DWMAC_PRINT_COUNTER( "%" PRIu32 " underfolw errors\n",
887                         self->stats.desc_status_counts_tx.underflow
888                         );
889    DWMAC_PRINT_COUNTER( "%" PRIu32 " IP header error\n",
890                         self->stats.desc_status_counts_tx.ip_header_error
891                         );
892    DWMAC_PRINT_COUNTER( "%" PRIu32 " payload error\n",
893                         self->stats.desc_status_counts_rx.source_addr_fail
894                         );
895    DWMAC_PRINT_COUNTER(
896      "%" PRIu32 " MAC defers before transmission because of the presence of carrier\n",
897      self->stats.desc_status_counts_tx.deferred
898      );
899    DWMAC_PRINT_COUNTER( "%" PRIu32 " VLAN frames\n",
900                         self->stats.desc_status_counts_tx.vlan
901                         );
902
903    printf( "\nRX frame counts:\n" );
904    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames with errors\n",
905                         self->stats.frame_counts_rx.errors
906                         );
907    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames dropped\n",
908                         self->stats.frame_counts_rx.dropped
909                         );
910    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames good\n",
911                         self->stats.frame_counts_rx.frames_good
912                         );
913    DWMAC_PRINT_COUNTER( "%" PRIu32 " bytes in good frames\n",
914                         self->stats.frame_counts_rx.bytes_good
915                         );
916    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames good or bad\n",
917                         self->stats.frame_counts_rx.frames
918                         );
919    DWMAC_PRINT_COUNTER( "%" PRIu32 " DMA suspended\n",
920                         self->stats.frame_counts_rx.dma_suspended
921                         );
922
923    printf( "\nTX frame counts:\n" );
924    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames received from network stack\n",
925                         self->stats.frame_counts_tx.frames_from_stack
926                         );
927    DWMAC_PRINT_COUNTER( "%" PRIu32 " frames tranmitted to DMA\n",
928                         self->stats.frame_counts_tx.frames_to_dma
929                         );
930    DWMAC_PRINT_COUNTER( "%" PRIu32 " packets tranmitted to DMA\n",
931                         self->stats.frame_counts_tx.packets_to_dma
932                         );
933    DWMAC_PRINT_COUNTER( "%" PRIu32 " bytes tranmitted to DMA\n",
934                         self->stats.frame_counts_tx.bytes_to_dma
935                         );
936    DWMAC_PRINT_COUNTER( "%" PRIu32 " packet buffers regained from DMA\n",
937                         self->stats.frame_counts_tx.packets_tranmitted_by_DMA
938                         );
939    DWMAC_PRINT_COUNTER( "%" PRIu32 " packet errors\n",
940                         self->stats.frame_counts_tx.packet_errors
941                         );
942
943    printf( "\n" );
944
945#ifdef RTEMS_DEBUG
946    {
947      const dwmac_common_desc_ops *DESC_OPS =
948        (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
949
950      ( DESC_OPS->print_rx_desc )(
951        self->dma_rx,
952        (unsigned int) self->bsd_config->xbuf_count
953        );
954
955      ( DESC_OPS->print_tx_desc )(
956        self->dma_tx,
957        (unsigned int) self->bsd_config->xbuf_count
958        );
959    }
960#endif /* RTEMS_DEBUG */
961  }
962
963  return eno;
964}
965
966static inline unsigned int dwmac_increment(
967  const unsigned int value,
968  const unsigned int cycle )
969{
970  if ( value < cycle ) {
971    return value + 1;
972  } else {
973    return 0;
974  }
975}
976
977/* Receive task
978 * It handles receiving frames */
979static void dwmac_task_rx( void *arg )
980{
981  dwmac_common_context         *self           = arg;
982  dwmac_common_rx_frame_counts *counts         = &self->stats.frame_counts_rx;
983  const unsigned int            INDEX_MAX      =
984    (unsigned int) self->bsd_config->rbuf_count - 1U;
985  size_t                        frame_len_last = 0;
986  const dwmac_common_desc_ops  *DESC_OPS       =
987    (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
988  size_t                        segment_size;
989
990
991  while ( true ) {
992    rtems_event_set   events;
993    rtems_status_code sc = rtems_bsdnet_event_receive(
994      DWMAC_COMMON_EVENT_TASK_INIT
995      | DWMAC_COMMON_EVENT_TASK_STOP
996      | DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED,
997      RTEMS_EVENT_ANY | RTEMS_WAIT,
998      RTEMS_NO_TIMEOUT,
999      &events
1000      );
1001    assert( sc == RTEMS_SUCCESSFUL );
1002
1003    /* Stop the task */
1004    if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) {
1005      dwmac_core_dma_stop_rx( self );
1006      dwmac_disable_irq_rx( self );
1007
1008      /* Release all tx mbufs at the risk of data loss */
1009      ( DESC_OPS->release_rx_bufs )( self );
1010
1011      dwmac_control_request_complete( self );
1012
1013      /* Return to events reception without re-enabling the interrupts
1014       * The task needs a re-initialization to to resume work */
1015      continue;
1016    }
1017
1018    /* Ininitialize / Re-initialize reception handling */
1019    if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) {
1020      unsigned int index;
1021      dwmac_core_dma_stop_rx( self );
1022      ( DESC_OPS->release_rx_bufs )( self );
1023
1024      for ( index = 0; index <= INDEX_MAX; ++index ) {
1025        self->mbuf_addr_rx[index] = ( DESC_OPS->alloc_data_buf )( self );
1026        assert( self->mbuf_addr_rx[index] != NULL );
1027        ( DESC_OPS->init_rx_desc )( self, index );
1028      }
1029
1030      self->idx_rx   = 0;
1031      frame_len_last = 0;
1032
1033      /* Clear our interrupt statuses */
1034      dwmac_core_reset_dma_irq_status_rx( self );
1035
1036      dwmac_core_dma_start_rx( self );
1037
1038      dwmac_control_request_complete( self );
1039      events = events
1040               & (rtems_event_set) ( ~DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED );
1041    }
1042
1043    /* Handle the reception of one or more frames */
1044    if ( ( events & DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED ) != 0 ) {
1045      unsigned int idx = self->idx_rx;
1046
1047      /* Only handle frames for which we own the DMA descriptor */
1048      while ( ( DESC_OPS->am_i_rx_owner )( self, idx ) ) {
1049        struct mbuf                 *p_m_new;
1050        dwmac_common_rx_frame_status status;
1051        unsigned int                 idx_next = dwmac_increment(
1052          self->idx_rx, INDEX_MAX );
1053
1054        /* Assign the next index (with wrap around) */
1055        self->idx_rx = idx_next;
1056
1057        /* read the status of the incoming frame */
1058        status = ( DESC_OPS->rx_status )( self, idx );
1059
1060        if ( status == DWMAC_COMMON_RX_FRAME_STATUS_DISCARD
1061             || status == DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE ) {
1062          DWMAC_PRINT_DBG(
1063            "rx discarded: %02u\n",
1064            idx
1065            );
1066          ++counts->errors;
1067
1068          /* simply re-initialize the DMA descriptor */
1069          ( DESC_OPS->init_rx_desc )( self, idx );
1070        } else if ( status == DWMAC_COMMON_RX_FRAME_STATUS_LLC_SNAP ) {
1071          DWMAC_PRINT_DBG(
1072            "rx dropped llc snap: %02u\n",
1073            idx
1074            );
1075          ++counts->dropped;
1076
1077          /* simply re-initialize the DMA descriptor */
1078          ( DESC_OPS->init_rx_desc )( self, idx );
1079        } else {
1080          /* Before actually handling the valid frame, make sure we get a new
1081           * mbuf */
1082          p_m_new = ( DESC_OPS->alloc_data_buf )( self );
1083
1084          if ( p_m_new != NULL ) {
1085            bool         is_first_seg;
1086            bool         is_last_seg;
1087            struct mbuf *p_m;
1088            uint32_t     frame_len = ( DESC_OPS->get_rx_frame_len )(
1089              self, idx );
1090
1091            /* frame_len is the cummulated size of all segments of a frame.
1092             * But what we need is the size of the single segment */
1093            is_first_seg = ( DESC_OPS->is_first_rx_segment )( self, idx );
1094            is_last_seg  = ( DESC_OPS->is_last_rx_segment )( self, idx );
1095
1096            if ( is_first_seg ) {
1097              segment_size = frame_len;
1098            } else {
1099              segment_size = frame_len - frame_len_last;
1100            }
1101
1102            frame_len_last          = frame_len;
1103
1104            p_m                     = self->mbuf_addr_rx[idx];
1105            self->mbuf_addr_rx[idx] = p_m_new;
1106
1107            /* Initialize the DMA descriptor with the new mbuf */
1108            ( DESC_OPS->init_rx_desc )( self, idx );
1109
1110            if ( p_m != NULL ) {
1111              /* Ethernet header */
1112              struct ether_header *eh = mtod( p_m, struct ether_header * );
1113              int                  sz = (int) segment_size;
1114
1115              rtems_cache_invalidate_multiple_data_lines(
1116                eh, segment_size );
1117
1118              /* Discard Ethernet header and CRC */
1119              if ( is_last_seg ) {
1120                sz -= ( ETHER_HDR_LEN + ETHER_CRC_LEN );
1121              } else {
1122                sz -= ETHER_HDR_LEN;
1123              }
1124
1125              /* Update mbuf */
1126              p_m->m_len        = sz;
1127              p_m->m_pkthdr.len = sz;
1128              p_m->m_data       = mtod( p_m, char * ) + ETHER_HDR_LEN;
1129
1130              DWMAC_COMMON_DSB();
1131
1132              DWMAC_PRINT_DBG(
1133                "rx: %02u: %u %s%s\n",
1134                idx,
1135                segment_size,
1136                ( is_first_seg ) ? ( "F" ) : ( "" ),
1137                ( is_last_seg ) ? ( "L" ) : ( "" )
1138                );
1139
1140              ether_input( &self->arpcom.ac_if, eh, p_m );
1141
1142              ++counts->frames_good;
1143              counts->bytes_good += (uint32_t) p_m->m_len;
1144            } else {
1145              DWMAC_PRINT_DBG( "rx: %s: Inconsistent Rx descriptor chain\n",
1146                               self->arpcom.ac_if.if_name );
1147              ++counts->dropped;
1148            }
1149          } else {
1150            /* We have to discard the received frame because we did not get a new
1151             * mbuf to replace the frame's mbuf. */
1152            ++counts->dropped;
1153
1154            /* simply re-initialize the DMA descriptor with the existing mbuf */
1155            ( DESC_OPS->init_rx_desc )( self, idx );
1156            DWMAC_PRINT_DBG(
1157              "rx dropped: %02u\n",
1158              idx
1159              );
1160          }
1161        }
1162
1163        if ( ( self->dmagrp->status & DMAGRP_STATUS_RU ) != 0 ) {
1164          /* The receive DMA is suspended and needs to get restarted */
1165          dwmac_core_dma_restart_rx( self );
1166          DWMAC_PRINT_DBG(
1167            "rx DMA restart: %02u\n",
1168            idx
1169            );
1170          ++counts->dma_suspended;
1171          self->dmagrp->status = DMAGRP_STATUS_RU;
1172        }
1173
1174        idx = idx_next;
1175        ++counts->frames;
1176      }
1177
1178      /* Clear interrupt */
1179      self->dmagrp->status = DMAGRP_STATUS_RI;
1180    }
1181
1182    /* Re-enable the IRQs */
1183    dwmac_enable_irq_rx( self );
1184  }
1185}
1186
1187static struct mbuf *dwmac_next_fragment(
1188  struct ifnet *ifp,
1189  struct mbuf  *m,
1190  bool         *is_first,
1191  bool         *is_last,
1192  size_t       *size ) {
1193  struct mbuf *n  = NULL;
1194  int          sz = 0;
1195
1196
1197  while ( true ) {
1198    if ( m == NULL ) {
1199      /* Dequeue first fragment of the next frame */
1200      IF_DEQUEUE( &ifp->if_snd, m );
1201
1202      /* Empty queue? */
1203      if ( m == NULL ) {
1204        return m;
1205      }
1206
1207      /* The sum of all fragments lengths must fit into one
1208       * ethernet transfer unit */
1209      assert( ETHER_MAX_LEN >= m->m_pkthdr.len );
1210      *is_first = true;
1211    }
1212
1213    /* Get fragment size */
1214    sz = m->m_len;
1215
1216    if ( sz > 0 ) {
1217      /* Now we have a not empty fragment */
1218      break;
1219    } else {
1220      /* Discard empty fragments */
1221      m = m_free( m );
1222    }
1223  }
1224
1225  /* Set fragment size */
1226  *size = (size_t) sz;
1227
1228  /* Discard empty successive fragments */
1229  n = m->m_next;
1230
1231  while ( n != NULL && n->m_len <= 0 ) {
1232    n = m_free( n );
1233  }
1234
1235  m->m_next = n;
1236
1237  /* Is our fragment the last in the frame? */
1238  if ( n == NULL ) {
1239    *is_last = true;
1240  } else {
1241    *is_last = false;
1242  }
1243
1244  return m;
1245}
1246
1247static int dwmac_update_autonegotiation_params( dwmac_common_context *self )
1248{
1249  int      eno      = 0;
1250  uint32_t value    = self->macgrp->mac_configuration;
1251  int      media    = 0;
1252  bool     media_ok = dwmac_if_media_status(
1253    self, &media, self->MDIO_BUS_ADDR );
1254
1255
1256  if ( media_ok ) {
1257    /* only ethernet supported, so far */
1258    if ( IFM_ETHER == IFM_TYPE( media ) ) {
1259      if ( IFM_NONE != IFM_SUBTYPE( media ) ) {
1260        if ( IFM_FDX & media ) {
1261          /* Enable duplex mode */
1262          value |= MACGRP_MAC_CONFIGURATION_DM;
1263        } else {
1264          /* Disable duplex mode */
1265          value &= ~MACGRP_MAC_CONFIGURATION_DM;
1266        }
1267
1268        switch ( IFM_SUBTYPE( media ) ) {
1269          case IFM_10_T:
1270
1271            /* Set RMII/RGMII speed to 10Mbps */
1272            value &= ~MACGRP_MAC_CONFIGURATION_FES;
1273
1274            /* MII 10/100 Mbps */
1275            value |= MACGRP_MAC_CONFIGURATION_PS;
1276            break;
1277          case IFM_100_TX:
1278
1279            /* Set RMII/RGMII speed to 100Mbps */
1280            value |= MACGRP_MAC_CONFIGURATION_FES;
1281
1282            /* MII 10/100 Mbps */
1283            value |= MACGRP_MAC_CONFIGURATION_PS;
1284            break;
1285          case IFM_1000_T:
1286
1287            /* RMII/RGMII speed irrelevant for 1000baseT */
1288            value &= ~MACGRP_MAC_CONFIGURATION_FES;
1289
1290            /* GMII 1000 Mbps */
1291            value &= ~MACGRP_MAC_CONFIGURATION_PS;
1292            break;
1293          default:
1294            eno = ENOTSUP;
1295            break;
1296        }
1297      } else {
1298        eno = ENOTSUP;
1299      }
1300    } else {
1301      eno = ENOTSUP;
1302    }
1303  } else {
1304    eno = ENOTSUP;
1305  }
1306
1307  if ( eno == 0 ) {
1308    self->macgrp->mac_configuration = value;
1309  }
1310
1311  return eno;
1312}
1313
1314/* Transmit task
1315 * It handles transmitting frames */
1316static void dwmac_task_tx( void *arg )
1317{
1318  dwmac_common_context        *self               = arg;
1319  unsigned int                 idx_transmit       = 0;
1320  unsigned int                 idx_transmit_first = 0;
1321  unsigned int                 idx_transmitted    = 0;
1322  unsigned int                 idx_release        = 0;
1323  struct mbuf                 *p_m                = NULL;
1324  bool                         is_first           = false;
1325  bool                         is_last            = false;
1326  size_t                       size               = 0;
1327  const unsigned int           INDEX_MAX          =
1328    (unsigned int) self->bsd_config->xbuf_count - 1U;
1329  const dwmac_common_dma_ops  *DMA_OPS            =
1330    (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma;
1331  const dwmac_common_desc_ops *DESC_OPS           =
1332    (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
1333  const dwmac_callback_cfg    *CALLBACK           = &self->CFG->CALLBACK;
1334
1335
1336  while ( true ) {
1337    rtems_event_set   events = 0;
1338    rtems_status_code sc     = rtems_bsdnet_event_receive(
1339      DWMAC_COMMON_EVENT_TASK_INIT
1340      | DWMAC_COMMON_EVENT_TASK_STOP
1341      | DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME
1342      | DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED
1343      | DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD
1344      | DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE,
1345      RTEMS_EVENT_ANY | RTEMS_WAIT,
1346      RTEMS_NO_TIMEOUT,
1347      &events
1348      );
1349    assert( sc == RTEMS_SUCCESSFUL );
1350
1351    while( events != 0 ) {
1352      /* Handle a status change of the ethernet PHY */
1353      if ( ( events & DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE ) != 0 ) {
1354        events &= ~DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE;
1355        dwmac_common_phy_status_counts *counts     =
1356          &self->stats.phy_status_counts;
1357        dwmac_phy_event                 phy_events = 0;
1358        int                             eno;
1359
1360        /* Get tripped PHY events */
1361        eno = CALLBACK->phy_events_get(
1362          self->arg,
1363          &phy_events
1364          );
1365
1366        if ( eno == 0 ) {
1367          /* Clear the PHY events */
1368          eno = CALLBACK->phy_event_clear( self->arg );
1369        }
1370
1371        if ( eno == 0 ) {
1372          if ( ( phy_events & PHY_EVENT_LINK_DOWN ) != 0 ) {
1373            ++counts->link_down;
1374          }
1375
1376          if ( ( phy_events & PHY_EVENT_LINK_UP ) != 0 ) {
1377            ++counts->link_up;
1378
1379            /* A link up events means that we have a new connection.
1380            * Thus the autonegotiation paremeters must get updated */
1381            (void) dwmac_update_autonegotiation_params( self );
1382          }
1383        }
1384
1385        assert( eno == 0 );
1386      }
1387
1388      /* Stop the task */
1389      if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) {
1390        dwmac_core_dma_stop_tx( self );
1391        dwmac_disable_irq_tx_all( self );
1392
1393        /* Release all tx mbufs at the risk of data loss */
1394        ( DESC_OPS->release_tx_bufs )( self );
1395
1396        dwmac_control_request_complete( self );
1397
1398        /* Return to events reception without re-enabling the interrupts
1399        * The task needs a re-initialization to to resume work */
1400        events = 0;
1401        continue;
1402      }
1403
1404      /* Ininitialize / Re-initialize transmission handling */
1405      if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) {
1406        events &= ~DWMAC_COMMON_EVENT_TASK_INIT;
1407        (void) dwmac_update_autonegotiation_params( self );
1408        dwmac_core_dma_stop_tx( self );
1409        ( DESC_OPS->release_tx_bufs )( self );
1410        idx_transmit       = 0;
1411        idx_transmit_first = 0;
1412        idx_transmitted    = 0;
1413        idx_release        = 0;
1414        p_m                = NULL;
1415        is_first           = false;
1416        is_last            = false;
1417        size               = 0;
1418        ( DESC_OPS->init_tx_desc )( self );
1419        dwmac_core_dma_start_tx( self );
1420        dwmac_core_dma_restart_tx( self );
1421
1422        /* Clear our interrupt statuses */
1423        dwmac_core_reset_dma_irq_status_tx( self );
1424        dwmac_enable_irq_tx_default( self );
1425
1426        dwmac_control_request_complete( self );
1427      }
1428
1429      /* Try to bump up the dma threshold due to a failure */
1430      if ( ( events & DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD ) != 0 ) {
1431        events &= ~DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD;
1432        if ( self->dma_threshold_control
1433            != DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
1434            && self->dma_threshold_control <= 256 ) {
1435          self->dma_threshold_control += 64;
1436          ( DMA_OPS->dma_mode )(
1437            self,
1438            self->dma_threshold_control,
1439            DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
1440            );
1441        }
1442      }
1443
1444      /* Handle one or more transmitted frames */
1445      if ( ( events & DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED ) != 0 ) {
1446        events &= ~DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED;
1447        dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
1448        dwmac_disable_irq_tx_transmitted( self );
1449
1450        /* Next index to be transmitted */
1451        unsigned int idx_transmitted_next = dwmac_increment(
1452          idx_transmitted, INDEX_MAX );
1453
1454        /* Free consumed fragments */
1455        if( idx_release != idx_transmitted_next
1456            && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) {
1457          while ( idx_release != idx_transmitted_next
1458                  && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) {
1459            /* Status handling per packet */
1460            if ( ( DESC_OPS->get_tx_ls )( self, idx_release ) ) {
1461              int status = ( DESC_OPS->tx_status )(
1462                self, idx_release
1463                );
1464
1465              if ( status == 0 ) {
1466                ++counts->packets_tranmitted_by_DMA;
1467              } else {
1468                ++counts->packet_errors;
1469              }
1470            }
1471
1472            DWMAC_PRINT_DBG(
1473              "tx: release %u\n",
1474              idx_release
1475              );
1476
1477            /* Release the DMA descriptor */
1478            ( DESC_OPS->release_tx_desc )( self, idx_release );
1479
1480            /* Release mbuf */
1481            m_free( self->mbuf_addr_tx[idx_release] );
1482            self->mbuf_addr_tx[idx_release] = NULL;
1483
1484            /* Next release index */
1485            idx_release = dwmac_increment(
1486              idx_release, INDEX_MAX );
1487          }
1488          if ( ( self->arpcom.ac_if.if_flags & IFF_OACTIVE ) != 0 ) {
1489            /* The last tranmission has been incomplete
1490            * (for example due to lack of DMA descriptors).
1491            * Continue it now! */
1492            events |= DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME;
1493          }
1494        } else {
1495          /* Clear transmit interrupt status */
1496          self->dmagrp->status = DMAGRP_STATUS_TI;
1497          /* Get re-activated by the next interrupt */
1498          dwmac_enable_irq_tx_transmitted( self );
1499        }
1500      }
1501
1502      /* There are one or more frames to be transmitted. */
1503      if ( ( events & DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME ) != 0 ) {
1504        events &= ~DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME;
1505        dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx;
1506
1507        if ( p_m != NULL ) {
1508          /* This frame will get re-counted */
1509          --counts->frames_from_stack;
1510        }
1511
1512        while ( true ) {
1513          unsigned int idx = dwmac_increment(
1514            idx_transmit, INDEX_MAX );
1515
1516          p_m = dwmac_next_fragment(
1517            &self->arpcom.ac_if,
1518            p_m,
1519            &is_first,
1520            &is_last,
1521            &size
1522            );
1523
1524          /* New fragment? */
1525          if ( p_m != NULL ) {
1526            ++counts->frames_from_stack;
1527
1528            /* Queue full? */
1529            if ( idx == idx_release ) {
1530              DWMAC_PRINT_DBG( "tx: full queue: 0x%08x\n", p_m );
1531
1532              /* The queue is full, wait for transmitted interrupt */
1533              break;
1534            }
1535
1536            /* Set the transfer data */
1537            rtems_cache_flush_multiple_data_lines(
1538              mtod( p_m, const void * ),
1539              size
1540              );
1541
1542            ( DESC_OPS->prepare_tx_desc )(
1543              self,
1544              idx_transmit,
1545              is_first,
1546              size,
1547              mtod( p_m, const void * )
1548              );
1549            self->mbuf_addr_tx[idx_transmit] = p_m;
1550
1551            ++counts->frames_to_dma;
1552            counts->bytes_to_dma += size;
1553            DWMAC_PRINT_DBG(
1554              "tx: %02" PRIu32 ": %u %s%s\n",
1555              idx_transmit, size,
1556              ( is_first != false ) ? ( "F" ) : ( "" ),
1557              ( is_last != false ) ? ( "L" ) : ( "" )
1558
1559              );
1560
1561            if ( is_first ) {
1562              idx_transmit_first = idx_transmit;
1563              is_first           = false;
1564            } else {
1565              /* To avoid race condition */
1566              ( DESC_OPS->release_tx_ownership )( self, idx_transmit );
1567            }
1568
1569            if ( is_last ) {
1570              /* Interrupt on completition only for the latest fragment */
1571              ( DESC_OPS->close_tx_desc )( self, idx_transmit );
1572
1573              /* To avoid race condition */
1574              ( DESC_OPS->release_tx_ownership )( self, idx_transmit_first );
1575              idx_transmitted = idx_transmit;
1576
1577              if ( ( self->dmagrp->status & DMAGRP_STATUS_TU ) != 0 ) {
1578                /* Re-enable the tranmit DMA */
1579                dwmac_core_dma_restart_tx( self );
1580                DWMAC_PRINT_DBG(
1581                  "tx DMA restart: %02u\n",
1582                  idx_transmit_first
1583                  );
1584              }
1585            }
1586
1587            /* Next transmit index */
1588            idx_transmit = idx;
1589
1590            if ( is_last ) {
1591              ++counts->packets_to_dma;
1592            }
1593
1594            /* Next fragment of the frame */
1595            p_m = p_m->m_next;
1596          } else {
1597            /* Nothing to transmit */
1598            break;
1599          }
1600        }
1601
1602        /* No more packets and fragments? */
1603        if ( p_m == NULL ) {
1604          /* Interface is now inactive */
1605          self->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
1606        } else {
1607          /* There are more packets pending to be sent,
1608          * but we have run out of DMA descriptors.
1609          * We will continue sending once descriptors
1610          * have been freed due to a transmitted interupt */
1611          DWMAC_PRINT_DBG( "tx: transmission incomplete\n" );
1612          events |= DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED;
1613        }
1614
1615        /* TODO: Add handling */
1616      }
1617
1618      DWMAC_PRINT_DBG( "tx: enable transmit interrupts\n" );
1619    }
1620  }
1621}
1622
1623/* Major driver initialization method. Gets called
1624 * by the network stack automatically */
1625static void dwmac_if_interface_init( void *arg )
1626{
1627  (void) arg;
1628}
1629
1630static void dwmac_if_set_promiscous_mode(
1631  dwmac_common_context *self,
1632  const bool            enabled )
1633{
1634  if ( enabled ) {
1635    /* Enable promiscuos mode */
1636    self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_PR;
1637  } else {
1638    /* Hash filter or perfect match */
1639    self->macgrp->mac_frame_filter &= ~MACGRP_MAC_FRAME_FILTER_PR;
1640    self->macgrp->mac_frame_filter &= ~MACGRP_MAC_FRAME_FILTER_HUC;
1641    self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HPF;
1642  }
1643}
1644
1645static int dwmac_create_dma_desc_rings( dwmac_common_context *self )
1646{
1647  int                          eno      = 0;
1648  const dwmac_common_desc_ops *DESC_OPS =
1649    (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
1650
1651
1652  /* create and initialize the Rx/Tx descriptors */
1653  eno = ( DESC_OPS->create_rx_desc )( self );
1654
1655  if ( eno == 0 ) {
1656    eno = ( DESC_OPS->create_tx_desc )( self );
1657  }
1658
1659  return eno;
1660}
1661
1662static int dwmac_destroy_dma_desc_rings( dwmac_common_context *self )
1663{
1664  int                          eno      = 0;
1665  const dwmac_common_desc_ops *DESC_OPS =
1666    (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
1667
1668
1669  /* Free the Rx/Tx descriptors and the data buffers */
1670  eno = ( DESC_OPS->destroy_rx_desc )( self );
1671
1672  if ( eno == 0 ) {
1673    eno = ( DESC_OPS->destroy_tx_desc )( self );
1674  }
1675
1676  return eno;
1677}
1678
1679static int dwmac_init_dma_engine( dwmac_common_context *self )
1680{
1681  uint32_t                     pbl                  =
1682    DWMAC_DMA_BUS_MODE_PBL_DEFAULT;
1683  uint32_t                     fixed_burst          =
1684    DWMAC_DMA_BUS_MODE_FB_DEFAULT;
1685  uint32_t                     mixed_burst          =
1686    DWMAC_DMA_BUS_MODE_MIXED_BURSTS_DEFAULT;
1687  uint32_t                     burst_len_4_support  =
1688    DWMAC_DMA_AXI_BURST_LENGTH_4_DEFAULT;
1689  uint32_t                     burst_len_8_support  =
1690    DWMAC_DMA_AXI_BURST_LENGTH_8_DEFAULT;
1691  uint32_t                     burst_len_16_support =
1692    DWMAC_DMA_AXI_BURST_LENGTH_16_DEFAULT;
1693  uint32_t                     burst_boundary       =
1694    DWMAC_DMA_AXI_BURST_BOUNDARY_DEFAULT;
1695  const dwmac_common_dma_ops  *DMA_OPS              =
1696    (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma;
1697  const dwmac_common_desc_ops *DESC_OPS             =
1698    (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops;
1699
1700
1701  /* The DMA configuration is optional */
1702  if ( self->CFG->DMA_CFG != NULL ) {
1703    const dwmac_dma_cfg *DMA_CFG = self->CFG->DMA_CFG;
1704    pbl                  = DMA_CFG->bus_mode_burst_length;
1705    fixed_burst          = DMA_CFG->bus_mode_burst_mode;
1706    mixed_burst          = DMA_CFG->bus_mode_burst_mixed;
1707    burst_len_4_support  = DMA_CFG->axi_burst_length_4_support;
1708    burst_len_8_support  = DMA_CFG->axi_burst_length_8_support;
1709    burst_len_16_support = DMA_CFG->axi_burst_length_16_support;
1710    burst_boundary       = DMA_CFG->axi_burst_boundary;
1711  }
1712
1713  return ( DMA_OPS->init )(
1714    self,
1715    pbl,
1716    fixed_burst,
1717    mixed_burst,
1718    ( DESC_OPS->use_enhanced_descs )( self ),
1719    burst_len_4_support,
1720    burst_len_8_support,
1721    burst_len_16_support,
1722    burst_boundary,
1723    &self->dma_tx[0],
1724    &self->dma_rx[0]
1725    );
1726}
1727
1728static void dwmac_dma_operation_mode( dwmac_common_context *self )
1729{
1730  const dwmac_common_dma_ops *DMA_OPS =
1731    (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma;
1732
1733
1734  if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_TXOESEL ) != 0 ) {
1735    ( DMA_OPS->dma_mode )(
1736      self,
1737      DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD,
1738      DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
1739      );
1740    self->dma_threshold_control = DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD;
1741  } else {
1742    ( DMA_OPS->dma_mode )(
1743      self,
1744      self->dma_threshold_control,
1745      DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD
1746      );
1747  }
1748}
1749
1750static void dwmac_mmc_setup( dwmac_common_context *self )
1751{
1752  /* Mask MMC irq, counters are managed in HW and registers
1753   * are not cleared on each READ eventually. */
1754
1755  /* No MAC Management Counters available */
1756  assert( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 );
1757
1758  if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 ) {
1759    self->macgrp->mmc_control = MACGRP_MMC_CONTROL_CNTRST;
1760  }
1761}
1762
1763static int dwmac_if_up_or_down(
1764  dwmac_common_context *self,
1765  const bool            up )
1766{
1767  int                          eno      = 0;
1768  rtems_status_code            sc       = RTEMS_SUCCESSFUL;
1769  struct ifnet                *ifp      = &self->arpcom.ac_if;
1770  const dwmac_callback_cfg    *CALLBACK = &self->CFG->CALLBACK;
1771  const dwmac_common_core_ops *CORE_OPS =
1772    (const dwmac_common_core_ops *) self->CFG->MAC_OPS->core;
1773
1774
1775  if ( up && self->state == DWMAC_COMMON_STATE_DOWN ) {
1776    eno = CALLBACK->nic_enable( self->arg );
1777
1778    if ( eno == 0 ) {
1779      eno = CALLBACK->phy_enable( self->arg );
1780    }
1781
1782    if ( eno == 0 ) {
1783      eno = CALLBACK->phy_event_enable(
1784        self->arg,
1785        PHY_EVENT_LINK_DOWN
1786        | PHY_EVENT_LINK_UP
1787        );
1788    }
1789
1790    if ( eno == 0 ) {
1791      eno = dwmac_create_dma_desc_rings( self );
1792    }
1793
1794    if ( eno == 0 ) {
1795      eno = dwmac_init_dma_engine( self );
1796    }
1797
1798    if ( eno == 0 ) {
1799      /* Copy the MAC addr into the HW  */
1800      ( CORE_OPS->set_umac_addr )( self, self->arpcom.ac_enaddr, 0 );
1801
1802      eno = ( CALLBACK->bus_setup )( self->arg );
1803    }
1804
1805    if ( eno == 0 ) {
1806      /* Initialize the MAC Core */
1807      ( CORE_OPS->core_init )( self );
1808
1809      /* Enable the MAC Rx/Tx */
1810      dwmac_core_set_mac( self, true );
1811
1812      /* Set the HW DMA mode and the COE */
1813      dwmac_dma_operation_mode( self );
1814
1815      /* Set up mmc counters */
1816      dwmac_mmc_setup( self );
1817
1818#ifdef BSP_FEATURE_IRQ_EXTENSION
1819      /* Install interrupt handler */
1820      sc = rtems_interrupt_handler_install(
1821        self->CFG->IRQ_EMAC,
1822        "Ethernet",
1823        RTEMS_INTERRUPT_UNIQUE,
1824        dwmac_core_dma_interrupt,
1825        self
1826        );
1827#else
1828      sc = RTEMS_NOT_IMPLEMENTED;
1829#endif
1830      eno = rtems_status_code_to_errno( sc );
1831    }
1832
1833    if ( eno == 0 ) {
1834      /* Start the ball rolling ... */
1835      eno = dwmac_control_request(
1836        self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_INIT );
1837    }
1838
1839    if ( eno == 0 ) {
1840      eno = dwmac_control_request(
1841        self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_INIT );
1842    }
1843
1844    if ( eno == 0 ) {
1845      dwmac_core_dma_start_rx( self );
1846
1847      /* Start the phy */
1848      eno = ( CALLBACK->phy_start )( self->arg );
1849    }
1850
1851    if ( eno == 0 ) {
1852      self->state = DWMAC_COMMON_STATE_UP;
1853    } else {
1854      ifp->if_flags &= ~IFF_UP;
1855      (void) dwmac_control_request(
1856        self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_STOP );
1857      (void) dwmac_control_request(
1858        self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_STOP );
1859#ifdef BSP_FEATURE_IRQ_EXTENSION
1860      (void) rtems_interrupt_handler_remove(
1861        self->CFG->IRQ_EMAC,
1862        dwmac_core_dma_interrupt,
1863        self
1864        );
1865#endif
1866      (void) ( CALLBACK->phy_stop )( self->arg );
1867      (void) ( CALLBACK->phy_disable )( self->arg );
1868
1869      /* Disable the MAC Rx/Tx */
1870      dwmac_core_set_mac( self, false );
1871      (void) ( CALLBACK->nic_disable )( self->arg );
1872      (void) dwmac_destroy_dma_desc_rings( self );
1873    }
1874  } else if ( !up && self->state == DWMAC_COMMON_STATE_UP ) {
1875    if ( eno == 0 ) {
1876      eno = dwmac_control_request(
1877        self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_STOP );
1878    }
1879
1880    if ( eno == 0 ) {
1881      eno = dwmac_control_request(
1882        self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_STOP );
1883    }
1884
1885    if ( eno == 0 ) {
1886#ifdef BSP_FEATURE_IRQ_EXTENSION
1887      sc = rtems_interrupt_handler_remove(
1888        self->CFG->IRQ_EMAC,
1889        dwmac_core_dma_interrupt,
1890        self
1891        );
1892#else
1893      sc = RTEMS_NOT_IMPLEMENTED;
1894#endif
1895      eno = rtems_status_code_to_errno( sc );
1896    }
1897
1898    if ( eno == 0 ) {
1899      eno = ( CALLBACK->phy_stop )( self->arg );
1900    }
1901
1902    if ( eno == 0 ) {
1903      eno = ( CALLBACK->phy_disable )( self->arg );
1904    }
1905
1906    if ( eno == 0 ) {
1907      /* Disable the MAC Rx/Tx */
1908      dwmac_core_set_mac( self, false );
1909
1910      eno = CALLBACK->nic_disable( self->arg );
1911    }
1912
1913    if ( eno == 0 ) {
1914      eno = dwmac_destroy_dma_desc_rings( self );
1915    }
1916
1917    if ( eno == 0 ) {
1918      /* Reset counters to be printed */
1919      memset( &self->stats, 0, sizeof( dwmac_common_stats ) );
1920
1921      /* Change state */
1922      self->state = DWMAC_COMMON_STATE_DOWN;
1923    }
1924  }
1925
1926  return eno;
1927}
1928
1929/* Get commands executed by the driver. This method gets called
1930 * automatically from the network stack */
1931static int dwmac_if_interface_ioctl(
1932  struct ifnet   *ifp,
1933  ioctl_command_t cmd,
1934  caddr_t         data )
1935{
1936  dwmac_common_context *self = ifp->if_softc;
1937  int                   eno  = 0;
1938
1939
1940  switch ( cmd ) {
1941    case SIOCGIFMEDIA:
1942    case SIOCSIFMEDIA:
1943      rtems_mii_ioctl( &self->mdio, self, cmd, (int *) data );
1944      break;
1945    case SIOCGIFADDR:
1946    case SIOCSIFADDR:
1947      ether_ioctl( ifp, cmd, data );
1948      break;
1949    case SIOCSIFFLAGS:
1950      eno = dwmac_if_up_or_down( self, ( ifp->if_flags & IFF_UP ) != 0 );
1951
1952      if ( eno == 0 && ( ifp->if_flags & IFF_UP ) != 0 ) {
1953        dwmac_if_set_promiscous_mode( self, ( ifp->if_flags & IFF_PROMISC )
1954                                      != 0 );
1955      } else {
1956        assert( eno == 0 );
1957      }
1958
1959      break;
1960    case SIOCADDMULTI:
1961    case SIOCDELMULTI:
1962#ifndef COMMENTED_OUT
1963      eno = ENOTSUP;
1964#else /* COMMENTED_OUT */
1965      {
1966        struct ifreq                *ifr      = (struct ifreq *) data;
1967        const dwmac_common_core_ops *CORE_OPS =
1968          (const dwmac_common_core_ops *) self->CFG->MAC_OPS->core;
1969        ( CORE_OPS->set_hash_filter )( self, cmd == SIOCADDMULTI, ifr );
1970      }
1971#endif /* COMMENTED_OUT */
1972      break;
1973    case SIO_RTEMS_SHOW_STATS:
1974      eno = dwmac_if_interface_stats( self );
1975      break;
1976    default:
1977      eno = EINVAL;
1978      break;
1979  }
1980
1981  return eno;
1982}
1983
1984/* Method called by the network stack if there are frames to be transmitted */
1985static void dwmac_if_interface_start( struct ifnet *ifp )
1986{
1987  rtems_status_code     sc;
1988  dwmac_common_context *self = ifp->if_softc;
1989
1990
1991  /* Mark that we are transmitting */
1992  ifp->if_flags |= IFF_OACTIVE;
1993
1994  if ( self->state == DWMAC_COMMON_STATE_UP ) {
1995    /* Wake up our task */
1996    sc = rtems_bsdnet_event_send( self->task_id_tx,
1997                                  DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME );
1998    assert( sc == RTEMS_SUCCESSFUL );
1999  }
2000}
2001
2002static int dwmac_if_clk_csr_set(
2003  const uint32_t        gmii_clk_rate,
2004  dwmac_common_context *self )
2005{
2006  int eno = 0;
2007
2008
2009  if ( gmii_clk_rate < DWCGNAC3504_CSR_F_35M ) {
2010    self->csr_clock = DWCGNAC3504_CSR_20_35M;
2011  } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_35M )
2012              && ( gmii_clk_rate < DWCGNAC3504_CSR_F_60M ) ) {
2013    self->csr_clock = DWCGNAC3504_CSR_35_60M;
2014  } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_60M )
2015              && ( gmii_clk_rate < DWCGNAC3504_CSR_F_100M ) ) {
2016    self->csr_clock = DWCGNAC3504_CSR_60_100M;
2017  } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_100M )
2018              && ( gmii_clk_rate < DWCGNAC3504_CSR_F_150M ) ) {
2019    self->csr_clock = DWCGNAC3504_CSR_100_150M;
2020  } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_150M )
2021              && ( gmii_clk_rate < DWCGNAC3504_CSR_F_250M ) ) {
2022    self->csr_clock = DWCGNAC3504_CSR_150_250M;
2023  } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_250M )
2024              && ( gmii_clk_rate < DWCGNAC3504_CSR_F_300M ) ) {
2025    self->csr_clock = DWCGNAC3504_CSR_250_300M;
2026  } else {
2027    assert( gmii_clk_rate < DWCGNAC3504_CSR_F_300M );
2028    eno = EINVAL;
2029  }
2030
2031  return eno;
2032}
2033
2034static int dwmac_fixup_unit_count(
2035  const dwmac_common_context *self,
2036  const int                   count,
2037  const int                   default_value,
2038  const int                   max )
2039{
2040  int ret = count;
2041
2042
2043  if ( ret <= 0 ) {
2044    ret = DWMAC_ALIGN( default_value, self->CFG->L1_CACHE_LINE_SIZE );
2045  } else if ( ret > max ) {
2046    ret = DWMAC_ALIGN( max, self->CFG->L1_CACHE_LINE_SIZE );
2047  }
2048
2049  return ret;
2050}
2051
2052/* Called during initial setup */
2053static int dwmac_if_attach(
2054  dwmac_common_context         *self,
2055  struct rtems_bsdnet_ifconfig *bsd_config,
2056  const dwmac_cfg              *driver_config,
2057  void                         *arg )
2058{
2059  int           eno                     = 0;
2060  struct ifnet *ifp                     = &self->arpcom.ac_if;
2061  char         *unit_name               = NULL;
2062  int           unit_number             = rtems_bsdnet_parse_driver_name(
2063    bsd_config,
2064    &unit_name );
2065  const dwmac_callback_cfg    *CALLBACK = &driver_config->CALLBACK;
2066  const dwmac_common_desc_ops *DESC_OPS =
2067    (const dwmac_common_desc_ops *) driver_config->DESC_OPS->ops;
2068  const dwmac_ifconfig_drv_ctrl *drv_ctrl =
2069    (const dwmac_ifconfig_drv_ctrl *) bsd_config->drv_ctrl;
2070
2071  assert( self != NULL );
2072  assert( bsd_config != NULL );
2073  assert( driver_config != NULL );
2074  assert( CALLBACK != NULL );
2075
2076  if ( self == NULL
2077       || bsd_config == NULL
2078       || driver_config == NULL
2079       || CALLBACK == NULL
2080       ) {
2081    eno = EINVAL;
2082  } else {
2083    assert( CALLBACK->nic_enable != NULL );
2084    assert( CALLBACK->nic_disable != NULL );
2085    assert( CALLBACK->phy_enable != NULL );
2086    assert( CALLBACK->phy_disable != NULL );
2087    assert( CALLBACK->phy_event_enable != NULL );
2088    assert( CALLBACK->phy_event_clear != NULL );
2089    assert( CALLBACK->phy_events_get != NULL );
2090    assert( CALLBACK->phy_start != NULL );
2091    assert( CALLBACK->phy_stop != NULL );
2092    assert( CALLBACK->mem_alloc_nocache != NULL );
2093    assert( CALLBACK->mem_free_nocache != NULL );
2094    assert( CALLBACK->bus_setup != NULL );
2095
2096    if ( CALLBACK->nic_enable == NULL
2097         || CALLBACK->nic_disable == NULL
2098         || CALLBACK->phy_enable == NULL
2099         || CALLBACK->phy_disable == NULL
2100         || CALLBACK->phy_event_enable == NULL
2101         || CALLBACK->phy_event_clear == NULL
2102         || CALLBACK->phy_events_get == NULL
2103         || CALLBACK->phy_start == NULL
2104         || CALLBACK->phy_stop == NULL
2105         || CALLBACK->mem_alloc_nocache == NULL
2106         || CALLBACK->mem_free_nocache == NULL
2107         || CALLBACK->bus_setup == NULL
2108         ) {
2109      eno = EINVAL;
2110    }
2111  }
2112
2113  if ( eno == 0 ) {
2114    self->dma_threshold_control = DWMAC_DMA_THRESHOLD_CONTROL_DEFAULT;
2115
2116    assert( driver_config->addr_gmac_regs != NULL );
2117    if ( driver_config->addr_gmac_regs != NULL ) {
2118      self->macgrp = driver_config->addr_gmac_regs;
2119
2120      assert( driver_config->addr_dma_regs != NULL );
2121      if ( driver_config->addr_dma_regs != NULL ) {
2122        self->dmagrp = driver_config->addr_dma_regs;
2123      } else {
2124        eno = EINVAL;
2125      }
2126    } else {
2127      eno = EINVAL;
2128    }
2129  }
2130
2131  if ( eno == 0 ) {
2132    eno = dwmac_if_clk_csr_set(
2133      driver_config->GMII_CLK_RATE,
2134      self
2135      );
2136  }
2137
2138  if ( eno == 0 ) {
2139    if ( drv_ctrl == NULL ) {
2140      self->MDIO_BUS_ADDR = driver_config->MDIO_BUS_ADDR;
2141    } else {
2142      self->MDIO_BUS_ADDR = drv_ctrl->phy_addr;
2143    }
2144
2145    assert( 32 >= self->MDIO_BUS_ADDR );
2146
2147    if ( 32 < self->MDIO_BUS_ADDR ) {
2148      eno = EINVAL;
2149    }
2150  }
2151
2152  if ( eno == 0 ) {
2153    self->arg        = arg;        /* Optional argument from upper layer */
2154    self->state      = DWMAC_COMMON_STATE_DOWN;
2155    self->bsd_config = bsd_config; /* BSD-Net configuration.
2156                                      Exists for ll BSD based network divers */
2157
2158    /* Device control */
2159    bsd_config->drv_ctrl = NULL;
2160
2161    /* MDIO */
2162    self->mdio.mdio_r = dwmac_if_mdio_read; /* read from phy
2163                                               registers */
2164    self->mdio.mdio_w = dwmac_if_mdio_write; /* write to phy
2165                                                registers */
2166
2167    if ( driver_config->MAC_OPS == &DWMAC_1000_ETHERNET_MAC_OPS ) {
2168      self->mdio.has_gmii = 1;
2169    } else {
2170      self->mdio.has_gmii = 0;
2171
2172      /* dwmac_dma_ops_100 and dwmac_core_ops_100 is not yet implemented! */
2173      assert( driver_config->MAC_OPS == &DWMAC_1000_ETHERNET_MAC_OPS );
2174      eno = ENOTSUP;
2175    }
2176
2177    if ( eno == 0 ) {
2178      self->CFG     = driver_config;
2179      ifp->if_ioctl = dwmac_if_interface_ioctl; /* Execute commands
2180                                                   at runtime */
2181      ifp->if_init  = dwmac_if_interface_init;        /* Initialization
2182                                                         (called once) */
2183
2184      /* Receive unit count */
2185      bsd_config->rbuf_count = dwmac_fixup_unit_count(
2186        self,
2187        bsd_config->rbuf_count,
2188        DWMAC_CONFIG_RX_UNIT_COUNT_DEFAULT,
2189        DWMAC_CONFIG_RX_UNIT_COUNT_MAX
2190        );
2191
2192      /* Transmit unit count */
2193      bsd_config->xbuf_count = dwmac_fixup_unit_count(
2194        self,
2195        bsd_config->xbuf_count,
2196        DWMAC_CONFIG_TX_UNIT_COUNT_DEFAULT,
2197        DWMAC_CONFIG_TX_UNIT_COUNT_MAX
2198        );
2199
2200      if (
2201        DWMAC_GLOBAL_MBUF_CNT / 4 < bsd_config->rbuf_count
2202          || DWMAG_GLOBAL_MCLUST_CNT / 4 < bsd_config->rbuf_count
2203      ) {
2204        bsp_fatal( DWMAC_FATAL_TOO_MANY_RBUFS_CONFIGURED );
2205      }
2206
2207      /* Copy MAC address */
2208      memcpy(
2209        self->arpcom.ac_enaddr,
2210        bsd_config->hardware_address,
2211        ETHER_ADDR_LEN
2212        );
2213
2214      /* Set interface data */
2215      ifp->if_softc          = self;
2216      ifp->if_unit           = (short) unit_number;
2217      ifp->if_name           = unit_name;
2218
2219      ifp->if_start          = dwmac_if_interface_start;  /* Start transmitting
2220                                                             frames */
2221      ifp->if_output         = ether_output;
2222      ifp->if_watchdog       = NULL;
2223      ifp->if_flags          = IFF_BROADCAST | IFF_SIMPLEX;
2224      ifp->if_snd.ifq_maxlen = ifqmaxlen;
2225      ifp->if_timer          = 0;
2226      ifp->if_mtu            =
2227        bsd_config->mtu > 0 ? (u_long) bsd_config->mtu : ETHERMTU;
2228
2229      eno = DESC_OPS->validate( self );
2230      assert( eno == 0 );
2231    }
2232
2233    if ( eno == 0 ) {
2234      /* Create and start the receive task for our driver */
2235      assert( self->task_id_rx == RTEMS_ID_NONE );
2236      self->task_id_rx = rtems_bsdnet_newproc(
2237        "ntrx",
2238        4096,
2239        dwmac_task_rx,
2240        self
2241        );
2242      assert( self->task_id_rx != RTEMS_ID_NONE );
2243
2244      if ( self->task_id_rx == RTEMS_ID_NONE ) {
2245        eno = ENOMEM;
2246      }
2247    }
2248
2249    if ( eno == 0 ) {
2250      /* Create and start the transmit task for our driver */
2251      assert( self->task_id_tx == RTEMS_ID_NONE );
2252      self->task_id_tx = rtems_bsdnet_newproc(
2253        "nttx",
2254        4096,
2255        dwmac_task_tx,
2256        self
2257        );
2258      assert( self->task_id_tx != RTEMS_ID_NONE );
2259
2260      if ( self->task_id_tx == RTEMS_ID_NONE ) {
2261        eno = ENOMEM;
2262      }
2263    }
2264  }
2265
2266  if ( eno == 0 ) {
2267    /* Change status */
2268    ifp->if_flags |= IFF_RUNNING;
2269
2270    /* Attach the interface */
2271    if_attach( ifp );
2272    ether_ifattach( ifp );
2273  }
2274
2275  return eno;
2276}
2277
2278/* Initial setup method. Part of the driver API
2279 * Returns the address of the driver context on success and NULL on failure */
2280void *dwmac_network_if_attach_detach(
2281  struct rtems_bsdnet_ifconfig *bsd_config,
2282  const dwmac_cfg              *driver_config,
2283  void                         *arg,
2284  int                           attaching )
2285{
2286  int                   eno     = 0;
2287  dwmac_common_context *context = NULL;
2288
2289
2290  if ( attaching ) {
2291    context = calloc( 1, sizeof( dwmac_common_context ) );
2292    assert( context != NULL );
2293
2294    if ( context != NULL ) {
2295      eno = dwmac_if_attach(
2296        context,
2297        bsd_config,
2298        driver_config,
2299        arg
2300        );
2301
2302      if ( eno != 0 ) {
2303        free( context, 0 );
2304        context = NULL;
2305      }
2306    }
2307  } else {
2308    /* Detaching is not supported */
2309    assert( attaching != false );
2310  }
2311
2312  return context;
2313}
2314
2315int dwmac_if_read_from_phy(
2316  void          *arg,
2317  const unsigned phy_reg,
2318  uint16_t      *val )
2319{
2320  int                   eno  = EINVAL;
2321  dwmac_common_context *self = (dwmac_common_context *) arg;
2322  uint32_t              value;
2323
2324
2325  if ( arg != NULL ) {
2326    eno = dwmac_if_mdio_read(
2327      self->MDIO_BUS_ADDR,
2328      self,
2329      phy_reg,
2330      &value );
2331  }
2332
2333  if ( eno == 0 ) {
2334    *val = (uint16_t) value;
2335  }
2336
2337  return eno;
2338}
2339
2340int dwmac_if_write_to_phy(
2341  void          *arg,
2342  const unsigned phy_reg,
2343  const uint16_t val )
2344{
2345  int                   eno  = EINVAL;
2346  dwmac_common_context *self = (dwmac_common_context *) arg;
2347
2348
2349  if ( arg != NULL ) {
2350    eno = dwmac_if_mdio_write(
2351      self->MDIO_BUS_ADDR,
2352      self,
2353      phy_reg,
2354      val );
2355  }
2356
2357  return eno;
2358}
2359
2360int dwmac_if_handle_phy_event( void *arg )
2361{
2362  int                   eno;
2363  rtems_status_code     sc;
2364  dwmac_common_context *self = (dwmac_common_context *) arg;
2365
2366
2367  sc = rtems_bsdnet_event_send(
2368    self->task_id_tx,
2369    DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE
2370    );
2371  eno = rtems_status_code_to_errno( sc );
2372
2373  return eno;
2374}
Note: See TracBrowser for help on using the repository browser.