Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/mm/cache-sh2a.c
10817 views
1
/*
2
* arch/sh/mm/cache-sh2a.c
3
*
4
* Copyright (C) 2008 Yoshinori Sato
5
*
6
* Released under the terms of the GNU GPL v2.0.
7
*/
8
9
#include <linux/init.h>
10
#include <linux/mm.h>
11
12
#include <asm/cache.h>
13
#include <asm/addrspace.h>
14
#include <asm/processor.h>
15
#include <asm/cacheflush.h>
16
#include <asm/io.h>
17
18
static void sh2a__flush_wback_region(void *start, int size)
19
{
20
unsigned long v;
21
unsigned long begin, end;
22
unsigned long flags;
23
24
begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
25
end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
26
& ~(L1_CACHE_BYTES-1);
27
28
local_irq_save(flags);
29
jump_to_uncached();
30
31
for (v = begin; v < end; v+=L1_CACHE_BYTES) {
32
unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0);
33
int way;
34
for (way = 0; way < 4; way++) {
35
unsigned long data = __raw_readl(addr | (way << 11));
36
if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
37
data &= ~SH_CACHE_UPDATED;
38
__raw_writel(data, addr | (way << 11));
39
}
40
}
41
}
42
43
back_to_cached();
44
local_irq_restore(flags);
45
}
46
47
static void sh2a__flush_purge_region(void *start, int size)
48
{
49
unsigned long v;
50
unsigned long begin, end;
51
unsigned long flags;
52
53
begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
54
end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
55
& ~(L1_CACHE_BYTES-1);
56
57
local_irq_save(flags);
58
jump_to_uncached();
59
60
for (v = begin; v < end; v+=L1_CACHE_BYTES) {
61
__raw_writel((v & CACHE_PHYSADDR_MASK),
62
CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
63
}
64
back_to_cached();
65
local_irq_restore(flags);
66
}
67
68
static void sh2a__flush_invalidate_region(void *start, int size)
69
{
70
unsigned long v;
71
unsigned long begin, end;
72
unsigned long flags;
73
74
begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
75
end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
76
& ~(L1_CACHE_BYTES-1);
77
local_irq_save(flags);
78
jump_to_uncached();
79
80
#ifdef CONFIG_CACHE_WRITEBACK
81
__raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
82
/* I-cache invalidate */
83
for (v = begin; v < end; v+=L1_CACHE_BYTES) {
84
__raw_writel((v & CACHE_PHYSADDR_MASK),
85
CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
86
}
87
#else
88
for (v = begin; v < end; v+=L1_CACHE_BYTES) {
89
__raw_writel((v & CACHE_PHYSADDR_MASK),
90
CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
91
__raw_writel((v & CACHE_PHYSADDR_MASK),
92
CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
93
}
94
#endif
95
back_to_cached();
96
local_irq_restore(flags);
97
}
98
99
/* WBack O-Cache and flush I-Cache */
100
static void sh2a_flush_icache_range(void *args)
101
{
102
struct flusher_data *data = args;
103
unsigned long start, end;
104
unsigned long v;
105
unsigned long flags;
106
107
start = data->addr1 & ~(L1_CACHE_BYTES-1);
108
end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1);
109
110
local_irq_save(flags);
111
jump_to_uncached();
112
113
for (v = start; v < end; v+=L1_CACHE_BYTES) {
114
unsigned long addr = (v & 0x000007f0);
115
int way;
116
/* O-Cache writeback */
117
for (way = 0; way < 4; way++) {
118
unsigned long data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
119
if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
120
data &= ~SH_CACHE_UPDATED;
121
__raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
122
}
123
}
124
/* I-Cache invalidate */
125
__raw_writel(addr,
126
CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008);
127
}
128
129
back_to_cached();
130
local_irq_restore(flags);
131
}
132
133
void __init sh2a_cache_init(void)
134
{
135
local_flush_icache_range = sh2a_flush_icache_range;
136
137
__flush_wback_region = sh2a__flush_wback_region;
138
__flush_purge_region = sh2a__flush_purge_region;
139
__flush_invalidate_region = sh2a__flush_invalidate_region;
140
}
141
142