xref: /linux/arch/s390/kernel/cache.c (revision 6668022c7bde3fdc96d3d257294a7216c7a46829)
1881730adSHeiko Carstens /*
2881730adSHeiko Carstens  * Extract CPU cache information and expose them via sysfs.
3881730adSHeiko Carstens  *
4881730adSHeiko Carstens  *    Copyright IBM Corp. 2012
5881730adSHeiko Carstens  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6881730adSHeiko Carstens  */
7881730adSHeiko Carstens 
8881730adSHeiko Carstens #include <linux/notifier.h>
9*6668022cSHeiko Carstens #include <linux/seq_file.h>
10881730adSHeiko Carstens #include <linux/init.h>
11881730adSHeiko Carstens #include <linux/list.h>
12881730adSHeiko Carstens #include <linux/slab.h>
13881730adSHeiko Carstens #include <linux/cpu.h>
14881730adSHeiko Carstens #include <asm/facility.h>
15881730adSHeiko Carstens 
16881730adSHeiko Carstens struct cache {
17881730adSHeiko Carstens 	unsigned long size;
18881730adSHeiko Carstens 	unsigned int line_size;
19881730adSHeiko Carstens 	unsigned int associativity;
20881730adSHeiko Carstens 	unsigned int nr_sets;
21*6668022cSHeiko Carstens 	unsigned int level   : 3;
22*6668022cSHeiko Carstens 	unsigned int type    : 2;
23*6668022cSHeiko Carstens 	unsigned int private : 1;
24881730adSHeiko Carstens 	struct list_head list;
25881730adSHeiko Carstens };
26881730adSHeiko Carstens 
27881730adSHeiko Carstens struct cache_dir {
28881730adSHeiko Carstens 	struct kobject *kobj;
29881730adSHeiko Carstens 	struct cache_index_dir *index;
30881730adSHeiko Carstens };
31881730adSHeiko Carstens 
32881730adSHeiko Carstens struct cache_index_dir {
33881730adSHeiko Carstens 	struct kobject kobj;
34881730adSHeiko Carstens 	int cpu;
35881730adSHeiko Carstens 	struct cache *cache;
36881730adSHeiko Carstens 	struct cache_index_dir *next;
37881730adSHeiko Carstens };
38881730adSHeiko Carstens 
39881730adSHeiko Carstens enum {
40881730adSHeiko Carstens 	CACHE_SCOPE_NOTEXISTS,
41881730adSHeiko Carstens 	CACHE_SCOPE_PRIVATE,
42881730adSHeiko Carstens 	CACHE_SCOPE_SHARED,
43881730adSHeiko Carstens 	CACHE_SCOPE_RESERVED,
44881730adSHeiko Carstens };
45881730adSHeiko Carstens 
46881730adSHeiko Carstens enum {
47881730adSHeiko Carstens 	CACHE_TYPE_SEPARATE,
48881730adSHeiko Carstens 	CACHE_TYPE_DATA,
49881730adSHeiko Carstens 	CACHE_TYPE_INSTRUCTION,
50881730adSHeiko Carstens 	CACHE_TYPE_UNIFIED,
51881730adSHeiko Carstens };
52881730adSHeiko Carstens 
53881730adSHeiko Carstens enum {
54881730adSHeiko Carstens 	EXTRACT_TOPOLOGY,
55881730adSHeiko Carstens 	EXTRACT_LINE_SIZE,
56881730adSHeiko Carstens 	EXTRACT_SIZE,
57881730adSHeiko Carstens 	EXTRACT_ASSOCIATIVITY,
58881730adSHeiko Carstens };
59881730adSHeiko Carstens 
60881730adSHeiko Carstens enum {
61881730adSHeiko Carstens 	CACHE_TI_UNIFIED = 0,
62881730adSHeiko Carstens 	CACHE_TI_INSTRUCTION = 0,
63881730adSHeiko Carstens 	CACHE_TI_DATA,
64881730adSHeiko Carstens };
65881730adSHeiko Carstens 
66881730adSHeiko Carstens struct cache_info {
67881730adSHeiko Carstens 	unsigned char	    : 4;
68881730adSHeiko Carstens 	unsigned char scope : 2;
69881730adSHeiko Carstens 	unsigned char type  : 2;
70881730adSHeiko Carstens };
71881730adSHeiko Carstens 
72881730adSHeiko Carstens #define CACHE_MAX_LEVEL 8
73881730adSHeiko Carstens 
74881730adSHeiko Carstens union cache_topology {
75881730adSHeiko Carstens 	struct cache_info ci[CACHE_MAX_LEVEL];
76881730adSHeiko Carstens 	unsigned long long raw;
77881730adSHeiko Carstens };
78881730adSHeiko Carstens 
79881730adSHeiko Carstens static const char * const cache_type_string[] = {
80881730adSHeiko Carstens 	"Data",
81881730adSHeiko Carstens 	"Instruction",
82881730adSHeiko Carstens 	"Unified",
83881730adSHeiko Carstens };
84881730adSHeiko Carstens 
85881730adSHeiko Carstens static struct cache_dir *cache_dir_cpu[NR_CPUS];
86881730adSHeiko Carstens static LIST_HEAD(cache_list);
87881730adSHeiko Carstens 
88*6668022cSHeiko Carstens void show_cacheinfo(struct seq_file *m)
89*6668022cSHeiko Carstens {
90*6668022cSHeiko Carstens 	struct cache *cache;
91*6668022cSHeiko Carstens 	int index = 0;
92*6668022cSHeiko Carstens 
93*6668022cSHeiko Carstens 	list_for_each_entry(cache, &cache_list, list) {
94*6668022cSHeiko Carstens 		seq_printf(m, "cache%-11d: ", index);
95*6668022cSHeiko Carstens 		seq_printf(m, "level=%d ", cache->level);
96*6668022cSHeiko Carstens 		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
97*6668022cSHeiko Carstens 		seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared");
98*6668022cSHeiko Carstens 		seq_printf(m, "size=%luK ", cache->size >> 10);
99*6668022cSHeiko Carstens 		seq_printf(m, "line_size=%u ", cache->line_size);
100*6668022cSHeiko Carstens 		seq_printf(m, "associativity=%d", cache->associativity);
101*6668022cSHeiko Carstens 		seq_puts(m, "\n");
102*6668022cSHeiko Carstens 		index++;
103*6668022cSHeiko Carstens 	}
104*6668022cSHeiko Carstens }
105*6668022cSHeiko Carstens 
106881730adSHeiko Carstens static inline unsigned long ecag(int ai, int li, int ti)
107881730adSHeiko Carstens {
108881730adSHeiko Carstens 	unsigned long cmd, val;
109881730adSHeiko Carstens 
110881730adSHeiko Carstens 	cmd = ai << 4 | li << 1 | ti;
111881730adSHeiko Carstens 	asm volatile(".insn	rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */
112881730adSHeiko Carstens 		     : "=d" (val) : "a" (cmd));
113881730adSHeiko Carstens 	return val;
114881730adSHeiko Carstens }
115881730adSHeiko Carstens 
116*6668022cSHeiko Carstens static int __init cache_add(int level, int private, int type)
117881730adSHeiko Carstens {
118881730adSHeiko Carstens 	struct cache *cache;
119881730adSHeiko Carstens 	int ti;
120881730adSHeiko Carstens 
121881730adSHeiko Carstens 	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
122881730adSHeiko Carstens 	if (!cache)
123881730adSHeiko Carstens 		return -ENOMEM;
124881730adSHeiko Carstens 	ti = type == CACHE_TYPE_DATA ? CACHE_TI_DATA : CACHE_TI_UNIFIED;
125881730adSHeiko Carstens 	cache->size = ecag(EXTRACT_SIZE, level, ti);
126881730adSHeiko Carstens 	cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
127881730adSHeiko Carstens 	cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
128881730adSHeiko Carstens 	cache->nr_sets = cache->size / cache->associativity;
129881730adSHeiko Carstens 	cache->nr_sets /= cache->line_size;
130*6668022cSHeiko Carstens 	cache->private = private;
131881730adSHeiko Carstens 	cache->level = level + 1;
132*6668022cSHeiko Carstens 	cache->type = type - 1;
133881730adSHeiko Carstens 	list_add_tail(&cache->list, &cache_list);
134881730adSHeiko Carstens 	return 0;
135881730adSHeiko Carstens }
136881730adSHeiko Carstens 
137881730adSHeiko Carstens static void __init cache_build_info(void)
138881730adSHeiko Carstens {
139881730adSHeiko Carstens 	struct cache *cache, *next;
140881730adSHeiko Carstens 	union cache_topology ct;
141*6668022cSHeiko Carstens 	int level, private, rc;
142881730adSHeiko Carstens 
143881730adSHeiko Carstens 	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
144881730adSHeiko Carstens 	for (level = 0; level < CACHE_MAX_LEVEL; level++) {
145881730adSHeiko Carstens 		switch (ct.ci[level].scope) {
146881730adSHeiko Carstens 		case CACHE_SCOPE_NOTEXISTS:
147881730adSHeiko Carstens 		case CACHE_SCOPE_RESERVED:
148881730adSHeiko Carstens 			return;
149*6668022cSHeiko Carstens 		case CACHE_SCOPE_SHARED:
150*6668022cSHeiko Carstens 			private = 0;
151*6668022cSHeiko Carstens 			break;
152881730adSHeiko Carstens 		case CACHE_SCOPE_PRIVATE:
153*6668022cSHeiko Carstens 			private = 1;
154881730adSHeiko Carstens 			break;
155881730adSHeiko Carstens 		}
156881730adSHeiko Carstens 		if (ct.ci[level].type == CACHE_TYPE_SEPARATE) {
157*6668022cSHeiko Carstens 			rc  = cache_add(level, private, CACHE_TYPE_DATA);
158*6668022cSHeiko Carstens 			rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION);
159881730adSHeiko Carstens 		} else {
160*6668022cSHeiko Carstens 			rc = cache_add(level, private, ct.ci[level].type);
161881730adSHeiko Carstens 		}
162881730adSHeiko Carstens 		if (rc)
163881730adSHeiko Carstens 			goto error;
164881730adSHeiko Carstens 	}
165881730adSHeiko Carstens 	return;
166881730adSHeiko Carstens error:
167881730adSHeiko Carstens 	list_for_each_entry_safe(cache, next, &cache_list, list) {
168881730adSHeiko Carstens 		list_del(&cache->list);
169881730adSHeiko Carstens 		kfree(cache);
170881730adSHeiko Carstens 	}
171881730adSHeiko Carstens }
172881730adSHeiko Carstens 
173881730adSHeiko Carstens static struct cache_dir *__cpuinit cache_create_cache_dir(int cpu)
174881730adSHeiko Carstens {
175881730adSHeiko Carstens 	struct cache_dir *cache_dir;
176881730adSHeiko Carstens 	struct kobject *kobj = NULL;
177881730adSHeiko Carstens 	struct device *dev;
178881730adSHeiko Carstens 
179881730adSHeiko Carstens 	dev = get_cpu_device(cpu);
180881730adSHeiko Carstens 	if (!dev)
181881730adSHeiko Carstens 		goto out;
182881730adSHeiko Carstens 	kobj = kobject_create_and_add("cache", &dev->kobj);
183881730adSHeiko Carstens 	if (!kobj)
184881730adSHeiko Carstens 		goto out;
185881730adSHeiko Carstens 	cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL);
186881730adSHeiko Carstens 	if (!cache_dir)
187881730adSHeiko Carstens 		goto out;
188881730adSHeiko Carstens 	cache_dir->kobj = kobj;
189881730adSHeiko Carstens 	cache_dir_cpu[cpu] = cache_dir;
190881730adSHeiko Carstens 	return cache_dir;
191881730adSHeiko Carstens out:
192881730adSHeiko Carstens 	kobject_put(kobj);
193881730adSHeiko Carstens 	return NULL;
194881730adSHeiko Carstens }
195881730adSHeiko Carstens 
196881730adSHeiko Carstens static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj)
197881730adSHeiko Carstens {
198881730adSHeiko Carstens 	return container_of(kobj, struct cache_index_dir, kobj);
199881730adSHeiko Carstens }
200881730adSHeiko Carstens 
201881730adSHeiko Carstens static void cache_index_release(struct kobject *kobj)
202881730adSHeiko Carstens {
203881730adSHeiko Carstens 	struct cache_index_dir *index;
204881730adSHeiko Carstens 
205881730adSHeiko Carstens 	index = kobj_to_cache_index_dir(kobj);
206881730adSHeiko Carstens 	kfree(index);
207881730adSHeiko Carstens }
208881730adSHeiko Carstens 
209881730adSHeiko Carstens static ssize_t cache_index_show(struct kobject *kobj,
210881730adSHeiko Carstens 				struct attribute *attr, char *buf)
211881730adSHeiko Carstens {
212881730adSHeiko Carstens 	struct kobj_attribute *kobj_attr;
213881730adSHeiko Carstens 
214881730adSHeiko Carstens 	kobj_attr = container_of(attr, struct kobj_attribute, attr);
215881730adSHeiko Carstens 	return kobj_attr->show(kobj, kobj_attr, buf);
216881730adSHeiko Carstens }
217881730adSHeiko Carstens 
218881730adSHeiko Carstens #define DEFINE_CACHE_ATTR(_name, _format, _value)			\
219881730adSHeiko Carstens static ssize_t cache_##_name##_show(struct kobject *kobj,		\
220881730adSHeiko Carstens 				    struct kobj_attribute *attr,	\
221881730adSHeiko Carstens 				    char *buf)				\
222881730adSHeiko Carstens {									\
223881730adSHeiko Carstens 	struct cache_index_dir *index;					\
224881730adSHeiko Carstens 									\
225881730adSHeiko Carstens 	index = kobj_to_cache_index_dir(kobj);				\
226881730adSHeiko Carstens 	return sprintf(buf, _format, _value);				\
227881730adSHeiko Carstens }									\
228881730adSHeiko Carstens static struct kobj_attribute cache_##_name##_attr =			\
229881730adSHeiko Carstens 	__ATTR(_name, 0444, cache_##_name##_show, NULL);
230881730adSHeiko Carstens 
231881730adSHeiko Carstens DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10);
232881730adSHeiko Carstens DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size);
233881730adSHeiko Carstens DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets);
234881730adSHeiko Carstens DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity);
235*6668022cSHeiko Carstens DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]);
236881730adSHeiko Carstens DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level);
237881730adSHeiko Carstens 
238881730adSHeiko Carstens static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf)
239881730adSHeiko Carstens {
240881730adSHeiko Carstens 	struct cache_index_dir *index;
241881730adSHeiko Carstens 	int len;
242881730adSHeiko Carstens 
243881730adSHeiko Carstens 	index = kobj_to_cache_index_dir(kobj);
244881730adSHeiko Carstens 	len = type ?
245881730adSHeiko Carstens 		cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) :
246881730adSHeiko Carstens 		cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu));
247881730adSHeiko Carstens 	len += sprintf(&buf[len], "\n");
248881730adSHeiko Carstens 	return len;
249881730adSHeiko Carstens }
250881730adSHeiko Carstens 
251881730adSHeiko Carstens static ssize_t shared_cpu_map_show(struct kobject *kobj,
252881730adSHeiko Carstens 				   struct kobj_attribute *attr, char *buf)
253881730adSHeiko Carstens {
254881730adSHeiko Carstens 	return shared_cpu_map_func(kobj, 0, buf);
255881730adSHeiko Carstens }
256881730adSHeiko Carstens static struct kobj_attribute cache_shared_cpu_map_attr =
257881730adSHeiko Carstens 	__ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL);
258881730adSHeiko Carstens 
259881730adSHeiko Carstens static ssize_t shared_cpu_list_show(struct kobject *kobj,
260881730adSHeiko Carstens 				    struct kobj_attribute *attr, char *buf)
261881730adSHeiko Carstens {
262881730adSHeiko Carstens 	return shared_cpu_map_func(kobj, 1, buf);
263881730adSHeiko Carstens }
264881730adSHeiko Carstens static struct kobj_attribute cache_shared_cpu_list_attr =
265881730adSHeiko Carstens 	__ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL);
266881730adSHeiko Carstens 
267881730adSHeiko Carstens static struct attribute *cache_index_default_attrs[] = {
268881730adSHeiko Carstens 	&cache_type_attr.attr,
269881730adSHeiko Carstens 	&cache_size_attr.attr,
270881730adSHeiko Carstens 	&cache_number_of_sets_attr.attr,
271881730adSHeiko Carstens 	&cache_ways_of_associativity_attr.attr,
272881730adSHeiko Carstens 	&cache_level_attr.attr,
273881730adSHeiko Carstens 	&cache_coherency_line_size_attr.attr,
274881730adSHeiko Carstens 	&cache_shared_cpu_map_attr.attr,
275881730adSHeiko Carstens 	&cache_shared_cpu_list_attr.attr,
276881730adSHeiko Carstens 	NULL,
277881730adSHeiko Carstens };
278881730adSHeiko Carstens 
279881730adSHeiko Carstens static const struct sysfs_ops cache_index_ops = {
280881730adSHeiko Carstens 	.show = cache_index_show,
281881730adSHeiko Carstens };
282881730adSHeiko Carstens 
283881730adSHeiko Carstens static struct kobj_type cache_index_type = {
284881730adSHeiko Carstens 	.sysfs_ops = &cache_index_ops,
285881730adSHeiko Carstens 	.release = cache_index_release,
286881730adSHeiko Carstens 	.default_attrs = cache_index_default_attrs,
287881730adSHeiko Carstens };
288881730adSHeiko Carstens 
289881730adSHeiko Carstens static int __cpuinit cache_create_index_dir(struct cache_dir *cache_dir,
290881730adSHeiko Carstens 					    struct cache *cache, int index,
291881730adSHeiko Carstens 					    int cpu)
292881730adSHeiko Carstens {
293881730adSHeiko Carstens 	struct cache_index_dir *index_dir;
294881730adSHeiko Carstens 	int rc;
295881730adSHeiko Carstens 
296881730adSHeiko Carstens 	index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL);
297881730adSHeiko Carstens 	if (!index_dir)
298881730adSHeiko Carstens 		return -ENOMEM;
299881730adSHeiko Carstens 	index_dir->cache = cache;
300881730adSHeiko Carstens 	index_dir->cpu = cpu;
301881730adSHeiko Carstens 	rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type,
302881730adSHeiko Carstens 				  cache_dir->kobj, "index%d", index);
303881730adSHeiko Carstens 	if (rc)
304881730adSHeiko Carstens 		goto out;
305881730adSHeiko Carstens 	index_dir->next = cache_dir->index;
306881730adSHeiko Carstens 	cache_dir->index = index_dir;
307881730adSHeiko Carstens 	return 0;
308881730adSHeiko Carstens out:
309881730adSHeiko Carstens 	kfree(index_dir);
310881730adSHeiko Carstens 	return rc;
311881730adSHeiko Carstens }
312881730adSHeiko Carstens 
313881730adSHeiko Carstens static int __cpuinit cache_add_cpu(int cpu)
314881730adSHeiko Carstens {
315881730adSHeiko Carstens 	struct cache_dir *cache_dir;
316881730adSHeiko Carstens 	struct cache *cache;
317881730adSHeiko Carstens 	int rc, index = 0;
318881730adSHeiko Carstens 
319881730adSHeiko Carstens 	if (list_empty(&cache_list))
320881730adSHeiko Carstens 		return 0;
321881730adSHeiko Carstens 	cache_dir = cache_create_cache_dir(cpu);
322881730adSHeiko Carstens 	if (!cache_dir)
323881730adSHeiko Carstens 		return -ENOMEM;
324881730adSHeiko Carstens 	list_for_each_entry(cache, &cache_list, list) {
325*6668022cSHeiko Carstens 		if (!cache->private)
326*6668022cSHeiko Carstens 			break;
327881730adSHeiko Carstens 		rc = cache_create_index_dir(cache_dir, cache, index, cpu);
328881730adSHeiko Carstens 		if (rc)
329881730adSHeiko Carstens 			return rc;
330881730adSHeiko Carstens 		index++;
331881730adSHeiko Carstens 	}
332881730adSHeiko Carstens 	return 0;
333881730adSHeiko Carstens }
334881730adSHeiko Carstens 
335881730adSHeiko Carstens static void __cpuinit cache_remove_cpu(int cpu)
336881730adSHeiko Carstens {
337881730adSHeiko Carstens 	struct cache_index_dir *index, *next;
338881730adSHeiko Carstens 	struct cache_dir *cache_dir;
339881730adSHeiko Carstens 
340881730adSHeiko Carstens 	cache_dir = cache_dir_cpu[cpu];
341881730adSHeiko Carstens 	if (!cache_dir)
342881730adSHeiko Carstens 		return;
343881730adSHeiko Carstens 	index = cache_dir->index;
344881730adSHeiko Carstens 	while (index) {
345881730adSHeiko Carstens 		next = index->next;
346881730adSHeiko Carstens 		kobject_put(&index->kobj);
347881730adSHeiko Carstens 		index = next;
348881730adSHeiko Carstens 	}
349881730adSHeiko Carstens 	kobject_put(cache_dir->kobj);
350881730adSHeiko Carstens 	kfree(cache_dir);
351881730adSHeiko Carstens 	cache_dir_cpu[cpu] = NULL;
352881730adSHeiko Carstens }
353881730adSHeiko Carstens 
354881730adSHeiko Carstens static int __cpuinit cache_hotplug(struct notifier_block *nfb,
355881730adSHeiko Carstens 				   unsigned long action, void *hcpu)
356881730adSHeiko Carstens {
357881730adSHeiko Carstens 	int cpu = (long)hcpu;
358881730adSHeiko Carstens 	int rc = 0;
359881730adSHeiko Carstens 
360881730adSHeiko Carstens 	switch (action & ~CPU_TASKS_FROZEN) {
361881730adSHeiko Carstens 	case CPU_ONLINE:
362881730adSHeiko Carstens 		rc = cache_add_cpu(cpu);
363881730adSHeiko Carstens 		if (rc)
364881730adSHeiko Carstens 			cache_remove_cpu(cpu);
365881730adSHeiko Carstens 		break;
366881730adSHeiko Carstens 	case CPU_DEAD:
367881730adSHeiko Carstens 		cache_remove_cpu(cpu);
368881730adSHeiko Carstens 		break;
369881730adSHeiko Carstens 	}
370881730adSHeiko Carstens 	return rc ? NOTIFY_BAD : NOTIFY_OK;
371881730adSHeiko Carstens }
372881730adSHeiko Carstens 
373881730adSHeiko Carstens static int __init cache_init(void)
374881730adSHeiko Carstens {
375881730adSHeiko Carstens 	int cpu;
376881730adSHeiko Carstens 
377881730adSHeiko Carstens 	if (!test_facility(34))
378881730adSHeiko Carstens 		return 0;
379881730adSHeiko Carstens 	cache_build_info();
380881730adSHeiko Carstens 	for_each_online_cpu(cpu)
381881730adSHeiko Carstens 		cache_add_cpu(cpu);
382881730adSHeiko Carstens 	hotcpu_notifier(cache_hotplug, 0);
383881730adSHeiko Carstens 	return 0;
384881730adSHeiko Carstens }
385881730adSHeiko Carstens device_initcall(cache_init);
386