GNU Linux-libre 4.14.265-gnu1
[releases.git] / arch / metag / mm / l2cache.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/kernel.h>
4 #include <linux/delay.h>
5
6 #include <asm/l2cache.h>
7 #include <asm/metag_isa.h>
8
9 /* If non-0, then initialise the L2 cache */
10 static int l2cache_init = 1;
11 /* If non-0, then initialise the L2 cache prefetch */
12 static int l2cache_init_pf = 1;
13
14 int l2c_pfenable;
15
16 static volatile u32 l2c_testdata[16] __initdata __aligned(64);
17
18 static int __init parse_l2cache(char *p)
19 {
20         char *cp = p;
21
22         if (get_option(&cp, &l2cache_init) != 1) {
23                 pr_err("Bad l2cache parameter (%s)\n", p);
24                 return 1;
25         }
26         return 0;
27 }
28 early_param("l2cache", parse_l2cache);
29
30 static int __init parse_l2cache_pf(char *p)
31 {
32         char *cp = p;
33
34         if (get_option(&cp, &l2cache_init_pf) != 1) {
35                 pr_err("Bad l2cache_pf parameter (%s)\n", p);
36                 return 1;
37         }
38         return 0;
39 }
40 early_param("l2cache_pf", parse_l2cache_pf);
41
42 static int __init meta_l2c_setup(void)
43 {
44         /*
45          * If the L2 cache isn't even present, don't do anything, but say so in
46          * the log.
47          */
48         if (!meta_l2c_is_present()) {
49                 pr_info("L2 Cache: Not present\n");
50                 return 0;
51         }
52
53         /*
54          * Check whether the line size is recognised.
55          */
56         if (!meta_l2c_linesize()) {
57                 pr_warn_once("L2 Cache: unknown line size id (config=0x%08x)\n",
58                              meta_l2c_config());
59         }
60
61         /*
62          * Initialise state.
63          */
64         l2c_pfenable = _meta_l2c_pf_is_enabled();
65
66         /*
67          * Enable the L2 cache and print to log whether it was already enabled
68          * by the bootloader.
69          */
70         if (l2cache_init) {
71                 pr_info("L2 Cache: Enabling... ");
72                 if (meta_l2c_enable())
73                         pr_cont("already enabled\n");
74                 else
75                         pr_cont("done\n");
76         } else {
77                 pr_info("L2 Cache: Not enabling\n");
78         }
79
80         /*
81          * Enable L2 cache prefetch.
82          */
83         if (l2cache_init_pf) {
84                 pr_info("L2 Cache: Enabling prefetch... ");
85                 if (meta_l2c_pf_enable(1))
86                         pr_cont("already enabled\n");
87                 else
88                         pr_cont("done\n");
89         } else {
90                 pr_info("L2 Cache: Not enabling prefetch\n");
91         }
92
93         return 0;
94 }
95 core_initcall(meta_l2c_setup);
96
97 int meta_l2c_disable(void)
98 {
99         unsigned long flags;
100         int en;
101
102         if (!meta_l2c_is_present())
103                 return 1;
104
105         /*
106          * Prevent other threads writing during the writeback, otherwise the
107          * writes will get "lost" when the L2 is disabled.
108          */
109         __global_lock2(flags);
110         en = meta_l2c_is_enabled();
111         if (likely(en)) {
112                 _meta_l2c_pf_enable(0);
113                 wr_fence();
114                 _meta_l2c_purge();
115                 _meta_l2c_enable(0);
116         }
117         __global_unlock2(flags);
118
119         return !en;
120 }
121
122 int meta_l2c_enable(void)
123 {
124         unsigned long flags;
125         int en;
126
127         if (!meta_l2c_is_present())
128                 return 0;
129
130         /*
131          * Init (clearing the L2) can happen while the L2 is disabled, so other
132          * threads are safe to continue executing, however we must not init the
133          * cache if it's already enabled (dirty lines would be discarded), so
134          * this operation should still be atomic with other threads.
135          */
136         __global_lock1(flags);
137         en = meta_l2c_is_enabled();
138         if (likely(!en)) {
139                 _meta_l2c_init();
140                 _meta_l2c_enable(1);
141                 _meta_l2c_pf_enable(l2c_pfenable);
142         }
143         __global_unlock1(flags);
144
145         return en;
146 }
147
148 int meta_l2c_pf_enable(int pfenable)
149 {
150         unsigned long flags;
151         int en = l2c_pfenable;
152
153         if (!meta_l2c_is_present())
154                 return 0;
155
156         /*
157          * We read modify write the enable register, so this operation must be
158          * atomic with other threads.
159          */
160         __global_lock1(flags);
161         en = l2c_pfenable;
162         l2c_pfenable = pfenable;
163         if (meta_l2c_is_enabled())
164                 _meta_l2c_pf_enable(pfenable);
165         __global_unlock1(flags);
166
167         return en;
168 }
169
170 int meta_l2c_flush(void)
171 {
172         unsigned long flags;
173         int en;
174
175         /*
176          * Prevent other threads writing during the writeback. This also
177          * involves read modify writes.
178          */
179         __global_lock2(flags);
180         en = meta_l2c_is_enabled();
181         if (likely(en)) {
182                 _meta_l2c_pf_enable(0);
183                 wr_fence();
184                 _meta_l2c_purge();
185                 _meta_l2c_enable(0);
186                 _meta_l2c_init();
187                 _meta_l2c_enable(1);
188                 _meta_l2c_pf_enable(l2c_pfenable);
189         }
190         __global_unlock2(flags);
191
192         return !en;
193 }