aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/mm/cache.c
blob: 450515b245a08dd0418ec65f51610048815cfcd4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * Copyright (C) 2004-2006 Atmel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/highmem.h>
#include <linux/unistd.h>

#include <asm/cacheflush.h>
#include <asm/cachectl.h>
#include <asm/processor.h>
#include <asm/uaccess.h>

/*
 * If you attempt to flush anything more than this, you need superuser
 * privileges.  The value is completely arbitrary.
 */
#define CACHEFLUSH_MAX_LEN	1024

void invalidate_dcache_region(void *start, size_t size)
{
	unsigned long v, begin, end, linesz;

	linesz = boot_cpu_data.dcache.linesz;

	//printk("invalidate dcache: %p + %u\n", start, size);

	/* You asked for it, you got it */
	begin = (unsigned long)start & ~(linesz - 1);
	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);

	for (v = begin; v < end; v += linesz)
		invalidate_dcache_line((void *)v);
}

void clean_dcache_region(void *start, size_t size)
{
	unsigned long v, begin, end, linesz;

	linesz = boot_cpu_data.dcache.linesz;
	begin = (unsigned long)start & ~(linesz - 1);
	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);

	for (v = begin; v < end; v += linesz)
		clean_dcache_line((void *)v);
	flush_write_buffer();
}

void flush_dcache_region(void *start, size_t size)
{
	unsigned long v, begin, end, linesz;

	linesz = boot_cpu_data.dcache.linesz;
	begin = (unsigned long)start & ~(linesz - 1);
	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);

	for (v = begin; v < end; v += linesz)
		flush_dcache_line((void *)v);
	flush_write_buffer();
}

void invalidate_icache_region(void *start, size_t size)
{
	unsigned long v, begin, end, linesz;

	linesz = boot_cpu_data.icache.linesz;
	begin = (unsigned long)start & ~(linesz - 1);
	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);

	for (v = begin; v < end; v += linesz)
		invalidate_icache_line((void *)v);
}

static inline void __flush_icache_range(unsigned long start, unsigned long end)
{
	unsigned long v, linesz;

	linesz = boot_cpu_data.dcache.linesz;
	for (v = start; v < end; v += linesz) {
		clean_dcache_line((void *)v);
		invalidate_icache_line((void *)v);
	}

	flush_write_buffer();
}

/*
 * This one is called after a module has been loaded.
 */
void flush_icache_range(unsigned long start, unsigned long end)
{
	unsigned long linesz;

	linesz = boot_cpu_data.dcache.linesz;
	__flush_icache_range(start & ~(linesz - 1),
			     (end + linesz - 1) & ~(linesz - 1));
}

/*
 * This one is called from do_no_page(), do_swap_page() and install_page().
 */
void flush_icache_page(struct vm_area_struct *vma, struct page *page)
{
	if (vma->vm_flags & VM_EXEC) {
		void *v = kmap(page);
		__flush_icache_range((unsigned long)v, (unsigned long)v + PAGE_SIZE);
		kunmap(v);
	}
}

/*
 * This one is used by copy_to_user_page()
 */
void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
			     unsigned long addr, int len)
{
	if (vma->vm_flags & VM_EXEC)
		flush_icache_range(addr, addr + len);
}

asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
{
	int ret;

	if (len > CACHEFLUSH_MAX_LEN) {
		ret = -EPERM;
		if (!capable(CAP_SYS_ADMIN))
			goto out;
	}

	ret = -EFAULT;
	if (!access_ok(VERIFY_WRITE, addr, len))
		goto out;

	switch (operation) {
	case CACHE_IFLUSH:
		flush_icache_range((unsigned long)addr,
				   (unsigned long)addr + len);
		ret = 0;
		break;
	default:
		ret = -EINVAL;
	}

out:
	return ret;
}
clude <linux/serial.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <asm/cpu.h> #include <asm/bootinfo.h> #include <asm/mips-boards/generic.h> #include <asm/mips-boards/prom.h> #include <asm/time.h> #include <asm/mips-boards/sim.h> #include <asm/mips-boards/simint.h> static void __init serial_init(void); unsigned int _isbonito = 0; const char *get_system_type(void) { return "MIPSsim"; } void __init plat_mem_setup(void) { set_io_port_base(0xbfd00000); serial_init(); pr_info("Linux started...\n"); } extern struct plat_smp_ops ssmtc_smp_ops; void __init prom_init(void) { set_io_port_base(0xbfd00000); pr_info("\nLINUX started...\n"); prom_init_cmdline(); prom_meminit(); #ifdef CONFIG_MIPS_MT_SMP if (cpu_has_mipsmt) register_smp_ops(&vsmp_smp_ops); else register_smp_ops(&up_smp_ops); #endif #ifdef CONFIG_MIPS_MT_SMTC if (cpu_has_mipsmt) register_smp_ops(&ssmtc_smp_ops); else register_smp_ops(&up_smp_ops); #endif } static void __init serial_init(void) { #ifdef CONFIG_SERIAL_8250 struct uart_port s; memset(&s, 0, sizeof(s)); s.iobase = 0x3f8; /* hardware int 4 - the serial int, is CPU int 6 but poll for now */ s.irq = 0; s.uartclk = 1843200; s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; s.iotype = UPIO_PORT; s.regshift = 0; s.timeout = 4; if (early_serial_setup(&s) != 0) { printk(KERN_ERR "Serial setup failed!\n"); } #endif }