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