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

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

libchip: Add dwmac 10/100/1000 network driver

  • Property mode set to 100644
File size: 6.7 KB
Line 
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
45static 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
63static 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
81static 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
111static 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
123static 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
234const 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};
Note: See TracBrowser for help on using the repository browser.