[4953b724] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @brief DWMAC 1000 on-chip Ethernet controllers Core Handling |
---|
| 5 | * |
---|
| 6 | * Functions and data which are specific to the DWMAC 1000 Core Handling. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /* |
---|
| 10 | * Copyright (c) 2013 embedded brains GmbH. All rights reserved. |
---|
| 11 | * |
---|
| 12 | * embedded brains GmbH |
---|
| 13 | * Dornierstr. 4 |
---|
| 14 | * 82178 Puchheim |
---|
| 15 | * Germany |
---|
| 16 | * <rtems@embedded-brains.de> |
---|
| 17 | * |
---|
| 18 | * The license and distribution terms for this file may be |
---|
| 19 | * found in the file LICENSE in this distribution or at |
---|
| 20 | * http://www.rtems.org/license/LICENSE. |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | #include <assert.h> |
---|
| 24 | #include "dwmac-core.h" |
---|
| 25 | #include "dwmac-common.h" |
---|
| 26 | |
---|
| 27 | #define DWMAC_1000_CORE_DEBUG |
---|
| 28 | |
---|
| 29 | //#undef DWMAC_1000_CORE_DEBUG |
---|
| 30 | #ifdef DWMAC_1000_CORE_DEBUG |
---|
| 31 | #define DWMAC_1000_CORE_PRINT_DBG( fmt, args ... ) printk( fmt, ## args ) |
---|
| 32 | #else |
---|
| 33 | #define DWMAC_1000_CORE_PRINT_DBG( fmt, args ... ) do { } while ( 0 ) |
---|
| 34 | #endif |
---|
| 35 | |
---|
| 36 | #define DWMAC_1000_CORE_INIT \ |
---|
| 37 | ( \ |
---|
| 38 | ( MACGRP_MAC_CONFIGURATION_JD \ |
---|
| 39 | | MACGRP_MAC_CONFIGURATION_BE ) \ |
---|
| 40 | & ~MACGRP_MAC_CONFIGURATION_PS \ |
---|
| 41 | ) |
---|
| 42 | |
---|
| 43 | #define DWMAC_1000_CORE_HASH_TABLE_SIZE 256 |
---|
| 44 | |
---|
| 45 | static volatile uint32_t *dwmac_1000_core_get_mac_addr_low( |
---|
| 46 | dwmac_common_context *self, |
---|
| 47 | const unsigned int mac_addr_index ) |
---|
| 48 | { |
---|
| 49 | volatile uint32_t *addr = NULL; |
---|
| 50 | |
---|
| 51 | assert( self != NULL ); |
---|
| 52 | assert( mac_addr_index <= 127 ); |
---|
| 53 | |
---|
| 54 | if ( mac_addr_index > 15 ) { |
---|
| 55 | addr = &self->macgrp->mac_addr16_127[mac_addr_index].low; |
---|
| 56 | } else { |
---|
| 57 | addr = &self->macgrp->mac_addr0_15[mac_addr_index].low; |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | return addr; |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | static volatile uint32_t *dwmac_1000_core_get_mac_addr_high( |
---|
| 64 | dwmac_common_context *self, |
---|
| 65 | const unsigned int mac_addr_index ) |
---|
| 66 | { |
---|
| 67 | volatile uint32_t *addr = NULL; |
---|
| 68 | |
---|
| 69 | assert( self != NULL ); |
---|
| 70 | assert( mac_addr_index <= 127 ); |
---|
| 71 | |
---|
| 72 | if ( mac_addr_index > 15 ) { |
---|
| 73 | addr = &self->macgrp->mac_addr16_127[mac_addr_index].high; |
---|
| 74 | } else { |
---|
| 75 | addr = &self->macgrp->mac_addr0_15[mac_addr_index].high; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | return addr; |
---|
| 79 | } |
---|
| 80 | |
---|
| 81 | static void dwmac_1000_core_init( dwmac_common_context *self ) |
---|
| 82 | { |
---|
| 83 | uint32_t value = self->macgrp->mac_configuration; |
---|
| 84 | |
---|
| 85 | value |= DWMAC_1000_CORE_INIT; |
---|
| 86 | |
---|
| 87 | if ( ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_RXTYP1COE ) != 0 |
---|
| 88 | || ( self->dmagrp->hw_feature & DMAGRP_HW_FEATURE_RXTYP2COE ) != 0 ) { |
---|
| 89 | /* Enable RX checksum calculation offload to hardware */ |
---|
| 90 | value |= MACGRP_MAC_CONFIGURATION_IPC; |
---|
| 91 | } |
---|
| 92 | |
---|
| 93 | /* No Jumbo- or Giant frames. The network stack does not support them */ |
---|
| 94 | value &= ~MACGRP_MAC_CONFIGURATION_JE; |
---|
| 95 | value &= ~MACGRP_MAC_CONFIGURATION_TWOKPE; |
---|
| 96 | self->macgrp->mac_configuration = value; |
---|
| 97 | |
---|
| 98 | /* Mask GMAC interrupts */ |
---|
| 99 | self->macgrp->interrupt_mask = |
---|
| 100 | MACGRP_INTERRUPT_MASK_RGSMIIIM |
---|
| 101 | | MACGRP_INTERRUPT_MASK_PCSLCHGIM |
---|
| 102 | | MACGRP_INTERRUPT_MASK_PCSANCIM |
---|
| 103 | | MACGRP_INTERRUPT_MASK_TSIM; |
---|
| 104 | |
---|
| 105 | /* mask out interrupts because we don't handle them yet */ |
---|
| 106 | self->macgrp->mmc_receive_interrupt_mask = ( uint32_t ) ~0L; |
---|
| 107 | self->macgrp->mmc_transmit_interrupt_mask = ( uint32_t ) ~0L; |
---|
| 108 | self->macgrp->mmc_ipc_receive_interrupt_mask = ( uint32_t ) ~0L; |
---|
| 109 | } |
---|
| 110 | |
---|
| 111 | static void dwmac_1000_core_set_umac_addr( |
---|
| 112 | dwmac_common_context *self, |
---|
| 113 | const uint8_t *addr, |
---|
| 114 | unsigned int reg_n ) |
---|
| 115 | { |
---|
| 116 | dwmac_core_set_mac_addr( |
---|
| 117 | addr, |
---|
| 118 | dwmac_1000_core_get_mac_addr_high( self, reg_n ), |
---|
| 119 | dwmac_1000_core_get_mac_addr_low( self, reg_n ) |
---|
| 120 | ); |
---|
| 121 | } |
---|
| 122 | |
---|
| 123 | static void dwmac_1000_core_set_hash_filter( |
---|
| 124 | dwmac_common_context *self, |
---|
| 125 | const bool add, |
---|
| 126 | struct ifreq *ifr ) |
---|
| 127 | { |
---|
| 128 | int eno = 0; |
---|
| 129 | struct arpcom *ac = &self->arpcom; |
---|
| 130 | |
---|
| 131 | if ( add ) { |
---|
| 132 | eno = ether_addmulti( ifr, ac ); |
---|
| 133 | } else { |
---|
| 134 | eno = ether_delmulti( ifr, ac ); |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | if ( eno == ENETRESET ) { |
---|
| 138 | struct ether_multistep step; |
---|
| 139 | struct ether_multi *enm; |
---|
| 140 | unsigned int num_multi = 0; |
---|
| 141 | unsigned int index; |
---|
| 142 | |
---|
| 143 | ETHER_FIRST_MULTI( step, ac, enm ); |
---|
| 144 | |
---|
| 145 | while ( enm != NULL ) { |
---|
| 146 | /* Find out how many multicast addresses we have to handle */ |
---|
| 147 | uint64_t addrlo = 0; |
---|
| 148 | uint64_t addrhi = 0; |
---|
| 149 | |
---|
| 150 | memcpy( &addrlo, enm->enm_addrlo, ETHER_ADDR_LEN ); |
---|
| 151 | memcpy( &addrhi, enm->enm_addrhi, ETHER_ADDR_LEN ); |
---|
| 152 | num_multi += 1U + (uint32_t) ( addrhi - addrlo ); |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | if ( num_multi > DWMAC_1000_CORE_HASH_TABLE_SIZE ) { |
---|
| 156 | /* Too many addresses to be hashed, Use the |
---|
| 157 | * pass all multi option instead */ |
---|
| 158 | |
---|
| 159 | for ( index = 0; index < 8; ++index ) { |
---|
| 160 | self->macgrp->hash_table_reg[index] = 0xffffffff; |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_PM; |
---|
| 164 | } else if ( num_multi > 0 ) { |
---|
| 165 | uint32_t hash_shadow[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
---|
| 166 | ETHER_FIRST_MULTI( step, ac, enm ); |
---|
| 167 | |
---|
| 168 | while ( enm != NULL ) { |
---|
| 169 | uint64_t addrlo = 0; |
---|
| 170 | uint64_t addrhi = 0; |
---|
| 171 | |
---|
| 172 | memcpy( &addrlo, enm->enm_addrlo, ETHER_ADDR_LEN ); |
---|
| 173 | memcpy( &addrhi, enm->enm_addrhi, ETHER_ADDR_LEN ); |
---|
| 174 | |
---|
| 175 | while ( addrlo <= addrhi ) { |
---|
| 176 | /* XXX: ether_crc32_le() does not work, why? */ |
---|
| 177 | uint32_t crc = ether_crc32_be( (uint8_t *) &addrlo, ETHER_ADDR_LEN ); |
---|
| 178 | |
---|
| 179 | /* The upper 8 bits of the bit reversed 32 bit CRC are used for hash filtering. |
---|
| 180 | * The most significant bits determine the register to be used and the |
---|
| 181 | * least significant five bits determine which bit to be set within the register */ |
---|
| 182 | uint32_t index_reg = ( crc >> 29 ) & 0x7; |
---|
| 183 | uint32_t index_bit = ( crc >> 24 ) & 0x1f; |
---|
| 184 | |
---|
| 185 | hash_shadow[index_reg] |= 1U << index_bit; |
---|
| 186 | ++addrlo; |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | ETHER_NEXT_MULTI( step, enm ); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | for ( index = 0; index < 8; ++index ) { |
---|
| 193 | self->macgrp->hash_table_reg[index] = hash_shadow[index]; |
---|
| 194 | } |
---|
| 195 | |
---|
| 196 | /* Hash filter for multicast */ |
---|
| 197 | self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HMC; |
---|
| 198 | } else { |
---|
| 199 | /* Set all hash registers to accect to accept no multicast packets */ |
---|
| 200 | for ( index = 0; index < 8; ++index ) { |
---|
| 201 | self->macgrp->hash_table_reg[index] = 0x00000000; |
---|
| 202 | } |
---|
| 203 | |
---|
| 204 | /* Hash filter for multicast */ |
---|
| 205 | self->macgrp->mac_frame_filter |= MACGRP_MAC_FRAME_FILTER_HMC; |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | DWMAC_1000_CORE_PRINT_DBG( |
---|
| 209 | "Frame Filter reg: 0x%08x\n", |
---|
| 210 | self->macgrp->mac_frame_filter |
---|
| 211 | ); |
---|
| 212 | DWMAC_1000_CORE_PRINT_DBG( |
---|
| 213 | "Hash regs:\n" |
---|
| 214 | "0x%08x\n" |
---|
| 215 | "0x%08x\n" |
---|
| 216 | "0x%08x\n" |
---|
| 217 | "0x%08x\n" |
---|
| 218 | "0x%08x\n" |
---|
| 219 | "0x%08x\n" |
---|
| 220 | "0x%08x\n" |
---|
| 221 | "0x%08x\n", |
---|
| 222 | self->macgrp->hash_table_reg[0], |
---|
| 223 | self->macgrp->hash_table_reg[1], |
---|
| 224 | self->macgrp->hash_table_reg[2], |
---|
| 225 | self->macgrp->hash_table_reg[3], |
---|
| 226 | self->macgrp->hash_table_reg[4], |
---|
| 227 | self->macgrp->hash_table_reg[5], |
---|
| 228 | self->macgrp->hash_table_reg[6], |
---|
| 229 | self->macgrp->hash_table_reg[7] |
---|
| 230 | ); |
---|
| 231 | } |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | const dwmac_common_core_ops dwmac_core_ops_1000 = { |
---|
| 235 | .core_init = dwmac_1000_core_init, |
---|
| 236 | .set_hash_filter = dwmac_1000_core_set_hash_filter, |
---|
| 237 | .set_umac_addr = dwmac_1000_core_set_umac_addr, |
---|
| 238 | }; |
---|