/** * @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, };