1 /*
2  * Copyright 2014, General Dynamics C4 Systems
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #include <arch/machine/hardware.h>
8 
cleanByWSL(word_t wsl)9 static inline void cleanByWSL(word_t wsl)
10 {
11     asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r"(wsl));
12 }
13 
cleanInvalidateByWSL(word_t wsl)14 static inline void cleanInvalidateByWSL(word_t wsl)
15 {
16     asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r"(wsl));
17 }
18 
19 
readCLID(void)20 static inline word_t readCLID(void)
21 {
22     word_t CLID;
23     asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r"(CLID));
24     return CLID;
25 }
26 
27 #define LOUU(x)    (((x) >> 27)        & MASK(3))
28 #define LOC(x)     (((x) >> 24)        & MASK(3))
29 #define LOUIS(x)   (((x) >> 21)        & MASK(3))
30 #define CTYPE(x,n) (((x) >> (n*3))     & MASK(3))
31 
32 enum arm_cache_type {
33     ARMCacheNone = 0,
34     ARMCacheI =    1,
35     ARMCacheD =    2,
36     ARMCacheID =   3,
37     ARMCacheU =    4,
38 };
39 
40 
readCacheSize(int level,bool_t instruction)41 static inline word_t readCacheSize(int level, bool_t instruction)
42 {
43     word_t size_unique_name, csselr_old;
44     /* Save CSSELR */
45     asm volatile("mrc p15, 2, %0, c0, c0, 0" : "=r"(csselr_old));
46     /* Select cache level */
47     asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"((level << 1) | instruction));
48     /* Read 'size' */
49     asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r"(size_unique_name));
50     /* Restore CSSELR */
51     asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"(csselr_old));
52     return size_unique_name;
53 }
54 
55 /* Number of bits to index within a cache line.  The field is log2(nwords) - 2
56  * , and thus by adding 4 we get log2(nbytes). */
57 #define LINEBITS(s) (( (s)        & MASK(3))  + 4)
58 /* Associativity, field is assoc - 1. */
59 #define ASSOC(s)    ((((s) >> 3)  & MASK(10)) + 1)
60 /* Number of sets, field is nsets - 1. */
61 #define NSETS(s)    ((((s) >> 13) & MASK(15)) + 1)
62 
63 
clean_D_PoU(void)64 void clean_D_PoU(void)
65 {
66     int clid = readCLID();
67     int lou = LOUU(clid);
68     int l;
69 
70     for (l = 0; l < lou; l++) {
71         if (CTYPE(clid, l) > ARMCacheI) {
72             word_t s = readCacheSize(l, 0);
73             int lbits = LINEBITS(s);
74             int assoc = ASSOC(s);
75             int assoc_bits = wordBits - clzl(assoc - 1);
76             int nsets = NSETS(s);
77             int w;
78 
79             for (w = 0; w < assoc; w++) {
80                 int v;
81 
82                 for (v = 0; v < nsets; v++) {
83                     cleanByWSL((w << (32 - assoc_bits)) |
84                                (v << lbits) | (l << 1));
85                 }
86             }
87         }
88     }
89 }
90 
cleanInvalidate_D_by_level(int l)91 static inline void cleanInvalidate_D_by_level(int l)
92 {
93     word_t s = readCacheSize(l, 0);
94     int lbits = LINEBITS(s);
95     int assoc = ASSOC(s);
96     int assoc_bits = wordBits - clzl(assoc - 1);
97     int nsets = NSETS(s);
98     int w;
99 
100     for (w = 0; w < assoc; w++) {
101         int v;
102 
103         for (v = 0; v < nsets; v++) {
104             cleanInvalidateByWSL((w << (32 - assoc_bits)) |
105                                  (v << lbits) | (l << 1));
106         }
107     }
108 }
109 
cleanInvalidate_D_PoC(void)110 void cleanInvalidate_D_PoC(void)
111 {
112     int clid = readCLID();
113     int loc = LOC(clid);
114     int l;
115 
116     for (l = 0; l < loc; l++) {
117         if (CTYPE(clid, l) > ARMCacheI) {
118             cleanInvalidate_D_by_level(l);
119         }
120     }
121 }
122 
cleanInvalidate_L1D(void)123 void cleanInvalidate_L1D(void)
124 {
125     cleanInvalidate_D_by_level(0);
126 }
127