source: rtems/c/src/libchip/network/dwmac.c @ 4953b724

4.115
Last change on this file since 4953b724 was 4953b724, checked in by Ralf Kirchner <ralf.kirchner@…>, on 02/17/14 at 14:43:53

libchip: Add dwmac 10/100/1000 network driver

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