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

4.11
Last change on this file since fd6cd36 was fd6cd36, checked in by Pavel Pisa <pisa@…>, on 07/03/16 at 23:30:05

bsps/arm: basic on core cache support changed to use l1 functions.

The basic data and instruction rage functions should be compatible
for all ARMv4,5,6,7 functions. On the other hand, some functions
are not portable, for example arm_cp15_data_cache_test_and_clean()
and arm_cp15_data_cache_invalidate() for all versions and there
has to be specialized version for newer cores.
arm_cache_l1_properties_for_level uses CCSIDR which is not present
on older chips.

Actual version is only experimental, needs more changes
and problem has been found on RPi1 with dlopen so there seems
to be real problem.

Updates #2783
Updates #2782

  • Property mode set to 100644
File size: 10.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 <bsp.h>
29#include <libcpu/arm-cp15.h>
30
31#ifdef __cplusplus
32extern "C" {
33#endif /* __cplusplus */
34
35/* These two defines also ensure that the rtems_cache_* functions have bodies */
36#define ARM_CACHE_L1_CPU_DATA_ALIGNMENT 32
37#define ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT 32
38#define ARM_CACHE_L1_CPU_SUPPORT_PROVIDES_RANGE_FUNCTIONS
39
40#define ARM_CACHE_L1_CSS_ID_DATA \
41          (ARM_CP15_CACHE_CSS_ID_DATA | ARM_CP15_CACHE_CSS_LEVEL(0))
42#define ARM_CACHE_L1_CSS_ID_INSTRUCTION \
43          (ARM_CP15_CACHE_CSS_ID_INSTRUCTION | ARM_CP15_CACHE_CSS_LEVEL(0))
44#define ARM_CACHE_L1_DATA_LINE_MASK ( ARM_CACHE_L1_CPU_DATA_ALIGNMENT - 1 )
45#define ARM_CACHE_L1_INSTRUCTION_LINE_MASK \
46  ( ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT \
47    - 1 )
48
49/* Errata Handlers */
50static void arm_cache_l1_errata_764369_handler( void )
51{
52#ifdef RTEMS_SMP
53  _ARM_Data_synchronization_barrier();
54#endif
55}
56
57/*
58 * @param l1LineSize      Number of bytes in cache line expressed as power of
59 *                        2 value
60 * @param l1Associativity Associativity of cache. The associativity does not
61 *                        have to be a power of 2.
62 * qparam liNumSets       Number of sets in cache
63 * */
64
65static inline void arm_cache_l1_properties_for_level(
66  uint32_t *l1LineSize,
67  uint32_t *l1Associativity,
68  uint32_t *l1NumSets,
69  uint32_t level_and_inst_dat
70)
71{
72  uint32_t ccsidr;
73
74  ccsidr = arm_cp15_get_cache_size_id_for_level(level_and_inst_dat);
75
76  /* Cache line size in words + 2 -> bytes) */
77  *l1LineSize      = arm_ccsidr_get_line_power(ccsidr);
78  /* Number of Ways */
79  *l1Associativity = arm_ccsidr_get_associativity(ccsidr);
80  /* Number of Sets */
81  *l1NumSets       = arm_ccsidr_get_num_sets(ccsidr);
82}
83
84/*
85 * @param log_2_line_bytes The number of bytes per cache line expressed in log2
86 * @param associativity    The associativity of the cache beeing operated
87 * @param cache_level_idx  The level of the cache beeing operated minus 1 e.g 0
88 *                         for cache level 1
89 * @param set              Number of the set to operate on
90 * @param way              Number of the way to operate on
91 * */
92
93static inline uint32_t arm_cache_l1_get_set_way_param(
94  const uint32_t log_2_line_bytes,
95  const uint32_t associativity,
96  const uint32_t cache_level_idx,
97  const uint32_t set,
98  const uint32_t way )
99{
100  uint32_t way_shift = __builtin_clz( associativity - 1 );
101
102
103  return ( 0
104           | ( way
105    << way_shift ) | ( set << log_2_line_bytes ) | ( cache_level_idx << 1 ) );
106}
107
108static inline void arm_cache_l1_flush_1_data_line( const void *d_addr )
109{
110  /* Flush the Data cache */
111  arm_cp15_data_cache_clean_and_invalidate_line( d_addr );
112
113  /* Wait for L1 flush to complete */
114  _ARM_Data_synchronization_barrier();
115}
116
117static inline void arm_cache_l1_flush_entire_data( void )
118{
119  uint32_t l1LineSize, l1Associativity, l1NumSets;
120  uint32_t s, w;
121  uint32_t set_way_param;
122
123  /* ensure ordering with previous memory accesses */
124  _ARM_Data_memory_barrier();
125
126  /* Get the L1 cache properties */
127  arm_cache_l1_properties_for_level( &l1LineSize,
128                    &l1Associativity, &l1NumSets,
129                    ARM_CACHE_L1_CSS_ID_DATA);
130
131  for ( w = 0; w < l1Associativity; ++w ) {
132    for ( s = 0; s < l1NumSets; ++s ) {
133      set_way_param = arm_cache_l1_get_set_way_param(
134        l1LineSize,
135        l1Associativity,
136        0,
137        s,
138        w
139        );
140      arm_cp15_data_cache_clean_line_by_set_and_way( set_way_param );
141    }
142  }
143
144  /* Wait for L1 flush to complete */
145  _ARM_Data_synchronization_barrier();
146}
147
148static inline void arm_cache_l1_invalidate_entire_data( void )
149{
150  uint32_t l1LineSize, l1Associativity, l1NumSets;
151  uint32_t s, w;
152  uint32_t set_way_param;
153
154  /* ensure ordering with previous memory accesses */
155  _ARM_Data_memory_barrier();
156
157  /* Get the L1 cache properties */
158  arm_cache_l1_properties_for_level( &l1LineSize,
159                    &l1Associativity, &l1NumSets,
160                    ARM_CACHE_L1_CSS_ID_DATA);
161
162  for ( w = 0; w < l1Associativity; ++w ) {
163    for ( s = 0; s < l1NumSets; ++s ) {
164      set_way_param = arm_cache_l1_get_set_way_param(
165        l1LineSize,
166        l1Associativity,
167        0,
168        s,
169        w
170        );
171      arm_cp15_data_cache_invalidate_line_by_set_and_way( set_way_param );
172    }
173  }
174
175  /* Wait for L1 invalidate to complete */
176  _ARM_Data_synchronization_barrier();
177}
178
179static inline void arm_cache_l1_clean_and_invalidate_entire_data( void )
180{
181  uint32_t l1LineSize, l1Associativity, l1NumSets;
182  uint32_t s, w;
183  uint32_t set_way_param;
184
185  /* ensure ordering with previous memory accesses */
186  _ARM_Data_memory_barrier();
187
188
189  /* Get the L1 cache properties */
190  arm_cache_l1_properties_for_level( &l1LineSize,
191                    &l1Associativity, &l1NumSets,
192                    ARM_CACHE_L1_CSS_ID_DATA);
193
194  for ( w = 0; w < l1Associativity; ++w ) {
195    for ( s = 0; s < l1NumSets; ++s ) {
196      set_way_param = arm_cache_l1_get_set_way_param(
197        l1LineSize,
198        l1Associativity,
199        0,
200        s,
201        w
202        );
203      arm_cp15_data_cache_clean_and_invalidate_line_by_set_and_way(
204        set_way_param );
205    }
206  }
207
208  /* Wait for L1 invalidate to complete */
209  _ARM_Data_synchronization_barrier();
210}
211
212static inline void arm_cache_l1_flush_data_range(
213  const void *d_addr,
214  size_t      n_bytes
215)
216{
217  if ( n_bytes != 0 ) {
218    uint32_t       adx       = (uint32_t) d_addr
219                               & ~ARM_CACHE_L1_DATA_LINE_MASK;
220    const uint32_t ADDR_LAST =
221      (uint32_t)( (size_t) d_addr + n_bytes - 1 );
222
223    arm_cache_l1_errata_764369_handler();
224
225    for (; adx <= ADDR_LAST; adx += ARM_CACHE_L1_CPU_DATA_ALIGNMENT ) {
226      /* Store and invalidate the Data cache line */
227      arm_cp15_data_cache_clean_and_invalidate_line( (void*)adx );
228    }
229    /* Wait for L1 store to complete */
230    _ARM_Data_synchronization_barrier();
231  }
232}
233
234
235static inline void arm_cache_l1_invalidate_1_data_line(
236  const void *d_addr )
237{
238  /* Invalidate the data cache line */
239  arm_cp15_data_cache_invalidate_line( d_addr );
240
241  /* Wait for L1 invalidate to complete */
242  _ARM_Data_synchronization_barrier();
243}
244
245static inline void arm_cache_l1_freeze_data( void )
246{
247  /* To be implemented as needed, if supported by hardware at all */
248}
249
250static inline void arm_cache_l1_unfreeze_data( void )
251{
252  /* To be implemented as needed, if supported by hardware at all */
253}
254
255static inline void arm_cache_l1_invalidate_1_instruction_line(
256  const void *i_addr )
257{
258  /* Invalidate the Instruction cache line */
259  arm_cp15_instruction_cache_invalidate_line( i_addr );
260
261  /* Wait for L1 invalidate to complete */
262  _ARM_Data_synchronization_barrier();
263}
264
265static inline void arm_cache_l1_invalidate_data_range(
266  const void *d_addr,
267  size_t      n_bytes
268)
269{
270  if ( n_bytes != 0 ) {
271    uint32_t       adx = (uint32_t) d_addr
272                         & ~ARM_CACHE_L1_DATA_LINE_MASK;
273    const uint32_t end =
274      (uint32_t)( (size_t)d_addr + n_bytes -1);
275
276    arm_cache_l1_errata_764369_handler();
277   
278    /* Back starting address up to start of a line and invalidate until end */
279    for (;
280         adx <= end;
281         adx += ARM_CACHE_L1_CPU_DATA_ALIGNMENT ) {
282        /* Invalidate the Instruction cache line */
283        arm_cp15_data_cache_invalidate_line( (void*)adx );
284    }
285    /* Wait for L1 invalidate to complete */
286    _ARM_Data_synchronization_barrier();
287  }
288}
289
290static inline void arm_cache_l1_invalidate_instruction_range(
291  const void *i_addr,
292  size_t      n_bytes
293)
294{
295  if ( n_bytes != 0 ) {
296    uint32_t       adx = (uint32_t) i_addr
297                         & ~ARM_CACHE_L1_INSTRUCTION_LINE_MASK;
298    const uint32_t end =
299      (uint32_t)( (size_t)i_addr + n_bytes -1);
300
301    arm_cache_l1_errata_764369_handler();
302
303    /* Back starting address up to start of a line and invalidate until end */
304    for (;
305         adx <= end;
306         adx += ARM_CACHE_L1_CPU_INSTRUCTION_ALIGNMENT ) {
307        /* Invalidate the Instruction cache line */
308        arm_cp15_instruction_cache_invalidate_line( (void*)adx );
309    }
310    /* Wait for L1 invalidate to complete */
311    _ARM_Data_synchronization_barrier();
312  }
313}
314
315static inline void arm_cache_l1_invalidate_entire_instruction( void )
316{
317  uint32_t ctrl = arm_cp15_get_control();
318
319
320  #ifdef RTEMS_SMP
321
322  /* invalidate I-cache inner shareable */
323  arm_cp15_instruction_cache_inner_shareable_invalidate_all();
324
325  /* I+BTB cache invalidate */
326  arm_cp15_instruction_cache_invalidate();
327  #else /* RTEMS_SMP */
328  /* I+BTB cache invalidate */
329  arm_cp15_instruction_cache_invalidate();
330  #endif /* RTEMS_SMP */
331
332  if ( ( ctrl & ARM_CP15_CTRL_Z ) == 0 ) {
333    arm_cp15_branch_predictor_inner_shareable_invalidate_all();
334    arm_cp15_branch_predictor_invalidate_all();
335  }
336}
337
338static inline void arm_cache_l1_freeze_instruction( void )
339{
340  /* To be implemented as needed, if supported by hardware at all */
341}
342
343static inline void arm_cache_l1_unfreeze_instruction( void )
344{
345  /* To be implemented as needed, if supported by hardware at all */
346}
347
348static inline void arm_cache_l1_disable_data( void )
349{
350  /* Clean and invalidate the Data cache */
351  arm_cache_l1_flush_entire_data();
352
353  /* Disable the Data cache */
354  arm_cp15_set_control( arm_cp15_get_control() & ~ARM_CP15_CTRL_C );
355}
356
357static inline void arm_cache_l1_disable_instruction( void )
358{
359  /* Synchronize the processor */
360  _ARM_Data_synchronization_barrier();
361
362  /* Invalidate the Instruction cache */
363  arm_cache_l1_invalidate_entire_instruction();
364
365  /* Disable the Instruction cache */
366  arm_cp15_set_control( arm_cp15_get_control() & ~ARM_CP15_CTRL_I );
367}
368
369static inline size_t arm_cache_l1_get_data_cache_size( void )
370{
371  size_t   size;
372  uint32_t line_size     = 0;
373  uint32_t associativity = 0;
374  uint32_t num_sets      = 0;
375
376  arm_cache_l1_properties_for_level( &line_size,
377                    &associativity, &num_sets,
378                    ARM_CACHE_L1_CSS_ID_DATA);
379
380  size = (1 << line_size) * associativity * num_sets;
381
382  return size;
383}
384
385static inline size_t arm_cache_l1_get_instruction_cache_size( void )
386{
387  size_t   size;
388  uint32_t line_size     = 0;
389  uint32_t associativity = 0;
390  uint32_t num_sets      = 0;
391
392  arm_cache_l1_properties_for_level( &line_size,
393                    &associativity, &num_sets,
394                    ARM_CACHE_L1_CSS_ID_INSTRUCTION);
395
396  size = (1 << line_size) * associativity * num_sets;
397
398  return size;
399}
400
401#ifdef __cplusplus
402}
403#endif /* __cplusplus */
404
405#endif /* LIBBSP_ARM_SHARED_CACHE_L1_H */
Note: See TracBrowser for help on using the repository browser.