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