ext3: Update MAINTAINERS for ext3 and JBD
[linux/fpc-iii.git] / arch / blackfin / kernel / cplb-nompu / cplbmgr.c
blob12b030842fdbc1623c99997c60e67d534f168112
1 /*
2 * File: arch/blackfin/kernel/cplb-nompu-c/cplbmgr.c
3 * Based on: arch/blackfin/kernel/cplb-mpu/cplbmgr.c
4 * Author: Michael McTernan <mmcternan@airvana.com>
6 * Created: 01Nov2008
7 * Description: CPLB miss handler.
9 * Modified:
10 * Copyright 2008 Airvana Inc.
11 * Copyright 2004-2007 Analog Devices Inc.
13 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
26 #include <linux/kernel.h>
27 #include <asm/blackfin.h>
28 #include <asm/cplbinit.h>
29 #include <asm/cplb.h>
30 #include <asm/mmu_context.h>
31 #include <asm/traps.h>
34 * WARNING
36 * This file is compiled with certain -ffixed-reg options. We have to
37 * make sure not to call any functions here that could clobber these
38 * registers.
41 int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS];
42 int nr_dcplb_supv_miss[NR_CPUS], nr_icplb_supv_miss[NR_CPUS];
43 int nr_cplb_flush[NR_CPUS], nr_dcplb_prot[NR_CPUS];
45 #ifdef CONFIG_EXCPT_IRQ_SYSC_L1
46 #define MGR_ATTR __attribute__((l1_text))
47 #else
48 #define MGR_ATTR
49 #endif
52 * We're in an exception handler. The normal cli nop nop workaround
53 * isn't going to do very much, as the only thing that can interrupt
54 * us is an NMI, and the cli isn't going to stop that.
56 #define NOWA_SSYNC __asm__ __volatile__ ("ssync;")
58 /* Anomaly handlers provide SSYNCs, so avoid extra if anomaly is present */
59 #if ANOMALY_05000125
61 #define bfin_write_DMEM_CONTROL_SSYNC(v) bfin_write_DMEM_CONTROL(v)
62 #define bfin_write_IMEM_CONTROL_SSYNC(v) bfin_write_IMEM_CONTROL(v)
64 #else
66 #define bfin_write_DMEM_CONTROL_SSYNC(v) \
67 do { NOWA_SSYNC; bfin_write_DMEM_CONTROL(v); NOWA_SSYNC; } while (0)
68 #define bfin_write_IMEM_CONTROL_SSYNC(v) \
69 do { NOWA_SSYNC; bfin_write_IMEM_CONTROL(v); NOWA_SSYNC; } while (0)
71 #endif
73 static inline void write_dcplb_data(int cpu, int idx, unsigned long data,
74 unsigned long addr)
76 unsigned long ctrl = bfin_read_DMEM_CONTROL();
77 bfin_write_DMEM_CONTROL_SSYNC(ctrl & ~ENDCPLB);
78 bfin_write32(DCPLB_DATA0 + idx * 4, data);
79 bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
80 bfin_write_DMEM_CONTROL_SSYNC(ctrl);
82 #ifdef CONFIG_CPLB_INFO
83 dcplb_tbl[cpu][idx].addr = addr;
84 dcplb_tbl[cpu][idx].data = data;
85 #endif
88 static inline void write_icplb_data(int cpu, int idx, unsigned long data,
89 unsigned long addr)
91 unsigned long ctrl = bfin_read_IMEM_CONTROL();
93 bfin_write_IMEM_CONTROL_SSYNC(ctrl & ~ENICPLB);
94 bfin_write32(ICPLB_DATA0 + idx * 4, data);
95 bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
96 bfin_write_IMEM_CONTROL_SSYNC(ctrl);
98 #ifdef CONFIG_CPLB_INFO
99 icplb_tbl[cpu][idx].addr = addr;
100 icplb_tbl[cpu][idx].data = data;
101 #endif
104 /* Counters to implement round-robin replacement. */
105 static int icplb_rr_index[NR_CPUS] PDT_ATTR;
106 static int dcplb_rr_index[NR_CPUS] PDT_ATTR;
109 * Find an ICPLB entry to be evicted and return its index.
111 static int evict_one_icplb(int cpu)
113 int i = first_switched_icplb + icplb_rr_index[cpu];
114 if (i >= MAX_CPLBS) {
115 i -= MAX_CPLBS - first_switched_icplb;
116 icplb_rr_index[cpu] -= MAX_CPLBS - first_switched_icplb;
118 icplb_rr_index[cpu]++;
119 return i;
122 static int evict_one_dcplb(int cpu)
124 int i = first_switched_dcplb + dcplb_rr_index[cpu];
125 if (i >= MAX_CPLBS) {
126 i -= MAX_CPLBS - first_switched_dcplb;
127 dcplb_rr_index[cpu] -= MAX_CPLBS - first_switched_dcplb;
129 dcplb_rr_index[cpu]++;
130 return i;
133 MGR_ATTR static int icplb_miss(int cpu)
135 unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
136 int status = bfin_read_ICPLB_STATUS();
137 int idx;
138 unsigned long i_data, base, addr1, eaddr;
140 nr_icplb_miss[cpu]++;
141 if (unlikely(status & FAULT_USERSUPV))
142 nr_icplb_supv_miss[cpu]++;
144 base = 0;
145 idx = 0;
146 do {
147 eaddr = icplb_bounds[idx].eaddr;
148 if (addr < eaddr)
149 break;
150 base = eaddr;
151 } while (++idx < icplb_nr_bounds);
153 if (unlikely(idx == icplb_nr_bounds))
154 return CPLB_NO_ADDR_MATCH;
156 i_data = icplb_bounds[idx].data;
157 if (unlikely(i_data == 0))
158 return CPLB_NO_ADDR_MATCH;
160 addr1 = addr & ~(SIZE_4M - 1);
161 addr &= ~(SIZE_1M - 1);
162 i_data |= PAGE_SIZE_1MB;
163 if (addr1 >= base && (addr1 + SIZE_4M) <= eaddr) {
165 * This works because
166 * (PAGE_SIZE_4MB & PAGE_SIZE_1MB) == PAGE_SIZE_1MB.
168 i_data |= PAGE_SIZE_4MB;
169 addr = addr1;
172 /* Pick entry to evict */
173 idx = evict_one_icplb(cpu);
175 write_icplb_data(cpu, idx, i_data, addr);
177 return CPLB_RELOADED;
180 MGR_ATTR static int dcplb_miss(int cpu)
182 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
183 int status = bfin_read_DCPLB_STATUS();
184 int idx;
185 unsigned long d_data, base, addr1, eaddr;
187 nr_dcplb_miss[cpu]++;
188 if (unlikely(status & FAULT_USERSUPV))
189 nr_dcplb_supv_miss[cpu]++;
191 base = 0;
192 idx = 0;
193 do {
194 eaddr = dcplb_bounds[idx].eaddr;
195 if (addr < eaddr)
196 break;
197 base = eaddr;
198 } while (++idx < dcplb_nr_bounds);
200 if (unlikely(idx == dcplb_nr_bounds))
201 return CPLB_NO_ADDR_MATCH;
203 d_data = dcplb_bounds[idx].data;
204 if (unlikely(d_data == 0))
205 return CPLB_NO_ADDR_MATCH;
207 addr1 = addr & ~(SIZE_4M - 1);
208 addr &= ~(SIZE_1M - 1);
209 d_data |= PAGE_SIZE_1MB;
210 if (addr1 >= base && (addr1 + SIZE_4M) <= eaddr) {
212 * This works because
213 * (PAGE_SIZE_4MB & PAGE_SIZE_1MB) == PAGE_SIZE_1MB.
215 d_data |= PAGE_SIZE_4MB;
216 addr = addr1;
219 /* Pick entry to evict */
220 idx = evict_one_dcplb(cpu);
222 write_dcplb_data(cpu, idx, d_data, addr);
224 return CPLB_RELOADED;
227 MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs)
229 int cause = seqstat & 0x3f;
230 unsigned int cpu = smp_processor_id();
231 switch (cause) {
232 case VEC_CPLB_I_M:
233 return icplb_miss(cpu);
234 case VEC_CPLB_M:
235 return dcplb_miss(cpu);
236 default:
237 return CPLB_UNKNOWN_ERR;