summaryrefslogtreecommitdiffstats
path: root/c/src/libchip/network/dwmac-desc-enh.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/libchip/network/dwmac-desc-enh.c')
-rw-r--r--c/src/libchip/network/dwmac-desc-enh.c1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/c/src/libchip/network/dwmac-desc-enh.c b/c/src/libchip/network/dwmac-desc-enh.c
new file mode 100644
index 0000000000..bd1e77db6c
--- /dev/null
+++ b/c/src/libchip/network/dwmac-desc-enh.c
@@ -0,0 +1,1051 @@
+/**
+ * @file
+ *
+ * @brief DWMAC 10/100/1000 Enhanced DMA Descriptor Handling.
+ *
+ * DWMAC 10/100/1000 on-chip Ethernet controllers.
+ * Functions and data for the handling of enhanced DMA descriptors.
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "dwmac-common.h"
+#include "dwmac-desc-com.h"
+#include "dwmac-core.h"
+#include <sys/queue.h>
+
+#undef DWMAC_DESC_ENH_DEBUG
+#ifdef DWMAC_DESC_ENH_DEBUG
+#define DWMAC_DESC_ENH_PRINT_DBG( fmt, args ... ) printk( fmt, ## args )
+#else
+#define DWMAC_DESC_ENH_PRINT_DBG( fmt, args ... ) do { } while ( 0 )
+#endif
+
+typedef enum {
+ DWMAC_IP_PAYLOAD_TYPE_UNKNOWN,
+ DWMAC_IP_PAYLOAD_TYPE_UDP,
+ DWMAC_IP_PAYLOAD_TYPE_TCP,
+ DWMAC_IP_PAYLOAD_TYPE_ICMP
+} dwmac_ip_payload_type;
+
+static void dwmac_desc_enh_rx_set_on_ring_chain(
+ volatile dwmac_desc_ext *p, int end )
+{
+ /* For simplicity reasons we will not use the second buffer.
+ * If we would use it we would have to set the size to MCLBYTES -1 */
+ p->erx.des0_3.des1 = DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_2_SIZE_SET(
+ p->erx.des0_3.des1, 0
+ );
+ p->erx.des0_3.des3 = (uint32_t) NULL;
+
+ if ( end )
+ p->erx.des0_3.des1 |= DWMAC_DESC_ERX_DES1_RECEIVE_END_OF_RING;
+}
+
+static void dwmac_desc_enh_tx_set_on_ring_chain(
+ volatile dwmac_desc_ext *p, const bool end )
+{
+ if ( end )
+ p->etx.des0_3.des0 |= DWMAC_DESC_ETX_DES0_TRANSMIT_END_OF_RING;
+}
+
+static void dwmac_desc_enh_set_tx_desc_len(
+ volatile dwmac_desc_ext *p_enh, size_t len )
+{
+ p_enh->etx.des0_3.des1 = DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_1_SIZE_SET(
+ p_enh->etx.des0_3.des1,
+ len
+ );
+}
+
+static bool dwmac_desc_enh_is_giant_frame( const uint32_t des0 )
+{
+ return (
+ ( des0
+ & DWMAC_DESC_ERX_DES0_TIMESTAMP_AVAIL_OR_CHECKSUM_ERROR_OR_GIANT_FRAME
+ ) != 0
+ );
+}
+
+static bool dwmac_desc_enh_is_udp_payload( const uint32_t des4 )
+{
+ return (
+ DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE_GET( des4 )
+ == DWMAC_IP_PAYLOAD_TYPE_UDP
+ );
+}
+
+static bool dwmac_desc_enh_is_tcp_payload( const uint32_t des4 )
+{
+ return (
+ DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE_GET( des4 )
+ == DWMAC_IP_PAYLOAD_TYPE_TCP
+ );
+}
+
+static bool dwmac_desc_enh_is_icmp_payload( const uint32_t des4 )
+{
+ return (
+ DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE_GET( des4 )
+ == DWMAC_IP_PAYLOAD_TYPE_ICMP
+ );
+}
+
+static dwmac_common_rx_frame_status dwmac_desc_enh_coe_status(
+ volatile dwmac_desc_ext *p_enh )
+{
+ dwmac_common_rx_frame_status ret = DWMAC_COMMON_RX_FRAME_STATUS_GOOD;
+ const uint32_t DES0 = p_enh->erx.des0_3.des0;
+ const uint32_t DES4 = p_enh->erx.des4;
+
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_EXT_STATUS_AVAIL_OR_RX_MAC_ADDR_STATUS )
+ != 0 ) {
+ if ( !dwmac_desc_enh_is_giant_frame( DES0 )
+ && ( DES0 & DWMAC_DESC_ERX_DES0_FREAME_TYPE ) == 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) == 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED ) == 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_ERROR ) == 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_HEADER_ERROR ) == 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IEEE 802.3 Type frame.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_LLC_SNAP;
+ } else if ( ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) != 0
+ || ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ != 0 )
+ && dwmac_desc_enh_is_giant_frame( DES0 ) ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 No CSUM Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_GOOD;
+ } else if ( ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) != 0
+ || ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ != 0 )
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 Payload Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) != 0
+ || ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ != 0 )
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_HEADER_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 Header Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) != 0
+ || ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ != 0 )
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_ERROR ) != 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IP_HEADER_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG(
+ "RX Des0 status: IPv4/6 Header and Payload Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) != 0
+ || ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ != 0 )
+ && ( !dwmac_desc_enh_is_udp_payload( DES4 ) )
+ && ( !dwmac_desc_enh_is_tcp_payload( DES4 ) )
+ && ( !dwmac_desc_enh_is_icmp_payload( DES4 ) ) ) {
+ DWMAC_DESC_ENH_PRINT_DBG(
+ "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ } else if ( ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED ) == 0
+ && ( DES4 & DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED )
+ == 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: No IPv4, IPv6 frame.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+ } else {
+ uint32_t status = (
+ (uint32_t) ( dwmac_desc_enh_is_giant_frame( DES0 ) << 2U )
+ | (uint32_t) ( ( ( DES0 & DWMAC_DESC_ERX_DES0_FREAME_TYPE )
+ != 0 ) << 1U ) )
+ & 0x7U;
+
+ /* bits 5 7 0 | Frame status
+ * ----------------------------------------------------------
+ * 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
+ * 1 0 0 | IPv4/6 No CSUM errorS.
+ * 1 0 1 | IPv4/6 CSUM PAYLOAD error
+ * 1 1 0 | IPv4/6 CSUM IP HR error
+ * 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
+ * 0 0 1 | IPv4/6 unsupported IP PAYLOAD
+ * 0 1 1 | COE bypassed.. no IPv4/6 frame
+ * 0 1 0 | Reserved.
+ */
+ if ( status == 0x0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IEEE 802.3 Type frame.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_LLC_SNAP;
+ } else if ( status == 0x4 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 No CSUM errorS.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_GOOD;
+ } else if ( status == 0x5 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 Payload Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( status == 0x6 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: IPv4/6 Header Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( status == 0x7 ) {
+ DWMAC_DESC_ENH_PRINT_DBG(
+ "RX Des0 status: IPv4/6 Header and Payload Error.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE;
+ } else if ( status == 0x1 ) {
+ DWMAC_DESC_ENH_PRINT_DBG(
+ "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ } else if ( status == 0x3 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "RX Des0 status: No IPv4, IPv6 frame.\n" );
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+ }
+
+ return ret;
+}
+
+static int dwmac_desc_enh_get_tx_status(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ int ret = 0;
+ volatile dwmac_desc_ext *dma_tx =
+ (volatile dwmac_desc_ext *) self->dma_tx;
+ volatile dwmac_desc_ext *p_desc = &dma_tx[idx_tx];
+ dwmac_common_desc_status_counts_tx *counts =
+ &self->stats.desc_status_counts_tx;
+
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_ERROR_SUMMARY ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "DWMAC TX error... 0x%08x\n", p->des01.etx );
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_JABBER_TIMEOUT )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tjabber_timeout error\n" );
+ ++counts->jabber;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_FRAME_FLUSHED )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tframe_flushed error\n" );
+ ++counts->frame_flushed;
+ dwmac_core_dma_flush_tx_fifo( self );
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_LOSS_OF_CARRIER )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tloss_carrier error\n" );
+ ++counts->losscarrier;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_NO_CARRIER )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tno_carrier error\n" );
+ ++counts->no_carrier;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_EXCESSIVE_COLLISION )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\texcessive_collisions\n" );
+ ++counts->excessive_collisions;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_EXCESSIVE_DEFERAL )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\texcessive tx_deferral\n" );
+ ++counts->excessive_deferral;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_UNDERFLOW_ERROR )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tunderflow error\n" );
+ dwmac_core_dma_flush_tx_fifo( self );
+ ++counts->underflow;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_IP_HEADER_ERROR )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tTX IP header csum error\n" );
+ ++counts->ip_header_error;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_IP_PAYLOAD_ERROR )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tAddr/Payload csum error\n" );
+ ++counts->payload_error;
+ dwmac_core_dma_flush_tx_fifo( self );
+ }
+
+ ret = -1;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_DEFERRED_BIT ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC TX status: tx deferred\n" );
+ ++counts->deferred;
+ }
+
+ if ( ( p_desc->etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_VLAN_FRAME ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC TX status: VLAN frame\n" );
+ ++counts->vlan;
+ }
+
+ return ret;
+}
+
+static dwmac_common_rx_frame_status dwmac_desc_enh_get_rx_status(
+ dwmac_common_context *self,
+ const unsigned int desc_idx )
+{
+ dwmac_common_desc_status_counts_rx *counts =
+ &self->stats.desc_status_counts_rx;
+ dwmac_common_rx_frame_status ret =
+ DWMAC_COMMON_RX_FRAME_STATUS_GOOD;
+ volatile dwmac_desc_ext *dma_rx =
+ (volatile dwmac_desc_ext *) self->dma_rx;
+ const uint32_t DES0 = dma_rx[desc_idx].erx.des0_3.des0;
+
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_ERROR_SUMMARY ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX Error Summary 0x%08x\n",
+ DES0 );
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_DESCRIPTOR_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tdescriptor error\n" );
+ ++counts->descriptor_error;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_OVERFLOW_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\toverflow error\n" );
+ ++counts->overflow_error;
+ }
+
+ if ( dwmac_desc_enh_is_giant_frame( DES0 ) ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tIPC Csum Error/Giant frame\n" );
+ ++counts->giant_frame;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_LATE_COLLISION ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tlate_collision error\n" );
+ ++counts->late_collision;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_RECEIVE_WATCHDOG_TIMEOUT )
+ != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\treceive_watchdog error\n" );
+ ++counts->watchdog_timeout;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_RECEIVE_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tReceive Error\n" );
+ ++counts->receive_error;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_CRC_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "\tCRC error\n" );
+ ++counts->crc_error;
+ }
+
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+
+ if ( ret == DWMAC_COMMON_RX_FRAME_STATUS_GOOD ) {
+ /* After a payload csum error, the ES bit is set.
+ * It doesn't match with the information reported into the databook.
+ * At any rate, we need to understand if the CSUM hw computation is ok
+ * and report this info to the upper layers. */
+ ret = dwmac_desc_enh_coe_status( &dma_rx[desc_idx] );
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_DRIBBLE_BIT_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX: dribbling error\n" );
+ ++counts->dribble_bit_error;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_SRC_ADDR_FILTER_FAIL ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX : Source Address filter fail\n" );
+ ++counts->source_addr_fail;
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_DEST_ADDR_FILTER_FAIL ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX : Dest Address filter fail\n" );
+ ++counts->dest_addr_fail;
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_LENGTH_ERROR ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX: length_error error\n" );
+ ++counts->length_error;
+ ret = DWMAC_COMMON_RX_FRAME_STATUS_DISCARD;
+ }
+
+ if ( ( DES0 & DWMAC_DESC_ERX_DES0_VLAN_TAG ) != 0 ) {
+ DWMAC_DESC_ENH_PRINT_DBG( "GMAC RX: VLAN frame tagged\n" );
+ ++counts->vlan_tag;
+ }
+
+ return ret;
+}
+
+static void dwmac_desc_enh_print_tx_desc(
+ volatile dwmac_desc *p,
+ const unsigned int count )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) p;
+ unsigned int index;
+
+
+ if ( p_enh != NULL ) {
+ for ( index = 0; index < count; ++index ) {
+ printf( "Transmit DMA Descriptor %d\n", index );
+ printf( "des0\n" );
+ printf(
+ " %u own bit\n"
+ " %u IRQ on Completion\n"
+ " %u Last Segment\n"
+ " %u First Segment\n"
+ " %u Disable CRC\n"
+ " %u Disable Pad\n"
+ " %u Transmit Timestamp Enable\n"
+ " %lu Checksum Insertion Control\n"
+ " %u Transmit End of Ring\n"
+ " %u Second Address Chained\n"
+ " %u Transmit Timestamp Status\n"
+ " %u IP Header Error\n"
+ " %u VLAN Frame\n"
+ " %lu Collision Count\n"
+ " %u Deferred Bit\n",
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_OWN_BIT ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_IRQ_ON_COMPLETION ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_LAST_SEGMENT ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_FIRST_SEGMENT ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_DISABLE_CRC ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_DISABLE_PAD ) != 0,
+ ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_TRANSMIT_TIMESTAMP_ENABLE ) != 0,
+ DWMAC_DESC_ETX_DES0_CHECKSUM_INSERTION_CONTROL_GET( p_enh[index].etx.
+ des0_3.des0 ),
+ ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_TRANSMIT_END_OF_RING ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_SECOND_ADDR_CHAINED ) != 0,
+ ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_TRANSMIT_TIMESTAMP_STATUS ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_IP_HEADER_ERROR ) != 0,
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_VLAN_FRAME ) != 0,
+ DWMAC_DESC_ETX_DES0_COLLISION_COUNT_GET( p_enh[index].etx.des0_3.des0 ),
+ ( p_enh[index].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_DEFERRED_BIT ) != 0
+ );
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_ERROR_SUMMARY ) != 0 ) {
+ printf( " Error Summary:\n" );
+
+ if ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_JABBER_TIMEOUT ) {
+ printf( " Jabber Timeout\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_FRAME_FLUSHED ) != 0 ) {
+ printf( " Frame Flush\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_IP_PAYLOAD_ERROR ) != 0 ) {
+ printf( " Payload Error\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_LOSS_OF_CARRIER ) != 0 ) {
+ printf( " Loss of Carrier\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_NO_CARRIER ) != 0 ) {
+ printf( " No Carrier\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_EXCESSIVE_COLLISION ) != 0 ) {
+ printf( " Excessive Collision\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_EXCESSIVE_COLLISION ) != 0 ) {
+ printf( " Ecessive Deferral\n" );
+ }
+
+ if ( ( p_enh[index].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_UNDERFLOW_ERROR ) != 0 ) {
+ printf( " Undeflow Error\n" );
+ }
+ }
+
+ printf( "des1\n" );
+ printf(
+ " %lu Transmit Buffer 2 Size\n"
+ " %lu Transmit Buffer 1 Size\n",
+ DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_2_SIZE_GET( p_enh[index].etx.des0_3.
+ des1 ),
+ DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_1_SIZE_GET( p_enh[index].etx.des0_3.
+ des1 )
+ );
+ printf( "des2\n" );
+ printf( " %p Buffer 1 Address\n", (void *) p_enh[index].etx.des0_3.des2 );
+ printf( "des3\n" );
+ printf( " %p Buffer 2 Address\n", (void *) p_enh[index].etx.des0_3.des3 );
+ }
+ }
+}
+
+static void dwmac_desc_enh_print_rx_desc(
+ volatile dwmac_desc *p,
+ const unsigned int count )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) p;
+ unsigned int index;
+
+
+ if ( p_enh != NULL ) {
+ for ( index = 0; index < count; ++index ) {
+ printf( "Receive DMA Descriptor %d\n", index );
+ printf( "des0\n" );
+ printf(
+ " %u Own Bit\n"
+ " %u Dest. Addr. Filter Fail\n"
+ " %lu Frame Length\n"
+ " %u Source Addr. Filter Fail\n"
+ " %u Length Error\n"
+ " %u VLAN Tag\n"
+ " %u First Descriptor\n"
+ " %u Last Descriptor\n"
+ " %u Frame Type\n"
+ " %u Dribble Bit Error\n"
+ " %u Extended Status Available\n",
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_OWN_BIT ) != 0,
+ ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_DEST_ADDR_FILTER_FAIL ) != 0,
+ DWMAC_DESC_ERX_DES0_FRAME_LENGTH_GET(
+ p_enh[index].erx.des0_3.des0 ),
+ ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_SRC_ADDR_FILTER_FAIL ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_LENGTH_ERROR ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_VLAN_TAG ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_FIRST_DESCRIPTOR ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_LAST_DESCRIPTOR ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_FREAME_TYPE ) != 0,
+ ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_DRIBBLE_BIT_ERROR ) != 0,
+ ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_EXT_STATUS_AVAIL_OR_RX_MAC_ADDR_STATUS ) != 0
+ );
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_ERROR_SUMMARY ) != 0 ) {
+ printf( " Error Summary:\n" );
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_DESCRIPTOR_ERROR ) != 0 ) {
+ printf( " Descriptor Error\n" );
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_OVERFLOW_ERROR ) != 0 ) {
+ printf( " Overflow Error\n" );
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ &
+ DWMAC_DESC_ERX_DES0_TIMESTAMP_AVAIL_OR_CHECKSUM_ERROR_OR_GIANT_FRAME )
+ != 0 ) {
+ printf( " Giant Frame\n" );
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_LATE_COLLISION ) != 0 ) {
+ printf( " Late Collision\n" );
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_RECEIVE_WATCHDOG_TIMEOUT ) != 0
+ || ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_RECEIVE_ERROR ) != 0 ) {
+ printf( " IP Header or IP Payload:\n" );
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_RECEIVE_WATCHDOG_TIMEOUT ) != 0 ) {
+ printf( " Watchdog Timeout\n" );
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_RECEIVE_ERROR ) != 0 ) {
+ printf( " Receive Error\n" );
+ }
+ }
+
+ if ( ( p_enh[index].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_CRC_ERROR )
+ != 0 ) {
+ printf( " CRC Error\n" );
+ }
+ }
+
+ printf( "des1\n" );
+ printf(
+ " %u Disable Interrupt on Completion\n"
+ " %lu Receive Buffer 2 Size\n"
+ " %u Receive End of Ring\n"
+ " %u Second Addr. Chained\n"
+ " %lu Receive Buffer 1 Size\n",
+ ( p_enh[index].erx.des0_3.des1
+ & DWMAC_DESC_ERX_DES1_DISABLE_IRQ_ON_COMPLETION ) != 0,
+ DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_2_SIZE_GET( p_enh[index].erx.des0_3.
+ des1 ),
+ ( p_enh[index].erx.des0_3.des1 & DWMAC_DESC_ERX_DES1_RECEIVE_END_OF_RING ) != 0,
+ ( p_enh[index].erx.des0_3.des1 & DWMAC_DESC_ERX_DES1_SECOND_ADDR_CHAINED ) != 0,
+ DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE_GET( p_enh[index].erx.des0_3.
+ des1 )
+ );
+ printf( "des2\n" );
+ printf( " %p Buffer 1 Address\n", (void *) p_enh[index].erx.des0_3.des2 );
+ printf( "des3\n" );
+ printf( " %p Buffer 2 Address\n", (void *) p_enh[index].erx.des0_3.des3 );
+ }
+ }
+}
+
+static int dwmac_desc_enh_create_rx_desc( dwmac_common_context *self )
+{
+ int eno = 0;
+ const size_t NUM_DESCS = (size_t) self->bsd_config->rbuf_count;
+ const size_t SIZE_DESCS = NUM_DESCS * sizeof( dwmac_desc_ext );
+ void *desc_mem = NULL;
+
+
+ assert( NULL == self->dma_rx );
+
+ /* Allocate an array of mbuf pointers */
+ self->mbuf_addr_rx = calloc( NUM_DESCS, sizeof( struct mbuf * ) );
+
+ if ( self->mbuf_addr_rx == NULL ) {
+ eno = ENOMEM;
+ }
+
+ /* Allocate an array of dma descriptors */
+ if ( eno == 0 ) {
+ eno = ( self->CFG->CALLBACK.mem_alloc_nocache )(
+ self->arg,
+ &desc_mem,
+ SIZE_DESCS
+ );
+ }
+
+ if ( eno == 0 ) {
+ if ( desc_mem != NULL ) {
+ memset( desc_mem, 0, SIZE_DESCS );
+ DWMAC_COMMON_DSB();
+ } else {
+ eno = ENOMEM;
+ }
+ }
+
+ if ( eno == 0 ) {
+ self->dma_rx = (volatile dwmac_desc *) desc_mem;
+ DWMAC_COMMON_DSB();
+ }
+
+ return eno;
+}
+
+static void dwmac_desc_enh_init_rx_desc(
+ dwmac_common_context *self,
+ const unsigned int index )
+{
+ volatile dwmac_desc_ext *p_enh =
+ (volatile dwmac_desc_ext *) self->dma_rx;
+ const size_t NUM_DESCS = (size_t) self->bsd_config->rbuf_count;
+ char *clust_start =
+ mtod( self->mbuf_addr_rx[index], char * );
+
+
+ assert( NULL != p_enh );
+
+ DWMAC_COMMON_DSB();
+
+ rtems_cache_invalidate_multiple_data_lines(
+ clust_start,
+ DWMAC_DESC_COM_BUF_SIZE + ETHER_ALIGN
+ );
+
+ if ( self->mbuf_addr_rx[index] != NULL ) {
+ p_enh[index].erx.des0_3.des1 = DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE_SET(
+ p_enh->erx.des0_3.des1,
+ DWMAC_DESC_COM_BUF_SIZE );
+ } else {
+ p_enh[index].erx.des0_3.des1 = DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE_SET(
+ p_enh->erx.des0_3.des1,
+ 0 );
+ }
+
+ p_enh[index].erx.des0_3.des2 = (uint32_t) clust_start;
+
+ /* The network controller supports adding a second data buffer to
+ * p_enh->erx.des0_3.des3. For simplicity reasons we will not do this */
+ dwmac_desc_enh_rx_set_on_ring_chain( &p_enh[index],
+ ( index == NUM_DESCS - 1 ) );
+ DWMAC_COMMON_DSB();
+ p_enh[index].erx.des0_3.des0 = DWMAC_DESC_ERX_DES0_OWN_BIT;
+}
+
+static int dwmac_desc_enh_destroy_rx_desc( dwmac_common_context *self )
+{
+ int eno = 0;
+ void *desc_mem = __DEVOLATILE( void *, self->dma_rx );
+
+
+ if ( self->mbuf_addr_rx != NULL ) {
+ free( self->mbuf_addr_rx, 0 );
+ self->mbuf_addr_rx = NULL;
+ }
+
+ if ( desc_mem != NULL ) {
+ eno = self->CFG->CALLBACK.mem_free_nocache( self->arg, desc_mem );
+ desc_mem = NULL;
+ self->dma_rx = (volatile dwmac_desc *) desc_mem;
+ }
+
+ DWMAC_COMMON_DSB();
+
+ return eno;
+}
+
+static void dwmac_desc_enh_release_rx_bufs( dwmac_common_context *self )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_rx;
+ const size_t NUM_DESCS = (size_t) self->bsd_config->rbuf_count;
+ unsigned int i;
+
+
+ assert( p_enh != NULL );
+
+ for ( i = 0; i < NUM_DESCS; ++i ) {
+ if ( p_enh[i].erx.des0_3.des2 != 0 ) {
+ struct mbuf *dummy;
+
+ assert( self->mbuf_addr_rx[i] != NULL );
+
+ MFREE( self->mbuf_addr_rx[i], dummy );
+ (void) dummy;
+ memset( __DEVOLATILE( void *,
+ &p_enh[i].erx ), 0, sizeof( dwmac_desc_ext ) );
+ }
+ }
+
+ self->dma_rx = (volatile dwmac_desc *) p_enh;
+ DWMAC_COMMON_DSB();
+}
+
+static int dwmac_desc_enh_create_tx_desc( dwmac_common_context *self )
+{
+ int eno = 0;
+ void *mem_desc = __DEVOLATILE( void *, self->dma_tx );
+ const size_t NUM_DESCS = (size_t) self->bsd_config->xbuf_count;
+ const size_t SIZE_DESCS = NUM_DESCS * sizeof( dwmac_desc_ext );
+
+
+ assert( mem_desc == NULL );
+
+ /* Allocate an array of mbuf pointers */
+ self->mbuf_addr_tx = calloc( NUM_DESCS, sizeof( struct mbuf * ) );
+
+ if ( self->mbuf_addr_tx == NULL ) {
+ eno = ENOMEM;
+ }
+
+ if ( eno == 0 ) {
+ eno = ( self->CFG->CALLBACK.mem_alloc_nocache )(
+ self->arg,
+ &mem_desc,
+ SIZE_DESCS
+ );
+ }
+
+ if ( eno == 0 ) {
+ if ( mem_desc != NULL ) {
+ memset( mem_desc, 0, SIZE_DESCS );
+ DWMAC_COMMON_DSB();
+ } else {
+ eno = ENOMEM;
+ }
+ }
+
+ if ( eno == 0 ) {
+ self->dma_tx = (volatile dwmac_desc *) mem_desc;
+ DWMAC_COMMON_DSB();
+ }
+
+ return eno;
+}
+
+static void dwmac_desc_enh_init_tx_desc( dwmac_common_context *self )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+ const size_t NUM_DESCS = (size_t) self->bsd_config->xbuf_count;
+ unsigned int i;
+
+
+ assert( p_enh != NULL );
+
+ for ( i = 0; i < NUM_DESCS; ++i ) {
+ dwmac_desc_enh_tx_set_on_ring_chain( &p_enh[i], ( i == NUM_DESCS - 1 ) );
+ }
+
+ self->dma_tx = (volatile dwmac_desc *) &p_enh[0];
+ DWMAC_COMMON_DSB();
+}
+
+static int dwmac_desc_enh_destroy_tx_desc( dwmac_common_context *self )
+{
+ int eno = 0;
+ void *mem_desc = __DEVOLATILE( void *, self->dma_tx );
+
+
+ if ( self->mbuf_addr_tx != NULL ) {
+ free( self->mbuf_addr_tx, 0 );
+ self->mbuf_addr_tx = NULL;
+ }
+
+ if ( mem_desc != NULL ) {
+ eno = self->CFG->CALLBACK.mem_free_nocache( self->arg, mem_desc );
+ mem_desc = NULL;
+ self->dma_tx = (volatile dwmac_desc *) mem_desc;
+ }
+
+ DWMAC_COMMON_DSB();
+
+ return eno;
+}
+
+static void dwmac_desc_enh_release_tx_bufs( dwmac_common_context *self )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+ const size_t NUM_DESCS = (size_t) self->bsd_config->xbuf_count;
+ unsigned int i;
+
+
+ assert( p_enh != NULL );
+
+ for ( i = 0; i < NUM_DESCS; ++i ) {
+ if ( p_enh[i].etx.des0_3.des1 != 0 ) {
+ struct mbuf *dummy;
+
+ assert( self->mbuf_addr_tx[i] != NULL );
+
+ MFREE( self->mbuf_addr_tx[i], dummy );
+ (void) dummy;
+ memset( __DEVOLATILE( void *,
+ &p_enh[i].etx ), 0, sizeof( dwmac_desc_ext ) );
+ }
+ }
+
+ self->dma_tx = (volatile dwmac_desc *) p_enh;
+ DWMAC_COMMON_DSB();
+}
+
+static inline size_t dwmac_desc_enh_get_rx_frame_len(
+ dwmac_common_context *self,
+ const unsigned int desc_idx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_rx;
+
+
+ /* The type-1 checksum offload engines append the checksum at
+ * the end of frame and the two bytes of checksum are added in
+ * the length.
+ * Adjust for that in the framelen for type-1 checksum offload
+ * engines. */
+ if ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_RXTYP1COE ) {
+ return DWMAC_DESC_ERX_DES0_FRAME_LENGTH_GET( p_enh[desc_idx].erx.des0_3.des0 )
+ - 2U;
+ } else {
+ return DWMAC_DESC_ERX_DES0_FRAME_LENGTH_GET( p_enh[desc_idx].erx.des0_3.des0 );
+ }
+}
+
+static bool dwmac_desc_enh_am_i_rx_owner(
+ dwmac_common_context *self,
+ const unsigned int desc_idx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_rx;
+ bool am_i_owner;
+
+
+ DWMAC_COMMON_DSB();
+ am_i_owner =
+ ( p_enh[desc_idx].erx.des0_3.des0 & DWMAC_DESC_ERX_DES0_OWN_BIT ) == 0;
+
+ return am_i_owner;
+}
+
+static bool dwmac_desc_enh_am_i_tx_owner(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+ bool am_i_owner;
+
+
+ DWMAC_COMMON_DSB();
+ am_i_owner =
+ ( p_enh[idx_tx].etx.des0_3.des0 & DWMAC_DESC_ETX_DES0_OWN_BIT ) == 0;
+
+ return am_i_owner;
+}
+
+static void dwmac_desc_enh_release_tx_ownership(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+
+
+ DWMAC_COMMON_DSB();
+ p_enh[idx_tx].erx.des0_3.des0 |= DWMAC_DESC_ETX_DES0_OWN_BIT;
+}
+
+static int dwmac_desc_enh_get_tx_ls(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+
+
+ return ( ( p_enh[idx_tx].etx.des0_3.des0
+ & DWMAC_DESC_ETX_DES0_LAST_SEGMENT ) != 0 );
+}
+
+static void dwmac_desc_enh_release_tx_desc(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+
+
+ p_enh[idx_tx].etx.des0_3.des0 =
+ p_enh[idx_tx].etx.des0_3.des0
+ & ( DWMAC_DESC_ETX_DES0_TRANSMIT_END_OF_RING
+ | DWMAC_DESC_ETX_DES0_SECOND_ADDR_CHAINED );
+
+ p_enh[idx_tx].etx.des0_3.des1 = 0;
+}
+
+static void dwmac_desc_enh_prepare_tx_desc(
+ dwmac_common_context *self,
+ const unsigned int idx,
+ const bool is_first,
+ const size_t len,
+ const void *pdata )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+
+
+ if ( is_first ) {
+ p_enh[idx].etx.des0_3.des0 |= DWMAC_DESC_ETX_DES0_FIRST_SEGMENT;
+ }
+
+ dwmac_desc_enh_set_tx_desc_len( &p_enh[idx], len );
+
+ p_enh[idx].etx.des0_3.des2 = (uintptr_t) pdata;
+}
+
+static void dwmac_desc_enh_close_tx_desc(
+ dwmac_common_context *self,
+ const unsigned int idx_tx )
+{
+ volatile dwmac_desc_ext *p_enh = (volatile dwmac_desc_ext *) self->dma_tx;
+
+
+ p_enh[idx_tx].etx.des0_3.des0 |= DWMAC_DESC_ETX_DES0_LAST_SEGMENT;
+ p_enh[idx_tx].etx.des0_3.des0 |= DWMAC_DESC_ETX_DES0_IRQ_ON_COMPLETION;
+}
+
+static bool dwmac_desc_enh_is_first_rx_segment(
+ dwmac_common_context *self,
+ const unsigned int descriptor_index )
+{
+ volatile dwmac_desc_ext *p_descs = (volatile dwmac_desc_ext *) self->dma_rx;
+
+
+ return ( ( p_descs[descriptor_index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_FIRST_DESCRIPTOR ) != 0 );
+}
+
+static bool dwmac_desc_enh_is_last_rx_segment(
+ dwmac_common_context *self,
+ const unsigned int descriptor_index )
+{
+ volatile dwmac_desc_ext *p_descs = (volatile dwmac_desc_ext *) self->dma_rx;
+
+
+ return ( ( p_descs[descriptor_index].erx.des0_3.des0
+ & DWMAC_DESC_ERX_DES0_LAST_DESCRIPTOR ) != 0 );
+}
+
+static int dwmac_desc_enh_validate( dwmac_common_context *self )
+{
+ /* Does the hardware support enhanced descriptors? */
+ if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_ENHDESSEL ) != 0 ) {
+ return 0;
+ } else {
+ return EINVAL;
+ }
+}
+
+static bool dwmac_desc_enh_use_enhanced_descs( dwmac_common_context *self )
+{
+ (void) self;
+
+ /* Yes, we use enhanced descriptors */
+ return true;
+}
+
+const dwmac_common_desc_ops dwmac_desc_ops_enhanced = {
+ .validate = dwmac_desc_enh_validate,
+ .use_enhanced_descs = dwmac_desc_enh_use_enhanced_descs,
+ .tx_status = dwmac_desc_enh_get_tx_status,
+ .rx_status = dwmac_desc_enh_get_rx_status,
+ .create_rx_desc = dwmac_desc_enh_create_rx_desc,
+ .create_tx_desc = dwmac_desc_enh_create_tx_desc,
+ .destroy_rx_desc = dwmac_desc_enh_destroy_rx_desc,
+ .destroy_tx_desc = dwmac_desc_enh_destroy_tx_desc,
+ .init_rx_desc = dwmac_desc_enh_init_rx_desc,
+ .init_tx_desc = dwmac_desc_enh_init_tx_desc,
+ .release_rx_bufs = dwmac_desc_enh_release_rx_bufs,
+ .release_tx_bufs = dwmac_desc_enh_release_tx_bufs,
+ .alloc_data_buf = dwmac_desc_com_new_mbuf,
+ .am_i_tx_owner = dwmac_desc_enh_am_i_tx_owner,
+ .am_i_rx_owner = dwmac_desc_enh_am_i_rx_owner,
+ .release_tx_desc = dwmac_desc_enh_release_tx_desc,
+ .prepare_tx_desc = dwmac_desc_enh_prepare_tx_desc,
+ .close_tx_desc = dwmac_desc_enh_close_tx_desc,
+ .get_tx_ls = dwmac_desc_enh_get_tx_ls,
+ .release_tx_ownership = dwmac_desc_enh_release_tx_ownership,
+ .get_rx_frame_len = dwmac_desc_enh_get_rx_frame_len,
+ .is_first_rx_segment = dwmac_desc_enh_is_first_rx_segment,
+ .is_last_rx_segment = dwmac_desc_enh_is_last_rx_segment,
+ .print_tx_desc = dwmac_desc_enh_print_tx_desc,
+ .print_rx_desc = dwmac_desc_enh_print_rx_desc,
+};
+
+/* This wrapped function pointer struct can be passed into the
+ * configuration initializer for the driver */
+const dwmac_descriptor_ops DWMAC_DESCRIPTOR_OPS_ENHANCED =
+ DWMAC_DESCRIPTOR_OPS_INITIALIZER(
+ &dwmac_desc_ops_enhanced
+ );