source: rtems/c/src/lib/libbsp/arm/shared/include/arm-cache-l1.h @ 924b47a

4.115
Last change on this file since 924b47a was 924b47a, checked in by Ralf Kirchner <ralf.kirchner@…>, on 04/17/14 at 07:21:36

bsp/arm: Cleanup L1 cache

  • Property mode set to 100644
File size: 12.8 KB
Line 
1/**
2 * @file arm-cache-l1.h
3 *
4 * @ingroup arm_shared
5 *
6 * @brief Level 1 Cache definitions and functions.
7 *
8 * This file implements handling for the ARM Level 1 cache controller
9 */
10
11/*
12 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
13 *
14 *  embedded brains GmbH
15 *  Dornierstr. 4
16 *  82178 Puchheim
17 *  Germany
18 *  <rtems@embedded-brains.de>
19 *
20 * The license and distribution terms for this file may be
21 * found in the file LICENSE in this distribution or at
22 * http://www.rtems.org/license/LICENSE.
23 */
24
25#ifndef LIBBSP_ARM_SHARED_CACHE_L1_H
26#define LIBBSP_ARM_SHARED_CACHE_L1_H
27
28#include <assert.h>
29#include <bsp.h>
30#include <libcpu/arm-cp15.h>
31
32#ifdef __cplusplus
33extern "C" {
34#endif /* __cplusplus */
35
36/* These two defines also ensure that the rtems_cache_* functions have bodies */
37#define ARM_CACHE_L1_CPU_DATA_ALIGNMENT 32
38#define ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT 32
39#define ARM_CACHE_L1_CPU_SUPPORT_PROVIDES_RANGE_FUNCTIONS
40
41#define ARM_CACHE_L1_CSS_ID_DATA 0
42#define ARM_CACHE_L1_CSS_ID_INSTRUCTION 1
43#define ARM_CACHE_L1_DATA_LINE_MASK ( ARM_CACHE_L1_CPU_DATA_ALIGNMENT - 1 )
44#define ARM_CACHE_L1_INSTRUCTION_LINE_MASK \
45  ( ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT \
46    - 1 )
47
48/* Errata Handlers */
49#if ( defined( RTEMS_SMP ) )
50  #define ARM_CACHE_L1_ERRATA_764369_HANDLER()                 \
51    if( arm_errata_is_applicable_processor_errata_764369() ) { \
52      _ARM_Data_synchronization_barrier();                     \
53    }                                           
54#else /* #if ( defined( RTEMS_SMP ) ) */
55  #define ARM_CACHE_L1_ERRATA_764369_HANDLER()
56#endif /* #if ( defined( RTEMS_SMP ) ) */
57
58   
59static void arm_cache_l1_select( const uint32_t selection )
60{
61  /* select current cache level in cssr */
62  arm_cp15_set_cache_size_selection( selection );
63
64  /* isb to sych the new cssr&csidr */
65  _ARM_Instruction_synchronization_barrier();
66}
67
68/*
69 * @param l1LineSize      Number of bytes in cache line expressed as power of
70 *                        2 value
71 * @param l1Associativity Associativity of cache. The associativity does not
72 *                        have to be a power of 2.
73 * qparam liNumSets       Number of sets in cache
74 * */
75
76static inline void arm_cache_l1_properties(
77  uint32_t *l1LineSize,
78  uint32_t *l1Associativity,
79  uint32_t *l1NumSets )
80{
81  uint32_t id;
82
83  _ARM_Instruction_synchronization_barrier();
84  id               = arm_cp15_get_cache_size_id();
85
86  /* Cache line size in words + 2 -> bytes) */
87  *l1LineSize      = ( id & 0x0007U ) + 2 + 2;
88  /* Number of Ways */
89  *l1Associativity = ( ( id >> 3 ) & 0x03ffU ) + 1;
90  /* Number of Sets */
91  *l1NumSets       = ( ( id >> 13 ) & 0x7fffU ) + 1;
92}
93
94/*
95 * @param log_2_line_bytes The number of bytes per cache line expressed in log2
96 * @param associativity    The associativity of the cache beeing operated
97 * @param cache_level_idx  The level of the cache beeing operated minus 1 e.g 0
98 *                         for cache level 1
99 * @param set              Number of the set to operate on
100 * @param way              Number of the way to operate on
101 * */
102
103static inline uint32_t arm_cache_l1_get_set_way_param(
104  const uint32_t log_2_line_bytes,
105  const uint32_t associativity,
106  const uint32_t cache_level_idx,
107  const uint32_t set,
108  const uint32_t way )
109{
110  uint32_t way_shift = __builtin_clz( associativity - 1 );
111
112
113  return ( 0
114           | ( way
115    << way_shift ) | ( set << log_2_line_bytes ) | ( cache_level_idx << 1 ) );
116}
117
118static inline void arm_cache_l1_flush_1_data_line( const void *d_addr )
119{
120  /* Flush the Data cache */
121  arm_cp15_data_cache_clean_and_invalidate_line( d_addr );
122
123  /* Wait for L1 flush to complete */
124  _ARM_Data_synchronization_barrier();
125}
126
127static inline void arm_cache_l1_flush_entire_data( void )
128{
129  uint32_t              l1LineSize, l1Associativity, l1NumSets;
130  uint32_t              s, w;
131  uint32_t              set_way_param;
132  rtems_interrupt_level level;
133
134
135  /* ensure ordering with previous memory accesses */
136  _ARM_Data_memory_barrier();
137
138  /* make cssr&csidr read atomic */
139  rtems_interrupt_disable( level );
140
141  /* Get the L1 cache properties */
142  arm_cache_l1_properties( &l1LineSize, &l1Associativity,
143                                     &l1NumSets );
144  rtems_interrupt_enable( level );
145
146  for ( w = 0; w < l1Associativity; ++w ) {
147    for ( s = 0; s < l1NumSets; ++s ) {
148      set_way_param = arm_cache_l1_get_set_way_param(
149        l1LineSize,
150        l1Associativity,
151        0,
152        s,
153        w
154        );
155      arm_cp15_data_cache_clean_line_by_set_and_way( set_way_param );
156    }
157  }
158
159  /* Wait for L1 flush to complete */
160  _ARM_Data_synchronization_barrier();
161}
162
163static inline void arm_cache_l1_invalidate_entire_data( void )
164{
165  uint32_t              l1LineSize, l1Associativity, l1NumSets;
166  uint32_t              s, w;
167  uint32_t              set_way_param;
168  rtems_interrupt_level level;
169
170
171  /* ensure ordering with previous memory accesses */
172  _ARM_Data_memory_barrier();
173
174  /* make cssr&csidr read atomic */
175  rtems_interrupt_disable( level );
176
177  /* Get the L1 cache properties */
178  arm_cache_l1_properties( &l1LineSize, &l1Associativity,
179                                     &l1NumSets );
180  rtems_interrupt_enable( level );
181
182  for ( w = 0; w < l1Associativity; ++w ) {
183    for ( s = 0; s < l1NumSets; ++s ) {
184      set_way_param = arm_cache_l1_get_set_way_param(
185        l1LineSize,
186        l1Associativity,
187        0,
188        s,
189        w
190        );
191      arm_cp15_data_cache_invalidate_line_by_set_and_way( set_way_param );
192    }
193  }
194
195  /* Wait for L1 invalidate to complete */
196  _ARM_Data_synchronization_barrier();
197}
198
199static inline void arm_cache_l1_clean_and_invalidate_entire_data( void )
200{
201  uint32_t              l1LineSize, l1Associativity, l1NumSets;
202  uint32_t              s, w;
203  uint32_t              set_way_param;
204  rtems_interrupt_level level;
205
206
207  /* ensure ordering with previous memory accesses */
208  _ARM_Data_memory_barrier();
209
210  /* make cssr&csidr read atomic */
211  rtems_interrupt_disable( level );
212
213  /* Get the L1 cache properties */
214  arm_cache_l1_properties( &l1LineSize, &l1Associativity,
215                                     &l1NumSets );
216  rtems_interrupt_enable( level );
217
218  for ( w = 0; w < l1Associativity; ++w ) {
219    for ( s = 0; s < l1NumSets; ++s ) {
220      set_way_param = arm_cache_l1_get_set_way_param(
221        l1LineSize,
222        l1Associativity,
223        0,
224        s,
225        w
226        );
227      arm_cp15_data_cache_clean_and_invalidate_line_by_set_and_way(
228        set_way_param );
229    }
230  }
231
232  /* Wait for L1 invalidate to complete */
233  _ARM_Data_synchronization_barrier();
234}
235
236static inline void arm_cache_l1_store_data( const void *d_addr )
237{
238  /* Store the Data cache line */
239  arm_cp15_data_cache_clean_line( d_addr );
240
241  /* Wait for L1 store to complete */
242  _ARM_Data_synchronization_barrier();
243}
244
245static inline void arm_cache_l1_flush_data_range(
246  const void *d_addr,
247  size_t      n_bytes
248)
249{
250  if ( n_bytes != 0 ) {
251    uint32_t       adx       = (uint32_t) d_addr
252                               & ~ARM_CACHE_L1_DATA_LINE_MASK;
253    const uint32_t ADDR_LAST =
254      ( (uint32_t) d_addr + n_bytes - 1 ) & ~ARM_CACHE_L1_DATA_LINE_MASK;
255     
256    ARM_CACHE_L1_ERRATA_764369_HANDLER();
257
258    for (; adx <= ADDR_LAST; adx += ARM_CACHE_L1_CPU_DATA_ALIGNMENT ) {
259      /* Store the Data cache line */
260      arm_cp15_data_cache_clean_line( (void*)adx );
261    }
262    /* Wait for L1 store to complete */
263    _ARM_Data_synchronization_barrier();
264  }
265}
266
267
268static inline void arm_cache_l1_invalidate_1_data_line(
269  const void *d_addr )
270{
271  /* Invalidate the data cache line */
272  arm_cp15_data_cache_invalidate_line( d_addr );
273
274  /* Wait for L1 invalidate to complete */
275  _ARM_Data_synchronization_barrier();
276}
277
278static inline void arm_cache_l1_freeze_data( void )
279{
280  /* To be implemented as needed, if supported by hardware at all */
281}
282
283static inline void arm_cache_l1_unfreeze_data( void )
284{
285  /* To be implemented as needed, if supported by hardware at all */
286}
287
288static inline void arm_cache_l1_invalidate_1_instruction_line(
289  const void *i_addr )
290{
291  /* Invalidate the Instruction cache line */
292  arm_cp15_instruction_cache_invalidate_line( i_addr );
293
294  /* Wait for L1 invalidate to complete */
295  _ARM_Data_synchronization_barrier();
296}
297
298static inline void arm_cache_l1_invalidate_data_range(
299  const void *d_addr,
300  size_t      n_bytes
301)
302{
303  if ( n_bytes != 0 ) {
304    uint32_t       adx = (uint32_t) d_addr
305                         & ~ARM_CACHE_L1_DATA_LINE_MASK;
306    const uint32_t end =
307      ( adx + n_bytes ) & ~ARM_CACHE_L1_DATA_LINE_MASK;
308
309    ARM_CACHE_L1_ERRATA_764369_HANDLER();
310   
311    /* Back starting address up to start of a line and invalidate until end */
312    for (;
313         adx < end;
314         adx += ARM_CACHE_L1_CPU_DATA_ALIGNMENT ) {
315        /* Invalidate the Instruction cache line */
316        arm_cp15_data_cache_invalidate_line( (void*)adx );
317    }
318    /* Wait for L1 invalidate to complete */
319    _ARM_Data_synchronization_barrier();
320  }
321}
322
323static inline void arm_cache_l1_invalidate_instruction_range(
324  const void *i_addr,
325  size_t      n_bytes
326)
327{
328  if ( n_bytes != 0 ) {
329    uint32_t       adx = (uint32_t) i_addr
330                         & ~ARM_CACHE_L1_INSTRUCTION_LINE_MASK;
331    const uint32_t end =
332      ( adx + n_bytes ) & ~ARM_CACHE_L1_INSTRUCTION_LINE_MASK;
333
334    arm_cache_l1_select( ARM_CACHE_L1_CSS_ID_INSTRUCTION );
335
336    ARM_CACHE_L1_ERRATA_764369_HANDLER();
337
338    /* Back starting address up to start of a line and invalidate until end */
339    for (;
340         adx < end;
341         adx += ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT ) {
342        /* Invalidate the Instruction cache line */
343        arm_cp15_instruction_cache_invalidate_line( (void*)adx );
344    }
345    /* Wait for L1 invalidate to complete */
346    _ARM_Data_synchronization_barrier();
347
348    arm_cache_l1_select( ARM_CACHE_L1_CSS_ID_DATA );
349  }
350}
351
352static inline void arm_cache_l1_invalidate_entire_instruction( void )
353{
354  uint32_t ctrl = arm_cp15_get_control();
355
356
357  #ifdef RTEMS_SMP
358
359  /* invalidate I-cache inner shareable */
360  arm_cp15_instruction_cache_inner_shareable_invalidate_all();
361
362  /* I+BTB cache invalidate */
363  arm_cp15_instruction_cache_invalidate();
364  #else /* RTEMS_SMP */
365  /* I+BTB cache invalidate */
366  arm_cp15_instruction_cache_invalidate();
367  #endif /* RTEMS_SMP */
368
369  if ( ( ctrl & ARM_CP15_CTRL_Z ) == 0 ) {
370    arm_cp15_branch_predictor_inner_shareable_invalidate_all();
371    arm_cp15_branch_predictor_invalidate_all();
372  }
373}
374
375static inline void arm_cache_l1_freeze_instruction( void )
376{
377  /* To be implemented as needed, if supported by hardware at all */
378}
379
380static inline void arm_cache_l1_unfreeze_instruction( void )
381{
382  /* To be implemented as needed, if supported by hardware at all */
383}
384
385static inline void arm_cache_l1_enable_data( void )
386{
387  rtems_interrupt_level level;
388  uint32_t              ctrl;
389
390
391  arm_cache_l1_select( ARM_CACHE_L1_CSS_ID_DATA );
392
393  assert( ARM_CACHE_L1_CPU_DATA_ALIGNMENT == arm_cp15_get_data_cache_line_size() );
394
395  rtems_interrupt_disable( level );
396  ctrl = arm_cp15_get_control();
397  rtems_interrupt_enable( level );
398
399  /* Only enable the cache if it is disabled */
400  if ( !( ctrl & ARM_CP15_CTRL_C ) ) {
401    /* Clean and invalidate the Data cache */
402    arm_cache_l1_invalidate_entire_data();
403
404    /* Enable the Data cache */
405    ctrl |= ARM_CP15_CTRL_C;
406
407    rtems_interrupt_disable( level );
408    arm_cp15_set_control( ctrl );
409    rtems_interrupt_enable( level );
410  }
411}
412
413static inline void arm_cache_l1_disable_data( void )
414{
415  rtems_interrupt_level level;
416
417
418  /* Clean and invalidate the Data cache */
419  arm_cache_l1_flush_entire_data();
420
421  rtems_interrupt_disable( level );
422
423  /* Disable the Data cache */
424  arm_cp15_set_control( arm_cp15_get_control() & ~ARM_CP15_CTRL_C );
425
426  rtems_interrupt_enable( level );
427}
428
429static inline void arm_cache_l1_disable_instruction( void )
430{
431  rtems_interrupt_level level;
432
433
434  rtems_interrupt_disable( level );
435
436  /* Synchronize the processor */
437  _ARM_Data_synchronization_barrier();
438
439  /* Invalidate the Instruction cache */
440  arm_cache_l1_invalidate_entire_instruction();
441
442  /* Disable the Instruction cache */
443  arm_cp15_set_control( arm_cp15_get_control() & ~ARM_CP15_CTRL_I );
444
445  rtems_interrupt_enable( level );
446}
447
448static inline void arm_cache_l1_enable_instruction( void )
449{
450  rtems_interrupt_level level;
451  uint32_t              ctrl;
452
453
454  arm_cache_l1_select( ARM_CACHE_L1_CSS_ID_INSTRUCTION );
455
456  assert( ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT
457          == arm_cp15_get_data_cache_line_size() );
458
459  rtems_interrupt_disable( level );
460
461  /* Enable Instruction cache only if it is disabled */
462  ctrl = arm_cp15_get_control();
463
464  if ( !( ctrl & ARM_CP15_CTRL_I ) ) {
465    /* Invalidate the Instruction cache */
466    arm_cache_l1_invalidate_entire_instruction();
467
468    /* Enable the Instruction cache */
469    ctrl |= ARM_CP15_CTRL_I;
470
471    arm_cp15_set_control( ctrl );
472  }
473
474  rtems_interrupt_enable( level );
475
476  arm_cache_l1_select( ARM_CACHE_L1_CSS_ID_DATA );
477}
478
479#ifdef __cplusplus
480}
481#endif /* __cplusplus */
482
483#endif /* LIBBSP_ARM_SHARED_CACHE_L1_H */
Note: See TracBrowser for help on using the repository browser.