From 4953b72490ce9666c5d783011bbf190229ffe689 Mon Sep 17 00:00:00 2001 From: Ralf Kirchner Date: Mon, 17 Feb 2014 15:43:53 +0100 Subject: libchip: Add dwmac 10/100/1000 network driver --- c/src/libchip/network/README.dwmac | 25 + c/src/libchip/network/dwmac-1000-core.c | 238 ++ c/src/libchip/network/dwmac-1000-dma.c | 244 ++ .../libchip/network/dwmac-1000-ethernet-mac-ops.c | 33 + c/src/libchip/network/dwmac-common.h | 374 ++++ c/src/libchip/network/dwmac-core.c | 406 ++++ c/src/libchip/network/dwmac-core.h | 76 + c/src/libchip/network/dwmac-desc-com.c | 60 + c/src/libchip/network/dwmac-desc-com.h | 44 + c/src/libchip/network/dwmac-desc-enh.c | 1051 +++++++++ c/src/libchip/network/dwmac-desc.h | 257 +++ c/src/libchip/network/dwmac-regs.h | 515 +++++ c/src/libchip/network/dwmac.c | 2325 ++++++++++++++++++++ c/src/libchip/network/dwmac.h | 878 ++++++++ 14 files changed, 6526 insertions(+) create mode 100644 c/src/libchip/network/README.dwmac create mode 100644 c/src/libchip/network/dwmac-1000-core.c create mode 100644 c/src/libchip/network/dwmac-1000-dma.c create mode 100644 c/src/libchip/network/dwmac-1000-ethernet-mac-ops.c create mode 100644 c/src/libchip/network/dwmac-common.h create mode 100644 c/src/libchip/network/dwmac-core.c create mode 100644 c/src/libchip/network/dwmac-core.h create mode 100644 c/src/libchip/network/dwmac-desc-com.c create mode 100644 c/src/libchip/network/dwmac-desc-com.h create mode 100644 c/src/libchip/network/dwmac-desc-enh.c create mode 100644 c/src/libchip/network/dwmac-desc.h create mode 100644 c/src/libchip/network/dwmac-regs.h create mode 100644 c/src/libchip/network/dwmac.c create mode 100644 c/src/libchip/network/dwmac.h (limited to 'c/src/libchip/network') diff --git a/c/src/libchip/network/README.dwmac b/c/src/libchip/network/README.dwmac new file mode 100644 index 0000000000..4fd16221bd --- /dev/null +++ b/c/src/libchip/network/README.dwmac @@ -0,0 +1,25 @@ +About +===== +The dwmac* files implement libchip driver for the DWMAC 10/100/1000 +ethernet MAC. The DWMAC 10/100/1000 ethernet MAC is a Synopsys IP core. + +Target Support +============== + +The target is required to provide the low level support routines as +listed in the Configuration section of this file. + +The file cs8900.[ch].bsp are an example BSP files for DIMMPC target. + +Conditionals +============ +None + +Todo +==== ++ Add support for DWMAC 10/100. currently only support for DWMAC 1000 + is implemented + +Configuration +============= +See the dwmac.h header file for the documentation. \ No newline at end of file diff --git a/c/src/libchip/network/dwmac-1000-core.c b/c/src/libchip/network/dwmac-1000-core.c new file mode 100644 index 0000000000..770078af43 --- /dev/null +++ b/c/src/libchip/network/dwmac-1000-core.c @@ -0,0 +1,238 @@ +/** + * @file + * + * @brief DWMAC 1000 on-chip Ethernet controllers Core Handling + * + * Functions and data which are specific to the DWMAC 1000 Core Handling. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include "dwmac-core.h" +#include "dwmac-common.h" + +#define DWMAC_1000_CORE_DEBUG + +//#undef DWMAC_1000_CORE_DEBUG +#ifdef DWMAC_1000_CORE_DEBUG +#define DWMAC_1000_CORE_PRINT_DBG( fmt, args ... ) printk( fmt, ## args ) +#else +#define DWMAC_1000_CORE_PRINT_DBG( fmt, args ... ) do { } while ( 0 ) +#endif + +#define DWMAC_1000_CORE_INIT \ + ( \ + ( MACGRP_MAC_CONFIGURATION_JD \ + | MACGRP_MAC_CONFIGURATION_BE ) \ + & ~MACGRP_MAC_CONFIGURATION_PS \ + ) + +#define DWMAC_1000_CORE_HASH_TABLE_SIZE 256 + +static volatile uint32_t *dwmac_1000_core_get_mac_addr_low( + dwmac_common_context *self, + const unsigned int mac_addr_index ) +{ + volatile uint32_t *addr = NULL; + + assert( self != NULL ); + assert( mac_addr_index <= 127 ); + + if ( mac_addr_index > 15 ) { + addr = &self->macgrp->mac_addr16_127[mac_addr_index].low; + } else { + addr = &self->macgrp->mac_addr0_15[mac_addr_index].low; + } + + return addr; +} + +static volatile uint32_t *dwmac_1000_core_get_mac_addr_high( + dwmac_common_context *self, + const unsigned int mac_addr_index ) +{ + volatile uint32_t *addr = NULL; + + assert( self != NULL ); + assert( mac_addr_index <= 127 ); + + if ( mac_addr_index > 15 ) { + addr = &self->macgrp->mac_addr16_127[mac_addr_index].high; + } else { + addr = &self->macgrp->mac_addr0_15[mac_addr_index].high; + } + + return addr; +} + +static void dwmac_1000_core_init( dwmac_common_context *self ) +{ + uint32_t value = self->macgrp->mac_configuration; + + value |= DWMAC_1000_CORE_INIT; + + if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_RXTYP1COE ) != 0 + || ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_RXTYP2COE ) != 0 ) { + /* Enable RX checksum calculation offload to hardware */ + value |= MACGRP_MAC_CONFIGURATION_IPC; + } + + /* No Jumbo- or Giant frames. The network stack does not support them */ + value &= ~MACGRP_MAC_CONFIGURATION_JE; + value &= ~MACGRP_MAC_CONFIGURATION_TWOKPE; + self->macgrp->mac_configuration = value; + + /* Mask GMAC interrupts */ + self->macgrp->interrupt_mask = + MACGRP_INTERRUPT_MASK_RGSMIIIM + | MACGRP_INTERRUPT_MASK_PCSLCHGIM + | MACGRP_INTERRUPT_MASK_PCSANCIM + | MACGRP_INTERRUPT_MASK_TSIM; + + /* mask out interrupts because we don't handle them yet */ + self->macgrp->mmc_receive_interrupt_mask = ( uint32_t ) ~0L; + self->macgrp->mmc_transmit_interrupt_mask = ( uint32_t ) ~0L; + self->macgrp->mmc_ipc_receive_interrupt_mask = ( uint32_t ) ~0L; +} + +static void dwmac_1000_core_set_umac_addr( + dwmac_common_context *self, + const uint8_t *addr, + unsigned int reg_n ) +{ + dwmac_core_set_mac_addr( + addr, + dwmac_1000_core_get_mac_addr_high( self, reg_n ), + dwmac_1000_core_get_mac_addr_low( self, reg_n ) + ); +} + +static void dwmac_1000_core_set_hash_filter( + dwmac_common_context *self, + const bool add, + struct ifreq *ifr ) +{ + int eno = 0; + struct arpcom *ac = &self->arpcom; + + if ( add ) { + eno = ether_addmulti( ifr, ac ); + } else { + eno = ether_delmulti( ifr, ac ); + } + + if ( eno == ENETRESET ) { + struct ether_multistep step; + struct ether_multi *enm; + unsigned int num_multi = 0; + unsigned int index; + + ETHER_FIRST_MULTI( step, ac, enm ); + + while ( enm != NULL ) { + /* Find out how many multicast addresses we have to handle */ + uint64_t addrlo = 0; + uint64_t addrhi = 0; + + memcpy( &addrlo, enm->enm_addrlo, ETHER_ADDR_LEN ); + memcpy( &addrhi, enm->enm_addrhi, ETHER_ADDR_LEN ); + num_multi += 1U + (uint32_t) ( addrhi - addrlo ); + } + + if ( num_multi > DWMAC_1000_CORE_HASH_TABLE_SIZE ) { + /* Too many addresses to be hashed, Use the + * pass all multi option instead */ + + for ( index = 0; index < 8; ++index ) { + self->macgrp->hash_table_reg[index] = 0xffffffff; + } + + self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_PM; + } else if ( num_multi > 0 ) { + uint32_t hash_shadow[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + ETHER_FIRST_MULTI( step, ac, enm ); + + while ( enm != NULL ) { + uint64_t addrlo = 0; + uint64_t addrhi = 0; + + memcpy( &addrlo, enm->enm_addrlo, ETHER_ADDR_LEN ); + memcpy( &addrhi, enm->enm_addrhi, ETHER_ADDR_LEN ); + + while ( addrlo <= addrhi ) { + /* XXX: ether_crc32_le() does not work, why? */ + uint32_t crc = ether_crc32_be( (uint8_t *) &addrlo, ETHER_ADDR_LEN ); + + /* The upper 8 bits of the bit reversed 32 bit CRC are used for hash filtering. + * The most significant bits determine the register to be used and the + * least significant five bits determine which bit to be set within the register */ + uint32_t index_reg = ( crc >> 29 ) & 0x7; + uint32_t index_bit = ( crc >> 24 ) & 0x1f; + + hash_shadow[index_reg] |= 1U << index_bit; + ++addrlo; + } + + ETHER_NEXT_MULTI( step, enm ); + } + + for ( index = 0; index < 8; ++index ) { + self->macgrp->hash_table_reg[index] = hash_shadow[index]; + } + + /* Hash filter for multicast */ + self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HMC; + } else { + /* Set all hash registers to accect to accept no multicast packets */ + for ( index = 0; index < 8; ++index ) { + self->macgrp->hash_table_reg[index] = 0x00000000; + } + + /* Hash filter for multicast */ + self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HMC; + } + + DWMAC_1000_CORE_PRINT_DBG( + "Frame Filter reg: 0x%08x\n", + self->macgrp->mac_frame_filter + ); + DWMAC_1000_CORE_PRINT_DBG( + "Hash regs:\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n" + "0x%08x\n", + self->macgrp->hash_table_reg[0], + self->macgrp->hash_table_reg[1], + self->macgrp->hash_table_reg[2], + self->macgrp->hash_table_reg[3], + self->macgrp->hash_table_reg[4], + self->macgrp->hash_table_reg[5], + self->macgrp->hash_table_reg[6], + self->macgrp->hash_table_reg[7] + ); + } +} + +const dwmac_common_core_ops dwmac_core_ops_1000 = { + .core_init = dwmac_1000_core_init, + .set_hash_filter = dwmac_1000_core_set_hash_filter, + .set_umac_addr = dwmac_1000_core_set_umac_addr, +}; diff --git a/c/src/libchip/network/dwmac-1000-dma.c b/c/src/libchip/network/dwmac-1000-dma.c new file mode 100644 index 0000000000..32e5914f08 --- /dev/null +++ b/c/src/libchip/network/dwmac-1000-dma.c @@ -0,0 +1,244 @@ +/** + * @file + * + * @brief DWMAC 1000 on-chip Ethernet controllers DMA handling + * + * Functions and data which are specific to the DWMAC 1000 DMA Handling. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include "dwmac-core.h" +#include "dwmac-common.h" + +typedef enum { + DWMAC100_OPERATION_MODE_TTC_CONTROL_64 = 0x00000000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_128 = 0x00004000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_192 = 0x00008000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_256 = 0x0000c000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_40 = 0x00010000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_32 = 0x00014000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_24 = 0x00018000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_16 = 0x0001c000, +} dwmac1000_operation_mode_ttc_control; + +typedef enum { + DWMAC100_OPERATION_MODE_RTC_CONTROL_64 = 0x00000000, + DWMAC100_OPERATION_MODE_RTC_CONTROL_32 = 0x00000008, + DWMAC100_OPERATION_MODE_RTC_CONTROL_96 = 0x00000010, + DWMAC100_OPERATION_MODE_RTC_CONTROL_128 = 0x00000018, +} dwmac1000_operation_mode_rtc_control; + +static int dwmac1000_dma_init( + dwmac_common_context *self, + const uint32_t pbl, + const uint32_t fb, + const uint32_t mb, + const bool use_enhanced_desc, + const uint32_t burst_len_4_support, + const uint32_t burst_len_8_support, + const uint32_t burst_len_16_support, + const uint32_t burst_boundary, + volatile dwmac_desc *dma_tx, + volatile dwmac_desc *dma_rx ) +{ + int eno = 0; + uint32_t value = self->dmagrp->bus_mode; + int limit = 10; + + + /* DMA SW reset */ + value |= DMAGRP_BUS_MODE_SWR; + self->dmagrp->bus_mode = value; + + while ( limit-- ) { + if ( !( self->dmagrp->bus_mode & DMAGRP_BUS_MODE_SWR ) ) + break; + + rtems_task_wake_after( rtems_clock_get_ticks_per_second() / 100 ); + } + + if ( limit < 0 ) { + eno = EBUSY; + } else { + /* + * Set the DMA PBL (Programmable Burst Length) mode + */ + if ( pbl >= DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_8 ) { + value = + DMAGRP_BUS_MODE_PBL( ( pbl + 1 ) / 8 ) | DMAGRP_BUS_MODE_RPBL( + ( pbl + 1 ) / 8 ) | DMAGRP_BUS_MODE_EIGHTXPBL; + } else { + value = DMAGRP_BUS_MODE_PBL( pbl + 1 ) | DMAGRP_BUS_MODE_RPBL( pbl + 1 ); + } + + /* Set the Fixed burst mode */ + if ( fb ) { + value |= DMAGRP_BUS_MODE_FB; + } + + /* Mixed Burst has no effect when fb is set */ + if ( mb ) { + value |= DMAGRP_BUS_MODE_MB; + } + + if ( use_enhanced_desc ) { + value |= DMAGRP_BUS_MODE_ATDS; + } + + self->dmagrp->bus_mode = value; + + /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE + * for supported bursts. + * + * Note: This is applicable only for revision GMACv3.61a. For + * older version this register is reserved and shall have no + * effect. + * + * Note: + * For Fixed Burst Mode: if we directly write 0xFF to this + * register using the configurations pass from platform code, + * this would ensure that all bursts supported by core are set + * and those which are not supported would remain ineffective. + * + * For Non Fixed Burst Mode: provide the maximum value of the + * burst length. Any burst equal or below the provided burst + * length would be allowed to perform. */ + value = self->dmagrp->axi_bus_mode; + + if ( burst_len_4_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND4; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND4; + } + + if ( burst_len_8_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND8; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND8; + } + + if ( burst_len_16_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND16; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND16; + } + + if ( burst_boundary ) { + value |= DMAGRP_AXI_BUS_MODE_ONEKBBE; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_ONEKBBE; + } + + self->dmagrp->axi_bus_mode = value; + + /* Mask interrupts by writing to CSR7 */ + dwmac_core_enable_dma_irq_rx( self ); + dwmac_core_enable_dma_irq_tx( self ); + + /* The base address of the RX/TX descriptor lists must be written into + * DMA CSR3 and CSR4, respectively. */ + self->dmagrp->transmit_descr_list_addr = (uintptr_t) &dma_tx[0]; + self->dmagrp->receive_descr_list_addr = (uintptr_t) &dma_rx[0]; + } + + return eno; +} + +static void dwmac1000_dma_operation_mode( + dwmac_common_context *self, + const unsigned int txmode, + const unsigned int rxmode ) +{ + uint32_t value = self->dmagrp->operation_mode; + + + if ( txmode == DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD ) { + /* Transmit COE type 2 cannot be done in cut-through mode. */ + value |= DMAGRP_OPERATION_MODE_TSF; + + /* Operating on second frame increase the performance + * especially when transmit store-and-forward is used.*/ + value |= DMAGRP_OPERATION_MODE_OSF; + } else { + value &= ~DMAGRP_OPERATION_MODE_TSF; + value &= ~DMAGRP_OPERATION_MODE_TTC_GET( value ); + + /* Set the transmit threshold */ + if ( txmode <= 32 ) { + value |= DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_32 + ); + } else if ( txmode <= 64 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_64 + ); + } else if ( txmode <= 128 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_128 + ); + } else if ( txmode <= 192 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_192 + ); + } else { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_256 + ); + } + } + + if ( rxmode == DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD ) { + value |= DMAGRP_OPERATION_MODE_RSF; + } else { + value &= ~DMAGRP_OPERATION_MODE_RSF; + value &= DMAGRP_OPERATION_MODE_RTC_GET( value ); + + if ( rxmode <= 32 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_32 + ); + } else if ( rxmode <= 64 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_64 + ); + } else if ( rxmode <= 96 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_96 + ); + } else { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_128 + ); + } + } + + self->dmagrp->operation_mode = value; +} + +const dwmac_common_dma_ops dwmac_dma_ops_1000 = { + .init = dwmac1000_dma_init, + .dma_mode = dwmac1000_dma_operation_mode, +}; diff --git a/c/src/libchip/network/dwmac-1000-ethernet-mac-ops.c b/c/src/libchip/network/dwmac-1000-ethernet-mac-ops.c new file mode 100644 index 0000000000..a4fe78241c --- /dev/null +++ b/c/src/libchip/network/dwmac-1000-ethernet-mac-ops.c @@ -0,0 +1,33 @@ +/** + * @file + * + * @brief Operations for the dwmac 1000 ethernet mac + * + * DWMAC_1000_ETHERNET_MAC_OPS will be accessible in the API header and can be + * passed to the configuration data if handling a DWMAC 1000 driver + */ + +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 "dwmac-common.h" + +extern const dwmac_common_dma_ops dwmac_dma_ops_1000; +extern const dwmac_common_core_ops dwmac_core_ops_1000; + +const dwmac_ethernet_mac_ops DWMAC_1000_ETHERNET_MAC_OPS = + DWMAC_ETHERNET_MAC_OPS_INITIALIZER( + &dwmac_core_ops_1000, + &dwmac_dma_ops_1000 + ); diff --git a/c/src/libchip/network/dwmac-common.h b/c/src/libchip/network/dwmac-common.h new file mode 100644 index 0000000000..b61b833078 --- /dev/null +++ b/c/src/libchip/network/dwmac-common.h @@ -0,0 +1,374 @@ +/** + * @file + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems./license/LICENSE. + */ + +#ifndef DWMAC_COMMON_H_ +#define DWMAC_COMMON_H_ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1 +#define __BSD_VISIBLE 1 + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "dwmac-desc.h" +#include "dwmac-regs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +/* Events */ +/* Common task events */ +#define DWMAC_COMMON_EVENT_TASK_INIT RTEMS_EVENT_1 +#define DWMAC_COMMON_EVENT_TASK_STOP RTEMS_EVENT_2 + +/* Events for the transmit task */ +#define DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME RTEMS_EVENT_3 +#define DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED RTEMS_EVENT_4 +#define DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD RTEMS_EVENT_5 +#define DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE RTEMS_EVENT_6 + +/* Events for the receive task */ +#define DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED RTEMS_EVENT_3 + +#ifdef __ARM_ARCH_7A__ + #define DWMAC_COMMON_DSB() _ARM_Data_synchronization_barrier() +#else /* __ARM_ARCH_7A__ */ + #define DWMAC_COMMON_DSB() +#endif /* __ARM_ARCH_7A__ */ + +/* Foreward declarations */ +typedef struct dwmac_common_core_ops dwmac_common_core_ops; +typedef struct dwmac_common_dma_ops dwmac_common_dma_ops; +typedef struct dwmac_common_desc_ops dwmac_common_desc_ops; + +typedef enum { /* IPC status */ + DWMAC_COMMON_RX_FRAME_STATUS_GOOD, + DWMAC_COMMON_RX_FRAME_STATUS_DISCARD, + DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE, + DWMAC_COMMON_RX_FRAME_STATUS_LLC_SNAP +} dwmac_common_rx_frame_status; + +typedef enum { + DWMAC_COMMON_STATE_DOWN, + DWMAC_COMMON_STATE_UP, + + DWMAC_COMMON_STATE_COUNT +} dwmac_common_state; + +typedef struct { + uint32_t link_down; + uint32_t link_up; +} dwmac_common_phy_status_counts; + +typedef struct { + uint32_t receive; + uint32_t transmit; + uint32_t tx_underflow; + uint32_t tx_jabber; + uint32_t rx_overflow; + uint32_t rx_early; + uint32_t rx_buf_unav; + uint32_t rx_process_stopped; + uint32_t rx_watchdog; + uint32_t tx_early; + uint32_t tx_buf_unav; + uint32_t tx_process_stopped; + uint32_t fatal_bus_error; + uint32_t unhandled; +} dwmac_common_dma_irq_counts; + +typedef struct { + uint32_t dest_addr_fail; /* When set, this bit indicates a frame that failed in the DA Filter in the MAC. */ + uint32_t crc_error; /* When set, this bit indicates that a CRC error occurred on the received frame. This field is valid only when the Last + Descriptor (RDES0[8]) is set. */ + uint32_t receive_error; /* When set, this bit indicates that the gmii_rxer_i signal is asserted while gmii_rxdv_i is asserted during frame + reception. Error can be of less or no extension, or error (rxd !=0xf) during extension. */ + uint32_t watchdog_timeout; /* When set, this bit indicates that the receive Watchdog Timer has expired while receiving the current frame and the + current frame is truncated after the Watchdog Timeout. */ + uint32_t late_collision; /* When set, this bit indicates that a late collision has occurred while receiving the frame in the half-duplex mode. */ + uint32_t giant_frame; /* When advanced timestamp feature is present, when set, this bit indicates that a snapshot of the Timestamp is + written in descriptor words 6 (RDES6) and 7 (RDES7). This is valid only when the Last Descriptor bit (RDES0[8]) is + set. + When IP Checksum Engine (Type 1) is selected, this bit, when set, indicates that the 16-bit IPv4 Header checksum + calculated by the EMAC did not match the received checksum bytes. + Otherwise, this bit, when set, indicates the Giant frame Status. Giant frames are larger than 1,518-byte (or + 1,522-byte for VLAN or 2,000-byte when Bit 27 (2KPE) of MAC Configuration register is set) normal frames and + larger than 9,018-byte (9,022-byte for VLAN) frame when Jumbo frame processing is enabled. */ + uint32_t overflow_error; /* When set, this bit indicates that the received frame was damaged because of buffer overflow in MTL. + Note: This bit is set only when the DMA transfers a partial frame to the application. This happens only when the RX + FIFO buffer is operating in the threshold mode. In the store-and-forward mode, all partial frames are dropped + completely in RX FIFO buffer. */ + uint32_t descriptor_error; /* When set, this bit indicates a frame truncation caused by a frame that does not fit within the current descriptor + buffers, and that the DMA does not own the Next descriptor. The frame is truncated. This field is valid only when the + Last Descriptor (RDES0[8]) is set. */ + uint32_t source_addr_fail; /* When set, this bit indicates that the SA field of frame failed the SA Filter in the MAC. */ + uint32_t length_error; /* When set, this bit indicates that the actual length of the frame received and that the Length/ Type field does not + match. This bit is valid only when the Frame Type (RDES0[5]) bit is reset. */ + uint32_t vlan_tag; /* When set, this bit indicates that the frame to which this descriptor is pointing is a VLAN frame tagged by the MAC. + The VLAN tagging depends on checking the VLAN fields of received frame based on the Register 7 (VLAN Tag + Register) setting. */ + uint32_t ethernet_frames; /* When set, this bit indicates that the receive frame is an Ethernet-type frame (the LT field is greater than or equal to + 0x0600). When this bit is reset, it indicates that the received frame is an IEEE802.3 frame. This bit is not valid for + Runt frames less than 14 bytes. */ + uint32_t dribble_bit_error; /* When set, this bit indicates that the received frame has a non-integer multiple of bytes (odd nibbles). This bit is valid + only in the MII Mode. */ +} dwmac_common_desc_status_counts_rx; + +typedef struct { + uint32_t jabber; /* When set, this bit indicates the MAC transmitter has experienced a jabber time-out. This bit is only set when Bit 22 + (Jabber Disable) of Register 0 (MAC Configuration Register) is not set. */ + uint32_t frame_flushed; /* When set, this bit indicates that the DMA or MTL flushed the frame because of a software Flush command given by + the CPU. */ + uint32_t losscarrier; /* When set, this bit indicates that a loss of carrier occurred during frame transmission (that is, the gmii_crs_i + signal was inactive for one or more transmit clock periods during frame transmission). This is valid only for the + frames transmitted without collision when the MAC operates in the half-duplex mode. */ + uint32_t no_carrier; /* When set, this bit indicates that the Carrier Sense signal form the PHY was not asserted during transmission. */ + uint32_t excessive_collisions; /* When set, this bit indicates that the transmission was aborted after 16 successive collisions while attempting to + transmit the current frame. If Bit 9 (Disable Retry) bit in the Register 0 (MAC Configuration Register) is set, this bit + is set after the first collision, and the transmission of the frame is aborted. */ + uint32_t excessive_deferral; /* When set, this bit indicates that the transmission has ended because of excessive deferral of over 24,288 bit times + (155,680 bits times in 1,000-Mbps mode or if Jumbo frame is enabled) if Bit 4 (Deferral Check) bit in Register 0 + (MAC Configuration Register) is set high. */ + uint32_t underflow; /* When set, this bit indicates that the MAC aborted the frame because the data arrived late from the Host memory. + Underflow Error indicates that the DMA encountered an empty transmit buffer while transmitting the frame. The + transmission process enters the Suspended state and sets both Transmit Underflow (Register 5[5]) and Transmit + Interrupt (Register 5[0]). */ + uint32_t ip_header_error; /* When set, this bit indicates that the MAC transmitter detected an error in the IP datagram header. The transmitter + checks the header length in the IPv4 packet against the number of header bytes received from the application and + indicates an error status if there is a mismatch. For IPv6 frames, a header error is reported if the main header length + is not 40 bytes. Furthermore, the Ethernet Length/Type field value for an IPv4 or IPv6 frame must match the IP + header version received with the packet. For IPv4 frames, an error status is also indicated if the Header Length field + has a value less than 0x5. */ + uint32_t payload_error; /* When set, this bit indicates that MAC transmitter detected an error in the TCP, UDP, or ICMP IP datagram payload. + The transmitter checks the payload length received in the IPv4 or IPv6 header against the actual number of TCP, + UDP, or ICMP packet bytes received from the application and issues an error status in case of a mismatch. */ + uint32_t deferred; /* When set, this bit indicates that the MAC defers before transmission because of the presence of carrier. This bit is + valid only in the half-duplex mode. */ + uint32_t vlan; /* When set, this bit indicates that the transmitted frame is a VLAN-type frame. */ +} dwmac_common_desc_status_counts_tx; + +typedef struct { + uint32_t errors; /* Frames with errors */ + uint32_t dropped; /* Frames dropped */ + uint32_t frames_good; /* Frames passed to the network stack */ + uint32_t bytes_good; /* Sum of bytes passed to the network stack */ + uint32_t frames; /* Frames handled (good or bad) */ + uint32_t dma_suspended; /* The receive DMA was supended due to lack of descriptors */ +} dwmac_common_rx_frame_counts; + +typedef struct { + uint32_t frames_from_stack; /* Frames received from the network stack fro tranmission */ + uint32_t frames_to_dma; /* Number of frames transmitted to DMA */ + uint32_t packets_to_dma; /* Number of packets transmitted to DMA*/ + uint32_t bytes_to_dma; /* Number of bytes transmitted */ + uint32_t packet_errors; /* Packets with errors */ + uint32_t packets_tranmitted_by_DMA; /* Packets tranmitted by the DMA */ +} dwmac_common_tx_frame_counts; + +typedef struct { + dwmac_common_phy_status_counts phy_status_counts; + dwmac_common_dma_irq_counts dma_irq_counts; + dwmac_common_desc_status_counts_rx desc_status_counts_rx; + dwmac_common_desc_status_counts_tx desc_status_counts_tx; + dwmac_common_rx_frame_counts frame_counts_rx; + dwmac_common_tx_frame_counts frame_counts_tx; +} dwmac_common_stats; + +typedef struct { + struct arpcom arpcom; + struct rtems_bsdnet_ifconfig *bsd_config; + struct rtems_mdio_info mdio; + rtems_id task_id_rx; + rtems_id task_id_tx; + rtems_id task_id_control; + void *arg; + volatile macgrp *macgrp; + volatile dmagrp *dmagrp; + unsigned int csr_clock; + dwmac_common_state state; + dwmac_common_stats stats; + unsigned int dma_threshold_control; + volatile dwmac_desc *dma_tx; + volatile dwmac_desc *dma_rx; + unsigned int idx_rx; + struct mbuf **mbuf_addr_rx; + struct mbuf **mbuf_addr_tx; + const dwmac_cfg *CFG; +} dwmac_common_context; + +struct dwmac_common_core_ops { + /* MAC core initialization */ + void (*core_init) ( dwmac_common_context *self ); + + /* Multicast filter setting */ + void (*set_hash_filter) ( + dwmac_common_context *self, + const bool add, + struct ifreq *ifr ); + + /* Set/Get Unicast MAC addresses */ + void (*set_umac_addr) ( + dwmac_common_context *ioaddr, + const unsigned char *addr, + const unsigned int reg_n ); +}; + +struct dwmac_common_dma_ops { + /* DMA core initialization */ + int (*init) ( + dwmac_common_context *self, + const uint32_t pbl, + const uint32_t fb, + const uint32_t mb, + const bool use_enhanced_desc, + const uint32_t burst_len_4_support, + const uint32_t burst_len_8_support, + const uint32_t burst_len_16_support, + const uint32_t burst_boundary, + volatile dwmac_desc *dma_tx, + volatile dwmac_desc *dma_rx ); + + /* Set tx/rx threshold in the csr6 register + * An invalid value enables the store-and-forward mode */ + void (*dma_mode) ( + dwmac_common_context *self, + const unsigned int txmode, + const unsigned int rxmode ); +}; + +struct dwmac_common_desc_ops { + /* Verify that it is OK to use the selected descriptor operations */ + int (*validate) ( dwmac_common_context *self ); + bool (*use_enhanced_descs) ( dwmac_common_context *self ); + + /* DMA RX descriptor ring allocation */ + int (*create_rx_desc) ( dwmac_common_context *self ); + + /* DMA TX descriptor ring allocation */ + int (*create_tx_desc) ( dwmac_common_context *self ); + + /* Free DMA RX descriptor ring */ + int (*destroy_rx_desc) ( dwmac_common_context *self ); + + /* Free DMA TX descriptor ring */ + int (*destroy_tx_desc) ( dwmac_common_context *self ); + + /* DMA RX descriptor initialization */ + void (*init_rx_desc) ( + dwmac_common_context *self, + const unsigned int index ); + + /* DMA TX descriptor ring initialization */ + void (*init_tx_desc) ( dwmac_common_context *self ); + + /* Free rx data buffers */ + void (*release_rx_bufs) ( dwmac_common_context *self ); + + /* Allocate a data buffer */ + struct mbuf *(*alloc_data_buf)( dwmac_common_context *self ); + + /* Free tx data buffers */ + void (*release_tx_bufs) ( dwmac_common_context *self ); + + /* Invoked by the xmit function to prepare the tx descriptor */ + void (*prepare_tx_desc) ( + dwmac_common_context *self, + const unsigned int idx, + const bool is_first, + const size_t len, + const void *pdata ); + + /* Set/get the owner of the descriptor */ + void (*release_tx_ownership) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + bool (*am_i_tx_owner) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + + /* Invoked by the xmit function to close the tx descriptor */ + void (*close_tx_desc) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + + /* Clean the tx descriptor as soon as the tx irq is received */ + void (*release_tx_desc) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + + /* Last tx segment reports the transmit status */ + int (*get_tx_ls) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + + /* Return the transmit status looking at the TDES1 */ + int (*tx_status) ( + dwmac_common_context *self, + const unsigned int idx_tx ); + + /* Handle extra events on specific interrupts hw dependent */ + bool (*am_i_rx_owner) ( + dwmac_common_context *self, + const unsigned int desc_idx ); + + /* Get the receive frame size */ + size_t (*get_rx_frame_len) ( + dwmac_common_context *self, + const unsigned int desc_idx ); + + /* Return the reception status looking at the RDES1 */ + dwmac_common_rx_frame_status (*rx_status) ( + dwmac_common_context *self, + const unsigned int desc_idx ); + bool (*is_first_rx_segment) ( + dwmac_common_context *self, + const unsigned int descriptor_index ); + bool (*is_last_rx_segment) ( + dwmac_common_context *self, + const unsigned int descriptor_index ); + void (*print_tx_desc) ( + volatile dwmac_desc *p, + const unsigned int count ); + void (*print_rx_desc) ( + volatile dwmac_desc *p, + const unsigned int count ); +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWMAC_COMMON_H_ */ diff --git a/c/src/libchip/network/dwmac-core.c b/c/src/libchip/network/dwmac-core.c new file mode 100644 index 0000000000..1050751e57 --- /dev/null +++ b/c/src/libchip/network/dwmac-core.c @@ -0,0 +1,406 @@ +/** + * @file + * + * @brief DWMAC 10/100/1000 Network Interface Controllers Core Handling + * + * DWMAC 10/100/1000 on-chip Synopsys IP Ethernet controllers. + * Driver core handling. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 "dwmac-core.h" +#include "dwmac-common.h" +#include "dwmac-regs.h" + +#undef DWMAC_CORE_DEBUG +#ifdef DWMAC_CORE_DEBUG +#define DWMAC_CORE_PRINT_DBG( fmt, args ... ) printk( fmt, ## args ) +#else +#define DWMAC_CORE_PRINT_DBG( fmt, args ... ) do { } while ( 0 ) +#endif + +/* DMA default interrupt masks */ +#define DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_RX \ + ( \ + DMAGRP_INTERRUPT_ENABLE_NIE \ + | DMAGRP_INTERRUPT_ENABLE_RIE \ + ) +#define DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_TX \ + ( \ + DMAGRP_INTERRUPT_ENABLE_NIE \ + | DMAGRP_INTERRUPT_ENABLE_TIE \ + | DMAGRP_INTERRUPT_ENABLE_FBE \ + | DMAGRP_INTERRUPT_ENABLE_UNE \ + | DMAGRP_INTERRUPT_ENABLE_AIE \ + ) + +#define DWMAC_CORE_INTR_STATUS_DEFAULT_MASK_RX \ + ( \ + DMAGRP_STATUS_NIS \ + | DMAGRP_STATUS_RI \ + ) +#define DWMAC_CORE_INTR_STATUS_DEFAULT_MASK_TX \ + ( \ + DMAGRP_STATUS_NIS \ + | DMAGRP_STATUS_TI \ + | DMAGRP_STATUS_FBI \ + | DMAGRP_STATUS_UNF \ + | DMAGRP_STATUS_AIS \ + ) + +/* CSR1 enables the transmit DMA to check for new descriptor */ +void dwmac_core_dma_restart_tx( dwmac_common_context *self ) +{ + self->dmagrp->transmit_poll_demand = 1; +} + +void dwmac_core_enable_dma_irq_tx( dwmac_common_context *self ) +{ + self->dmagrp->interrupt_enable |= DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_TX; +} + +void dwmac_core_enable_dma_irq_rx( dwmac_common_context *self ) +{ + self->dmagrp->interrupt_enable |= DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_RX; +} + +void dwmac_core_disable_dma_irq_tx( dwmac_common_context *self ) +{ + self->dmagrp->interrupt_enable &= ~DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_TX; +} + +void dwmac_core_reset_dma_irq_status_tx( dwmac_common_context *self ) +{ + self->dmagrp->status = DWMAC_CORE_INTR_STATUS_DEFAULT_MASK_TX; +} + +void dwmac_core_reset_dma_irq_status_rx( dwmac_common_context *self ) +{ + self->dmagrp->status = DWMAC_CORE_INTR_STATUS_DEFAULT_MASK_RX; +} + +void dwmac_core_disable_dma_irq_rx( dwmac_common_context *self ) +{ + self->dmagrp->interrupt_enable &= ~DWMAC_CORE_INTR_ENABLE_DEFAULT_MASK_RX; +} + +void dwmac_core_dma_start_tx( dwmac_common_context *self ) +{ + self->dmagrp->operation_mode |= DMAGRP_OPERATION_MODE_ST; +} + +void dwmac_core_dma_stop_tx( dwmac_common_context *self ) +{ + self->dmagrp->operation_mode &= ~DMAGRP_OPERATION_MODE_ST; +} + +void dwmac_core_dma_start_rx( dwmac_common_context *self ) +{ + self->dmagrp->operation_mode |= DMAGRP_OPERATION_MODE_SR; +} + +void dwmac_core_dma_stop_rx( dwmac_common_context *self ) +{ + self->dmagrp->operation_mode &= ~DMAGRP_OPERATION_MODE_SR; +} + +void dwmac_core_dma_restart_rx( dwmac_common_context *self ) +{ + self->dmagrp->receive_poll_demand = 1; +} + +#ifdef DWMAC_CORE_DEBUG +static void show_tx_process_state( const uint32_t status ) +{ + const uint32_t STATE = DMAGRP_STATUS_TS_GET( status ); + + + switch ( STATE ) { + case 0: + DWMAC_CORE_PRINT_DBG( "- TX (Stopped): Reset or Stop command\n" ); + break; + case 1: + DWMAC_CORE_PRINT_DBG( "- TX (Running):Fetching the Tx desc\n" ); + break; + case 2: + DWMAC_CORE_PRINT_DBG( "- TX (Running): Waiting for end of tx\n" ); + break; + case 3: + DWMAC_CORE_PRINT_DBG( "- TX (Running): Reading the data " + "and queuing the data into the Tx buf\n" ); + break; + case 6: + DWMAC_CORE_PRINT_DBG( "- TX (Suspended): Tx Buff Underflow " + "or an unavailable Transmit descriptor\n" ); + break; + case 7: + DWMAC_CORE_PRINT_DBG( "- TX (Running): Closing Tx descriptor\n" ); + break; + default: + break; + } +} + +static void show_rx_process_state( const uint32_t status ) +{ + const uint32_t STATE = DMAGRP_STATUS_RS_GET( status ); + + + switch ( STATE ) { + case 0: + DWMAC_CORE_PRINT_DBG( "- RX (Stopped): Reset or Stop command\n" ); + break; + case 1: + DWMAC_CORE_PRINT_DBG( "- RX (Running): Fetching the Rx desc\n" ); + break; + case 2: + DWMAC_CORE_PRINT_DBG( "- RX (Running):Checking for end of pkt\n" ); + break; + case 3: + DWMAC_CORE_PRINT_DBG( "- RX (Running): Waiting for Rx pkt\n" ); + break; + case 4: + DWMAC_CORE_PRINT_DBG( "- RX (Suspended): Unavailable Rx buf\n" ); + break; + case 5: + DWMAC_CORE_PRINT_DBG( "- RX (Running): Closing Rx descriptor\n" ); + break; + case 6: + DWMAC_CORE_PRINT_DBG( "- RX(Running): Flushing the current frame" + " from the Rx buf\n" ); + break; + case 7: + DWMAC_CORE_PRINT_DBG( "- RX (Running): Queuing the Rx frame" + " from the Rx buf into memory\n" ); + break; + default: + break; + } +} + +#else /* DWMAC_CORE_DEBUG */ + #define show_tx_process_state( status ) + #define show_rx_process_state( status ) +#endif /* DWMAC_CORE_DEBUG */ + +void dwmac_core_dma_interrupt( void *arg ) +{ + dwmac_common_context *self = (dwmac_common_context *) arg; + dwmac_common_dma_irq_counts *count = &self->stats.dma_irq_counts; + rtems_event_set events_receive = 0; + rtems_event_set events_transmit = 0; + + /* Get interrupt status */ + uint32_t irq_status = self->dmagrp->status & self->dmagrp->interrupt_enable; + uint32_t irq_handled = 0; + uint32_t irq_disable = 0; + + + DWMAC_CORE_PRINT_DBG( "%s: [CSR5: 0x%08x]\n", __func__, irq_status ); + + /* It displays the DMA process states (CSR5 register) if DWMAC_CORE_DEBUG is #defined */ + show_tx_process_state( self->dmagrp->status ); + show_rx_process_state( self->dmagrp->status ); + + /* Is there any abnormal interrupt? */ + if ( irq_status & DMAGRP_STATUS_AIS ) { + DWMAC_CORE_PRINT_DBG( "CSR5[15] DMA ABNORMAL IRQ: " ); + + if ( irq_status & DMAGRP_STATUS_UNF ) { + DWMAC_CORE_PRINT_DBG( "transmit underflow\n" ); + events_transmit |= DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD; + irq_handled |= DMAGRP_STATUS_UNF; + irq_disable |= DMAGRP_INTERRUPT_ENABLE_UNE; + ++count->tx_underflow; + } + + if ( irq_status & DMAGRP_STATUS_TJT ) { + DWMAC_CORE_PRINT_DBG( "transmit jabber\n" ); + irq_handled |= DMAGRP_STATUS_TJT; + ++count->tx_jabber; + } + + if ( irq_status & DMAGRP_STATUS_OVF ) { + DWMAC_CORE_PRINT_DBG( "recv overflow\n" ); + irq_handled |= DMAGRP_STATUS_OVF; + ++count->rx_overflow; + } + + if ( irq_status & DMAGRP_STATUS_TU ) { + DWMAC_CORE_PRINT_DBG( "transmit buffer unavailable\n" ); + irq_handled |= DMAGRP_STATUS_TU; + ++count->tx_buf_unav; + } + + if ( irq_status & DMAGRP_STATUS_RU ) { + DWMAC_CORE_PRINT_DBG( "receive buffer unavailable\n" ); + irq_handled |= DMAGRP_STATUS_RU; + ++count->rx_buf_unav; + } + + if ( irq_status & DMAGRP_STATUS_RPS ) { + DWMAC_CORE_PRINT_DBG( "receive process stopped\n" ); + irq_handled |= DMAGRP_STATUS_RPS; + ++count->rx_process_stopped; + } + + if ( irq_status & DMAGRP_STATUS_RWT ) { + DWMAC_CORE_PRINT_DBG( "receive watchdog\n" ); + irq_handled |= DMAGRP_STATUS_RWT; + ++count->rx_watchdog; + } + + if ( irq_status & DMAGRP_STATUS_ETI ) { + DWMAC_CORE_PRINT_DBG( "transmit early interrupt\n" ); + irq_handled |= DMAGRP_STATUS_ETI; + ++count->tx_early; + } + + if ( irq_status & DMAGRP_STATUS_ERI ) { + DWMAC_CORE_PRINT_DBG( "receive early interrupt\n" ); + irq_handled |= DMAGRP_STATUS_ERI; + ++count->rx_early; + } + + if ( irq_status & DMAGRP_STATUS_TPS ) { + DWMAC_CORE_PRINT_DBG( "transmit process stopped\n" ); + events_transmit |= DWMAC_COMMON_EVENT_TASK_INIT; + irq_handled |= DMAGRP_STATUS_TPS; + irq_disable |= DMAGRP_INTERRUPT_ENABLE_TSE; + ++count->tx_process_stopped; + } + + if ( irq_status & DMAGRP_STATUS_FBI ) { + DWMAC_CORE_PRINT_DBG( "fatal bus error\n" ); + events_transmit |= DWMAC_COMMON_EVENT_TASK_INIT; + irq_handled |= DMAGRP_STATUS_FBI; + irq_disable |= DMAGRP_INTERRUPT_ENABLE_FBE; + ++count->fatal_bus_error; + } + + irq_handled |= DMAGRP_STATUS_AIS; + } + + /* Is there any normal interrupt? */ + if ( irq_status & DMAGRP_STATUS_NIS ) { + /* Transmit interrupt */ + if ( irq_status & DMAGRP_STATUS_TI ) { + events_transmit |= DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED; + irq_handled |= DMAGRP_STATUS_TI; + irq_disable |= DMAGRP_INTERRUPT_ENABLE_TIE; + ++count->transmit; + } + + /* Receive interrupt */ + if ( irq_status & DMAGRP_STATUS_RI ) { + events_receive |= DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED; + irq_handled |= DMAGRP_STATUS_RI; + irq_disable |= DMAGRP_INTERRUPT_ENABLE_RIE; + ++count->receive; + } + + irq_handled |= DMAGRP_STATUS_NIS; + } + + /* Optional hardware blocks, interrupts should be disabled */ + if ( irq_status + & ( DMAGRP_STATUS_GMI | DMAGRP_STATUS_GLI ) ) { + DWMAC_CORE_PRINT_DBG( "%s: unexpected status %08x\n", __func__, + irq_status ); + + if ( irq_status & DMAGRP_STATUS_GMI ) { + irq_handled |= DMAGRP_STATUS_GMI; + ++count->unhandled; + } + + if ( irq_status & DMAGRP_STATUS_GLI ) { + irq_handled |= DMAGRP_STATUS_GLI; + ++count->unhandled; + } + } + + /* Count remaining unhandled interrupts (there should not be any) */ + if ( ( irq_status & 0x1FFCF ) != irq_handled ) { + ++count->unhandled; + } + + /* Disable interrupts which need further handling by tasks. + * The tasks will re-enable them. */ + self->dmagrp->interrupt_enable &= ~irq_disable; + + /* Clear interrupts */ + self->dmagrp->status = irq_handled; + + /* Send events to receive task */ + if ( events_receive != 0 ) { + (void) rtems_bsdnet_event_send( self->task_id_rx, events_receive ); + } + + /* Send events to transmit task */ + if ( events_transmit != 0 ) { + (void) rtems_bsdnet_event_send( self->task_id_tx, events_transmit ); + } + + DWMAC_CORE_PRINT_DBG( "\n\n" ); +} + +void dwmac_core_dma_flush_tx_fifo( dwmac_common_context *self ) +{ + self->dmagrp->operation_mode |= DMAGRP_OPERATION_MODE_FTF; + + do { + } while ( ( self->dmagrp->operation_mode & DMAGRP_OPERATION_MODE_FTF ) != 0 ); +} + +void dwmac_core_set_mac_addr( + const uint8_t addr[6], + volatile uint32_t *reg_high, + volatile uint32_t *reg_low ) +{ + uint32_t data = MAC_HIGH_ADDRHI( ( addr[5] << 8 ) | addr[4] ); + + + /* For MAC Addr registers se have to set the Address Enable (AE) + * bit that has no effect on the High Reg 0 where the bit 31 (MO) + * is RO. + */ + data |= MAC_HIGH_AE; + *reg_high = data; + + data = + ( (uint32_t) addr[3] << 24 ) + | ( (uint32_t) addr[2] << 16 ) + | ( (uint32_t) addr[1] << 8 ) + | addr[0]; + *reg_low = data; +} + +/* Enable disable MAC RX/TX */ +void dwmac_core_set_mac( + dwmac_common_context *self, + const bool enable ) +{ + uint32_t value = self->macgrp->mac_configuration; + + + if ( enable ) { + value |= MACGRP_MAC_CONFIGURATION_RE | MACGRP_MAC_CONFIGURATION_TE; + } else { + value &= ~( MACGRP_MAC_CONFIGURATION_RE | MACGRP_MAC_CONFIGURATION_TE ); + } + + self->macgrp->mac_configuration = value; +} diff --git a/c/src/libchip/network/dwmac-core.h b/c/src/libchip/network/dwmac-core.h new file mode 100644 index 0000000000..3a35d00729 --- /dev/null +++ b/c/src/libchip/network/dwmac-core.h @@ -0,0 +1,76 @@ +/** + * @file + * + * @brief DWMAC 10/100/1000 Network Interface Controllers Core Handling + * + * DWMAC 10/100/1000 on-chip Synopsys IP Ethernet controllers. + * Driver core handling. + * This header file is NOT part of the driver API. + */ + +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef DWMAC_CORE_H_ +#define DWMAC_CORE_H_ + +#include +#include "dwmac-common.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void dwmac_core_set_mac_addr( + const uint8_t addr[6], + volatile uint32_t *reg_high, + volatile uint32_t *reg_low ); + +void dwmac_core_set_mac( + dwmac_common_context *self, + const bool enable ); + +void dwmac_core_dma_start_tx( dwmac_common_context *self ); + +void dwmac_core_dma_stop_tx( dwmac_common_context *self ); + +void dwmac_core_dma_start_rx( dwmac_common_context *self ); + +void dwmac_core_dma_stop_rx( dwmac_common_context *self ); + +void dwmac_core_dma_restart_rx( dwmac_common_context *self ); + +void dwmac_core_dma_restart_tx( dwmac_common_context *self ); + +void dwmac_core_enable_dma_irq_rx( dwmac_common_context *self ); + +void dwmac_core_enable_dma_irq_tx( dwmac_common_context *self ); + +void dwmac_core_disable_dma_irq_tx( dwmac_common_context *self ); + +void dwmac_core_disable_dma_irq_rx( dwmac_common_context *self ); + +void dwmac_core_reset_dma_irq_status_tx( dwmac_common_context *self ); + +void dwmac_core_reset_dma_irq_status_rx( dwmac_common_context *self ); + +void dwmac_core_dma_interrupt( void *arg ); + +void dwmac_core_dma_flush_tx_fifo( dwmac_common_context *self ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWMAC_CORE_H_ */ diff --git a/c/src/libchip/network/dwmac-desc-com.c b/c/src/libchip/network/dwmac-desc-com.c new file mode 100644 index 0000000000..ecbd2624db --- /dev/null +++ b/c/src/libchip/network/dwmac-desc-com.c @@ -0,0 +1,60 @@ +/** + * @file + * + * @brief DWMAC 10/100/1000 Common Descriptor Handling + * + * DWMAC 10/100/1000 on-chip Ethernet controllers. + * Functions which are common to normal and enhanced DMA descriptors. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 "dwmac-desc-com.h" + +#undef DWMAC_DESC_COM_DEBUG +#ifdef DWMAC_DESC_COM_DEBUG +#define DWMAC_DESC_COM_PRINT_DBG( fmt, args ... ) printk( fmt, ## args ) +#else +#define DWMAC_DESC_COM_PRINT_DBG( fmt, args ... ) do { } while ( 0 ) +#endif + +struct mbuf *dwmac_desc_com_new_mbuf( dwmac_common_context *self ) { + struct ifnet *ifp = &self->arpcom.ac_if; + struct mbuf *m = NULL; + + + MGETHDR( m, M_DONTWAIT, MT_DATA ); + + if ( m != NULL ) { + MCLGET( m, M_DONTWAIT ); + + if ( m->m_ext.ext_buf != NULL ) { + if ( ( m->m_flags & M_EXT ) != 0 ) { + /* Set receive interface */ + m->m_pkthdr.rcvif = ifp; + + /* Make sure packet data will be aligned */ + m->m_data = mtod( m, char * ) + ETHER_ALIGN; + return m; + } else { + m_free( m ); + } + } else { + m_free( m ); + } + } + + return NULL; +} diff --git a/c/src/libchip/network/dwmac-desc-com.h b/c/src/libchip/network/dwmac-desc-com.h new file mode 100644 index 0000000000..da591c1a74 --- /dev/null +++ b/c/src/libchip/network/dwmac-desc-com.h @@ -0,0 +1,44 @@ +/** + * @file + * + * @brief DWMAC 10/100/1000 Common Descriptor Handling. + * + * DWMAC 10/100/1000 on-chip Ethernet controllers. + * Functions and data which are common to normal and enhanced DMA descriptors. + * This header file is NOT part of the driver API. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef DWMAC_DESC_COM_H_ +#define DWMAC_DESC_COM_H_ + +#include "dwmac-common.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DWMAC_DESC_COM_HW_CRC_BYTES 4 +#define DWMAC_DESC_COM_BUF_SIZE ( ETHER_MAX_LEN + DWMAC_DESC_COM_HW_CRC_BYTES ) + +struct mbuf *dwmac_desc_com_new_mbuf( dwmac_common_context *self ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWMAC_DESC_COM_H_ */ 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 + * + * + * 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 +#include +#include +#include "dwmac-common.h" +#include "dwmac-desc-com.h" +#include "dwmac-core.h" +#include + +#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 + ); diff --git a/c/src/libchip/network/dwmac-desc.h b/c/src/libchip/network/dwmac-desc.h new file mode 100644 index 0000000000..bc5b54abbe --- /dev/null +++ b/c/src/libchip/network/dwmac-desc.h @@ -0,0 +1,257 @@ +#ifndef DWMAC_DESC_RX_REGS_H +#define DWMAC_DESC_RX_REGS_H + +#include + +typedef struct { + uint32_t des0; +#define DWMAC_DESC_RX_DES0_OWN_BIT BSP_BIT32(31) +#define DWMAC_DESC_RX_DES0_DEST_ADDR_FILTER_FAIL BSP_BIT32(30) +#define DWMAC_DESC_RX_DES0_FRAME_LENGTH(val) BSP_FLD32(val, 16, 29) +#define DWMAC_DESC_RX_DES0_FRAME_LENGTH_GET(reg) BSP_FLD32GET(reg, 16, 29) +#define DWMAC_DESC_RX_DES0_FRAME_LENGTH_SET(reg, val) BSP_FLD32SET(reg, val, 16, 29) +#define DWMAC_DESC_RX_DES0_ERROR_SUMMARY BSP_BIT32(15) +#define DWMAC_DESC_RX_DES0_DESCRIPTOR_ERROR BSP_BIT32(14) +#define DWMAC_DESC_RX_DES0_SRC_ADDR_FILTER_FAIL BSP_BIT32(13) +#define DWMAC_DESC_RX_DES0_LENGTH_ERROR BSP_BIT32(12) +#define DWMAC_DESC_RX_DES0_OVERFLOW_ERROR BSP_BIT32(11) +#define DWMAC_DESC_RX_DES0_VLAN_TAG BSP_BIT32(10) +#define DWMAC_DESC_RX_DES0_FIRST_DESCRIPTOR BSP_BIT32(9) +#define DWMAC_DESC_RX_DES0_LAST_DESCRIPTOR BSP_BIT32(8) +#define DWMAC_DESC_RX_DES0_CHECKSUM_ERROR BSP_BIT32(7) +#define DWMAC_DESC_RX_DES0_LATE_COLLISION BSP_BIT32(6) +#define DWMAC_DESC_RX_DES0_FRAME_TYPE BSP_BIT32(5) +#define DWMAC_DESC_RX_DES0_RECEIVE_WATCHDOG_TIMEOUT BSP_BIT32(4) +#define DWMAC_DESC_RX_DES0_RECEIVE_ERROR BSP_BIT32(3) +#define DWMAC_DESC_RX_DES0_DRIBBLE_BIT_ERROR BSP_BIT32(2) +#define DWMAC_DESC_RX_DES0_CRC_ERROR BSP_BIT32(1) +#define DWMAC_DESC_RX_DES0_RX_MAC_ADDR_OR_PAYLOAD_CHECKSUM_ERROR BSP_BIT32(0) + uint32_t des1; +#define DWMAC_DESC_RX_DES1_DISABLE_IRQ_ON_COMPLETION BSP_BIT32(31) +#define DWMAC_DESC_RX_DES1_RECEIVE_END_OF_RING BSP_BIT32(25) +#define DWMAC_DESC_RX_DES1_SECOND_ADDR_CHAINED BSP_BIT32(24) +#define DWMAC_DESC_RX_DES1_RECEIVE_BUFFER_2_SIZE(val) BSP_FLD32(val, 11, 21) +#define DWMAC_DESC_RX_DES1_RECEIVE_BUFFER_2_SIZE_GET(reg) BSP_FLD32GET(reg, 11, 21) +#define DWMAC_DESC_RX_DES1_RECEIVE_BUFFER_2_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 11, 21) +#define DWMAC_DESC_RX_DES1_RECIVE_BUFFER_1_SIZE(val) BSP_FLD32(val, 0, 10) +#define DWMAC_DESC_RX_DES1_RECIVE_BUFFER_1_SIZE_GET(reg) BSP_FLD32GET(reg, 0, 10) +#define DWMAC_DESC_RX_DES1_RECIVE_BUFFER_1_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 10) + uint32_t des2; +#define DWMAC_DESC_RX_DES2_BUFF_1_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_RX_DES2_BUFF_1_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_RX_DES2_BUFF_1_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +#define DWMAC_DESC_RX_DES2_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_RX_DES2_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_RX_DES2_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des3; +#define DWMAC_DESC_RX_DES3_BUFF_2_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_RX_DES3_BUFF_2_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_RX_DES3_BUFF_2_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +#define DWMAC_DESC_RX_DES3_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_RX_DES3_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_RX_DES3_IEEE_RECEIVE_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_rx; + +typedef struct { + uint32_t des0; +#define DWMAC_DESC_TX_DES0_OWN_BIT BSP_BIT32(31) +#define DWMAC_DESC_TX_DES0_TX_TIMESTAMP_STATUS BSP_BIT32(17) +#define DWMAC_DESC_TX_DES0_IP_HEADER_ERROR BSP_BIT32(16) +#define DWMAC_DESC_TX_DES0_ERROR_SUMMARY BSP_BIT32(15) +#define DWMAC_DESC_TX_DES0_JABBER_TIMEOUT BSP_BIT32(14) +#define DWMAC_DESC_TX_DES0_FRAME_FLUSHED BSP_BIT32(13) +#define DWMAC_DESC_TX_DES0_PAYLOAD_CHECKSUM_ERROR BSP_BIT32(12) +#define DWMAC_DESC_TX_DES0_LOSS_OF_CARRIER BSP_BIT32(11) +#define DWMAC_DESC_TX_DES0_NO_CARRIER BSP_BIT32(10) +#define DWMAC_DESC_TX_DES0_EXCESSIVE_COLLISION BSP_BIT32(8) +#define DWMAC_DESC_TX_DES0_VLAN_FRAME BSP_BIT32(7) +#define DWMAC_DESC_TX_DES0_COLLISION_TIMEOUT(val) BSP_FLD32(val, 3, 6) +#define DWMAC_DESC_TX_DES0_COLLISION_TIMEOUT_GET(reg) BSP_FLD32GET(reg, 3, 6) +#define DWMAC_DESC_TX_DES0_COLLISION_TIMEOUT_SET(reg, val) BSP_FLD32SET(reg, val, 3, 6) +#define DWMAC_DESC_TX_DES0_EXCESSIVE_DEFERAL BSP_BIT32(2) +#define DWMAC_DESC_TX_DES0_UNDERFLOW_ERROR BSP_BIT32(1) +#define DWMAC_DESC_TX_DES0_DEFERED_BIT BSP_BIT32(0) + uint32_t des1; +#define DWMAC_DESC_TX_DES1_IRQ_ON_COMPLETION BSP_BIT32(31) +#define DWMAC_DESC_TX_DES1_LAST_SEGMENT BSP_BIT32(30) +#define DWMAC_DESC_TX_DES1_FIRST_SEGMENT BSP_BIT32(29) +#define DWMAC_DESC_TX_DES1_CHECKSUM_INSERTION_CONTROL(val) BSP_FLD32(val, 27, 28) +#define DWMAC_DESC_TX_DES1_CHECKSUM_INSERTION_CONTROL_GET(reg) BSP_FLD32GET(reg, 27, 28) +#define DWMAC_DESC_TX_DES1_CHECKSUM_INSERTION_CONTROL_SET(reg, val) BSP_FLD32SET(reg, val, 27, 28) +#define DWMAC_DESC_TX_DES1_DISABLE_CRC BSP_BIT32(26) +#define DWMAC_DESC_TX_DES1_TRANSMIT_END_OF_RING BSP_BIT32(25) +#define DWMAC_DESC_TX_DES1_SECOND_ADDRESS_CHAINED BSP_BIT32(24) +#define DWMAC_DESC_TX_DES1_DISABLE_PADDING BSP_BIT32(23) +#define DWMAC_DESC_TX_DES1_TRANSMIT_TIMESTAMP_ENABLE BSP_BIT32(22) +#define DWMAC_DESC_TX_DES1_TRANMIT_BUFFER_2_SIZE(val) BSP_FLD32(val, 11, 21) +#define DWMAC_DESC_TX_DES1_TRANMIT_BUFFER_2_SIZE_GET(reg) BSP_FLD32GET(reg, 11, 21) +#define DWMAC_DESC_TX_DES1_TRANMIT_BUFFER_2_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 11, 21) +#define DWMAC_DESC_TX_DES1_TRANSMIT_BUFFER_1_SIZE(val) BSP_FLD32(val, 0, 10) +#define DWMAC_DESC_TX_DES1_TRANSMIT_BUFFER_1_SIZE_GET(reg) BSP_FLD32GET(reg, 0, 10) +#define DWMAC_DESC_TX_DES1_TRANSMIT_BUFFER_1_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 10) + uint32_t des2; +#define DWMAC_DESC_TX_DES2_BUFF_1_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_TX_DES2_BUFF_1_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_TX_DES2_BUFF_1_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +#define DWMAC_DESC_TX_DES2_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_TX_DES2_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_TX_DES2_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des3; +#define DWMAC_DESC_TX_DES3_BUFF_2_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_TX_DES3_BUFF_2_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_TX_DES3_BUFF_2_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +#define DWMAC_DESC_TX_DES3_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_TX_DES3_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_TX_DES3_IEEE_TRANSMIT_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_tx; + +typedef struct { + uint32_t des0; +#define DWMAC_DESC_ERX_DES0_OWN_BIT BSP_BIT32(31) +#define DWMAC_DESC_ERX_DES0_DEST_ADDR_FILTER_FAIL BSP_BIT32(30) +#define DWMAC_DESC_ERX_DES0_FRAME_LENGTH(val) BSP_FLD32(val, 16, 29) +#define DWMAC_DESC_ERX_DES0_FRAME_LENGTH_GET(reg) BSP_FLD32GET(reg, 16, 29) +#define DWMAC_DESC_ERX_DES0_FRAME_LENGTH_SET(reg, val) BSP_FLD32SET(reg, val, 16, 29) +#define DWMAC_DESC_ERX_DES0_ERROR_SUMMARY BSP_BIT32(15) +#define DWMAC_DESC_ERX_DES0_DESCRIPTOR_ERROR BSP_BIT32(14) +#define DWMAC_DESC_ERX_DES0_SRC_ADDR_FILTER_FAIL BSP_BIT32(13) +#define DWMAC_DESC_ERX_DES0_LENGTH_ERROR BSP_BIT32(12) +#define DWMAC_DESC_ERX_DES0_OVERFLOW_ERROR BSP_BIT32(11) +#define DWMAC_DESC_ERX_DES0_VLAN_TAG BSP_BIT32(10) +#define DWMAC_DESC_ERX_DES0_FIRST_DESCRIPTOR BSP_BIT32(9) +#define DWMAC_DESC_ERX_DES0_LAST_DESCRIPTOR BSP_BIT32(8) +#define DWMAC_DESC_ERX_DES0_TIMESTAMP_AVAIL_OR_CHECKSUM_ERROR_OR_GIANT_FRAME BSP_BIT32(7) +#define DWMAC_DESC_ERX_DES0_LATE_COLLISION BSP_BIT32(6) +#define DWMAC_DESC_ERX_DES0_FREAME_TYPE BSP_BIT32(5) +#define DWMAC_DESC_ERX_DES0_RECEIVE_WATCHDOG_TIMEOUT BSP_BIT32(4) +#define DWMAC_DESC_ERX_DES0_RECEIVE_ERROR BSP_BIT32(3) +#define DWMAC_DESC_ERX_DES0_DRIBBLE_BIT_ERROR BSP_BIT32(2) +#define DWMAC_DESC_ERX_DES0_CRC_ERROR BSP_BIT32(1) +#define DWMAC_DESC_ERX_DES0_EXT_STATUS_AVAIL_OR_RX_MAC_ADDR_STATUS BSP_BIT32(0) + uint32_t des1; +#define DWMAC_DESC_ERX_DES1_DISABLE_IRQ_ON_COMPLETION BSP_BIT32(31) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_2_SIZE(val) BSP_FLD32(val, 16, 28) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_2_SIZE_GET(reg) BSP_FLD32GET(reg, 16, 28) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_2_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 16, 28) +#define DWMAC_DESC_ERX_DES1_RECEIVE_END_OF_RING BSP_BIT32(15) +#define DWMAC_DESC_ERX_DES1_SECOND_ADDR_CHAINED BSP_BIT32(14) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE(val) BSP_FLD32(val, 0, 12) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE_GET(reg) BSP_FLD32GET(reg, 0, 12) +#define DWMAC_DESC_ERX_DES1_RECEIVE_BUFF_1_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 12) + uint32_t des2; +#define DWMAC_DESC_ERX_DES2_BUFF_1_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_ERX_DES2_BUFF_1_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_ERX_DES2_BUFF_1_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des3; +#define DWMAC_DESC_ERX_DES3_BUFF_2_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_ERX_DES3_BUFF_2_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_ERX_DES3_BUFF_2_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_erx; + +typedef struct { + uint32_t des0; +#define DWMAC_DESC_ETX_DES0_OWN_BIT BSP_BIT32(31) +#define DWMAC_DESC_ETX_DES0_IRQ_ON_COMPLETION BSP_BIT32(30) +#define DWMAC_DESC_ETX_DES0_LAST_SEGMENT BSP_BIT32(29) +#define DWMAC_DESC_ETX_DES0_FIRST_SEGMENT BSP_BIT32(28) +#define DWMAC_DESC_ETX_DES0_DISABLE_CRC BSP_BIT32(27) +#define DWMAC_DESC_ETX_DES0_DISABLE_PAD BSP_BIT32(26) +#define DWMAC_DESC_ETX_DES0_TRANSMIT_TIMESTAMP_ENABLE BSP_BIT32(25) +#define DWMAC_DESC_ETX_DES0_CHECKSUM_INSERTION_CONTROL(val) BSP_FLD32(val, 22, 23) +#define DWMAC_DESC_ETX_DES0_CHECKSUM_INSERTION_CONTROL_GET(reg) BSP_FLD32GET(reg, 22, 23) +#define DWMAC_DESC_ETX_DES0_CHECKSUM_INSERTION_CONTROL_SET(reg, val) BSP_FLD32SET(reg, val, 22, 23) +#define DWMAC_DESC_ETX_DES0_TRANSMIT_END_OF_RING BSP_BIT32(21) +#define DWMAC_DESC_ETX_DES0_SECOND_ADDR_CHAINED BSP_BIT32(20) +#define DWMAC_DESC_ETX_DES0_TRANSMIT_TIMESTAMP_STATUS BSP_BIT32(17) +#define DWMAC_DESC_ETX_DES0_IP_HEADER_ERROR BSP_BIT32(16) +#define DWMAC_DESC_ETX_DES0_ERROR_SUMMARY BSP_BIT32(15) +#define DWMAC_DESC_ETX_DES0_JABBER_TIMEOUT BSP_BIT32(14) +#define DWMAC_DESC_ETX_DES0_FRAME_FLUSHED BSP_BIT32(13) +#define DWMAC_DESC_ETX_DES0_IP_PAYLOAD_ERROR BSP_BIT32(12) +#define DWMAC_DESC_ETX_DES0_LOSS_OF_CARRIER BSP_BIT32(11) +#define DWMAC_DESC_ETX_DES0_NO_CARRIER BSP_BIT32(10) +#define DWMAC_DESC_ETX_DES0_EXCESSIVE_COLLISION BSP_BIT32(8) +#define DWMAC_DESC_ETX_DES0_VLAN_FRAME BSP_BIT32(7) +#define DWMAC_DESC_ETX_DES0_COLLISION_COUNT(val) BSP_FLD32(val, 3, 6) +#define DWMAC_DESC_ETX_DES0_COLLISION_COUNT_GET(reg) BSP_FLD32GET(reg, 3, 6) +#define DWMAC_DESC_ETX_DES0_COLLISION_COUNT_SET(reg, val) BSP_FLD32SET(reg, val, 3, 6) +#define DWMAC_DESC_ETX_DES0_EXCESSIVE_DEFERAL BSP_BIT32(2) +#define DWMAC_DESC_ETX_DES0_UNDERFLOW_ERROR BSP_BIT32(1) +#define DWMAC_DESC_ETX_DES0_DEFERRED_BIT BSP_BIT32(0) + uint32_t des1; +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_2_SIZE(val) BSP_FLD32(val, 16, 28) +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_2_SIZE_GET(reg) BSP_FLD32GET(reg, 16, 28) +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_2_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 16, 28) +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_1_SIZE(val) BSP_FLD32(val, 0, 12) +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_1_SIZE_GET(reg) BSP_FLD32GET(reg, 0, 12) +#define DWMAC_DESC_ETX_DES1_TRANSMIT_BUFFER_1_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 12) + uint32_t des2; +#define DWMAC_DESC_ETX_DES2_BUFF_1_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_ETX_DES2_BUFF_1_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_ETX_DES2_BUFF_1_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des3; +#define DWMAC_DESC_ETX_DES3_BUFF_2_ADDR_PTR(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_ETX_DES3_BUFF_2_ADDR_PTR_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_ETX_DES3_BUFF_2_ADDR_PTR_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_etx; + +typedef union { + dwmac_desc_rx rx; + dwmac_desc_tx tx; + dwmac_desc_erx erx; + dwmac_desc_etx etx; +} dwmac_desc; + +typedef struct { + dwmac_desc_erx des0_3; + uint32_t des4; +#define DWMAC_DESC_EXT_ERX_DES4_LAYER3_AND_LAYER4_FILTER_MATCHED(val) BSP_FLD32(val, 26, 27) +#define DWMAC_DESC_EXT_ERX_DES4_LAYER3_AND_LAYER4_FILTER_MATCHED_GET(reg) BSP_FLD32GET(reg, 26, 27) +#define DWMAC_DESC_EXT_ERX_DES4_LAYER3_AND_LAYER4_FILTER_MATCHED_SET(reg, val) BSP_FLD32SET(reg, val, 26, 27) +#define DWMAC_DESC_EXT_ERX_DES4_LAYER4_FILTER_MATCH BSP_BIT32(25) +#define DWMAC_DESC_EXT_ERX_DES4_LAYER3_FILTER_MATCH BSP_BIT32(24) +#define DWMAC_DESC_EXT_ERX_DES4_TIMESTAMP_DROPPED BSP_BIT32(14) +#define DWMAC_DESC_EXT_ERX_DES4_PTP_VERSION BSP_BIT32(13) +#define DWMAC_DESC_EXT_ERX_DES4_PTP_FRAME_TYPE BSP_BIT32(12) +#define DWMAC_DESC_EXT_ERX_DES4_MESSAGE_TYPE(val) BSP_FLD32(val, 8, 11) +#define DWMAC_DESC_EXT_ERX_DES4_MESSAGE_TYPE_GET(reg) BSP_FLD32GET(reg, 8, 11) +#define DWMAC_DESC_EXT_ERX_DES4_MESSAGE_TYPE_SET(reg, val) BSP_FLD32SET(reg, val, 8, 11) +#define DWMAC_DESC_EXT_ERX_DES4_IPV6_PACKET_RECEIVED BSP_BIT32(7) +#define DWMAC_DESC_EXT_ERX_DES4_IPV4_PACKET_RECEIVED BSP_BIT32(6) +#define DWMAC_DESC_EXT_ERX_DES4_IP_CHECKSUM_BYPASSED BSP_BIT32(5) +#define DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_ERROR BSP_BIT32(4) +#define DWMAC_DESC_EXT_ERX_DES4_IP_HEADER_ERROR BSP_BIT32(3) +#define DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE(val) BSP_FLD32(val, 0, 2) +#define DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE_GET(reg) BSP_FLD32GET(reg, 0, 2) +#define DWMAC_DESC_EXT_ERX_DES4_IP_PAYLOAD_TYPE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 2) + uint32_t des5; + uint32_t des6; +#define DWMAC_DESC_EXT_ERX_DES6_RECEIVE_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_EXT_ERX_DES6_RECEIVE_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_EXT_ERX_DES6_RECEIVE_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des7; +#define DWMAC_DESC_EXT_ERX_DES7_RECEIVE_FRAME_TIMESTAMP_HIGH(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_EXT_ERX_DES7_RECEIVE_FRAME_TIMESTAMP_HIGH_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_EXT_ERX_DES7_RECEIVE_FRAME_TIMESTAMP_HIGH_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_ext_erx; + +typedef struct { + dwmac_desc_etx des0_3; + uint32_t des4; + uint32_t des5; + uint32_t des6; +#define DWMAC_DESC_EXT_ETX_DES6_TRANSMIT_FRAME_TIMESTAMP_LOW(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_EXT_ETX_DES6_TRANSMIT_FRAME_TIMESTAMP_LOW_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_EXT_ETX_DES6_TRANSMIT_FRAME_TIMESTAMP_LOW_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t des7; +#define DWMAC_DESC_EXT_ETX_DES7_TRANSMIT_FRAME_TIMESTAMP_HIGH(val) BSP_FLD32(val, 0, 31) +#define DWMAC_DESC_EXT_ETX_DES7_TRANSMIT_FRAME_TIMESTAMP_HIGH_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DWMAC_DESC_EXT_ETX_DES7_TRANSMIT_FRAME_TIMESTAMP_HIGH_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) +} dwmac_desc_ext_etx; + +typedef union { + dwmac_desc_ext_erx erx; + dwmac_desc_ext_etx etx; +} dwmac_desc_ext; + +#endif /* DWMAC_DESC_RX_REGS_H */ diff --git a/c/src/libchip/network/dwmac-regs.h b/c/src/libchip/network/dwmac-regs.h new file mode 100644 index 0000000000..53d7486750 --- /dev/null +++ b/c/src/libchip/network/dwmac-regs.h @@ -0,0 +1,515 @@ +#ifndef MAC_REGS_H +#define MAC_REGS_H + +#include + +typedef struct { + uint32_t high; +#define MAC_HIGH_ADDRHI(val) BSP_FLD32(val, 0, 15) +#define MAC_HIGH_ADDRHI_GET(reg) BSP_FLD32GET(reg, 0, 15) +#define MAC_HIGH_ADDRHI_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15) +#define MAC_HIGH_MBC0 BSP_BIT32(24) +#define MAC_HIGH_MBC1 BSP_BIT32(25) +#define MAC_HIGH_MBC2 BSP_BIT32(26) +#define MAC_HIGH_MBC3 BSP_BIT32(27) +#define MAC_HIGH_MBC4 BSP_BIT32(28) +#define MAC_HIGH_MBC5 BSP_BIT32(29) +#define MAC_HIGH_SA BSP_BIT32(30) +#define MAC_HIGH_AE BSP_BIT32(31) + uint32_t low; +#define MAC_LOW_ADDRLO(val) BSP_FLD32(val, 0, 32) +#define MAC_LOW_ADDRLO_GET(reg) BSP_FLD32GET(reg, 0, 32) +#define MAC_LOW_ADDRLO_SET(reg, val) BSP_FLD32SET(reg, val, 0, 32) +} mac; + +typedef struct { + uint32_t mac_configuration; +#define MACGRP_MAC_CONFIGURATION_PRELEN(val) BSP_FLD32(val, 0, 1) +#define MACGRP_MAC_CONFIGURATION_PRELEN_GET(reg) BSP_FLD32GET(reg, 0, 1) +#define MACGRP_MAC_CONFIGURATION_PRELEN_SET(reg, val) BSP_FLD32SET(reg, val, 0, 1) +#define MACGRP_MAC_CONFIGURATION_RE BSP_BIT32(2) +#define MACGRP_MAC_CONFIGURATION_TE BSP_BIT32(3) +#define MACGRP_MAC_CONFIGURATION_DC BSP_BIT32(4) +#define MACGRP_MAC_CONFIGURATION_BL(val) BSP_FLD32(val, 5, 6) +#define MACGRP_MAC_CONFIGURATION_BL_GET(reg) BSP_FLD32GET(reg, 5, 6) +#define MACGRP_MAC_CONFIGURATION_BL_SET(reg, val) BSP_FLD32SET(reg, val, 5, 6) +#define MACGRP_MAC_CONFIGURATION_ACS BSP_BIT32(7) +#define MACGRP_MAC_CONFIGURATION_LUD BSP_BIT32(8) +#define MACGRP_MAC_CONFIGURATION_DR BSP_BIT32(9) +#define MACGRP_MAC_CONFIGURATION_IPC BSP_BIT32(10) +#define MACGRP_MAC_CONFIGURATION_DM BSP_BIT32(11) +#define MACGRP_MAC_CONFIGURATION_LM BSP_BIT32(12) +#define MACGRP_MAC_CONFIGURATION_DO BSP_BIT32(13) +#define MACGRP_MAC_CONFIGURATION_FES BSP_BIT32(14) +#define MACGRP_MAC_CONFIGURATION_PS BSP_BIT32(15) +#define MACGRP_MAC_CONFIGURATION_DCRS BSP_BIT32(16) +#define MACGRP_MAC_CONFIGURATION_IFG(val) BSP_FLD32(val, 17, 19) +#define MACGRP_MAC_CONFIGURATION_IFG_GET(reg) BSP_FLD32GET(reg, 17, 19) +#define MACGRP_MAC_CONFIGURATION_IFG_SET(reg, val) BSP_FLD32SET(reg, val, 17, 19) +#define MACGRP_MAC_CONFIGURATION_JE BSP_BIT32(20) +#define MACGRP_MAC_CONFIGURATION_BE BSP_BIT32(21) +#define MACGRP_MAC_CONFIGURATION_JD BSP_BIT32(22) +#define MACGRP_MAC_CONFIGURATION_WD BSP_BIT32(23) +#define MACGRP_MAC_CONFIGURATION_TC BSP_BIT32(24) +#define MACGRP_MAC_CONFIGURATION_CST BSP_BIT32(25) +#define MACGRP_MAC_CONFIGURATION_TWOKPE BSP_BIT32(27) + uint32_t mac_frame_filter; +#define MACGRP_MAC_FRAME_FILTER_PR BSP_BIT32(0) +#define MACGRP_MAC_FRAME_FILTER_HUC BSP_BIT32(1) +#define MACGRP_MAC_FRAME_FILTER_HMC BSP_BIT32(2) +#define MACGRP_MAC_FRAME_FILTER_DAIF BSP_BIT32(3) +#define MACGRP_MAC_FRAME_FILTER_PM BSP_BIT32(4) +#define MACGRP_MAC_FRAME_FILTER_DBF BSP_BIT32(5) +#define MACGRP_MAC_FRAME_FILTER_PCF(val) BSP_FLD32(val, 6, 7) +#define MACGRP_MAC_FRAME_FILTER_PCF_GET(reg) BSP_FLD32GET(reg, 6, 7) +#define MACGRP_MAC_FRAME_FILTER_PCF_SET(reg, val) BSP_FLD32SET(reg, val, 6, 7) +#define MACGRP_MAC_FRAME_FILTER_SAIF BSP_BIT32(8) +#define MACGRP_MAC_FRAME_FILTER_SAF BSP_BIT32(9) +#define MACGRP_MAC_FRAME_FILTER_HPF BSP_BIT32(10) +#define MACGRP_MAC_FRAME_FILTER_VTFE BSP_BIT32(16) +#define MACGRP_MAC_FRAME_FILTER_IPFE BSP_BIT32(20) +#define MACGRP_MAC_FRAME_FILTER_DNTU BSP_BIT32(21) +#define MACGRP_MAC_FRAME_FILTER_RA BSP_BIT32(31) + uint32_t reserved_08[2]; + uint32_t gmii_address; +#define MACGRP_GMII_ADDRESS_GMII_BUSY BSP_BIT32(0) +#define MACGRP_GMII_ADDRESS_GMII_WRITE BSP_BIT32(1) +#define MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE(val) BSP_FLD32(val, 2, 5) +#define MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_GET(reg) BSP_FLD32GET(reg, 2, 5) +#define MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_SET(reg, val) BSP_FLD32SET(reg, val, 2, 5) +#define MACGRP_GMII_ADDRESS_GMII_REGISTER(val) BSP_FLD32(val, 6, 10) +#define MACGRP_GMII_ADDRESS_GMII_REGISTER_GET(reg) BSP_FLD32GET(reg, 6, 10) +#define MACGRP_GMII_ADDRESS_GMII_REGISTER_SET(reg, val) BSP_FLD32SET(reg, val, 6, 10) +#define MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS(val) BSP_FLD32(val, 11, 15) +#define MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_GET(reg) BSP_FLD32GET(reg, 11, 15) +#define MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET(reg, val) BSP_FLD32SET(reg, val, 11, 15) + uint32_t gmii_data; +#define MACGRP_GMII_DATA_GMII_DATA(val) BSP_FLD32(val, 0, 15) +#define MACGRP_GMII_DATA_GMII_DATA_GET(reg) BSP_FLD32GET(reg, 0, 15) +#define MACGRP_GMII_DATA_GMII_DATA_SET(reg, val) BSP_FLD32SET(reg, val, 0, 15) + uint32_t reserved_18[9]; + uint32_t interrupt_mask; +#define MACGRP_INTERRUPT_MASK_RGSMIIIM BSP_BIT32(0) +#define MACGRP_INTERRUPT_MASK_PCSLCHGIM BSP_BIT32(1) +#define MACGRP_INTERRUPT_MASK_PCSANCIM BSP_BIT32(2) +#define MACGRP_INTERRUPT_MASK_TSIM BSP_BIT32(9) +#define MACGRP_INTERRUPT_MASK_LPIIM BSP_BIT32(10) + mac mac_addr0_15[16]; + uint32_t reserved_c0[16]; + uint32_t mmc_control; +#define MACGRP_MMC_CONTROL_CNTRST BSP_BIT32(0) +#define MACGRP_MMC_CONTROL_CNTSTOPRO BSP_BIT32(1) +#define MACGRP_MMC_CONTROL_RSTONRD BSP_BIT32(2) +#define MACGRP_MMC_CONTROL_CNTFREEZ BSP_BIT32(3) +#define MACGRP_MMC_CONTROL_CNTPRST BSP_BIT32(4) +#define MACGRP_MMC_CONTROL_CNTPRSTLVL BSP_BIT32(5) +#define MACGRP_MMC_CONTROL_UCDBC BSP_BIT32(8) + uint32_t mmc_receive_interrupt; +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXGBFRMIS BSP_BIT32(0) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXGBOCTIS BSP_BIT32(1) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXGOCTIS BSP_BIT32(2) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXBCGFIS BSP_BIT32(3) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXMCGFIS BSP_BIT32(4) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXCRCERFIS BSP_BIT32(5) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXALGNERFIS BSP_BIT32(6) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXRUNTFIS BSP_BIT32(7) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXJABERFIS BSP_BIT32(8) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXUSIZEGFIS BSP_BIT32(9) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXOSIZEGFIS BSP_BIT32(10) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX64OCTGBFIS BSP_BIT32(11) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX65T127OCTGBFIS BSP_BIT32(12) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX128T255OCTGBFIS BSP_BIT32(13) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX256T511OCTGBFIS BSP_BIT32(14) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX512T1023OCTGBFIS BSP_BIT32(15) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RX1024TMAXOCTGBFIS BSP_BIT32(16) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXUCGFIS BSP_BIT32(17) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXLENERFIS BSP_BIT32(18) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXORANGEFIS BSP_BIT32(19) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXPAUSFIS BSP_BIT32(20) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXFOVFIS BSP_BIT32(21) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXVLANGBFIS BSP_BIT32(22) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXWDOGFIS BSP_BIT32(23) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXRCVERRFIS BSP_BIT32(24) +#define MACGRP_MMC_RECEIVE_INTERRUPT_RXCTRLFIS BSP_BIT32(25) + uint32_t mmc_transmit_interrupt; +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXGBOCTIS BSP_BIT32(0) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXGBFRMIS BSP_BIT32(1) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXBCGFIS BSP_BIT32(2) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXMCGFIS BSP_BIT32(3) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX64OCTGBFIS BSP_BIT32(4) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX65T127OCTGBFIS BSP_BIT32(5) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX128T255OCTGBFIS BSP_BIT32(6) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX256T511OCTGBFIS BSP_BIT32(7) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX512T1023OCTGBFIS BSP_BIT32(8) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TX1024TMAXOCTGBFIS BSP_BIT32(9) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXUCGBFIS BSP_BIT32(10) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXMCGBFIS BSP_BIT32(11) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXBCGBFIS BSP_BIT32(12) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXUFLOWERFIS BSP_BIT32(13) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXSCOLGFIS BSP_BIT32(14) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXMCOLGFIS BSP_BIT32(15) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXDEFFIS BSP_BIT32(16) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXLATCOLFIS BSP_BIT32(17) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXEXCOLFIS BSP_BIT32(18) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXCARERFIS BSP_BIT32(19) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXGOCTIS BSP_BIT32(20) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXGFRMIS BSP_BIT32(21) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXEXDEFFIS BSP_BIT32(22) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXPAUSFIS BSP_BIT32(23) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXVLANGFIS BSP_BIT32(24) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_TXOSIZEGFIS BSP_BIT32(25) + uint32_t mmc_receive_interrupt_mask; +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXGBFRMIM BSP_BIT32(0) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXGBOCTIM BSP_BIT32(1) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXGOCTIM BSP_BIT32(2) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXBCGFIM BSP_BIT32(3) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXMCGFIM BSP_BIT32(4) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXCRCERFIM BSP_BIT32(5) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXALGNERFIM BSP_BIT32(6) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXRUNTFIM BSP_BIT32(7) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXJABERFIM BSP_BIT32(8) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXUSIZEGFIM BSP_BIT32(9) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXOSIZEGFIM BSP_BIT32(10) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX64OCTGBFIM BSP_BIT32(11) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX65T127OCTGBFIM BSP_BIT32(12) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX128T255OCTGBFIM BSP_BIT32(13) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX256T511OCTGBFIM BSP_BIT32(14) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX512T1023OCTGBFIM BSP_BIT32(15) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RX1024TMAXOCTGBFIM BSP_BIT32(16) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXUCGFIM BSP_BIT32(17) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXLENERFIM BSP_BIT32(18) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXORANGEFIM BSP_BIT32(19) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXPAUSFIM BSP_BIT32(20) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXFOVFIM BSP_BIT32(21) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXVLANGBFIM BSP_BIT32(22) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXWDOGFIM BSP_BIT32(23) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXRCVERRFIM BSP_BIT32(24) +#define MACGRP_MMC_RECEIVE_INTERRUPT_MASK_RXCTRLFIM BSP_BIT32(25) + uint32_t mmc_transmit_interrupt_mask; +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXGBOCTIM BSP_BIT32(0) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXGBFRMIM BSP_BIT32(1) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXBCGFIM BSP_BIT32(2) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXMCGFIM BSP_BIT32(3) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX64OCTGBFIM BSP_BIT32(4) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX65T127OCTGBFIM BSP_BIT32(5) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX128T255OCTGBFIM BSP_BIT32(6) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX256T511OCTGBFIM BSP_BIT32(7) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX512T1023OCTGBFIM BSP_BIT32(8) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TX1024TMAXOCTGBFIM BSP_BIT32(9) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXUCGBFIM BSP_BIT32(10) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXMCGBFIM BSP_BIT32(11) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXBCGBFIM BSP_BIT32(12) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXUFLOWERFIM BSP_BIT32(13) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXSCOLGFIM BSP_BIT32(14) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXMCOLGFIM BSP_BIT32(15) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXDEFFIM BSP_BIT32(16) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXLATCOLFIM BSP_BIT32(17) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXEXCOLFIM BSP_BIT32(18) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXCARERFIM BSP_BIT32(19) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXGOCTIM BSP_BIT32(20) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXGFRMIM BSP_BIT32(21) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXEXDEFFIM BSP_BIT32(22) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXPAUSFIM BSP_BIT32(23) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXVLANGFIM BSP_BIT32(24) +#define MACGRP_MMC_TRANSMIT_INTERRUPT_MASK_TXOSIZEGFIM BSP_BIT32(25) + uint32_t txoctetcount_gb; + uint32_t txframecount_gb; + uint32_t txbroadcastframes_g; + uint32_t txmulticastframes_g; + uint32_t tx64octets_gb; + uint32_t tx65to127octets_gb; + uint32_t tx128to255octets_gb; + uint32_t tx256to511octets_gb; + uint32_t tx512to1023octets_gb; + uint32_t tx1024tomaxoctets_gb; + uint32_t txunicastframes_gb; + uint32_t txmulticastframes_gb; + uint32_t txbroadcastframes_gb; + uint32_t txunderflowerror; + uint32_t txsinglecol_g; + uint32_t txmulticol_g; + uint32_t txdeferred; + uint32_t txlatecol; + uint32_t txexesscol; + uint32_t txcarriererr; + uint32_t txoctetcnt; + uint32_t txframecount_g; + uint32_t txexcessdef; + uint32_t txpauseframes; + uint32_t txvlanframes_g; + uint32_t txoversize_g; + uint32_t reserved_17c; + uint32_t rxframecount_gb; + uint32_t rxoctetcount_gb; + uint32_t rxoctetcount_g; + uint32_t rxbroadcastframes_g; + uint32_t rxmulticastframes_g; + uint32_t rxcrcerror; + uint32_t rxalignmenterror; + uint32_t rxrunterror; + uint32_t rxjabbererror; + uint32_t rxundersize_g; + uint32_t rxoversize_g; + uint32_t rx64octets_gb; + uint32_t rx65to127octets_gb; + uint32_t rx128to255octets_gb; + uint32_t rx256to511octets_gb; + uint32_t rx512to1023octets_gb; + uint32_t rx1024tomaxoctets_gb; + uint32_t rxunicastframes_g; + uint32_t rxlengtherror; + uint32_t rxoutofrangetype; + uint32_t rxpauseframes; + uint32_t rxfifooverflow; + uint32_t rxvlanframes_gb; + uint32_t rxwatchdogerror; + uint32_t rxrcverror; + uint32_t rxctrlframes_g; + uint32_t reserved_1e8[6]; + uint32_t mmc_ipc_receive_interrupt_mask; +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4GFIM BSP_BIT32(0) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4HERFIM BSP_BIT32(1) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4NOPAYFIM BSP_BIT32(2) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4FRAGFIM BSP_BIT32(3) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4UDSBLFIM BSP_BIT32(4) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6GFIM BSP_BIT32(5) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6HERFIM BSP_BIT32(6) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6NOPAYFIM BSP_BIT32(7) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXUDPGFIM BSP_BIT32(8) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXUDPERFIM BSP_BIT32(9) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXTCPGFIM BSP_BIT32(10) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXTCPERFIM BSP_BIT32(11) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXICMPGFIM BSP_BIT32(12) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXICMPERFIM BSP_BIT32(13) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4GOIM BSP_BIT32(16) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4HEROIM BSP_BIT32(17) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4NOPAYOIM BSP_BIT32(18) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4FRAGOIM BSP_BIT32(19) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV4UDSBLOIM BSP_BIT32(20) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6GOIM BSP_BIT32(21) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6HEROIM BSP_BIT32(22) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXIPV6NOPAYOIM BSP_BIT32(23) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXUDPGOIM BSP_BIT32(24) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXUDPEROIM BSP_BIT32(25) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXTCPGOIM BSP_BIT32(26) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXTCPEROIM BSP_BIT32(27) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXICMPGOIM BSP_BIT32(28) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_MASK_RXICMPEROIM BSP_BIT32(29) + uint32_t reserved_204; + uint32_t mmc_ipc_receive_interrupt; +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4GFIS BSP_BIT32(0) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4HERFIS BSP_BIT32(1) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4NOPAYFIS BSP_BIT32(2) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4FRAGFIS BSP_BIT32(3) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4UDSBLFIS BSP_BIT32(4) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6GFIS BSP_BIT32(5) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6HERFIS BSP_BIT32(6) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6NOPAYFIS BSP_BIT32(7) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXUDPGFIS BSP_BIT32(8) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXUDPERFIS BSP_BIT32(9) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXTCPGFIS BSP_BIT32(10) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXTCPERFIS BSP_BIT32(11) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXICMPGFIS BSP_BIT32(12) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXICMPERFIS BSP_BIT32(13) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4GOIS BSP_BIT32(16) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4HEROIS BSP_BIT32(17) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4NOPAYOIS BSP_BIT32(18) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4FRAGOIS BSP_BIT32(19) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV4UDSBLOIS BSP_BIT32(20) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6GOIS BSP_BIT32(21) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6HEROIS BSP_BIT32(22) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXIPV6NOPAYOIS BSP_BIT32(23) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXUDPGOIS BSP_BIT32(24) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXUDPEROIS BSP_BIT32(25) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXTCPGOIS BSP_BIT32(26) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXTCPEROIS BSP_BIT32(27) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXICMPGOIS BSP_BIT32(28) +#define MACGRP_MMC_IPC_RECEIVE_INTERRUPT_RXICMPEROIS BSP_BIT32(29) + uint32_t reserved_20c; + uint32_t rxipv4_gd_frms; + uint32_t rxipv4_hdrerr_frms; + uint32_t rxipv4_nopay_frms; + uint32_t rxipv4_frag_frms; + uint32_t rxipv4_udsbl_frms; + uint32_t rxipv6_gd_frms; + uint32_t rxipv6_hdrerr_frms; + uint32_t rxipv6_nopay_frms; + uint32_t rxudp_gd_frms; + uint32_t rxudp_err_frms; + uint32_t rxtcp_gd_frms; + uint32_t rxtcp_err_frms; + uint32_t rxicmp_gd_frms; + uint32_t rxicmp_err_frms; + uint32_t reserved_248[2]; + uint32_t rxipv4_gd_octets; + uint32_t rxipv4_hdrerr_octets; + uint32_t rxipv4_nopay_octets; + uint32_t rxipv4_frag_octets; + uint32_t rxipv4_udsbl_octets; + uint32_t rxipv6_gd_octets; + uint32_t rxipv6_hdrerr_octets; + uint32_t rxipv6_nopay_octets; + uint32_t rxudp_gd_octets; + uint32_t rxudp_err_octets; + uint32_t rxtcp_gd_octets; + uint32_t rxtcperroctets; + uint32_t rxicmp_gd_octets; + uint32_t rxicmp_err_octets; + uint32_t reserved_288[158]; + uint32_t hash_table_reg[8]; + uint32_t reserved_520[184]; + mac mac_addr16_127[112]; +} macgrp; + +typedef struct { + uint32_t bus_mode; +#define DMAGRP_BUS_MODE_SWR BSP_BIT32(0) +#define DMAGRP_BUS_MODE_DSL(val) BSP_FLD32(val, 2, 6) +#define DMAGRP_BUS_MODE_DSL_GET(reg) BSP_FLD32GET(reg, 2, 6) +#define DMAGRP_BUS_MODE_DSL_SET(reg, val) BSP_FLD32SET(reg, val, 2, 6) +#define DMAGRP_BUS_MODE_ATDS BSP_BIT32(7) +#define DMAGRP_BUS_MODE_PBL(val) BSP_FLD32(val, 8, 13) +#define DMAGRP_BUS_MODE_PBL_GET(reg) BSP_FLD32GET(reg, 8, 13) +#define DMAGRP_BUS_MODE_PBL_SET(reg, val) BSP_FLD32SET(reg, val, 8, 13) +#define DMAGRP_BUS_MODE_FB BSP_BIT32(16) +#define DMAGRP_BUS_MODE_RPBL(val) BSP_FLD32(val, 17, 22) +#define DMAGRP_BUS_MODE_RPBL_GET(reg) BSP_FLD32GET(reg, 17, 22) +#define DMAGRP_BUS_MODE_RPBL_SET(reg, val) BSP_FLD32SET(reg, val, 17, 22) +#define DMAGRP_BUS_MODE_USP BSP_BIT32(23) +#define DMAGRP_BUS_MODE_EIGHTXPBL BSP_BIT32(24) +#define DMAGRP_BUS_MODE_AAL BSP_BIT32(25) +#define DMAGRP_BUS_MODE_MB BSP_BIT32(26) + uint32_t transmit_poll_demand; +#define DMAGRP_TRANSMIT_POLL_DEMAND_TPD(val) BSP_FLD32(val, 0, 31) +#define DMAGRP_TRANSMIT_POLL_DEMAND_TPD_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DMAGRP_TRANSMIT_POLL_DEMAND_TPD_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t receive_poll_demand; +#define DMAGRP_RECEIVE_POLL_DEMAND_RPD(val) BSP_FLD32(val, 0, 31) +#define DMAGRP_RECEIVE_POLL_DEMAND_RPD_GET(reg) BSP_FLD32GET(reg, 0, 31) +#define DMAGRP_RECEIVE_POLL_DEMAND_RPD_SET(reg, val) BSP_FLD32SET(reg, val, 0, 31) + uint32_t receive_descr_list_addr; +#define DMAGRP_RECEIVE_DESCR_LIST_ADDR_RDESLA_32BIT(val) BSP_FLD32(val, 2, 31) +#define DMAGRP_RECEIVE_DESCR_LIST_ADDR_RDESLA_32BIT_GET(reg) BSP_FLD32GET(reg, 2, 31) +#define DMAGRP_RECEIVE_DESCR_LIST_ADDR_RDESLA_32BIT_SET(reg, val) BSP_FLD32SET(reg, val, 2, 31) + uint32_t transmit_descr_list_addr; +#define DMAGRP_TRANSMIT_DESCR_LIST_ADDR_TDESLA_32BIT(val) BSP_FLD32(val, 2, 31) +#define DMAGRP_TRANSMIT_DESCR_LIST_ADDR_TDESLA_32BIT_GET(reg) BSP_FLD32GET(reg, 2, 31) +#define DMAGRP_TRANSMIT_DESCR_LIST_ADDR_TDESLA_32BIT_SET(reg, val) BSP_FLD32SET(reg, val, 2, 31) + uint32_t status; +#define DMAGRP_STATUS_TI BSP_BIT32(0) +#define DMAGRP_STATUS_TPS BSP_BIT32(1) +#define DMAGRP_STATUS_TU BSP_BIT32(2) +#define DMAGRP_STATUS_TJT BSP_BIT32(3) +#define DMAGRP_STATUS_OVF BSP_BIT32(4) +#define DMAGRP_STATUS_UNF BSP_BIT32(5) +#define DMAGRP_STATUS_RI BSP_BIT32(6) +#define DMAGRP_STATUS_RU BSP_BIT32(7) +#define DMAGRP_STATUS_RPS BSP_BIT32(8) +#define DMAGRP_STATUS_RWT BSP_BIT32(9) +#define DMAGRP_STATUS_ETI BSP_BIT32(10) +#define DMAGRP_STATUS_FBI BSP_BIT32(13) +#define DMAGRP_STATUS_ERI BSP_BIT32(14) +#define DMAGRP_STATUS_AIS BSP_BIT32(15) +#define DMAGRP_STATUS_NIS BSP_BIT32(16) +#define DMAGRP_STATUS_RS(val) BSP_FLD32(val, 17, 19) +#define DMAGRP_STATUS_RS_GET(reg) BSP_FLD32GET(reg, 17, 19) +#define DMAGRP_STATUS_RS_SET(reg, val) BSP_FLD32SET(reg, val, 17, 19) +#define DMAGRP_STATUS_TS(val) BSP_FLD32(val, 20, 22) +#define DMAGRP_STATUS_TS_GET(reg) BSP_FLD32GET(reg, 20, 22) +#define DMAGRP_STATUS_TS_SET(reg, val) BSP_FLD32SET(reg, val, 20, 22) +#define DMAGRP_STATUS_EB(val) BSP_FLD32(val, 23, 25) +#define DMAGRP_STATUS_EB_GET(reg) BSP_FLD32GET(reg, 23, 25) +#define DMAGRP_STATUS_EB_SET(reg, val) BSP_FLD32SET(reg, val, 23, 25) +#define DMAGRP_STATUS_GLI BSP_BIT32(26) +#define DMAGRP_STATUS_GMI BSP_BIT32(27) +#define DMAGRP_STATUS_TTI BSP_BIT32(29) +#define DMAGRP_STATUS_GLPII BSP_BIT32(30) + uint32_t operation_mode; +#define DMAGRP_OPERATION_MODE_SR BSP_BIT32(1) +#define DMAGRP_OPERATION_MODE_OSF BSP_BIT32(2) +#define DMAGRP_OPERATION_MODE_RTC(val) BSP_FLD32(val, 3, 4) +#define DMAGRP_OPERATION_MODE_RTC_GET(reg) BSP_FLD32GET(reg, 3, 4) +#define DMAGRP_OPERATION_MODE_RTC_SET(reg, val) BSP_FLD32SET(reg, val, 3, 4) +#define DMAGRP_OPERATION_MODE_FUF BSP_BIT32(6) +#define DMAGRP_OPERATION_MODE_FEF BSP_BIT32(7) +#define DMAGRP_OPERATION_MODE_EFC BSP_BIT32(8) +#define DMAGRP_OPERATION_MODE_RFA(val) BSP_FLD32(val, 9, 10) +#define DMAGRP_OPERATION_MODE_RFA_GET(reg) BSP_FLD32GET(reg, 9, 10) +#define DMAGRP_OPERATION_MODE_RFA_SET(reg, val) BSP_FLD32SET(reg, val, 9, 10) +#define DMAGRP_OPERATION_MODE_RFD(val) BSP_FLD32(val, 11, 12) +#define DMAGRP_OPERATION_MODE_RFD_GET(reg) BSP_FLD32GET(reg, 11, 12) +#define DMAGRP_OPERATION_MODE_RFD_SET(reg, val) BSP_FLD32SET(reg, val, 11, 12) +#define DMAGRP_OPERATION_MODE_ST BSP_BIT32(13) +#define DMAGRP_OPERATION_MODE_TTC(val) BSP_FLD32(val, 14, 16) +#define DMAGRP_OPERATION_MODE_TTC_GET(reg) BSP_FLD32GET(reg, 14, 16) +#define DMAGRP_OPERATION_MODE_TTC_SET(reg, val) BSP_FLD32SET(reg, val, 14, 16) +#define DMAGRP_OPERATION_MODE_FTF BSP_BIT32(20) +#define DMAGRP_OPERATION_MODE_TSF BSP_BIT32(21) +#define DMAGRP_OPERATION_MODE_DFF BSP_BIT32(24) +#define DMAGRP_OPERATION_MODE_RSF BSP_BIT32(25) +#define DMAGRP_OPERATION_MODE_DT BSP_BIT32(26) + uint32_t interrupt_enable; +#define DMAGRP_INTERRUPT_ENABLE_TIE BSP_BIT32(0) +#define DMAGRP_INTERRUPT_ENABLE_TSE BSP_BIT32(1) +#define DMAGRP_INTERRUPT_ENABLE_TUE BSP_BIT32(2) +#define DMAGRP_INTERRUPT_ENABLE_TJE BSP_BIT32(3) +#define DMAGRP_INTERRUPT_ENABLE_OVE BSP_BIT32(4) +#define DMAGRP_INTERRUPT_ENABLE_UNE BSP_BIT32(5) +#define DMAGRP_INTERRUPT_ENABLE_RIE BSP_BIT32(6) +#define DMAGRP_INTERRUPT_ENABLE_RUE BSP_BIT32(7) +#define DMAGRP_INTERRUPT_ENABLE_RSE BSP_BIT32(8) +#define DMAGRP_INTERRUPT_ENABLE_RWE BSP_BIT32(9) +#define DMAGRP_INTERRUPT_ENABLE_ETE BSP_BIT32(10) +#define DMAGRP_INTERRUPT_ENABLE_FBE BSP_BIT32(13) +#define DMAGRP_INTERRUPT_ENABLE_ERE BSP_BIT32(14) +#define DMAGRP_INTERRUPT_ENABLE_AIE BSP_BIT32(15) +#define DMAGRP_INTERRUPT_ENABLE_NIE BSP_BIT32(16) + uint32_t reserved_20[2]; + uint32_t axi_bus_mode; +#define DMAGRP_AXI_BUS_MODE_UNDEFINED BSP_BIT32(0) +#define DMAGRP_AXI_BUS_MODE_BLEND4 BSP_BIT32(1) +#define DMAGRP_AXI_BUS_MODE_BLEND8 BSP_BIT32(2) +#define DMAGRP_AXI_BUS_MODE_BLEND16 BSP_BIT32(3) +#define DMAGRP_AXI_BUS_MODE_AXI_AAL BSP_BIT32(12) +#define DMAGRP_AXI_BUS_MODE_ONEKBBE BSP_BIT32(13) +#define DMAGRP_AXI_BUS_MODE_RD_OSR_LMT(val) BSP_FLD32(val, 16, 19) +#define DMAGRP_AXI_BUS_MODE_RD_OSR_LMT_GET(reg) BSP_FLD32GET(reg, 16, 19) +#define DMAGRP_AXI_BUS_MODE_RD_OSR_LMT_SET(reg, val) BSP_FLD32SET(reg, val, 16, 19) +#define DMAGRP_AXI_BUS_MODE_WR_OSR_LMT(val) BSP_FLD32(val, 20, 23) +#define DMAGRP_AXI_BUS_MODE_WR_OSR_LMT_GET(reg) BSP_FLD32GET(reg, 20, 23) +#define DMAGRP_AXI_BUS_MODE_WR_OSR_LMT_SET(reg, val) BSP_FLD32SET(reg, val, 20, 23) +#define DMAGRP_AXI_BUS_MODE_LPI_XIT_FRM BSP_BIT32(30) +#define DMAGRP_AXI_BUS_MODE_EN_LPI BSP_BIT32(31) + uint32_t reserved_2c[11]; + uint32_t hw_feature; +#define DMAGRP_HW_FEATURE_MIISEL BSP_BIT32(0) +#define DMAGRP_HW_FEATURE_GMIISEL BSP_BIT32(1) +#define DMAGRP_HW_FEATURE_HDSEL BSP_BIT32(2) +#define DMAGRP_HW_FEATURE_HASHSEL BSP_BIT32(4) +#define DMAGRP_HW_FEATURE_ADDMACADRSEL BSP_BIT32(5) +#define DMAGRP_HW_FEATURE_PCSSEL BSP_BIT32(6) +#define DMAGRP_HW_FEATURE_SMASEL BSP_BIT32(8) +#define DMAGRP_HW_FEATURE_RWKSEL BSP_BIT32(9) +#define DMAGRP_HW_FEATURE_MGKSEL BSP_BIT32(10) +#define DMAGRP_HW_FEATURE_MMCSEL BSP_BIT32(11) +#define DMAGRP_HW_FEATURE_TSVER1SEL BSP_BIT32(12) +#define DMAGRP_HW_FEATURE_TSVER2SEL BSP_BIT32(13) +#define DMAGRP_HW_FEATURE_EEESEL BSP_BIT32(14) +#define DMAGRP_HW_FEATURE_AVSEL BSP_BIT32(15) +#define DMAGRP_HW_FEATURE_TXOESEL BSP_BIT32(16) +#define DMAGRP_HW_FEATURE_RXTYP1COE BSP_BIT32(17) +#define DMAGRP_HW_FEATURE_RXTYP2COE BSP_BIT32(18) +#define DMAGRP_HW_FEATURE_RXFIFOSIZE BSP_BIT32(19) +#define DMAGRP_HW_FEATURE_RXCHCNT(val) BSP_FLD32(val, 20, 21) +#define DMAGRP_HW_FEATURE_RXCHCNT_GET(reg) BSP_FLD32GET(reg, 20, 21) +#define DMAGRP_HW_FEATURE_RXCHCNT_SET(reg, val) BSP_FLD32SET(reg, val, 20, 21) +#define DMAGRP_HW_FEATURE_TXCHCNT(val) BSP_FLD32(val, 22, 23) +#define DMAGRP_HW_FEATURE_TXCHCNT_GET(reg) BSP_FLD32GET(reg, 22, 23) +#define DMAGRP_HW_FEATURE_TXCHCNT_SET(reg, val) BSP_FLD32SET(reg, val, 22, 23) +#define DMAGRP_HW_FEATURE_ENHDESSEL BSP_BIT32(24) +#define DMAGRP_HW_FEATURE_ACTPHYIF(val) BSP_FLD32(val, 28, 30) +#define DMAGRP_HW_FEATURE_ACTPHYIF_GET(reg) BSP_FLD32GET(reg, 28, 30) +#define DMAGRP_HW_FEATURE_ACTPHYIF_SET(reg, val) BSP_FLD32SET(reg, val, 28, 30) +} dmagrp; + +#endif /* MAC_REGS_H */ diff --git a/c/src/libchip/network/dwmac.c b/c/src/libchip/network/dwmac.c new file mode 100644 index 0000000000..a4373d2388 --- /dev/null +++ b/c/src/libchip/network/dwmac.c @@ -0,0 +1,2325 @@ +/** + * @file + * + * @brief DWMAC 10/100/1000 Network Interface Controller + * + * DWMAC 10/100/1000 on-chip Ethernet controllers are a Synopsys IP Core. + * This is the main mode for the network interface controller. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include "dwmac-common.h" +#include "dwmac-core.h" +#include + +/* PHY events which can be combined to an event set. + * The PHY can create an event for a corresponding status change */ +const dwmac_phy_event PHY_EVENT_JABBER = 0x80; +const dwmac_phy_event PHY_EVENT_RECEIVE_ERROR = 0x40; +const dwmac_phy_event PHY_EVENT_PAGE_RECEIVE = 0x20; +const dwmac_phy_event PHY_EVENT_PARALLEL_DETECT_FAULT = 0x10; +const dwmac_phy_event PHY_EVENT_LINK_PARTNER_ACK = 0x08; +const dwmac_phy_event PHY_EVENT_LINK_DOWN = 0x04; +const dwmac_phy_event PHY_EVENT_REMOTE_FAULT = 0x02; +const dwmac_phy_event PHY_EVENT_LINK_UP = 0x01; + +/* Default values for the number of DMA descriptors and mbufs to be used */ +#define DWMAC_CONFIG_RX_UNIT_COUNT_DEFAULT 256 +#define DWMAC_CONFIG_RX_UNIT_COUNT_MAX INT_MAX +#define DWMAC_CONFIG_TX_UNIT_COUNT_DEFAULT 256 +#define DWMAC_CONFIG_TX_UNIT_COUNT_MAX INT_MAX + +/* Default values for the DMA configuration */ +#define DWMAC_DMA_BUS_MODE_PBL_DEFAULT DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_8 +#define DWMAC_DMA_BUS_MODE_FB_DEFAULT \ + DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR +#define DWMAC_DMA_BUS_MODE_MIXED_BURSTS_DEFAULT \ + DWMAC_DMA_CFG_BUS_MODE_BURST_NOT_MIXED +#define DWMAC_DMA_AXI_BURST_LENGTH_4_DEFAULT \ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_NOT_SUPPORTED +#define DWMAC_DMA_AXI_BURST_LENGTH_8_DEFAULT \ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_NOT_SUPPORTED +#define DWMAC_DMA_AXI_BURST_LENGTH_16_DEFAULT \ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_NOT_SUPPORTED +#define DWMAC_DMA_AXI_BURST_BOUNDARY_DEFAULT \ + DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB + +/* CSR Frequency Access Defines*/ +#define DWCGNAC3504_CSR_F_35M 35000000 +#define DWCGNAC3504_CSR_F_60M 60000000 +#define DWCGNAC3504_CSR_F_100M 100000000 +#define DWCGNAC3504_CSR_F_150M 150000000 +#define DWCGNAC3504_CSR_F_250M 250000000 +#define DWCGNAC3504_CSR_F_300M 300000000 + +/* MDC Clock Selection define*/ +#define DWCGNAC3504_CSR_60_100M 0x0 /* MDC = clk_scr_i/42 */ +#define DWCGNAC3504_CSR_100_150M 0x1 /* MDC = clk_scr_i/62 */ +#define DWCGNAC3504_CSR_20_35M 0x2 /* MDC = clk_scr_i/16 */ +#define DWCGNAC3504_CSR_35_60M 0x3 /* MDC = clk_scr_i/26 */ +#define DWCGNAC3504_CSR_150_250M 0x4 /* MDC = clk_scr_i/102 */ +#define DWCGNAC3504_CSR_250_300M 0x5 /* MDC = clk_scr_i/122 */ + +#define DWMAC_ALIGN( value, num_bytes_to_align_to ) \ + ( ( ( value ) + ( ( typeof( value ) )( num_bytes_to_align_to ) - 1 ) ) \ + & ~( ( typeof( value ) )( num_bytes_to_align_to ) - 1 ) ) + +#undef DWMAC_DEBUG +#ifdef DWMAC_DEBUG +#define DWMAC_PRINT_DBG( fmt, args ... ) printk( fmt, ## args ) +#else +#define DWMAC_PRINT_DBG( fmt, args ... ) do { } while ( 0 ) +#endif + +#define DWMAC_DMA_THRESHOLD_CONTROL_DEFAULT 64 + +static int dwmac_if_mdio_busy_wait( const volatile uint32_t *gmii_address ) +{ + rtems_interval timeout = rtems_clock_get_ticks_per_second(); + rtems_interval i = 0; + + + while ( ( *gmii_address & MACGRP_GMII_ADDRESS_GMII_BUSY ) != 0 + && i < timeout ) { + rtems_task_wake_after( 1 ); + ++i; + } + + return i < timeout ? 0 : EBUSY; +} + +static int dwmac_if_mdio_read( + int phy, + void *arg, + unsigned phy_reg, + uint32_t *val ) +{ + int eno = 0; + dwmac_common_context *self = (dwmac_common_context *) arg; + volatile uint32_t *mii_address = &self->macgrp->gmii_address; + volatile uint32_t *mii_data = &self->macgrp->gmii_data; + uint32_t reg_value = 0; + + + if ( phy == -1 ) { + reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET( + reg_value, + self->CFG->MDIO_BUS_ADDR + ); + } else { + reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET( + reg_value, + phy + ); + } + + reg_value = MACGRP_GMII_ADDRESS_GMII_REGISTER_SET( + reg_value, + phy_reg + ); + reg_value &= ~MACGRP_GMII_ADDRESS_GMII_WRITE; + + /* For the 7111 GMAC, we must set BUSY bit in the MII address register while + * accessing the PHY registers. + * Fortunately, it seems this has no drawback for the 7109 MAC. */ + reg_value |= MACGRP_GMII_ADDRESS_GMII_BUSY; + reg_value = MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_SET( + reg_value, + self->csr_clock + ); + + eno = dwmac_if_mdio_busy_wait( mii_address ); + + if ( eno == 0 ) { + *mii_address = reg_value; + + if ( dwmac_if_mdio_busy_wait( mii_address ) ) { + eno = EBUSY; + } else { + /* Read the value from the MII data register */ + *val = MACGRP_GMII_DATA_GMII_DATA_GET( *mii_data ); + } + } + + return eno; +} + +static int dwmac_if_mdio_write( + int phy, + void *arg, + unsigned phy_reg, + uint32_t val ) +{ + int eno = 0; + dwmac_common_context *self = (dwmac_common_context *) arg; + volatile uint32_t *mii_address = &self->macgrp->gmii_address; + volatile uint32_t *mii_data = &self->macgrp->gmii_data; + uint32_t reg_value = *mii_address; + + + if ( phy == -1 ) { + reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET( + reg_value, + self->CFG->MDIO_BUS_ADDR + ); + } else { + reg_value = MACGRP_GMII_ADDRESS_PHYSICAL_LAYER_ADDRESS_SET( + reg_value, + phy + ); + } + + reg_value = MACGRP_GMII_ADDRESS_GMII_REGISTER_SET( + reg_value, + phy_reg + ); + reg_value |= MACGRP_GMII_ADDRESS_GMII_WRITE; + reg_value |= MACGRP_GMII_ADDRESS_GMII_BUSY; + reg_value = MACGRP_GMII_ADDRESS_CSR_CLOCK_RANGE_SET( + reg_value, + self->csr_clock + ); + + /* Wait until any existing MII operation is complete */ + eno = dwmac_if_mdio_busy_wait( mii_address ); + + if ( eno == 0 ) { + /* Set the MII address register to write */ + *mii_data = val; + *mii_address = reg_value; + + /* Wait until any existing MII operation is complete */ + eno = dwmac_if_mdio_busy_wait( mii_address ); + } + + return eno; +} + +static int dwmac_get_phy_info( + dwmac_common_context *self, + const uint8_t mdio_bus_addr, + uint32_t *oui, + uint8_t *model, + uint8_t *revision ) +{ + int eno = 0; + uint32_t read; + + + eno = dwmac_if_mdio_read( + mdio_bus_addr, + self, + 2, + &read ); + + if ( eno == 0 ) { + *oui = 0 | ( read << 6 ); + eno = dwmac_if_mdio_read( + mdio_bus_addr, + self, + 3, + &read ); + + if ( eno == 0 ) { + *oui |= ( read & 0xFC00 ) >> 10; + *model = (uint8_t) ( ( read & 0x03F0 ) >> 4 ); + *revision = read & 0x000F; + } + } + + return eno; +} + +static inline void dwmac_enable_irq_rx( dwmac_common_context *self ) +{ + dwmac_core_enable_dma_irq_rx( self ); +} + +static inline void dwmac_enable_irq_tx( dwmac_common_context *self ) +{ + dwmac_core_enable_dma_irq_tx( self ); +} + +static inline void dwmac_disable_irq_rx( dwmac_common_context *self ) +{ + dwmac_core_disable_dma_irq_rx( self ); +} + +static inline void dwmac_diable_irq_tx( dwmac_common_context *self ) +{ + dwmac_core_disable_dma_irq_tx( self ); +} + +static void dwmac_control_request_complete( const dwmac_common_context *self ) +{ + rtems_status_code sc = rtems_event_transient_send( self->task_id_control ); + + + assert( sc == RTEMS_SUCCESSFUL ); +} + +static int dwmac_control_request( + dwmac_common_context *self, + rtems_id task, + rtems_event_set event ) +{ + int eno = 0; + rtems_status_code sc = RTEMS_SUCCESSFUL; + uint32_t nest_count = 0; + + + self->task_id_control = rtems_task_self(); + + sc = rtems_bsdnet_event_send( task, event ); + + eno = rtems_status_code_to_errno( sc ); + + if ( eno == 0 ) { + nest_count = rtems_bsdnet_semaphore_release_recursive(); + sc = rtems_event_transient_receive( RTEMS_WAIT, RTEMS_NO_TIMEOUT ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + rtems_bsdnet_semaphore_obtain_recursive( nest_count ); + self->task_id_control = 0; + } + + return eno; +} + +static bool dwmac_if_media_status( + dwmac_common_context *self, + int *media, + uint8_t phy_address ) +{ + struct ifnet *ifp = &self->arpcom.ac_if; + + + *media = (int) IFM_MAKEWORD( 0, 0, 0, phy_address ); + + return ( *ifp->if_ioctl )( ifp, SIOCGIFMEDIA, (caddr_t) media ) == 0; +} + +#define DWMAC_PRINT_COUNTER( fmt, counter, args ... ) \ + if ( counter != 0 ) { \ + printf( fmt, counter, ## args ); \ + } + +/* Print statistics. Get called via ioctl. */ +static int dwmac_if_interface_stats( void *arg ) +{ + int eno = 0; + dwmac_common_context *self = arg; + volatile macgrp *macgrp = self->macgrp; + int media = 0; + bool media_ok = dwmac_if_media_status( + self, &media, self->CFG->MDIO_BUS_ADDR ); + uint32_t oui; + uint8_t model; + uint8_t revision; + uint16_t giant_frame_size = 1518; + + + if ( ( MACGRP_MAC_CONFIGURATION_JE & macgrp->mac_configuration ) != 0 ) { + /* Jumbo Frames are enabled */ + giant_frame_size = 9018; + } + + if ( media_ok ) { + rtems_ifmedia2str( media, NULL, 0 ); + printf( "\n" ); + eno = dwmac_get_phy_info( + self, + self->CFG->MDIO_BUS_ADDR, + &oui, + &model, + &revision ); + + if ( eno == 0 ) { + printf( "PHY 0x%02x: OUI = 0x%04" PRIX32 ", Model = 0x%02" PRIX8 ", Rev = " + "0x%02" PRIX8 "\n", + self->CFG->MDIO_BUS_ADDR, + oui, + model, + revision ); + printf( "PHY status counters:\n" ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " link down\n", + self->stats.phy_status_counts.link_down + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " link up\n", + self->stats.phy_status_counts.link_up + ); + } + } else { + printf( "PHY %d communication error\n", self->CFG->MDIO_BUS_ADDR ); + } + + printf( "\nHardware counters:\n" ); + + if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 ) { + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes transmitted, exclusive of preamble and retried bytes, " + "in good and bad frames\n", + macgrp->txoctetcount_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted, exclusive of retried " + "frames\n", + macgrp->txframecount_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good broadcast frames transmitted\n", + macgrp->txbroadcastframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good multicast frames transmitted\n", + macgrp->txmulticastframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length 64 bytes, " + "exclusive of preamble and retried frames\n", + macgrp->tx64octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length between 65 and " + "127 (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->tx65to127octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length between 128 and " + "255 (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->tx128to255octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length between 256 and " + "511 (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->tx256to511octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length between 512 and " + "1,023 (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->tx512to1023octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames transmitted with length between 1,024 and" + " maxsize (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->tx1024tomaxoctets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad unicast frames transmitted\n", + macgrp->txunicastframes_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad multicast frames transmitted\n", + macgrp->txmulticastframes_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad broadcast frames transmitted\n", + macgrp->txbroadcastframes_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames aborted due to frame underflow error\n", + macgrp->txunderflowerror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " successfully transmitted frames after a single collision in " + "Half-duplex mode\n", + macgrp->txsinglecol_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " successfully transmitted frames after more than a single" + " collision in Half-duplex mode\n", + macgrp->txmulticol_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " successfully transmitted frames after a deferral in " + "Halfduplex mode\n", + macgrp->txdeferred + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames aborted due to late collision error\n", + macgrp->txlatecol + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames aborted due to excessive (16) collision errors\n", + macgrp->txexesscol + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames aborted due to carrier sense error (no carrier or loss" + " of carrier)\n", + macgrp->txcarriererr + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes transmitted, exclusive of preamble, in good frames " + "only\n", + macgrp->txoctetcnt + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good frames transmitted\n", + macgrp->txframecount_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames aborted due to excessive deferral error (deferred for" + " more than two max-sized frame times)\n", + macgrp->txexcessdef + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good PAUSE frames transmitted\n", + macgrp->txpauseframes + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good VLAN frames transmitted, exclusive of retried frames\n", + macgrp->txvlanframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received\n", + macgrp->txoversize_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received\n", + macgrp->rxframecount_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received, exclusive of preamble, in good and bad " + "frames\n", + macgrp->rxoctetcount_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received, exclusive of preamble, only in good frames\n", + macgrp->rxoctetcount_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good broadcast frames received\n", + macgrp->rxbroadcastframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good multicast frames received\n", + macgrp->rxmulticastframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with CRC error\n", + macgrp->rxcrcerror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with alignment (dribble) error. Valid only" + " in 10/100 mode\n", + macgrp->rxalignmenterror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with runt (<64 bytes and CRC error) error\n", + macgrp->rxrunterror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " giant frames received with length (including CRC) greater " + "than %" PRIu16 " bytes (%" PRIu16 " bytes for VLAN tagged) and with CRC" + " error\n", + macgrp->rxjabbererror, giant_frame_size, giant_frame_size + 4 + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with length less than 64 bytes, without any" + " errors\n", + macgrp->rxundersize_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with length greater than the maxsize (1,518" + " or 1,522 for VLAN tagged frames), without errors\n", + macgrp->rxoversize_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length 64 bytes, exclusive" + " of preamble\n", + macgrp->rx64octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length between 65 and 127" + " (inclusive) bytes, exclusive of preamble\n", + macgrp->rx65to127octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length between 128 and 255" + " (inclusive) bytes, exclusive of preamble\n", + macgrp->rx128to255octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length between 256 and 511" + " (inclusive) bytes, exclusive of preamble\n", + macgrp->rx256to511octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length between 512 and " + "1,023 (inclusive) bytes, exclusive of preamble\n", + macgrp->rx512to1023octets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad frames received with length between 1,024 and" + " maxsize (inclusive) bytes, exclusive of preamble and retried frames\n", + macgrp->rx1024tomaxoctets_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good unicast frames received\n", + macgrp->rxunicastframes_g + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with length error (length type field not " + "equal to frame size), for all frames with valid length field\n", + macgrp->rxlengtherror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with length field not equal to the valid " + "frame size (greater than 1,500 but less than 1,536)\n", + macgrp->rxoutofrangetype + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and valid PAUSE frames received\n", + macgrp->rxpauseframes + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " missed received frames due to FIFO overflow\n", + macgrp->rxfifooverflow + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good and bad VLAN frames received\n", + macgrp->rxvlanframes_gb + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with error due to watchdog timeout error " + "(frames with a data load larger than 2,048 bytes)\n", + macgrp->rxwatchdogerror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " frames received with Receive error or Frame Extension error" + " on the GMII or MII interface\n", + macgrp->rxrcverror + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " received good control frames\n", + macgrp->rxctrlframes_g + ); + + printf( "\n" ); + + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IPv4 datagrams received with the TCP, UDP, or ICMP " + "payload\n", + macgrp->rxipv4_gd_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " IPv4 datagrams received with header (checksum, length, or " + "version mismatch) errors\n", + macgrp->rxipv4_hdrerr_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " IPv4 datagram frames received that did not have a TCP, UDP, " + "or ICMP payload processed by the Checksum engine\n", + macgrp->rxipv4_nopay_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IPv4 datagrams with fragmentation\n", + macgrp->rxipv4_frag_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IPv4 datagrams received that had a UDP payload with " + "checksum disabled\n", + macgrp->rxipv4_udsbl_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IPv6 datagrams received with TCP, UDP, or ICMP " + "payloads\n", + macgrp->rxipv6_gd_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " IPv6 datagrams received with header errors (length or " + "version mismatch)\n", + macgrp->rxipv6_hdrerr_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " IPv6 datagram frames received that did not have a TCP, UDP," + " or ICMP payload. This includes all IPv6 datagrams with fragmentation" + " or security extension headers\n", + macgrp->rxipv6_nopay_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams with a good UDP payload. This counter is " + "not updated when the counter is incremented\n", + macgrp->rxudp_gd_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams whose UDP payload has a checksum error\n", + macgrp->rxudp_err_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams with a good TCP payload\n", + macgrp->rxtcp_gd_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams whose TCP payload has a checksum error\n", + macgrp->rxtcp_err_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams with a good ICMP payload\n", + macgrp->rxicmp_gd_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " good IP datagrams whose ICMP payload has a checksum error\n", + macgrp->rxicmp_err_frms + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in good IPv4 datagrams encapsulating TCP, UDP," + " or ICMP data\n", + macgrp->rxipv4_gd_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in IPv4 datagrams with header errors (checksum," + " length, version mismatch). The value in the Length field of IPv4 " + "header is used to update this counter\n", + macgrp->rxipv4_hdrerr_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in IPv4 datagrams that did not have a TCP, UDP" + ", or ICMP payload. The value in the IPv4 headers Length field is used" + " to update this counter\n", + macgrp->rxipv4_nopay_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in fragmented IPv4 datagrams. The value in the" + " IPv4 headers Length field is used to update this counter\n", + macgrp->rxipv4_frag_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a UDP segment that had the UDP checksum " + "disabled. This counter does not count IP Header bytes\n", + macgrp->rxipv4_udsbl_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in good IPv6 datagrams encapsulating TCP, UDP " + "or ICMPv6 data\n", + macgrp->rxipv6_gd_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in IPv6 datagrams with header errors (length, " + "version mismatch). The value in the IPv6 headers Length field is used " + "to update this counter\n", + macgrp->rxipv6_hdrerr_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in IPv6 datagrams that did not have a TCP, UDP" + ", or ICMP payload. The value in the IPv6 headers Length field is used " + "to update this counter\n", + macgrp->rxipv6_nopay_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a good UDP segment. This counter does not " + "count IP header bytes\n", + macgrp->rxudp_gd_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a UDP segment that had checksum errors\n", + macgrp->rxudp_err_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a good TCP segment\n", + macgrp->rxtcp_gd_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a TCP segment with checksum errors\n", + macgrp->rxtcperroctets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in a good ICMP segment\n", + macgrp->rxicmp_gd_octets + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " bytes received in an ICMP segment with checksum errors\n", + macgrp->rxicmp_err_octets + ); + } + + if ( eno == 0 ) { + printf( "\nInterrupt counts:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " receive interrputs\n", + self->stats.dma_irq_counts.receive + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " transmit interrupts\n", + self->stats.dma_irq_counts.transmit + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " tx jabber interrupts\n", + self->stats.dma_irq_counts.tx_jabber + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " rx overflow interrupts\n", + self->stats.dma_irq_counts.rx_overflow + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " rx early interrupts\n", + self->stats.dma_irq_counts.rx_early + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " rx buffer unavailable interrupts\n", + self->stats.dma_irq_counts.rx_buf_unav + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " rx process stopped interrupts\n", + self->stats.dma_irq_counts.rx_process_stopped + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " rx watchdog interrupts\n", + self->stats.dma_irq_counts.rx_watchdog + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " tx early interrupts\n", + self->stats.dma_irq_counts.tx_early + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " tx buffer unavailable interrupts\n", + self->stats.dma_irq_counts.tx_buf_unav + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " tx process stopped interrupts\n", + self->stats.dma_irq_counts.tx_process_stopped + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " tx underflow interrupts\n", + self->stats.dma_irq_counts.tx_underflow + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " fatal bus error interrupts\n", + self->stats.dma_irq_counts.fatal_bus_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " unhandled interrupts\n", + self->stats.dma_irq_counts.unhandled + ); + + printf( "\nRX DMA status counts:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " CRC errors\n", + self->stats.desc_status_counts_rx.crc_error + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " late collision when receing in half duplex mode\n", + self->stats.desc_status_counts_rx.late_collision + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " giant frame or timestamp or checksum error\n", + self->stats.desc_status_counts_rx.giant_frame + ); + + if ( self->stats.desc_status_counts_rx.watchdog_timeout != 0 + || self->stats.desc_status_counts_rx.receive_error != 0 ) { + printf( " IP Header or IP Payload:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " receive watchdog timeout\n", + self->stats.desc_status_counts_rx.watchdog_timeout + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " receive error\n", + self->stats.desc_status_counts_rx.receive_error + ); + } + + DWMAC_PRINT_COUNTER( "%" PRIu32 " buffer overflows in MTL\n", + self->stats.desc_status_counts_rx.overflow_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " descriptor buffers too small\n", + self->stats.desc_status_counts_rx.descriptor_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " length errors\n", + self->stats.desc_status_counts_rx.length_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " dribble bit errors\n", + self->stats.desc_status_counts_rx.dribble_bit_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " vlan tags\n", + self->stats.desc_status_counts_rx.vlan_tag + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " ethernet frames\n", + self->stats.desc_status_counts_rx.ethernet_frames + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " destination address filter failures\n", + self->stats.desc_status_counts_rx.dest_addr_fail + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " source addresss filter failures\n", + self->stats.desc_status_counts_rx.source_addr_fail + ); + + printf( "\nTX DMA status counts:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " jabber time-outs\n", + self->stats.desc_status_counts_tx.jabber + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frame flushes\n", + self->stats.desc_status_counts_tx.frame_flushed + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " losses of carrier\n", + self->stats.desc_status_counts_tx.losscarrier + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " no carriers\n", + self->stats.desc_status_counts_tx.no_carrier + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " excessive collisions\n", + self->stats.desc_status_counts_tx.excessive_collisions + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " excessive deferrals\n", + self->stats.desc_status_counts_tx.excessive_deferral + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " underfolw errors\n", + self->stats.desc_status_counts_tx.underflow + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " IP header error\n", + self->stats.desc_status_counts_tx.ip_header_error + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " payload error\n", + self->stats.desc_status_counts_rx.source_addr_fail + ); + DWMAC_PRINT_COUNTER( + "%" PRIu32 " MAC defers before transmission because of the presence of carrier\n", + self->stats.desc_status_counts_tx.deferred + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " VLAN frames\n", + self->stats.desc_status_counts_tx.vlan + ); + + printf( "\nRX frame counts:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames with errors\n", + self->stats.frame_counts_rx.errors + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames dropped\n", + self->stats.frame_counts_rx.dropped + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames good\n", + self->stats.frame_counts_rx.frames_good + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " bytes in good frames\n", + self->stats.frame_counts_rx.bytes_good + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames good or bad\n", + self->stats.frame_counts_rx.frames + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " DMA suspended\n", + self->stats.frame_counts_rx.dma_suspended + ); + + printf( "\nTX frame counts:\n" ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames received from network stack\n", + self->stats.frame_counts_tx.frames_from_stack + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " frames tranmitted to DMA\n", + self->stats.frame_counts_tx.frames_to_dma + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " packets tranmitted to DMA\n", + self->stats.frame_counts_tx.packets_to_dma + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " bytes tranmitted to DMA\n", + self->stats.frame_counts_tx.bytes_to_dma + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " packets tranmitted by DMA\n", + self->stats.frame_counts_tx.packets_tranmitted_by_DMA + ); + DWMAC_PRINT_COUNTER( "%" PRIu32 " packet errors\n", + self->stats.frame_counts_tx.packet_errors + ); + + printf( "\n" ); + +#ifdef RTEMS_DEBUG + { + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + + ( DESC_OPS->print_rx_desc )( + self->dma_rx, + (unsigned int) self->bsd_config->xbuf_count + ); + + ( DESC_OPS->print_tx_desc )( + self->dma_tx, + (unsigned int) self->bsd_config->xbuf_count + ); + } +#endif /* RTEMS_DEBUG */ + } + + return eno; +} + +static inline unsigned int dwmac_increment( + const unsigned int value, + const unsigned int cycle ) +{ + if ( value < cycle ) { + return value + 1; + } else { + return 0; + } +} + +/* Receive task + * It handles receiving frames */ +static void dwmac_task_rx( void *arg ) +{ + dwmac_common_context *self = arg; + dwmac_common_rx_frame_counts *counts = &self->stats.frame_counts_rx; + const unsigned int INDEX_MAX = + (unsigned int) self->bsd_config->rbuf_count - 1U; + size_t frame_len_last = 0; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + size_t segment_size; + + + while ( true ) { + rtems_event_set events; + rtems_status_code sc = rtems_bsdnet_event_receive( + DWMAC_COMMON_EVENT_TASK_INIT + | DWMAC_COMMON_EVENT_TASK_STOP + | DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + assert( sc == RTEMS_SUCCESSFUL ); + + /* Stop the task */ + if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) { + dwmac_core_dma_stop_rx( self ); + dwmac_disable_irq_rx( self ); + + /* Release all tx mbufs at the risk of data loss */ + ( DESC_OPS->release_rx_bufs )( self ); + + dwmac_control_request_complete( self ); + + /* Return to events reception without re-enabling the interrupts + * The task needs a re-initialization to to resume work */ + continue; + } + + /* Ininitialize / Re-initialize reception handling */ + if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) { + unsigned int index; + dwmac_core_dma_stop_rx( self ); + ( DESC_OPS->release_rx_bufs )( self ); + + for ( index = 0; index <= INDEX_MAX; ++index ) { + self->mbuf_addr_rx[index] = ( DESC_OPS->alloc_data_buf )( self ); + assert( self->mbuf_addr_rx[index] != NULL ); + ( DESC_OPS->init_rx_desc )( self, index ); + } + + self->idx_rx = 0; + frame_len_last = 0; + + /* Clear our interrupt statuses */ + dwmac_core_reset_dma_irq_status_rx( self ); + + dwmac_core_dma_start_rx( self ); + + dwmac_control_request_complete( self ); + events = events + & (rtems_event_set) ( ~DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED ); + } + + /* Handle the reception of one or more frames */ + if ( ( events & DWMAC_COMMON_EVENT_RX_FRAME_RECEIVED ) != 0 ) { + unsigned int idx = self->idx_rx; + + /* Only handle frames for which we own the DMA descriptor */ + while ( ( DESC_OPS->am_i_rx_owner )( self, idx ) ) { + struct mbuf *p_m_new; + dwmac_common_rx_frame_status status; + unsigned int idx_next = dwmac_increment( + self->idx_rx, INDEX_MAX ); + + /* Assign the next index (with wrap around) */ + self->idx_rx = idx_next; + + /* read the status of the incoming frame */ + status = ( DESC_OPS->rx_status )( self, idx ); + + if ( status == DWMAC_COMMON_RX_FRAME_STATUS_DISCARD + || status == DWMAC_COMMON_RX_FRAME_STATUS_CSUM_NONE ) { + DWMAC_PRINT_DBG( + "rx discarded: %02u\n", + idx + ); + ++counts->errors; + + /* simply re-initialize the DMA descriptor */ + ( DESC_OPS->init_rx_desc )( self, idx ); + } else if ( status == DWMAC_COMMON_RX_FRAME_STATUS_LLC_SNAP ) { + DWMAC_PRINT_DBG( + "rx dropped llc snap: %02u\n", + idx + ); + ++counts->dropped; + + /* simply re-initialize the DMA descriptor */ + ( DESC_OPS->init_rx_desc )( self, idx ); + } else { + /* Before actually handling the valid frame, make sure we get a new + * mbuf */ + p_m_new = ( DESC_OPS->alloc_data_buf )( self ); + + if ( p_m_new != NULL ) { + bool is_first_seg; + bool is_last_seg; + struct mbuf *p_m; + uint32_t frame_len = ( DESC_OPS->get_rx_frame_len )( + self, idx ); + + /* frame_len is the cummulated size of all segments of a frame. + * But what we need is the size of the single segment */ + is_first_seg = ( DESC_OPS->is_first_rx_segment )( self, idx ); + is_last_seg = ( DESC_OPS->is_last_rx_segment )( self, idx ); + + if ( is_first_seg ) { + segment_size = frame_len; + } else { + segment_size = frame_len - frame_len_last; + } + + frame_len_last = frame_len; + + p_m = self->mbuf_addr_rx[idx]; + self->mbuf_addr_rx[idx] = p_m_new; + + /* Initialize the DMA descriptor with the new mbuf */ + ( DESC_OPS->init_rx_desc )( self, idx ); + + if ( p_m != NULL ) { + /* Ethernet header */ + struct ether_header *eh = mtod( p_m, struct ether_header * ); + int sz = (int) segment_size; + + rtems_cache_invalidate_multiple_data_lines( + eh, segment_size ); + + /* Discard Ethernet header and CRC */ + if ( is_last_seg ) { + sz -= ( ETHER_HDR_LEN + ETHER_CRC_LEN ); + } else { + sz -= ETHER_HDR_LEN; + } + + /* Update mbuf */ + p_m->m_len = sz; + p_m->m_pkthdr.len = sz; + p_m->m_data = mtod( p_m, char * ) + ETHER_HDR_LEN; + + DWMAC_COMMON_DSB(); + + DWMAC_PRINT_DBG( + "rx: %02u: %u %s%s\n", + idx, + segment_size, + ( is_first_seg ) ? ( "F" ) : ( "" ), + ( is_last_seg ) ? ( "L" ) : ( "" ) + ); + + ether_input( &self->arpcom.ac_if, eh, p_m ); + + ++counts->frames_good; + counts->bytes_good += (uint32_t) p_m->m_len; + } else { + DWMAC_PRINT_DBG( "rx: %s: Inconsistent Rx descriptor chain\n", + self->arpcom.ac_if.if_name ); + ++counts->dropped; + } + } else { + /* We have to discard the received frame because we did not get a new + * mbuf to replace the frame's mbuf. */ + ++counts->dropped; + + /* simply re-initialize the DMA descriptor with the existing mbuf */ + ( DESC_OPS->init_rx_desc )( self, idx ); + DWMAC_PRINT_DBG( + "rx dropped: %02u\n", + idx + ); + } + } + + if ( ( self->dmagrp->status & DMAGRP_STATUS_RU ) != 0 ) { + /* The receive DMA is suspended and needs to get restarted */ + dwmac_core_dma_restart_rx( self ); + DWMAC_PRINT_DBG( + "rx DMA restart: %02u\n", + idx + ); + ++counts->dma_suspended; + } + + idx = idx_next; + ++counts->frames; + } + + /* Clear interrupt */ + self->dmagrp->status = DMAGRP_STATUS_RI; + } + + /* Re-enable the IRQs */ + dwmac_enable_irq_rx( self ); + } +} + +static struct mbuf *dwmac_next_fragment( + struct ifnet *ifp, + struct mbuf *m, + bool *is_first, + bool *is_last, + size_t *size ) { + struct mbuf *n = NULL; + int sz = 0; + + + while ( true ) { + if ( m == NULL ) { + /* Dequeue first fragment of the next frame */ + IF_DEQUEUE( &ifp->if_snd, m ); + + /* Empty queue? */ + if ( m == NULL ) { + return m; + } + + /* The sum of all fragments lengths must fit into one + * ethernet transfer unit */ + assert( ETHER_MAX_LEN >= m->m_pkthdr.len ); + *is_first = true; + } + + /* Get fragment size */ + sz = m->m_len; + + if ( sz > 0 ) { + /* Now we have a not empty fragment */ + break; + } else { + /* Discard empty fragments */ + m = m_free( m ); + } + } + + /* Set fragment size */ + *size = (size_t) sz; + + /* Discard empty successive fragments */ + n = m->m_next; + + while ( n != NULL && n->m_len <= 0 ) { + n = m_free( n ); + } + + m->m_next = n; + + /* Is our fragment the last in the frame? */ + if ( n == NULL ) { + *is_last = true; + } else { + *is_last = false; + } + + return m; +} + +static int dwmac_update_autonegotiation_params( dwmac_common_context *self ) +{ + int eno = 0; + uint32_t value = self->macgrp->mac_configuration; + int media = 0; + bool media_ok = dwmac_if_media_status( + self, &media, self->CFG->MDIO_BUS_ADDR ); + + + if ( media_ok ) { + /* only ethernet supported, so far */ + if ( IFM_ETHER == IFM_TYPE( media ) ) { + if ( IFM_NONE != IFM_SUBTYPE( media ) ) { + if ( IFM_FDX & media ) { + /* Enable duplex mode */ + value |= MACGRP_MAC_CONFIGURATION_DM; + } else { + /* Disable duplex mode */ + value &= ~MACGRP_MAC_CONFIGURATION_DM; + } + + switch ( IFM_SUBTYPE( media ) ) { + case IFM_10_T: + + /* Set RMII/RGMII speed to 10Mbps */ + value &= ~MACGRP_MAC_CONFIGURATION_FES; + + /* MII 10/100 Mbps */ + value |= MACGRP_MAC_CONFIGURATION_PS; + break; + case IFM_100_TX: + + /* Set RMII/RGMII speed to 100Mbps */ + value |= MACGRP_MAC_CONFIGURATION_FES; + + /* MII 10/100 Mbps */ + value |= MACGRP_MAC_CONFIGURATION_PS; + break; + case IFM_1000_T: + + /* RMII/RGMII speed irrelevant for 1000baseT */ + value &= ~MACGRP_MAC_CONFIGURATION_FES; + + /* GMII 1000 Mbps */ + value &= ~MACGRP_MAC_CONFIGURATION_PS; + break; + default: + eno = ENOTSUP; + break; + } + } else { + eno = ENOTSUP; + } + } else { + eno = ENOTSUP; + } + } else { + eno = ENOTSUP; + } + + if ( eno == 0 ) { + self->macgrp->mac_configuration = value; + } + + return eno; +} + +/* Transmit task + * It handles transmitting frames */ +static void dwmac_task_tx( void *arg ) +{ + dwmac_common_context *self = arg; + unsigned int idx_transmit = 0; + unsigned int idx_transmit_first = 0; + unsigned int idx_transmitted = 0; + unsigned int idx_release = 0; + struct mbuf *p_m = NULL; + bool is_first = false; + bool is_last = false; + size_t size = 0; + const unsigned int INDEX_MAX = + (unsigned int) self->bsd_config->xbuf_count - 1U; + const dwmac_common_dma_ops *DMA_OPS = + (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + const dwmac_callback_cfg *CALLBACK = &self->CFG->CALLBACK; + + + while ( true ) { + rtems_event_set events = 0; + rtems_status_code sc = rtems_bsdnet_event_receive( + DWMAC_COMMON_EVENT_TASK_INIT + | DWMAC_COMMON_EVENT_TASK_STOP + | DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME + | DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED + | DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD + | DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + assert( sc == RTEMS_SUCCESSFUL ); + + /* Handle a status change of the ethernet PHY */ + if ( ( events & DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE ) != 0 ) { + dwmac_common_phy_status_counts *counts = + &self->stats.phy_status_counts; + dwmac_phy_event phy_events = 0; + int eno; + + /* Get tripped PHY events */ + eno = CALLBACK->phy_events_get( + self->arg, + &phy_events + ); + + if ( eno == 0 ) { + /* Clear the PHY events */ + eno = CALLBACK->phy_event_clear( self->arg ); + } + + if ( eno == 0 ) { + if ( ( phy_events & PHY_EVENT_LINK_DOWN ) != 0 ) { + ++counts->link_down; + } + + if ( ( phy_events & PHY_EVENT_LINK_UP ) != 0 ) { + ++counts->link_up; + + /* A link up events means that we have a new connection. + * Thus the autonegotiation paremeters must get updated */ + (void) dwmac_update_autonegotiation_params( self ); + } + } + + assert( eno == 0 ); + } + + /* Stop the task */ + if ( ( events & DWMAC_COMMON_EVENT_TASK_STOP ) != 0 ) { + dwmac_core_dma_stop_tx( self ); + dwmac_diable_irq_tx( self ); + + /* Release all tx mbufs at the risk of data loss */ + ( DESC_OPS->release_tx_bufs )( self ); + + dwmac_control_request_complete( self ); + + /* Return to events reception without re-enabling the interrupts + * The task needs a re-initialization to to resume work */ + continue; + } + + /* Ininitialize / Re-initialize transmission handling */ + if ( ( events & DWMAC_COMMON_EVENT_TASK_INIT ) != 0 ) { + (void) dwmac_update_autonegotiation_params( self ); + dwmac_core_dma_stop_tx( self ); + ( DESC_OPS->release_tx_bufs )( self ); + idx_transmit = 0; + idx_transmit_first = 0; + idx_transmitted = 0; + idx_release = 0; + p_m = NULL; + is_first = false; + is_last = false; + size = 0; + ( DESC_OPS->init_tx_desc )( self ); + dwmac_core_dma_start_tx( self ); + dwmac_core_dma_restart_tx( self ); + + /* Clear our interrupt statuses */ + dwmac_core_reset_dma_irq_status_tx( self ); + + dwmac_control_request_complete( self ); + } + + /* Try to bump up the dma threshold due to a failure */ + if ( ( events & DWMAC_COMMON_EVENT_TX_BUMP_UP_DMA_THRESHOLD ) != 0 ) { + if ( self->dma_threshold_control + != DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD + && self->dma_threshold_control <= 256 ) { + self->dma_threshold_control += 64; + ( DMA_OPS->dma_mode )( + self, + self->dma_threshold_control, + DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD + ); + } + } + + /* Handle one or more transmitted frames */ + if ( ( events & DWMAC_COMMON_EVENT_TX_FRAME_TRANSMITTED ) != 0 ) { + dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx; + + /* Next index to be transmitted */ + unsigned int idx_transmitted_next = dwmac_increment( + idx_transmitted, INDEX_MAX ); + + /* Free consumed fragments */ + while ( idx_release != idx_transmitted_next + && ( DESC_OPS->am_i_tx_owner )( self, idx_release ) ) { + /* Status handling per packet */ + if ( ( DESC_OPS->get_tx_ls )( self, idx_release ) ) { + int status = ( DESC_OPS->tx_status )( + self, idx_release + ); + + if ( status == 0 ) { + ++counts->packets_tranmitted_by_DMA; + } else { + ++counts->packet_errors; + } + } + + DWMAC_PRINT_DBG( + "tx: release %u\n", + idx_release + ); + + /* Release the DMA descriptor */ + ( DESC_OPS->release_tx_desc )( self, idx_release ); + + /* Release mbuf */ + m_free( self->mbuf_addr_tx[idx_release] ); + self->mbuf_addr_tx[idx_release] = NULL; + + /* Next release index */ + idx_release = dwmac_increment( + idx_release, INDEX_MAX ); + } + + /* Clear transmit interrupt status */ + self->dmagrp->status = DMAGRP_STATUS_TI; + + if ( ( self->arpcom.ac_if.if_flags & IFF_OACTIVE ) != 0 ) { + /* The last tranmission has been incomplete + * (for example due to lack of DMA descriptors). + * Continue it now! */ + events |= DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME; + } + } + + /* There are one or more frames to be transmitted. */ + if ( ( events & DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME ) != 0 ) { + dwmac_common_tx_frame_counts *counts = &self->stats.frame_counts_tx; + + if ( p_m != NULL ) { + /* This frame will get re-counted */ + --counts->frames_from_stack; + } + + while ( true ) { + unsigned int idx = dwmac_increment( + idx_transmit, INDEX_MAX ); + + p_m = dwmac_next_fragment( + &self->arpcom.ac_if, + p_m, + &is_first, + &is_last, + &size + ); + + /* New fragment? */ + if ( p_m != NULL ) { + ++counts->frames_from_stack; + + /* Queue full? */ + if ( idx == idx_release ) { + DWMAC_PRINT_DBG( "tx: full queue: 0x%08x\n", p_m ); + + /* The queue is full, wait for transmitted interrupt */ + break; + } + + /* Set the transfer data */ + rtems_cache_flush_multiple_data_lines( + mtod( p_m, const void * ), + size + ); + + ( DESC_OPS->prepare_tx_desc )( + self, + idx_transmit, + is_first, + size, + mtod( p_m, const void * ) + ); + self->mbuf_addr_tx[idx_transmit] = p_m; + + ++counts->frames_to_dma; + counts->bytes_to_dma += size; + DWMAC_PRINT_DBG( + "tx: %02" PRIu32 ": %u %s%s\n", + idx_transmit, size, + ( is_first != false ) ? ( "F" ) : ( "" ), + ( is_last != false ) ? ( "L" ) : ( "" ) + + ); + + if ( is_first ) { + idx_transmit_first = idx_transmit; + is_first = false; + } else { + /* To avoid race condition */ + ( DESC_OPS->release_tx_ownership )( self, idx_transmit ); + } + + if ( is_last ) { + /* Interrupt on completition only for the latest fragment */ + ( DESC_OPS->close_tx_desc )( self, idx_transmit ); + + /* To avoid race condition */ + ( DESC_OPS->release_tx_ownership )( self, idx_transmit_first ); + idx_transmitted = idx_transmit; + + if ( ( self->dmagrp->status & DMAGRP_STATUS_TU ) != 0 ) { + /* Re-enable the tranmit DMA */ + dwmac_core_dma_restart_tx( self ); + DWMAC_PRINT_DBG( + "tx DMA restart: %02u\n", + idx_transmit_first + ); + } + } + + /* Next transmit index */ + idx_transmit = idx; + + if ( is_last ) { + ++counts->packets_to_dma; + } + + /* Next fragment of the frame */ + p_m = p_m->m_next; + } else { + /* Nothing to transmit */ + break; + } + } + + /* No more packets and fragments? */ + if ( p_m == NULL ) { + /* Interface is now inactive */ + self->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + } else { + /* There are more packets pending to be sent, + * but we have run out of DMA descriptors. + * We will continue sending once descriptors + * have been freed due to a transmitted interupt */ + DWMAC_PRINT_DBG( "tx: transmission incomplete\n" ); + } + + /* TODO: Add handling */ + } + + DWMAC_PRINT_DBG( "tx: enable transmit interrupts\n" ); + + /* Re-enable transmit interrupts */ + dwmac_enable_irq_tx( self ); + } +} + +/* Major driver initialization method. Gets called + * by the network stack automatically */ +static void dwmac_if_interface_init( void *arg ) +{ + (void) arg; +} + +static void dwmac_if_set_promiscous_mode( + dwmac_common_context *self, + const bool enabled ) +{ + if ( enabled ) { + /* Enable promiscuos mode */ + self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_PR; + } else { + /* Hash filter or perfect match */ + self->macgrp->mac_frame_filter &= ~MACGRP_MAC_FRAME_FILTER_PR; + self->macgrp->mac_frame_filter &= ~MACGRP_MAC_FRAME_FILTER_HUC; + self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HPF; + } +} + +static int dwmac_create_dma_desc_rings( dwmac_common_context *self ) +{ + int eno = 0; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + + + /* create and initialize the Rx/Tx descriptors */ + eno = ( DESC_OPS->create_rx_desc )( self ); + + if ( eno == 0 ) { + eno = ( DESC_OPS->create_tx_desc )( self ); + } + + return eno; +} + +static int dwmac_destroy_dma_desc_rings( dwmac_common_context *self ) +{ + int eno = 0; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + + + /* Free the Rx/Tx descriptors and the data buffers */ + eno = ( DESC_OPS->destroy_rx_desc )( self ); + + if ( eno == 0 ) { + eno = ( DESC_OPS->destroy_tx_desc )( self ); + } + + return eno; +} + +static int dwmac_init_dma_engine( dwmac_common_context *self ) +{ + uint32_t pbl = + DWMAC_DMA_BUS_MODE_PBL_DEFAULT; + uint32_t fixed_burst = + DWMAC_DMA_BUS_MODE_FB_DEFAULT; + uint32_t mixed_burst = + DWMAC_DMA_BUS_MODE_MIXED_BURSTS_DEFAULT; + uint32_t burst_len_4_support = + DWMAC_DMA_AXI_BURST_LENGTH_4_DEFAULT; + uint32_t burst_len_8_support = + DWMAC_DMA_AXI_BURST_LENGTH_8_DEFAULT; + uint32_t burst_len_16_support = + DWMAC_DMA_AXI_BURST_LENGTH_16_DEFAULT; + uint32_t burst_boundary = + DWMAC_DMA_AXI_BURST_BOUNDARY_DEFAULT; + const dwmac_common_dma_ops *DMA_OPS = + (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) self->CFG->DESC_OPS->ops; + + + /* The DMA configuration is optional */ + if ( self->CFG->DMA_CFG != NULL ) { + const dwmac_dma_cfg *DMA_CFG = self->CFG->DMA_CFG; + pbl = DMA_CFG->bus_mode_burst_length; + fixed_burst = DMA_CFG->bus_mode_burst_mode; + mixed_burst = DMA_CFG->bus_mode_burst_mixed; + burst_len_4_support = DMA_CFG->axi_burst_length_4_support; + burst_len_8_support = DMA_CFG->axi_burst_length_8_support; + burst_len_16_support = DMA_CFG->axi_burst_length_16_support; + burst_boundary = DMA_CFG->axi_burst_boundary; + } + + return ( DMA_OPS->init )( + self, + pbl, + fixed_burst, + mixed_burst, + ( DESC_OPS->use_enhanced_descs )( self ), + burst_len_4_support, + burst_len_8_support, + burst_len_16_support, + burst_boundary, + &self->dma_tx[0], + &self->dma_rx[0] + ); +} + +static void dwmac_dma_operation_mode( dwmac_common_context *self ) +{ + const dwmac_common_dma_ops *DMA_OPS = + (const dwmac_common_dma_ops *) self->CFG->MAC_OPS->dma; + + + if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_TXOESEL ) != 0 ) { + ( DMA_OPS->dma_mode )( + self, + DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD, + DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD + ); + self->dma_threshold_control = DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD; + } else { + ( DMA_OPS->dma_mode )( + self, + self->dma_threshold_control, + DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD + ); + } +} + +static void dwmac_mmc_setup( dwmac_common_context *self ) +{ + /* Mask MMC irq, counters are managed in HW and registers + * are not cleared on each READ eventually. */ + + /* No MAC Management Counters available */ + assert( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 ); + + if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_MMCSEL ) != 0 ) { + self->macgrp->mmc_control = MACGRP_MMC_CONTROL_CNTRST; + } +} + +static int dwmac_if_up_or_down( + dwmac_common_context *self, + const bool up ) +{ + int eno = 0; + rtems_status_code sc = RTEMS_SUCCESSFUL; + struct ifnet *ifp = &self->arpcom.ac_if; + const dwmac_callback_cfg *CALLBACK = &self->CFG->CALLBACK; + const dwmac_common_core_ops *CORE_OPS = + (const dwmac_common_core_ops *) self->CFG->MAC_OPS->core; + + + if ( up && self->state == DWMAC_COMMON_STATE_DOWN ) { + eno = CALLBACK->nic_enable( self->arg ); + + if ( eno == 0 ) { + eno = CALLBACK->phy_enable( self->arg ); + } + + if ( eno == 0 ) { + eno = CALLBACK->phy_event_enable( + self->arg, + PHY_EVENT_LINK_DOWN + | PHY_EVENT_LINK_UP + ); + } + + if ( eno == 0 ) { + eno = dwmac_create_dma_desc_rings( self ); + } + + if ( eno == 0 ) { + eno = dwmac_init_dma_engine( self ); + } + + if ( eno == 0 ) { + /* Copy the MAC addr into the HW */ + ( CORE_OPS->set_umac_addr )( self, self->arpcom.ac_enaddr, 0 ); + + eno = ( CALLBACK->bus_setup )( self->arg ); + } + + if ( eno == 0 ) { + /* Initialize the MAC Core */ + ( CORE_OPS->core_init )( self ); + + /* Enable the MAC Rx/Tx */ + dwmac_core_set_mac( self, true ); + + /* Set the HW DMA mode and the COE */ + dwmac_dma_operation_mode( self ); + + /* Set up mmc counters */ + dwmac_mmc_setup( self ); + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + self->CFG->IRQ_EMAC, + "Ethernet", + RTEMS_INTERRUPT_UNIQUE, + dwmac_core_dma_interrupt, + self + ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + /* Start the ball rolling ... */ + sc = dwmac_control_request( + self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_INIT ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + sc = dwmac_control_request( + self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_INIT ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + dwmac_core_dma_start_rx( self ); + + /* Start the phy */ + eno = ( CALLBACK->phy_start )( self->arg ); + } + + if ( eno == 0 ) { + self->state = DWMAC_COMMON_STATE_UP; + } else { + ifp->if_flags &= ~IFF_UP; + (void) dwmac_control_request( + self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_STOP ); + (void) dwmac_control_request( + self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_STOP ); + (void) rtems_interrupt_handler_remove( + self->CFG->IRQ_EMAC, + dwmac_core_dma_interrupt, + self + ); + (void) ( CALLBACK->phy_stop )( self->arg ); + (void) ( CALLBACK->phy_disable )( self->arg ); + + /* Disable the MAC Rx/Tx */ + dwmac_core_set_mac( self, false ); + (void) ( CALLBACK->nic_disable )( self->arg ); + (void) dwmac_destroy_dma_desc_rings( self ); + } + } else if ( !up && self->state == DWMAC_COMMON_STATE_UP ) { + if ( eno == 0 ) { + sc = dwmac_control_request( + self, self->task_id_tx, DWMAC_COMMON_EVENT_TASK_STOP ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + sc = dwmac_control_request( + self, self->task_id_rx, DWMAC_COMMON_EVENT_TASK_STOP ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + sc = rtems_interrupt_handler_remove( + self->CFG->IRQ_EMAC, + dwmac_core_dma_interrupt, + self + ); + eno = rtems_status_code_to_errno( sc ); + } + + if ( eno == 0 ) { + eno = ( CALLBACK->phy_stop )( self->arg ); + } + + if ( eno == 0 ) { + eno = ( CALLBACK->phy_disable )( self->arg ); + } + + if ( eno == 0 ) { + /* Disable the MAC Rx/Tx */ + dwmac_core_set_mac( self, false ); + + eno = CALLBACK->nic_disable( self->arg ); + } + + if ( eno == 0 ) { + eno = dwmac_destroy_dma_desc_rings( self ); + } + + if ( eno == 0 ) { + /* Reset counters to be printed */ + memset( &self->stats, 0, sizeof( dwmac_common_stats ) ); + + /* Change state */ + self->state = DWMAC_COMMON_STATE_DOWN; + } + } + + return eno; +} + +/* Get commands executed by the driver. This method gets called + * automatically from the network stack */ +static int dwmac_if_interface_ioctl( + struct ifnet *ifp, + ioctl_command_t cmd, + caddr_t data ) +{ + dwmac_common_context *self = ifp->if_softc; + int eno = 0; + + + switch ( cmd ) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + rtems_mii_ioctl( &self->mdio, self, cmd, (int *) data ); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl( ifp, cmd, data ); + break; + case SIOCSIFFLAGS: + eno = dwmac_if_up_or_down( self, ( ifp->if_flags & IFF_UP ) != 0 ); + + if ( eno == 0 && ( ifp->if_flags & IFF_UP ) != 0 ) { + dwmac_if_set_promiscous_mode( self, ( ifp->if_flags & IFF_PROMISC ) + != 0 ); + } else { + assert( eno == 0 ); + } + + break; + case SIOCADDMULTI: + case SIOCDELMULTI: +#ifndef COMMENTED_OUT + eno = ENOTSUP; +#else /* COMMENTED_OUT */ + { + struct ifreq *ifr = (struct ifreq *) data; + const dwmac_common_core_ops *CORE_OPS = + (const dwmac_common_core_ops *) self->CFG->MAC_OPS->core; + ( CORE_OPS->set_hash_filter )( self, cmd == SIOCADDMULTI, ifr ); + } +#endif /* COMMENTED_OUT */ + break; + case SIO_RTEMS_SHOW_STATS: + eno = dwmac_if_interface_stats( self ); + break; + default: + eno = EINVAL; + break; + } + + return eno; +} + +/* Method called by the network stack if there are frames to be transmitted */ +static void dwmac_if_interface_start( struct ifnet *ifp ) +{ + rtems_status_code sc; + dwmac_common_context *self = ifp->if_softc; + + + /* Mark that we are transmitting */ + ifp->if_flags |= IFF_OACTIVE; + + if ( self->state == DWMAC_COMMON_STATE_UP ) { + /* Wake up our task */ + sc = rtems_bsdnet_event_send( self->task_id_tx, + DWMAC_COMMON_EVENT_TX_TRANSMIT_FRAME ); + assert( sc == RTEMS_SUCCESSFUL ); + } +} + +static int dwmac_if_clk_csr_set( + const uint32_t gmii_clk_rate, + dwmac_common_context *self ) +{ + int eno = 0; + + + if ( gmii_clk_rate < DWCGNAC3504_CSR_F_35M ) { + self->csr_clock = DWCGNAC3504_CSR_20_35M; + } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_35M ) + && ( gmii_clk_rate < DWCGNAC3504_CSR_F_60M ) ) { + self->csr_clock = DWCGNAC3504_CSR_35_60M; + } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_60M ) + && ( gmii_clk_rate < DWCGNAC3504_CSR_F_100M ) ) { + self->csr_clock = DWCGNAC3504_CSR_60_100M; + } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_100M ) + && ( gmii_clk_rate < DWCGNAC3504_CSR_F_150M ) ) { + self->csr_clock = DWCGNAC3504_CSR_100_150M; + } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_150M ) + && ( gmii_clk_rate < DWCGNAC3504_CSR_F_250M ) ) { + self->csr_clock = DWCGNAC3504_CSR_150_250M; + } else if ( ( gmii_clk_rate >= DWCGNAC3504_CSR_F_250M ) + && ( gmii_clk_rate < DWCGNAC3504_CSR_F_300M ) ) { + self->csr_clock = DWCGNAC3504_CSR_250_300M; + } else { + eno = EINVAL; + } + + return eno; +} + +static int dwmac_fixup_unit_count( + const dwmac_common_context *self, + const int count, + const int default_value, + const int max ) +{ + int ret = count; + + + if ( ret <= 0 ) { + ret = DWMAC_ALIGN( default_value, self->CFG->L1_CACHE_LINE_SIZE ); + } else if ( ret > max ) { + ret = DWMAC_ALIGN( max, self->CFG->L1_CACHE_LINE_SIZE ); + } + + return ret; +} + +/* Called during initial setup */ +static int dwmac_if_attach( + dwmac_common_context *self, + struct rtems_bsdnet_ifconfig *bsd_config, + const dwmac_cfg *driver_config, + void *arg ) +{ + int eno = 0; + struct ifnet *ifp = &self->arpcom.ac_if; + char *unit_name = NULL; + int unit_number = rtems_bsdnet_parse_driver_name( + bsd_config, + &unit_name ); + const dwmac_callback_cfg *CALLBACK = &driver_config->CALLBACK; + const dwmac_common_desc_ops *DESC_OPS = + (const dwmac_common_desc_ops *) driver_config->DESC_OPS->ops; + + + assert( self != NULL ); + assert( bsd_config != NULL ); + assert( driver_config != NULL ); + assert( CALLBACK != NULL ); + + if ( self == NULL + || bsd_config == NULL + || driver_config == NULL + || CALLBACK == NULL + ) { + eno = EINVAL; + } else { + assert( CALLBACK->nic_enable != NULL ); + assert( CALLBACK->nic_disable != NULL ); + assert( CALLBACK->phy_enable != NULL ); + assert( CALLBACK->phy_disable != NULL ); + assert( CALLBACK->phy_event_enable != NULL ); + assert( CALLBACK->phy_event_clear != NULL ); + assert( CALLBACK->phy_events_get != NULL ); + assert( CALLBACK->phy_start != NULL ); + assert( CALLBACK->phy_stop != NULL ); + assert( CALLBACK->mem_alloc_nocache != NULL ); + assert( CALLBACK->mem_free_nocache != NULL ); + assert( CALLBACK->bus_setup != NULL ); + + if ( CALLBACK->nic_enable == NULL + || CALLBACK->nic_disable == NULL + || CALLBACK->phy_enable == NULL + || CALLBACK->phy_disable == NULL + || CALLBACK->phy_event_enable == NULL + || CALLBACK->phy_event_clear == NULL + || CALLBACK->phy_events_get == NULL + || CALLBACK->phy_start == NULL + || CALLBACK->phy_stop == NULL + || CALLBACK->mem_alloc_nocache == NULL + || CALLBACK->mem_free_nocache == NULL + || CALLBACK->bus_setup == NULL + ) { + eno = EINVAL; + } + } + + if ( eno == 0 ) { + self->dma_threshold_control = DWMAC_DMA_THRESHOLD_CONTROL_DEFAULT; + + if ( driver_config->addr_gmac_regs != NULL ) { + self->macgrp = driver_config->addr_gmac_regs; + + if ( driver_config->addr_dma_regs != NULL ) { + self->dmagrp = driver_config->addr_dma_regs; + } else { + eno = EINVAL; + } + } else { + eno = EINVAL; + } + } + + if ( eno == 0 ) { + eno = dwmac_if_clk_csr_set( + driver_config->GMII_CLK_RATE, + self + ); + } + + if ( eno == 0 ) { + assert( 32 >= driver_config->MDIO_BUS_ADDR ); + + if ( 32 < driver_config->MDIO_BUS_ADDR ) { + eno = EINVAL; + } + } + + if ( eno == 0 ) { + self->arg = arg; /* Optional argument from upper layer */ + self->state = DWMAC_COMMON_STATE_DOWN; + self->bsd_config = bsd_config; /* BSD-Net configuration. + Exists for ll BSD based network divers */ + + /* Device control */ + bsd_config->drv_ctrl = NULL; + + /* MDIO */ + self->mdio.mdio_r = dwmac_if_mdio_read; /* read from phy + registers */ + self->mdio.mdio_w = dwmac_if_mdio_write; /* write to phy + registers */ + + if ( driver_config->MAC_OPS == &DWMAC_1000_ETHERNET_MAC_OPS ) { + self->mdio.has_gmii = 1; + } else { + self->mdio.has_gmii = 0; + + /* dwmac_dma_ops_100 and dwmac_core_ops_100 is not yet implemented! */ + assert( driver_config->MAC_OPS == &DWMAC_1000_ETHERNET_MAC_OPS ); + eno = ENOTSUP; + } + + if ( eno == 0 ) { + self->CFG = driver_config; + ifp->if_ioctl = dwmac_if_interface_ioctl; /* Execute commands + at runtime */ + ifp->if_init = dwmac_if_interface_init; /* Initialization + (called once) */ + + /* Receive unit count */ + bsd_config->rbuf_count = dwmac_fixup_unit_count( + self, + bsd_config->rbuf_count, + DWMAC_CONFIG_RX_UNIT_COUNT_DEFAULT, + DWMAC_CONFIG_RX_UNIT_COUNT_MAX + ); + + /* Transmit unit count */ + bsd_config->xbuf_count = dwmac_fixup_unit_count( + self, + bsd_config->xbuf_count, + DWMAC_CONFIG_TX_UNIT_COUNT_DEFAULT, + DWMAC_CONFIG_TX_UNIT_COUNT_MAX + ); + + /* Copy MAC address */ + memcpy( + self->arpcom.ac_enaddr, + bsd_config->hardware_address, + ETHER_ADDR_LEN + ); + + /* Set interface data */ + ifp->if_softc = self; + ifp->if_unit = (short) unit_number; + ifp->if_name = unit_name; + + ifp->if_start = dwmac_if_interface_start; /* Start transmitting + frames */ + ifp->if_output = ether_output; + ifp->if_watchdog = NULL; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_timer = 0; + ifp->if_mtu = + bsd_config->mtu > 0 ? (u_long) bsd_config->mtu : ETHERMTU; + + eno = DESC_OPS->validate( self ); + assert( eno == 0 ); + } + + if ( eno == 0 ) { + /* Create and start the receive task for our driver */ + assert( self->task_id_rx == RTEMS_ID_NONE ); + self->task_id_rx = rtems_bsdnet_newproc( + "ntrx", + 4096, + dwmac_task_rx, + self + ); + assert( self->task_id_rx != RTEMS_ID_NONE ); + + if ( self->task_id_rx == RTEMS_ID_NONE ) { + eno = ENOMEM; + } + } + + if ( eno == 0 ) { + /* Create and start the transmit task for our driver */ + assert( self->task_id_tx == RTEMS_ID_NONE ); + self->task_id_tx = rtems_bsdnet_newproc( + "nttx", + 4096, + dwmac_task_tx, + self + ); + assert( self->task_id_tx != RTEMS_ID_NONE ); + + if ( self->task_id_tx == RTEMS_ID_NONE ) { + eno = ENOMEM; + } + } + } + + if ( eno == 0 ) { + /* Change status */ + ifp->if_flags |= IFF_RUNNING; + + /* Attach the interface */ + if_attach( ifp ); + ether_ifattach( ifp ); + } + + return eno; +} + +/* Initial setup method. Part of the driver API + * Returns the address of the driver context on success and NULL on failure */ +void *dwmac_network_if_attach_detach( + struct rtems_bsdnet_ifconfig *bsd_config, + const dwmac_cfg *driver_config, + void *arg, + int attaching ) +{ + int eno = 0; + dwmac_common_context *context = NULL; + + + if ( attaching ) { + context = calloc( 1, sizeof( dwmac_common_context ) ); + assert( context != NULL ); + + if ( context != NULL ) { + eno = dwmac_if_attach( + context, + bsd_config, + driver_config, + arg + ); + + if ( eno != 0 ) { + free( context, 0 ); + context = NULL; + } + } + } else { + /* Detaching is not supported */ + assert( attaching != false ); + } + + return context; +} + +int dwmac_if_read_from_phy( + void *arg, + const unsigned phy_reg, + uint16_t *val ) +{ + int eno = EINVAL; + dwmac_common_context *self = (dwmac_common_context *) arg; + uint32_t value; + + + if ( arg != NULL ) { + eno = dwmac_if_mdio_read( + self->CFG->MDIO_BUS_ADDR, + self, + phy_reg, + &value ); + } + + if ( eno == 0 ) { + *val = (uint16_t) value; + } + + return eno; +} + +int dwmac_if_write_to_phy( + void *arg, + const unsigned phy_reg, + const uint16_t val ) +{ + int eno = EINVAL; + dwmac_common_context *self = (dwmac_common_context *) arg; + + + if ( arg != NULL ) { + eno = dwmac_if_mdio_write( + self->CFG->MDIO_BUS_ADDR, + self, + phy_reg, + val ); + } + + return eno; +} + +int dwmac_if_handle_phy_event( void *arg ) +{ + int eno; + rtems_status_code sc; + dwmac_common_context *self = (dwmac_common_context *) arg; + + + sc = rtems_bsdnet_event_send( + self->task_id_tx, + DWMAC_COMMON_EVENT_TX_PHY_STATUS_CHANGE + ); + eno = rtems_status_code_to_errno( sc ); + + return eno; +} diff --git a/c/src/libchip/network/dwmac.h b/c/src/libchip/network/dwmac.h new file mode 100644 index 0000000000..9ccf75af44 --- /dev/null +++ b/c/src/libchip/network/dwmac.h @@ -0,0 +1,878 @@ +/** + * @file + * + * @brief API header for the DWMAC 10/100/1000 Network Interface Controllers + * + * DWMAC 10/100/1000 on-chip Ethernet controllers are a Synopsys IP Core. + */ + +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef DWMAC_H_ +#define DWMAC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @brief PHY event. + * + * Data type to be used for PHY events and event sets. + */ +typedef uint8_t dwmac_phy_event; + +/** @brief PHY event Jabber. */ +extern const dwmac_phy_event PHY_EVENT_JABBER; + +/** @brief PHY event Receive Error. */ +extern const dwmac_phy_event PHY_EVENT_RECEIVE_ERROR; + +/** @brief PHY event Page Receive. */ +extern const dwmac_phy_event PHY_EVENT_PAGE_RECEIVE; + +/** @brief PHY event Parallel Detect Fault. */ +extern const dwmac_phy_event PHY_EVENT_PARALLEL_DETECT_FAULT; + +/** @brief PHY event Link Partner Acknowledge. */ +extern const dwmac_phy_event PHY_EVENT_LINK_PARTNER_ACK; + +/** @brief PHY event Link Down. */ +extern const dwmac_phy_event PHY_EVENT_LINK_DOWN; + +/** @brief PHY event Remote Fault. */ +extern const dwmac_phy_event PHY_EVENT_REMOTE_FAULT; + +/** @brief PHY event Link Up. */ +extern const dwmac_phy_event PHY_EVENT_LINK_UP; + +/** @brief NIC enable + * + * Enables (e.g. powers up) the network interface card. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_nic_enable)( void *arg ); + +/** @brief NIC disable. + * + * Disables (e.g. powers down) the network interface card. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_nic_disable)( void *arg ); + +/** @brief PHY enable. + * + * Enables (e.g. powers up) the network PHY. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_phy_enable)( void *arg ); + +/** @brief PHY disable. + * + * Disables (e.g. powers down) the network PHY. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_phy_disable)( void *arg ); + +/** @brief PHY event enable. + * + * Enables generation of events for an event set. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @param[in] event_set Set of events. For these events shall get generated + * upon PHY status change. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_phy_event_enable)( + void *arg, + const dwmac_phy_event event_set ); + +/** @brief Clear phy event status. + * + * Clears all PHY event statuses. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_phy_event_status_clear)( void *arg ); + +/** + * @brief Get the PHY event status. + * + * Reports status on PHY events (e.g. PHY interrupts). + * @param[in,out] arg The void pointer argument passed to the + * attach_detach method. + * @param[out] event_set Pointer to a buffer for a set of events for which a + * PHY status change was detected. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + * @see dwmac_phy_event for events. + */ +typedef int +(*dwmac_if_phy_events_status_get)( + void *arg, + dwmac_phy_event *event_set ); + +/** + * @brief Start the network PHY. + * + * Do anything necessary to start the network PHY (start generating + * events, ...). + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwcmac_if_phy_start)( void *arg ); + +/** + * @brief Stop the network PHY. + * + * Do anything necessary to stop the network PHY (stop generating events, ...). + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwcmac_if_phy_stop)( void *arg ); + +/** + * @brief Allocate nocache RAM. + * + * Allocate uncached RAM. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @param[out] memory Pointer of a buffer to write the address of the + * allocated memory to. + * @param[in] size Number of bytes to be allocated + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_mem_alloc_nocache)( + void *arg, + void **memory, + const size_t size ); + +/** + * @brief Free nocache RAM. + * + * Release uncached RAM. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @param[in] memory Pointer to the memory to be freed. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_mem_free_nocache)( + void *arg, + void *memory ); + +/** + * @brief Bus setup. + * + * Callback method for setting up the system bus for the network driver. + * @param[in,out] arg The void pointer argument passed to the attach_detach + * method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach for the attach_detach method. + */ +typedef int +(*dwmac_if_bus_setup)( void *arg ); + +/** + * @brief Callback methods. + * + * The address of an instance of such a callback struct must get passed + * to the attach_detach method of the network driver. + * Via these callback methods, those parts of the network driver which + * are micro controller specific or PCB specific will get handled. + * @see dwmac_network_if_attach_detach() for the drivers attach_detach method. + */ +typedef struct { + /** @brief Enable the network interface controller. */ + dwmac_if_nic_enable nic_enable; + + /** @brief Disable the network interface controller. */ + dwmac_if_nic_disable nic_disable; + + /** @brief Enable (power up, ... ) the network PHY. */ + dwmac_if_phy_enable phy_enable; + + /** @brief Disable (power down, ... ) the network PHY. */ + dwmac_if_phy_disable phy_disable; + + /** @brief Enable a set of PHY events for generation upon status change. */ + dwmac_if_phy_event_enable phy_event_enable; + + /** @brief Clear the event status (e.g. interrupt staus) of the PHY. */ + dwmac_if_phy_event_status_clear phy_event_clear; + + /** @brief Get set of tripped events from PHY. */ + dwmac_if_phy_events_status_get phy_events_get; + + /** @brief Start the phy (start generating events, ...). */ + dwcmac_if_phy_start phy_start; + + /** @brief Stop the phy (stop generating events, ...). */ + dwcmac_if_phy_stop phy_stop; + + /** @brief Allocate uncached memory. */ + dwmac_if_mem_alloc_nocache mem_alloc_nocache; + + /** @brief Free uncached memory. */ + dwmac_if_mem_free_nocache mem_free_nocache; + + /** @brief Setup handling for bus upon device startup. */ + dwmac_if_bus_setup bus_setup; +} dwmac_callback_cfg; + +/** @brief Initializer for callback methods. + * + * Initializes a struct which contains pointers to the callback methods + * required by the driver. + * @see dwmac_callback_cfg for the struct. + * @param[in] nic_enable Callback method for for enabling the + * network interface controller. + * @param[in] nic_disable Callback method for disabling the + * network interface controller. + * @param[in] phy_enable Callback method for enabling the + * network PHY. + * @param[in] phy_disable Callback method for disabling the + * network PHY. + * @param[in] phy_event_enable Callback method for enabling PHY status + * changes for event generation. + * @param[in] phy_event_clear Callback method for + * clearing/acknowledging PHY events. + * @param[in] phy_events_get Callback method for reading the status of + * PHY events. + * @param[in] phy_start Callback method for starting event + * generation by the network PHY. + * @param[in] phy_stop Callback method for stoping event + * generation by the network PHY. + * @param[in] mem_alloc_nocache Callback method for allocating uncached + * RAM. + * @param[in] mem_free_nocache Callback method for releasing uncached + * RAM. + * @param[in] bus_setup Callback method for setting up the system + * bus. + * @returns An initialized struct of pointers to callback methods. + * @see dwmac_if_nic_enable for the NIC enable methods. + * @see dwmac_if_nic_disable for NIC disable methods. + * @see dwmac_if_phy_enable for PHY enable methods. + * @see dwmac_if_phy_disable for PHY disable methods. + * @see dwmac_if_phy_event_enable for PHY envent enable methods. + * @see dwmac_if_phy_event_status_clear for PHY event status clear methods. + * @see dwmac_if_phy_events_status_get for PHY event status get methods. + * @see dwcmac_if_phy_start for PHY start methods. + * @see dwcmac_if_phy_stop for PHY stop methods. + * @see dwmac_if_mem_alloc_nocache for nocache mem alloc methods. + * @see dwmac_if_mem_free_nocache for nocache mem free methods. + * @see dwmac_if_bus_setup for bus setup methods. + */ +#define DWMAC_CALLBACK_CFG_INITIALIZER( \ + nic_enable, \ + nic_disable, \ + phy_enable, \ + phy_disable, \ + phy_event_enable, \ + phy_event_clear, \ + phy_events_get, \ + phy_start, \ + phy_stop, \ + mem_alloc_nocache, \ + mem_free_nocache, \ + bus_setup \ + ) \ + { \ + nic_enable, \ + nic_disable, \ + phy_enable, \ + phy_disable, \ + phy_event_enable, \ + phy_event_clear, \ + phy_events_get, \ + phy_start, \ + phy_stop, \ + mem_alloc_nocache, \ + mem_free_nocache, \ + bus_setup \ + } + +/** @brief Ethernet MAC operations. + * + * Actually this is a mere wrapper which contains void ponters to the core + * operations and DMA operations to be used by the driver (void pointer + * for the purpose of information hiding). + * There will be two instances of such a struct: + * One for DWMAC 10/100 ethernet operations and one for DWMAC 1000 ethernet + * operations. + * The address of either of these must get passed to the initializer of the + * driver configuration for configuring the driver. + * @see DWMAC_100_ETHERNET_MAC_OPS for DWMAC 10/100 ethernet operations. + * @see DWMAC_1000_ETHERNET_MAC_OPS for DWMAC 1000 ethernet operations. + * @see DWMAC_CFG_INITIALIZER driver configuration initializer. + * @see DWMAC_ETHERNET_MAC_OPS_INITIALIZER for an initializer for the MAC + * operations + */ +typedef struct { + const void *core; + const void *dma; +} dwmac_ethernet_mac_ops; + +/** @brief Ethernet MAC operations initializer. + * + * Initializes a structure of ethernet MAC operations. + * @see dwmac_ethernet_mac_ops for the struct. + * @param[in] core_ops_addr Address of the core operations to be used by the + * driver. + * @param[in] dma_ops_addr Address of the DMA operations to be used by the + * driver. + * @returns An initialized struct of ethernet mac operations. + */ +#define DWMAC_ETHERNET_MAC_OPS_INITIALIZER( \ + core_ops_addr, \ + dma_ops_addr \ + ) \ + { \ + core_ops_addr, \ + dma_ops_addr \ + } + +/** @brief Descriptor operations. + * + * Actually this is a mere wrapper which contains a void pointer to a + * descriptor operations struct which can be used by the driver (void pointer + * for the purpose of information hiding). + * There will be two instances of such a struct: + * One for normal DMA descriptors and one for enhanced DMA descriptors. + * The address of either of these must get passed to the configuration + * initializer for configuring the driver. + * @see DWMAC_DESCRIPTOR_OPS_NORMAL for normal DMA descriptor operations. + * @see DWMAC_DESCRIPTOR_OPS_ENHANCED for enhanced DMA descriptor operations. + * @see DWMAC_CFG_INITIALIZER for the configuration initializer. + * @see DWMAC_DESCRIPTOR_OPS_INITIALIZER for an initializer an initializer + * for descriptor operations. + */ +typedef struct { + /** @brief Address of the descriptor operations to be used by the driver */ + const void *ops; +} dwmac_descriptor_ops; + +/** @brief Initializer for descriptor operations. + * + * Initializes a struct which simply makes up a wrapper for DMA descriptor + * operations. + * @param[in] desc_ops_addr Address of the descriptor operations. + * @returns an initialized descriptor operations struct. + * @see dwmac_descriptor_ops for the struct. + */ +#define DWMAC_DESCRIPTOR_OPS_INITIALIZER( \ + desc_ops_addr \ + ) \ + { \ + desc_ops_addr \ + } + +/** @brief Ethernet MAC operations for DWMAC 1000. + * + * Pass the address of DWMAC_1000_ETHERNET_MAC_OPS to the configuration + * initializer if the driver is supposed to control a DWMAC 1000. + * @see DWMAC_CFG_INITIALIZER for the configuration initializer. + */ +extern const dwmac_ethernet_mac_ops DWMAC_1000_ETHERNET_MAC_OPS; + +/** @brief Ethernet MAC operations for DWMAC 10/100. + * + * Pass the address of DWMAC_100_ETHERNET_MAC_OPS to the configuration + * initializer if the driver is supposed to control a DWMAC 10/100. + * NOTE: Currently the DWMAC_100_ETHERNET_MAC_OPS are not yet implemented. + * @see DWMAC_CFG_INITIALIZER for the configuration initializer. + */ +extern const dwmac_ethernet_mac_ops DWMAC_100_ETHERNET_MAC_OPS; + +/** @brief DMA descriptor operations for normal descriptors. + * + * Pass the address of DWMAC_DESCRIPTOR_OPS_NORMAL to the configuration + * initializer if you intend to use the normal DMA descriptors. + * NOTE: Currently the DWMAC_DESCRIPTOR_OPS_NORMAL are not yet implmented. + * @see DWMAC_CFG_INITIALIZER for the configuration initializer. + */ +extern const dwmac_descriptor_ops DWMAC_DESCRIPTOR_OPS_NORMAL; + +/** @brief DMA descriptor operations for enhanced descriptors. + * + * Pass the address of DWMAC_DESCRIPTOR_OPS_ENHANCED to the configuration + * initializer if you intend to use the enhanced DMA descriptors. + * @see DWMAC_CFG_INITIALIZER for the configuration initializer. + */ +extern const dwmac_descriptor_ops DWMAC_DESCRIPTOR_OPS_ENHANCED; + +/** @brief Burst size. */ +typedef enum { + /** @brief Burst size = 1. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_1 = 0, + + /** @brief Burst size = 2. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_2 = 1, + + /** @brief Burst size = 4. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_4 = 3, + + /** @brief Burst size = 8. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_8 = 7, + + /** @brief Burst size = 16. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_16 = 15, + + /** @brief Burst size = 32. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_32 = 31, + + /** @brief Burst size = 64. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_64 = 63, + + /** @brief Burst size = 128. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_128 = 127, + + /** @brief Burst size = 256. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_256 = 255 +} dwmac_dma_cfg_bus_mode_burst_length; + +/** @brief Burst mode. */ +typedef enum { + /** @brief Single burst or incrment bursts. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR, + + /** @brief Fixed burst size. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_FIXED +} dwmac_dma_cfg_bus_mode_burst_mode; + +/** @brief Mixed burst mode support. */ +typedef enum { + /** @brief Mixed burst mode is not supported. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_NOT_MIXED, + /** @brief Mixed burst mode is supported. */ + DWMAC_DMA_CFG_BUS_MODE_BURST_MIXED +} dwmac_dma_cfg_bus_mode_burst_mixed; + +/** @brief Burst length 4 support. */ +typedef enum { + /** @brief Bursts of length 4 are not supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_NOT_SUPPORTED, + + /** @brief Bursts of length 4 are supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_SUPPORTED +} dwmac_dma_cfg_axi_burst_length_4_support; + +/** @brief Burst length 8 support. */ +typedef enum { + /** @brief Bursts of length 8 are not supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_NOT_SUPPORTED, + + /** @brief Bursts of length 8 are supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_SUPPORTED +} dwmac_dma_cfg_axi_burst_length_8_support; + +/** @brief Burst length 16 support. */ +typedef enum { + /** @brief Bursts of length 16 are not supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_NOT_SUPPORTED, + + /** @brief Bursts of length 16 are supported. */ + DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_SUPPORTED +} dwmac_dma_cfg_axi_burst_length_16_support; + +/** @brief DMA Burst Boundary parameters. */ +typedef enum { + /** @brief Transfers do not cross 4 kB boundary. */ + DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB, + + /** @brief Transfers do not cross 1 kB boundary. */ + DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_1_KB +} dwmac_dma_cfg_axi_burst_boundary; + +/** + * @brief DMA configuration. + * + * Configuration data for the DMA of the network driver. + * @see DWMAC_DMA_CFG_INITIALIZER for an inititializer. + */ +typedef union { + uint16_t raw; + struct { + /** @brief Maximum number of beats to be transferred in one DMA transaction. + * + * This is the maximum value that is used in a single block Read or Write. + * The DMA always attempts to burst as specified in bus_mode_burst_length + * each time it starts a Burst transfer on the host bus. + * Any non-permissible value results in undefined behavior. + * The bus_mode_burst_length values have the following limitation: + * The maximum number of possible beats (bus_mode_burst_length) is limited + * by the size of the Tx FIFO and Rx FIFO in the MTL layer and the data bus + * width on the DMA. + * The FIFO has a constraint that the maximum beat supported is half the + * depth of the FIFO, except when specified. + * @see dwmac_dma_cfg_bus_mode_burst_length for permissible values */ + uint16_t bus_mode_burst_length : 6; + + /** @brief Controls whether the AXI Master performs fixed bursts or not. + * + * When set to DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_FIXED, the AXI interface + * uses FIXED bursts during the start of the normal burst transfers. + * When set to DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR, the AXI + * interface uses SINGLE and INCR burst transfer operations. + * @see dwmac_dma_cfg_bus_mode_burst_mode for valid parameters. */ + uint16_t bus_mode_burst_mode : 1; + + /** @brief Controls whether mixed bursts will be used or not. + * + * Mixed burst has no effect when if DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_FIXED is set. + * @see dwmac_dma_cfg_bus_mode_burst_mixed for valid parameters. */ + uint16_t bus_mode_burst_mixed : 1; + + /** @brief Controls support of burst length 4. + * + * When set to DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_SUPPORTED, the GMAC-AXI is + * allowed to select a burst length of 4 on the AXI Master interface. + * @see dwmac_dma_cfg_axi_burst_length_4_support for valid parameters see. */ + uint16_t axi_burst_length_4_support : 1; + + /** @brief Controls support of burst length 8. + * + * When set to DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_SUPPORTED, the GMAC-AXI is + * allowed to select a burst length of 8 on the AXI Master interface. + * @see dwmac_dma_cfg_axi_burst_length_8_support For valid parameters. */ + uint16_t axi_burst_length_8_support : 1; + + /** @brief Controls support of burst length 16. + * + * When set to DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_SUPPORTED fixed bust is + * not selected, the GMAC-AXI is allowed to select a burst length of 16 on + * the AXI Master interface. + * @see dwmac_dma_cfg_axi_burst_length_16_support for valid parameters see. */ + uint16_t axi_burst_length_16_support : 1; + + /** @brief Select Burst Boundary. + * + * When set to DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_1_KB, the GMAC-AXI Master + * performs burst transfers that do not cross 1 KB boundary. + * When set to DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB, the GMAC-AXI Master + * performs burst transfers that do not cross 4 KB boundary. + * @see dwmac_dma_cfg_axi_burst_boundary for valid parameters see. */ + uint16_t axi_burst_boundary : 1; + + uint16_t unused : 4; + }; +} dwmac_dma_cfg; + +/** @brief DMA Configuration initializer. + * + * Initializer for a DMA configuration struct. + * + * @param[in] bus_mode_burst_length Number of bytes to be sent in one + * burst within a DMA transfer on the + * bus . + * @param[in] bus_mode_burst_mode Mode to be used for burst transfers. + * @param[in] bus_mode_burst_mixed Use mixed bursts or not. Fixed bursts + * have priority over mixed bursts. + * @param[in] axi_burst_length_4_support Support or don't support burst + * lengths of 4. + * @param[in] axi_burst_length_8_support Support or don't support burst + * lengths of 8. + * @param[in] axi_burst_length_16_support Support or don't support burst + * lengths of 16. + * @param[in] axi_burst_boundary Select the burst boundary. + * @returns An initialized struct of DMA configuration parameters. + * @see dwmac_dma_cfg_bus_mode_burst_length for burst lengths. + * @see dwmac_dma_cfg_bus_mode_burst_mode for burst modes + * @see dwmac_dma_cfg_bus_mode_burst_mixed for burst mixing. + * @see dwmac_dma_cfg_axi_burst_length_4_support for burst length 4 support. + * @see dwmac_dma_cfg_axi_burst_length_8_support for burst length 8 support. + * @see dwmac_dma_cfg_axi_burst_length_16_support for burst length 16 support. + * @see dwmac_dma_cfg_axi_burst_boundary for burst boundaries. + */ +#define DWMAC_DMA_CFG_INITIALIZER( \ + bus_mode_burst_length, \ + bus_mode_burst_mode, \ + bus_mode_burst_mixed, \ + axi_burst_length_4_support, \ + axi_burst_length_8_support, \ + axi_burst_length_16_support, \ + axi_burst_boundary \ + ) \ + { \ + BSP_FLD16( bus_mode_burst_length, 0, 5 ) \ + | BSP_FLD16( bus_mode_burst_mode, 6, 6 ) \ + | BSP_FLD16( bus_mode_burst_mixed, 7, 7 ) \ + | BSP_FLD16( axi_burst_length_4_support, 8, 8 ) \ + | BSP_FLD16( axi_burst_length_8_support, 9, 9 ) \ + | BSP_FLD16( axi_burst_length_16_support, 10, 10 ) \ + | BSP_FLD16( axi_burst_boundary, 11, 11 ) \ + } + +/** + * @brief Driver configuration. + * + * Configuration data for the network driver. + * See @see DWMAC_CFG_INITIALIZER for an initializer. + */ +typedef struct { + /** @brief The clock to be used for the gmii interface in Hz. */ + const uint32_t GMII_CLK_RATE; + + /** @brief Start address of the MAC group registers. */ + volatile void *addr_gmac_regs; + + /** @brief Start address of the DMA group registers. */ + volatile void *addr_dma_regs; + + /** @brief Address of the PHY on the mdio bus (5 bit). */ + const uint8_t MDIO_BUS_ADDR; + + /** @brief Bytes per L1 cache line. */ + const uint8_t L1_CACHE_LINE_SIZE; + + /** @brief Interrupt vector number for EMAC IRQs. */ + const rtems_vector_number IRQ_EMAC; + + /** @brief Optional configuration for bus mode and axi bus mode. */ + const dwmac_dma_cfg *DMA_CFG; + + /** @brief Methods which must get provided to the by the micro controller. */ + const dwmac_callback_cfg CALLBACK; + + /** @brief Operations which are specific to the ethernet MAC. */ + const dwmac_ethernet_mac_ops *MAC_OPS; + + /** @brief DMA descriptor operations. */ + const dwmac_descriptor_ops *DESC_OPS; +} dwmac_cfg; + +/** + * @brief Configuration initializer. + * + * Initializes the configuration data to be passed to + * the initialization method. + * @see dwmac_network_if_attach_detach(). + * + * @param[in] mdio_clk_rate The clock to be used for the gmii + * interface in Hz. + * @param[in] macgrp_regs_addr Base address of the MAC group registers. + * @param[in] dmagrp_regs_addr Base address of the DMA group registers. + * @param[in] mdio_bus_addr Address of the network PHY on the + * mdio bus. + * @param[in] l1_cache_line_size Size of a cache line in the level 1 cache. + * @param[in] irq_emac Number of the EMAC interrupt. + * @param[in] arch_has_prefetch True if architecture supports. + * prefetching, false if not. + * @param[in] dma_cfg_addr Address of the optional DMA configuration. + * Set to NULL for defaults. + * @param[in] nic_enable Callback method for for enabling the + * network interface controller. + * @param[in] nic_disable Callback method for disabling the + * network interface controller. + * @param[in] phy_enable Callback method for enabling the + * network PHY. + * @param[in] phy_disable Callback method for disabling the + * network PHY. + * @param[in] phy_event_enable Callback method for enabling PHY status + * changes for event generation. + * @param[in] phy_event_clear Callback method for + * clearing/acknowledging PHY events. + * @param[in] phy_events_get Callback method for reading the status of + * PHY events. + * @param[in] phy_start Callback method for starting event + * generation by the network PHY. + * @param[in] phy_stop Callback method for stoping event + * generation by the network PHY. + * @param[in] mem_alloc_nocache Callback method for allocating uncached + * RAM. + * @param[in] mem_free_nocache Callback method for releasing uncached + * RAM. + * @param[in] bus_setup Callback method for setting up the system + * bus. + * @param[in] ethernet_mac_ops_addr Address of a struct encapsulating + * ethernet MAC operations for DWMAC 1000 or + * DWMAC 10/100. + * @param[in] descriptor_ops_addr Address of a struct encasulating DMA + * descriptor operations for either normal + * descriptors or enhanced descriptors. + * @returns An initialized struct of configuration parameters. + * @see dwmac_cfg for the struct returned. + * @see dwmac_dma_cfg for DMA configurations. + * @see dwmac_if_nic_enable for NIC enable methods. + * @see dwmac_if_nic_disable for NIC disable methods. + * @see dwmac_if_phy_enable for PHY enable methods. + * @see dwmac_if_phy_disable for PHY disable methods. + * @see dwmac_if_phy_event_enable for PHY event enble methods. + * @see dwmac_if_phy_event_status_clear for PHY status clear methods. + * @see dwmac_if_phy_events_status_get for PHY status get mehods. + * @see dwcmac_if_phy_start for PHY start methods. + * @see dwcmac_if_phy_stop for PHY stop methods. + * @see dwmac_if_mem_alloc_nocache for nocache memory allocate methods. + * @see dwmac_if_mem_free_nocache for nocache memory release methods. + * @see dwmac_if_bus_setup for bus setup methods. + * @see DWMAC_1000_ETHERNET_MAC_OPS for DWMAC 1000 MAC operations. + * @see DWMAC_100_ETHERNET_MAC_OPS for DWMAC 10/100 MAC operations. + * @see DWMAC_DESCRIPTOR_OPS_NORMAL for normal DMA descriptor operations. + * @see DWMAC_DESCRIPTOR_OPS_ENHANCED for enhanced DMA descriptor operations. + */ +#define DWMAC_CFG_INITIALIZER( \ + mdio_clk_rate, \ + macgrp_regs_addr, \ + dmagrp_regs_addr, \ + mdio_bus_addr, \ + l1_cache_line_size, \ + irq_emac, \ + dma_cfg_addr, \ + nic_enable, \ + nic_disable, \ + phy_enable, \ + phy_disable, \ + phy_event_enable, \ + phy_event_clear, \ + phy_events_get, \ + phy_start, \ + phy_stop, \ + mem_alloc_nocache, \ + mem_free_nocache, \ + bus_setup, \ + ethernet_mac_ops_addr, \ + descriptor_ops_addr \ + ) \ + { \ + mdio_clk_rate, \ + macgrp_regs_addr, \ + dmagrp_regs_addr, \ + mdio_bus_addr, \ + l1_cache_line_size, \ + irq_emac, \ + dma_cfg_addr, \ + DWMAC_CALLBACK_CFG_INITIALIZER( \ + nic_enable, \ + nic_disable, \ + phy_enable, \ + phy_disable, \ + phy_event_enable, \ + phy_event_clear, \ + phy_events_get, \ + phy_start, \ + phy_stop, \ + mem_alloc_nocache, \ + mem_free_nocache, \ + bus_setup \ + ), \ + ethernet_mac_ops_addr, \ + descriptor_ops_addr \ + } + +/** + * @brief Initialization method. + * + * Initializes the network driver and "links" it to the network stack. + * + * @param[in] bsd_config The BSD configuation passed to all + * network_if_attach_detach() methods. + * @param[in] driver_config Address of of a struct containing driver + * specific configuration data. + * @param[in] arg An optional argument which will get passed to all + * callback methods. + * @param[in] attaching 1 for attching and 0 for detaching. + * NOTE: Detaching is not supported! + * @returns Address of the drivers context if successful or NULL if not + * successful. + * @see dwmac_cfg for the driver configuration struct + * @see DWMAC_CFG_INITIALIZER() for an initializer for the driver configuration + */ +void *dwmac_network_if_attach_detach( + struct rtems_bsdnet_ifconfig *bsd_config, + const dwmac_cfg *driver_config, + void *arg, + int attaching ); + +/** + * @brief Read from PHY + * + * Read a value from a register of the network PHY. + * + * @param[in,out] arg Pointer returned from the attach_detach method. + * @param[in] phy_reg The PHY register to be read from. + * @param[out] val Buffer address for the value to be read. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach() for the attach detach method. + */ +int dwmac_if_read_from_phy( + void *arg, + const unsigned phy_reg, + uint16_t *val ); + +/** + * @brief Write to PHY. + * + * Write a value to a register of the network PHY. + * + * @param[in,out] arg Pointer returned from the attach_detach method. + * @param[in] phy_reg The PHY register to be written to. + * @param[in] val The value to be written. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach() for the attach_detach method. + */ +int dwmac_if_write_to_phy( + void *arg, + const unsigned phy_reg, + const uint16_t val ); + +/** + * @brief Handle PHY event. + * + * Handle an event from the network PHY. + * + * @param[in,out] arg Pointer returned from the attach_detach method. + * @returns 0 on success, error code from errno.h on failure. + * @see dwmac_network_if_attach_detach() for the attach_detach method. + */ +int dwmac_if_handle_phy_event( void *arg ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWMAC_H_ */ -- cgit v1.2.3