diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m32r/kernel |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m32r/kernel')
31 files changed, 11198 insertions, 0 deletions
diff --git a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile new file mode 100644 index 000000000000..cfd690bf6d8a --- /dev/null +++ b/arch/m32r/kernel/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # | ||
2 | # Makefile for the Linux/M32R kernel. | ||
3 | # | ||
4 | |||
5 | extra-y := head.o init_task.o vmlinux.lds | ||
6 | |||
7 | obj-y := process.o entry.o traps.o align.o irq.o setup.o time.o \ | ||
8 | m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o | ||
9 | |||
10 | obj-$(CONFIG_SMP) += smp.o smpboot.o | ||
11 | obj-$(CONFIG_PLAT_MAPPI) += setup_mappi.o io_mappi.o | ||
12 | obj-$(CONFIG_PLAT_MAPPI2) += setup_mappi2.o io_mappi2.o | ||
13 | obj-$(CONFIG_PLAT_USRV) += setup_usrv.o io_usrv.o | ||
14 | obj-$(CONFIG_PLAT_M32700UT) += setup_m32700ut.o io_m32700ut.o | ||
15 | obj-$(CONFIG_PLAT_OPSPUT) += setup_opsput.o io_opsput.o | ||
16 | obj-$(CONFIG_MODULES) += module.o | ||
17 | obj-$(CONFIG_PLAT_OAKS32R) += setup_oaks32r.o io_oaks32r.o | ||
18 | |||
19 | EXTRA_AFLAGS := -traditional | ||
20 | |||
diff --git a/arch/m32r/kernel/align.c b/arch/m32r/kernel/align.c new file mode 100644 index 000000000000..48ec29714238 --- /dev/null +++ b/arch/m32r/kernel/align.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /* | ||
2 | * align.c - address exception handler for M32R | ||
3 | * | ||
4 | * Copyright (c) 2003 Hitoshi Yamamoto | ||
5 | */ | ||
6 | |||
7 | #include <linux/config.h> | ||
8 | #include <asm/ptrace.h> | ||
9 | #include <asm/uaccess.h> | ||
10 | |||
11 | static int get_reg(struct pt_regs *regs, int nr) | ||
12 | { | ||
13 | int val; | ||
14 | |||
15 | if (nr < 4) | ||
16 | val = *(unsigned long *)(®s->r0 + nr); | ||
17 | else if (nr < 7) | ||
18 | val = *(unsigned long *)(®s->r4 + (nr - 4)); | ||
19 | else if (nr < 13) | ||
20 | val = *(unsigned long *)(®s->r7 + (nr - 7)); | ||
21 | else | ||
22 | val = *(unsigned long *)(®s->fp + (nr - 13)); | ||
23 | |||
24 | return val; | ||
25 | } | ||
26 | |||
27 | static void set_reg(struct pt_regs *regs, int nr, int val) | ||
28 | { | ||
29 | if (nr < 4) | ||
30 | *(unsigned long *)(®s->r0 + nr) = val; | ||
31 | else if (nr < 7) | ||
32 | *(unsigned long *)(®s->r4 + (nr - 4)) = val; | ||
33 | else if (nr < 13) | ||
34 | *(unsigned long *)(®s->r7 + (nr - 7)) = val; | ||
35 | else | ||
36 | *(unsigned long *)(®s->fp + (nr - 13)) = val; | ||
37 | } | ||
38 | |||
39 | #define REG1(insn) (((insn) & 0x0f00) >> 8) | ||
40 | #define REG2(insn) ((insn) & 0x000f) | ||
41 | #define PSW_BC 0x100 | ||
42 | |||
43 | /* O- instruction */ | ||
44 | #define ISA_LD1 0x20c0 /* ld Rdest, @Rsrc */ | ||
45 | #define ISA_LD2 0x20e0 /* ld Rdest, @Rsrc+ */ | ||
46 | #define ISA_LDH 0x20a0 /* ldh Rdest, @Rsrc */ | ||
47 | #define ISA_LDUH 0x20b0 /* lduh Rdest, @Rsrc */ | ||
48 | #define ISA_ST1 0x2040 /* st Rsrc1, @Rsrc2 */ | ||
49 | #define ISA_ST2 0x2060 /* st Rsrc1, @+Rsrc2 */ | ||
50 | #define ISA_ST3 0x2070 /* st Rsrc1, @-Rsrc2 */ | ||
51 | #define ISA_STH1 0x2020 /* sth Rsrc1, @Rsrc2 */ | ||
52 | #define ISA_STH2 0x2030 /* sth Rsrc1, @Rsrc2+ */ | ||
53 | |||
54 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
55 | |||
56 | /* OS instruction */ | ||
57 | #define ISA_ADD 0x00a0 /* add Rdest, Rsrc */ | ||
58 | #define ISA_ADDI 0x4000 /* addi Rdest, #imm8 */ | ||
59 | #define ISA_ADDX 0x0090 /* addx Rdest, Rsrc */ | ||
60 | #define ISA_AND 0x00c0 /* and Rdest, Rsrc */ | ||
61 | #define ISA_CMP 0x0040 /* cmp Rsrc1, Rsrc2 */ | ||
62 | #define ISA_CMPEQ 0x0060 /* cmpeq Rsrc1, Rsrc2 */ | ||
63 | #define ISA_CMPU 0x0050 /* cmpu Rsrc1, Rsrc2 */ | ||
64 | #define ISA_CMPZ 0x0070 /* cmpz Rsrc */ | ||
65 | #define ISA_LDI 0x6000 /* ldi Rdest, #imm8 */ | ||
66 | #define ISA_MV 0x1080 /* mv Rdest, Rsrc */ | ||
67 | #define ISA_NEG 0x0030 /* neg Rdest, Rsrc */ | ||
68 | #define ISA_NOP 0x7000 /* nop */ | ||
69 | #define ISA_NOT 0x00b0 /* not Rdest, Rsrc */ | ||
70 | #define ISA_OR 0x00e0 /* or Rdest, Rsrc */ | ||
71 | #define ISA_SUB 0x0020 /* sub Rdest, Rsrc */ | ||
72 | #define ISA_SUBX 0x0010 /* subx Rdest, Rsrc */ | ||
73 | #define ISA_XOR 0x00d0 /* xor Rdest, Rsrc */ | ||
74 | |||
75 | /* -S instruction */ | ||
76 | #define ISA_MUL 0x1060 /* mul Rdest, Rsrc */ | ||
77 | #define ISA_MULLO_A0 0x3010 /* mullo Rsrc1, Rsrc2, A0 */ | ||
78 | #define ISA_MULLO_A1 0x3090 /* mullo Rsrc1, Rsrc2, A1 */ | ||
79 | #define ISA_MVFACMI_A0 0x50f2 /* mvfacmi Rdest, A0 */ | ||
80 | #define ISA_MVFACMI_A1 0x50f6 /* mvfacmi Rdest, A1 */ | ||
81 | |||
82 | static int emu_addi(unsigned short insn, struct pt_regs *regs) | ||
83 | { | ||
84 | char imm = (char)(insn & 0xff); | ||
85 | int dest = REG1(insn); | ||
86 | int val; | ||
87 | |||
88 | val = get_reg(regs, dest); | ||
89 | val += imm; | ||
90 | set_reg(regs, dest, val); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int emu_ldi(unsigned short insn, struct pt_regs *regs) | ||
96 | { | ||
97 | char imm = (char)(insn & 0xff); | ||
98 | |||
99 | set_reg(regs, REG1(insn), (int)imm); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int emu_add(unsigned short insn, struct pt_regs *regs) | ||
105 | { | ||
106 | int dest = REG1(insn); | ||
107 | int src = REG2(insn); | ||
108 | int val; | ||
109 | |||
110 | val = get_reg(regs, dest); | ||
111 | val += get_reg(regs, src); | ||
112 | set_reg(regs, dest, val); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int emu_addx(unsigned short insn, struct pt_regs *regs) | ||
118 | { | ||
119 | int dest = REG1(insn); | ||
120 | unsigned int val, tmp; | ||
121 | |||
122 | val = regs->psw & PSW_BC ? 1 : 0; | ||
123 | tmp = get_reg(regs, dest); | ||
124 | val += tmp; | ||
125 | val += (unsigned int)get_reg(regs, REG2(insn)); | ||
126 | set_reg(regs, dest, val); | ||
127 | |||
128 | /* C bit set */ | ||
129 | if (val < tmp) | ||
130 | regs->psw |= PSW_BC; | ||
131 | else | ||
132 | regs->psw &= ~(PSW_BC); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int emu_and(unsigned short insn, struct pt_regs *regs) | ||
138 | { | ||
139 | int dest = REG1(insn); | ||
140 | int val; | ||
141 | |||
142 | val = get_reg(regs, dest); | ||
143 | val &= get_reg(regs, REG2(insn)); | ||
144 | set_reg(regs, dest, val); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int emu_cmp(unsigned short insn, struct pt_regs *regs) | ||
150 | { | ||
151 | if (get_reg(regs, REG1(insn)) < get_reg(regs, REG2(insn))) | ||
152 | regs->psw |= PSW_BC; | ||
153 | else | ||
154 | regs->psw &= ~(PSW_BC); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int emu_cmpeq(unsigned short insn, struct pt_regs *regs) | ||
160 | { | ||
161 | if (get_reg(regs, REG1(insn)) == get_reg(regs, REG2(insn))) | ||
162 | regs->psw |= PSW_BC; | ||
163 | else | ||
164 | regs->psw &= ~(PSW_BC); | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int emu_cmpu(unsigned short insn, struct pt_regs *regs) | ||
170 | { | ||
171 | if ((unsigned int)get_reg(regs, REG1(insn)) | ||
172 | < (unsigned int)get_reg(regs, REG2(insn))) | ||
173 | regs->psw |= PSW_BC; | ||
174 | else | ||
175 | regs->psw &= ~(PSW_BC); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int emu_cmpz(unsigned short insn, struct pt_regs *regs) | ||
181 | { | ||
182 | if (!get_reg(regs, REG2(insn))) | ||
183 | regs->psw |= PSW_BC; | ||
184 | else | ||
185 | regs->psw &= ~(PSW_BC); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int emu_mv(unsigned short insn, struct pt_regs *regs) | ||
191 | { | ||
192 | int val; | ||
193 | |||
194 | val = get_reg(regs, REG2(insn)); | ||
195 | set_reg(regs, REG1(insn), val); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int emu_neg(unsigned short insn, struct pt_regs *regs) | ||
201 | { | ||
202 | int val; | ||
203 | |||
204 | val = get_reg(regs, REG2(insn)); | ||
205 | set_reg(regs, REG1(insn), 0 - val); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int emu_not(unsigned short insn, struct pt_regs *regs) | ||
211 | { | ||
212 | int val; | ||
213 | |||
214 | val = get_reg(regs, REG2(insn)); | ||
215 | set_reg(regs, REG1(insn), ~val); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int emu_or(unsigned short insn, struct pt_regs *regs) | ||
221 | { | ||
222 | int dest = REG1(insn); | ||
223 | int val; | ||
224 | |||
225 | val = get_reg(regs, dest); | ||
226 | val |= get_reg(regs, REG2(insn)); | ||
227 | set_reg(regs, dest, val); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int emu_sub(unsigned short insn, struct pt_regs *regs) | ||
233 | { | ||
234 | int dest = REG1(insn); | ||
235 | int val; | ||
236 | |||
237 | val = get_reg(regs, dest); | ||
238 | val -= get_reg(regs, REG2(insn)); | ||
239 | set_reg(regs, dest, val); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int emu_subx(unsigned short insn, struct pt_regs *regs) | ||
245 | { | ||
246 | int dest = REG1(insn); | ||
247 | unsigned int val, tmp; | ||
248 | |||
249 | val = tmp = get_reg(regs, dest); | ||
250 | val -= (unsigned int)get_reg(regs, REG2(insn)); | ||
251 | val -= regs->psw & PSW_BC ? 1 : 0; | ||
252 | set_reg(regs, dest, val); | ||
253 | |||
254 | /* C bit set */ | ||
255 | if (val > tmp) | ||
256 | regs->psw |= PSW_BC; | ||
257 | else | ||
258 | regs->psw &= ~(PSW_BC); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int emu_xor(unsigned short insn, struct pt_regs *regs) | ||
264 | { | ||
265 | int dest = REG1(insn); | ||
266 | unsigned int val; | ||
267 | |||
268 | val = (unsigned int)get_reg(regs, dest); | ||
269 | val ^= (unsigned int)get_reg(regs, REG2(insn)); | ||
270 | set_reg(regs, dest, val); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int emu_mul(unsigned short insn, struct pt_regs *regs) | ||
276 | { | ||
277 | int dest = REG1(insn); | ||
278 | int reg1, reg2; | ||
279 | |||
280 | reg1 = get_reg(regs, dest); | ||
281 | reg2 = get_reg(regs, REG2(insn)); | ||
282 | |||
283 | __asm__ __volatile__ ( | ||
284 | "mul %0, %1; \n\t" | ||
285 | : "+r" (reg1) : "r" (reg2) | ||
286 | ); | ||
287 | |||
288 | set_reg(regs, dest, reg1); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int emu_mullo_a0(unsigned short insn, struct pt_regs *regs) | ||
294 | { | ||
295 | int reg1, reg2; | ||
296 | |||
297 | reg1 = get_reg(regs, REG1(insn)); | ||
298 | reg2 = get_reg(regs, REG2(insn)); | ||
299 | |||
300 | __asm__ __volatile__ ( | ||
301 | "mullo %0, %1, a0; \n\t" | ||
302 | "mvfachi %0, a0; \n\t" | ||
303 | "mvfaclo %1, a0; \n\t" | ||
304 | : "+r" (reg1), "+r" (reg2) | ||
305 | ); | ||
306 | |||
307 | regs->acc0h = reg1; | ||
308 | regs->acc0l = reg2; | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int emu_mullo_a1(unsigned short insn, struct pt_regs *regs) | ||
314 | { | ||
315 | int reg1, reg2; | ||
316 | |||
317 | reg1 = get_reg(regs, REG1(insn)); | ||
318 | reg2 = get_reg(regs, REG2(insn)); | ||
319 | |||
320 | __asm__ __volatile__ ( | ||
321 | "mullo %0, %1, a0; \n\t" | ||
322 | "mvfachi %0, a0; \n\t" | ||
323 | "mvfaclo %1, a0; \n\t" | ||
324 | : "+r" (reg1), "+r" (reg2) | ||
325 | ); | ||
326 | |||
327 | regs->acc1h = reg1; | ||
328 | regs->acc1l = reg2; | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int emu_mvfacmi_a0(unsigned short insn, struct pt_regs *regs) | ||
334 | { | ||
335 | unsigned long val; | ||
336 | |||
337 | val = (regs->acc0h << 16) | (regs->acc0l >> 16); | ||
338 | set_reg(regs, REG1(insn), (int)val); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int emu_mvfacmi_a1(unsigned short insn, struct pt_regs *regs) | ||
344 | { | ||
345 | unsigned long val; | ||
346 | |||
347 | val = (regs->acc1h << 16) | (regs->acc1l >> 16); | ||
348 | set_reg(regs, REG1(insn), (int)val); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int emu_m32r2(unsigned short insn, struct pt_regs *regs) | ||
354 | { | ||
355 | int res = -1; | ||
356 | |||
357 | if ((insn & 0x7fff) == ISA_NOP) /* nop */ | ||
358 | return 0; | ||
359 | |||
360 | switch(insn & 0x7000) { | ||
361 | case ISA_ADDI: /* addi Rdest, #imm8 */ | ||
362 | res = emu_addi(insn, regs); | ||
363 | break; | ||
364 | case ISA_LDI: /* ldi Rdest, #imm8 */ | ||
365 | res = emu_ldi(insn, regs); | ||
366 | break; | ||
367 | default: | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | if (!res) | ||
372 | return 0; | ||
373 | |||
374 | switch(insn & 0x70f0) { | ||
375 | case ISA_ADD: /* add Rdest, Rsrc */ | ||
376 | res = emu_add(insn, regs); | ||
377 | break; | ||
378 | case ISA_ADDX: /* addx Rdest, Rsrc */ | ||
379 | res = emu_addx(insn, regs); | ||
380 | break; | ||
381 | case ISA_AND: /* and Rdest, Rsrc */ | ||
382 | res = emu_and(insn, regs); | ||
383 | break; | ||
384 | case ISA_CMP: /* cmp Rsrc1, Rsrc2 */ | ||
385 | res = emu_cmp(insn, regs); | ||
386 | break; | ||
387 | case ISA_CMPEQ: /* cmpeq Rsrc1, Rsrc2 */ | ||
388 | res = emu_cmpeq(insn, regs); | ||
389 | break; | ||
390 | case ISA_CMPU: /* cmpu Rsrc1, Rsrc2 */ | ||
391 | res = emu_cmpu(insn, regs); | ||
392 | break; | ||
393 | case ISA_CMPZ: /* cmpz Rsrc */ | ||
394 | res = emu_cmpz(insn, regs); | ||
395 | break; | ||
396 | case ISA_MV: /* mv Rdest, Rsrc */ | ||
397 | res = emu_mv(insn, regs); | ||
398 | break; | ||
399 | case ISA_NEG: /* neg Rdest, Rsrc */ | ||
400 | res = emu_neg(insn, regs); | ||
401 | break; | ||
402 | case ISA_NOT: /* not Rdest, Rsrc */ | ||
403 | res = emu_not(insn, regs); | ||
404 | break; | ||
405 | case ISA_OR: /* or Rdest, Rsrc */ | ||
406 | res = emu_or(insn, regs); | ||
407 | break; | ||
408 | case ISA_SUB: /* sub Rdest, Rsrc */ | ||
409 | res = emu_sub(insn, regs); | ||
410 | break; | ||
411 | case ISA_SUBX: /* subx Rdest, Rsrc */ | ||
412 | res = emu_subx(insn, regs); | ||
413 | break; | ||
414 | case ISA_XOR: /* xor Rdest, Rsrc */ | ||
415 | res = emu_xor(insn, regs); | ||
416 | break; | ||
417 | case ISA_MUL: /* mul Rdest, Rsrc */ | ||
418 | res = emu_mul(insn, regs); | ||
419 | break; | ||
420 | case ISA_MULLO_A0: /* mullo Rsrc1, Rsrc2 */ | ||
421 | res = emu_mullo_a0(insn, regs); | ||
422 | break; | ||
423 | case ISA_MULLO_A1: /* mullo Rsrc1, Rsrc2 */ | ||
424 | res = emu_mullo_a1(insn, regs); | ||
425 | break; | ||
426 | default: | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | if (!res) | ||
431 | return 0; | ||
432 | |||
433 | switch(insn & 0x70ff) { | ||
434 | case ISA_MVFACMI_A0: /* mvfacmi Rdest */ | ||
435 | res = emu_mvfacmi_a0(insn, regs); | ||
436 | break; | ||
437 | case ISA_MVFACMI_A1: /* mvfacmi Rdest */ | ||
438 | res = emu_mvfacmi_a1(insn, regs); | ||
439 | break; | ||
440 | default: | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | return res; | ||
445 | } | ||
446 | |||
447 | #endif /* CONFIG_ISA_DUAL_ISSUE */ | ||
448 | |||
449 | /* | ||
450 | * ld : ?010 dest 1100 src | ||
451 | * 0010 dest 1110 src : ld Rdest, @Rsrc+ | ||
452 | * ldh : ?010 dest 1010 src | ||
453 | * lduh : ?010 dest 1011 src | ||
454 | * st : ?010 src1 0100 src2 | ||
455 | * 0010 src1 0110 src2 : st Rsrc1, @+Rsrc2 | ||
456 | * 0010 src1 0111 src2 : st Rsrc1, @-Rsrc2 | ||
457 | * sth : ?010 src1 0010 src2 | ||
458 | */ | ||
459 | |||
460 | static int insn_check(unsigned long insn, struct pt_regs *regs, | ||
461 | unsigned char **ucp) | ||
462 | { | ||
463 | int res = 0; | ||
464 | |||
465 | /* | ||
466 | * 32bit insn | ||
467 | * ld Rdest, @(disp16, Rsrc) | ||
468 | * st Rdest, @(disp16, Rsrc) | ||
469 | */ | ||
470 | if (insn & 0x80000000) { /* 32bit insn */ | ||
471 | *ucp += (short)(insn & 0x0000ffff); | ||
472 | regs->bpc += 4; | ||
473 | } else { /* 16bit insn */ | ||
474 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
475 | /* parallel exec check */ | ||
476 | if (!(regs->bpc & 0x2) && insn & 0x8000) { | ||
477 | res = emu_m32r2((unsigned short)insn, regs); | ||
478 | regs->bpc += 4; | ||
479 | } else | ||
480 | #endif /* CONFIG_ISA_DUAL_ISSUE */ | ||
481 | regs->bpc += 2; | ||
482 | } | ||
483 | |||
484 | return res; | ||
485 | } | ||
486 | |||
487 | static int emu_ld(unsigned long insn32, struct pt_regs *regs) | ||
488 | { | ||
489 | unsigned char *ucp; | ||
490 | unsigned long val; | ||
491 | unsigned short insn16; | ||
492 | int size, src; | ||
493 | |||
494 | insn16 = insn32 >> 16; | ||
495 | src = REG2(insn16); | ||
496 | ucp = (unsigned char *)get_reg(regs, src); | ||
497 | |||
498 | if (insn_check(insn32, regs, &ucp)) | ||
499 | return -1; | ||
500 | |||
501 | size = insn16 & 0x0040 ? 4 : 2; | ||
502 | if (copy_from_user(&val, ucp, size)) | ||
503 | return -1; | ||
504 | |||
505 | if (size == 2) | ||
506 | val >>= 16; | ||
507 | |||
508 | /* ldh sign check */ | ||
509 | if ((insn16 & 0x00f0) == 0x00a0 && (val & 0x8000)) | ||
510 | val |= 0xffff0000; | ||
511 | |||
512 | set_reg(regs, REG1(insn16), val); | ||
513 | |||
514 | /* ld increment check */ | ||
515 | if ((insn16 & 0xf0f0) == ISA_LD2) /* ld Rdest, @Rsrc+ */ | ||
516 | set_reg(regs, src, (unsigned long)(ucp + 4)); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int emu_st(unsigned long insn32, struct pt_regs *regs) | ||
522 | { | ||
523 | unsigned char *ucp; | ||
524 | unsigned long val; | ||
525 | unsigned short insn16; | ||
526 | int size, src2; | ||
527 | |||
528 | insn16 = insn32 >> 16; | ||
529 | src2 = REG2(insn16); | ||
530 | |||
531 | ucp = (unsigned char *)get_reg(regs, src2); | ||
532 | |||
533 | if (insn_check(insn32, regs, &ucp)) | ||
534 | return -1; | ||
535 | |||
536 | size = insn16 & 0x0040 ? 4 : 2; | ||
537 | val = get_reg(regs, REG1(insn16)); | ||
538 | if (size == 2) | ||
539 | val <<= 16; | ||
540 | |||
541 | /* st inc/dec check */ | ||
542 | if ((insn16 & 0xf0e0) == 0x2060) { | ||
543 | if (insn16 & 0x0010) | ||
544 | ucp -= 4; | ||
545 | else | ||
546 | ucp += 4; | ||
547 | |||
548 | set_reg(regs, src2, (unsigned long)ucp); | ||
549 | } | ||
550 | |||
551 | if (copy_to_user(ucp, &val, size)) | ||
552 | return -1; | ||
553 | |||
554 | /* sth inc check */ | ||
555 | if ((insn16 & 0xf0f0) == ISA_STH2) { | ||
556 | ucp += 2; | ||
557 | set_reg(regs, src2, (unsigned long)ucp); | ||
558 | } | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | int handle_unaligned_access(unsigned long insn32, struct pt_regs *regs) | ||
564 | { | ||
565 | unsigned short insn16; | ||
566 | int res; | ||
567 | |||
568 | insn16 = insn32 >> 16; | ||
569 | |||
570 | /* ld or st check */ | ||
571 | if ((insn16 & 0x7000) != 0x2000) | ||
572 | return -1; | ||
573 | |||
574 | /* insn alignment check */ | ||
575 | if ((insn16 & 0x8000) && (regs->bpc & 3)) | ||
576 | return -1; | ||
577 | |||
578 | if (insn16 & 0x0080) /* ld */ | ||
579 | res = emu_ld(insn32, regs); | ||
580 | else /* st */ | ||
581 | res = emu_st(insn32, regs); | ||
582 | |||
583 | return res; | ||
584 | } | ||
585 | |||
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S new file mode 100644 index 000000000000..dddbf6b5ed2c --- /dev/null +++ b/arch/m32r/kernel/entry.S | |||
@@ -0,0 +1,1000 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/entry.S | ||
3 | * | ||
4 | * Copyright (c) 2001, 2002 Hirokazu Takata, Hitoshi Yamamoto, H. Kondo | ||
5 | * Copyright (c) 2003 Hitoshi Yamamoto | ||
6 | * Copyright (c) 2004 Hirokazu Takata <takata at linux-m32r.org> | ||
7 | * | ||
8 | * Taken from i386 version. | ||
9 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * entry.S contains the system-call and fault low-level handling routines. | ||
14 | * This also contains the timer-interrupt handler, as well as all interrupts | ||
15 | * and faults that can result in a task-switch. | ||
16 | * | ||
17 | * NOTE: This code handles signal-recognition, which happens every time | ||
18 | * after a timer-interrupt and after each system call. | ||
19 | * | ||
20 | * Stack layout in 'ret_from_system_call': | ||
21 | * ptrace needs to have all regs on the stack. | ||
22 | * if the order here is changed, it needs to be | ||
23 | * updated in fork.c:copy_process, signal.c:do_signal, | ||
24 | * ptrace.c and ptrace.h | ||
25 | * | ||
26 | * M32Rx/M32R2 M32R | ||
27 | * @(sp) - r4 ditto | ||
28 | * @(0x04,sp) - r5 ditto | ||
29 | * @(0x08,sp) - r6 ditto | ||
30 | * @(0x0c,sp) - *pt_regs ditto | ||
31 | * @(0x10,sp) - r0 ditto | ||
32 | * @(0x14,sp) - r1 ditto | ||
33 | * @(0x18,sp) - r2 ditto | ||
34 | * @(0x1c,sp) - r3 ditto | ||
35 | * @(0x20,sp) - r7 ditto | ||
36 | * @(0x24,sp) - r8 ditto | ||
37 | * @(0x28,sp) - r9 ditto | ||
38 | * @(0x2c,sp) - r10 ditto | ||
39 | * @(0x30,sp) - r11 ditto | ||
40 | * @(0x34,sp) - r12 ditto | ||
41 | * @(0x38,sp) - syscall_nr ditto | ||
42 | * @(0x3c,sp) - acc0h @(0x3c,sp) - acch | ||
43 | * @(0x40,sp) - acc0l @(0x40,sp) - accl | ||
44 | * @(0x44,sp) - acc1h @(0x44,sp) - psw | ||
45 | * @(0x48,sp) - acc1l @(0x48,sp) - bpc | ||
46 | * @(0x4c,sp) - psw @(0x4c,sp) - bbpsw | ||
47 | * @(0x50,sp) - bpc @(0x50,sp) - bbpc | ||
48 | * @(0x54,sp) - bbpsw @(0x54,sp) - spu (cr3) | ||
49 | * @(0x58,sp) - bbpc @(0x58,sp) - fp (r13) | ||
50 | * @(0x5c,sp) - spu (cr3) @(0x5c,sp) - lr (r14) | ||
51 | * @(0x60,sp) - fp (r13) @(0x60,sp) - spi (cr12) | ||
52 | * @(0x64,sp) - lr (r14) @(0x64,sp) - orig_r0 | ||
53 | * @(0x68,sp) - spi (cr2) | ||
54 | * @(0x6c,sp) - orig_r0 | ||
55 | * | ||
56 | */ | ||
57 | |||
58 | #include <linux/config.h> | ||
59 | #include <linux/linkage.h> | ||
60 | #include <asm/irq.h> | ||
61 | #include <asm/unistd.h> | ||
62 | #include <asm/assembler.h> | ||
63 | #include <asm/thread_info.h> | ||
64 | #include <asm/errno.h> | ||
65 | #include <asm/segment.h> | ||
66 | #include <asm/smp.h> | ||
67 | #include <asm/page.h> | ||
68 | #include <asm/m32r.h> | ||
69 | #include <asm/mmu_context.h> | ||
70 | |||
71 | #if !defined(CONFIG_MMU) | ||
72 | #define sys_madvise sys_ni_syscall | ||
73 | #define sys_readahead sys_ni_syscall | ||
74 | #define sys_mprotect sys_ni_syscall | ||
75 | #define sys_msync sys_ni_syscall | ||
76 | #define sys_mlock sys_ni_syscall | ||
77 | #define sys_munlock sys_ni_syscall | ||
78 | #define sys_mlockall sys_ni_syscall | ||
79 | #define sys_munlockall sys_ni_syscall | ||
80 | #define sys_mremap sys_ni_syscall | ||
81 | #define sys_mincore sys_ni_syscall | ||
82 | #define sys_remap_file_pages sys_ni_syscall | ||
83 | #endif /* CONFIG_MMU */ | ||
84 | |||
85 | #define R4(reg) @reg | ||
86 | #define R5(reg) @(0x04,reg) | ||
87 | #define R6(reg) @(0x08,reg) | ||
88 | #define PTREGS(reg) @(0x0C,reg) | ||
89 | #define R0(reg) @(0x10,reg) | ||
90 | #define R1(reg) @(0x14,reg) | ||
91 | #define R2(reg) @(0x18,reg) | ||
92 | #define R3(reg) @(0x1C,reg) | ||
93 | #define R7(reg) @(0x20,reg) | ||
94 | #define R8(reg) @(0x24,reg) | ||
95 | #define R9(reg) @(0x28,reg) | ||
96 | #define R10(reg) @(0x2C,reg) | ||
97 | #define R11(reg) @(0x30,reg) | ||
98 | #define R12(reg) @(0x34,reg) | ||
99 | #define SYSCALL_NR(reg) @(0x38,reg) | ||
100 | #if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) | ||
101 | #define ACC0H(reg) @(0x3C,reg) | ||
102 | #define ACC0L(reg) @(0x40,reg) | ||
103 | #define ACC1H(reg) @(0x44,reg) | ||
104 | #define ACC1L(reg) @(0x48,reg) | ||
105 | #define PSW(reg) @(0x4C,reg) | ||
106 | #define BPC(reg) @(0x50,reg) | ||
107 | #define BBPSW(reg) @(0x54,reg) | ||
108 | #define BBPC(reg) @(0x58,reg) | ||
109 | #define SPU(reg) @(0x5C,reg) | ||
110 | #define FP(reg) @(0x60,reg) /* FP = R13 */ | ||
111 | #define LR(reg) @(0x64,reg) | ||
112 | #define SP(reg) @(0x68,reg) | ||
113 | #define ORIG_R0(reg) @(0x6C,reg) | ||
114 | #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) | ||
115 | #define ACCH(reg) @(0x3C,reg) | ||
116 | #define ACCL(reg) @(0x40,reg) | ||
117 | #define PSW(reg) @(0x44,reg) | ||
118 | #define BPC(reg) @(0x48,reg) | ||
119 | #define BBPSW(reg) @(0x4C,reg) | ||
120 | #define BBPC(reg) @(0x50,reg) | ||
121 | #define SPU(reg) @(0x54,reg) | ||
122 | #define FP(reg) @(0x58,reg) /* FP = R13 */ | ||
123 | #define LR(reg) @(0x5C,reg) | ||
124 | #define SP(reg) @(0x60,reg) | ||
125 | #define ORIG_R0(reg) @(0x64,reg) | ||
126 | #else | ||
127 | #error unknown isa configuration | ||
128 | #endif | ||
129 | |||
130 | CF_MASK = 0x00000001 | ||
131 | TF_MASK = 0x00000100 | ||
132 | IF_MASK = 0x00000200 | ||
133 | DF_MASK = 0x00000400 | ||
134 | NT_MASK = 0x00004000 | ||
135 | VM_MASK = 0x00020000 | ||
136 | |||
137 | #ifdef CONFIG_PREEMPT | ||
138 | #define preempt_stop(x) CLI(x) | ||
139 | #else | ||
140 | #define preempt_stop(x) | ||
141 | #define resume_kernel restore_all | ||
142 | #endif | ||
143 | |||
144 | ENTRY(ret_from_fork) | ||
145 | ld r0, @sp+ | ||
146 | bl schedule_tail | ||
147 | GET_THREAD_INFO(r8) | ||
148 | bra syscall_exit | ||
149 | |||
150 | /* | ||
151 | * Return to user mode is not as complex as all this looks, | ||
152 | * but we want the default path for a system call return to | ||
153 | * go as quickly as possible which is why some of this is | ||
154 | * less clear than it otherwise should be. | ||
155 | */ | ||
156 | |||
157 | ; userspace resumption stub bypassing syscall exit tracing | ||
158 | ALIGN | ||
159 | ret_from_exception: | ||
160 | preempt_stop(r4) | ||
161 | ret_from_intr: | ||
162 | ld r4, PSW(sp) | ||
163 | #ifdef CONFIG_ISA_M32R2 | ||
164 | and3 r4, r4, #0x8800 ; check BSM and BPM bits | ||
165 | #else | ||
166 | and3 r4, r4, #0x8000 ; check BSM bit | ||
167 | #endif | ||
168 | beqz r4, resume_kernel | ||
169 | ENTRY(resume_userspace) | ||
170 | CLI(r4) ; make sure we don't miss an interrupt | ||
171 | ; setting need_resched or sigpending | ||
172 | ; between sampling and the iret | ||
173 | GET_THREAD_INFO(r8) | ||
174 | ld r9, @(TI_FLAGS, r8) | ||
175 | and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done on | ||
176 | ; int/exception return? | ||
177 | bnez r4, work_pending | ||
178 | bra restore_all | ||
179 | |||
180 | #ifdef CONFIG_PREEMPT | ||
181 | ENTRY(resume_kernel) | ||
182 | GET_THREAD_INFO(r8) | ||
183 | ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ? | ||
184 | bnez r9, restore_all | ||
185 | need_resched: | ||
186 | ld r9, @(TI_FLAGS, r8) ; need_resched set ? | ||
187 | and3 r4, r9, #_TIF_NEED_RESCHED | ||
188 | beqz r4, restore_all | ||
189 | ld r4, PSW(sp) ; interrupts off (exception path) ? | ||
190 | and3 r4, r4, #0x4000 | ||
191 | beqz r4, restore_all | ||
192 | LDIMM (r4, PREEMPT_ACTIVE) | ||
193 | st r4, @(TI_PRE_COUNT, r8) | ||
194 | STI(r4) | ||
195 | bl schedule | ||
196 | ldi r4, #0 | ||
197 | st r4, @(TI_PRE_COUNT, r8) | ||
198 | CLI(r4) | ||
199 | bra need_resched | ||
200 | #endif | ||
201 | |||
202 | ; system call handler stub | ||
203 | ENTRY(system_call) | ||
204 | SWITCH_TO_KERNEL_STACK | ||
205 | SAVE_ALL | ||
206 | STI(r4) ; Enable interrupt | ||
207 | st sp, PTREGS(sp) ; implicit pt_regs parameter | ||
208 | cmpui r7, #NR_syscalls | ||
209 | bnc syscall_badsys | ||
210 | st r7, SYSCALL_NR(sp) ; syscall_nr | ||
211 | ; system call tracing in operation | ||
212 | GET_THREAD_INFO(r8) | ||
213 | ld r9, @(TI_FLAGS, r8) | ||
214 | and3 r4, r9, #_TIF_SYSCALL_TRACE | ||
215 | bnez r4, syscall_trace_entry | ||
216 | syscall_call: | ||
217 | slli r7, #2 ; table jump for the system call | ||
218 | LDIMM (r4, sys_call_table) | ||
219 | add r7, r4 | ||
220 | ld r7, @r7 | ||
221 | jl r7 ; execute system call | ||
222 | st r0, R0(sp) ; save the return value | ||
223 | syscall_exit: | ||
224 | CLI(r4) ; make sure we don't miss an interrupt | ||
225 | ; setting need_resched or sigpending | ||
226 | ; between sampling and the iret | ||
227 | ld r9, @(TI_FLAGS, r8) | ||
228 | and3 r4, r9, #_TIF_ALLWORK_MASK ; current->work | ||
229 | bnez r4, syscall_exit_work | ||
230 | restore_all: | ||
231 | RESTORE_ALL | ||
232 | |||
233 | # perform work that needs to be done immediately before resumption | ||
234 | # r9 : frags | ||
235 | ALIGN | ||
236 | work_pending: | ||
237 | and3 r4, r9, #_TIF_NEED_RESCHED | ||
238 | beqz r4, work_notifysig | ||
239 | work_resched: | ||
240 | bl schedule | ||
241 | CLI(r4) ; make sure we don't miss an interrupt | ||
242 | ; setting need_resched or sigpending | ||
243 | ; between sampling and the iret | ||
244 | ld r9, @(TI_FLAGS, r8) | ||
245 | and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done other | ||
246 | ; than syscall tracing? | ||
247 | beqz r4, restore_all | ||
248 | and3 r4, r4, #_TIF_NEED_RESCHED | ||
249 | bnez r4, work_resched | ||
250 | |||
251 | work_notifysig: ; deal with pending signals and | ||
252 | ; notify-resume requests | ||
253 | mv r0, sp ; arg1 : struct pt_regs *regs | ||
254 | ldi r1, #0 ; arg2 : sigset_t *oldset | ||
255 | mv r2, r9 ; arg3 : __u32 thread_info_flags | ||
256 | bl do_notify_resume | ||
257 | bra restore_all | ||
258 | |||
259 | ; perform syscall exit tracing | ||
260 | ALIGN | ||
261 | syscall_trace_entry: | ||
262 | ldi r4, #-ENOSYS | ||
263 | st r4, R0(sp) | ||
264 | bl do_syscall_trace | ||
265 | ld r0, ORIG_R0(sp) | ||
266 | ld r1, R1(sp) | ||
267 | ld r2, R2(sp) | ||
268 | ld r3, R3(sp) | ||
269 | ld r4, R4(sp) | ||
270 | ld r5, R5(sp) | ||
271 | ld r6, R6(sp) | ||
272 | ld r7, SYSCALL_NR(sp) | ||
273 | cmpui r7, #NR_syscalls | ||
274 | bc syscall_call | ||
275 | bra syscall_exit | ||
276 | |||
277 | ; perform syscall exit tracing | ||
278 | ALIGN | ||
279 | syscall_exit_work: | ||
280 | ld r9, @(TI_FLAGS, r8) | ||
281 | and3 r4, r9, #_TIF_SYSCALL_TRACE | ||
282 | beqz r4, work_pending | ||
283 | STI(r4) ; could let do_syscall_trace() call | ||
284 | ; schedule() instead | ||
285 | bl do_syscall_trace | ||
286 | bra resume_userspace | ||
287 | |||
288 | ALIGN | ||
289 | syscall_fault: | ||
290 | SAVE_ALL | ||
291 | GET_THREAD_INFO(r8) | ||
292 | ldi r4, #-EFAULT | ||
293 | st r4, R0(sp) | ||
294 | bra resume_userspace | ||
295 | |||
296 | ALIGN | ||
297 | syscall_badsys: | ||
298 | ldi r4, #-ENOSYS | ||
299 | st r4, R0(sp) | ||
300 | bra resume_userspace | ||
301 | |||
302 | .global eit_vector | ||
303 | |||
304 | .equ ei_vec_table, eit_vector + 0x0200 | ||
305 | |||
306 | /* | ||
307 | * EI handler routine | ||
308 | */ | ||
309 | ENTRY(ei_handler) | ||
310 | #if defined(CONFIG_CHIP_M32700) | ||
311 | SWITCH_TO_KERNEL_STACK | ||
312 | ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI). | ||
313 | #endif | ||
314 | SAVE_ALL | ||
315 | mv r1, sp ; arg1(regs) | ||
316 | #if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ | ||
317 | || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ | ||
318 | || defined(CONFIG_CHIP_OPSP) | ||
319 | |||
320 | ; GET_ICU_STATUS; | ||
321 | seth r0, #shigh(M32R_ICU_ISTS_ADDR) | ||
322 | ld r0, @(low(M32R_ICU_ISTS_ADDR),r0) | ||
323 | st r0, @-sp | ||
324 | #if defined(CONFIG_SMP) | ||
325 | /* | ||
326 | * If IRQ == 0 --> Nothing to do, Not write IMASK | ||
327 | * If IRQ == IPI --> Do IPI handler, Not write IMASK | ||
328 | * If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK | ||
329 | */ | ||
330 | slli r0, #4 | ||
331 | srli r0, #24 ; r0(irq_num<<2) | ||
332 | ;; IRQ exist check | ||
333 | #if defined(CONFIG_CHIP_M32700) | ||
334 | /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ | ||
335 | beqz r0, 3f ; if (!irq_num) goto exit | ||
336 | #else | ||
337 | beqz r0, 1f ; if (!irq_num) goto exit | ||
338 | #endif /* WORKAROUND */ | ||
339 | ;; IPI check | ||
340 | cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check | ||
341 | bc 2f | ||
342 | cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check | ||
343 | bnc 2f | ||
344 | LDIMM (r2, ei_vec_table) | ||
345 | add r2, r0 | ||
346 | ld r2, @r2 | ||
347 | beqz r2, 1f ; if (no IPI handler) goto exit | ||
348 | mv r0, r1 ; arg0(regs) | ||
349 | jl r2 | ||
350 | .fillinsn | ||
351 | 1: | ||
352 | addi sp, #4 | ||
353 | bra ret_to_intr | ||
354 | #if defined(CONFIG_CHIP_M32700) | ||
355 | /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */ | ||
356 | .fillinsn | ||
357 | 3: | ||
358 | ld24 r14, #0x00070000 | ||
359 | seth r0, #shigh(M32R_ICU_IMASK_ADDR) | ||
360 | st r14, @(low(M32R_ICU_IMASK_ADDR), r0) | ||
361 | addi sp, #4 | ||
362 | bra ret_to_intr | ||
363 | #endif /* WORKAROUND */ | ||
364 | ;; do_IRQ | ||
365 | .fillinsn | ||
366 | 2: | ||
367 | srli r0, #2 | ||
368 | #if defined(CONFIG_PLAT_USRV) | ||
369 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
370 | bnez r2, 9f | ||
371 | ; read ICU status register of PLD | ||
372 | seth r0, #high(PLD_ICUISTS) | ||
373 | or3 r0, r0, #low(PLD_ICUISTS) | ||
374 | lduh r0, @r0 | ||
375 | slli r0, #21 | ||
376 | srli r0, #27 ; ISN | ||
377 | addi r0, #(M32700UT_PLD_IRQ_BASE) | ||
378 | .fillinsn | ||
379 | 9: | ||
380 | #elif defined(CONFIG_PLAT_M32700UT) | ||
381 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
382 | bnez r2, check_int0 | ||
383 | ; read ICU status register of PLD | ||
384 | seth r0, #high(PLD_ICUISTS) | ||
385 | or3 r0, r0, #low(PLD_ICUISTS) | ||
386 | lduh r0, @r0 | ||
387 | slli r0, #21 | ||
388 | srli r0, #27 ; ISN | ||
389 | addi r0, #(M32700UT_PLD_IRQ_BASE) | ||
390 | bra check_end | ||
391 | .fillinsn | ||
392 | check_int0: | ||
393 | add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt | ||
394 | bnez r2, check_int2 | ||
395 | ; read ICU status of LAN-board | ||
396 | seth r0, #high(M32700UT_LAN_ICUISTS) | ||
397 | or3 r0, r0, #low(M32700UT_LAN_ICUISTS) | ||
398 | lduh r0, @r0 | ||
399 | slli r0, #21 | ||
400 | srli r0, #27 ; ISN | ||
401 | add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) | ||
402 | bra check_end | ||
403 | .fillinsn | ||
404 | check_int2: | ||
405 | add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt | ||
406 | bnez r2, check_end | ||
407 | ; read ICU status of LCD-board | ||
408 | seth r0, #high(M32700UT_LCD_ICUISTS) | ||
409 | or3 r0, r0, #low(M32700UT_LCD_ICUISTS) | ||
410 | lduh r0, @r0 | ||
411 | slli r0, #21 | ||
412 | srli r0, #27 ; ISN | ||
413 | add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) | ||
414 | bra check_end | ||
415 | .fillinsn | ||
416 | check_end: | ||
417 | #elif defined(CONFIG_PLAT_OPSPUT) | ||
418 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
419 | bnez r2, check_int0 | ||
420 | ; read ICU status register of PLD | ||
421 | seth r0, #high(PLD_ICUISTS) | ||
422 | or3 r0, r0, #low(PLD_ICUISTS) | ||
423 | lduh r0, @r0 | ||
424 | slli r0, #21 | ||
425 | srli r0, #27 ; ISN | ||
426 | addi r0, #(OPSPUT_PLD_IRQ_BASE) | ||
427 | bra check_end | ||
428 | .fillinsn | ||
429 | check_int0: | ||
430 | add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt | ||
431 | bnez r2, check_int2 | ||
432 | ; read ICU status of LAN-board | ||
433 | seth r0, #high(OPSPUT_LAN_ICUISTS) | ||
434 | or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) | ||
435 | lduh r0, @r0 | ||
436 | slli r0, #21 | ||
437 | srli r0, #27 ; ISN | ||
438 | add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) | ||
439 | bra check_end | ||
440 | .fillinsn | ||
441 | check_int2: | ||
442 | add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt | ||
443 | bnez r2, check_end | ||
444 | ; read ICU status of LCD-board | ||
445 | seth r0, #high(OPSPUT_LCD_ICUISTS) | ||
446 | or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) | ||
447 | lduh r0, @r0 | ||
448 | slli r0, #21 | ||
449 | srli r0, #27 ; ISN | ||
450 | add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) | ||
451 | bra check_end | ||
452 | .fillinsn | ||
453 | check_end: | ||
454 | #endif /* CONFIG_PLAT_OPSPUT */ | ||
455 | bl do_IRQ ; r0(irq), r1(regs) | ||
456 | #else /* not CONFIG_SMP */ | ||
457 | srli r0, #22 ; r0(irq) | ||
458 | #if defined(CONFIG_PLAT_USRV) | ||
459 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
460 | bnez r2, 1f | ||
461 | ; read ICU status register of PLD | ||
462 | seth r0, #high(PLD_ICUISTS) | ||
463 | or3 r0, r0, #low(PLD_ICUISTS) | ||
464 | lduh r0, @r0 | ||
465 | slli r0, #21 | ||
466 | srli r0, #27 ; ISN | ||
467 | addi r0, #(M32700UT_PLD_IRQ_BASE) | ||
468 | .fillinsn | ||
469 | 1: | ||
470 | #elif defined(CONFIG_PLAT_M32700UT) | ||
471 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
472 | bnez r2, check_int0 | ||
473 | ; read ICU status register of PLD | ||
474 | seth r0, #high(PLD_ICUISTS) | ||
475 | or3 r0, r0, #low(PLD_ICUISTS) | ||
476 | lduh r0, @r0 | ||
477 | slli r0, #21 | ||
478 | srli r0, #27 ; ISN | ||
479 | addi r0, #(M32700UT_PLD_IRQ_BASE) | ||
480 | bra check_end | ||
481 | .fillinsn | ||
482 | check_int0: | ||
483 | add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt | ||
484 | bnez r2, check_int2 | ||
485 | ; read ICU status of LAN-board | ||
486 | seth r0, #high(M32700UT_LAN_ICUISTS) | ||
487 | or3 r0, r0, #low(M32700UT_LAN_ICUISTS) | ||
488 | lduh r0, @r0 | ||
489 | slli r0, #21 | ||
490 | srli r0, #27 ; ISN | ||
491 | add3 r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE) | ||
492 | bra check_end | ||
493 | .fillinsn | ||
494 | check_int2: | ||
495 | add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt | ||
496 | bnez r2, check_end | ||
497 | ; read ICU status of LCD-board | ||
498 | seth r0, #high(M32700UT_LCD_ICUISTS) | ||
499 | or3 r0, r0, #low(M32700UT_LCD_ICUISTS) | ||
500 | lduh r0, @r0 | ||
501 | slli r0, #21 | ||
502 | srli r0, #27 ; ISN | ||
503 | add3 r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE) | ||
504 | bra check_end | ||
505 | .fillinsn | ||
506 | check_end: | ||
507 | #elif defined(CONFIG_PLAT_OPSPUT) | ||
508 | add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt | ||
509 | bnez r2, check_int0 | ||
510 | ; read ICU status register of PLD | ||
511 | seth r0, #high(PLD_ICUISTS) | ||
512 | or3 r0, r0, #low(PLD_ICUISTS) | ||
513 | lduh r0, @r0 | ||
514 | slli r0, #21 | ||
515 | srli r0, #27 ; ISN | ||
516 | addi r0, #(OPSPUT_PLD_IRQ_BASE) | ||
517 | bra check_end | ||
518 | .fillinsn | ||
519 | check_int0: | ||
520 | add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt | ||
521 | bnez r2, check_int2 | ||
522 | ; read ICU status of LAN-board | ||
523 | seth r0, #high(OPSPUT_LAN_ICUISTS) | ||
524 | or3 r0, r0, #low(OPSPUT_LAN_ICUISTS) | ||
525 | lduh r0, @r0 | ||
526 | slli r0, #21 | ||
527 | srli r0, #27 ; ISN | ||
528 | add3 r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE) | ||
529 | bra check_end | ||
530 | .fillinsn | ||
531 | check_int2: | ||
532 | add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt | ||
533 | bnez r2, check_end | ||
534 | ; read ICU status of LCD-board | ||
535 | seth r0, #high(OPSPUT_LCD_ICUISTS) | ||
536 | or3 r0, r0, #low(OPSPUT_LCD_ICUISTS) | ||
537 | lduh r0, @r0 | ||
538 | slli r0, #21 | ||
539 | srli r0, #27 ; ISN | ||
540 | add3 r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE) | ||
541 | bra check_end | ||
542 | .fillinsn | ||
543 | check_end: | ||
544 | #endif /* CONFIG_PLAT_OPSPUT */ | ||
545 | bl do_IRQ | ||
546 | #endif /* CONFIG_SMP */ | ||
547 | ld r14, @sp+ | ||
548 | seth r0, #shigh(M32R_ICU_IMASK_ADDR) | ||
549 | st r14, @(low(M32R_ICU_IMASK_ADDR),r0) | ||
550 | #else | ||
551 | #error no chip configuration | ||
552 | #endif | ||
553 | ret_to_intr: | ||
554 | bra ret_from_intr | ||
555 | |||
556 | /* | ||
557 | * Default EIT handler | ||
558 | */ | ||
559 | ALIGN | ||
560 | int_msg: | ||
561 | .asciz "Unknown interrupt\n" | ||
562 | .byte 0 | ||
563 | |||
564 | ENTRY(default_eit_handler) | ||
565 | push r0 | ||
566 | mvfc r0, psw | ||
567 | push r1 | ||
568 | push r2 | ||
569 | push r3 | ||
570 | push r0 | ||
571 | LDIMM (r0, __KERNEL_DS) | ||
572 | mv r0, r1 | ||
573 | mv r0, r2 | ||
574 | LDIMM (r0, int_msg) | ||
575 | bl printk | ||
576 | pop r0 | ||
577 | pop r3 | ||
578 | pop r2 | ||
579 | pop r1 | ||
580 | mvtc r0, psw | ||
581 | pop r0 | ||
582 | infinit: | ||
583 | bra infinit | ||
584 | |||
585 | #ifdef CONFIG_MMU | ||
586 | /* | ||
587 | * Access Exception handler | ||
588 | */ | ||
589 | ENTRY(ace_handler) | ||
590 | SWITCH_TO_KERNEL_STACK | ||
591 | SAVE_ALL | ||
592 | |||
593 | seth r2, #shigh(MMU_REG_BASE) /* Check status register */ | ||
594 | ld r4, @(low(MESTS_offset),r2) | ||
595 | st r4, @(low(MESTS_offset),r2) | ||
596 | srl3 r1, r4, #4 | ||
597 | #ifdef CONFIG_CHIP_M32700 | ||
598 | and3 r1, r1, #0x0000ffff | ||
599 | ; WORKAROUND: ignore TME bit for the M32700(TS1). | ||
600 | #endif /* CONFIG_CHIP_M32700 */ | ||
601 | beqz r1, inst | ||
602 | oprand: | ||
603 | ld r2, @(low(MDEVA_offset),r2) ; set address | ||
604 | srli r2, #12 | ||
605 | slli r2, #12 | ||
606 | srli r1, #1 | ||
607 | bra 1f | ||
608 | inst: | ||
609 | and3 r1, r4, #2 | ||
610 | srli r1, #1 | ||
611 | or3 r1, r1, #8 | ||
612 | mvfc r2, bpc ; set address | ||
613 | .fillinsn | ||
614 | 1: | ||
615 | mvfc r3, psw | ||
616 | mv r0, sp | ||
617 | and3 r3, r3, 0x800 | ||
618 | srli r3, #9 | ||
619 | or r1, r3 | ||
620 | /* | ||
621 | * do_page_fault(): | ||
622 | * r0 : struct pt_regs *regs | ||
623 | * r1 : unsigned long error-code | ||
624 | * r2 : unsigned long address | ||
625 | * error-code: | ||
626 | * +------+------+------+------+ | ||
627 | * | bit3 | bit2 | bit1 | bit0 | | ||
628 | * +------+------+------+------+ | ||
629 | * bit 3 == 0:means data, 1:means instruction | ||
630 | * bit 2 == 0:means kernel, 1:means user-mode | ||
631 | * bit 1 == 0:means read, 1:means write | ||
632 | * bit 0 == 0:means no page found 1:means protection fault | ||
633 | * | ||
634 | */ | ||
635 | bl do_page_fault | ||
636 | bra ret_from_intr | ||
637 | #endif /* CONFIG_MMU */ | ||
638 | |||
639 | |||
640 | ENTRY(alignment_check) | ||
641 | /* void alignment_check(int error_code) */ | ||
642 | SWITCH_TO_KERNEL_STACK | ||
643 | SAVE_ALL | ||
644 | ldi r1, #0x30 ; error_code | ||
645 | mv r0, sp ; pt_regs | ||
646 | bl do_alignment_check | ||
647 | error_code: | ||
648 | bra ret_from_exception | ||
649 | |||
650 | ENTRY(rie_handler) | ||
651 | /* void rie_handler(int error_code) */ | ||
652 | SWITCH_TO_KERNEL_STACK | ||
653 | SAVE_ALL | ||
654 | mvfc r0, bpc | ||
655 | ld r1, @r0 | ||
656 | seth r0, #0xa0f0 | ||
657 | st r1, @r0 | ||
658 | ldi r1, #0x20 ; error_code | ||
659 | mv r0, sp ; pt_regs | ||
660 | bl do_rie_handler | ||
661 | bra error_code | ||
662 | |||
663 | ENTRY(pie_handler) | ||
664 | /* void pie_handler(int error_code) */ | ||
665 | SWITCH_TO_KERNEL_STACK | ||
666 | SAVE_ALL | ||
667 | ldi r1, #0 ; error_code ; FIXME | ||
668 | mv r0, sp ; pt_regs | ||
669 | bl do_pie_handler | ||
670 | bra error_code | ||
671 | |||
672 | ENTRY(debug_trap) | ||
673 | .global withdraw_debug_trap | ||
674 | /* void debug_trap(void) */ | ||
675 | SWITCH_TO_KERNEL_STACK | ||
676 | SAVE_ALL | ||
677 | mv r0, sp ; pt_regs | ||
678 | bl withdraw_debug_trap | ||
679 | ldi r1, #0 ; error_code | ||
680 | mv r0, sp ; pt_regs | ||
681 | bl do_debug_trap | ||
682 | bra error_code | ||
683 | |||
684 | |||
685 | /* Cache flushing handler */ | ||
686 | ENTRY(cache_flushing_handler) | ||
687 | .global _flush_cache_all | ||
688 | /* void _flush_cache_all(void); */ | ||
689 | SWITCH_TO_KERNEL_STACK | ||
690 | push r0 | ||
691 | push r1 | ||
692 | push r2 | ||
693 | push r3 | ||
694 | push r4 | ||
695 | push r5 | ||
696 | push r6 | ||
697 | push r7 | ||
698 | push lr | ||
699 | bl _flush_cache_all | ||
700 | pop lr | ||
701 | pop r7 | ||
702 | pop r6 | ||
703 | pop r5 | ||
704 | pop r4 | ||
705 | pop r3 | ||
706 | pop r2 | ||
707 | pop r1 | ||
708 | pop r0 | ||
709 | rte | ||
710 | |||
711 | .data | ||
712 | ENTRY(sys_call_table) | ||
713 | .long sys_restart_syscall /* 0 - old "setup()" system call*/ | ||
714 | .long sys_exit | ||
715 | .long sys_fork | ||
716 | .long sys_read | ||
717 | .long sys_write | ||
718 | .long sys_open /* 5 */ | ||
719 | .long sys_close | ||
720 | .long sys_waitpid | ||
721 | .long sys_creat | ||
722 | .long sys_link | ||
723 | .long sys_unlink /* 10 */ | ||
724 | .long sys_execve | ||
725 | .long sys_chdir | ||
726 | .long sys_time | ||
727 | .long sys_mknod | ||
728 | .long sys_chmod /* 15 */ | ||
729 | .long sys_ni_syscall /* lchown16 syscall holder */ | ||
730 | .long sys_ni_syscall /* old break syscall holder */ | ||
731 | .long sys_ni_syscall /* old stat syscall holder */ | ||
732 | .long sys_lseek | ||
733 | .long sys_getpid /* 20 */ | ||
734 | .long sys_mount | ||
735 | .long sys_oldumount | ||
736 | .long sys_ni_syscall /* setuid16 syscall holder */ | ||
737 | .long sys_ni_syscall /* getuid16 syscall holder */ | ||
738 | .long sys_stime /* 25 */ | ||
739 | .long sys_ptrace | ||
740 | .long sys_alarm | ||
741 | .long sys_ni_syscall /* old fstat syscall holder */ | ||
742 | .long sys_pause | ||
743 | .long sys_utime /* 30 */ | ||
744 | .long sys_ni_syscall /* old stty syscall holder */ | ||
745 | .long sys_cachectl /* for M32R */ /* old gtty syscall holder */ | ||
746 | .long sys_access | ||
747 | .long sys_ni_syscall /* nice syscall holder */ | ||
748 | .long sys_ni_syscall /* 35 - old ftime syscall holder */ | ||
749 | .long sys_sync | ||
750 | .long sys_kill | ||
751 | .long sys_rename | ||
752 | .long sys_mkdir | ||
753 | .long sys_rmdir /* 40 */ | ||
754 | .long sys_dup | ||
755 | .long sys_pipe | ||
756 | .long sys_times | ||
757 | .long sys_ni_syscall /* old prof syscall holder */ | ||
758 | .long sys_brk /* 45 */ | ||
759 | .long sys_ni_syscall /* setgid16 syscall holder */ | ||
760 | .long sys_getgid /* will be unused */ | ||
761 | .long sys_ni_syscall /* signal syscall holder */ | ||
762 | .long sys_ni_syscall /* geteuid16 syscall holder */ | ||
763 | .long sys_ni_syscall /* 50 - getegid16 syscall holder */ | ||
764 | .long sys_acct | ||
765 | .long sys_umount /* recycled never used phys() */ | ||
766 | .long sys_ni_syscall /* old lock syscall holder */ | ||
767 | .long sys_ioctl | ||
768 | .long sys_fcntl /* 55 - will be unused */ | ||
769 | .long sys_ni_syscall /* mpx syscall holder */ | ||
770 | .long sys_setpgid | ||
771 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
772 | .long sys_ni_syscall /* sys_olduname */ | ||
773 | .long sys_umask /* 60 */ | ||
774 | .long sys_chroot | ||
775 | .long sys_ustat | ||
776 | .long sys_dup2 | ||
777 | .long sys_getppid | ||
778 | .long sys_getpgrp /* 65 */ | ||
779 | .long sys_setsid | ||
780 | .long sys_ni_syscall /* sigaction syscall holder */ | ||
781 | .long sys_ni_syscall /* sgetmask syscall holder */ | ||
782 | .long sys_ni_syscall /* ssetmask syscall holder */ | ||
783 | .long sys_ni_syscall /* 70 - setreuid16 syscall holder */ | ||
784 | .long sys_ni_syscall /* setregid16 syscall holder */ | ||
785 | .long sys_ni_syscall /* sigsuspend syscall holder */ | ||
786 | .long sys_ni_syscall /* sigpending syscall holder */ | ||
787 | .long sys_sethostname | ||
788 | .long sys_setrlimit /* 75 */ | ||
789 | .long sys_getrlimit/*will be unused*/ | ||
790 | .long sys_getrusage | ||
791 | .long sys_gettimeofday | ||
792 | .long sys_settimeofday | ||
793 | .long sys_ni_syscall /* 80 - getgroups16 syscall holder */ | ||
794 | .long sys_ni_syscall /* setgroups16 syscall holder */ | ||
795 | .long sys_ni_syscall /* sys_oldselect */ | ||
796 | .long sys_symlink | ||
797 | .long sys_ni_syscall /* old lstat syscall holder */ | ||
798 | .long sys_readlink /* 85 */ | ||
799 | .long sys_uselib | ||
800 | .long sys_swapon | ||
801 | .long sys_reboot | ||
802 | .long sys_ni_syscall /* readdir syscall holder */ | ||
803 | .long sys_ni_syscall /* 90 - old_mmap syscall holder */ | ||
804 | .long sys_munmap | ||
805 | .long sys_truncate | ||
806 | .long sys_ftruncate | ||
807 | .long sys_fchmod | ||
808 | .long sys_ni_syscall /* 95 - fchwon16 syscall holder */ | ||
809 | .long sys_getpriority | ||
810 | .long sys_setpriority | ||
811 | .long sys_ni_syscall /* old profil syscall holder */ | ||
812 | .long sys_statfs | ||
813 | .long sys_fstatfs /* 100 */ | ||
814 | .long sys_ni_syscall /* ioperm syscall holder */ | ||
815 | .long sys_socketcall | ||
816 | .long sys_syslog | ||
817 | .long sys_setitimer | ||
818 | .long sys_getitimer /* 105 */ | ||
819 | .long sys_newstat | ||
820 | .long sys_newlstat | ||
821 | .long sys_newfstat | ||
822 | .long sys_ni_syscall /* old uname syscall holder */ | ||
823 | .long sys_ni_syscall /* 110 - iopl syscall holder */ | ||
824 | .long sys_vhangup | ||
825 | .long sys_ni_syscall /* idle syscall holder */ | ||
826 | .long sys_ni_syscall /* vm86old syscall holder */ | ||
827 | .long sys_wait4 | ||
828 | .long sys_swapoff /* 115 */ | ||
829 | .long sys_sysinfo | ||
830 | .long sys_ipc | ||
831 | .long sys_fsync | ||
832 | .long sys_ni_syscall /* sigreturn syscall holder */ | ||
833 | .long sys_clone /* 120 */ | ||
834 | .long sys_setdomainname | ||
835 | .long sys_newuname | ||
836 | .long sys_ni_syscall /* modify_ldt syscall holder */ | ||
837 | .long sys_adjtimex | ||
838 | .long sys_mprotect /* 125 */ | ||
839 | .long sys_ni_syscall /* sigprocmask syscall holder */ | ||
840 | .long sys_ni_syscall /* create_module syscall holder */ | ||
841 | .long sys_init_module | ||
842 | .long sys_delete_module | ||
843 | .long sys_ni_syscall /* 130 - get_kernel_syms */ | ||
844 | .long sys_quotactl | ||
845 | .long sys_getpgid | ||
846 | .long sys_fchdir | ||
847 | .long sys_bdflush | ||
848 | .long sys_sysfs /* 135 */ | ||
849 | .long sys_personality | ||
850 | .long sys_ni_syscall /* afs_syscall syscall holder */ | ||
851 | .long sys_ni_syscall /* setfsuid16 syscall holder */ | ||
852 | .long sys_ni_syscall /* setfsgid16 syscall holder */ | ||
853 | .long sys_llseek /* 140 */ | ||
854 | .long sys_getdents | ||
855 | .long sys_select | ||
856 | .long sys_flock | ||
857 | .long sys_msync | ||
858 | .long sys_readv /* 145 */ | ||
859 | .long sys_writev | ||
860 | .long sys_getsid | ||
861 | .long sys_fdatasync | ||
862 | .long sys_sysctl | ||
863 | .long sys_mlock /* 150 */ | ||
864 | .long sys_munlock | ||
865 | .long sys_mlockall | ||
866 | .long sys_munlockall | ||
867 | .long sys_sched_setparam | ||
868 | .long sys_sched_getparam /* 155 */ | ||
869 | .long sys_sched_setscheduler | ||
870 | .long sys_sched_getscheduler | ||
871 | .long sys_sched_yield | ||
872 | .long sys_sched_get_priority_max | ||
873 | .long sys_sched_get_priority_min /* 160 */ | ||
874 | .long sys_sched_rr_get_interval | ||
875 | .long sys_nanosleep | ||
876 | .long sys_mremap | ||
877 | .long sys_ni_syscall /* setresuid16 syscall holder */ | ||
878 | .long sys_ni_syscall /* 165 - getresuid16 syscall holder */ | ||
879 | .long sys_tas /* vm86 syscall holder */ | ||
880 | .long sys_ni_syscall /* query_module syscall holder */ | ||
881 | .long sys_poll | ||
882 | .long sys_nfsservctl | ||
883 | .long sys_setresgid /* 170 */ | ||
884 | .long sys_getresgid | ||
885 | .long sys_prctl | ||
886 | .long sys_rt_sigreturn | ||
887 | .long sys_rt_sigaction | ||
888 | .long sys_rt_sigprocmask /* 175 */ | ||
889 | .long sys_rt_sigpending | ||
890 | .long sys_rt_sigtimedwait | ||
891 | .long sys_rt_sigqueueinfo | ||
892 | .long sys_rt_sigsuspend | ||
893 | .long sys_pread64 /* 180 */ | ||
894 | .long sys_pwrite64 | ||
895 | .long sys_ni_syscall /* chown16 syscall holder */ | ||
896 | .long sys_getcwd | ||
897 | .long sys_capget | ||
898 | .long sys_capset /* 185 */ | ||
899 | .long sys_sigaltstack | ||
900 | .long sys_sendfile | ||
901 | .long sys_ni_syscall /* streams1 */ | ||
902 | .long sys_ni_syscall /* streams2 */ | ||
903 | .long sys_vfork /* 190 */ | ||
904 | .long sys_getrlimit | ||
905 | .long sys_mmap2 | ||
906 | .long sys_truncate64 | ||
907 | .long sys_ftruncate64 | ||
908 | .long sys_stat64 /* 195 */ | ||
909 | .long sys_lstat64 | ||
910 | .long sys_fstat64 | ||
911 | .long sys_lchown | ||
912 | .long sys_getuid | ||
913 | .long sys_getgid /* 200 */ | ||
914 | .long sys_geteuid | ||
915 | .long sys_getegid | ||
916 | .long sys_setreuid | ||
917 | .long sys_setregid | ||
918 | .long sys_getgroups /* 205 */ | ||
919 | .long sys_setgroups | ||
920 | .long sys_fchown | ||
921 | .long sys_setresuid | ||
922 | .long sys_getresuid | ||
923 | .long sys_setresgid /* 210 */ | ||
924 | .long sys_getresgid | ||
925 | .long sys_chown | ||
926 | .long sys_setuid | ||
927 | .long sys_setgid | ||
928 | .long sys_setfsuid /* 215 */ | ||
929 | .long sys_setfsgid | ||
930 | .long sys_pivot_root | ||
931 | .long sys_mincore | ||
932 | .long sys_madvise | ||
933 | .long sys_getdents64 /* 220 */ | ||
934 | .long sys_fcntl64 | ||
935 | .long sys_ni_syscall /* reserved for TUX */ | ||
936 | .long sys_ni_syscall /* Reserved for Security */ | ||
937 | .long sys_gettid | ||
938 | .long sys_readahead /* 225 */ | ||
939 | .long sys_setxattr | ||
940 | .long sys_lsetxattr | ||
941 | .long sys_fsetxattr | ||
942 | .long sys_getxattr | ||
943 | .long sys_lgetxattr /* 230 */ | ||
944 | .long sys_fgetxattr | ||
945 | .long sys_listxattr | ||
946 | .long sys_llistxattr | ||
947 | .long sys_flistxattr | ||
948 | .long sys_removexattr /* 235 */ | ||
949 | .long sys_lremovexattr | ||
950 | .long sys_fremovexattr | ||
951 | .long sys_tkill | ||
952 | .long sys_sendfile64 | ||
953 | .long sys_futex /* 240 */ | ||
954 | .long sys_sched_setaffinity | ||
955 | .long sys_sched_getaffinity | ||
956 | .long sys_ni_syscall /* reserved for "set_thread_area" system call */ | ||
957 | .long sys_ni_syscall /* reserved for "get_thread_area" system call */ | ||
958 | .long sys_io_setup /* 245 */ | ||
959 | .long sys_io_destroy | ||
960 | .long sys_io_getevents | ||
961 | .long sys_io_submit | ||
962 | .long sys_io_cancel | ||
963 | .long sys_fadvise64 /* 250 */ | ||
964 | .long sys_ni_syscall | ||
965 | .long sys_exit_group | ||
966 | .long sys_lookup_dcookie | ||
967 | .long sys_epoll_create | ||
968 | .long sys_epoll_ctl /* 255 */ | ||
969 | .long sys_epoll_wait | ||
970 | .long sys_remap_file_pages | ||
971 | .long sys_set_tid_address | ||
972 | .long sys_timer_create | ||
973 | .long sys_timer_settime /* 260 */ | ||
974 | .long sys_timer_gettime | ||
975 | .long sys_timer_getoverrun | ||
976 | .long sys_timer_delete | ||
977 | .long sys_clock_settime | ||
978 | .long sys_clock_gettime /* 265 */ | ||
979 | .long sys_clock_getres | ||
980 | .long sys_clock_nanosleep | ||
981 | .long sys_statfs64 | ||
982 | .long sys_fstatfs64 | ||
983 | .long sys_tgkill /* 270 */ | ||
984 | .long sys_utimes | ||
985 | .long sys_fadvise64_64 | ||
986 | .long sys_ni_syscall /* Reserved for sys_vserver */ | ||
987 | .long sys_ni_syscall /* Reserved for sys_mbind */ | ||
988 | .long sys_ni_syscall /* Reserved for sys_get_mempolicy */ | ||
989 | .long sys_ni_syscall /* Reserved for sys_set_mempolicy */ | ||
990 | .long sys_mq_open | ||
991 | .long sys_mq_unlink | ||
992 | .long sys_mq_timedsend | ||
993 | .long sys_mq_timedreceive /* 280 */ | ||
994 | .long sys_mq_notify | ||
995 | .long sys_mq_getsetattr | ||
996 | .long sys_ni_syscall /* reserved for kexec */ | ||
997 | .long sys_waitid | ||
998 | |||
999 | syscall_table_size=(.-sys_call_table) | ||
1000 | |||
diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S new file mode 100644 index 000000000000..3e83173995cd --- /dev/null +++ b/arch/m32r/kernel/head.S | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/head.S | ||
3 | * | ||
4 | * M32R startup code. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | /* $Id$ */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | __INIT | ||
14 | __INITDATA | ||
15 | |||
16 | .text | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/linkage.h> | ||
19 | #include <asm/segment.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pgtable.h> | ||
22 | #include <asm/assembler.h> | ||
23 | #include <asm/m32r.h> | ||
24 | #include <asm/mmu_context.h> | ||
25 | |||
26 | /* | ||
27 | * References to members of the boot_cpu_data structure. | ||
28 | */ | ||
29 | .text | ||
30 | .global start_kernel | ||
31 | .global __bss_start | ||
32 | .global _end | ||
33 | ENTRY(stext) | ||
34 | ENTRY(_stext) | ||
35 | ENTRY(startup_32) | ||
36 | /* Setup up the stack pointer */ | ||
37 | LDIMM (r0, spi_stack_top) | ||
38 | LDIMM (r1, spu_stack_top) | ||
39 | mvtc r0, spi | ||
40 | mvtc r1, spu | ||
41 | |||
42 | /* Initilalize PSW */ | ||
43 | ldi r0, #0x0000 /* use SPI, disable EI */ | ||
44 | mvtc r0, psw | ||
45 | |||
46 | /* Set up the stack pointer */ | ||
47 | LDIMM (r0, stack_start) | ||
48 | ld r0, @r0 | ||
49 | mvtc r0, spi | ||
50 | |||
51 | /* | ||
52 | * Clear BSS first so that there are no surprises... | ||
53 | */ | ||
54 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
55 | |||
56 | LDIMM (r2, __bss_start) | ||
57 | LDIMM (r3, _end) | ||
58 | sub r3, r2 ; BSS size in bytes | ||
59 | ; R4 = BSS size in longwords (rounded down) | ||
60 | mv r4, r3 || ldi r1, #0 | ||
61 | srli r4, #4 || addi r2, #-4 | ||
62 | beqz r4, .Lendloop1 | ||
63 | .Lloop1: | ||
64 | #ifndef CONFIG_CHIP_M32310 | ||
65 | ; Touch memory for the no-write-allocating cache. | ||
66 | ld r0, @(4,r2) | ||
67 | #endif | ||
68 | st r1, @+r2 || addi r4, #-1 | ||
69 | st r1, @+r2 | ||
70 | st r1, @+r2 | ||
71 | st r1, @+r2 || cmpeq r1, r4 ; R4 = 0? | ||
72 | bnc .Lloop1 | ||
73 | .Lendloop1: | ||
74 | and3 r4, r3, #15 | ||
75 | addi r2, #4 | ||
76 | beqz r4, .Lendloop2 | ||
77 | .Lloop2: | ||
78 | stb r1, @r2 || addi r4, #-1 | ||
79 | addi r2, #1 | ||
80 | bnez r4, .Lloop2 | ||
81 | .Lendloop2: | ||
82 | |||
83 | #else /* not CONFIG_ISA_DUAL_ISSUE */ | ||
84 | |||
85 | LDIMM (r2, __bss_start) | ||
86 | LDIMM (r3, _end) | ||
87 | sub r3, r2 ; BSS size in bytes | ||
88 | mv r4, r3 | ||
89 | srli r4, #2 ; R4 = BSS size in longwords (rounded down) | ||
90 | ldi r1, #0 ; clear R1 for longwords store | ||
91 | addi r2, #-4 ; account for pre-inc store | ||
92 | beqz r4, .Lendloop1 ; any more to go? | ||
93 | .Lloop1: | ||
94 | st r1, @+r2 ; yep, zero out another longword | ||
95 | addi r4, #-1 ; decrement count | ||
96 | bnez r4, .Lloop1 ; go do some more | ||
97 | .Lendloop1: | ||
98 | and3 r4, r3, #3 ; get no. of remaining BSS bytes to clear | ||
99 | addi r2, #4 ; account for pre-inc store | ||
100 | beqz r4, .Lendloop2 ; any more to go? | ||
101 | .Lloop2: | ||
102 | stb r1, @r2 ; yep, zero out another byte | ||
103 | addi r2, #1 ; bump address | ||
104 | addi r4, #-1 ; decrement count | ||
105 | bnez r4, .Lloop2 ; go do some more | ||
106 | .Lendloop2: | ||
107 | |||
108 | #endif /* not CONFIG_ISA_DUAL_ISSUE */ | ||
109 | |||
110 | #if 0 /* M32R_FIXME */ | ||
111 | /* | ||
112 | * Copy data segment from ROM to RAM. | ||
113 | */ | ||
114 | .global ROM_D, TOP_DATA, END_DATA | ||
115 | |||
116 | LDIMM (r1, ROM_D) | ||
117 | LDIMM (r2, TOP_DATA) | ||
118 | LDIMM (r3, END_DATA) | ||
119 | addi r2, #-4 | ||
120 | addi r3, #-4 | ||
121 | loop1: | ||
122 | ld r0, @r1+ | ||
123 | st r0, @+r2 | ||
124 | cmp r2, r3 | ||
125 | bc loop1 | ||
126 | #endif /* 0 */ | ||
127 | |||
128 | /* Jump to kernel */ | ||
129 | LDIMM (r2, start_kernel) | ||
130 | jl r2 | ||
131 | .fillinsn | ||
132 | 1: | ||
133 | bra 1b ; main should never return here, but | ||
134 | ; just in case, we know what happens. | ||
135 | |||
136 | #ifdef CONFIG_SMP | ||
137 | /* | ||
138 | * AP startup routine | ||
139 | */ | ||
140 | .text | ||
141 | .global eit_vector | ||
142 | ENTRY(startup_AP) | ||
143 | ;; setup EVB | ||
144 | LDIMM (r4, eit_vector) | ||
145 | mvtc r4, cr5 | ||
146 | |||
147 | ;; enable MMU | ||
148 | LDIMM (r2, init_tlb) | ||
149 | jl r2 | ||
150 | seth r4, #high(MATM) | ||
151 | or3 r4, r4, #low(MATM) | ||
152 | ldi r5, #0x01 | ||
153 | st r5, @r4 ; Set MATM Reg(T bit ON) | ||
154 | ld r6, @r4 ; MATM Check | ||
155 | LDIMM (r5, 1f) | ||
156 | jmp r5 ; enable MMU | ||
157 | nop | ||
158 | .fillinsn | ||
159 | 1: | ||
160 | ;; ISN check | ||
161 | ld r6, @r4 ; MATM Check | ||
162 | seth r4, #high(M32R_ICU_ISTS_ADDR) | ||
163 | or3 r4, r4, #low(M32R_ICU_ISTS_ADDR) | ||
164 | ld r5, @r4 ; Read ISTSi reg. | ||
165 | mv r6, r5 | ||
166 | slli r5, #13 ; PIML check | ||
167 | srli r5, #13 ; | ||
168 | seth r4, #high(M32R_ICU_IMASK_ADDR) | ||
169 | or3 r4, r4, #low(M32R_ICU_IMASK_ADDR) | ||
170 | st r5, @r4 ; Write IMASKi reg. | ||
171 | slli r6, #4 ; ISN check | ||
172 | srli r6, #26 ; | ||
173 | seth r4, #high(M32R_IRQ_IPI5) | ||
174 | or3 r4, r4, #low(M32R_IRQ_IPI5) | ||
175 | bne r4, r6, 2f ; if (ISN != CPU_BOOT_IPI) goto sleep; | ||
176 | |||
177 | ;; check cpu_bootout_map and set cpu_bootin_map | ||
178 | LDIMM (r4, cpu_bootout_map) | ||
179 | ld r4, @r4 | ||
180 | seth r5, #high(M32R_CPUID_PORTL) | ||
181 | or3 r5, r5, #low(M32R_CPUID_PORTL) | ||
182 | ld r5, @r5 | ||
183 | ldi r6, #1 | ||
184 | sll r6, r5 | ||
185 | and r4, r6 | ||
186 | beqz r4, 2f | ||
187 | LDIMM (r4, cpu_bootin_map) | ||
188 | ld r5, @r4 | ||
189 | or r5, r6 | ||
190 | st r6, @r4 | ||
191 | |||
192 | ;; clear PSW | ||
193 | ldi r4, #0 | ||
194 | mvtc r4, psw | ||
195 | |||
196 | ;; setup SPI | ||
197 | LDIMM (r4, stack_start) | ||
198 | ld r4, @r4 | ||
199 | mvtc r4, spi | ||
200 | |||
201 | ;; setup BPC (start_secondary) | ||
202 | LDIMM (r4, start_secondary) | ||
203 | mvtc r4, bpc | ||
204 | |||
205 | rte ; goto startup_secondary | ||
206 | nop | ||
207 | nop | ||
208 | |||
209 | .fillinsn | ||
210 | 2: | ||
211 | ;; disable MMU | ||
212 | seth r4, #high(MATM) | ||
213 | or3 r4, r4, #low(MATM) | ||
214 | ldi r5, #0 | ||
215 | st r5, @r4 ; Set MATM Reg(T bit OFF) | ||
216 | ld r6, @r4 ; MATM Check | ||
217 | LDIMM (r4, 3f) | ||
218 | seth r5, #high(__PAGE_OFFSET) | ||
219 | or3 r5, r5, #low(__PAGE_OFFSET) | ||
220 | not r5, r5 | ||
221 | and r4, r5 | ||
222 | jmp r4 ; disable MMU | ||
223 | nop | ||
224 | .fillinsn | ||
225 | 3: | ||
226 | ;; SLEEP and wait IPI | ||
227 | LDIMM (r4, AP_loop) | ||
228 | seth r5, #high(__PAGE_OFFSET) | ||
229 | or3 r5, r5, #low(__PAGE_OFFSET) | ||
230 | not r5, r5 | ||
231 | and r4, r5 | ||
232 | jmp r4 | ||
233 | nop | ||
234 | nop | ||
235 | #endif /* CONFIG_SMP */ | ||
236 | |||
237 | ENTRY(stack_start) | ||
238 | .long init_thread_union+8192 | ||
239 | .long __KERNEL_DS | ||
240 | |||
241 | /* | ||
242 | * This is initialized to create a identity-mapping at 0-4M (for bootup | ||
243 | * purposes) and another mapping of the 0-4M area at virtual address | ||
244 | * PAGE_OFFSET. | ||
245 | */ | ||
246 | .text | ||
247 | |||
248 | #define MOUNT_ROOT_RDONLY 1 | ||
249 | #define RAMDISK_FLAGS 0 ; 1024KB | ||
250 | #define ORIG_ROOT_DEV 0x0100 ; /dev/ram0 (major:01, minor:00) | ||
251 | #define LOADER_TYPE 1 ; (??? - non-zero value seems | ||
252 | ; to be needed to boot from initrd) | ||
253 | |||
254 | #define COMMAND_LINE "" | ||
255 | |||
256 | .section .empty_zero_page, "aw" | ||
257 | ENTRY(empty_zero_page) | ||
258 | .long MOUNT_ROOT_RDONLY /* offset: +0x00 */ | ||
259 | .long RAMDISK_FLAGS | ||
260 | .long ORIG_ROOT_DEV | ||
261 | .long LOADER_TYPE | ||
262 | .long 0 /* INITRD_START */ /* +0x10 */ | ||
263 | .long 0 /* INITRD_SIZE */ | ||
264 | .long 0 /* CPU_CLOCK */ | ||
265 | .long 0 /* BUS_CLOCK */ | ||
266 | .long 0 /* TIMER_DIVIDE */ /* +0x20 */ | ||
267 | .balign 256,0 | ||
268 | .asciz COMMAND_LINE | ||
269 | .byte 0 | ||
270 | .balign 4096,0,4096 | ||
271 | |||
272 | /*------------------------------------------------------------------------ | ||
273 | * Stack area | ||
274 | */ | ||
275 | .section .spi | ||
276 | ALIGN | ||
277 | .global spi_stack_top | ||
278 | .zero 1024 | ||
279 | spi_stack_top: | ||
280 | |||
281 | .section .spu | ||
282 | ALIGN | ||
283 | .global spu_stack_top | ||
284 | .zero 1024 | ||
285 | spu_stack_top: | ||
286 | |||
287 | .end | ||
diff --git a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c new file mode 100644 index 000000000000..9e508fd9d970 --- /dev/null +++ b/arch/m32r/kernel/init_task.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* orig : i386 init_task.c */ | ||
2 | |||
3 | #include <linux/mm.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/sched.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/init_task.h> | ||
8 | #include <linux/fs.h> | ||
9 | #include <linux/mqueue.h> | ||
10 | |||
11 | #include <asm/uaccess.h> | ||
12 | #include <asm/pgtable.h> | ||
13 | |||
14 | static struct fs_struct init_fs = INIT_FS; | ||
15 | static struct files_struct init_files = INIT_FILES; | ||
16 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
17 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
18 | struct mm_struct init_mm = INIT_MM(init_mm); | ||
19 | |||
20 | EXPORT_SYMBOL(init_mm); | ||
21 | |||
22 | /* | ||
23 | * Initial thread structure. | ||
24 | * | ||
25 | * We need to make sure that this is 8192-byte aligned due to the | ||
26 | * way process stacks are handled. This is done by having a special | ||
27 | * "init_task" linker map entry.. | ||
28 | */ | ||
29 | union thread_union init_thread_union | ||
30 | __attribute__((__section__(".data.init_task"))) = | ||
31 | { INIT_THREAD_INFO(init_task) }; | ||
32 | |||
33 | /* | ||
34 | * Initial task structure. | ||
35 | * | ||
36 | * All other task structs will be allocated on slabs in fork.c | ||
37 | */ | ||
38 | struct task_struct init_task = INIT_TASK(init_task); | ||
39 | |||
40 | EXPORT_SYMBOL(init_task); | ||
41 | |||
diff --git a/arch/m32r/kernel/io_m32700ut.c b/arch/m32r/kernel/io_m32700ut.c new file mode 100644 index 000000000000..371ba904e968 --- /dev/null +++ b/arch/m32r/kernel/io_m32700ut.c | |||
@@ -0,0 +1,472 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_m32700ut.c | ||
3 | * | ||
4 | * Typical I/O routines for M32700UT board. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Takeo Takahashi | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <asm/m32r.h> | ||
16 | #include <asm/page.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/byteorder.h> | ||
19 | |||
20 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
21 | #include <linux/types.h> | ||
22 | |||
23 | #define M32R_PCC_IOMAP_SIZE 0x1000 | ||
24 | |||
25 | #define M32R_PCC_IOSTART0 0x1000 | ||
26 | #define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) | ||
27 | |||
28 | extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); | ||
29 | extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); | ||
30 | extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); | ||
31 | extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); | ||
32 | #endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ | ||
33 | |||
34 | #define PORT2ADDR(port) _port2addr(port) | ||
35 | #define PORT2ADDR_USB(port) _port2addr_usb(port) | ||
36 | |||
37 | static inline void *_port2addr(unsigned long port) | ||
38 | { | ||
39 | return (void *)(port + NONCACHE_OFFSET); | ||
40 | } | ||
41 | |||
42 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
43 | static inline void *__port2addr_ata(unsigned long port) | ||
44 | { | ||
45 | static int dummy_reg; | ||
46 | |||
47 | switch (port) { | ||
48 | case 0x1f0: return (void *)0xac002000; | ||
49 | case 0x1f1: return (void *)0xac012800; | ||
50 | case 0x1f2: return (void *)0xac012002; | ||
51 | case 0x1f3: return (void *)0xac012802; | ||
52 | case 0x1f4: return (void *)0xac012004; | ||
53 | case 0x1f5: return (void *)0xac012804; | ||
54 | case 0x1f6: return (void *)0xac012006; | ||
55 | case 0x1f7: return (void *)0xac012806; | ||
56 | case 0x3f6: return (void *)0xac01200e; | ||
57 | default: return (void *)&dummy_reg; | ||
58 | } | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | /* | ||
63 | * M32700UT-LAN is located in the extended bus space | ||
64 | * from 0x10000000 to 0x13ffffff on physical address. | ||
65 | * The base address of LAN controller(LAN91C111) is 0x300. | ||
66 | */ | ||
67 | #define LAN_IOSTART 0x300 | ||
68 | #define LAN_IOEND 0x320 | ||
69 | static inline void *_port2addr_ne(unsigned long port) | ||
70 | { | ||
71 | return (void *)(port + NONCACHE_OFFSET + 0x10000000); | ||
72 | } | ||
73 | static inline void *_port2addr_usb(unsigned long port) | ||
74 | { | ||
75 | return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); | ||
76 | } | ||
77 | |||
78 | static inline void delay(void) | ||
79 | { | ||
80 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * NIC I/O function | ||
85 | */ | ||
86 | |||
87 | #define PORT2ADDR_NE(port) _port2addr_ne(port) | ||
88 | |||
89 | static inline unsigned char _ne_inb(void *portp) | ||
90 | { | ||
91 | return *(volatile unsigned char *)portp; | ||
92 | } | ||
93 | |||
94 | static inline unsigned short _ne_inw(void *portp) | ||
95 | { | ||
96 | return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); | ||
97 | } | ||
98 | |||
99 | static inline void _ne_insb(void *portp, void *addr, unsigned long count) | ||
100 | { | ||
101 | unsigned char *buf = (unsigned char *)addr; | ||
102 | |||
103 | while (count--) | ||
104 | *buf++ = _ne_inb(portp); | ||
105 | } | ||
106 | |||
107 | static inline void _ne_outb(unsigned char b, void *portp) | ||
108 | { | ||
109 | *(volatile unsigned char *)portp = b; | ||
110 | } | ||
111 | |||
112 | static inline void _ne_outw(unsigned short w, void *portp) | ||
113 | { | ||
114 | *(volatile unsigned short *)portp = cpu_to_le16(w); | ||
115 | } | ||
116 | |||
117 | unsigned char _inb(unsigned long port) | ||
118 | { | ||
119 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
120 | return _ne_inb(PORT2ADDR_NE(port)); | ||
121 | |||
122 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
123 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
124 | return *(volatile unsigned char *)__port2addr_ata(port); | ||
125 | } | ||
126 | #endif | ||
127 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
128 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
129 | unsigned char b; | ||
130 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
131 | return b; | ||
132 | } else | ||
133 | #endif | ||
134 | |||
135 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
136 | } | ||
137 | |||
138 | unsigned short _inw(unsigned long port) | ||
139 | { | ||
140 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
141 | return _ne_inw(PORT2ADDR_NE(port)); | ||
142 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
143 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
144 | return *(volatile unsigned short *)__port2addr_ata(port); | ||
145 | } | ||
146 | #endif | ||
147 | #if defined(CONFIG_USB) | ||
148 | else if(port >= 0x340 && port < 0x3a0) | ||
149 | return *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
150 | #endif | ||
151 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
152 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
153 | unsigned short w; | ||
154 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
155 | return w; | ||
156 | } else | ||
157 | #endif | ||
158 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
159 | } | ||
160 | |||
161 | unsigned long _inl(unsigned long port) | ||
162 | { | ||
163 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
164 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
165 | unsigned long l; | ||
166 | pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); | ||
167 | return l; | ||
168 | } else | ||
169 | #endif | ||
170 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
171 | } | ||
172 | |||
173 | unsigned char _inb_p(unsigned long port) | ||
174 | { | ||
175 | unsigned char v; | ||
176 | |||
177 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
178 | v = _ne_inb(PORT2ADDR_NE(port)); | ||
179 | else | ||
180 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
181 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
182 | return *(volatile unsigned char *)__port2addr_ata(port); | ||
183 | } else | ||
184 | #endif | ||
185 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
186 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
187 | unsigned char b; | ||
188 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
189 | return b; | ||
190 | } else | ||
191 | #endif | ||
192 | v = *(volatile unsigned char *)PORT2ADDR(port); | ||
193 | |||
194 | delay(); | ||
195 | return (v); | ||
196 | } | ||
197 | |||
198 | unsigned short _inw_p(unsigned long port) | ||
199 | { | ||
200 | unsigned short v; | ||
201 | |||
202 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
203 | v = _ne_inw(PORT2ADDR_NE(port)); | ||
204 | else | ||
205 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
206 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
207 | return *(volatile unsigned short *)__port2addr_ata(port); | ||
208 | } else | ||
209 | #endif | ||
210 | #if defined(CONFIG_USB) | ||
211 | if(port >= 0x340 && port < 0x3a0) | ||
212 | return *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
213 | else | ||
214 | #endif | ||
215 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
216 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
217 | unsigned short w; | ||
218 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
219 | return w; | ||
220 | } else | ||
221 | #endif | ||
222 | v = *(volatile unsigned short *)PORT2ADDR(port); | ||
223 | |||
224 | delay(); | ||
225 | return (v); | ||
226 | } | ||
227 | |||
228 | unsigned long _inl_p(unsigned long port) | ||
229 | { | ||
230 | unsigned long v; | ||
231 | |||
232 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
233 | delay(); | ||
234 | return (v); | ||
235 | } | ||
236 | |||
237 | void _outb(unsigned char b, unsigned long port) | ||
238 | { | ||
239 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
240 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
241 | else | ||
242 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
243 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
244 | *(volatile unsigned char *)__port2addr_ata(port) = b; | ||
245 | } else | ||
246 | #endif | ||
247 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
248 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
249 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
250 | } else | ||
251 | #endif | ||
252 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
253 | } | ||
254 | |||
255 | void _outw(unsigned short w, unsigned long port) | ||
256 | { | ||
257 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
258 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
259 | else | ||
260 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
261 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
262 | *(volatile unsigned short *)__port2addr_ata(port) = w; | ||
263 | } else | ||
264 | #endif | ||
265 | #if defined(CONFIG_USB) | ||
266 | if(port >= 0x340 && port < 0x3a0) | ||
267 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
268 | else | ||
269 | #endif | ||
270 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
271 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
272 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
273 | } else | ||
274 | #endif | ||
275 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
276 | } | ||
277 | |||
278 | void _outl(unsigned long l, unsigned long port) | ||
279 | { | ||
280 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
281 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
282 | pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); | ||
283 | } else | ||
284 | #endif | ||
285 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
286 | } | ||
287 | |||
288 | void _outb_p(unsigned char b, unsigned long port) | ||
289 | { | ||
290 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
291 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
292 | else | ||
293 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
294 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
295 | *(volatile unsigned char *)__port2addr_ata(port) = b; | ||
296 | } else | ||
297 | #endif | ||
298 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
299 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
300 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
301 | } else | ||
302 | #endif | ||
303 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
304 | |||
305 | delay(); | ||
306 | } | ||
307 | |||
308 | void _outw_p(unsigned short w, unsigned long port) | ||
309 | { | ||
310 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
311 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
312 | else | ||
313 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
314 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
315 | *(volatile unsigned short *)__port2addr_ata(port) = w; | ||
316 | } else | ||
317 | #endif | ||
318 | #if defined(CONFIG_USB) | ||
319 | if(port >= 0x340 && port < 0x3a0) | ||
320 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
321 | else | ||
322 | #endif | ||
323 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
324 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
325 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
326 | } else | ||
327 | #endif | ||
328 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
329 | |||
330 | delay(); | ||
331 | } | ||
332 | |||
333 | void _outl_p(unsigned long l, unsigned long port) | ||
334 | { | ||
335 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
336 | delay(); | ||
337 | } | ||
338 | |||
339 | void _insb(unsigned int port, void *addr, unsigned long count) | ||
340 | { | ||
341 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
342 | _ne_insb(PORT2ADDR_NE(port), addr, count); | ||
343 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
344 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
345 | unsigned char *buf = addr; | ||
346 | unsigned char *portp = __port2addr_ata(port); | ||
347 | while (count--) | ||
348 | *buf++ = *(volatile unsigned char *)portp; | ||
349 | } | ||
350 | #endif | ||
351 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
352 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
353 | pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
354 | count, 1); | ||
355 | } | ||
356 | #endif | ||
357 | else { | ||
358 | unsigned char *buf = addr; | ||
359 | unsigned char *portp = PORT2ADDR(port); | ||
360 | while (count--) | ||
361 | *buf++ = *(volatile unsigned char *)portp; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | void _insw(unsigned int port, void *addr, unsigned long count) | ||
366 | { | ||
367 | unsigned short *buf = addr; | ||
368 | unsigned short *portp; | ||
369 | |||
370 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
371 | /* | ||
372 | * This portion is only used by smc91111.c to read data | ||
373 | * from the DATA_REG. Do not swap the data. | ||
374 | */ | ||
375 | portp = PORT2ADDR_NE(port); | ||
376 | while (count--) | ||
377 | *buf++ = *(volatile unsigned short *)portp; | ||
378 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
379 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
380 | pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), | ||
381 | count, 1); | ||
382 | #endif | ||
383 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
384 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
385 | portp = __port2addr_ata(port); | ||
386 | while (count--) | ||
387 | *buf++ = *(volatile unsigned short *)portp; | ||
388 | #endif | ||
389 | } else { | ||
390 | portp = PORT2ADDR(port); | ||
391 | while (count--) | ||
392 | *buf++ = *(volatile unsigned short *)portp; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | void _insl(unsigned int port, void *addr, unsigned long count) | ||
397 | { | ||
398 | unsigned long *buf = addr; | ||
399 | unsigned long *portp; | ||
400 | |||
401 | portp = PORT2ADDR(port); | ||
402 | while (count--) | ||
403 | *buf++ = *(volatile unsigned long *)portp; | ||
404 | } | ||
405 | |||
406 | void _outsb(unsigned int port, const void *addr, unsigned long count) | ||
407 | { | ||
408 | const unsigned char *buf = addr; | ||
409 | unsigned char *portp; | ||
410 | |||
411 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
412 | portp = PORT2ADDR_NE(port); | ||
413 | while (count--) | ||
414 | _ne_outb(*buf++, portp); | ||
415 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
416 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
417 | portp = __port2addr_ata(port); | ||
418 | while (count--) | ||
419 | *(volatile unsigned char *)portp = *buf++; | ||
420 | #endif | ||
421 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
422 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
423 | pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
424 | count, 1); | ||
425 | #endif | ||
426 | } else { | ||
427 | portp = PORT2ADDR(port); | ||
428 | while (count--) | ||
429 | *(volatile unsigned char *)portp = *buf++; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | void _outsw(unsigned int port, const void *addr, unsigned long count) | ||
434 | { | ||
435 | const unsigned short *buf = addr; | ||
436 | unsigned short *portp; | ||
437 | |||
438 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
439 | /* | ||
440 | * This portion is only used by smc91111.c to write data | ||
441 | * into the DATA_REG. Do not swap the data. | ||
442 | */ | ||
443 | portp = PORT2ADDR_NE(port); | ||
444 | while (count--) | ||
445 | *(volatile unsigned short *)portp = *buf++; | ||
446 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
447 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
448 | portp = __port2addr_ata(port); | ||
449 | while (count--) | ||
450 | *(volatile unsigned short *)portp = *buf++; | ||
451 | #endif | ||
452 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
453 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
454 | pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), | ||
455 | count, 1); | ||
456 | #endif | ||
457 | } else { | ||
458 | portp = PORT2ADDR(port); | ||
459 | while (count--) | ||
460 | *(volatile unsigned short *)portp = *buf++; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | void _outsl(unsigned int port, const void *addr, unsigned long count) | ||
465 | { | ||
466 | const unsigned long *buf = addr; | ||
467 | unsigned char *portp; | ||
468 | |||
469 | portp = PORT2ADDR(port); | ||
470 | while (count--) | ||
471 | *(volatile unsigned long *)portp = *buf++; | ||
472 | } | ||
diff --git a/arch/m32r/kernel/io_mappi.c b/arch/m32r/kernel/io_mappi.c new file mode 100644 index 000000000000..85688ffb52f9 --- /dev/null +++ b/arch/m32r/kernel/io_mappi.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_mappi.c | ||
3 | * | ||
4 | * Typical I/O routines for Mappi board. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <asm/m32r.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/byteorder.h> | ||
15 | |||
16 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #define M32R_PCC_IOMAP_SIZE 0x1000 | ||
20 | |||
21 | #define M32R_PCC_IOSTART0 0x1000 | ||
22 | #define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) | ||
23 | #define M32R_PCC_IOSTART1 0x2000 | ||
24 | #define M32R_PCC_IOEND1 (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1) | ||
25 | |||
26 | extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int); | ||
27 | extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int); | ||
28 | #endif /* CONFIG_PCMCIA && CONFIG_M32R_PCC */ | ||
29 | |||
30 | #define PORT2ADDR(port) _port2addr(port) | ||
31 | |||
32 | static inline void *_port2addr(unsigned long port) | ||
33 | { | ||
34 | return (void *)(port + NONCACHE_OFFSET); | ||
35 | } | ||
36 | |||
37 | static inline void *_port2addr_ne(unsigned long port) | ||
38 | { | ||
39 | return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000); | ||
40 | } | ||
41 | |||
42 | static inline void delay(void) | ||
43 | { | ||
44 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * NIC I/O function | ||
49 | */ | ||
50 | |||
51 | #define PORT2ADDR_NE(port) _port2addr_ne(port) | ||
52 | |||
53 | static inline unsigned char _ne_inb(void *portp) | ||
54 | { | ||
55 | return (unsigned char) *(volatile unsigned short *)portp; | ||
56 | } | ||
57 | |||
58 | static inline unsigned short _ne_inw(void *portp) | ||
59 | { | ||
60 | unsigned short tmp; | ||
61 | |||
62 | tmp = *(volatile unsigned short *)portp; | ||
63 | return le16_to_cpu(tmp); | ||
64 | } | ||
65 | |||
66 | static inline void _ne_outb(unsigned char b, void *portp) | ||
67 | { | ||
68 | *(volatile unsigned short *)portp = (unsigned short)b; | ||
69 | } | ||
70 | |||
71 | static inline void _ne_outw(unsigned short w, void *portp) | ||
72 | { | ||
73 | *(volatile unsigned short *)portp = cpu_to_le16(w); | ||
74 | } | ||
75 | |||
76 | unsigned char _inb(unsigned long port) | ||
77 | { | ||
78 | if (port >= 0x300 && port < 0x320) | ||
79 | return _ne_inb(PORT2ADDR_NE(port)); | ||
80 | else | ||
81 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
82 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
83 | unsigned char b; | ||
84 | pcc_ioread(0, port, &b, sizeof(b), 1, 0); | ||
85 | return b; | ||
86 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
87 | unsigned char b; | ||
88 | pcc_ioread(1, port, &b, sizeof(b), 1, 0); | ||
89 | return b; | ||
90 | } else | ||
91 | #endif | ||
92 | |||
93 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
94 | } | ||
95 | |||
96 | unsigned short _inw(unsigned long port) | ||
97 | { | ||
98 | if (port >= 0x300 && port < 0x320) | ||
99 | return _ne_inw(PORT2ADDR_NE(port)); | ||
100 | else | ||
101 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
102 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
103 | unsigned short w; | ||
104 | pcc_ioread(0, port, &w, sizeof(w), 1, 0); | ||
105 | return w; | ||
106 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
107 | unsigned short w; | ||
108 | pcc_ioread(1, port, &w, sizeof(w), 1, 0); | ||
109 | return w; | ||
110 | } else | ||
111 | #endif | ||
112 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
113 | } | ||
114 | |||
115 | unsigned long _inl(unsigned long port) | ||
116 | { | ||
117 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
118 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
119 | unsigned long l; | ||
120 | pcc_ioread(0, port, &l, sizeof(l), 1, 0); | ||
121 | return l; | ||
122 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
123 | unsigned short l; | ||
124 | pcc_ioread(1, port, &l, sizeof(l), 1, 0); | ||
125 | return l; | ||
126 | } else | ||
127 | #endif | ||
128 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
129 | } | ||
130 | |||
131 | unsigned char _inb_p(unsigned long port) | ||
132 | { | ||
133 | unsigned char v; | ||
134 | |||
135 | if (port >= 0x300 && port < 0x320) | ||
136 | v = _ne_inb(PORT2ADDR_NE(port)); | ||
137 | else | ||
138 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
139 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
140 | unsigned char b; | ||
141 | pcc_ioread(0, port, &b, sizeof(b), 1, 0); | ||
142 | return b; | ||
143 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
144 | unsigned char b; | ||
145 | pcc_ioread(1, port, &b, sizeof(b), 1, 0); | ||
146 | return b; | ||
147 | } else | ||
148 | #endif | ||
149 | v = *(volatile unsigned char *)PORT2ADDR(port); | ||
150 | |||
151 | delay(); | ||
152 | return (v); | ||
153 | } | ||
154 | |||
155 | unsigned short _inw_p(unsigned long port) | ||
156 | { | ||
157 | unsigned short v; | ||
158 | |||
159 | if (port >= 0x300 && port < 0x320) | ||
160 | v = _ne_inw(PORT2ADDR_NE(port)); | ||
161 | else | ||
162 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
163 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
164 | unsigned short w; | ||
165 | pcc_ioread(0, port, &w, sizeof(w), 1, 0); | ||
166 | return w; | ||
167 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
168 | unsigned short w; | ||
169 | pcc_ioread(1, port, &w, sizeof(w), 1, 0); | ||
170 | return w; | ||
171 | } else | ||
172 | #endif | ||
173 | v = *(volatile unsigned short *)PORT2ADDR(port); | ||
174 | |||
175 | delay(); | ||
176 | return (v); | ||
177 | } | ||
178 | |||
179 | unsigned long _inl_p(unsigned long port) | ||
180 | { | ||
181 | unsigned long v; | ||
182 | |||
183 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
184 | delay(); | ||
185 | return (v); | ||
186 | } | ||
187 | |||
188 | void _outb(unsigned char b, unsigned long port) | ||
189 | { | ||
190 | if (port >= 0x300 && port < 0x320) | ||
191 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
192 | else | ||
193 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
194 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
195 | pcc_iowrite(0, port, &b, sizeof(b), 1, 0); | ||
196 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
197 | pcc_iowrite(1, port, &b, sizeof(b), 1, 0); | ||
198 | } else | ||
199 | #endif | ||
200 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
201 | } | ||
202 | |||
203 | void _outw(unsigned short w, unsigned long port) | ||
204 | { | ||
205 | if (port >= 0x300 && port < 0x320) | ||
206 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
207 | else | ||
208 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
209 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
210 | pcc_iowrite(0, port, &w, sizeof(w), 1, 0); | ||
211 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
212 | pcc_iowrite(1, port, &w, sizeof(w), 1, 0); | ||
213 | } else | ||
214 | #endif | ||
215 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
216 | } | ||
217 | |||
218 | void _outl(unsigned long l, unsigned long port) | ||
219 | { | ||
220 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
221 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
222 | pcc_iowrite(0, port, &l, sizeof(l), 1, 0); | ||
223 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
224 | pcc_iowrite(1, port, &l, sizeof(l), 1, 0); | ||
225 | } else | ||
226 | #endif | ||
227 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
228 | } | ||
229 | |||
230 | void _outb_p(unsigned char b, unsigned long port) | ||
231 | { | ||
232 | if (port >= 0x300 && port < 0x320) | ||
233 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
234 | else | ||
235 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
236 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
237 | pcc_iowrite(0, port, &b, sizeof(b), 1, 0); | ||
238 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
239 | pcc_iowrite(1, port, &b, sizeof(b), 1, 0); | ||
240 | } else | ||
241 | #endif | ||
242 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
243 | |||
244 | delay(); | ||
245 | } | ||
246 | |||
247 | void _outw_p(unsigned short w, unsigned long port) | ||
248 | { | ||
249 | if (port >= 0x300 && port < 0x320) | ||
250 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
251 | else | ||
252 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
253 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
254 | pcc_iowrite(0, port, &w, sizeof(w), 1, 0); | ||
255 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
256 | pcc_iowrite(1, port, &w, sizeof(w), 1, 0); | ||
257 | } else | ||
258 | #endif | ||
259 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
260 | |||
261 | delay(); | ||
262 | } | ||
263 | |||
264 | void _outl_p(unsigned long l, unsigned long port) | ||
265 | { | ||
266 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
267 | delay(); | ||
268 | } | ||
269 | |||
270 | void _insb(unsigned int port, void *addr, unsigned long count) | ||
271 | { | ||
272 | unsigned short *buf = addr; | ||
273 | unsigned short *portp; | ||
274 | |||
275 | if (port >= 0x300 && port < 0x320){ | ||
276 | portp = PORT2ADDR_NE(port); | ||
277 | while (count--) | ||
278 | *buf++ = *(volatile unsigned char *)portp; | ||
279 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
280 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
281 | pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), | ||
282 | count, 1); | ||
283 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
284 | pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), | ||
285 | count, 1); | ||
286 | #endif | ||
287 | } else { | ||
288 | portp = PORT2ADDR(port); | ||
289 | while (count--) | ||
290 | *buf++ = *(volatile unsigned char *)portp; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | void _insw(unsigned int port, void *addr, unsigned long count) | ||
295 | { | ||
296 | unsigned short *buf = addr; | ||
297 | unsigned short *portp; | ||
298 | |||
299 | if (port >= 0x300 && port < 0x320) { | ||
300 | portp = PORT2ADDR_NE(port); | ||
301 | while (count--) | ||
302 | *buf++ = _ne_inw(portp); | ||
303 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
304 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
305 | pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), | ||
306 | count, 1); | ||
307 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
308 | pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), | ||
309 | count, 1); | ||
310 | #endif | ||
311 | } else { | ||
312 | portp = PORT2ADDR(port); | ||
313 | while (count--) | ||
314 | *buf++ = *(volatile unsigned short *)portp; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | void _insl(unsigned int port, void *addr, unsigned long count) | ||
319 | { | ||
320 | unsigned long *buf = addr; | ||
321 | unsigned long *portp; | ||
322 | |||
323 | portp = PORT2ADDR(port); | ||
324 | while (count--) | ||
325 | *buf++ = *(volatile unsigned long *)portp; | ||
326 | } | ||
327 | |||
328 | void _outsb(unsigned int port, const void *addr, unsigned long count) | ||
329 | { | ||
330 | const unsigned char *buf = addr; | ||
331 | unsigned char *portp; | ||
332 | |||
333 | if (port >= 0x300 && port < 0x320) { | ||
334 | portp = PORT2ADDR_NE(port); | ||
335 | while (count--) | ||
336 | _ne_outb(*buf++, portp); | ||
337 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
338 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
339 | pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), | ||
340 | count, 1); | ||
341 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
342 | pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), | ||
343 | count, 1); | ||
344 | #endif | ||
345 | } else { | ||
346 | portp = PORT2ADDR(port); | ||
347 | while (count--) | ||
348 | *(volatile unsigned char *)portp = *buf++; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | void _outsw(unsigned int port, const void *addr, unsigned long count) | ||
353 | { | ||
354 | const unsigned short *buf = addr; | ||
355 | unsigned short *portp; | ||
356 | |||
357 | if (port >= 0x300 && port < 0x320) { | ||
358 | portp = PORT2ADDR_NE(port); | ||
359 | while (count--) | ||
360 | _ne_outw(*buf++, portp); | ||
361 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) | ||
362 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
363 | pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), | ||
364 | count, 1); | ||
365 | } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { | ||
366 | pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), | ||
367 | count, 1); | ||
368 | #endif | ||
369 | } else { | ||
370 | portp = PORT2ADDR(port); | ||
371 | while (count--) | ||
372 | *(volatile unsigned short *)portp = *buf++; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | void _outsl(unsigned int port, const void *addr, unsigned long count) | ||
377 | { | ||
378 | const unsigned long *buf = addr; | ||
379 | unsigned char *portp; | ||
380 | |||
381 | portp = PORT2ADDR(port); | ||
382 | while (count--) | ||
383 | *(volatile unsigned long *)portp = *buf++; | ||
384 | } | ||
diff --git a/arch/m32r/kernel/io_mappi2.c b/arch/m32r/kernel/io_mappi2.c new file mode 100644 index 000000000000..4182cd4f97c8 --- /dev/null +++ b/arch/m32r/kernel/io_mappi2.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_mappi2.c | ||
3 | * | ||
4 | * Typical I/O routines for Mappi2 board. | ||
5 | * | ||
6 | * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Mamoru Sakugawa | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <asm/m32r.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/byteorder.h> | ||
15 | |||
16 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #define M32R_PCC_IOMAP_SIZE 0x1000 | ||
20 | |||
21 | #define M32R_PCC_IOSTART0 0x1000 | ||
22 | #define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) | ||
23 | |||
24 | extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); | ||
25 | extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); | ||
26 | extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); | ||
27 | extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); | ||
28 | #endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */ | ||
29 | |||
30 | #define PORT2ADDR(port) _port2addr(port) | ||
31 | #define PORT2ADDR_NE(port) _port2addr_ne(port) | ||
32 | #define PORT2ADDR_USB(port) _port2addr_usb(port) | ||
33 | |||
34 | static inline void *_port2addr(unsigned long port) | ||
35 | { | ||
36 | return (void *)(port + NONCACHE_OFFSET); | ||
37 | } | ||
38 | |||
39 | #define LAN_IOSTART 0x300 | ||
40 | #define LAN_IOEND 0x320 | ||
41 | |||
42 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
43 | static inline void *__port2addr_ata(unsigned long port) | ||
44 | { | ||
45 | static int dummy_reg; | ||
46 | |||
47 | switch (port) { | ||
48 | case 0x1f0: return (void *)0xac002000; | ||
49 | case 0x1f1: return (void *)0xac012800; | ||
50 | case 0x1f2: return (void *)0xac012002; | ||
51 | case 0x1f3: return (void *)0xac012802; | ||
52 | case 0x1f4: return (void *)0xac012004; | ||
53 | case 0x1f5: return (void *)0xac012804; | ||
54 | case 0x1f6: return (void *)0xac012006; | ||
55 | case 0x1f7: return (void *)0xac012806; | ||
56 | case 0x3f6: return (void *)0xac01200e; | ||
57 | default: return (void *)&dummy_reg; | ||
58 | } | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | #ifdef CONFIG_CHIP_OPSP | ||
63 | static inline void *_port2addr_ne(unsigned long port) | ||
64 | { | ||
65 | return (void *)(port + NONCACHE_OFFSET + 0x10000000); | ||
66 | } | ||
67 | #else | ||
68 | static inline void *_port2addr_ne(unsigned long port) | ||
69 | { | ||
70 | return (void *)(port + NONCACHE_OFFSET + 0x04000000); | ||
71 | } | ||
72 | #endif | ||
73 | static inline void *_port2addr_usb(unsigned long port) | ||
74 | { | ||
75 | return (void *)(port + NONCACHE_OFFSET + 0x14000000); | ||
76 | } | ||
77 | static inline void delay(void) | ||
78 | { | ||
79 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * NIC I/O function | ||
84 | */ | ||
85 | |||
86 | static inline unsigned char _ne_inb(void *portp) | ||
87 | { | ||
88 | return (unsigned char) *(volatile unsigned char *)portp; | ||
89 | } | ||
90 | |||
91 | static inline unsigned short _ne_inw(void *portp) | ||
92 | { | ||
93 | return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); | ||
94 | } | ||
95 | |||
96 | static inline void _ne_insb(void *portp, void * addr, unsigned long count) | ||
97 | { | ||
98 | unsigned char *buf = addr; | ||
99 | |||
100 | while (count--) | ||
101 | *buf++ = *(volatile unsigned char *)portp; | ||
102 | } | ||
103 | |||
104 | static inline void _ne_outb(unsigned char b, void *portp) | ||
105 | { | ||
106 | *(volatile unsigned char *)portp = (unsigned char)b; | ||
107 | } | ||
108 | |||
109 | static inline void _ne_outw(unsigned short w, void *portp) | ||
110 | { | ||
111 | *(volatile unsigned short *)portp = cpu_to_le16(w); | ||
112 | } | ||
113 | |||
114 | unsigned char _inb(unsigned long port) | ||
115 | { | ||
116 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
117 | return _ne_inb(PORT2ADDR_NE(port)); | ||
118 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
119 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
120 | return *(volatile unsigned char *)__port2addr_ata(port); | ||
121 | } | ||
122 | #endif | ||
123 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
124 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
125 | unsigned char b; | ||
126 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
127 | return b; | ||
128 | } else | ||
129 | #endif | ||
130 | |||
131 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
132 | } | ||
133 | |||
134 | unsigned short _inw(unsigned long port) | ||
135 | { | ||
136 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
137 | return _ne_inw(PORT2ADDR_NE(port)); | ||
138 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
139 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
140 | return *(volatile unsigned short *)__port2addr_ata(port); | ||
141 | } | ||
142 | #endif | ||
143 | #if defined(CONFIG_USB) | ||
144 | else if (port >= 0x340 && port < 0x3a0) | ||
145 | return *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
146 | #endif | ||
147 | |||
148 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
149 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
150 | unsigned short w; | ||
151 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
152 | return w; | ||
153 | } else | ||
154 | #endif | ||
155 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
156 | } | ||
157 | |||
158 | unsigned long _inl(unsigned long port) | ||
159 | { | ||
160 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
161 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
162 | unsigned long l; | ||
163 | pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); | ||
164 | return l; | ||
165 | } else | ||
166 | #endif | ||
167 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
168 | } | ||
169 | |||
170 | unsigned char _inb_p(unsigned long port) | ||
171 | { | ||
172 | unsigned char v; | ||
173 | |||
174 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
175 | v = _ne_inb(PORT2ADDR_NE(port)); | ||
176 | else | ||
177 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
178 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
179 | return *(volatile unsigned char *)__port2addr_ata(port); | ||
180 | } else | ||
181 | #endif | ||
182 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
183 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
184 | unsigned char b; | ||
185 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
186 | return b; | ||
187 | } else | ||
188 | #endif | ||
189 | v = *(volatile unsigned char *)PORT2ADDR(port); | ||
190 | |||
191 | delay(); | ||
192 | return (v); | ||
193 | } | ||
194 | |||
195 | unsigned short _inw_p(unsigned long port) | ||
196 | { | ||
197 | unsigned short v; | ||
198 | |||
199 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
200 | v = _ne_inw(PORT2ADDR_NE(port)); | ||
201 | else | ||
202 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
203 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
204 | return *(volatile unsigned short *)__port2addr_ata(port); | ||
205 | } else | ||
206 | #endif | ||
207 | #if defined(CONFIG_USB) | ||
208 | if (port >= 0x340 && port < 0x3a0) | ||
209 | v = *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
210 | else | ||
211 | #endif | ||
212 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
213 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
214 | unsigned short w; | ||
215 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
216 | return w; | ||
217 | } else | ||
218 | #endif | ||
219 | v = *(volatile unsigned short *)PORT2ADDR(port); | ||
220 | |||
221 | delay(); | ||
222 | return (v); | ||
223 | } | ||
224 | |||
225 | unsigned long _inl_p(unsigned long port) | ||
226 | { | ||
227 | unsigned long v; | ||
228 | |||
229 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
230 | delay(); | ||
231 | return (v); | ||
232 | } | ||
233 | |||
234 | void _outb(unsigned char b, unsigned long port) | ||
235 | { | ||
236 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
237 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
238 | else | ||
239 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
240 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
241 | *(volatile unsigned char *)__port2addr_ata(port) = b; | ||
242 | } else | ||
243 | #endif | ||
244 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
245 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
246 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
247 | } else | ||
248 | #endif | ||
249 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
250 | } | ||
251 | |||
252 | void _outw(unsigned short w, unsigned long port) | ||
253 | { | ||
254 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
255 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
256 | else | ||
257 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
258 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
259 | *(volatile unsigned short *)__port2addr_ata(port) = w; | ||
260 | } else | ||
261 | #endif | ||
262 | #if defined(CONFIG_USB) | ||
263 | if (port >= 0x340 && port < 0x3a0) | ||
264 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
265 | else | ||
266 | #endif | ||
267 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
268 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
269 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
270 | } else | ||
271 | #endif | ||
272 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
273 | } | ||
274 | |||
275 | void _outl(unsigned long l, unsigned long port) | ||
276 | { | ||
277 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
278 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
279 | pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); | ||
280 | } else | ||
281 | #endif | ||
282 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
283 | } | ||
284 | |||
285 | void _outb_p(unsigned char b, unsigned long port) | ||
286 | { | ||
287 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
288 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
289 | else | ||
290 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
291 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
292 | *(volatile unsigned char *)__port2addr_ata(port) = b; | ||
293 | } else | ||
294 | #endif | ||
295 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
296 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
297 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
298 | } else | ||
299 | #endif | ||
300 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
301 | |||
302 | delay(); | ||
303 | } | ||
304 | |||
305 | void _outw_p(unsigned short w, unsigned long port) | ||
306 | { | ||
307 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
308 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
309 | else | ||
310 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
311 | if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
312 | *(volatile unsigned short *)__port2addr_ata(port) = w; | ||
313 | } else | ||
314 | #endif | ||
315 | #if defined(CONFIG_USB) | ||
316 | if (port >= 0x340 && port < 0x3a0) | ||
317 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
318 | else | ||
319 | #endif | ||
320 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
321 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
322 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
323 | } else | ||
324 | #endif | ||
325 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
326 | |||
327 | delay(); | ||
328 | } | ||
329 | |||
330 | void _outl_p(unsigned long l, unsigned long port) | ||
331 | { | ||
332 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
333 | delay(); | ||
334 | } | ||
335 | |||
336 | void _insb(unsigned int port, void * addr, unsigned long count) | ||
337 | { | ||
338 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
339 | _ne_insb(PORT2ADDR_NE(port), addr, count); | ||
340 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
341 | else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
342 | unsigned char *buf = addr; | ||
343 | unsigned char *portp = __port2addr_ata(port); | ||
344 | while (count--) | ||
345 | *buf++ = *(volatile unsigned char *)portp; | ||
346 | } | ||
347 | #endif | ||
348 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
349 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
350 | pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
351 | count, 1); | ||
352 | } | ||
353 | #endif | ||
354 | else { | ||
355 | unsigned char *buf = addr; | ||
356 | unsigned char *portp = PORT2ADDR(port); | ||
357 | while (count--) | ||
358 | *buf++ = *(volatile unsigned char *)portp; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | void _insw(unsigned int port, void * addr, unsigned long count) | ||
363 | { | ||
364 | unsigned short *buf = addr; | ||
365 | unsigned short *portp; | ||
366 | |||
367 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
368 | portp = PORT2ADDR_NE(port); | ||
369 | while (count--) | ||
370 | *buf++ = *(volatile unsigned short *)portp; | ||
371 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
372 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
373 | pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), | ||
374 | count, 1); | ||
375 | #endif | ||
376 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
377 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
378 | portp = __port2addr_ata(port); | ||
379 | while (count--) | ||
380 | *buf++ = *(volatile unsigned short *)portp; | ||
381 | #endif | ||
382 | } else { | ||
383 | portp = PORT2ADDR(port); | ||
384 | while (count--) | ||
385 | *buf++ = *(volatile unsigned short *)portp; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | void _insl(unsigned int port, void * addr, unsigned long count) | ||
390 | { | ||
391 | unsigned long *buf = addr; | ||
392 | unsigned long *portp; | ||
393 | |||
394 | portp = PORT2ADDR(port); | ||
395 | while (count--) | ||
396 | *buf++ = *(volatile unsigned long *)portp; | ||
397 | } | ||
398 | |||
399 | void _outsb(unsigned int port, const void * addr, unsigned long count) | ||
400 | { | ||
401 | const unsigned char *buf = addr; | ||
402 | unsigned char *portp; | ||
403 | |||
404 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
405 | portp = PORT2ADDR_NE(port); | ||
406 | while (count--) | ||
407 | _ne_outb(*buf++, portp); | ||
408 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
409 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
410 | portp = __port2addr_ata(port); | ||
411 | while (count--) | ||
412 | *(volatile unsigned char *)portp = *buf++; | ||
413 | #endif | ||
414 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
415 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
416 | pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
417 | count, 1); | ||
418 | #endif | ||
419 | } else { | ||
420 | portp = PORT2ADDR(port); | ||
421 | while (count--) | ||
422 | *(volatile unsigned char *)portp = *buf++; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | void _outsw(unsigned int port, const void * addr, unsigned long count) | ||
427 | { | ||
428 | const unsigned short *buf = addr; | ||
429 | unsigned short *portp; | ||
430 | |||
431 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
432 | portp = PORT2ADDR_NE(port); | ||
433 | while (count--) | ||
434 | *(volatile unsigned short *)portp = *buf++; | ||
435 | #if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) | ||
436 | } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { | ||
437 | portp = __port2addr_ata(port); | ||
438 | while (count--) | ||
439 | *(volatile unsigned short *)portp = *buf++; | ||
440 | #endif | ||
441 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
442 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
443 | pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), | ||
444 | count, 1); | ||
445 | #endif | ||
446 | } else { | ||
447 | portp = PORT2ADDR(port); | ||
448 | while (count--) | ||
449 | *(volatile unsigned short *)portp = *buf++; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | void _outsl(unsigned int port, const void * addr, unsigned long count) | ||
454 | { | ||
455 | const unsigned long *buf = addr; | ||
456 | unsigned char *portp; | ||
457 | |||
458 | portp = PORT2ADDR(port); | ||
459 | while (count--) | ||
460 | *(volatile unsigned long *)portp = *buf++; | ||
461 | } | ||
diff --git a/arch/m32r/kernel/io_oaks32r.c b/arch/m32r/kernel/io_oaks32r.c new file mode 100644 index 000000000000..286964794d51 --- /dev/null +++ b/arch/m32r/kernel/io_oaks32r.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_oaks32r.c | ||
3 | * | ||
4 | * Typical I/O routines for OAKS32R board. | ||
5 | * | ||
6 | * Copyright (c) 2001-2004 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Mamoru Sakugawa | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <asm/m32r.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <asm/io.h> | ||
14 | |||
15 | #define PORT2ADDR(port) _port2addr(port) | ||
16 | |||
17 | static inline void *_port2addr(unsigned long port) | ||
18 | { | ||
19 | return (void *)(port + NONCACHE_OFFSET); | ||
20 | } | ||
21 | |||
22 | static inline void *_port2addr_ne(unsigned long port) | ||
23 | { | ||
24 | return (void *)((port<<1) + NONCACHE_OFFSET + 0x02000000); | ||
25 | } | ||
26 | |||
27 | static inline void delay(void) | ||
28 | { | ||
29 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * NIC I/O function | ||
34 | */ | ||
35 | |||
36 | #define PORT2ADDR_NE(port) _port2addr_ne(port) | ||
37 | |||
38 | static inline unsigned char _ne_inb(void *portp) | ||
39 | { | ||
40 | return *(volatile unsigned char *)(portp+1); | ||
41 | } | ||
42 | |||
43 | static inline unsigned short _ne_inw(void *portp) | ||
44 | { | ||
45 | unsigned short tmp; | ||
46 | |||
47 | tmp = *(unsigned short *)(portp) & 0xff; | ||
48 | tmp |= *(unsigned short *)(portp+2) << 8; | ||
49 | return tmp; | ||
50 | } | ||
51 | |||
52 | static inline void _ne_insb(void *portp, void *addr, unsigned long count) | ||
53 | { | ||
54 | unsigned char *buf = addr; | ||
55 | while (count--) | ||
56 | *buf++ = *(volatile unsigned char *)(portp+1); | ||
57 | } | ||
58 | |||
59 | static inline void _ne_outb(unsigned char b, void *portp) | ||
60 | { | ||
61 | *(volatile unsigned char *)(portp+1) = b; | ||
62 | } | ||
63 | |||
64 | static inline void _ne_outw(unsigned short w, void *portp) | ||
65 | { | ||
66 | *(volatile unsigned short *)portp = (w >> 8); | ||
67 | *(volatile unsigned short *)(portp+2) = (w & 0xff); | ||
68 | } | ||
69 | |||
70 | unsigned char _inb(unsigned long port) | ||
71 | { | ||
72 | if (port >= 0x300 && port < 0x320) | ||
73 | return _ne_inb(PORT2ADDR_NE(port)); | ||
74 | |||
75 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
76 | } | ||
77 | |||
78 | unsigned short _inw(unsigned long port) | ||
79 | { | ||
80 | if (port >= 0x300 && port < 0x320) | ||
81 | return _ne_inw(PORT2ADDR_NE(port)); | ||
82 | |||
83 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
84 | } | ||
85 | |||
86 | unsigned long _inl(unsigned long port) | ||
87 | { | ||
88 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
89 | } | ||
90 | |||
91 | unsigned char _inb_p(unsigned long port) | ||
92 | { | ||
93 | unsigned char v; | ||
94 | |||
95 | if (port >= 0x300 && port < 0x320) | ||
96 | v = _ne_inb(PORT2ADDR_NE(port)); | ||
97 | else | ||
98 | v = *(volatile unsigned char *)PORT2ADDR(port); | ||
99 | |||
100 | delay(); | ||
101 | return (v); | ||
102 | } | ||
103 | |||
104 | unsigned short _inw_p(unsigned long port) | ||
105 | { | ||
106 | unsigned short v; | ||
107 | |||
108 | if (port >= 0x300 && port < 0x320) | ||
109 | v = _ne_inw(PORT2ADDR_NE(port)); | ||
110 | else | ||
111 | v = *(volatile unsigned short *)PORT2ADDR(port); | ||
112 | |||
113 | delay(); | ||
114 | return (v); | ||
115 | } | ||
116 | |||
117 | unsigned long _inl_p(unsigned long port) | ||
118 | { | ||
119 | unsigned long v; | ||
120 | |||
121 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
122 | delay(); | ||
123 | return (v); | ||
124 | } | ||
125 | |||
126 | void _outb(unsigned char b, unsigned long port) | ||
127 | { | ||
128 | if (port >= 0x300 && port < 0x320) | ||
129 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
130 | else | ||
131 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
132 | } | ||
133 | |||
134 | void _outw(unsigned short w, unsigned long port) | ||
135 | { | ||
136 | if (port >= 0x300 && port < 0x320) | ||
137 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
138 | else | ||
139 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
140 | } | ||
141 | |||
142 | void _outl(unsigned long l, unsigned long port) | ||
143 | { | ||
144 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
145 | } | ||
146 | |||
147 | void _outb_p(unsigned char b, unsigned long port) | ||
148 | { | ||
149 | if (port >= 0x300 && port < 0x320) | ||
150 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
151 | else | ||
152 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
153 | |||
154 | delay(); | ||
155 | } | ||
156 | |||
157 | void _outw_p(unsigned short w, unsigned long port) | ||
158 | { | ||
159 | if (port >= 0x300 && port < 0x320) | ||
160 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
161 | else | ||
162 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
163 | |||
164 | delay(); | ||
165 | } | ||
166 | |||
167 | void _outl_p(unsigned long l, unsigned long port) | ||
168 | { | ||
169 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
170 | delay(); | ||
171 | } | ||
172 | |||
173 | void _insb(unsigned int port, void *addr, unsigned long count) | ||
174 | { | ||
175 | if (port >= 0x300 && port < 0x320) | ||
176 | _ne_insb(PORT2ADDR_NE(port), addr, count); | ||
177 | else { | ||
178 | unsigned char *buf = addr; | ||
179 | unsigned char *portp = PORT2ADDR(port); | ||
180 | while (count--) | ||
181 | *buf++ = *(volatile unsigned char *)portp; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | void _insw(unsigned int port, void *addr, unsigned long count) | ||
186 | { | ||
187 | unsigned short *buf = addr; | ||
188 | unsigned short *portp; | ||
189 | |||
190 | if (port >= 0x300 && port < 0x320) { | ||
191 | portp = PORT2ADDR_NE(port); | ||
192 | while (count--) | ||
193 | *buf++ = _ne_inw(portp); | ||
194 | } else { | ||
195 | portp = PORT2ADDR(port); | ||
196 | while (count--) | ||
197 | *buf++ = *(volatile unsigned short *)portp; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | void _insl(unsigned int port, void *addr, unsigned long count) | ||
202 | { | ||
203 | unsigned long *buf = addr; | ||
204 | unsigned long *portp; | ||
205 | |||
206 | portp = PORT2ADDR(port); | ||
207 | while (count--) | ||
208 | *buf++ = *(volatile unsigned long *)portp; | ||
209 | } | ||
210 | |||
211 | void _outsb(unsigned int port, const void *addr, unsigned long count) | ||
212 | { | ||
213 | const unsigned char *buf = addr; | ||
214 | unsigned char *portp; | ||
215 | |||
216 | if (port >= 0x300 && port < 0x320) { | ||
217 | portp = PORT2ADDR_NE(port); | ||
218 | while (count--) | ||
219 | _ne_outb(*buf++, portp); | ||
220 | } else { | ||
221 | portp = PORT2ADDR(port); | ||
222 | while (count--) | ||
223 | *(volatile unsigned char *)portp = *buf++; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | void _outsw(unsigned int port, const void *addr, unsigned long count) | ||
228 | { | ||
229 | const unsigned short *buf = addr; | ||
230 | unsigned short *portp; | ||
231 | |||
232 | if (port >= 0x300 && port < 0x320) { | ||
233 | portp = PORT2ADDR_NE(port); | ||
234 | while (count--) | ||
235 | _ne_outw(*buf++, portp); | ||
236 | } else { | ||
237 | portp = PORT2ADDR(port); | ||
238 | while (count--) | ||
239 | *(volatile unsigned short *)portp = *buf++; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | void _outsl(unsigned int port, const void *addr, unsigned long count) | ||
244 | { | ||
245 | const unsigned long *buf = addr; | ||
246 | unsigned char *portp; | ||
247 | |||
248 | portp = PORT2ADDR(port); | ||
249 | while (count--) | ||
250 | *(volatile unsigned long *)portp = *buf++; | ||
251 | } | ||
diff --git a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c new file mode 100644 index 000000000000..aaf42f9f76da --- /dev/null +++ b/arch/m32r/kernel/io_opsput.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_mappi.c | ||
3 | * | ||
4 | * Typical I/O routines for OPSPUT board. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Takeo Takahashi | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <asm/m32r.h> | ||
16 | #include <asm/page.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/byteorder.h> | ||
19 | |||
20 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
21 | #include <linux/types.h> | ||
22 | |||
23 | #define M32R_PCC_IOMAP_SIZE 0x1000 | ||
24 | |||
25 | #define M32R_PCC_IOSTART0 0x1000 | ||
26 | #define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) | ||
27 | |||
28 | extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); | ||
29 | extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); | ||
30 | extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); | ||
31 | extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); | ||
32 | #endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ | ||
33 | |||
34 | #define PORT2ADDR(port) _port2addr(port) | ||
35 | #define PORT2ADDR_USB(port) _port2addr_usb(port) | ||
36 | |||
37 | static inline void *_port2addr(unsigned long port) | ||
38 | { | ||
39 | return (void *)(port + NONCACHE_OFFSET); | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * OPSPUT-LAN is located in the extended bus space | ||
44 | * from 0x10000000 to 0x13ffffff on physical address. | ||
45 | * The base address of LAN controller(LAN91C111) is 0x300. | ||
46 | */ | ||
47 | #define LAN_IOSTART 0x300 | ||
48 | #define LAN_IOEND 0x320 | ||
49 | static inline void *_port2addr_ne(unsigned long port) | ||
50 | { | ||
51 | return (void *)(port + NONCACHE_OFFSET + 0x10000000); | ||
52 | } | ||
53 | static inline void *_port2addr_usb(unsigned long port) | ||
54 | { | ||
55 | return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000); | ||
56 | } | ||
57 | |||
58 | static inline void delay(void) | ||
59 | { | ||
60 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * NIC I/O function | ||
65 | */ | ||
66 | |||
67 | #define PORT2ADDR_NE(port) _port2addr_ne(port) | ||
68 | |||
69 | static inline unsigned char _ne_inb(void *portp) | ||
70 | { | ||
71 | return *(volatile unsigned char *)portp; | ||
72 | } | ||
73 | |||
74 | static inline unsigned short _ne_inw(void *portp) | ||
75 | { | ||
76 | return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); | ||
77 | } | ||
78 | |||
79 | static inline void _ne_insb(void *portp, void *addr, unsigned long count) | ||
80 | { | ||
81 | unsigned char *buf = (unsigned char *)addr; | ||
82 | |||
83 | while (count--) | ||
84 | *buf++ = _ne_inb(portp); | ||
85 | } | ||
86 | |||
87 | static inline void _ne_outb(unsigned char b, void *portp) | ||
88 | { | ||
89 | *(volatile unsigned char *)portp = b; | ||
90 | } | ||
91 | |||
92 | static inline void _ne_outw(unsigned short w, void *portp) | ||
93 | { | ||
94 | *(volatile unsigned short *)portp = cpu_to_le16(w); | ||
95 | } | ||
96 | |||
97 | unsigned char _inb(unsigned long port) | ||
98 | { | ||
99 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
100 | return _ne_inb(PORT2ADDR_NE(port)); | ||
101 | |||
102 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
103 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
104 | unsigned char b; | ||
105 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
106 | return b; | ||
107 | } else | ||
108 | #endif | ||
109 | |||
110 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
111 | } | ||
112 | |||
113 | unsigned short _inw(unsigned long port) | ||
114 | { | ||
115 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
116 | return _ne_inw(PORT2ADDR_NE(port)); | ||
117 | #if defined(CONFIG_USB) | ||
118 | else if(port >= 0x340 && port < 0x3a0) | ||
119 | return *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
120 | #endif | ||
121 | |||
122 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
123 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
124 | unsigned short w; | ||
125 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
126 | return w; | ||
127 | } else | ||
128 | #endif | ||
129 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
130 | } | ||
131 | |||
132 | unsigned long _inl(unsigned long port) | ||
133 | { | ||
134 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
135 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
136 | unsigned long l; | ||
137 | pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); | ||
138 | return l; | ||
139 | } else | ||
140 | #endif | ||
141 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
142 | } | ||
143 | |||
144 | unsigned char _inb_p(unsigned long port) | ||
145 | { | ||
146 | unsigned char v; | ||
147 | |||
148 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
149 | v = _ne_inb(PORT2ADDR_NE(port)); | ||
150 | else | ||
151 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
152 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
153 | unsigned char b; | ||
154 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
155 | return b; | ||
156 | } else | ||
157 | #endif | ||
158 | v = *(volatile unsigned char *)PORT2ADDR(port); | ||
159 | |||
160 | delay(); | ||
161 | return (v); | ||
162 | } | ||
163 | |||
164 | unsigned short _inw_p(unsigned long port) | ||
165 | { | ||
166 | unsigned short v; | ||
167 | |||
168 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
169 | v = _ne_inw(PORT2ADDR_NE(port)); | ||
170 | else | ||
171 | #if defined(CONFIG_USB) | ||
172 | if(port >= 0x340 && port < 0x3a0) | ||
173 | return *(volatile unsigned short *)PORT2ADDR_USB(port); | ||
174 | else | ||
175 | #endif | ||
176 | |||
177 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
178 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
179 | unsigned short w; | ||
180 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
181 | return w; | ||
182 | } else | ||
183 | #endif | ||
184 | v = *(volatile unsigned short *)PORT2ADDR(port); | ||
185 | |||
186 | delay(); | ||
187 | return (v); | ||
188 | } | ||
189 | |||
190 | unsigned long _inl_p(unsigned long port) | ||
191 | { | ||
192 | unsigned long v; | ||
193 | |||
194 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
195 | delay(); | ||
196 | return (v); | ||
197 | } | ||
198 | |||
199 | void _outb(unsigned char b, unsigned long port) | ||
200 | { | ||
201 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
202 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
203 | else | ||
204 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
205 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
206 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
207 | } else | ||
208 | #endif | ||
209 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
210 | } | ||
211 | |||
212 | void _outw(unsigned short w, unsigned long port) | ||
213 | { | ||
214 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
215 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
216 | else | ||
217 | #if defined(CONFIG_USB) | ||
218 | if(port >= 0x340 && port < 0x3a0) | ||
219 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
220 | else | ||
221 | #endif | ||
222 | |||
223 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
224 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
225 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
226 | } else | ||
227 | #endif | ||
228 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
229 | } | ||
230 | |||
231 | void _outl(unsigned long l, unsigned long port) | ||
232 | { | ||
233 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
234 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
235 | pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); | ||
236 | } else | ||
237 | #endif | ||
238 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
239 | } | ||
240 | |||
241 | void _outb_p(unsigned char b, unsigned long port) | ||
242 | { | ||
243 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
244 | _ne_outb(b, PORT2ADDR_NE(port)); | ||
245 | else | ||
246 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
247 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
248 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
249 | } else | ||
250 | #endif | ||
251 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
252 | |||
253 | delay(); | ||
254 | } | ||
255 | |||
256 | void _outw_p(unsigned short w, unsigned long port) | ||
257 | { | ||
258 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
259 | _ne_outw(w, PORT2ADDR_NE(port)); | ||
260 | else | ||
261 | #if defined(CONFIG_USB) | ||
262 | if(port >= 0x340 && port < 0x3a0) | ||
263 | *(volatile unsigned short *)PORT2ADDR_USB(port) = w; | ||
264 | else | ||
265 | #endif | ||
266 | |||
267 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
268 | if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
269 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
270 | } else | ||
271 | #endif | ||
272 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
273 | |||
274 | delay(); | ||
275 | } | ||
276 | |||
277 | void _outl_p(unsigned long l, unsigned long port) | ||
278 | { | ||
279 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
280 | delay(); | ||
281 | } | ||
282 | |||
283 | void _insb(unsigned int port, void *addr, unsigned long count) | ||
284 | { | ||
285 | if (port >= LAN_IOSTART && port < LAN_IOEND) | ||
286 | _ne_insb(PORT2ADDR_NE(port), addr, count); | ||
287 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
288 | else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
289 | pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
290 | count, 1); | ||
291 | } | ||
292 | #endif | ||
293 | else { | ||
294 | unsigned char *buf = addr; | ||
295 | unsigned char *portp = PORT2ADDR(port); | ||
296 | while (count--) | ||
297 | *buf++ = *(volatile unsigned char *)portp; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void _insw(unsigned int port, void *addr, unsigned long count) | ||
302 | { | ||
303 | unsigned short *buf = addr; | ||
304 | unsigned short *portp; | ||
305 | |||
306 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
307 | /* | ||
308 | * This portion is only used by smc91111.c to read data | ||
309 | * from the DATA_REG. Do not swap the data. | ||
310 | */ | ||
311 | portp = PORT2ADDR_NE(port); | ||
312 | while (count--) | ||
313 | *buf++ = *(volatile unsigned short *)portp; | ||
314 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
315 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
316 | pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), | ||
317 | count, 1); | ||
318 | #endif | ||
319 | } else { | ||
320 | portp = PORT2ADDR(port); | ||
321 | while (count--) | ||
322 | *buf++ = *(volatile unsigned short *)portp; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | void _insl(unsigned int port, void *addr, unsigned long count) | ||
327 | { | ||
328 | unsigned long *buf = addr; | ||
329 | unsigned long *portp; | ||
330 | |||
331 | portp = PORT2ADDR(port); | ||
332 | while (count--) | ||
333 | *buf++ = *(volatile unsigned long *)portp; | ||
334 | } | ||
335 | |||
336 | void _outsb(unsigned int port, const void *addr, unsigned long count) | ||
337 | { | ||
338 | const unsigned char *buf = addr; | ||
339 | unsigned char *portp; | ||
340 | |||
341 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
342 | portp = PORT2ADDR_NE(port); | ||
343 | while (count--) | ||
344 | _ne_outb(*buf++, portp); | ||
345 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
346 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
347 | pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
348 | count, 1); | ||
349 | #endif | ||
350 | } else { | ||
351 | portp = PORT2ADDR(port); | ||
352 | while (count--) | ||
353 | *(volatile unsigned char *)portp = *buf++; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | void _outsw(unsigned int port, const void *addr, unsigned long count) | ||
358 | { | ||
359 | const unsigned short *buf = addr; | ||
360 | unsigned short *portp; | ||
361 | |||
362 | if (port >= LAN_IOSTART && port < LAN_IOEND) { | ||
363 | /* | ||
364 | * This portion is only used by smc91111.c to write data | ||
365 | * into the DATA_REG. Do not swap the data. | ||
366 | */ | ||
367 | portp = PORT2ADDR_NE(port); | ||
368 | while (count--) | ||
369 | *(volatile unsigned short *)portp = *buf++; | ||
370 | #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) | ||
371 | } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { | ||
372 | pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), | ||
373 | count, 1); | ||
374 | #endif | ||
375 | } else { | ||
376 | portp = PORT2ADDR(port); | ||
377 | while (count--) | ||
378 | *(volatile unsigned short *)portp = *buf++; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | void _outsl(unsigned int port, const void *addr, unsigned long count) | ||
383 | { | ||
384 | const unsigned long *buf = addr; | ||
385 | unsigned char *portp; | ||
386 | |||
387 | portp = PORT2ADDR(port); | ||
388 | while (count--) | ||
389 | *(volatile unsigned long *)portp = *buf++; | ||
390 | } | ||
diff --git a/arch/m32r/kernel/io_usrv.c b/arch/m32r/kernel/io_usrv.c new file mode 100644 index 000000000000..27928a0b99ed --- /dev/null +++ b/arch/m32r/kernel/io_usrv.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/io_usrv.c | ||
3 | * | ||
4 | * Typical I/O routines for uServer board. | ||
5 | * | ||
6 | * Copyright (c) 2001 - 2003 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Takeo Takahashi | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <asm/m32r.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include "../drivers/m32r_cfc.h" | ||
22 | |||
23 | extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); | ||
24 | extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); | ||
25 | extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); | ||
26 | extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); | ||
27 | #define CFC_IOSTART CFC_IOPORT_BASE | ||
28 | #define CFC_IOEND (CFC_IOSTART + (M32R_PCC_MAPSIZE * M32R_MAX_PCC) - 1) | ||
29 | |||
30 | #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) | ||
31 | #define UART0_REGSTART 0x04c20000 | ||
32 | #define UART1_REGSTART 0x04c20100 | ||
33 | #define UART_IOMAP_SIZE 8 | ||
34 | #define UART0_IOSTART 0x3f8 | ||
35 | #define UART0_IOEND (UART0_IOSTART + UART_IOMAP_SIZE - 1) | ||
36 | #define UART1_IOSTART 0x2f8 | ||
37 | #define UART1_IOEND (UART1_IOSTART + UART_IOMAP_SIZE - 1) | ||
38 | #endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ | ||
39 | |||
40 | #define PORT2ADDR(port) _port2addr(port) | ||
41 | |||
42 | static __inline__ void *_port2addr(unsigned long port) | ||
43 | { | ||
44 | #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) | ||
45 | if (port >= UART0_IOSTART && port <= UART0_IOEND) | ||
46 | port = ((port - UART0_IOSTART) << 1) + UART0_REGSTART; | ||
47 | else if (port >= UART1_IOSTART && port <= UART1_IOEND) | ||
48 | port = ((port - UART1_IOSTART) << 1) + UART1_REGSTART; | ||
49 | #endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ | ||
50 | return (void *)(port + NONCACHE_OFFSET); | ||
51 | } | ||
52 | |||
53 | static __inline__ void delay(void) | ||
54 | { | ||
55 | __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); | ||
56 | } | ||
57 | |||
58 | unsigned char _inb(unsigned long port) | ||
59 | { | ||
60 | if (port >= CFC_IOSTART && port <= CFC_IOEND) { | ||
61 | unsigned char b; | ||
62 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
63 | return b; | ||
64 | } else | ||
65 | return *(volatile unsigned char *)PORT2ADDR(port); | ||
66 | } | ||
67 | |||
68 | unsigned short _inw(unsigned long port) | ||
69 | { | ||
70 | if (port >= CFC_IOSTART && port <= CFC_IOEND) { | ||
71 | unsigned short w; | ||
72 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
73 | return w; | ||
74 | } else | ||
75 | return *(volatile unsigned short *)PORT2ADDR(port); | ||
76 | } | ||
77 | |||
78 | unsigned long _inl(unsigned long port) | ||
79 | { | ||
80 | if (port >= CFC_IOSTART && port <= CFC_IOEND) { | ||
81 | unsigned long l; | ||
82 | pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); | ||
83 | return l; | ||
84 | } else | ||
85 | return *(volatile unsigned long *)PORT2ADDR(port); | ||
86 | } | ||
87 | |||
88 | unsigned char _inb_p(unsigned long port) | ||
89 | { | ||
90 | unsigned char b; | ||
91 | |||
92 | if (port >= CFC_IOSTART && port <= CFC_IOEND) { | ||
93 | pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); | ||
94 | return b; | ||
95 | } else { | ||
96 | b = *(volatile unsigned char *)PORT2ADDR(port); | ||
97 | delay(); | ||
98 | return b; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | unsigned short _inw_p(unsigned long port) | ||
103 | { | ||
104 | unsigned short w; | ||
105 | |||
106 | if (port >= CFC_IOSTART && port <= CFC_IOEND) { | ||
107 | pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); | ||
108 | return w; | ||
109 | } else { | ||
110 | w = *(volatile unsigned short *)PORT2ADDR(port); | ||
111 | delay(); | ||
112 | return w; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | unsigned long _inl_p(unsigned long port) | ||
117 | { | ||
118 | unsigned long v; | ||
119 | |||
120 | v = *(volatile unsigned long *)PORT2ADDR(port); | ||
121 | delay(); | ||
122 | |||
123 | return v; | ||
124 | } | ||
125 | |||
126 | void _outb(unsigned char b, unsigned long port) | ||
127 | { | ||
128 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
129 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
130 | else | ||
131 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
132 | } | ||
133 | |||
134 | void _outw(unsigned short w, unsigned long port) | ||
135 | { | ||
136 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
137 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
138 | else | ||
139 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
140 | } | ||
141 | |||
142 | void _outl(unsigned long l, unsigned long port) | ||
143 | { | ||
144 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
145 | pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); | ||
146 | else | ||
147 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
148 | } | ||
149 | |||
150 | void _outb_p(unsigned char b, unsigned long port) | ||
151 | { | ||
152 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
153 | pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); | ||
154 | else | ||
155 | *(volatile unsigned char *)PORT2ADDR(port) = b; | ||
156 | delay(); | ||
157 | } | ||
158 | |||
159 | void _outw_p(unsigned short w, unsigned long port) | ||
160 | { | ||
161 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
162 | pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); | ||
163 | else | ||
164 | *(volatile unsigned short *)PORT2ADDR(port) = w; | ||
165 | delay(); | ||
166 | } | ||
167 | |||
168 | void _outl_p(unsigned long l, unsigned long port) | ||
169 | { | ||
170 | *(volatile unsigned long *)PORT2ADDR(port) = l; | ||
171 | delay(); | ||
172 | } | ||
173 | |||
174 | void _insb(unsigned int port, void * addr, unsigned long count) | ||
175 | { | ||
176 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
177 | pcc_ioread_byte(0, port, addr, sizeof(unsigned char), count, 1); | ||
178 | else { | ||
179 | unsigned char *buf = addr; | ||
180 | unsigned char *portp = PORT2ADDR(port); | ||
181 | while (count--) | ||
182 | *buf++ = *(volatile unsigned char *)portp; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | void _insw(unsigned int port, void * addr, unsigned long count) | ||
187 | { | ||
188 | unsigned short *buf = addr; | ||
189 | unsigned short *portp; | ||
190 | |||
191 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
192 | pcc_ioread_word(0, port, addr, sizeof(unsigned short), count, | ||
193 | 1); | ||
194 | else { | ||
195 | portp = PORT2ADDR(port); | ||
196 | while (count--) | ||
197 | *buf++ = *(volatile unsigned short *)portp; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | void _insl(unsigned int port, void * addr, unsigned long count) | ||
202 | { | ||
203 | unsigned long *buf = addr; | ||
204 | unsigned long *portp; | ||
205 | |||
206 | portp = PORT2ADDR(port); | ||
207 | while (count--) | ||
208 | *buf++ = *(volatile unsigned long *)portp; | ||
209 | } | ||
210 | |||
211 | void _outsb(unsigned int port, const void * addr, unsigned long count) | ||
212 | { | ||
213 | const unsigned char *buf = addr; | ||
214 | unsigned char *portp; | ||
215 | |||
216 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
217 | pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), | ||
218 | count, 1); | ||
219 | else { | ||
220 | portp = PORT2ADDR(port); | ||
221 | while (count--) | ||
222 | *(volatile unsigned char *)portp = *buf++; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | void _outsw(unsigned int port, const void * addr, unsigned long count) | ||
227 | { | ||
228 | const unsigned short *buf = addr; | ||
229 | unsigned short *portp; | ||
230 | |||
231 | if (port >= CFC_IOSTART && port <= CFC_IOEND) | ||
232 | pcc_iowrite_word(0, port, (void *)addr, sizeof(unsigned short), | ||
233 | count, 1); | ||
234 | else { | ||
235 | portp = PORT2ADDR(port); | ||
236 | while (count--) | ||
237 | *(volatile unsigned short *)portp = *buf++; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | void _outsl(unsigned int port, const void * addr, unsigned long count) | ||
242 | { | ||
243 | const unsigned long *buf = addr; | ||
244 | unsigned char *portp; | ||
245 | |||
246 | portp = PORT2ADDR(port); | ||
247 | while (count--) | ||
248 | *(volatile unsigned long *)portp = *buf++; | ||
249 | } | ||
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c new file mode 100644 index 000000000000..1ce63926a3c0 --- /dev/null +++ b/arch/m32r/kernel/irq.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/irq.c | ||
3 | * | ||
4 | * Copyright (c) 2003, 2004 Hitoshi Yamamoto | ||
5 | * Copyright (c) 2004 Hirokazu Takata <takata at linux-m32r.org> | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * linux/arch/i386/kernel/irq.c | ||
10 | * | ||
11 | * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar | ||
12 | * | ||
13 | * This file contains the lowest level m32r-specific interrupt | ||
14 | * entry and irq statistics code. All the remaining irq logic is | ||
15 | * done by the generic kernel/irq/ code and in the | ||
16 | * m32r-specific irq controller code. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel_stat.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
25 | atomic_t irq_err_count; | ||
26 | atomic_t irq_mis_count; | ||
27 | |||
28 | /* | ||
29 | * Generic, controller-independent functions: | ||
30 | */ | ||
31 | |||
32 | int show_interrupts(struct seq_file *p, void *v) | ||
33 | { | ||
34 | int i = *(loff_t *) v, j; | ||
35 | struct irqaction * action; | ||
36 | unsigned long flags; | ||
37 | |||
38 | if (i == 0) { | ||
39 | seq_printf(p, " "); | ||
40 | for (j=0; j<NR_CPUS; j++) | ||
41 | if (cpu_online(j)) | ||
42 | seq_printf(p, "CPU%d ",j); | ||
43 | seq_putc(p, '\n'); | ||
44 | } | ||
45 | |||
46 | if (i < NR_IRQS) { | ||
47 | spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
48 | action = irq_desc[i].action; | ||
49 | if (!action) | ||
50 | goto skip; | ||
51 | seq_printf(p, "%3d: ",i); | ||
52 | #ifndef CONFIG_SMP | ||
53 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
54 | #else | ||
55 | for (j = 0; j < NR_CPUS; j++) | ||
56 | if (cpu_online(j)) | ||
57 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | ||
58 | #endif | ||
59 | seq_printf(p, " %14s", irq_desc[i].handler->typename); | ||
60 | seq_printf(p, " %s", action->name); | ||
61 | |||
62 | for (action=action->next; action; action = action->next) | ||
63 | seq_printf(p, ", %s", action->name); | ||
64 | |||
65 | seq_putc(p, '\n'); | ||
66 | skip: | ||
67 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
68 | } else if (i == NR_IRQS) { | ||
69 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | ||
70 | seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * do_IRQ handles all normal device IRQ's (the special | ||
77 | * SMP cross-CPU interrupts have their own specific | ||
78 | * handlers). | ||
79 | */ | ||
80 | asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) | ||
81 | { | ||
82 | irq_enter(); | ||
83 | |||
84 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
85 | /* FIXME M32R */ | ||
86 | #endif | ||
87 | __do_IRQ(irq, regs); | ||
88 | irq_exit(); | ||
89 | |||
90 | return 1; | ||
91 | } | ||
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c new file mode 100644 index 000000000000..e5ec134d81d9 --- /dev/null +++ b/arch/m32r/kernel/m32r_ksyms.c | |||
@@ -0,0 +1,140 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/smp.h> | ||
4 | #include <linux/user.h> | ||
5 | #include <linux/elfcore.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <linux/in6.h> | ||
8 | #include <linux/interrupt.h> | ||
9 | #include <linux/smp_lock.h> | ||
10 | #include <linux/string.h> | ||
11 | |||
12 | #include <asm/semaphore.h> | ||
13 | #include <asm/processor.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/checksum.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/delay.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/tlbflush.h> | ||
20 | |||
21 | extern void dump_thread(struct pt_regs *, struct user *); | ||
22 | |||
23 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) | ||
24 | extern struct drive_info_struct drive_info; | ||
25 | EXPORT_SYMBOL(drive_info); | ||
26 | #endif | ||
27 | |||
28 | /* platform dependent support */ | ||
29 | EXPORT_SYMBOL(boot_cpu_data); | ||
30 | EXPORT_SYMBOL(dump_thread); | ||
31 | EXPORT_SYMBOL(dump_fpu); | ||
32 | EXPORT_SYMBOL(__ioremap); | ||
33 | EXPORT_SYMBOL(iounmap); | ||
34 | EXPORT_SYMBOL(enable_irq); | ||
35 | EXPORT_SYMBOL(disable_irq); | ||
36 | EXPORT_SYMBOL(disable_irq_nosync); | ||
37 | EXPORT_SYMBOL(kernel_thread); | ||
38 | EXPORT_SYMBOL(__down); | ||
39 | EXPORT_SYMBOL(__down_interruptible); | ||
40 | EXPORT_SYMBOL(__up); | ||
41 | EXPORT_SYMBOL(__down_trylock); | ||
42 | |||
43 | /* Networking helper routines. */ | ||
44 | /* Delay loops */ | ||
45 | EXPORT_SYMBOL(__udelay); | ||
46 | EXPORT_SYMBOL(__delay); | ||
47 | EXPORT_SYMBOL(__const_udelay); | ||
48 | |||
49 | EXPORT_SYMBOL(__get_user_1); | ||
50 | EXPORT_SYMBOL(__get_user_2); | ||
51 | EXPORT_SYMBOL(__get_user_4); | ||
52 | |||
53 | EXPORT_SYMBOL(strpbrk); | ||
54 | EXPORT_SYMBOL(strstr); | ||
55 | |||
56 | EXPORT_SYMBOL(strncpy_from_user); | ||
57 | EXPORT_SYMBOL(__strncpy_from_user); | ||
58 | EXPORT_SYMBOL(clear_user); | ||
59 | EXPORT_SYMBOL(__clear_user); | ||
60 | EXPORT_SYMBOL(__generic_copy_from_user); | ||
61 | EXPORT_SYMBOL(__generic_copy_to_user); | ||
62 | EXPORT_SYMBOL(strnlen_user); | ||
63 | |||
64 | #ifdef CONFIG_SMP | ||
65 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
66 | extern void *dcache_dummy; | ||
67 | EXPORT_SYMBOL(dcache_dummy); | ||
68 | #endif | ||
69 | EXPORT_SYMBOL(cpu_data); | ||
70 | EXPORT_SYMBOL(cpu_online_map); | ||
71 | EXPORT_SYMBOL(cpu_callout_map); | ||
72 | |||
73 | /* Global SMP stuff */ | ||
74 | EXPORT_SYMBOL(synchronize_irq); | ||
75 | EXPORT_SYMBOL(smp_call_function); | ||
76 | |||
77 | /* TLB flushing */ | ||
78 | EXPORT_SYMBOL(smp_flush_tlb_page); | ||
79 | #endif | ||
80 | |||
81 | /* compiler generated symbol */ | ||
82 | extern void __ashldi3(void); | ||
83 | extern void __ashrdi3(void); | ||
84 | extern void __lshldi3(void); | ||
85 | extern void __lshrdi3(void); | ||
86 | extern void __muldi3(void); | ||
87 | EXPORT_SYMBOL(__ashldi3); | ||
88 | EXPORT_SYMBOL(__ashrdi3); | ||
89 | EXPORT_SYMBOL(__lshldi3); | ||
90 | EXPORT_SYMBOL(__lshrdi3); | ||
91 | EXPORT_SYMBOL(__muldi3); | ||
92 | |||
93 | /* memory and string operations */ | ||
94 | EXPORT_SYMBOL(memchr); | ||
95 | EXPORT_SYMBOL(memcpy); | ||
96 | /* EXPORT_SYMBOL(memcpy_fromio); // not implement yet */ | ||
97 | /* EXPORT_SYMBOL(memcpy_toio); // not implement yet */ | ||
98 | EXPORT_SYMBOL(memset); | ||
99 | /* EXPORT_SYMBOL(memset_io); // not implement yet */ | ||
100 | EXPORT_SYMBOL(memmove); | ||
101 | EXPORT_SYMBOL(memcmp); | ||
102 | EXPORT_SYMBOL(memscan); | ||
103 | EXPORT_SYMBOL(copy_page); | ||
104 | EXPORT_SYMBOL(clear_page); | ||
105 | |||
106 | EXPORT_SYMBOL(strcat); | ||
107 | EXPORT_SYMBOL(strchr); | ||
108 | EXPORT_SYMBOL(strcmp); | ||
109 | EXPORT_SYMBOL(strcpy); | ||
110 | EXPORT_SYMBOL(strlen); | ||
111 | EXPORT_SYMBOL(strncat); | ||
112 | EXPORT_SYMBOL(strncmp); | ||
113 | EXPORT_SYMBOL(strnlen); | ||
114 | EXPORT_SYMBOL(strncpy); | ||
115 | |||
116 | EXPORT_SYMBOL(_inb); | ||
117 | EXPORT_SYMBOL(_inw); | ||
118 | EXPORT_SYMBOL(_inl); | ||
119 | EXPORT_SYMBOL(_outb); | ||
120 | EXPORT_SYMBOL(_outw); | ||
121 | EXPORT_SYMBOL(_outl); | ||
122 | EXPORT_SYMBOL(_inb_p); | ||
123 | EXPORT_SYMBOL(_inw_p); | ||
124 | EXPORT_SYMBOL(_inl_p); | ||
125 | EXPORT_SYMBOL(_outb_p); | ||
126 | EXPORT_SYMBOL(_outw_p); | ||
127 | EXPORT_SYMBOL(_outl_p); | ||
128 | EXPORT_SYMBOL(_insb); | ||
129 | EXPORT_SYMBOL(_insw); | ||
130 | EXPORT_SYMBOL(_insl); | ||
131 | EXPORT_SYMBOL(_outsb); | ||
132 | EXPORT_SYMBOL(_outsw); | ||
133 | EXPORT_SYMBOL(_outsl); | ||
134 | EXPORT_SYMBOL(_readb); | ||
135 | EXPORT_SYMBOL(_readw); | ||
136 | EXPORT_SYMBOL(_readl); | ||
137 | EXPORT_SYMBOL(_writeb); | ||
138 | EXPORT_SYMBOL(_writew); | ||
139 | EXPORT_SYMBOL(_writel); | ||
140 | |||
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c new file mode 100644 index 000000000000..f6a79a016ce0 --- /dev/null +++ b/arch/m32r/kernel/module.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* Kernel module help for M32R. | ||
2 | |||
3 | This program is free software; you can redistribute it and/or modify | ||
4 | it under the terms of the GNU General Public License as published by | ||
5 | the Free Software Foundation; either version 2 of the License, or | ||
6 | (at your option) any later version. | ||
7 | |||
8 | This program is distributed in the hope that it will be useful, | ||
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License | ||
14 | along with this program; if not, write to the Free Software | ||
15 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/moduleloader.h> | ||
20 | #include <linux/elf.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/kernel.h> | ||
25 | |||
26 | #if 0 | ||
27 | #define DEBUGP printk | ||
28 | #else | ||
29 | #define DEBUGP(fmt...) | ||
30 | #endif | ||
31 | |||
32 | void *module_alloc(unsigned long size) | ||
33 | { | ||
34 | if (size == 0) | ||
35 | return NULL; | ||
36 | #ifdef CONFIG_MMU | ||
37 | return vmalloc_exec(size); | ||
38 | #else | ||
39 | return vmalloc(size); | ||
40 | #endif | ||
41 | } | ||
42 | |||
43 | |||
44 | /* Free memory returned from module_alloc */ | ||
45 | void module_free(struct module *mod, void *module_region) | ||
46 | { | ||
47 | vfree(module_region); | ||
48 | /* FIXME: If module_region == mod->init_region, trim exception | ||
49 | table entries. */ | ||
50 | } | ||
51 | |||
52 | /* We don't need anything special. */ | ||
53 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
54 | Elf_Shdr *sechdrs, | ||
55 | char *secstrings, | ||
56 | struct module *mod) | ||
57 | { | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | #define COPY_UNALIGNED_WORD(sw, tw, align) \ | ||
62 | { \ | ||
63 | void *__s = &(sw), *__t = &(tw); \ | ||
64 | unsigned short *__s2 = __s, *__t2 =__t; \ | ||
65 | unsigned char *__s1 = __s, *__t1 =__t; \ | ||
66 | switch ((align)) \ | ||
67 | { \ | ||
68 | case 0: \ | ||
69 | *(unsigned long *) __t = *(unsigned long *) __s; \ | ||
70 | break; \ | ||
71 | case 2: \ | ||
72 | *__t2++ = *__s2++; \ | ||
73 | *__t2 = *__s2; \ | ||
74 | break; \ | ||
75 | default: \ | ||
76 | *__t1++ = *__s1++; \ | ||
77 | *__t1++ = *__s1++; \ | ||
78 | *__t1++ = *__s1++; \ | ||
79 | *__t1 = *__s1; \ | ||
80 | break; \ | ||
81 | } \ | ||
82 | } | ||
83 | |||
84 | #define COPY_UNALIGNED_HWORD(sw, tw, align) \ | ||
85 | { \ | ||
86 | void *__s = &(sw), *__t = &(tw); \ | ||
87 | unsigned short *__s2 = __s, *__t2 =__t; \ | ||
88 | unsigned char *__s1 = __s, *__t1 =__t; \ | ||
89 | switch ((align)) \ | ||
90 | { \ | ||
91 | case 0: \ | ||
92 | *__t2 = *__s2; \ | ||
93 | break; \ | ||
94 | default: \ | ||
95 | *__t1++ = *__s1++; \ | ||
96 | *__t1 = *__s1; \ | ||
97 | break; \ | ||
98 | } \ | ||
99 | } | ||
100 | |||
101 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
102 | const char *strtab, | ||
103 | unsigned int symindex, | ||
104 | unsigned int relsec, | ||
105 | struct module *me) | ||
106 | { | ||
107 | unsigned int i; | ||
108 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; | ||
109 | Elf32_Sym *sym; | ||
110 | Elf32_Addr relocation; | ||
111 | uint32_t *location; | ||
112 | uint32_t value; | ||
113 | unsigned short *hlocation; | ||
114 | unsigned short hvalue; | ||
115 | int svalue; | ||
116 | int align; | ||
117 | |||
118 | DEBUGP("Applying relocate section %u to %u\n", relsec, | ||
119 | sechdrs[relsec].sh_info); | ||
120 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
121 | /* This is where to make the change */ | ||
122 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
123 | + rel[i].r_offset; | ||
124 | /* This is the symbol it is referring to. Note that all | ||
125 | undefined symbols have been resolved. */ | ||
126 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
127 | + ELF32_R_SYM(rel[i].r_info); | ||
128 | relocation = sym->st_value + rel[i].r_addend; | ||
129 | align = (int)location & 3; | ||
130 | |||
131 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
132 | case R_M32R_32_RELA: | ||
133 | COPY_UNALIGNED_WORD (*location, value, align); | ||
134 | value += relocation; | ||
135 | COPY_UNALIGNED_WORD (value, *location, align); | ||
136 | break; | ||
137 | case R_M32R_HI16_ULO_RELA: | ||
138 | COPY_UNALIGNED_WORD (*location, value, align); | ||
139 | relocation = (relocation >>16) & 0xffff; | ||
140 | /* RELA must has 0 at relocation field. */ | ||
141 | value += relocation; | ||
142 | COPY_UNALIGNED_WORD (value, *location, align); | ||
143 | break; | ||
144 | case R_M32R_HI16_SLO_RELA: | ||
145 | COPY_UNALIGNED_WORD (*location, value, align); | ||
146 | if (relocation & 0x8000) relocation += 0x10000; | ||
147 | relocation = (relocation >>16) & 0xffff; | ||
148 | /* RELA must has 0 at relocation field. */ | ||
149 | value += relocation; | ||
150 | COPY_UNALIGNED_WORD (value, *location, align); | ||
151 | break; | ||
152 | case R_M32R_16_RELA: | ||
153 | hlocation = (unsigned short *)location; | ||
154 | relocation = relocation & 0xffff; | ||
155 | /* RELA must has 0 at relocation field. */ | ||
156 | hvalue = relocation; | ||
157 | COPY_UNALIGNED_WORD (hvalue, *hlocation, align); | ||
158 | break; | ||
159 | case R_M32R_SDA16_RELA: | ||
160 | case R_M32R_LO16_RELA: | ||
161 | COPY_UNALIGNED_WORD (*location, value, align); | ||
162 | relocation = relocation & 0xffff; | ||
163 | /* RELA must has 0 at relocation field. */ | ||
164 | value += relocation; | ||
165 | COPY_UNALIGNED_WORD (value, *location, align); | ||
166 | break; | ||
167 | case R_M32R_24_RELA: | ||
168 | COPY_UNALIGNED_WORD (*location, value, align); | ||
169 | relocation = relocation & 0xffffff; | ||
170 | /* RELA must has 0 at relocation field. */ | ||
171 | value += relocation; | ||
172 | COPY_UNALIGNED_WORD (value, *location, align); | ||
173 | break; | ||
174 | case R_M32R_18_PCREL_RELA: | ||
175 | relocation = (relocation - (Elf32_Addr) location); | ||
176 | if (relocation < -0x20000 || 0x1fffc < relocation) | ||
177 | { | ||
178 | printk(KERN_ERR "module %s: relocation overflow: %u\n", | ||
179 | me->name, relocation); | ||
180 | return -ENOEXEC; | ||
181 | } | ||
182 | COPY_UNALIGNED_WORD (*location, value, align); | ||
183 | if (value & 0xffff) | ||
184 | { | ||
185 | /* RELA must has 0 at relocation field. */ | ||
186 | printk(KERN_ERR "module %s: illegal relocation field: %u\n", | ||
187 | me->name, value); | ||
188 | return -ENOEXEC; | ||
189 | } | ||
190 | relocation = (relocation >> 2) & 0xffff; | ||
191 | value += relocation; | ||
192 | COPY_UNALIGNED_WORD (value, *location, align); | ||
193 | break; | ||
194 | case R_M32R_10_PCREL_RELA: | ||
195 | hlocation = (unsigned short *)location; | ||
196 | relocation = (relocation - (Elf32_Addr) location); | ||
197 | COPY_UNALIGNED_HWORD (*hlocation, hvalue, align); | ||
198 | svalue = (int)hvalue; | ||
199 | svalue = (signed char)svalue << 2; | ||
200 | relocation += svalue; | ||
201 | relocation = (relocation >> 2) & 0xff; | ||
202 | hvalue = hvalue & 0xff00; | ||
203 | hvalue += relocation; | ||
204 | COPY_UNALIGNED_HWORD (hvalue, *hlocation, align); | ||
205 | break; | ||
206 | case R_M32R_26_PCREL_RELA: | ||
207 | relocation = (relocation - (Elf32_Addr) location); | ||
208 | if (relocation < -0x2000000 || 0x1fffffc < relocation) | ||
209 | { | ||
210 | printk(KERN_ERR "module %s: relocation overflow: %u\n", | ||
211 | me->name, relocation); | ||
212 | return -ENOEXEC; | ||
213 | } | ||
214 | COPY_UNALIGNED_WORD (*location, value, align); | ||
215 | if (value & 0xffffff) | ||
216 | { | ||
217 | /* RELA must has 0 at relocation field. */ | ||
218 | printk(KERN_ERR "module %s: illegal relocation field: %u\n", | ||
219 | me->name, value); | ||
220 | return -ENOEXEC; | ||
221 | } | ||
222 | relocation = (relocation >> 2) & 0xffffff; | ||
223 | value += relocation; | ||
224 | COPY_UNALIGNED_WORD (value, *location, align); | ||
225 | break; | ||
226 | default: | ||
227 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
228 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
229 | return -ENOEXEC; | ||
230 | } | ||
231 | } | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int apply_relocate(Elf32_Shdr *sechdrs, | ||
236 | const char *strtab, | ||
237 | unsigned int symindex, | ||
238 | unsigned int relsec, | ||
239 | struct module *me) | ||
240 | { | ||
241 | #if 0 | ||
242 | printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", | ||
243 | me->name); | ||
244 | return -ENOEXEC; | ||
245 | #endif | ||
246 | return 0; | ||
247 | |||
248 | } | ||
249 | |||
250 | int module_finalize(const Elf_Ehdr *hdr, | ||
251 | const Elf_Shdr *sechdrs, | ||
252 | struct module *me) | ||
253 | { | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | void module_arch_cleanup(struct module *mod) | ||
258 | { | ||
259 | } | ||
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c new file mode 100644 index 000000000000..b556c3cf6495 --- /dev/null +++ b/arch/m32r/kernel/process.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/process.c | ||
3 | * | ||
4 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
5 | * Hitoshi Yamamoto | ||
6 | * Taken from sh version. | ||
7 | * Copyright (C) 1995 Linus Torvalds | ||
8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | ||
9 | */ | ||
10 | |||
11 | #undef DEBUG_PROCESS | ||
12 | #ifdef DEBUG_PROCESS | ||
13 | #define DPRINTK(fmt, args...) printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \ | ||
14 | __FUNCTION__, ##args) | ||
15 | #else | ||
16 | #define DPRINTK(fmt, args...) | ||
17 | #endif | ||
18 | |||
19 | /* | ||
20 | * This file handles the architecture-dependent parts of process handling.. | ||
21 | */ | ||
22 | |||
23 | #include <linux/fs.h> | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/ptrace.h> | ||
27 | #include <linux/unistd.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/hardirq.h> | ||
30 | |||
31 | #include <asm/io.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | #include <asm/mmu_context.h> | ||
34 | #include <asm/elf.h> | ||
35 | #include <asm/m32r.h> | ||
36 | |||
37 | #include <linux/err.h> | ||
38 | |||
39 | static int hlt_counter=0; | ||
40 | |||
41 | /* | ||
42 | * Return saved PC of a blocked thread. | ||
43 | */ | ||
44 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
45 | { | ||
46 | return tsk->thread.lr; | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Powermanagement idle function, if any.. | ||
51 | */ | ||
52 | void (*pm_idle)(void) = NULL; | ||
53 | |||
54 | void disable_hlt(void) | ||
55 | { | ||
56 | hlt_counter++; | ||
57 | } | ||
58 | |||
59 | EXPORT_SYMBOL(disable_hlt); | ||
60 | |||
61 | void enable_hlt(void) | ||
62 | { | ||
63 | hlt_counter--; | ||
64 | } | ||
65 | |||
66 | EXPORT_SYMBOL(enable_hlt); | ||
67 | |||
68 | /* | ||
69 | * We use this is we don't have any better | ||
70 | * idle routine.. | ||
71 | */ | ||
72 | void default_idle(void) | ||
73 | { | ||
74 | /* M32R_FIXME: Please use "cpu_sleep" mode. */ | ||
75 | cpu_relax(); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * On SMP it's slightly faster (but much more power-consuming!) | ||
80 | * to poll the ->work.need_resched flag instead of waiting for the | ||
81 | * cross-CPU IPI to arrive. Use this option with caution. | ||
82 | */ | ||
83 | static void poll_idle (void) | ||
84 | { | ||
85 | /* M32R_FIXME */ | ||
86 | cpu_relax(); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * The idle thread. There's no useful work to be | ||
91 | * done, so just try to conserve power and have a | ||
92 | * low exit latency (ie sit in a loop waiting for | ||
93 | * somebody to say that they'd like to reschedule) | ||
94 | */ | ||
95 | void cpu_idle (void) | ||
96 | { | ||
97 | /* endless idle loop with no priority at all */ | ||
98 | while (1) { | ||
99 | while (!need_resched()) { | ||
100 | void (*idle)(void) = pm_idle; | ||
101 | |||
102 | if (!idle) | ||
103 | idle = default_idle; | ||
104 | |||
105 | idle(); | ||
106 | } | ||
107 | schedule(); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void machine_restart(char *__unused) | ||
112 | { | ||
113 | printk("Please push reset button!\n"); | ||
114 | while (1) | ||
115 | cpu_relax(); | ||
116 | } | ||
117 | |||
118 | EXPORT_SYMBOL(machine_restart); | ||
119 | |||
120 | void machine_halt(void) | ||
121 | { | ||
122 | printk("Please push reset button!\n"); | ||
123 | while (1) | ||
124 | cpu_relax(); | ||
125 | } | ||
126 | |||
127 | EXPORT_SYMBOL(machine_halt); | ||
128 | |||
129 | void machine_power_off(void) | ||
130 | { | ||
131 | /* M32R_FIXME */ | ||
132 | } | ||
133 | |||
134 | EXPORT_SYMBOL(machine_power_off); | ||
135 | |||
136 | static int __init idle_setup (char *str) | ||
137 | { | ||
138 | if (!strncmp(str, "poll", 4)) { | ||
139 | printk("using poll in idle threads.\n"); | ||
140 | pm_idle = poll_idle; | ||
141 | } else if (!strncmp(str, "sleep", 4)) { | ||
142 | printk("using sleep in idle threads.\n"); | ||
143 | pm_idle = default_idle; | ||
144 | } | ||
145 | |||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | __setup("idle=", idle_setup); | ||
150 | |||
151 | void show_regs(struct pt_regs * regs) | ||
152 | { | ||
153 | printk("\n"); | ||
154 | printk("BPC[%08lx]:PSW[%08lx]:LR [%08lx]:FP [%08lx]\n", \ | ||
155 | regs->bpc, regs->psw, regs->lr, regs->fp); | ||
156 | printk("BBPC[%08lx]:BBPSW[%08lx]:SPU[%08lx]:SPI[%08lx]\n", \ | ||
157 | regs->bbpc, regs->bbpsw, regs->spu, regs->spi); | ||
158 | printk("R0 [%08lx]:R1 [%08lx]:R2 [%08lx]:R3 [%08lx]\n", \ | ||
159 | regs->r0, regs->r1, regs->r2, regs->r3); | ||
160 | printk("R4 [%08lx]:R5 [%08lx]:R6 [%08lx]:R7 [%08lx]\n", \ | ||
161 | regs->r4, regs->r5, regs->r6, regs->r7); | ||
162 | printk("R8 [%08lx]:R9 [%08lx]:R10[%08lx]:R11[%08lx]\n", \ | ||
163 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
164 | printk("R12[%08lx]\n", \ | ||
165 | regs->r12); | ||
166 | |||
167 | #if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) | ||
168 | printk("ACC0H[%08lx]:ACC0L[%08lx]\n", \ | ||
169 | regs->acc0h, regs->acc0l); | ||
170 | printk("ACC1H[%08lx]:ACC1L[%08lx]\n", \ | ||
171 | regs->acc1h, regs->acc1l); | ||
172 | #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) | ||
173 | printk("ACCH[%08lx]:ACCL[%08lx]\n", \ | ||
174 | regs->acch, regs->accl); | ||
175 | #else | ||
176 | #error unknown isa configuration | ||
177 | #endif | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Create a kernel thread | ||
182 | */ | ||
183 | |||
184 | /* | ||
185 | * This is the mechanism for creating a new kernel thread. | ||
186 | * | ||
187 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
188 | * who haven't done an "execve()") should use this: it will work within | ||
189 | * a system call from a "real" process, but the process memory space will | ||
190 | * not be free'd until both the parent and the child have exited. | ||
191 | */ | ||
192 | static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) | ||
193 | { | ||
194 | fn(arg); | ||
195 | do_exit(-1); | ||
196 | } | ||
197 | |||
198 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
199 | { | ||
200 | struct pt_regs regs; | ||
201 | |||
202 | memset(®s, 0, sizeof (regs)); | ||
203 | regs.r1 = (unsigned long)fn; | ||
204 | regs.r2 = (unsigned long)arg; | ||
205 | |||
206 | regs.bpc = (unsigned long)kernel_thread_helper; | ||
207 | |||
208 | regs.psw = M32R_PSW_BIE; | ||
209 | |||
210 | /* Ok, create the new process. */ | ||
211 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, | ||
212 | NULL); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * Free current thread data structures etc.. | ||
217 | */ | ||
218 | void exit_thread(void) | ||
219 | { | ||
220 | /* Nothing to do. */ | ||
221 | DPRINTK("pid = %d\n", current->pid); | ||
222 | } | ||
223 | |||
224 | void flush_thread(void) | ||
225 | { | ||
226 | DPRINTK("pid = %d\n", current->pid); | ||
227 | memset(¤t->thread.debug_trap, 0, sizeof(struct debug_trap)); | ||
228 | } | ||
229 | |||
230 | void release_thread(struct task_struct *dead_task) | ||
231 | { | ||
232 | /* do nothing */ | ||
233 | DPRINTK("pid = %d\n", dead_task->pid); | ||
234 | } | ||
235 | |||
236 | /* Fill in the fpu structure for a core dump.. */ | ||
237 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | ||
238 | { | ||
239 | return 0; /* Task didn't use the fpu at all. */ | ||
240 | } | ||
241 | |||
242 | int copy_thread(int nr, unsigned long clone_flags, unsigned long spu, | ||
243 | unsigned long unused, struct task_struct *tsk, struct pt_regs *regs) | ||
244 | { | ||
245 | struct pt_regs *childregs; | ||
246 | unsigned long sp = (unsigned long)tsk->thread_info + THREAD_SIZE; | ||
247 | extern void ret_from_fork(void); | ||
248 | |||
249 | /* Copy registers */ | ||
250 | sp -= sizeof (struct pt_regs); | ||
251 | childregs = (struct pt_regs *)sp; | ||
252 | *childregs = *regs; | ||
253 | |||
254 | childregs->spu = spu; | ||
255 | childregs->r0 = 0; /* Child gets zero as return value */ | ||
256 | regs->r0 = tsk->pid; | ||
257 | tsk->thread.sp = (unsigned long)childregs; | ||
258 | tsk->thread.lr = (unsigned long)ret_from_fork; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * fill in the user structure for a core dump.. | ||
265 | */ | ||
266 | void dump_thread(struct pt_regs * regs, struct user * dump) | ||
267 | { | ||
268 | /* M32R_FIXME */ | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Capture the user space registers if the task is not running (in user space) | ||
273 | */ | ||
274 | int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) | ||
275 | { | ||
276 | /* M32R_FIXME */ | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, | ||
281 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
282 | struct pt_regs regs) | ||
283 | { | ||
284 | #ifdef CONFIG_MMU | ||
285 | return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL); | ||
286 | #else | ||
287 | return -EINVAL; | ||
288 | #endif /* CONFIG_MMU */ | ||
289 | } | ||
290 | |||
291 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
292 | unsigned long parent_tidptr, | ||
293 | unsigned long child_tidptr, | ||
294 | unsigned long r4, unsigned long r5, unsigned long r6, | ||
295 | struct pt_regs regs) | ||
296 | { | ||
297 | if (!newsp) | ||
298 | newsp = regs.spu; | ||
299 | |||
300 | return do_fork(clone_flags, newsp, ®s, 0, | ||
301 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * This is trivial, and on the face of it looks like it | ||
306 | * could equally well be done in user mode. | ||
307 | * | ||
308 | * Not so, for quite unobvious reasons - register pressure. | ||
309 | * In user mode vfork() cannot have a stack frame, and if | ||
310 | * done by calling the "clone()" system call directly, you | ||
311 | * do not have enough call-clobbered registers to hold all | ||
312 | * the information you need. | ||
313 | */ | ||
314 | asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, | ||
315 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
316 | struct pt_regs regs) | ||
317 | { | ||
318 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, | ||
319 | NULL, NULL); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * sys_execve() executes a new program. | ||
324 | */ | ||
325 | asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, | ||
326 | char __user * __user *uenvp, | ||
327 | unsigned long r3, unsigned long r4, unsigned long r5, | ||
328 | unsigned long r6, struct pt_regs regs) | ||
329 | { | ||
330 | int error; | ||
331 | char *filename; | ||
332 | |||
333 | filename = getname(ufilename); | ||
334 | error = PTR_ERR(filename); | ||
335 | if (IS_ERR(filename)) | ||
336 | goto out; | ||
337 | |||
338 | error = do_execve(filename, uargv, uenvp, ®s); | ||
339 | if (error == 0) { | ||
340 | task_lock(current); | ||
341 | current->ptrace &= ~PT_DTRACE; | ||
342 | task_unlock(current); | ||
343 | } | ||
344 | putname(filename); | ||
345 | out: | ||
346 | return error; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * These bracket the sleeping functions.. | ||
351 | */ | ||
352 | #define first_sched ((unsigned long) scheduling_functions_start_here) | ||
353 | #define last_sched ((unsigned long) scheduling_functions_end_here) | ||
354 | |||
355 | unsigned long get_wchan(struct task_struct *p) | ||
356 | { | ||
357 | /* M32R_FIXME */ | ||
358 | return (0); | ||
359 | } | ||
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c new file mode 100644 index 000000000000..8b40f362dd6f --- /dev/null +++ b/arch/m32r/kernel/ptrace.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/ptrace.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Hirokazu Takata, Takeo Takahashi | ||
5 | * Copyright (C) 2004 Hirokazu Takata, Kei Sakamoto | ||
6 | * | ||
7 | * Original x86 implementation: | ||
8 | * By Ross Biro 1/23/92 | ||
9 | * edited by Linus Torvalds | ||
10 | * | ||
11 | * Some code taken from sh version: | ||
12 | * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka | ||
13 | * Some code taken from arm version: | ||
14 | * Copyright (C) 2000 Russell King | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <linux/smp_lock.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/user.h> | ||
26 | #include <linux/string.h> | ||
27 | |||
28 | #include <asm/cacheflush.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | #include <asm/pgtable.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/processor.h> | ||
34 | #include <asm/mmu_context.h> | ||
35 | |||
36 | /* | ||
37 | * Get the address of the live pt_regs for the specified task. | ||
38 | * These are saved onto the top kernel stack when the process | ||
39 | * is not running. | ||
40 | * | ||
41 | * Note: if a user thread is execve'd from kernel space, the | ||
42 | * kernel stack will not be empty on entry to the kernel, so | ||
43 | * ptracing these tasks will fail. | ||
44 | */ | ||
45 | static inline struct pt_regs * | ||
46 | get_user_regs(struct task_struct *task) | ||
47 | { | ||
48 | return (struct pt_regs *) | ||
49 | ((unsigned long)task->thread_info + THREAD_SIZE | ||
50 | - sizeof(struct pt_regs)); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * This routine will get a word off of the process kernel stack. | ||
55 | */ | ||
56 | static inline unsigned long int | ||
57 | get_stack_long(struct task_struct *task, int offset) | ||
58 | { | ||
59 | unsigned long *stack; | ||
60 | |||
61 | stack = (unsigned long *)get_user_regs(task); | ||
62 | |||
63 | return stack[offset]; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * This routine will put a word on the process kernel stack. | ||
68 | */ | ||
69 | static inline int | ||
70 | put_stack_long(struct task_struct *task, int offset, unsigned long data) | ||
71 | { | ||
72 | unsigned long *stack; | ||
73 | |||
74 | stack = (unsigned long *)get_user_regs(task); | ||
75 | stack[offset] = data; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int reg_offset[] = { | ||
81 | PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, | ||
82 | PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU, | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * Read the word at offset "off" into the "struct user". We | ||
87 | * actually access the pt_regs stored on the kernel stack. | ||
88 | */ | ||
89 | static int ptrace_read_user(struct task_struct *tsk, unsigned long off, | ||
90 | unsigned long __user *data) | ||
91 | { | ||
92 | unsigned long tmp; | ||
93 | #ifndef NO_FPU | ||
94 | struct user * dummy = NULL; | ||
95 | #endif | ||
96 | |||
97 | if ((off & 3) || (off < 0) || (off > sizeof(struct user) - 3)) | ||
98 | return -EIO; | ||
99 | |||
100 | off >>= 2; | ||
101 | switch (off) { | ||
102 | case PT_EVB: | ||
103 | __asm__ __volatile__ ( | ||
104 | "mvfc %0, cr5 \n\t" | ||
105 | : "=r" (tmp) | ||
106 | ); | ||
107 | break; | ||
108 | case PT_CBR: { | ||
109 | unsigned long psw; | ||
110 | psw = get_stack_long(tsk, PT_PSW); | ||
111 | tmp = ((psw >> 8) & 1); | ||
112 | } | ||
113 | break; | ||
114 | case PT_PSW: { | ||
115 | unsigned long psw, bbpsw; | ||
116 | psw = get_stack_long(tsk, PT_PSW); | ||
117 | bbpsw = get_stack_long(tsk, PT_BBPSW); | ||
118 | tmp = ((psw >> 8) & 0xff) | ((bbpsw & 0xff) << 8); | ||
119 | } | ||
120 | break; | ||
121 | case PT_PC: | ||
122 | tmp = get_stack_long(tsk, PT_BPC); | ||
123 | break; | ||
124 | case PT_BPC: | ||
125 | off = PT_BBPC; | ||
126 | /* fall through */ | ||
127 | default: | ||
128 | if (off < (sizeof(struct pt_regs) >> 2)) | ||
129 | tmp = get_stack_long(tsk, off); | ||
130 | #ifndef NO_FPU | ||
131 | else if (off >= (long)(&dummy->fpu >> 2) && | ||
132 | off < (long)(&dummy->u_fpvalid >> 2)) { | ||
133 | if (!tsk_used_math(tsk)) { | ||
134 | if (off == (long)(&dummy->fpu.fpscr >> 2)) | ||
135 | tmp = FPSCR_INIT; | ||
136 | else | ||
137 | tmp = 0; | ||
138 | } else | ||
139 | tmp = ((long *)(&tsk->thread.fpu >> 2)) | ||
140 | [off - (long)&dummy->fpu]; | ||
141 | } else if (off == (long)(&dummy->u_fpvalid >> 2)) | ||
142 | tmp = !!tsk_used_math(tsk); | ||
143 | #endif /* not NO_FPU */ | ||
144 | else | ||
145 | tmp = 0; | ||
146 | } | ||
147 | |||
148 | return put_user(tmp, data); | ||
149 | } | ||
150 | |||
151 | static int ptrace_write_user(struct task_struct *tsk, unsigned long off, | ||
152 | unsigned long data) | ||
153 | { | ||
154 | int ret = -EIO; | ||
155 | #ifndef NO_FPU | ||
156 | struct user * dummy = NULL; | ||
157 | #endif | ||
158 | |||
159 | if ((off & 3) || off < 0 || | ||
160 | off > sizeof(struct user) - 3) | ||
161 | return -EIO; | ||
162 | |||
163 | off >>= 2; | ||
164 | switch (off) { | ||
165 | case PT_EVB: | ||
166 | case PT_BPC: | ||
167 | case PT_SPI: | ||
168 | /* We don't allow to modify evb. */ | ||
169 | ret = 0; | ||
170 | break; | ||
171 | case PT_PSW: | ||
172 | case PT_CBR: { | ||
173 | /* We allow to modify only cbr in psw */ | ||
174 | unsigned long psw; | ||
175 | psw = get_stack_long(tsk, PT_PSW); | ||
176 | psw = (psw & ~0x100) | ((data & 1) << 8); | ||
177 | ret = put_stack_long(tsk, PT_PSW, psw); | ||
178 | } | ||
179 | break; | ||
180 | case PT_PC: | ||
181 | off = PT_BPC; | ||
182 | data &= ~1; | ||
183 | /* fall through */ | ||
184 | default: | ||
185 | if (off < (sizeof(struct pt_regs) >> 2)) | ||
186 | ret = put_stack_long(tsk, off, data); | ||
187 | #ifndef NO_FPU | ||
188 | else if (off >= (long)(&dummy->fpu >> 2) && | ||
189 | off < (long)(&dummy->u_fpvalid >> 2)) { | ||
190 | set_stopped_child_used_math(tsk); | ||
191 | ((long *)&tsk->thread.fpu) | ||
192 | [off - (long)&dummy->fpu] = data; | ||
193 | ret = 0; | ||
194 | } else if (off == (long)(&dummy->u_fpvalid >> 2)) { | ||
195 | conditional_stopped_child_used_math(data, tsk); | ||
196 | ret = 0; | ||
197 | } | ||
198 | #endif /* not NO_FPU */ | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Get all user integer registers. | ||
207 | */ | ||
208 | static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | ||
209 | { | ||
210 | struct pt_regs *regs = get_user_regs(tsk); | ||
211 | |||
212 | return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * Set all user integer registers. | ||
217 | */ | ||
218 | static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) | ||
219 | { | ||
220 | struct pt_regs newregs; | ||
221 | int ret; | ||
222 | |||
223 | ret = -EFAULT; | ||
224 | if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { | ||
225 | struct pt_regs *regs = get_user_regs(tsk); | ||
226 | *regs = newregs; | ||
227 | ret = 0; | ||
228 | } | ||
229 | |||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | |||
234 | static inline int | ||
235 | check_condition_bit(struct task_struct *child) | ||
236 | { | ||
237 | return (int)((get_stack_long(child, PT_PSW) >> 8) & 1); | ||
238 | } | ||
239 | |||
240 | static int | ||
241 | check_condition_src(unsigned long op, unsigned long regno1, | ||
242 | unsigned long regno2, struct task_struct *child) | ||
243 | { | ||
244 | unsigned long reg1, reg2; | ||
245 | |||
246 | reg2 = get_stack_long(child, reg_offset[regno2]); | ||
247 | |||
248 | switch (op) { | ||
249 | case 0x0: /* BEQ */ | ||
250 | reg1 = get_stack_long(child, reg_offset[regno1]); | ||
251 | return reg1 == reg2; | ||
252 | case 0x1: /* BNE */ | ||
253 | reg1 = get_stack_long(child, reg_offset[regno1]); | ||
254 | return reg1 != reg2; | ||
255 | case 0x8: /* BEQZ */ | ||
256 | return reg2 == 0; | ||
257 | case 0x9: /* BNEZ */ | ||
258 | return reg2 != 0; | ||
259 | case 0xa: /* BLTZ */ | ||
260 | return (int)reg2 < 0; | ||
261 | case 0xb: /* BGEZ */ | ||
262 | return (int)reg2 >= 0; | ||
263 | case 0xc: /* BLEZ */ | ||
264 | return (int)reg2 <= 0; | ||
265 | case 0xd: /* BGTZ */ | ||
266 | return (int)reg2 > 0; | ||
267 | default: | ||
268 | /* never reached */ | ||
269 | return 0; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | static void | ||
274 | compute_next_pc_for_16bit_insn(unsigned long insn, unsigned long pc, | ||
275 | unsigned long *next_pc, | ||
276 | struct task_struct *child) | ||
277 | { | ||
278 | unsigned long op, op2, op3; | ||
279 | unsigned long disp; | ||
280 | unsigned long regno; | ||
281 | int parallel = 0; | ||
282 | |||
283 | if (insn & 0x00008000) | ||
284 | parallel = 1; | ||
285 | if (pc & 3) | ||
286 | insn &= 0x7fff; /* right slot */ | ||
287 | else | ||
288 | insn >>= 16; /* left slot */ | ||
289 | |||
290 | op = (insn >> 12) & 0xf; | ||
291 | op2 = (insn >> 8) & 0xf; | ||
292 | op3 = (insn >> 4) & 0xf; | ||
293 | |||
294 | if (op == 0x7) { | ||
295 | switch (op2) { | ||
296 | case 0xd: /* BNC */ | ||
297 | case 0x9: /* BNCL */ | ||
298 | if (!check_condition_bit(child)) { | ||
299 | disp = (long)(insn << 24) >> 22; | ||
300 | *next_pc = (pc & ~0x3) + disp; | ||
301 | return; | ||
302 | } | ||
303 | break; | ||
304 | case 0x8: /* BCL */ | ||
305 | case 0xc: /* BC */ | ||
306 | if (check_condition_bit(child)) { | ||
307 | disp = (long)(insn << 24) >> 22; | ||
308 | *next_pc = (pc & ~0x3) + disp; | ||
309 | return; | ||
310 | } | ||
311 | break; | ||
312 | case 0xe: /* BL */ | ||
313 | case 0xf: /* BRA */ | ||
314 | disp = (long)(insn << 24) >> 22; | ||
315 | *next_pc = (pc & ~0x3) + disp; | ||
316 | return; | ||
317 | break; | ||
318 | } | ||
319 | } else if (op == 0x1) { | ||
320 | switch (op2) { | ||
321 | case 0x0: | ||
322 | if (op3 == 0xf) { /* TRAP */ | ||
323 | #if 1 | ||
324 | /* pass through */ | ||
325 | #else | ||
326 | /* kernel space is not allowed as next_pc */ | ||
327 | unsigned long evb; | ||
328 | unsigned long trapno; | ||
329 | trapno = insn & 0xf; | ||
330 | __asm__ __volatile__ ( | ||
331 | "mvfc %0, cr5\n" | ||
332 | :"=r"(evb) | ||
333 | : | ||
334 | ); | ||
335 | *next_pc = evb + (trapno << 2); | ||
336 | return; | ||
337 | #endif | ||
338 | } else if (op3 == 0xd) { /* RTE */ | ||
339 | *next_pc = get_stack_long(child, PT_BPC); | ||
340 | return; | ||
341 | } | ||
342 | break; | ||
343 | case 0xc: /* JC */ | ||
344 | if (op3 == 0xc && check_condition_bit(child)) { | ||
345 | regno = insn & 0xf; | ||
346 | *next_pc = get_stack_long(child, | ||
347 | reg_offset[regno]); | ||
348 | return; | ||
349 | } | ||
350 | break; | ||
351 | case 0xd: /* JNC */ | ||
352 | if (op3 == 0xc && !check_condition_bit(child)) { | ||
353 | regno = insn & 0xf; | ||
354 | *next_pc = get_stack_long(child, | ||
355 | reg_offset[regno]); | ||
356 | return; | ||
357 | } | ||
358 | break; | ||
359 | case 0xe: /* JL */ | ||
360 | case 0xf: /* JMP */ | ||
361 | if (op3 == 0xc) { /* JMP */ | ||
362 | regno = insn & 0xf; | ||
363 | *next_pc = get_stack_long(child, | ||
364 | reg_offset[regno]); | ||
365 | return; | ||
366 | } | ||
367 | break; | ||
368 | } | ||
369 | } | ||
370 | if (parallel) | ||
371 | *next_pc = pc + 4; | ||
372 | else | ||
373 | *next_pc = pc + 2; | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | compute_next_pc_for_32bit_insn(unsigned long insn, unsigned long pc, | ||
378 | unsigned long *next_pc, | ||
379 | struct task_struct *child) | ||
380 | { | ||
381 | unsigned long op; | ||
382 | unsigned long op2; | ||
383 | unsigned long disp; | ||
384 | unsigned long regno1, regno2; | ||
385 | |||
386 | op = (insn >> 28) & 0xf; | ||
387 | if (op == 0xf) { /* branch 24-bit relative */ | ||
388 | op2 = (insn >> 24) & 0xf; | ||
389 | switch (op2) { | ||
390 | case 0xd: /* BNC */ | ||
391 | case 0x9: /* BNCL */ | ||
392 | if (!check_condition_bit(child)) { | ||
393 | disp = (long)(insn << 8) >> 6; | ||
394 | *next_pc = (pc & ~0x3) + disp; | ||
395 | return; | ||
396 | } | ||
397 | break; | ||
398 | case 0x8: /* BCL */ | ||
399 | case 0xc: /* BC */ | ||
400 | if (check_condition_bit(child)) { | ||
401 | disp = (long)(insn << 8) >> 6; | ||
402 | *next_pc = (pc & ~0x3) + disp; | ||
403 | return; | ||
404 | } | ||
405 | break; | ||
406 | case 0xe: /* BL */ | ||
407 | case 0xf: /* BRA */ | ||
408 | disp = (long)(insn << 8) >> 6; | ||
409 | *next_pc = (pc & ~0x3) + disp; | ||
410 | return; | ||
411 | } | ||
412 | } else if (op == 0xb) { /* branch 16-bit relative */ | ||
413 | op2 = (insn >> 20) & 0xf; | ||
414 | switch (op2) { | ||
415 | case 0x0: /* BEQ */ | ||
416 | case 0x1: /* BNE */ | ||
417 | case 0x8: /* BEQZ */ | ||
418 | case 0x9: /* BNEZ */ | ||
419 | case 0xa: /* BLTZ */ | ||
420 | case 0xb: /* BGEZ */ | ||
421 | case 0xc: /* BLEZ */ | ||
422 | case 0xd: /* BGTZ */ | ||
423 | regno1 = ((insn >> 24) & 0xf); | ||
424 | regno2 = ((insn >> 16) & 0xf); | ||
425 | if (check_condition_src(op2, regno1, regno2, child)) { | ||
426 | disp = (long)(insn << 16) >> 14; | ||
427 | *next_pc = (pc & ~0x3) + disp; | ||
428 | return; | ||
429 | } | ||
430 | break; | ||
431 | } | ||
432 | } | ||
433 | *next_pc = pc + 4; | ||
434 | } | ||
435 | |||
436 | static inline void | ||
437 | compute_next_pc(unsigned long insn, unsigned long pc, | ||
438 | unsigned long *next_pc, struct task_struct *child) | ||
439 | { | ||
440 | if (insn & 0x80000000) | ||
441 | compute_next_pc_for_32bit_insn(insn, pc, next_pc, child); | ||
442 | else | ||
443 | compute_next_pc_for_16bit_insn(insn, pc, next_pc, child); | ||
444 | } | ||
445 | |||
446 | static int | ||
447 | register_debug_trap(struct task_struct *child, unsigned long next_pc, | ||
448 | unsigned long next_insn, unsigned long *code) | ||
449 | { | ||
450 | struct debug_trap *p = &child->thread.debug_trap; | ||
451 | unsigned long addr = next_pc & ~3; | ||
452 | |||
453 | if (p->nr_trap == MAX_TRAPS) { | ||
454 | printk("kernel BUG at %s %d: p->nr_trap = %d\n", | ||
455 | __FILE__, __LINE__, p->nr_trap); | ||
456 | return -1; | ||
457 | } | ||
458 | p->addr[p->nr_trap] = addr; | ||
459 | p->insn[p->nr_trap] = next_insn; | ||
460 | p->nr_trap++; | ||
461 | if (next_pc & 3) { | ||
462 | *code = (next_insn & 0xffff0000) | 0x10f1; | ||
463 | /* xxx --> TRAP1 */ | ||
464 | } else { | ||
465 | if ((next_insn & 0x80000000) || (next_insn & 0x8000)) { | ||
466 | *code = 0x10f17000; | ||
467 | /* TRAP1 --> NOP */ | ||
468 | } else { | ||
469 | *code = (next_insn & 0xffff) | 0x10f10000; | ||
470 | /* TRAP1 --> xxx */ | ||
471 | } | ||
472 | } | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int | ||
477 | unregister_debug_trap(struct task_struct *child, unsigned long addr, | ||
478 | unsigned long *code) | ||
479 | { | ||
480 | struct debug_trap *p = &child->thread.debug_trap; | ||
481 | int i; | ||
482 | |||
483 | /* Search debug trap entry. */ | ||
484 | for (i = 0; i < p->nr_trap; i++) { | ||
485 | if (p->addr[i] == addr) | ||
486 | break; | ||
487 | } | ||
488 | if (i >= p->nr_trap) { | ||
489 | /* The trap may be requested from debugger. | ||
490 | * ptrace should do nothing in this case. | ||
491 | */ | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /* Recover orignal instruction code. */ | ||
496 | *code = p->insn[i]; | ||
497 | |||
498 | /* Shift debug trap entries. */ | ||
499 | while (i < p->nr_trap - 1) { | ||
500 | p->insn[i] = p->insn[i + 1]; | ||
501 | p->addr[i] = p->addr[i + 1]; | ||
502 | i++; | ||
503 | } | ||
504 | p->nr_trap--; | ||
505 | return 1; | ||
506 | } | ||
507 | |||
508 | static void | ||
509 | unregister_all_debug_traps(struct task_struct *child) | ||
510 | { | ||
511 | struct debug_trap *p = &child->thread.debug_trap; | ||
512 | int i; | ||
513 | |||
514 | for (i = 0; i < p->nr_trap; i++) | ||
515 | access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1); | ||
516 | p->nr_trap = 0; | ||
517 | } | ||
518 | |||
519 | static inline void | ||
520 | invalidate_cache(void) | ||
521 | { | ||
522 | #if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) | ||
523 | |||
524 | _flush_cache_copyback_all(); | ||
525 | |||
526 | #else /* ! CONFIG_CHIP_M32700 */ | ||
527 | |||
528 | /* Invalidate cache */ | ||
529 | __asm__ __volatile__ ( | ||
530 | "ldi r0, #-1 \n\t" | ||
531 | "ldi r1, #0 \n\t" | ||
532 | "stb r1, @r0 ; cache off \n\t" | ||
533 | "; \n\t" | ||
534 | "ldi r0, #-2 \n\t" | ||
535 | "ldi r1, #1 \n\t" | ||
536 | "stb r1, @r0 ; cache invalidate \n\t" | ||
537 | ".fillinsn \n" | ||
538 | "0: \n\t" | ||
539 | "ldb r1, @r0 ; invalidate check \n\t" | ||
540 | "bnez r1, 0b \n\t" | ||
541 | "; \n\t" | ||
542 | "ldi r0, #-1 \n\t" | ||
543 | "ldi r1, #1 \n\t" | ||
544 | "stb r1, @r0 ; cache on \n\t" | ||
545 | : : : "r0", "r1", "memory" | ||
546 | ); | ||
547 | /* FIXME: copying-back d-cache and invalidating i-cache are needed. | ||
548 | */ | ||
549 | #endif /* CONFIG_CHIP_M32700 */ | ||
550 | } | ||
551 | |||
552 | /* Embed a debug trap (TRAP1) code */ | ||
553 | static int | ||
554 | embed_debug_trap(struct task_struct *child, unsigned long next_pc) | ||
555 | { | ||
556 | unsigned long next_insn, code; | ||
557 | unsigned long addr = next_pc & ~3; | ||
558 | |||
559 | if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0) | ||
560 | != sizeof(next_insn)) { | ||
561 | return -1; /* error */ | ||
562 | } | ||
563 | |||
564 | /* Set a trap code. */ | ||
565 | if (register_debug_trap(child, next_pc, next_insn, &code)) { | ||
566 | return -1; /* error */ | ||
567 | } | ||
568 | if (access_process_vm(child, addr, &code, sizeof(code), 1) | ||
569 | != sizeof(code)) { | ||
570 | return -1; /* error */ | ||
571 | } | ||
572 | return 0; /* success */ | ||
573 | } | ||
574 | |||
575 | void | ||
576 | withdraw_debug_trap(struct pt_regs *regs) | ||
577 | { | ||
578 | unsigned long addr; | ||
579 | unsigned long code; | ||
580 | |||
581 | addr = (regs->bpc - 2) & ~3; | ||
582 | regs->bpc -= 2; | ||
583 | if (unregister_debug_trap(current, addr, &code)) { | ||
584 | access_process_vm(current, addr, &code, sizeof(code), 1); | ||
585 | invalidate_cache(); | ||
586 | } | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | init_debug_traps(struct task_struct *child) | ||
591 | { | ||
592 | struct debug_trap *p = &child->thread.debug_trap; | ||
593 | int i; | ||
594 | p->nr_trap = 0; | ||
595 | for (i = 0; i < MAX_TRAPS; i++) { | ||
596 | p->addr[i] = 0; | ||
597 | p->insn[i] = 0; | ||
598 | } | ||
599 | } | ||
600 | |||
601 | |||
602 | /* | ||
603 | * Called by kernel/ptrace.c when detaching.. | ||
604 | * | ||
605 | * Make sure single step bits etc are not set. | ||
606 | */ | ||
607 | void ptrace_disable(struct task_struct *child) | ||
608 | { | ||
609 | /* nothing to do.. */ | ||
610 | } | ||
611 | |||
612 | static int | ||
613 | do_ptrace(long request, struct task_struct *child, long addr, long data) | ||
614 | { | ||
615 | unsigned long tmp; | ||
616 | int ret; | ||
617 | |||
618 | switch (request) { | ||
619 | /* | ||
620 | * read word at location "addr" in the child process. | ||
621 | */ | ||
622 | case PTRACE_PEEKTEXT: | ||
623 | case PTRACE_PEEKDATA: | ||
624 | ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
625 | if (ret == sizeof(tmp)) | ||
626 | ret = put_user(tmp,(unsigned long __user *) data); | ||
627 | else | ||
628 | ret = -EIO; | ||
629 | break; | ||
630 | |||
631 | /* | ||
632 | * read the word at location addr in the USER area. | ||
633 | */ | ||
634 | case PTRACE_PEEKUSR: | ||
635 | ret = ptrace_read_user(child, addr, | ||
636 | (unsigned long __user *)data); | ||
637 | break; | ||
638 | |||
639 | /* | ||
640 | * write the word at location addr. | ||
641 | */ | ||
642 | case PTRACE_POKETEXT: | ||
643 | case PTRACE_POKEDATA: | ||
644 | ret = access_process_vm(child, addr, &data, sizeof(data), 1); | ||
645 | if (ret == sizeof(data)) { | ||
646 | ret = 0; | ||
647 | if (request == PTRACE_POKETEXT) { | ||
648 | invalidate_cache(); | ||
649 | } | ||
650 | } else { | ||
651 | ret = -EIO; | ||
652 | } | ||
653 | break; | ||
654 | |||
655 | /* | ||
656 | * write the word at location addr in the USER area. | ||
657 | */ | ||
658 | case PTRACE_POKEUSR: | ||
659 | ret = ptrace_write_user(child, addr, data); | ||
660 | break; | ||
661 | |||
662 | /* | ||
663 | * continue/restart and stop at next (return from) syscall | ||
664 | */ | ||
665 | case PTRACE_SYSCALL: | ||
666 | case PTRACE_CONT: | ||
667 | ret = -EIO; | ||
668 | if ((unsigned long) data > _NSIG) | ||
669 | break; | ||
670 | if (request == PTRACE_SYSCALL) | ||
671 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
672 | else | ||
673 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
674 | child->exit_code = data; | ||
675 | wake_up_process(child); | ||
676 | ret = 0; | ||
677 | break; | ||
678 | |||
679 | /* | ||
680 | * make the child exit. Best I can do is send it a sigkill. | ||
681 | * perhaps it should be put in the status that it wants to | ||
682 | * exit. | ||
683 | */ | ||
684 | case PTRACE_KILL: { | ||
685 | ret = 0; | ||
686 | unregister_all_debug_traps(child); | ||
687 | invalidate_cache(); | ||
688 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
689 | break; | ||
690 | child->exit_code = SIGKILL; | ||
691 | wake_up_process(child); | ||
692 | break; | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * execute single instruction. | ||
697 | */ | ||
698 | case PTRACE_SINGLESTEP: { | ||
699 | unsigned long next_pc; | ||
700 | unsigned long pc, insn; | ||
701 | |||
702 | ret = -EIO; | ||
703 | if ((unsigned long) data > _NSIG) | ||
704 | break; | ||
705 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
706 | if ((child->ptrace & PT_DTRACE) == 0) { | ||
707 | /* Spurious delayed TF traps may occur */ | ||
708 | child->ptrace |= PT_DTRACE; | ||
709 | } | ||
710 | |||
711 | /* Compute next pc. */ | ||
712 | pc = get_stack_long(child, PT_BPC); | ||
713 | |||
714 | if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) | ||
715 | != sizeof(insn)) | ||
716 | break; | ||
717 | |||
718 | compute_next_pc(insn, pc, &next_pc, child); | ||
719 | if (next_pc & 0x80000000) | ||
720 | break; | ||
721 | |||
722 | if (embed_debug_trap(child, next_pc)) | ||
723 | break; | ||
724 | |||
725 | invalidate_cache(); | ||
726 | child->exit_code = data; | ||
727 | |||
728 | /* give it a chance to run. */ | ||
729 | wake_up_process(child); | ||
730 | ret = 0; | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | /* | ||
735 | * detach a process that was attached. | ||
736 | */ | ||
737 | case PTRACE_DETACH: | ||
738 | ret = 0; | ||
739 | ret = ptrace_detach(child, data); | ||
740 | break; | ||
741 | |||
742 | case PTRACE_GETREGS: | ||
743 | ret = ptrace_getregs(child, (void __user *)data); | ||
744 | break; | ||
745 | |||
746 | case PTRACE_SETREGS: | ||
747 | ret = ptrace_setregs(child, (void __user *)data); | ||
748 | break; | ||
749 | |||
750 | default: | ||
751 | ret = ptrace_request(child, request, addr, data); | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | ||
759 | { | ||
760 | struct task_struct *child; | ||
761 | int ret; | ||
762 | |||
763 | lock_kernel(); | ||
764 | ret = -EPERM; | ||
765 | if (request == PTRACE_TRACEME) { | ||
766 | /* are we already being traced? */ | ||
767 | if (current->ptrace & PT_PTRACED) | ||
768 | goto out; | ||
769 | /* set the ptrace bit in the process flags. */ | ||
770 | current->ptrace |= PT_PTRACED; | ||
771 | ret = 0; | ||
772 | goto out; | ||
773 | } | ||
774 | ret = -ESRCH; | ||
775 | read_lock(&tasklist_lock); | ||
776 | child = find_task_by_pid(pid); | ||
777 | if (child) | ||
778 | get_task_struct(child); | ||
779 | read_unlock(&tasklist_lock); | ||
780 | if (!child) | ||
781 | goto out; | ||
782 | |||
783 | ret = -EPERM; | ||
784 | if (pid == 1) /* you may not mess with init */ | ||
785 | goto out; | ||
786 | |||
787 | if (request == PTRACE_ATTACH) { | ||
788 | ret = ptrace_attach(child); | ||
789 | if (ret == 0) | ||
790 | init_debug_traps(child); | ||
791 | goto out_tsk; | ||
792 | } | ||
793 | |||
794 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
795 | if (ret == 0) | ||
796 | ret = do_ptrace(request, child, addr, data); | ||
797 | |||
798 | out_tsk: | ||
799 | put_task_struct(child); | ||
800 | out: | ||
801 | unlock_kernel(); | ||
802 | |||
803 | return ret; | ||
804 | } | ||
805 | |||
806 | /* notification of system call entry/exit | ||
807 | * - triggered by current->work.syscall_trace | ||
808 | */ | ||
809 | void do_syscall_trace(void) | ||
810 | { | ||
811 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
812 | return; | ||
813 | if (!(current->ptrace & PT_PTRACED)) | ||
814 | return; | ||
815 | /* the 0x80 provides a way for the tracing parent to distinguish | ||
816 | between a syscall stop and SIGTRAP delivery */ | ||
817 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
818 | ? 0x80 : 0)); | ||
819 | |||
820 | /* | ||
821 | * this isn't the same as continuing with a signal, but it will do | ||
822 | * for normal use. strace only continues with a signal if the | ||
823 | * stopping signal is not SIGTRAP. -brl | ||
824 | */ | ||
825 | if (current->exit_code) { | ||
826 | send_sig(current->exit_code, current, 1); | ||
827 | current->exit_code = 0; | ||
828 | } | ||
829 | } | ||
diff --git a/arch/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c new file mode 100644 index 000000000000..9a6e6d754ddc --- /dev/null +++ b/arch/m32r/kernel/semaphore.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/semaphore.c | ||
3 | * orig : i386 2.6.4 | ||
4 | * | ||
5 | * M32R semaphore implementation. | ||
6 | * | ||
7 | * Copyright (c) 2002 - 2004 Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * i386 semaphore implementation. | ||
12 | * | ||
13 | * (C) Copyright 1999 Linus Torvalds | ||
14 | * | ||
15 | * Portions Copyright 1999 Red Hat, Inc. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License | ||
19 | * as published by the Free Software Foundation; either version | ||
20 | * 2 of the License, or (at your option) any later version. | ||
21 | * | ||
22 | * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org> | ||
23 | */ | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <asm/semaphore.h> | ||
29 | |||
30 | /* | ||
31 | * Semaphores are implemented using a two-way counter: | ||
32 | * The "count" variable is decremented for each process | ||
33 | * that tries to acquire the semaphore, while the "sleeping" | ||
34 | * variable is a count of such acquires. | ||
35 | * | ||
36 | * Notably, the inline "up()" and "down()" functions can | ||
37 | * efficiently test if they need to do any extra work (up | ||
38 | * needs to do something only if count was negative before | ||
39 | * the increment operation. | ||
40 | * | ||
41 | * "sleeping" and the contention routine ordering is protected | ||
42 | * by the spinlock in the semaphore's waitqueue head. | ||
43 | * | ||
44 | * Note that these functions are only called when there is | ||
45 | * contention on the lock, and as such all this is the | ||
46 | * "non-critical" part of the whole semaphore business. The | ||
47 | * critical part is the inline stuff in <asm/semaphore.h> | ||
48 | * where we want to avoid any extra jumps and calls. | ||
49 | */ | ||
50 | |||
51 | /* | ||
52 | * Logic: | ||
53 | * - only on a boundary condition do we need to care. When we go | ||
54 | * from a negative count to a non-negative, we wake people up. | ||
55 | * - when we go from a non-negative count to a negative do we | ||
56 | * (a) synchronize with the "sleeper" count and (b) make sure | ||
57 | * that we're on the wakeup list before we synchronize so that | ||
58 | * we cannot lose wakeup events. | ||
59 | */ | ||
60 | |||
61 | asmlinkage void __up(struct semaphore *sem) | ||
62 | { | ||
63 | wake_up(&sem->wait); | ||
64 | } | ||
65 | |||
66 | asmlinkage void __sched __down(struct semaphore * sem) | ||
67 | { | ||
68 | struct task_struct *tsk = current; | ||
69 | DECLARE_WAITQUEUE(wait, tsk); | ||
70 | unsigned long flags; | ||
71 | |||
72 | tsk->state = TASK_UNINTERRUPTIBLE; | ||
73 | spin_lock_irqsave(&sem->wait.lock, flags); | ||
74 | add_wait_queue_exclusive_locked(&sem->wait, &wait); | ||
75 | |||
76 | sem->sleepers++; | ||
77 | for (;;) { | ||
78 | int sleepers = sem->sleepers; | ||
79 | |||
80 | /* | ||
81 | * Add "everybody else" into it. They aren't | ||
82 | * playing, because we own the spinlock in | ||
83 | * the wait_queue_head. | ||
84 | */ | ||
85 | if (!atomic_add_negative(sleepers - 1, &sem->count)) { | ||
86 | sem->sleepers = 0; | ||
87 | break; | ||
88 | } | ||
89 | sem->sleepers = 1; /* us - see -1 above */ | ||
90 | spin_unlock_irqrestore(&sem->wait.lock, flags); | ||
91 | |||
92 | schedule(); | ||
93 | |||
94 | spin_lock_irqsave(&sem->wait.lock, flags); | ||
95 | tsk->state = TASK_UNINTERRUPTIBLE; | ||
96 | } | ||
97 | remove_wait_queue_locked(&sem->wait, &wait); | ||
98 | wake_up_locked(&sem->wait); | ||
99 | spin_unlock_irqrestore(&sem->wait.lock, flags); | ||
100 | tsk->state = TASK_RUNNING; | ||
101 | } | ||
102 | |||
103 | asmlinkage int __sched __down_interruptible(struct semaphore * sem) | ||
104 | { | ||
105 | int retval = 0; | ||
106 | struct task_struct *tsk = current; | ||
107 | DECLARE_WAITQUEUE(wait, tsk); | ||
108 | unsigned long flags; | ||
109 | |||
110 | tsk->state = TASK_INTERRUPTIBLE; | ||
111 | spin_lock_irqsave(&sem->wait.lock, flags); | ||
112 | add_wait_queue_exclusive_locked(&sem->wait, &wait); | ||
113 | |||
114 | sem->sleepers++; | ||
115 | for (;;) { | ||
116 | int sleepers = sem->sleepers; | ||
117 | |||
118 | /* | ||
119 | * With signals pending, this turns into | ||
120 | * the trylock failure case - we won't be | ||
121 | * sleeping, and we* can't get the lock as | ||
122 | * it has contention. Just correct the count | ||
123 | * and exit. | ||
124 | */ | ||
125 | if (signal_pending(current)) { | ||
126 | retval = -EINTR; | ||
127 | sem->sleepers = 0; | ||
128 | atomic_add(sleepers, &sem->count); | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * Add "everybody else" into it. They aren't | ||
134 | * playing, because we own the spinlock in | ||
135 | * wait_queue_head. The "-1" is because we're | ||
136 | * still hoping to get the semaphore. | ||
137 | */ | ||
138 | if (!atomic_add_negative(sleepers - 1, &sem->count)) { | ||
139 | sem->sleepers = 0; | ||
140 | break; | ||
141 | } | ||
142 | sem->sleepers = 1; /* us - see -1 above */ | ||
143 | spin_unlock_irqrestore(&sem->wait.lock, flags); | ||
144 | |||
145 | schedule(); | ||
146 | |||
147 | spin_lock_irqsave(&sem->wait.lock, flags); | ||
148 | tsk->state = TASK_INTERRUPTIBLE; | ||
149 | } | ||
150 | remove_wait_queue_locked(&sem->wait, &wait); | ||
151 | wake_up_locked(&sem->wait); | ||
152 | spin_unlock_irqrestore(&sem->wait.lock, flags); | ||
153 | |||
154 | tsk->state = TASK_RUNNING; | ||
155 | return retval; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Trylock failed - make sure we correct for | ||
160 | * having decremented the count. | ||
161 | * | ||
162 | * We could have done the trylock with a | ||
163 | * single "cmpxchg" without failure cases, | ||
164 | * but then it wouldn't work on a 386. | ||
165 | */ | ||
166 | asmlinkage int __down_trylock(struct semaphore * sem) | ||
167 | { | ||
168 | int sleepers; | ||
169 | unsigned long flags; | ||
170 | |||
171 | spin_lock_irqsave(&sem->wait.lock, flags); | ||
172 | sleepers = sem->sleepers + 1; | ||
173 | sem->sleepers = 0; | ||
174 | |||
175 | /* | ||
176 | * Add "everybody else" and us into it. They aren't | ||
177 | * playing, because we own the spinlock in the | ||
178 | * wait_queue_head. | ||
179 | */ | ||
180 | if (!atomic_add_negative(sleepers, &sem->count)) { | ||
181 | wake_up_locked(&sem->wait); | ||
182 | } | ||
183 | |||
184 | spin_unlock_irqrestore(&sem->wait.lock, flags); | ||
185 | return 1; | ||
186 | } | ||
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c new file mode 100644 index 000000000000..4826cd6e40e8 --- /dev/null +++ b/arch/m32r/kernel/setup.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup.c | ||
3 | * | ||
4 | * Setup routines for Renesas M32R | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/stddef.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/bootmem.h> | ||
18 | #include <linux/console.h> | ||
19 | #include <linux/initrd.h> | ||
20 | #include <linux/major.h> | ||
21 | #include <linux/root_dev.h> | ||
22 | #include <linux/seq_file.h> | ||
23 | #include <linux/timex.h> | ||
24 | #include <linux/tty.h> | ||
25 | #include <linux/cpu.h> | ||
26 | #include <linux/nodemask.h> | ||
27 | |||
28 | #include <asm/processor.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/mmu_context.h> | ||
32 | #include <asm/m32r.h> | ||
33 | #include <asm/setup.h> | ||
34 | #include <asm/sections.h> | ||
35 | |||
36 | #ifdef CONFIG_MMU | ||
37 | extern void init_mmu(void); | ||
38 | #endif | ||
39 | |||
40 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) \ | ||
41 | || defined(CONFIG_BLK_DEV_IDE_MODULE) \ | ||
42 | || defined(CONFIG_BLK_DEV_HD_MODULE) | ||
43 | struct drive_info_struct { char dummy[32]; } drive_info; | ||
44 | #endif | ||
45 | |||
46 | extern char _end[]; | ||
47 | |||
48 | /* | ||
49 | * Machine setup.. | ||
50 | */ | ||
51 | struct cpuinfo_m32r boot_cpu_data; | ||
52 | |||
53 | #ifdef CONFIG_BLK_DEV_RAM | ||
54 | extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ | ||
55 | extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ | ||
56 | extern int rd_image_start; /* starting block # of image */ | ||
57 | #endif | ||
58 | |||
59 | #if defined(CONFIG_VGA_CONSOLE) | ||
60 | struct screen_info screen_info = { | ||
61 | .orig_video_lines = 25, | ||
62 | .orig_video_cols = 80, | ||
63 | .orig_video_mode = 0, | ||
64 | .orig_video_ega_bx = 0, | ||
65 | .orig_video_isVGA = 1, | ||
66 | .orig_video_points = 8 | ||
67 | }; | ||
68 | #endif | ||
69 | |||
70 | extern int root_mountflags; | ||
71 | |||
72 | static char command_line[COMMAND_LINE_SIZE]; | ||
73 | |||
74 | static struct resource data_resource = { | ||
75 | .name = "Kernel data", | ||
76 | .start = 0, | ||
77 | .end = 0, | ||
78 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | ||
79 | }; | ||
80 | |||
81 | static struct resource code_resource = { | ||
82 | .name = "Kernel code", | ||
83 | .start = 0, | ||
84 | .end = 0, | ||
85 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | ||
86 | }; | ||
87 | |||
88 | unsigned long memory_start; | ||
89 | unsigned long memory_end; | ||
90 | |||
91 | void __init setup_arch(char **); | ||
92 | int get_cpuinfo(char *); | ||
93 | |||
94 | static __inline__ void parse_mem_cmdline(char ** cmdline_p) | ||
95 | { | ||
96 | char c = ' '; | ||
97 | char *to = command_line; | ||
98 | char *from = COMMAND_LINE; | ||
99 | int len = 0; | ||
100 | int usermem = 0; | ||
101 | |||
102 | /* Save unparsed command line copy for /proc/cmdline */ | ||
103 | memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); | ||
104 | saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; | ||
105 | |||
106 | memory_start = (unsigned long)CONFIG_MEMORY_START+PAGE_OFFSET; | ||
107 | memory_end = memory_start+(unsigned long)CONFIG_MEMORY_SIZE; | ||
108 | |||
109 | for ( ; ; ) { | ||
110 | if (c == ' ' && !memcmp(from, "mem=", 4)) { | ||
111 | if (to != command_line) | ||
112 | to--; | ||
113 | |||
114 | { | ||
115 | unsigned long mem_size; | ||
116 | |||
117 | usermem = 1; | ||
118 | mem_size = memparse(from+4, &from); | ||
119 | memory_end = memory_start + mem_size; | ||
120 | } | ||
121 | } | ||
122 | c = *(from++); | ||
123 | if (!c) | ||
124 | break; | ||
125 | |||
126 | if (COMMAND_LINE_SIZE <= ++len) | ||
127 | break; | ||
128 | |||
129 | *(to++) = c; | ||
130 | } | ||
131 | *to = '\0'; | ||
132 | *cmdline_p = command_line; | ||
133 | if (usermem) | ||
134 | printk(KERN_INFO "user-defined physical RAM map:\n"); | ||
135 | } | ||
136 | |||
137 | #ifndef CONFIG_DISCONTIGMEM | ||
138 | static unsigned long __init setup_memory(void) | ||
139 | { | ||
140 | unsigned long start_pfn, max_low_pfn, bootmap_size; | ||
141 | |||
142 | start_pfn = PFN_UP( __pa(_end) ); | ||
143 | max_low_pfn = PFN_DOWN( __pa(memory_end) ); | ||
144 | |||
145 | /* | ||
146 | * Initialize the boot-time allocator (with low memory only): | ||
147 | */ | ||
148 | bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, | ||
149 | CONFIG_MEMORY_START>>PAGE_SHIFT, max_low_pfn); | ||
150 | |||
151 | /* | ||
152 | * Register fully available low RAM pages with the bootmem allocator. | ||
153 | */ | ||
154 | { | ||
155 | unsigned long curr_pfn; | ||
156 | unsigned long last_pfn; | ||
157 | unsigned long pages; | ||
158 | |||
159 | /* | ||
160 | * We are rounding up the start address of usable memory: | ||
161 | */ | ||
162 | curr_pfn = PFN_UP(__pa(memory_start)); | ||
163 | |||
164 | /* | ||
165 | * ... and at the end of the usable range downwards: | ||
166 | */ | ||
167 | last_pfn = PFN_DOWN(__pa(memory_end)); | ||
168 | |||
169 | if (last_pfn > max_low_pfn) | ||
170 | last_pfn = max_low_pfn; | ||
171 | |||
172 | pages = last_pfn - curr_pfn; | ||
173 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Reserve the kernel text and | ||
178 | * Reserve the bootmem bitmap. We do this in two steps (first step | ||
179 | * was init_bootmem()), because this catches the (definitely buggy) | ||
180 | * case of us accidentally initializing the bootmem allocator with | ||
181 | * an invalid RAM area. | ||
182 | */ | ||
183 | reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE, | ||
184 | (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1) | ||
185 | - CONFIG_MEMORY_START); | ||
186 | |||
187 | /* | ||
188 | * reserve physical page 0 - it's a special BIOS page on many boxes, | ||
189 | * enabling clean reboots, SMP operation, laptop functions. | ||
190 | */ | ||
191 | reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE); | ||
192 | |||
193 | /* | ||
194 | * reserve memory hole | ||
195 | */ | ||
196 | #ifdef CONFIG_MEMHOLE | ||
197 | reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE); | ||
198 | #endif | ||
199 | |||
200 | #ifdef CONFIG_BLK_DEV_INITRD | ||
201 | if (LOADER_TYPE && INITRD_START) { | ||
202 | if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { | ||
203 | reserve_bootmem(INITRD_START, INITRD_SIZE); | ||
204 | initrd_start = INITRD_START ? | ||
205 | INITRD_START + PAGE_OFFSET : 0; | ||
206 | |||
207 | initrd_end = initrd_start + INITRD_SIZE; | ||
208 | printk("initrd:start[%08lx],size[%08lx]\n", | ||
209 | initrd_start, INITRD_SIZE); | ||
210 | } else { | ||
211 | printk("initrd extends beyond end of memory " | ||
212 | "(0x%08lx > 0x%08lx)\ndisabling initrd\n", | ||
213 | INITRD_START + INITRD_SIZE, | ||
214 | max_low_pfn << PAGE_SHIFT); | ||
215 | |||
216 | initrd_start = 0; | ||
217 | } | ||
218 | } | ||
219 | #endif | ||
220 | |||
221 | return max_low_pfn; | ||
222 | } | ||
223 | #else /* CONFIG_DISCONTIGMEM */ | ||
224 | extern unsigned long setup_memory(void); | ||
225 | #endif /* CONFIG_DISCONTIGMEM */ | ||
226 | |||
227 | #define M32R_PCC_PCATCR 0x00ef7014 /* will move to m32r.h */ | ||
228 | |||
229 | void __init setup_arch(char **cmdline_p) | ||
230 | { | ||
231 | ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); | ||
232 | |||
233 | boot_cpu_data.cpu_clock = M32R_CPUCLK; | ||
234 | boot_cpu_data.bus_clock = M32R_BUSCLK; | ||
235 | boot_cpu_data.timer_divide = M32R_TIMER_DIVIDE; | ||
236 | |||
237 | #ifdef CONFIG_BLK_DEV_RAM | ||
238 | rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; | ||
239 | rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); | ||
240 | rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); | ||
241 | #endif | ||
242 | |||
243 | if (!MOUNT_ROOT_RDONLY) | ||
244 | root_mountflags &= ~MS_RDONLY; | ||
245 | |||
246 | #ifdef CONFIG_VT | ||
247 | #if defined(CONFIG_VGA_CONSOLE) | ||
248 | conswitchp = &vga_con; | ||
249 | #elif defined(CONFIG_DUMMY_CONSOLE) | ||
250 | conswitchp = &dummy_con; | ||
251 | #endif | ||
252 | #endif | ||
253 | |||
254 | #ifdef CONFIG_DISCONTIGMEM | ||
255 | nodes_clear(node_online_map); | ||
256 | node_set_online(0); | ||
257 | node_set_online(1); | ||
258 | #endif /* CONFIG_DISCONTIGMEM */ | ||
259 | |||
260 | init_mm.start_code = (unsigned long) _text; | ||
261 | init_mm.end_code = (unsigned long) _etext; | ||
262 | init_mm.end_data = (unsigned long) _edata; | ||
263 | init_mm.brk = (unsigned long) _end; | ||
264 | |||
265 | code_resource.start = virt_to_phys(_text); | ||
266 | code_resource.end = virt_to_phys(_etext)-1; | ||
267 | data_resource.start = virt_to_phys(_etext); | ||
268 | data_resource.end = virt_to_phys(_edata)-1; | ||
269 | |||
270 | parse_mem_cmdline(cmdline_p); | ||
271 | |||
272 | setup_memory(); | ||
273 | |||
274 | paging_init(); | ||
275 | } | ||
276 | |||
277 | static struct cpu cpu[NR_CPUS]; | ||
278 | |||
279 | static int __init topology_init(void) | ||
280 | { | ||
281 | int cpu_id; | ||
282 | |||
283 | for (cpu_id = 0; cpu_id < NR_CPUS; cpu_id++) | ||
284 | if (cpu_possible(cpu_id)) | ||
285 | register_cpu(&cpu[cpu_id], cpu_id, NULL); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | subsys_initcall(topology_init); | ||
291 | |||
292 | #ifdef CONFIG_PROC_FS | ||
293 | /* | ||
294 | * Get CPU information for use by the procfs. | ||
295 | */ | ||
296 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
297 | { | ||
298 | struct cpuinfo_m32r *c = v; | ||
299 | unsigned long cpu = c - cpu_data; | ||
300 | |||
301 | #ifdef CONFIG_SMP | ||
302 | if (!cpu_online(cpu)) | ||
303 | return 0; | ||
304 | #endif /* CONFIG_SMP */ | ||
305 | |||
306 | seq_printf(m, "processor\t: %ld\n", cpu); | ||
307 | |||
308 | #ifdef CONFIG_CHIP_VDEC2 | ||
309 | seq_printf(m, "cpu family\t: VDEC2\n" | ||
310 | "cache size\t: Unknown\n"); | ||
311 | #elif CONFIG_CHIP_M32700 | ||
312 | seq_printf(m,"cpu family\t: M32700\n" | ||
313 | "cache size\t: I-8KB/D-8KB\n"); | ||
314 | #elif CONFIG_CHIP_M32102 | ||
315 | seq_printf(m,"cpu family\t: M32102\n" | ||
316 | "cache size\t: I-8KB\n"); | ||
317 | #elif CONFIG_CHIP_OPSP | ||
318 | seq_printf(m,"cpu family\t: OPSP\n" | ||
319 | "cache size\t: I-8KB/D-8KB\n"); | ||
320 | #elif CONFIG_CHIP_MP | ||
321 | seq_printf(m, "cpu family\t: M32R-MP\n" | ||
322 | "cache size\t: I-xxKB/D-xxKB\n"); | ||
323 | #else | ||
324 | seq_printf(m, "cpu family\t: Unknown\n"); | ||
325 | #endif | ||
326 | seq_printf(m, "bogomips\t: %lu.%02lu\n", | ||
327 | c->loops_per_jiffy/(500000/HZ), | ||
328 | (c->loops_per_jiffy/(5000/HZ)) % 100); | ||
329 | #ifdef CONFIG_PLAT_MAPPI | ||
330 | seq_printf(m, "Machine\t\t: Mappi Evaluation board\n"); | ||
331 | #elif CONFIG_PLAT_MAPPI2 | ||
332 | seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n"); | ||
333 | #elif CONFIG_PLAT_M32700UT | ||
334 | seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n"); | ||
335 | #elif CONFIG_PLAT_OPSPUT | ||
336 | seq_printf(m, "Machine\t\t: OPSPUT Evaluation board\n"); | ||
337 | #elif CONFIG_PLAT_USRV | ||
338 | seq_printf(m, "Machine\t\t: uServer\n"); | ||
339 | #elif CONFIG_PLAT_OAKS32R | ||
340 | seq_printf(m, "Machine\t\t: OAKS32R\n"); | ||
341 | #else | ||
342 | seq_printf(m, "Machine\t\t: Unknown\n"); | ||
343 | #endif | ||
344 | |||
345 | #define PRINT_CLOCK(name, value) \ | ||
346 | seq_printf(m, name " clock\t: %d.%02dMHz\n", \ | ||
347 | ((value) / 1000000), ((value) % 1000000)/10000) | ||
348 | |||
349 | PRINT_CLOCK("CPU", (int)c->cpu_clock); | ||
350 | PRINT_CLOCK("Bus", (int)c->bus_clock); | ||
351 | |||
352 | seq_printf(m, "\n"); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
358 | { | ||
359 | return *pos < NR_CPUS ? cpu_data + *pos : NULL; | ||
360 | } | ||
361 | |||
362 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
363 | { | ||
364 | ++*pos; | ||
365 | return c_start(m, pos); | ||
366 | } | ||
367 | |||
368 | static void c_stop(struct seq_file *m, void *v) | ||
369 | { | ||
370 | } | ||
371 | |||
372 | struct seq_operations cpuinfo_op = { | ||
373 | start: c_start, | ||
374 | next: c_next, | ||
375 | stop: c_stop, | ||
376 | show: show_cpuinfo, | ||
377 | }; | ||
378 | #endif /* CONFIG_PROC_FS */ | ||
379 | |||
380 | unsigned long cpu_initialized __initdata = 0; | ||
381 | |||
382 | /* | ||
383 | * cpu_init() initializes state that is per-CPU. Some data is already | ||
384 | * initialized (naturally) in the bootstrap process. | ||
385 | * We reload them nevertheless, this function acts as a | ||
386 | * 'CPU state barrier', nothing should get across. | ||
387 | */ | ||
388 | #if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \ | ||
389 | || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ | ||
390 | || defined(CONFIG_CHIP_OPSP) | ||
391 | void __init cpu_init (void) | ||
392 | { | ||
393 | int cpu_id = smp_processor_id(); | ||
394 | |||
395 | if (test_and_set_bit(cpu_id, &cpu_initialized)) { | ||
396 | printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id); | ||
397 | for ( ; ; ) | ||
398 | local_irq_enable(); | ||
399 | } | ||
400 | printk(KERN_INFO "Initializing CPU#%d\n", cpu_id); | ||
401 | |||
402 | /* Set up and load the per-CPU TSS and LDT */ | ||
403 | atomic_inc(&init_mm.mm_count); | ||
404 | current->active_mm = &init_mm; | ||
405 | if (current->mm) | ||
406 | BUG(); | ||
407 | |||
408 | /* Force FPU initialization */ | ||
409 | current_thread_info()->status = 0; | ||
410 | clear_used_math(); | ||
411 | |||
412 | #ifdef CONFIG_MMU | ||
413 | /* Set up MMU */ | ||
414 | init_mmu(); | ||
415 | #endif | ||
416 | |||
417 | /* Set up ICUIMASK */ | ||
418 | outl(0x00070000, M32R_ICU_IMASK_PORTL); /* imask=111 */ | ||
419 | } | ||
420 | #endif /* defined(CONFIG_CHIP_VDEC2) ... */ | ||
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c new file mode 100644 index 000000000000..488aa87bab76 --- /dev/null +++ b/arch/m32r/kernel/setup_m32700ut.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_m32700ut.c | ||
3 | * | ||
4 | * Setup routines for Renesas M32700UT Board | ||
5 | * | ||
6 | * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Takeo Takahashi | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/device.h> | ||
19 | |||
20 | #include <asm/system.h> | ||
21 | #include <asm/m32r.h> | ||
22 | #include <asm/io.h> | ||
23 | |||
24 | /* | ||
25 | * M32700 Interrupt Control Unit (Level 1) | ||
26 | */ | ||
27 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
28 | |||
29 | #ifndef CONFIG_SMP | ||
30 | typedef struct { | ||
31 | unsigned long icucr; /* ICU Control Register */ | ||
32 | } icu_data_t; | ||
33 | #endif /* CONFIG_SMP */ | ||
34 | |||
35 | static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; | ||
36 | |||
37 | static void disable_m32700ut_irq(unsigned int irq) | ||
38 | { | ||
39 | unsigned long port, data; | ||
40 | |||
41 | port = irq2port(irq); | ||
42 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
43 | outl(data, port); | ||
44 | } | ||
45 | |||
46 | static void enable_m32700ut_irq(unsigned int irq) | ||
47 | { | ||
48 | unsigned long port, data; | ||
49 | |||
50 | port = irq2port(irq); | ||
51 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
52 | outl(data, port); | ||
53 | } | ||
54 | |||
55 | static void mask_and_ack_m32700ut(unsigned int irq) | ||
56 | { | ||
57 | disable_m32700ut_irq(irq); | ||
58 | } | ||
59 | |||
60 | static void end_m32700ut_irq(unsigned int irq) | ||
61 | { | ||
62 | enable_m32700ut_irq(irq); | ||
63 | } | ||
64 | |||
65 | static unsigned int startup_m32700ut_irq(unsigned int irq) | ||
66 | { | ||
67 | enable_m32700ut_irq(irq); | ||
68 | return (0); | ||
69 | } | ||
70 | |||
71 | static void shutdown_m32700ut_irq(unsigned int irq) | ||
72 | { | ||
73 | unsigned long port; | ||
74 | |||
75 | port = irq2port(irq); | ||
76 | outl(M32R_ICUCR_ILEVEL7, port); | ||
77 | } | ||
78 | |||
79 | static struct hw_interrupt_type m32700ut_irq_type = | ||
80 | { | ||
81 | "M32700UT-IRQ", | ||
82 | startup_m32700ut_irq, | ||
83 | shutdown_m32700ut_irq, | ||
84 | enable_m32700ut_irq, | ||
85 | disable_m32700ut_irq, | ||
86 | mask_and_ack_m32700ut, | ||
87 | end_m32700ut_irq | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Interrupt Control Unit of PLD on M32700UT (Level 2) | ||
92 | */ | ||
93 | #define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) | ||
94 | #define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ | ||
95 | (((x) - 1) * sizeof(unsigned short))) | ||
96 | |||
97 | typedef struct { | ||
98 | unsigned short icucr; /* ICU Control Register */ | ||
99 | } pld_icu_data_t; | ||
100 | |||
101 | static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; | ||
102 | |||
103 | static void disable_m32700ut_pld_irq(unsigned int irq) | ||
104 | { | ||
105 | unsigned long port, data; | ||
106 | unsigned int pldirq; | ||
107 | |||
108 | pldirq = irq2pldirq(irq); | ||
109 | // disable_m32700ut_irq(M32R_IRQ_INT1); | ||
110 | port = pldirq2port(pldirq); | ||
111 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
112 | outw(data, port); | ||
113 | } | ||
114 | |||
115 | static void enable_m32700ut_pld_irq(unsigned int irq) | ||
116 | { | ||
117 | unsigned long port, data; | ||
118 | unsigned int pldirq; | ||
119 | |||
120 | pldirq = irq2pldirq(irq); | ||
121 | // enable_m32700ut_irq(M32R_IRQ_INT1); | ||
122 | port = pldirq2port(pldirq); | ||
123 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
124 | outw(data, port); | ||
125 | } | ||
126 | |||
127 | static void mask_and_ack_m32700ut_pld(unsigned int irq) | ||
128 | { | ||
129 | disable_m32700ut_pld_irq(irq); | ||
130 | // mask_and_ack_m32700ut(M32R_IRQ_INT1); | ||
131 | } | ||
132 | |||
133 | static void end_m32700ut_pld_irq(unsigned int irq) | ||
134 | { | ||
135 | enable_m32700ut_pld_irq(irq); | ||
136 | end_m32700ut_irq(M32R_IRQ_INT1); | ||
137 | } | ||
138 | |||
139 | static unsigned int startup_m32700ut_pld_irq(unsigned int irq) | ||
140 | { | ||
141 | enable_m32700ut_pld_irq(irq); | ||
142 | return (0); | ||
143 | } | ||
144 | |||
145 | static void shutdown_m32700ut_pld_irq(unsigned int irq) | ||
146 | { | ||
147 | unsigned long port; | ||
148 | unsigned int pldirq; | ||
149 | |||
150 | pldirq = irq2pldirq(irq); | ||
151 | // shutdown_m32700ut_irq(M32R_IRQ_INT1); | ||
152 | port = pldirq2port(pldirq); | ||
153 | outw(PLD_ICUCR_ILEVEL7, port); | ||
154 | } | ||
155 | |||
156 | static struct hw_interrupt_type m32700ut_pld_irq_type = | ||
157 | { | ||
158 | "M32700UT-PLD-IRQ", | ||
159 | startup_m32700ut_pld_irq, | ||
160 | shutdown_m32700ut_pld_irq, | ||
161 | enable_m32700ut_pld_irq, | ||
162 | disable_m32700ut_pld_irq, | ||
163 | mask_and_ack_m32700ut_pld, | ||
164 | end_m32700ut_pld_irq | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * Interrupt Control Unit of PLD on M32700UT-LAN (Level 2) | ||
169 | */ | ||
170 | #define irq2lanpldirq(x) ((x) - M32700UT_LAN_PLD_IRQ_BASE) | ||
171 | #define lanpldirq2port(x) (unsigned long)((int)M32700UT_LAN_ICUCR1 + \ | ||
172 | (((x) - 1) * sizeof(unsigned short))) | ||
173 | |||
174 | static pld_icu_data_t lanpld_icu_data[M32700UT_NUM_LAN_PLD_IRQ]; | ||
175 | |||
176 | static void disable_m32700ut_lanpld_irq(unsigned int irq) | ||
177 | { | ||
178 | unsigned long port, data; | ||
179 | unsigned int pldirq; | ||
180 | |||
181 | pldirq = irq2lanpldirq(irq); | ||
182 | port = lanpldirq2port(pldirq); | ||
183 | data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
184 | outw(data, port); | ||
185 | } | ||
186 | |||
187 | static void enable_m32700ut_lanpld_irq(unsigned int irq) | ||
188 | { | ||
189 | unsigned long port, data; | ||
190 | unsigned int pldirq; | ||
191 | |||
192 | pldirq = irq2lanpldirq(irq); | ||
193 | port = lanpldirq2port(pldirq); | ||
194 | data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
195 | outw(data, port); | ||
196 | } | ||
197 | |||
198 | static void mask_and_ack_m32700ut_lanpld(unsigned int irq) | ||
199 | { | ||
200 | disable_m32700ut_lanpld_irq(irq); | ||
201 | } | ||
202 | |||
203 | static void end_m32700ut_lanpld_irq(unsigned int irq) | ||
204 | { | ||
205 | enable_m32700ut_lanpld_irq(irq); | ||
206 | end_m32700ut_irq(M32R_IRQ_INT0); | ||
207 | } | ||
208 | |||
209 | static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq) | ||
210 | { | ||
211 | enable_m32700ut_lanpld_irq(irq); | ||
212 | return (0); | ||
213 | } | ||
214 | |||
215 | static void shutdown_m32700ut_lanpld_irq(unsigned int irq) | ||
216 | { | ||
217 | unsigned long port; | ||
218 | unsigned int pldirq; | ||
219 | |||
220 | pldirq = irq2lanpldirq(irq); | ||
221 | port = lanpldirq2port(pldirq); | ||
222 | outw(PLD_ICUCR_ILEVEL7, port); | ||
223 | } | ||
224 | |||
225 | static struct hw_interrupt_type m32700ut_lanpld_irq_type = | ||
226 | { | ||
227 | "M32700UT-PLD-LAN-IRQ", | ||
228 | startup_m32700ut_lanpld_irq, | ||
229 | shutdown_m32700ut_lanpld_irq, | ||
230 | enable_m32700ut_lanpld_irq, | ||
231 | disable_m32700ut_lanpld_irq, | ||
232 | mask_and_ack_m32700ut_lanpld, | ||
233 | end_m32700ut_lanpld_irq | ||
234 | }; | ||
235 | |||
236 | /* | ||
237 | * Interrupt Control Unit of PLD on M32700UT-LCD (Level 2) | ||
238 | */ | ||
239 | #define irq2lcdpldirq(x) ((x) - M32700UT_LCD_PLD_IRQ_BASE) | ||
240 | #define lcdpldirq2port(x) (unsigned long)((int)M32700UT_LCD_ICUCR1 + \ | ||
241 | (((x) - 1) * sizeof(unsigned short))) | ||
242 | |||
243 | static pld_icu_data_t lcdpld_icu_data[M32700UT_NUM_LCD_PLD_IRQ]; | ||
244 | |||
245 | static void disable_m32700ut_lcdpld_irq(unsigned int irq) | ||
246 | { | ||
247 | unsigned long port, data; | ||
248 | unsigned int pldirq; | ||
249 | |||
250 | pldirq = irq2lcdpldirq(irq); | ||
251 | port = lcdpldirq2port(pldirq); | ||
252 | data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
253 | outw(data, port); | ||
254 | } | ||
255 | |||
256 | static void enable_m32700ut_lcdpld_irq(unsigned int irq) | ||
257 | { | ||
258 | unsigned long port, data; | ||
259 | unsigned int pldirq; | ||
260 | |||
261 | pldirq = irq2lcdpldirq(irq); | ||
262 | port = lcdpldirq2port(pldirq); | ||
263 | data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
264 | outw(data, port); | ||
265 | } | ||
266 | |||
267 | static void mask_and_ack_m32700ut_lcdpld(unsigned int irq) | ||
268 | { | ||
269 | disable_m32700ut_lcdpld_irq(irq); | ||
270 | } | ||
271 | |||
272 | static void end_m32700ut_lcdpld_irq(unsigned int irq) | ||
273 | { | ||
274 | enable_m32700ut_lcdpld_irq(irq); | ||
275 | end_m32700ut_irq(M32R_IRQ_INT2); | ||
276 | } | ||
277 | |||
278 | static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq) | ||
279 | { | ||
280 | enable_m32700ut_lcdpld_irq(irq); | ||
281 | return (0); | ||
282 | } | ||
283 | |||
284 | static void shutdown_m32700ut_lcdpld_irq(unsigned int irq) | ||
285 | { | ||
286 | unsigned long port; | ||
287 | unsigned int pldirq; | ||
288 | |||
289 | pldirq = irq2lcdpldirq(irq); | ||
290 | port = lcdpldirq2port(pldirq); | ||
291 | outw(PLD_ICUCR_ILEVEL7, port); | ||
292 | } | ||
293 | |||
294 | static struct hw_interrupt_type m32700ut_lcdpld_irq_type = | ||
295 | { | ||
296 | "M32700UT-PLD-LCD-IRQ", | ||
297 | startup_m32700ut_lcdpld_irq, | ||
298 | shutdown_m32700ut_lcdpld_irq, | ||
299 | enable_m32700ut_lcdpld_irq, | ||
300 | disable_m32700ut_lcdpld_irq, | ||
301 | mask_and_ack_m32700ut_lcdpld, | ||
302 | end_m32700ut_lcdpld_irq | ||
303 | }; | ||
304 | |||
305 | void __init init_IRQ(void) | ||
306 | { | ||
307 | #if defined(CONFIG_SMC91X) | ||
308 | /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/ | ||
309 | irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED; | ||
310 | irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type; | ||
311 | irq_desc[M32700UT_LAN_IRQ_LAN].action = 0; | ||
312 | irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ | ||
313 | lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ | ||
314 | disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN); | ||
315 | #endif /* CONFIG_SMC91X */ | ||
316 | |||
317 | /* MFT2 : system timer */ | ||
318 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
319 | irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type; | ||
320 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
321 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
322 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
323 | disable_m32700ut_irq(M32R_IRQ_MFT2); | ||
324 | |||
325 | /* SIO0 : receive */ | ||
326 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
327 | irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type; | ||
328 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
329 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
330 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
331 | disable_m32700ut_irq(M32R_IRQ_SIO0_R); | ||
332 | |||
333 | /* SIO0 : send */ | ||
334 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
335 | irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type; | ||
336 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
337 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
338 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
339 | disable_m32700ut_irq(M32R_IRQ_SIO0_S); | ||
340 | |||
341 | /* SIO1 : receive */ | ||
342 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
343 | irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type; | ||
344 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
345 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
346 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
347 | disable_m32700ut_irq(M32R_IRQ_SIO1_R); | ||
348 | |||
349 | /* SIO1 : send */ | ||
350 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
351 | irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type; | ||
352 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
353 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
354 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
355 | disable_m32700ut_irq(M32R_IRQ_SIO1_S); | ||
356 | |||
357 | /* DMA1 : */ | ||
358 | irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; | ||
359 | irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type; | ||
360 | irq_desc[M32R_IRQ_DMA1].action = 0; | ||
361 | irq_desc[M32R_IRQ_DMA1].depth = 1; | ||
362 | icu_data[M32R_IRQ_DMA1].icucr = 0; | ||
363 | disable_m32700ut_irq(M32R_IRQ_DMA1); | ||
364 | |||
365 | #ifdef CONFIG_SERIAL_M32R_PLDSIO | ||
366 | /* INT#1: SIO0 Receive on PLD */ | ||
367 | irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; | ||
368 | irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type; | ||
369 | irq_desc[PLD_IRQ_SIO0_RCV].action = 0; | ||
370 | irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ | ||
371 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | ||
372 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV); | ||
373 | |||
374 | /* INT#1: SIO0 Send on PLD */ | ||
375 | irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; | ||
376 | irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type; | ||
377 | irq_desc[PLD_IRQ_SIO0_SND].action = 0; | ||
378 | irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ | ||
379 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | ||
380 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND); | ||
381 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ | ||
382 | |||
383 | /* INT#1: CFC IREQ on PLD */ | ||
384 | irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; | ||
385 | irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type; | ||
386 | irq_desc[PLD_IRQ_CFIREQ].action = 0; | ||
387 | irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ | ||
388 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ | ||
389 | disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ); | ||
390 | |||
391 | /* INT#1: CFC Insert on PLD */ | ||
392 | irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; | ||
393 | irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type; | ||
394 | irq_desc[PLD_IRQ_CFC_INSERT].action = 0; | ||
395 | irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ | ||
396 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ | ||
397 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT); | ||
398 | |||
399 | /* INT#1: CFC Eject on PLD */ | ||
400 | irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; | ||
401 | irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type; | ||
402 | irq_desc[PLD_IRQ_CFC_EJECT].action = 0; | ||
403 | irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ | ||
404 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ | ||
405 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT); | ||
406 | |||
407 | /* | ||
408 | * INT0# is used for LAN, DIO | ||
409 | * We enable it here. | ||
410 | */ | ||
411 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; | ||
412 | enable_m32700ut_irq(M32R_IRQ_INT0); | ||
413 | |||
414 | /* | ||
415 | * INT1# is used for UART, MMC, CF Controller in FPGA. | ||
416 | * We enable it here. | ||
417 | */ | ||
418 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; | ||
419 | enable_m32700ut_irq(M32R_IRQ_INT1); | ||
420 | |||
421 | #if defined(CONFIG_USB) | ||
422 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ | ||
423 | |||
424 | irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; | ||
425 | irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type; | ||
426 | irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0; | ||
427 | irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1; | ||
428 | lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ | ||
429 | disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1); | ||
430 | #endif | ||
431 | /* | ||
432 | * INT2# is used for BAT, USB, AUDIO | ||
433 | * We enable it here. | ||
434 | */ | ||
435 | icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; | ||
436 | enable_m32700ut_irq(M32R_IRQ_INT2); | ||
437 | |||
438 | //#if defined(CONFIG_VIDEO_M32R_AR) | ||
439 | /* | ||
440 | * INT3# is used for AR | ||
441 | */ | ||
442 | irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; | ||
443 | irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type; | ||
444 | irq_desc[M32R_IRQ_INT3].action = 0; | ||
445 | irq_desc[M32R_IRQ_INT3].depth = 1; | ||
446 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
447 | disable_m32700ut_irq(M32R_IRQ_INT3); | ||
448 | //#endif /* CONFIG_VIDEO_M32R_AR */ | ||
449 | } | ||
450 | |||
451 | #define LAN_IOSTART 0x300 | ||
452 | #define LAN_IOEND 0x320 | ||
453 | static struct resource smc91x_resources[] = { | ||
454 | [0] = { | ||
455 | .start = (LAN_IOSTART), | ||
456 | .end = (LAN_IOEND), | ||
457 | .flags = IORESOURCE_MEM, | ||
458 | }, | ||
459 | [1] = { | ||
460 | .start = M32700UT_LAN_IRQ_LAN, | ||
461 | .end = M32700UT_LAN_IRQ_LAN, | ||
462 | .flags = IORESOURCE_IRQ, | ||
463 | } | ||
464 | }; | ||
465 | |||
466 | static struct platform_device smc91x_device = { | ||
467 | .name = "smc91x", | ||
468 | .id = 0, | ||
469 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
470 | .resource = smc91x_resources, | ||
471 | }; | ||
472 | |||
473 | static int __init platform_init(void) | ||
474 | { | ||
475 | platform_device_register(&smc91x_device); | ||
476 | return 0; | ||
477 | } | ||
478 | arch_initcall(platform_init); | ||
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c new file mode 100644 index 000000000000..1e74110f0670 --- /dev/null +++ b/arch/m32r/kernel/setup_mappi.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_mappi.c | ||
3 | * | ||
4 | * Setup routines for Renesas MAPPI Board | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/system.h> | ||
16 | #include <asm/m32r.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
20 | |||
21 | #ifndef CONFIG_SMP | ||
22 | typedef struct { | ||
23 | unsigned long icucr; /* ICU Control Register */ | ||
24 | } icu_data_t; | ||
25 | #endif /* CONFIG_SMP */ | ||
26 | |||
27 | icu_data_t icu_data[NR_IRQS]; | ||
28 | |||
29 | static void disable_mappi_irq(unsigned int irq) | ||
30 | { | ||
31 | unsigned long port, data; | ||
32 | |||
33 | port = irq2port(irq); | ||
34 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
35 | outl(data, port); | ||
36 | } | ||
37 | |||
38 | static void enable_mappi_irq(unsigned int irq) | ||
39 | { | ||
40 | unsigned long port, data; | ||
41 | |||
42 | port = irq2port(irq); | ||
43 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
44 | outl(data, port); | ||
45 | } | ||
46 | |||
47 | static void mask_and_ack_mappi(unsigned int irq) | ||
48 | { | ||
49 | disable_mappi_irq(irq); | ||
50 | } | ||
51 | |||
52 | static void end_mappi_irq(unsigned int irq) | ||
53 | { | ||
54 | enable_mappi_irq(irq); | ||
55 | } | ||
56 | |||
57 | static unsigned int startup_mappi_irq(unsigned int irq) | ||
58 | { | ||
59 | enable_mappi_irq(irq); | ||
60 | return (0); | ||
61 | } | ||
62 | |||
63 | static void shutdown_mappi_irq(unsigned int irq) | ||
64 | { | ||
65 | unsigned long port; | ||
66 | |||
67 | port = irq2port(irq); | ||
68 | outl(M32R_ICUCR_ILEVEL7, port); | ||
69 | } | ||
70 | |||
71 | static struct hw_interrupt_type mappi_irq_type = | ||
72 | { | ||
73 | "MAPPI-IRQ", | ||
74 | startup_mappi_irq, | ||
75 | shutdown_mappi_irq, | ||
76 | enable_mappi_irq, | ||
77 | disable_mappi_irq, | ||
78 | mask_and_ack_mappi, | ||
79 | end_mappi_irq | ||
80 | }; | ||
81 | |||
82 | void __init init_IRQ(void) | ||
83 | { | ||
84 | static int once = 0; | ||
85 | |||
86 | if (once) | ||
87 | return; | ||
88 | else | ||
89 | once++; | ||
90 | |||
91 | #ifdef CONFIG_NE2000 | ||
92 | /* INT0 : LAN controller (RTL8019AS) */ | ||
93 | irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; | ||
94 | irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type; | ||
95 | irq_desc[M32R_IRQ_INT0].action = 0; | ||
96 | irq_desc[M32R_IRQ_INT0].depth = 1; | ||
97 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
98 | disable_mappi_irq(M32R_IRQ_INT0); | ||
99 | #endif /* CONFIG_M32R_NE2000 */ | ||
100 | |||
101 | /* MFT2 : system timer */ | ||
102 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
103 | irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; | ||
104 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
105 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
106 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
107 | disable_mappi_irq(M32R_IRQ_MFT2); | ||
108 | |||
109 | #ifdef CONFIG_SERIAL_M32R_SIO | ||
110 | /* SIO0_R : uart receive data */ | ||
111 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
112 | irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; | ||
113 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
114 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
115 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
116 | disable_mappi_irq(M32R_IRQ_SIO0_R); | ||
117 | |||
118 | /* SIO0_S : uart send data */ | ||
119 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
120 | irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; | ||
121 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
122 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
123 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
124 | disable_mappi_irq(M32R_IRQ_SIO0_S); | ||
125 | |||
126 | /* SIO1_R : uart receive data */ | ||
127 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
128 | irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; | ||
129 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
130 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
131 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
132 | disable_mappi_irq(M32R_IRQ_SIO1_R); | ||
133 | |||
134 | /* SIO1_S : uart send data */ | ||
135 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
136 | irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; | ||
137 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
138 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
139 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
140 | disable_mappi_irq(M32R_IRQ_SIO1_S); | ||
141 | #endif /* CONFIG_SERIAL_M32R_SIO */ | ||
142 | |||
143 | #if defined(CONFIG_M32R_PCC) | ||
144 | /* INT1 : pccard0 interrupt */ | ||
145 | irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; | ||
146 | irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type; | ||
147 | irq_desc[M32R_IRQ_INT1].action = 0; | ||
148 | irq_desc[M32R_IRQ_INT1].depth = 1; | ||
149 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; | ||
150 | disable_mappi_irq(M32R_IRQ_INT1); | ||
151 | |||
152 | /* INT2 : pccard1 interrupt */ | ||
153 | irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED; | ||
154 | irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type; | ||
155 | irq_desc[M32R_IRQ_INT2].action = 0; | ||
156 | irq_desc[M32R_IRQ_INT2].depth = 1; | ||
157 | icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; | ||
158 | disable_mappi_irq(M32R_IRQ_INT2); | ||
159 | #endif /* CONFIG_M32RPCC */ | ||
160 | } | ||
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c new file mode 100644 index 000000000000..1904d465a507 --- /dev/null +++ b/arch/m32r/kernel/setup_mappi2.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_mappi.c | ||
3 | * | ||
4 | * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Mamoru Sakugawa | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/device.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/m32r.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
21 | |||
22 | #ifndef CONFIG_SMP | ||
23 | typedef struct { | ||
24 | unsigned long icucr; /* ICU Control Register */ | ||
25 | } icu_data_t; | ||
26 | #endif /* CONFIG_SMP */ | ||
27 | |||
28 | icu_data_t icu_data[NR_IRQS]; | ||
29 | |||
30 | static void disable_mappi2_irq(unsigned int irq) | ||
31 | { | ||
32 | unsigned long port, data; | ||
33 | |||
34 | if ((irq == 0) ||(irq >= NR_IRQS)) { | ||
35 | printk("bad irq 0x%08x\n", irq); | ||
36 | return; | ||
37 | } | ||
38 | port = irq2port(irq); | ||
39 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
40 | outl(data, port); | ||
41 | } | ||
42 | |||
43 | static void enable_mappi2_irq(unsigned int irq) | ||
44 | { | ||
45 | unsigned long port, data; | ||
46 | |||
47 | if ((irq == 0) ||(irq >= NR_IRQS)) { | ||
48 | printk("bad irq 0x%08x\n", irq); | ||
49 | return; | ||
50 | } | ||
51 | port = irq2port(irq); | ||
52 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
53 | outl(data, port); | ||
54 | } | ||
55 | |||
56 | static void mask_and_ack_mappi2(unsigned int irq) | ||
57 | { | ||
58 | disable_mappi2_irq(irq); | ||
59 | } | ||
60 | |||
61 | static void end_mappi2_irq(unsigned int irq) | ||
62 | { | ||
63 | enable_mappi2_irq(irq); | ||
64 | } | ||
65 | |||
66 | static unsigned int startup_mappi2_irq(unsigned int irq) | ||
67 | { | ||
68 | enable_mappi2_irq(irq); | ||
69 | return (0); | ||
70 | } | ||
71 | |||
72 | static void shutdown_mappi2_irq(unsigned int irq) | ||
73 | { | ||
74 | unsigned long port; | ||
75 | |||
76 | port = irq2port(irq); | ||
77 | outl(M32R_ICUCR_ILEVEL7, port); | ||
78 | } | ||
79 | |||
80 | static struct hw_interrupt_type mappi2_irq_type = | ||
81 | { | ||
82 | "MAPPI2-IRQ", | ||
83 | startup_mappi2_irq, | ||
84 | shutdown_mappi2_irq, | ||
85 | enable_mappi2_irq, | ||
86 | disable_mappi2_irq, | ||
87 | mask_and_ack_mappi2, | ||
88 | end_mappi2_irq | ||
89 | }; | ||
90 | |||
91 | void __init init_IRQ(void) | ||
92 | { | ||
93 | #if defined(CONFIG_SMC91X) | ||
94 | /* INT0 : LAN controller (SMC91111) */ | ||
95 | irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; | ||
96 | irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type; | ||
97 | irq_desc[M32R_IRQ_INT0].action = 0; | ||
98 | irq_desc[M32R_IRQ_INT0].depth = 1; | ||
99 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
100 | disable_mappi2_irq(M32R_IRQ_INT0); | ||
101 | #endif /* CONFIG_SMC91X */ | ||
102 | |||
103 | /* MFT2 : system timer */ | ||
104 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
105 | irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type; | ||
106 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
107 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
108 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
109 | disable_mappi2_irq(M32R_IRQ_MFT2); | ||
110 | |||
111 | #ifdef CONFIG_SERIAL_M32R_SIO | ||
112 | /* SIO0_R : uart receive data */ | ||
113 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
114 | irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type; | ||
115 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
116 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
117 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
118 | disable_mappi2_irq(M32R_IRQ_SIO0_R); | ||
119 | |||
120 | /* SIO0_S : uart send data */ | ||
121 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
122 | irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type; | ||
123 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
124 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
125 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
126 | disable_mappi2_irq(M32R_IRQ_SIO0_S); | ||
127 | /* SIO1_R : uart receive data */ | ||
128 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
129 | irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type; | ||
130 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
131 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
132 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
133 | disable_mappi2_irq(M32R_IRQ_SIO1_R); | ||
134 | |||
135 | /* SIO1_S : uart send data */ | ||
136 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
137 | irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type; | ||
138 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
139 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
140 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
141 | disable_mappi2_irq(M32R_IRQ_SIO1_S); | ||
142 | #endif /* CONFIG_M32R_USE_DBG_CONSOLE */ | ||
143 | |||
144 | #if defined(CONFIG_USB) | ||
145 | /* INT1 : USB Host controller interrupt */ | ||
146 | irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; | ||
147 | irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type; | ||
148 | irq_desc[M32R_IRQ_INT1].action = 0; | ||
149 | irq_desc[M32R_IRQ_INT1].depth = 1; | ||
150 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; | ||
151 | disable_mappi2_irq(M32R_IRQ_INT1); | ||
152 | #endif /* CONFIG_USB */ | ||
153 | |||
154 | /* ICUCR40: CFC IREQ */ | ||
155 | irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; | ||
156 | irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type; | ||
157 | irq_desc[PLD_IRQ_CFIREQ].action = 0; | ||
158 | irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ | ||
159 | // icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; | ||
160 | icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; | ||
161 | disable_mappi2_irq(PLD_IRQ_CFIREQ); | ||
162 | |||
163 | #if defined(CONFIG_M32R_CFC) | ||
164 | /* ICUCR41: CFC Insert */ | ||
165 | irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; | ||
166 | irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type; | ||
167 | irq_desc[PLD_IRQ_CFC_INSERT].action = 0; | ||
168 | irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ | ||
169 | icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; | ||
170 | // icu_data[PLD_IRQ_CFC_INSERT].icucr = 0; | ||
171 | disable_mappi2_irq(PLD_IRQ_CFC_INSERT); | ||
172 | |||
173 | /* ICUCR42: CFC Eject */ | ||
174 | irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; | ||
175 | irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type; | ||
176 | irq_desc[PLD_IRQ_CFC_EJECT].action = 0; | ||
177 | irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ | ||
178 | icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
179 | // icu_data[PLD_IRQ_CFC_EJECT].icucr = 0; | ||
180 | disable_mappi2_irq(PLD_IRQ_CFC_EJECT); | ||
181 | |||
182 | #endif /* CONFIG_MAPPI2_CFC */ | ||
183 | } | ||
184 | |||
185 | #define LAN_IOSTART 0x300 | ||
186 | #define LAN_IOEND 0x320 | ||
187 | static struct resource smc91x_resources[] = { | ||
188 | [0] = { | ||
189 | .start = (LAN_IOSTART), | ||
190 | .end = (LAN_IOEND), | ||
191 | .flags = IORESOURCE_MEM, | ||
192 | }, | ||
193 | [1] = { | ||
194 | .start = M32R_IRQ_INT0, | ||
195 | .end = M32R_IRQ_INT0, | ||
196 | .flags = IORESOURCE_IRQ, | ||
197 | } | ||
198 | }; | ||
199 | |||
200 | static struct platform_device smc91x_device = { | ||
201 | .name = "smc91x", | ||
202 | .id = 0, | ||
203 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
204 | .resource = smc91x_resources, | ||
205 | }; | ||
206 | |||
207 | static int __init platform_init(void) | ||
208 | { | ||
209 | platform_device_register(&smc91x_device); | ||
210 | return 0; | ||
211 | } | ||
212 | arch_initcall(platform_init); | ||
diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c new file mode 100644 index 000000000000..b04834526c9a --- /dev/null +++ b/arch/m32r/kernel/setup_oaks32r.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_oaks32r.c | ||
3 | * | ||
4 | * Setup routines for OAKS32R Board | ||
5 | * | ||
6 | * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto, Mamoru Sakugawa | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/system.h> | ||
16 | #include <asm/m32r.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
20 | |||
21 | #ifndef CONFIG_SMP | ||
22 | typedef struct { | ||
23 | unsigned long icucr; /* ICU Control Register */ | ||
24 | } icu_data_t; | ||
25 | #endif /* CONFIG_SMP */ | ||
26 | |||
27 | icu_data_t icu_data[NR_IRQS]; | ||
28 | |||
29 | static void disable_oaks32r_irq(unsigned int irq) | ||
30 | { | ||
31 | unsigned long port, data; | ||
32 | |||
33 | port = irq2port(irq); | ||
34 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
35 | outl(data, port); | ||
36 | } | ||
37 | |||
38 | static void enable_oaks32r_irq(unsigned int irq) | ||
39 | { | ||
40 | unsigned long port, data; | ||
41 | |||
42 | port = irq2port(irq); | ||
43 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
44 | outl(data, port); | ||
45 | } | ||
46 | |||
47 | static void mask_and_ack_mappi(unsigned int irq) | ||
48 | { | ||
49 | disable_oaks32r_irq(irq); | ||
50 | } | ||
51 | |||
52 | static void end_oaks32r_irq(unsigned int irq) | ||
53 | { | ||
54 | enable_oaks32r_irq(irq); | ||
55 | } | ||
56 | |||
57 | static unsigned int startup_oaks32r_irq(unsigned int irq) | ||
58 | { | ||
59 | enable_oaks32r_irq(irq); | ||
60 | return (0); | ||
61 | } | ||
62 | |||
63 | static void shutdown_oaks32r_irq(unsigned int irq) | ||
64 | { | ||
65 | unsigned long port; | ||
66 | |||
67 | port = irq2port(irq); | ||
68 | outl(M32R_ICUCR_ILEVEL7, port); | ||
69 | } | ||
70 | |||
71 | static struct hw_interrupt_type oaks32r_irq_type = | ||
72 | { | ||
73 | "OAKS32R-IRQ", | ||
74 | startup_oaks32r_irq, | ||
75 | shutdown_oaks32r_irq, | ||
76 | enable_oaks32r_irq, | ||
77 | disable_oaks32r_irq, | ||
78 | mask_and_ack_mappi, | ||
79 | end_oaks32r_irq | ||
80 | }; | ||
81 | |||
82 | void __init init_IRQ(void) | ||
83 | { | ||
84 | static int once = 0; | ||
85 | |||
86 | if (once) | ||
87 | return; | ||
88 | else | ||
89 | once++; | ||
90 | |||
91 | #ifdef CONFIG_NE2000 | ||
92 | /* INT3 : LAN controller (RTL8019AS) */ | ||
93 | irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; | ||
94 | irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type; | ||
95 | irq_desc[M32R_IRQ_INT3].action = 0; | ||
96 | irq_desc[M32R_IRQ_INT3].depth = 1; | ||
97 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
98 | disable_oaks32r_irq(M32R_IRQ_INT3); | ||
99 | #endif /* CONFIG_M32R_NE2000 */ | ||
100 | |||
101 | /* MFT2 : system timer */ | ||
102 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
103 | irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type; | ||
104 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
105 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
106 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
107 | disable_oaks32r_irq(M32R_IRQ_MFT2); | ||
108 | |||
109 | #ifdef CONFIG_SERIAL_M32R_SIO | ||
110 | /* SIO0_R : uart receive data */ | ||
111 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
112 | irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type; | ||
113 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
114 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
115 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
116 | disable_oaks32r_irq(M32R_IRQ_SIO0_R); | ||
117 | |||
118 | /* SIO0_S : uart send data */ | ||
119 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
120 | irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type; | ||
121 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
122 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
123 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
124 | disable_oaks32r_irq(M32R_IRQ_SIO0_S); | ||
125 | |||
126 | /* SIO1_R : uart receive data */ | ||
127 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
128 | irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type; | ||
129 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
130 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
131 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
132 | disable_oaks32r_irq(M32R_IRQ_SIO1_R); | ||
133 | |||
134 | /* SIO1_S : uart send data */ | ||
135 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
136 | irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type; | ||
137 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
138 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
139 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
140 | disable_oaks32r_irq(M32R_IRQ_SIO1_S); | ||
141 | #endif /* CONFIG_SERIAL_M32R_SIO */ | ||
142 | |||
143 | } | ||
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c new file mode 100644 index 000000000000..84315e344c58 --- /dev/null +++ b/arch/m32r/kernel/setup_opsput.c | |||
@@ -0,0 +1,482 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_opsput.c | ||
3 | * | ||
4 | * Setup routines for Renesas OPSPUT Board | ||
5 | * | ||
6 | * Copyright (c) 2002-2004 | ||
7 | * Hiroyuki Kondo, Hirokazu Takata, | ||
8 | * Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General | ||
11 | * Public License. See the file "COPYING" in the main directory of this | ||
12 | * archive for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/device.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/m32r.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* | ||
26 | * OPSP Interrupt Control Unit (Level 1) | ||
27 | */ | ||
28 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
29 | |||
30 | #ifndef CONFIG_SMP | ||
31 | typedef struct { | ||
32 | unsigned long icucr; /* ICU Control Register */ | ||
33 | } icu_data_t; | ||
34 | #endif /* CONFIG_SMP */ | ||
35 | |||
36 | static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; | ||
37 | |||
38 | static void disable_opsput_irq(unsigned int irq) | ||
39 | { | ||
40 | unsigned long port, data; | ||
41 | |||
42 | port = irq2port(irq); | ||
43 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
44 | outl(data, port); | ||
45 | } | ||
46 | |||
47 | static void enable_opsput_irq(unsigned int irq) | ||
48 | { | ||
49 | unsigned long port, data; | ||
50 | |||
51 | port = irq2port(irq); | ||
52 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
53 | outl(data, port); | ||
54 | } | ||
55 | |||
56 | static void mask_and_ack_opsput(unsigned int irq) | ||
57 | { | ||
58 | disable_opsput_irq(irq); | ||
59 | } | ||
60 | |||
61 | static void end_opsput_irq(unsigned int irq) | ||
62 | { | ||
63 | enable_opsput_irq(irq); | ||
64 | } | ||
65 | |||
66 | static unsigned int startup_opsput_irq(unsigned int irq) | ||
67 | { | ||
68 | enable_opsput_irq(irq); | ||
69 | return (0); | ||
70 | } | ||
71 | |||
72 | static void shutdown_opsput_irq(unsigned int irq) | ||
73 | { | ||
74 | unsigned long port; | ||
75 | |||
76 | port = irq2port(irq); | ||
77 | outl(M32R_ICUCR_ILEVEL7, port); | ||
78 | } | ||
79 | |||
80 | static struct hw_interrupt_type opsput_irq_type = | ||
81 | { | ||
82 | "OPSPUT-IRQ", | ||
83 | startup_opsput_irq, | ||
84 | shutdown_opsput_irq, | ||
85 | enable_opsput_irq, | ||
86 | disable_opsput_irq, | ||
87 | mask_and_ack_opsput, | ||
88 | end_opsput_irq | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * Interrupt Control Unit of PLD on OPSPUT (Level 2) | ||
93 | */ | ||
94 | #define irq2pldirq(x) ((x) - OPSPUT_PLD_IRQ_BASE) | ||
95 | #define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ | ||
96 | (((x) - 1) * sizeof(unsigned short))) | ||
97 | |||
98 | typedef struct { | ||
99 | unsigned short icucr; /* ICU Control Register */ | ||
100 | } pld_icu_data_t; | ||
101 | |||
102 | static pld_icu_data_t pld_icu_data[OPSPUT_NUM_PLD_IRQ]; | ||
103 | |||
104 | static void disable_opsput_pld_irq(unsigned int irq) | ||
105 | { | ||
106 | unsigned long port, data; | ||
107 | unsigned int pldirq; | ||
108 | |||
109 | pldirq = irq2pldirq(irq); | ||
110 | // disable_opsput_irq(M32R_IRQ_INT1); | ||
111 | port = pldirq2port(pldirq); | ||
112 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
113 | outw(data, port); | ||
114 | } | ||
115 | |||
116 | static void enable_opsput_pld_irq(unsigned int irq) | ||
117 | { | ||
118 | unsigned long port, data; | ||
119 | unsigned int pldirq; | ||
120 | |||
121 | pldirq = irq2pldirq(irq); | ||
122 | // enable_opsput_irq(M32R_IRQ_INT1); | ||
123 | port = pldirq2port(pldirq); | ||
124 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
125 | outw(data, port); | ||
126 | } | ||
127 | |||
128 | static void mask_and_ack_opsput_pld(unsigned int irq) | ||
129 | { | ||
130 | disable_opsput_pld_irq(irq); | ||
131 | // mask_and_ack_opsput(M32R_IRQ_INT1); | ||
132 | } | ||
133 | |||
134 | static void end_opsput_pld_irq(unsigned int irq) | ||
135 | { | ||
136 | enable_opsput_pld_irq(irq); | ||
137 | end_opsput_irq(M32R_IRQ_INT1); | ||
138 | } | ||
139 | |||
140 | static unsigned int startup_opsput_pld_irq(unsigned int irq) | ||
141 | { | ||
142 | enable_opsput_pld_irq(irq); | ||
143 | return (0); | ||
144 | } | ||
145 | |||
146 | static void shutdown_opsput_pld_irq(unsigned int irq) | ||
147 | { | ||
148 | unsigned long port; | ||
149 | unsigned int pldirq; | ||
150 | |||
151 | pldirq = irq2pldirq(irq); | ||
152 | // shutdown_opsput_irq(M32R_IRQ_INT1); | ||
153 | port = pldirq2port(pldirq); | ||
154 | outw(PLD_ICUCR_ILEVEL7, port); | ||
155 | } | ||
156 | |||
157 | static struct hw_interrupt_type opsput_pld_irq_type = | ||
158 | { | ||
159 | "OPSPUT-PLD-IRQ", | ||
160 | startup_opsput_pld_irq, | ||
161 | shutdown_opsput_pld_irq, | ||
162 | enable_opsput_pld_irq, | ||
163 | disable_opsput_pld_irq, | ||
164 | mask_and_ack_opsput_pld, | ||
165 | end_opsput_pld_irq | ||
166 | }; | ||
167 | |||
168 | /* | ||
169 | * Interrupt Control Unit of PLD on OPSPUT-LAN (Level 2) | ||
170 | */ | ||
171 | #define irq2lanpldirq(x) ((x) - OPSPUT_LAN_PLD_IRQ_BASE) | ||
172 | #define lanpldirq2port(x) (unsigned long)((int)OPSPUT_LAN_ICUCR1 + \ | ||
173 | (((x) - 1) * sizeof(unsigned short))) | ||
174 | |||
175 | static pld_icu_data_t lanpld_icu_data[OPSPUT_NUM_LAN_PLD_IRQ]; | ||
176 | |||
177 | static void disable_opsput_lanpld_irq(unsigned int irq) | ||
178 | { | ||
179 | unsigned long port, data; | ||
180 | unsigned int pldirq; | ||
181 | |||
182 | pldirq = irq2lanpldirq(irq); | ||
183 | port = lanpldirq2port(pldirq); | ||
184 | data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
185 | outw(data, port); | ||
186 | } | ||
187 | |||
188 | static void enable_opsput_lanpld_irq(unsigned int irq) | ||
189 | { | ||
190 | unsigned long port, data; | ||
191 | unsigned int pldirq; | ||
192 | |||
193 | pldirq = irq2lanpldirq(irq); | ||
194 | port = lanpldirq2port(pldirq); | ||
195 | data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
196 | outw(data, port); | ||
197 | } | ||
198 | |||
199 | static void mask_and_ack_opsput_lanpld(unsigned int irq) | ||
200 | { | ||
201 | disable_opsput_lanpld_irq(irq); | ||
202 | } | ||
203 | |||
204 | static void end_opsput_lanpld_irq(unsigned int irq) | ||
205 | { | ||
206 | enable_opsput_lanpld_irq(irq); | ||
207 | end_opsput_irq(M32R_IRQ_INT0); | ||
208 | } | ||
209 | |||
210 | static unsigned int startup_opsput_lanpld_irq(unsigned int irq) | ||
211 | { | ||
212 | enable_opsput_lanpld_irq(irq); | ||
213 | return (0); | ||
214 | } | ||
215 | |||
216 | static void shutdown_opsput_lanpld_irq(unsigned int irq) | ||
217 | { | ||
218 | unsigned long port; | ||
219 | unsigned int pldirq; | ||
220 | |||
221 | pldirq = irq2lanpldirq(irq); | ||
222 | port = lanpldirq2port(pldirq); | ||
223 | outw(PLD_ICUCR_ILEVEL7, port); | ||
224 | } | ||
225 | |||
226 | static struct hw_interrupt_type opsput_lanpld_irq_type = | ||
227 | { | ||
228 | "OPSPUT-PLD-LAN-IRQ", | ||
229 | startup_opsput_lanpld_irq, | ||
230 | shutdown_opsput_lanpld_irq, | ||
231 | enable_opsput_lanpld_irq, | ||
232 | disable_opsput_lanpld_irq, | ||
233 | mask_and_ack_opsput_lanpld, | ||
234 | end_opsput_lanpld_irq | ||
235 | }; | ||
236 | |||
237 | /* | ||
238 | * Interrupt Control Unit of PLD on OPSPUT-LCD (Level 2) | ||
239 | */ | ||
240 | #define irq2lcdpldirq(x) ((x) - OPSPUT_LCD_PLD_IRQ_BASE) | ||
241 | #define lcdpldirq2port(x) (unsigned long)((int)OPSPUT_LCD_ICUCR1 + \ | ||
242 | (((x) - 1) * sizeof(unsigned short))) | ||
243 | |||
244 | static pld_icu_data_t lcdpld_icu_data[OPSPUT_NUM_LCD_PLD_IRQ]; | ||
245 | |||
246 | static void disable_opsput_lcdpld_irq(unsigned int irq) | ||
247 | { | ||
248 | unsigned long port, data; | ||
249 | unsigned int pldirq; | ||
250 | |||
251 | pldirq = irq2lcdpldirq(irq); | ||
252 | port = lcdpldirq2port(pldirq); | ||
253 | data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
254 | outw(data, port); | ||
255 | } | ||
256 | |||
257 | static void enable_opsput_lcdpld_irq(unsigned int irq) | ||
258 | { | ||
259 | unsigned long port, data; | ||
260 | unsigned int pldirq; | ||
261 | |||
262 | pldirq = irq2lcdpldirq(irq); | ||
263 | port = lcdpldirq2port(pldirq); | ||
264 | data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
265 | outw(data, port); | ||
266 | } | ||
267 | |||
268 | static void mask_and_ack_opsput_lcdpld(unsigned int irq) | ||
269 | { | ||
270 | disable_opsput_lcdpld_irq(irq); | ||
271 | } | ||
272 | |||
273 | static void end_opsput_lcdpld_irq(unsigned int irq) | ||
274 | { | ||
275 | enable_opsput_lcdpld_irq(irq); | ||
276 | end_opsput_irq(M32R_IRQ_INT2); | ||
277 | } | ||
278 | |||
279 | static unsigned int startup_opsput_lcdpld_irq(unsigned int irq) | ||
280 | { | ||
281 | enable_opsput_lcdpld_irq(irq); | ||
282 | return (0); | ||
283 | } | ||
284 | |||
285 | static void shutdown_opsput_lcdpld_irq(unsigned int irq) | ||
286 | { | ||
287 | unsigned long port; | ||
288 | unsigned int pldirq; | ||
289 | |||
290 | pldirq = irq2lcdpldirq(irq); | ||
291 | port = lcdpldirq2port(pldirq); | ||
292 | outw(PLD_ICUCR_ILEVEL7, port); | ||
293 | } | ||
294 | |||
295 | static struct hw_interrupt_type opsput_lcdpld_irq_type = | ||
296 | { | ||
297 | "OPSPUT-PLD-LCD-IRQ", | ||
298 | startup_opsput_lcdpld_irq, | ||
299 | shutdown_opsput_lcdpld_irq, | ||
300 | enable_opsput_lcdpld_irq, | ||
301 | disable_opsput_lcdpld_irq, | ||
302 | mask_and_ack_opsput_lcdpld, | ||
303 | end_opsput_lcdpld_irq | ||
304 | }; | ||
305 | |||
306 | void __init init_IRQ(void) | ||
307 | { | ||
308 | #if defined(CONFIG_SMC91X) | ||
309 | /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/ | ||
310 | irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED; | ||
311 | irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type; | ||
312 | irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0; | ||
313 | irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */ | ||
314 | lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ | ||
315 | disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN); | ||
316 | #endif /* CONFIG_SMC91X */ | ||
317 | |||
318 | /* MFT2 : system timer */ | ||
319 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
320 | irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type; | ||
321 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
322 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
323 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
324 | disable_opsput_irq(M32R_IRQ_MFT2); | ||
325 | |||
326 | /* SIO0 : receive */ | ||
327 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
328 | irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type; | ||
329 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
330 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
331 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
332 | disable_opsput_irq(M32R_IRQ_SIO0_R); | ||
333 | |||
334 | /* SIO0 : send */ | ||
335 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
336 | irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type; | ||
337 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
338 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
339 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
340 | disable_opsput_irq(M32R_IRQ_SIO0_S); | ||
341 | |||
342 | /* SIO1 : receive */ | ||
343 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
344 | irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type; | ||
345 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
346 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
347 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
348 | disable_opsput_irq(M32R_IRQ_SIO1_R); | ||
349 | |||
350 | /* SIO1 : send */ | ||
351 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
352 | irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type; | ||
353 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
354 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
355 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
356 | disable_opsput_irq(M32R_IRQ_SIO1_S); | ||
357 | |||
358 | /* DMA1 : */ | ||
359 | irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED; | ||
360 | irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type; | ||
361 | irq_desc[M32R_IRQ_DMA1].action = 0; | ||
362 | irq_desc[M32R_IRQ_DMA1].depth = 1; | ||
363 | icu_data[M32R_IRQ_DMA1].icucr = 0; | ||
364 | disable_opsput_irq(M32R_IRQ_DMA1); | ||
365 | |||
366 | #ifdef CONFIG_SERIAL_M32R_PLDSIO | ||
367 | /* INT#1: SIO0 Receive on PLD */ | ||
368 | irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED; | ||
369 | irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type; | ||
370 | irq_desc[PLD_IRQ_SIO0_RCV].action = 0; | ||
371 | irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */ | ||
372 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | ||
373 | disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV); | ||
374 | |||
375 | /* INT#1: SIO0 Send on PLD */ | ||
376 | irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED; | ||
377 | irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type; | ||
378 | irq_desc[PLD_IRQ_SIO0_SND].action = 0; | ||
379 | irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */ | ||
380 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | ||
381 | disable_opsput_pld_irq(PLD_IRQ_SIO0_SND); | ||
382 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ | ||
383 | |||
384 | #if defined(CONFIG_M32R_CFC) | ||
385 | /* INT#1: CFC IREQ on PLD */ | ||
386 | irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; | ||
387 | irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type; | ||
388 | irq_desc[PLD_IRQ_CFIREQ].action = 0; | ||
389 | irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ | ||
390 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ | ||
391 | disable_opsput_pld_irq(PLD_IRQ_CFIREQ); | ||
392 | |||
393 | /* INT#1: CFC Insert on PLD */ | ||
394 | irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; | ||
395 | irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type; | ||
396 | irq_desc[PLD_IRQ_CFC_INSERT].action = 0; | ||
397 | irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ | ||
398 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ | ||
399 | disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT); | ||
400 | |||
401 | /* INT#1: CFC Eject on PLD */ | ||
402 | irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; | ||
403 | irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type; | ||
404 | irq_desc[PLD_IRQ_CFC_EJECT].action = 0; | ||
405 | irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ | ||
406 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ | ||
407 | disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT); | ||
408 | #endif /* CONFIG_M32R_CFC */ | ||
409 | |||
410 | |||
411 | /* | ||
412 | * INT0# is used for LAN, DIO | ||
413 | * We enable it here. | ||
414 | */ | ||
415 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; | ||
416 | enable_opsput_irq(M32R_IRQ_INT0); | ||
417 | |||
418 | /* | ||
419 | * INT1# is used for UART, MMC, CF Controller in FPGA. | ||
420 | * We enable it here. | ||
421 | */ | ||
422 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; | ||
423 | enable_opsput_irq(M32R_IRQ_INT1); | ||
424 | |||
425 | #if defined(CONFIG_USB) | ||
426 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ | ||
427 | |||
428 | irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED; | ||
429 | irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type; | ||
430 | irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0; | ||
431 | irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1; | ||
432 | lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ | ||
433 | disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1); | ||
434 | #endif | ||
435 | /* | ||
436 | * INT2# is used for BAT, USB, AUDIO | ||
437 | * We enable it here. | ||
438 | */ | ||
439 | icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; | ||
440 | enable_opsput_irq(M32R_IRQ_INT2); | ||
441 | |||
442 | //#if defined(CONFIG_VIDEO_M32R_AR) | ||
443 | /* | ||
444 | * INT3# is used for AR | ||
445 | */ | ||
446 | irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED; | ||
447 | irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type; | ||
448 | irq_desc[M32R_IRQ_INT3].action = 0; | ||
449 | irq_desc[M32R_IRQ_INT3].depth = 1; | ||
450 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | ||
451 | disable_opsput_irq(M32R_IRQ_INT3); | ||
452 | //#endif /* CONFIG_VIDEO_M32R_AR */ | ||
453 | } | ||
454 | |||
455 | #define LAN_IOSTART 0x300 | ||
456 | #define LAN_IOEND 0x320 | ||
457 | static struct resource smc91x_resources[] = { | ||
458 | [0] = { | ||
459 | .start = (LAN_IOSTART), | ||
460 | .end = (LAN_IOEND), | ||
461 | .flags = IORESOURCE_MEM, | ||
462 | }, | ||
463 | [1] = { | ||
464 | .start = OPSPUT_LAN_IRQ_LAN, | ||
465 | .end = OPSPUT_LAN_IRQ_LAN, | ||
466 | .flags = IORESOURCE_IRQ, | ||
467 | } | ||
468 | }; | ||
469 | |||
470 | static struct platform_device smc91x_device = { | ||
471 | .name = "smc91x", | ||
472 | .id = 0, | ||
473 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
474 | .resource = smc91x_resources, | ||
475 | }; | ||
476 | |||
477 | static int __init platform_init(void) | ||
478 | { | ||
479 | platform_device_register(&smc91x_device); | ||
480 | return 0; | ||
481 | } | ||
482 | arch_initcall(platform_init); | ||
diff --git a/arch/m32r/kernel/setup_usrv.c b/arch/m32r/kernel/setup_usrv.c new file mode 100644 index 000000000000..fe417be5e3e9 --- /dev/null +++ b/arch/m32r/kernel/setup_usrv.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/setup_usrv.c | ||
3 | * | ||
4 | * Setup routines for MITSUBISHI uServer | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002, 2003 Hiroyuki Kondo, Hirokazu Takata, | ||
7 | * Hitoshi Yamamoto | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/system.h> | ||
16 | #include <asm/m32r.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) | ||
20 | |||
21 | #if !defined(CONFIG_SMP) | ||
22 | typedef struct { | ||
23 | unsigned long icucr; /* ICU Control Register */ | ||
24 | } icu_data_t; | ||
25 | #endif /* CONFIG_SMP */ | ||
26 | |||
27 | icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; | ||
28 | |||
29 | static void disable_mappi_irq(unsigned int irq) | ||
30 | { | ||
31 | unsigned long port, data; | ||
32 | |||
33 | port = irq2port(irq); | ||
34 | data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; | ||
35 | outl(data, port); | ||
36 | } | ||
37 | |||
38 | static void enable_mappi_irq(unsigned int irq) | ||
39 | { | ||
40 | unsigned long port, data; | ||
41 | |||
42 | port = irq2port(irq); | ||
43 | data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; | ||
44 | outl(data, port); | ||
45 | } | ||
46 | |||
47 | static void mask_and_ack_mappi(unsigned int irq) | ||
48 | { | ||
49 | disable_mappi_irq(irq); | ||
50 | } | ||
51 | |||
52 | static void end_mappi_irq(unsigned int irq) | ||
53 | { | ||
54 | enable_mappi_irq(irq); | ||
55 | } | ||
56 | |||
57 | static unsigned int startup_mappi_irq(unsigned int irq) | ||
58 | { | ||
59 | enable_mappi_irq(irq); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static void shutdown_mappi_irq(unsigned int irq) | ||
64 | { | ||
65 | unsigned long port; | ||
66 | |||
67 | port = irq2port(irq); | ||
68 | outl(M32R_ICUCR_ILEVEL7, port); | ||
69 | } | ||
70 | |||
71 | static struct hw_interrupt_type mappi_irq_type = | ||
72 | { | ||
73 | "M32700-IRQ", | ||
74 | startup_mappi_irq, | ||
75 | shutdown_mappi_irq, | ||
76 | enable_mappi_irq, | ||
77 | disable_mappi_irq, | ||
78 | mask_and_ack_mappi, | ||
79 | end_mappi_irq | ||
80 | }; | ||
81 | |||
82 | /* | ||
83 | * Interrupt Control Unit of PLD on M32700UT (Level 2) | ||
84 | */ | ||
85 | #define irq2pldirq(x) ((x) - M32700UT_PLD_IRQ_BASE) | ||
86 | #define pldirq2port(x) (unsigned long)((int)PLD_ICUCR1 + \ | ||
87 | (((x) - 1) * sizeof(unsigned short))) | ||
88 | |||
89 | typedef struct { | ||
90 | unsigned short icucr; /* ICU Control Register */ | ||
91 | } pld_icu_data_t; | ||
92 | |||
93 | static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ]; | ||
94 | |||
95 | static void disable_m32700ut_pld_irq(unsigned int irq) | ||
96 | { | ||
97 | unsigned long port, data; | ||
98 | unsigned int pldirq; | ||
99 | |||
100 | pldirq = irq2pldirq(irq); | ||
101 | port = pldirq2port(pldirq); | ||
102 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7; | ||
103 | outw(data, port); | ||
104 | } | ||
105 | |||
106 | static void enable_m32700ut_pld_irq(unsigned int irq) | ||
107 | { | ||
108 | unsigned long port, data; | ||
109 | unsigned int pldirq; | ||
110 | |||
111 | pldirq = irq2pldirq(irq); | ||
112 | port = pldirq2port(pldirq); | ||
113 | data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6; | ||
114 | outw(data, port); | ||
115 | } | ||
116 | |||
117 | static void mask_and_ack_m32700ut_pld(unsigned int irq) | ||
118 | { | ||
119 | disable_m32700ut_pld_irq(irq); | ||
120 | } | ||
121 | |||
122 | static void end_m32700ut_pld_irq(unsigned int irq) | ||
123 | { | ||
124 | enable_m32700ut_pld_irq(irq); | ||
125 | end_mappi_irq(M32R_IRQ_INT1); | ||
126 | } | ||
127 | |||
128 | static unsigned int startup_m32700ut_pld_irq(unsigned int irq) | ||
129 | { | ||
130 | enable_m32700ut_pld_irq(irq); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static void shutdown_m32700ut_pld_irq(unsigned int irq) | ||
135 | { | ||
136 | unsigned long port; | ||
137 | unsigned int pldirq; | ||
138 | |||
139 | pldirq = irq2pldirq(irq); | ||
140 | port = pldirq2port(pldirq); | ||
141 | outw(PLD_ICUCR_ILEVEL7, port); | ||
142 | } | ||
143 | |||
144 | static struct hw_interrupt_type m32700ut_pld_irq_type = | ||
145 | { | ||
146 | "USRV-PLD-IRQ", | ||
147 | startup_m32700ut_pld_irq, | ||
148 | shutdown_m32700ut_pld_irq, | ||
149 | enable_m32700ut_pld_irq, | ||
150 | disable_m32700ut_pld_irq, | ||
151 | mask_and_ack_m32700ut_pld, | ||
152 | end_m32700ut_pld_irq | ||
153 | }; | ||
154 | |||
155 | void __init init_IRQ(void) | ||
156 | { | ||
157 | static int once = 0; | ||
158 | int i; | ||
159 | |||
160 | if (once) | ||
161 | return; | ||
162 | else | ||
163 | once++; | ||
164 | |||
165 | /* MFT2 : system timer */ | ||
166 | irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; | ||
167 | irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type; | ||
168 | irq_desc[M32R_IRQ_MFT2].action = 0; | ||
169 | irq_desc[M32R_IRQ_MFT2].depth = 1; | ||
170 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | ||
171 | disable_mappi_irq(M32R_IRQ_MFT2); | ||
172 | |||
173 | #if defined(CONFIG_SERIAL_M32R_SIO) | ||
174 | /* SIO0_R : uart receive data */ | ||
175 | irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; | ||
176 | irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type; | ||
177 | irq_desc[M32R_IRQ_SIO0_R].action = 0; | ||
178 | irq_desc[M32R_IRQ_SIO0_R].depth = 1; | ||
179 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | ||
180 | disable_mappi_irq(M32R_IRQ_SIO0_R); | ||
181 | |||
182 | /* SIO0_S : uart send data */ | ||
183 | irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; | ||
184 | irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type; | ||
185 | irq_desc[M32R_IRQ_SIO0_S].action = 0; | ||
186 | irq_desc[M32R_IRQ_SIO0_S].depth = 1; | ||
187 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | ||
188 | disable_mappi_irq(M32R_IRQ_SIO0_S); | ||
189 | |||
190 | /* SIO1_R : uart receive data */ | ||
191 | irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; | ||
192 | irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type; | ||
193 | irq_desc[M32R_IRQ_SIO1_R].action = 0; | ||
194 | irq_desc[M32R_IRQ_SIO1_R].depth = 1; | ||
195 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | ||
196 | disable_mappi_irq(M32R_IRQ_SIO1_R); | ||
197 | |||
198 | /* SIO1_S : uart send data */ | ||
199 | irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; | ||
200 | irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type; | ||
201 | irq_desc[M32R_IRQ_SIO1_S].action = 0; | ||
202 | irq_desc[M32R_IRQ_SIO1_S].depth = 1; | ||
203 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | ||
204 | disable_mappi_irq(M32R_IRQ_SIO1_S); | ||
205 | #endif /* CONFIG_SERIAL_M32R_SIO */ | ||
206 | |||
207 | /* INT#67-#71: CFC#0 IREQ on PLD */ | ||
208 | for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) { | ||
209 | irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED; | ||
210 | irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type; | ||
211 | irq_desc[PLD_IRQ_CF0 + i].action = 0; | ||
212 | irq_desc[PLD_IRQ_CF0 + i].depth = 1; /* disable nested irq */ | ||
213 | pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr | ||
214 | = PLD_ICUCR_ISMOD01; /* 'L' level sense */ | ||
215 | disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i); | ||
216 | } | ||
217 | |||
218 | #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) | ||
219 | /* INT#76: 16552D#0 IREQ on PLD */ | ||
220 | irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED; | ||
221 | irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type; | ||
222 | irq_desc[PLD_IRQ_UART0].action = 0; | ||
223 | irq_desc[PLD_IRQ_UART0].depth = 1; /* disable nested irq */ | ||
224 | pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr | ||
225 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ | ||
226 | disable_m32700ut_pld_irq(PLD_IRQ_UART0); | ||
227 | |||
228 | /* INT#77: 16552D#1 IREQ on PLD */ | ||
229 | irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED; | ||
230 | irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type; | ||
231 | irq_desc[PLD_IRQ_UART1].action = 0; | ||
232 | irq_desc[PLD_IRQ_UART1].depth = 1; /* disable nested irq */ | ||
233 | pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr | ||
234 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ | ||
235 | disable_m32700ut_pld_irq(PLD_IRQ_UART1); | ||
236 | #endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */ | ||
237 | |||
238 | #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE) | ||
239 | /* INT#80: AK4524 IREQ on PLD */ | ||
240 | irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED; | ||
241 | irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type; | ||
242 | irq_desc[PLD_IRQ_SNDINT].action = 0; | ||
243 | irq_desc[PLD_IRQ_SNDINT].depth = 1; /* disable nested irq */ | ||
244 | pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr | ||
245 | = PLD_ICUCR_ISMOD01; /* 'L' level sense */ | ||
246 | disable_m32700ut_pld_irq(PLD_IRQ_SNDINT); | ||
247 | #endif /* CONFIG_IDC_AK4524 || CONFIG_IDC_AK4524_MODULE */ | ||
248 | |||
249 | /* | ||
250 | * INT1# is used for UART, MMC, CF Controller in FPGA. | ||
251 | * We enable it here. | ||
252 | */ | ||
253 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD11; | ||
254 | enable_mappi_irq(M32R_IRQ_INT1); | ||
255 | } | ||
256 | |||
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c new file mode 100644 index 000000000000..50311eb07a24 --- /dev/null +++ b/arch/m32r/kernel/signal.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/signal.c | ||
3 | * | ||
4 | * Copyright (c) 2003 Hitoshi Yamamoto | ||
5 | * | ||
6 | * Taken from i386 version. | ||
7 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
8 | * | ||
9 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | ||
10 | * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/smp_lock.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/signal.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/wait.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/stddef.h> | ||
24 | #include <linux/personality.h> | ||
25 | #include <linux/suspend.h> | ||
26 | #include <asm/cacheflush.h> | ||
27 | #include <asm/ucontext.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | |||
30 | #define DEBUG_SIG 0 | ||
31 | |||
32 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
33 | |||
34 | int do_signal(struct pt_regs *, sigset_t *); | ||
35 | |||
36 | asmlinkage int | ||
37 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | ||
38 | unsigned long r2, unsigned long r3, unsigned long r4, | ||
39 | unsigned long r5, unsigned long r6, struct pt_regs regs) | ||
40 | { | ||
41 | sigset_t saveset, newset; | ||
42 | |||
43 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
44 | if (sigsetsize != sizeof(sigset_t)) | ||
45 | return -EINVAL; | ||
46 | |||
47 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
48 | return -EFAULT; | ||
49 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
50 | |||
51 | spin_lock_irq(¤t->sighand->siglock); | ||
52 | saveset = current->blocked; | ||
53 | current->blocked = newset; | ||
54 | recalc_sigpending(); | ||
55 | spin_unlock_irq(¤t->sighand->siglock); | ||
56 | |||
57 | regs.r0 = -EINTR; | ||
58 | while (1) { | ||
59 | current->state = TASK_INTERRUPTIBLE; | ||
60 | schedule(); | ||
61 | if (do_signal(®s, &saveset)) | ||
62 | return regs.r0; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | asmlinkage int | ||
67 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
68 | unsigned long r2, unsigned long r3, unsigned long r4, | ||
69 | unsigned long r5, unsigned long r6, struct pt_regs regs) | ||
70 | { | ||
71 | return do_sigaltstack(uss, uoss, regs.spu); | ||
72 | } | ||
73 | |||
74 | |||
75 | /* | ||
76 | * Do a signal return; undo the signal stack. | ||
77 | */ | ||
78 | |||
79 | struct rt_sigframe | ||
80 | { | ||
81 | int sig; | ||
82 | struct siginfo *pinfo; | ||
83 | void *puc; | ||
84 | struct siginfo info; | ||
85 | struct ucontext uc; | ||
86 | // struct _fpstate fpstate; | ||
87 | }; | ||
88 | |||
89 | static int | ||
90 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | ||
91 | int *r0_p) | ||
92 | { | ||
93 | unsigned int err = 0; | ||
94 | |||
95 | /* Always make any pending restarted system calls return -EINTR */ | ||
96 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
97 | |||
98 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) | ||
99 | COPY(r4); | ||
100 | COPY(r5); | ||
101 | COPY(r6); | ||
102 | COPY(pt_regs); | ||
103 | /* COPY(r0); Skip r0 */ | ||
104 | COPY(r1); | ||
105 | COPY(r2); | ||
106 | COPY(r3); | ||
107 | COPY(r7); | ||
108 | COPY(r8); | ||
109 | COPY(r9); | ||
110 | COPY(r10); | ||
111 | COPY(r11); | ||
112 | COPY(r12); | ||
113 | #if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) | ||
114 | COPY(acc0h); | ||
115 | COPY(acc0l); | ||
116 | COPY(acc1h); | ||
117 | COPY(acc1l); | ||
118 | #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) | ||
119 | COPY(acch); | ||
120 | COPY(accl); | ||
121 | #else | ||
122 | #error unknown isa configuration | ||
123 | #endif | ||
124 | COPY(psw); | ||
125 | COPY(bpc); | ||
126 | COPY(bbpsw); | ||
127 | COPY(bbpc); | ||
128 | COPY(spu); | ||
129 | COPY(fp); | ||
130 | COPY(lr); | ||
131 | COPY(spi); | ||
132 | #undef COPY | ||
133 | |||
134 | regs->syscall_nr = -1; /* disable syscall checks */ | ||
135 | err |= __get_user(*r0_p, &sc->sc_r0); | ||
136 | |||
137 | return err; | ||
138 | } | ||
139 | |||
140 | asmlinkage int | ||
141 | sys_rt_sigreturn(unsigned long r0, unsigned long r1, | ||
142 | unsigned long r2, unsigned long r3, unsigned long r4, | ||
143 | unsigned long r5, unsigned long r6, struct pt_regs regs) | ||
144 | { | ||
145 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.spu; | ||
146 | sigset_t set; | ||
147 | stack_t st; | ||
148 | int result; | ||
149 | |||
150 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
151 | goto badframe; | ||
152 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
153 | goto badframe; | ||
154 | |||
155 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
156 | spin_lock_irq(¤t->sighand->siglock); | ||
157 | current->blocked = set; | ||
158 | recalc_sigpending(); | ||
159 | spin_unlock_irq(¤t->sighand->siglock); | ||
160 | |||
161 | if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &result)) | ||
162 | goto badframe; | ||
163 | |||
164 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | ||
165 | goto badframe; | ||
166 | /* It is more difficult to avoid calling this function than to | ||
167 | call it and ignore errors. */ | ||
168 | do_sigaltstack(&st, NULL, regs.spu); | ||
169 | |||
170 | return result; | ||
171 | |||
172 | badframe: | ||
173 | force_sig(SIGSEGV, current); | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Set up a signal frame. | ||
179 | */ | ||
180 | |||
181 | static int | ||
182 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | ||
183 | unsigned long mask) | ||
184 | { | ||
185 | int err = 0; | ||
186 | |||
187 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | ||
188 | COPY(r4); | ||
189 | COPY(r5); | ||
190 | COPY(r6); | ||
191 | COPY(pt_regs); | ||
192 | COPY(r0); | ||
193 | COPY(r1); | ||
194 | COPY(r2); | ||
195 | COPY(r3); | ||
196 | COPY(r7); | ||
197 | COPY(r8); | ||
198 | COPY(r9); | ||
199 | COPY(r10); | ||
200 | COPY(r11); | ||
201 | COPY(r12); | ||
202 | #if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) | ||
203 | COPY(acc0h); | ||
204 | COPY(acc0l); | ||
205 | COPY(acc1h); | ||
206 | COPY(acc1l); | ||
207 | #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) | ||
208 | COPY(acch); | ||
209 | COPY(accl); | ||
210 | #else | ||
211 | #error unknown isa configuration | ||
212 | #endif | ||
213 | COPY(psw); | ||
214 | COPY(bpc); | ||
215 | COPY(bbpsw); | ||
216 | COPY(bbpc); | ||
217 | COPY(spu); | ||
218 | COPY(fp); | ||
219 | COPY(lr); | ||
220 | COPY(spi); | ||
221 | #undef COPY | ||
222 | |||
223 | err |= __put_user(mask, &sc->oldmask); | ||
224 | |||
225 | return err; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Determine which stack to use.. | ||
230 | */ | ||
231 | static inline void __user * | ||
232 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | ||
233 | { | ||
234 | /* This is the X/Open sanctioned signal stack switching. */ | ||
235 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
236 | if (sas_ss_flags(sp) == 0) | ||
237 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
238 | } | ||
239 | |||
240 | return (void __user *)((sp - frame_size) & -8ul); | ||
241 | } | ||
242 | |||
243 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
244 | sigset_t *set, struct pt_regs *regs) | ||
245 | { | ||
246 | struct rt_sigframe __user *frame; | ||
247 | int err = 0; | ||
248 | int signal; | ||
249 | |||
250 | frame = get_sigframe(ka, regs->spu, sizeof(*frame)); | ||
251 | |||
252 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
253 | goto give_sigsegv; | ||
254 | |||
255 | signal = current_thread_info()->exec_domain | ||
256 | && current_thread_info()->exec_domain->signal_invmap | ||
257 | && sig < 32 | ||
258 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
259 | : sig; | ||
260 | |||
261 | err |= __put_user(signal, &frame->sig); | ||
262 | if (err) | ||
263 | goto give_sigsegv; | ||
264 | |||
265 | err |= __put_user(&frame->info, &frame->pinfo); | ||
266 | err |= __put_user(&frame->uc, &frame->puc); | ||
267 | err |= copy_siginfo_to_user(&frame->info, info); | ||
268 | if (err) | ||
269 | goto give_sigsegv; | ||
270 | |||
271 | /* Create the ucontext. */ | ||
272 | err |= __put_user(0, &frame->uc.uc_flags); | ||
273 | err |= __put_user(0, &frame->uc.uc_link); | ||
274 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
275 | err |= __put_user(sas_ss_flags(regs->spu), | ||
276 | &frame->uc.uc_stack.ss_flags); | ||
277 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
278 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | ||
279 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
280 | if (err) | ||
281 | goto give_sigsegv; | ||
282 | |||
283 | /* Set up to return from userspace. */ | ||
284 | regs->lr = (unsigned long)ka->sa.sa_restorer; | ||
285 | |||
286 | /* Set up registers for signal handler */ | ||
287 | regs->spu = (unsigned long)frame; | ||
288 | regs->r0 = signal; /* Arg for signal handler */ | ||
289 | regs->r1 = (unsigned long)&frame->info; | ||
290 | regs->r2 = (unsigned long)&frame->uc; | ||
291 | regs->bpc = (unsigned long)ka->sa.sa_handler; | ||
292 | |||
293 | set_fs(USER_DS); | ||
294 | |||
295 | #if DEBUG_SIG | ||
296 | printk("SIG deliver (%s:%d): sp=%p pc=%p\n", | ||
297 | current->comm, current->pid, frame, regs->pc); | ||
298 | #endif | ||
299 | |||
300 | return; | ||
301 | |||
302 | give_sigsegv: | ||
303 | force_sigsegv(sig, current); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * OK, we're invoking a handler | ||
308 | */ | ||
309 | |||
310 | static void | ||
311 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | ||
312 | sigset_t *oldset, struct pt_regs *regs) | ||
313 | { | ||
314 | unsigned short inst; | ||
315 | |||
316 | /* Are we from a system call? */ | ||
317 | if (regs->syscall_nr >= 0) { | ||
318 | /* If so, check system call restarting.. */ | ||
319 | switch (regs->r0) { | ||
320 | case -ERESTART_RESTARTBLOCK: | ||
321 | case -ERESTARTNOHAND: | ||
322 | regs->r0 = -EINTR; | ||
323 | break; | ||
324 | |||
325 | case -ERESTARTSYS: | ||
326 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
327 | regs->r0 = -EINTR; | ||
328 | break; | ||
329 | } | ||
330 | /* fallthrough */ | ||
331 | case -ERESTARTNOINTR: | ||
332 | regs->r0 = regs->orig_r0; | ||
333 | inst = *(unsigned short *)(regs->bpc - 2); | ||
334 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | ||
335 | regs->bpc -= 2; | ||
336 | else | ||
337 | regs->bpc -= 4; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /* Set up the stack frame */ | ||
342 | setup_rt_frame(sig, ka, info, oldset, regs); | ||
343 | |||
344 | if (!(ka->sa.sa_flags & SA_NODEFER)) { | ||
345 | spin_lock_irq(¤t->sighand->siglock); | ||
346 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
347 | sigaddset(¤t->blocked,sig); | ||
348 | recalc_sigpending(); | ||
349 | spin_unlock_irq(¤t->sighand->siglock); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
355 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
356 | * mistake. | ||
357 | */ | ||
358 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | ||
359 | { | ||
360 | siginfo_t info; | ||
361 | int signr; | ||
362 | struct k_sigaction ka; | ||
363 | unsigned short inst; | ||
364 | |||
365 | /* | ||
366 | * We want the common case to go fast, which | ||
367 | * is why we may in certain cases get here from | ||
368 | * kernel mode. Just return without doing anything | ||
369 | * if so. | ||
370 | */ | ||
371 | if (!user_mode(regs)) | ||
372 | return 1; | ||
373 | |||
374 | if (current->flags & PF_FREEZE) { | ||
375 | refrigerator(0); | ||
376 | goto no_signal; | ||
377 | } | ||
378 | |||
379 | if (!oldset) | ||
380 | oldset = ¤t->blocked; | ||
381 | |||
382 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
383 | if (signr > 0) { | ||
384 | /* Reenable any watchpoints before delivering the | ||
385 | * signal to user space. The processor register will | ||
386 | * have been cleared if the watchpoint triggered | ||
387 | * inside the kernel. | ||
388 | */ | ||
389 | |||
390 | /* Whee! Actually deliver the signal. */ | ||
391 | handle_signal(signr, &ka, &info, oldset, regs); | ||
392 | return 1; | ||
393 | } | ||
394 | |||
395 | no_signal: | ||
396 | /* Did we come from a system call? */ | ||
397 | if (regs->syscall_nr >= 0) { | ||
398 | /* Restart the system call - no handlers present */ | ||
399 | if (regs->r0 == -ERESTARTNOHAND || | ||
400 | regs->r0 == -ERESTARTSYS || | ||
401 | regs->r0 == -ERESTARTNOINTR) { | ||
402 | regs->r0 = regs->orig_r0; | ||
403 | inst = *(unsigned short *)(regs->bpc - 2); | ||
404 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | ||
405 | regs->bpc -= 2; | ||
406 | else | ||
407 | regs->bpc -= 4; | ||
408 | } | ||
409 | if (regs->r0 == -ERESTART_RESTARTBLOCK){ | ||
410 | regs->r0 = regs->orig_r0; | ||
411 | regs->r7 = __NR_restart_syscall; | ||
412 | inst = *(unsigned short *)(regs->bpc - 2); | ||
413 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | ||
414 | regs->bpc -= 2; | ||
415 | else | ||
416 | regs->bpc -= 4; | ||
417 | } | ||
418 | } | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * notification of userspace execution resumption | ||
424 | * - triggered by current->work.notify_resume | ||
425 | */ | ||
426 | void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | ||
427 | __u32 thread_info_flags) | ||
428 | { | ||
429 | /* Pending single-step? */ | ||
430 | if (thread_info_flags & _TIF_SINGLESTEP) | ||
431 | clear_thread_flag(TIF_SINGLESTEP); | ||
432 | |||
433 | /* deal with pending signal delivery */ | ||
434 | if (thread_info_flags & _TIF_SIGPENDING) | ||
435 | do_signal(regs,oldset); | ||
436 | |||
437 | clear_thread_flag(TIF_IRET); | ||
438 | } | ||
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c new file mode 100644 index 000000000000..48b187f2d2b3 --- /dev/null +++ b/arch/m32r/kernel/smp.c | |||
@@ -0,0 +1,965 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/smp.c | ||
3 | * | ||
4 | * M32R SMP support routines. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 Hitoshi Yamamoto | ||
7 | * | ||
8 | * Taken from i386 version. | ||
9 | * (c) 1995 Alan Cox, Building #3 <alan@redhat.com> | ||
10 | * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com> | ||
11 | * | ||
12 | * This code is released under the GNU General Public License version 2 or | ||
13 | * later. | ||
14 | */ | ||
15 | |||
16 | #undef DEBUG_SMP | ||
17 | |||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/smp.h> | ||
23 | #include <linux/profile.h> | ||
24 | #include <linux/cpu.h> | ||
25 | |||
26 | #include <asm/cacheflush.h> | ||
27 | #include <asm/pgalloc.h> | ||
28 | #include <asm/atomic.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/mmu_context.h> | ||
31 | #include <asm/m32r.h> | ||
32 | |||
33 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
34 | /* Data structures and variables */ | ||
35 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
36 | |||
37 | /* | ||
38 | * Structure and data for smp_call_function(). This is designed to minimise | ||
39 | * static memory requirements. It also looks cleaner. | ||
40 | */ | ||
41 | static DEFINE_SPINLOCK(call_lock); | ||
42 | |||
43 | struct call_data_struct { | ||
44 | void (*func) (void *info); | ||
45 | void *info; | ||
46 | atomic_t started; | ||
47 | atomic_t finished; | ||
48 | int wait; | ||
49 | } __attribute__ ((__aligned__(SMP_CACHE_BYTES))); | ||
50 | |||
51 | static struct call_data_struct *call_data; | ||
52 | |||
53 | /* | ||
54 | * For flush_cache_all() | ||
55 | */ | ||
56 | static DEFINE_SPINLOCK(flushcache_lock); | ||
57 | static volatile unsigned long flushcache_cpumask = 0; | ||
58 | |||
59 | /* | ||
60 | * For flush_tlb_others() | ||
61 | */ | ||
62 | static volatile cpumask_t flush_cpumask; | ||
63 | static struct mm_struct *flush_mm; | ||
64 | static struct vm_area_struct *flush_vma; | ||
65 | static volatile unsigned long flush_va; | ||
66 | static DEFINE_SPINLOCK(tlbstate_lock); | ||
67 | #define FLUSH_ALL 0xffffffff | ||
68 | |||
69 | DECLARE_PER_CPU(int, prof_multiplier); | ||
70 | DECLARE_PER_CPU(int, prof_old_multiplier); | ||
71 | DECLARE_PER_CPU(int, prof_counter); | ||
72 | |||
73 | extern spinlock_t ipi_lock[]; | ||
74 | |||
75 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
76 | /* Function Prototypes */ | ||
77 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
78 | |||
79 | void smp_send_reschedule(int); | ||
80 | void smp_reschedule_interrupt(void); | ||
81 | |||
82 | void smp_flush_cache_all(void); | ||
83 | void smp_flush_cache_all_interrupt(void); | ||
84 | |||
85 | void smp_flush_tlb_all(void); | ||
86 | static void flush_tlb_all_ipi(void *); | ||
87 | |||
88 | void smp_flush_tlb_mm(struct mm_struct *); | ||
89 | void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \ | ||
90 | unsigned long); | ||
91 | void smp_flush_tlb_page(struct vm_area_struct *, unsigned long); | ||
92 | static void flush_tlb_others(cpumask_t, struct mm_struct *, | ||
93 | struct vm_area_struct *, unsigned long); | ||
94 | void smp_invalidate_interrupt(void); | ||
95 | |||
96 | void smp_send_stop(void); | ||
97 | static void stop_this_cpu(void *); | ||
98 | |||
99 | int smp_call_function(void (*) (void *), void *, int, int); | ||
100 | void smp_call_function_interrupt(void); | ||
101 | |||
102 | void smp_send_timer(void); | ||
103 | void smp_ipi_timer_interrupt(struct pt_regs *); | ||
104 | void smp_local_timer_interrupt(struct pt_regs *); | ||
105 | |||
106 | void send_IPI_allbutself(int, int); | ||
107 | static void send_IPI_mask(cpumask_t, int, int); | ||
108 | unsigned long send_IPI_mask_phys(cpumask_t, int, int); | ||
109 | |||
110 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
111 | /* Rescheduling request Routines */ | ||
112 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
113 | |||
114 | /*==========================================================================* | ||
115 | * Name: smp_send_reschedule | ||
116 | * | ||
117 | * Description: This routine requests other CPU to execute rescheduling. | ||
118 | * 1.Send 'RESCHEDULE_IPI' to other CPU. | ||
119 | * Request other CPU to execute 'smp_reschedule_interrupt()'. | ||
120 | * | ||
121 | * Born on Date: 2002.02.05 | ||
122 | * | ||
123 | * Arguments: cpu_id - Target CPU ID | ||
124 | * | ||
125 | * Returns: void (cannot fail) | ||
126 | * | ||
127 | * Modification log: | ||
128 | * Date Who Description | ||
129 | * ---------- --- -------------------------------------------------------- | ||
130 | * | ||
131 | *==========================================================================*/ | ||
132 | void smp_send_reschedule(int cpu_id) | ||
133 | { | ||
134 | WARN_ON(cpu_is_offline(cpu_id)); | ||
135 | send_IPI_mask(cpumask_of_cpu(cpu_id), RESCHEDULE_IPI, 1); | ||
136 | } | ||
137 | |||
138 | /*==========================================================================* | ||
139 | * Name: smp_reschedule_interrupt | ||
140 | * | ||
141 | * Description: This routine executes on CPU which received | ||
142 | * 'RESCHEDULE_IPI'. | ||
143 | * Rescheduling is processed at the exit of interrupt | ||
144 | * operation. | ||
145 | * | ||
146 | * Born on Date: 2002.02.05 | ||
147 | * | ||
148 | * Arguments: NONE | ||
149 | * | ||
150 | * Returns: void (cannot fail) | ||
151 | * | ||
152 | * Modification log: | ||
153 | * Date Who Description | ||
154 | * ---------- --- -------------------------------------------------------- | ||
155 | * | ||
156 | *==========================================================================*/ | ||
157 | void smp_reschedule_interrupt(void) | ||
158 | { | ||
159 | /* nothing to do */ | ||
160 | } | ||
161 | |||
162 | /*==========================================================================* | ||
163 | * Name: smp_flush_cache_all | ||
164 | * | ||
165 | * Description: This routine sends a 'INVALIDATE_CACHE_IPI' to all other | ||
166 | * CPUs in the system. | ||
167 | * | ||
168 | * Born on Date: 2003-05-28 | ||
169 | * | ||
170 | * Arguments: NONE | ||
171 | * | ||
172 | * Returns: void (cannot fail) | ||
173 | * | ||
174 | * Modification log: | ||
175 | * Date Who Description | ||
176 | * ---------- --- -------------------------------------------------------- | ||
177 | * | ||
178 | *==========================================================================*/ | ||
179 | void smp_flush_cache_all(void) | ||
180 | { | ||
181 | cpumask_t cpumask; | ||
182 | unsigned long *mask; | ||
183 | |||
184 | preempt_disable(); | ||
185 | cpumask = cpu_online_map; | ||
186 | cpu_clear(smp_processor_id(), cpumask); | ||
187 | spin_lock(&flushcache_lock); | ||
188 | mask=cpus_addr(cpumask); | ||
189 | atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask); | ||
190 | send_IPI_mask(cpumask, INVALIDATE_CACHE_IPI, 0); | ||
191 | _flush_cache_copyback_all(); | ||
192 | while (flushcache_cpumask) | ||
193 | mb(); | ||
194 | spin_unlock(&flushcache_lock); | ||
195 | preempt_enable(); | ||
196 | } | ||
197 | |||
198 | void smp_flush_cache_all_interrupt(void) | ||
199 | { | ||
200 | _flush_cache_copyback_all(); | ||
201 | clear_bit(smp_processor_id(), &flushcache_cpumask); | ||
202 | } | ||
203 | |||
204 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
205 | /* TLB flush request Routins */ | ||
206 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
207 | |||
208 | /*==========================================================================* | ||
209 | * Name: smp_flush_tlb_all | ||
210 | * | ||
211 | * Description: This routine flushes all processes TLBs. | ||
212 | * 1.Request other CPU to execute 'flush_tlb_all_ipi()'. | ||
213 | * 2.Execute 'do_flush_tlb_all_local()'. | ||
214 | * | ||
215 | * Born on Date: 2002.02.05 | ||
216 | * | ||
217 | * Arguments: NONE | ||
218 | * | ||
219 | * Returns: void (cannot fail) | ||
220 | * | ||
221 | * Modification log: | ||
222 | * Date Who Description | ||
223 | * ---------- --- -------------------------------------------------------- | ||
224 | * | ||
225 | *==========================================================================*/ | ||
226 | void smp_flush_tlb_all(void) | ||
227 | { | ||
228 | unsigned long flags; | ||
229 | |||
230 | preempt_disable(); | ||
231 | local_irq_save(flags); | ||
232 | __flush_tlb_all(); | ||
233 | local_irq_restore(flags); | ||
234 | smp_call_function(flush_tlb_all_ipi, 0, 1, 1); | ||
235 | preempt_enable(); | ||
236 | } | ||
237 | |||
238 | /*==========================================================================* | ||
239 | * Name: flush_tlb_all_ipi | ||
240 | * | ||
241 | * Description: This routine flushes all local TLBs. | ||
242 | * 1.Execute 'do_flush_tlb_all_local()'. | ||
243 | * | ||
244 | * Born on Date: 2002.02.05 | ||
245 | * | ||
246 | * Arguments: *info - not used | ||
247 | * | ||
248 | * Returns: void (cannot fail) | ||
249 | * | ||
250 | * Modification log: | ||
251 | * Date Who Description | ||
252 | * ---------- --- -------------------------------------------------------- | ||
253 | * | ||
254 | *==========================================================================*/ | ||
255 | static void flush_tlb_all_ipi(void *info) | ||
256 | { | ||
257 | __flush_tlb_all(); | ||
258 | } | ||
259 | |||
260 | /*==========================================================================* | ||
261 | * Name: smp_flush_tlb_mm | ||
262 | * | ||
263 | * Description: This routine flushes the specified mm context TLB's. | ||
264 | * | ||
265 | * Born on Date: 2002.02.05 | ||
266 | * | ||
267 | * Arguments: *mm - a pointer to the mm struct for flush TLB | ||
268 | * | ||
269 | * Returns: void (cannot fail) | ||
270 | * | ||
271 | * Modification log: | ||
272 | * Date Who Description | ||
273 | * ---------- --- -------------------------------------------------------- | ||
274 | * | ||
275 | *==========================================================================*/ | ||
276 | void smp_flush_tlb_mm(struct mm_struct *mm) | ||
277 | { | ||
278 | int cpu_id = smp_processor_id(); | ||
279 | cpumask_t cpu_mask; | ||
280 | unsigned long *mmc = &mm->context[cpu_id]; | ||
281 | unsigned long flags; | ||
282 | |||
283 | preempt_disable(); | ||
284 | cpu_mask = mm->cpu_vm_mask; | ||
285 | cpu_clear(cpu_id, cpu_mask); | ||
286 | |||
287 | if (*mmc != NO_CONTEXT) { | ||
288 | local_irq_save(flags); | ||
289 | *mmc = NO_CONTEXT; | ||
290 | if (mm == current->mm) | ||
291 | activate_context(mm); | ||
292 | else | ||
293 | cpu_clear(cpu_id, mm->cpu_vm_mask); | ||
294 | local_irq_restore(flags); | ||
295 | } | ||
296 | if (!cpus_empty(cpu_mask)) | ||
297 | flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL); | ||
298 | |||
299 | preempt_enable(); | ||
300 | } | ||
301 | |||
302 | /*==========================================================================* | ||
303 | * Name: smp_flush_tlb_range | ||
304 | * | ||
305 | * Description: This routine flushes a range of pages. | ||
306 | * | ||
307 | * Born on Date: 2002.02.05 | ||
308 | * | ||
309 | * Arguments: *mm - a pointer to the mm struct for flush TLB | ||
310 | * start - not used | ||
311 | * end - not used | ||
312 | * | ||
313 | * Returns: void (cannot fail) | ||
314 | * | ||
315 | * Modification log: | ||
316 | * Date Who Description | ||
317 | * ---------- --- -------------------------------------------------------- | ||
318 | * | ||
319 | *==========================================================================*/ | ||
320 | void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | ||
321 | unsigned long end) | ||
322 | { | ||
323 | smp_flush_tlb_mm(vma->vm_mm); | ||
324 | } | ||
325 | |||
326 | /*==========================================================================* | ||
327 | * Name: smp_flush_tlb_page | ||
328 | * | ||
329 | * Description: This routine flushes one page. | ||
330 | * | ||
331 | * Born on Date: 2002.02.05 | ||
332 | * | ||
333 | * Arguments: *vma - a pointer to the vma struct include va | ||
334 | * va - virtual address for flush TLB | ||
335 | * | ||
336 | * Returns: void (cannot fail) | ||
337 | * | ||
338 | * Modification log: | ||
339 | * Date Who Description | ||
340 | * ---------- --- -------------------------------------------------------- | ||
341 | * | ||
342 | *==========================================================================*/ | ||
343 | void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | ||
344 | { | ||
345 | struct mm_struct *mm = vma->vm_mm; | ||
346 | int cpu_id = smp_processor_id(); | ||
347 | cpumask_t cpu_mask; | ||
348 | unsigned long *mmc = &mm->context[cpu_id]; | ||
349 | unsigned long flags; | ||
350 | |||
351 | preempt_disable(); | ||
352 | cpu_mask = mm->cpu_vm_mask; | ||
353 | cpu_clear(cpu_id, cpu_mask); | ||
354 | |||
355 | #ifdef DEBUG_SMP | ||
356 | if (!mm) | ||
357 | BUG(); | ||
358 | #endif | ||
359 | |||
360 | if (*mmc != NO_CONTEXT) { | ||
361 | local_irq_save(flags); | ||
362 | va &= PAGE_MASK; | ||
363 | va |= (*mmc & MMU_CONTEXT_ASID_MASK); | ||
364 | __flush_tlb_page(va); | ||
365 | local_irq_restore(flags); | ||
366 | } | ||
367 | if (!cpus_empty(cpu_mask)) | ||
368 | flush_tlb_others(cpu_mask, mm, vma, va); | ||
369 | |||
370 | preempt_enable(); | ||
371 | } | ||
372 | |||
373 | /*==========================================================================* | ||
374 | * Name: flush_tlb_others | ||
375 | * | ||
376 | * Description: This routine requests other CPU to execute flush TLB. | ||
377 | * 1.Setup parmeters. | ||
378 | * 2.Send 'INVALIDATE_TLB_IPI' to other CPU. | ||
379 | * Request other CPU to execute 'smp_invalidate_interrupt()'. | ||
380 | * 3.Wait for other CPUs operation finished. | ||
381 | * | ||
382 | * Born on Date: 2002.02.05 | ||
383 | * | ||
384 | * Arguments: cpumask - bitmap of target CPUs | ||
385 | * *mm - a pointer to the mm struct for flush TLB | ||
386 | * *vma - a pointer to the vma struct include va | ||
387 | * va - virtual address for flush TLB | ||
388 | * | ||
389 | * Returns: void (cannot fail) | ||
390 | * | ||
391 | * Modification log: | ||
392 | * Date Who Description | ||
393 | * ---------- --- -------------------------------------------------------- | ||
394 | * | ||
395 | *==========================================================================*/ | ||
396 | static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | ||
397 | struct vm_area_struct *vma, unsigned long va) | ||
398 | { | ||
399 | unsigned long *mask; | ||
400 | #ifdef DEBUG_SMP | ||
401 | unsigned long flags; | ||
402 | __save_flags(flags); | ||
403 | if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ | ||
404 | BUG(); | ||
405 | #endif /* DEBUG_SMP */ | ||
406 | |||
407 | /* | ||
408 | * A couple of (to be removed) sanity checks: | ||
409 | * | ||
410 | * - we do not send IPIs to not-yet booted CPUs. | ||
411 | * - current CPU must not be in mask | ||
412 | * - mask must exist :) | ||
413 | */ | ||
414 | BUG_ON(cpus_empty(cpumask)); | ||
415 | |||
416 | BUG_ON(cpu_isset(smp_processor_id(), cpumask)); | ||
417 | BUG_ON(!mm); | ||
418 | |||
419 | /* If a CPU which we ran on has gone down, OK. */ | ||
420 | cpus_and(cpumask, cpumask, cpu_online_map); | ||
421 | if (cpus_empty(cpumask)) | ||
422 | return; | ||
423 | |||
424 | /* | ||
425 | * i'm not happy about this global shared spinlock in the | ||
426 | * MM hot path, but we'll see how contended it is. | ||
427 | * Temporarily this turns IRQs off, so that lockups are | ||
428 | * detected by the NMI watchdog. | ||
429 | */ | ||
430 | spin_lock(&tlbstate_lock); | ||
431 | |||
432 | flush_mm = mm; | ||
433 | flush_vma = vma; | ||
434 | flush_va = va; | ||
435 | mask=cpus_addr(cpumask); | ||
436 | atomic_set_mask(*mask, (atomic_t *)&flush_cpumask); | ||
437 | |||
438 | /* | ||
439 | * We have to send the IPI only to | ||
440 | * CPUs affected. | ||
441 | */ | ||
442 | send_IPI_mask(cpumask, INVALIDATE_TLB_IPI, 0); | ||
443 | |||
444 | while (!cpus_empty(flush_cpumask)) { | ||
445 | /* nothing. lockup detection does not belong here */ | ||
446 | mb(); | ||
447 | } | ||
448 | |||
449 | flush_mm = NULL; | ||
450 | flush_vma = NULL; | ||
451 | flush_va = 0; | ||
452 | spin_unlock(&tlbstate_lock); | ||
453 | } | ||
454 | |||
455 | /*==========================================================================* | ||
456 | * Name: smp_invalidate_interrupt | ||
457 | * | ||
458 | * Description: This routine executes on CPU which received | ||
459 | * 'INVALIDATE_TLB_IPI'. | ||
460 | * 1.Flush local TLB. | ||
461 | * 2.Report flush TLB process was finished. | ||
462 | * | ||
463 | * Born on Date: 2002.02.05 | ||
464 | * | ||
465 | * Arguments: NONE | ||
466 | * | ||
467 | * Returns: void (cannot fail) | ||
468 | * | ||
469 | * Modification log: | ||
470 | * Date Who Description | ||
471 | * ---------- --- -------------------------------------------------------- | ||
472 | * | ||
473 | *==========================================================================*/ | ||
474 | void smp_invalidate_interrupt(void) | ||
475 | { | ||
476 | int cpu_id = smp_processor_id(); | ||
477 | unsigned long *mmc = &flush_mm->context[cpu_id]; | ||
478 | |||
479 | if (!cpu_isset(cpu_id, flush_cpumask)) | ||
480 | return; | ||
481 | |||
482 | if (flush_va == FLUSH_ALL) { | ||
483 | *mmc = NO_CONTEXT; | ||
484 | if (flush_mm == current->active_mm) | ||
485 | activate_context(flush_mm); | ||
486 | else | ||
487 | cpu_clear(cpu_id, flush_mm->cpu_vm_mask); | ||
488 | } else { | ||
489 | unsigned long va = flush_va; | ||
490 | |||
491 | if (*mmc != NO_CONTEXT) { | ||
492 | va &= PAGE_MASK; | ||
493 | va |= (*mmc & MMU_CONTEXT_ASID_MASK); | ||
494 | __flush_tlb_page(va); | ||
495 | } | ||
496 | } | ||
497 | cpu_clear(cpu_id, flush_cpumask); | ||
498 | } | ||
499 | |||
500 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
501 | /* Stop CPU request Routins */ | ||
502 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
503 | |||
504 | /*==========================================================================* | ||
505 | * Name: smp_send_stop | ||
506 | * | ||
507 | * Description: This routine requests stop all CPUs. | ||
508 | * 1.Request other CPU to execute 'stop_this_cpu()'. | ||
509 | * | ||
510 | * Born on Date: 2002.02.05 | ||
511 | * | ||
512 | * Arguments: NONE | ||
513 | * | ||
514 | * Returns: void (cannot fail) | ||
515 | * | ||
516 | * Modification log: | ||
517 | * Date Who Description | ||
518 | * ---------- --- -------------------------------------------------------- | ||
519 | * | ||
520 | *==========================================================================*/ | ||
521 | void smp_send_stop(void) | ||
522 | { | ||
523 | smp_call_function(stop_this_cpu, NULL, 1, 0); | ||
524 | } | ||
525 | |||
526 | /*==========================================================================* | ||
527 | * Name: stop_this_cpu | ||
528 | * | ||
529 | * Description: This routine halt CPU. | ||
530 | * | ||
531 | * Born on Date: 2002.02.05 | ||
532 | * | ||
533 | * Arguments: NONE | ||
534 | * | ||
535 | * Returns: void (cannot fail) | ||
536 | * | ||
537 | * Modification log: | ||
538 | * Date Who Description | ||
539 | * ---------- --- -------------------------------------------------------- | ||
540 | * | ||
541 | *==========================================================================*/ | ||
542 | static void stop_this_cpu(void *dummy) | ||
543 | { | ||
544 | int cpu_id = smp_processor_id(); | ||
545 | |||
546 | /* | ||
547 | * Remove this CPU: | ||
548 | */ | ||
549 | cpu_clear(cpu_id, cpu_online_map); | ||
550 | |||
551 | /* | ||
552 | * PSW IE = 1; | ||
553 | * IMASK = 0; | ||
554 | * goto SLEEP | ||
555 | */ | ||
556 | local_irq_disable(); | ||
557 | outl(0, M32R_ICU_IMASK_PORTL); | ||
558 | inl(M32R_ICU_IMASK_PORTL); /* dummy read */ | ||
559 | local_irq_enable(); | ||
560 | |||
561 | for ( ; ; ); | ||
562 | } | ||
563 | |||
564 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
565 | /* Call function Routins */ | ||
566 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
567 | |||
568 | /*==========================================================================* | ||
569 | * Name: smp_call_function | ||
570 | * | ||
571 | * Description: This routine sends a 'CALL_FUNCTION_IPI' to all other CPUs | ||
572 | * in the system. | ||
573 | * | ||
574 | * Born on Date: 2002.02.05 | ||
575 | * | ||
576 | * Arguments: *func - The function to run. This must be fast and | ||
577 | * non-blocking. | ||
578 | * *info - An arbitrary pointer to pass to the function. | ||
579 | * nonatomic - currently unused. | ||
580 | * wait - If true, wait (atomically) until function has | ||
581 | * completed on other CPUs. | ||
582 | * | ||
583 | * Returns: 0 on success, else a negative status code. Does not return | ||
584 | * until remote CPUs are nearly ready to execute <<func>> or | ||
585 | * are or have executed. | ||
586 | * | ||
587 | * Cautions: You must not call this function with disabled interrupts or | ||
588 | * from a hardware interrupt handler, you may call it from a | ||
589 | * bottom half handler. | ||
590 | * | ||
591 | * Modification log: | ||
592 | * Date Who Description | ||
593 | * ---------- --- -------------------------------------------------------- | ||
594 | * | ||
595 | *==========================================================================*/ | ||
596 | int smp_call_function(void (*func) (void *info), void *info, int nonatomic, | ||
597 | int wait) | ||
598 | { | ||
599 | struct call_data_struct data; | ||
600 | int cpus; | ||
601 | |||
602 | #ifdef DEBUG_SMP | ||
603 | unsigned long flags; | ||
604 | __save_flags(flags); | ||
605 | if (!(flags & 0x0040)) /* Interrupt Disable NONONO */ | ||
606 | BUG(); | ||
607 | #endif /* DEBUG_SMP */ | ||
608 | |||
609 | /* Holding any lock stops cpus from going down. */ | ||
610 | spin_lock(&call_lock); | ||
611 | cpus = num_online_cpus() - 1; | ||
612 | |||
613 | if (!cpus) { | ||
614 | spin_unlock(&call_lock); | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | /* Can deadlock when called with interrupts disabled */ | ||
619 | WARN_ON(irqs_disabled()); | ||
620 | |||
621 | data.func = func; | ||
622 | data.info = info; | ||
623 | atomic_set(&data.started, 0); | ||
624 | data.wait = wait; | ||
625 | if (wait) | ||
626 | atomic_set(&data.finished, 0); | ||
627 | |||
628 | call_data = &data; | ||
629 | mb(); | ||
630 | |||
631 | /* Send a message to all other CPUs and wait for them to respond */ | ||
632 | send_IPI_allbutself(CALL_FUNCTION_IPI, 0); | ||
633 | |||
634 | /* Wait for response */ | ||
635 | while (atomic_read(&data.started) != cpus) | ||
636 | barrier(); | ||
637 | |||
638 | if (wait) | ||
639 | while (atomic_read(&data.finished) != cpus) | ||
640 | barrier(); | ||
641 | spin_unlock(&call_lock); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | /*==========================================================================* | ||
647 | * Name: smp_call_function_interrupt | ||
648 | * | ||
649 | * Description: This routine executes on CPU which received | ||
650 | * 'CALL_FUNCTION_IPI'. | ||
651 | * | ||
652 | * Born on Date: 2002.02.05 | ||
653 | * | ||
654 | * Arguments: NONE | ||
655 | * | ||
656 | * Returns: void (cannot fail) | ||
657 | * | ||
658 | * Modification log: | ||
659 | * Date Who Description | ||
660 | * ---------- --- -------------------------------------------------------- | ||
661 | * | ||
662 | *==========================================================================*/ | ||
663 | void smp_call_function_interrupt(void) | ||
664 | { | ||
665 | void (*func) (void *info) = call_data->func; | ||
666 | void *info = call_data->info; | ||
667 | int wait = call_data->wait; | ||
668 | |||
669 | /* | ||
670 | * Notify initiating CPU that I've grabbed the data and am | ||
671 | * about to execute the function | ||
672 | */ | ||
673 | mb(); | ||
674 | atomic_inc(&call_data->started); | ||
675 | /* | ||
676 | * At this point the info structure may be out of scope unless wait==1 | ||
677 | */ | ||
678 | irq_enter(); | ||
679 | (*func)(info); | ||
680 | irq_exit(); | ||
681 | |||
682 | if (wait) { | ||
683 | mb(); | ||
684 | atomic_inc(&call_data->finished); | ||
685 | } | ||
686 | } | ||
687 | |||
688 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
689 | /* Timer Routins */ | ||
690 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
691 | |||
692 | /*==========================================================================* | ||
693 | * Name: smp_send_timer | ||
694 | * | ||
695 | * Description: This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs | ||
696 | * in the system. | ||
697 | * | ||
698 | * Born on Date: 2002.02.05 | ||
699 | * | ||
700 | * Arguments: NONE | ||
701 | * | ||
702 | * Returns: void (cannot fail) | ||
703 | * | ||
704 | * Modification log: | ||
705 | * Date Who Description | ||
706 | * ---------- --- -------------------------------------------------------- | ||
707 | * | ||
708 | *==========================================================================*/ | ||
709 | void smp_send_timer(void) | ||
710 | { | ||
711 | send_IPI_allbutself(LOCAL_TIMER_IPI, 1); | ||
712 | } | ||
713 | |||
714 | /*==========================================================================* | ||
715 | * Name: smp_send_timer | ||
716 | * | ||
717 | * Description: This routine executes on CPU which received | ||
718 | * 'LOCAL_TIMER_IPI'. | ||
719 | * | ||
720 | * Born on Date: 2002.02.05 | ||
721 | * | ||
722 | * Arguments: *regs - a pointer to the saved regster info | ||
723 | * | ||
724 | * Returns: void (cannot fail) | ||
725 | * | ||
726 | * Modification log: | ||
727 | * Date Who Description | ||
728 | * ---------- --- -------------------------------------------------------- | ||
729 | * | ||
730 | *==========================================================================*/ | ||
731 | void smp_ipi_timer_interrupt(struct pt_regs *regs) | ||
732 | { | ||
733 | irq_enter(); | ||
734 | smp_local_timer_interrupt(regs); | ||
735 | irq_exit(); | ||
736 | } | ||
737 | |||
738 | /*==========================================================================* | ||
739 | * Name: smp_local_timer_interrupt | ||
740 | * | ||
741 | * Description: Local timer interrupt handler. It does both profiling and | ||
742 | * process statistics/rescheduling. | ||
743 | * We do profiling in every local tick, statistics/rescheduling | ||
744 | * happen only every 'profiling multiplier' ticks. The default | ||
745 | * multiplier is 1 and it can be changed by writing the new | ||
746 | * multiplier value into /proc/profile. | ||
747 | * | ||
748 | * Born on Date: 2002.02.05 | ||
749 | * | ||
750 | * Arguments: *regs - a pointer to the saved regster info | ||
751 | * | ||
752 | * Returns: void (cannot fail) | ||
753 | * | ||
754 | * Original: arch/i386/kernel/apic.c | ||
755 | * | ||
756 | * Modification log: | ||
757 | * Date Who Description | ||
758 | * ---------- --- -------------------------------------------------------- | ||
759 | * 2003-06-24 hy use per_cpu structure. | ||
760 | *==========================================================================*/ | ||
761 | void smp_local_timer_interrupt(struct pt_regs *regs) | ||
762 | { | ||
763 | int user = user_mode(regs); | ||
764 | int cpu_id = smp_processor_id(); | ||
765 | |||
766 | /* | ||
767 | * The profiling function is SMP safe. (nothing can mess | ||
768 | * around with "current", and the profiling counters are | ||
769 | * updated with atomic operations). This is especially | ||
770 | * useful with a profiling multiplier != 1 | ||
771 | */ | ||
772 | |||
773 | profile_tick(CPU_PROFILING, regs); | ||
774 | |||
775 | if (--per_cpu(prof_counter, cpu_id) <= 0) { | ||
776 | /* | ||
777 | * The multiplier may have changed since the last time we got | ||
778 | * to this point as a result of the user writing to | ||
779 | * /proc/profile. In this case we need to adjust the APIC | ||
780 | * timer accordingly. | ||
781 | * | ||
782 | * Interrupts are already masked off at this point. | ||
783 | */ | ||
784 | per_cpu(prof_counter, cpu_id) | ||
785 | = per_cpu(prof_multiplier, cpu_id); | ||
786 | if (per_cpu(prof_counter, cpu_id) | ||
787 | != per_cpu(prof_old_multiplier, cpu_id)) | ||
788 | { | ||
789 | per_cpu(prof_old_multiplier, cpu_id) | ||
790 | = per_cpu(prof_counter, cpu_id); | ||
791 | } | ||
792 | |||
793 | update_process_times(user); | ||
794 | } | ||
795 | } | ||
796 | |||
797 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
798 | /* Send IPI Routins */ | ||
799 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
800 | |||
801 | /*==========================================================================* | ||
802 | * Name: send_IPI_allbutself | ||
803 | * | ||
804 | * Description: This routine sends a IPI to all other CPUs in the system. | ||
805 | * | ||
806 | * Born on Date: 2002.02.05 | ||
807 | * | ||
808 | * Arguments: ipi_num - Number of IPI | ||
809 | * try - 0 : Send IPI certainly. | ||
810 | * !0 : The following IPI is not sended when Target CPU | ||
811 | * has not received the before IPI. | ||
812 | * | ||
813 | * Returns: void (cannot fail) | ||
814 | * | ||
815 | * Modification log: | ||
816 | * Date Who Description | ||
817 | * ---------- --- -------------------------------------------------------- | ||
818 | * | ||
819 | *==========================================================================*/ | ||
820 | void send_IPI_allbutself(int ipi_num, int try) | ||
821 | { | ||
822 | cpumask_t cpumask; | ||
823 | |||
824 | cpumask = cpu_online_map; | ||
825 | cpu_clear(smp_processor_id(), cpumask); | ||
826 | |||
827 | send_IPI_mask(cpumask, ipi_num, try); | ||
828 | } | ||
829 | |||
830 | /*==========================================================================* | ||
831 | * Name: send_IPI_mask | ||
832 | * | ||
833 | * Description: This routine sends a IPI to CPUs in the system. | ||
834 | * | ||
835 | * Born on Date: 2002.02.05 | ||
836 | * | ||
837 | * Arguments: cpu_mask - Bitmap of target CPUs logical ID | ||
838 | * ipi_num - Number of IPI | ||
839 | * try - 0 : Send IPI certainly. | ||
840 | * !0 : The following IPI is not sended when Target CPU | ||
841 | * has not received the before IPI. | ||
842 | * | ||
843 | * Returns: void (cannot fail) | ||
844 | * | ||
845 | * Modification log: | ||
846 | * Date Who Description | ||
847 | * ---------- --- -------------------------------------------------------- | ||
848 | * | ||
849 | *==========================================================================*/ | ||
850 | static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try) | ||
851 | { | ||
852 | cpumask_t physid_mask, tmp; | ||
853 | int cpu_id, phys_id; | ||
854 | int num_cpus = num_online_cpus(); | ||
855 | |||
856 | if (num_cpus <= 1) /* NO MP */ | ||
857 | return; | ||
858 | |||
859 | cpus_and(tmp, cpumask, cpu_online_map); | ||
860 | BUG_ON(!cpus_equal(cpumask, tmp)); | ||
861 | |||
862 | physid_mask = CPU_MASK_NONE; | ||
863 | for_each_cpu_mask(cpu_id, cpumask){ | ||
864 | if ((phys_id = cpu_to_physid(cpu_id)) != -1) | ||
865 | cpu_set(phys_id, physid_mask); | ||
866 | } | ||
867 | |||
868 | send_IPI_mask_phys(physid_mask, ipi_num, try); | ||
869 | } | ||
870 | |||
871 | /*==========================================================================* | ||
872 | * Name: send_IPI_mask_phys | ||
873 | * | ||
874 | * Description: This routine sends a IPI to other CPUs in the system. | ||
875 | * | ||
876 | * Born on Date: 2002.02.05 | ||
877 | * | ||
878 | * Arguments: cpu_mask - Bitmap of target CPUs physical ID | ||
879 | * ipi_num - Number of IPI | ||
880 | * try - 0 : Send IPI certainly. | ||
881 | * !0 : The following IPI is not sended when Target CPU | ||
882 | * has not received the before IPI. | ||
883 | * | ||
884 | * Returns: IPICRi regster value. | ||
885 | * | ||
886 | * Modification log: | ||
887 | * Date Who Description | ||
888 | * ---------- --- -------------------------------------------------------- | ||
889 | * | ||
890 | *==========================================================================*/ | ||
891 | unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num, | ||
892 | int try) | ||
893 | { | ||
894 | spinlock_t *ipilock; | ||
895 | unsigned long flags = 0; | ||
896 | volatile unsigned long *ipicr_addr; | ||
897 | unsigned long ipicr_val; | ||
898 | unsigned long my_physid_mask; | ||
899 | unsigned long mask = cpus_addr(physid_mask)[0]; | ||
900 | |||
901 | |||
902 | if (mask & ~physids_coerce(phys_cpu_present_map)) | ||
903 | BUG(); | ||
904 | if (ipi_num >= NR_IPIS) | ||
905 | BUG(); | ||
906 | |||
907 | mask <<= IPI_SHIFT; | ||
908 | ipilock = &ipi_lock[ipi_num]; | ||
909 | ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR | ||
910 | + (ipi_num << 2)); | ||
911 | my_physid_mask = ~(1 << smp_processor_id()); | ||
912 | |||
913 | /* | ||
914 | * lock ipi_lock[i] | ||
915 | * check IPICRi == 0 | ||
916 | * write IPICRi (send IPIi) | ||
917 | * unlock ipi_lock[i] | ||
918 | */ | ||
919 | __asm__ __volatile__ ( | ||
920 | ";; LOCK ipi_lock[i] \n\t" | ||
921 | ".fillinsn \n" | ||
922 | "1: \n\t" | ||
923 | "mvfc %1, psw \n\t" | ||
924 | "clrpsw #0x40 -> nop \n\t" | ||
925 | DCACHE_CLEAR("r4", "r5", "%2") | ||
926 | "lock r4, @%2 \n\t" | ||
927 | "addi r4, #-1 \n\t" | ||
928 | "unlock r4, @%2 \n\t" | ||
929 | "mvtc %1, psw \n\t" | ||
930 | "bnez r4, 2f \n\t" | ||
931 | LOCK_SECTION_START(".balign 4 \n\t") | ||
932 | ".fillinsn \n" | ||
933 | "2: \n\t" | ||
934 | "ld r4, @%2 \n\t" | ||
935 | "blez r4, 2b \n\t" | ||
936 | "bra 1b \n\t" | ||
937 | LOCK_SECTION_END | ||
938 | ";; CHECK IPICRi == 0 \n\t" | ||
939 | ".fillinsn \n" | ||
940 | "3: \n\t" | ||
941 | "ld %0, @%3 \n\t" | ||
942 | "and %0, %6 \n\t" | ||
943 | "beqz %0, 4f \n\t" | ||
944 | "bnez %5, 5f \n\t" | ||
945 | "bra 3b \n\t" | ||
946 | ";; WRITE IPICRi (send IPIi) \n\t" | ||
947 | ".fillinsn \n" | ||
948 | "4: \n\t" | ||
949 | "st %4, @%3 \n\t" | ||
950 | ";; UNLOCK ipi_lock[i] \n\t" | ||
951 | ".fillinsn \n" | ||
952 | "5: \n\t" | ||
953 | "ldi r4, #1 \n\t" | ||
954 | "st r4, @%2 \n\t" | ||
955 | : "=&r"(ipicr_val) | ||
956 | : "r"(flags), "r"(&ipilock->slock), "r"(ipicr_addr), | ||
957 | "r"(mask), "r"(try), "r"(my_physid_mask) | ||
958 | : "memory", "r4" | ||
959 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
960 | , "r5" | ||
961 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
962 | ); | ||
963 | |||
964 | return ipicr_val; | ||
965 | } | ||
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c new file mode 100644 index 000000000000..f9a0e723478d --- /dev/null +++ b/arch/m32r/kernel/smpboot.c | |||
@@ -0,0 +1,630 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/smpboot.c | ||
3 | * orig : i386 2.4.10 | ||
4 | * | ||
5 | * M32R SMP booting functions | ||
6 | * | ||
7 | * Copyright (c) 2001, 2002, 2003 Hitoshi Yamamoto | ||
8 | * | ||
9 | * Taken from i386 version. | ||
10 | * (c) 1995 Alan Cox, Building #3 <alan@redhat.com> | ||
11 | * (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com> | ||
12 | * | ||
13 | * Much of the core SMP work is based on previous work by Thomas Radke, to | ||
14 | * whom a great many thanks are extended. | ||
15 | * | ||
16 | * Thanks to Intel for making available several different Pentium, | ||
17 | * Pentium Pro and Pentium-II/Xeon MP machines. | ||
18 | * Original development of Linux SMP code supported by Caldera. | ||
19 | * | ||
20 | * This code is released under the GNU General Public License version 2 or | ||
21 | * later. | ||
22 | * | ||
23 | * Fixes | ||
24 | * Felix Koop : NR_CPUS used properly | ||
25 | * Jose Renau : Handle single CPU case. | ||
26 | * Alan Cox : By repeated request | ||
27 | * 8) - Total BogoMIP report. | ||
28 | * Greg Wright : Fix for kernel stacks panic. | ||
29 | * Erich Boleyn : MP v1.4 and additional changes. | ||
30 | * Matthias Sattler : Changes for 2.1 kernel map. | ||
31 | * Michel Lespinasse : Changes for 2.1 kernel map. | ||
32 | * Michael Chastain : Change trampoline.S to gnu as. | ||
33 | * Alan Cox : Dumb bug: 'B' step PPro's are fine | ||
34 | * Ingo Molnar : Added APIC timers, based on code | ||
35 | * from Jose Renau | ||
36 | * Ingo Molnar : various cleanups and rewrites | ||
37 | * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. | ||
38 | * Maciej W. Rozycki : Bits for genuine 82489DX APICs | ||
39 | * Martin J. Bligh : Added support for multi-quad systems | ||
40 | */ | ||
41 | |||
42 | #include <linux/config.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/mm.h> | ||
45 | #include <linux/smp_lock.h> | ||
46 | #include <linux/irq.h> | ||
47 | #include <linux/bootmem.h> | ||
48 | #include <linux/delay.h> | ||
49 | |||
50 | #include <asm/io.h> | ||
51 | #include <asm/pgalloc.h> | ||
52 | #include <asm/tlbflush.h> | ||
53 | |||
54 | #define DEBUG_SMP | ||
55 | #ifdef DEBUG_SMP | ||
56 | #define Dprintk(x...) printk(x) | ||
57 | #else | ||
58 | #define Dprintk(x...) | ||
59 | #endif | ||
60 | |||
61 | extern cpumask_t cpu_initialized; | ||
62 | |||
63 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
64 | /* Data structures and variables */ | ||
65 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
66 | |||
67 | /* Processor that is doing the boot up */ | ||
68 | static unsigned int bsp_phys_id = -1; | ||
69 | |||
70 | /* Bitmask of physically existing CPUs */ | ||
71 | physid_mask_t phys_cpu_present_map; | ||
72 | |||
73 | /* Bitmask of currently online CPUs */ | ||
74 | cpumask_t cpu_online_map; | ||
75 | |||
76 | cpumask_t cpu_bootout_map; | ||
77 | cpumask_t cpu_bootin_map; | ||
78 | cpumask_t cpu_callout_map; | ||
79 | static cpumask_t cpu_callin_map; | ||
80 | |||
81 | /* Per CPU bogomips and other parameters */ | ||
82 | struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; | ||
83 | |||
84 | static int cpucount; | ||
85 | static cpumask_t smp_commenced_mask; | ||
86 | |||
87 | extern struct { | ||
88 | void * spi; | ||
89 | unsigned short ss; | ||
90 | } stack_start; | ||
91 | |||
92 | /* which physical physical ID maps to which logical CPU number */ | ||
93 | static volatile int physid_2_cpu[NR_CPUS]; | ||
94 | |||
95 | /* which logical CPU number maps to which physical ID */ | ||
96 | volatile int cpu_2_physid[NR_CPUS]; | ||
97 | |||
98 | DEFINE_PER_CPU(int, prof_multiplier) = 1; | ||
99 | DEFINE_PER_CPU(int, prof_old_multiplier) = 1; | ||
100 | DEFINE_PER_CPU(int, prof_counter) = 1; | ||
101 | |||
102 | spinlock_t ipi_lock[NR_IPIS]; | ||
103 | |||
104 | static unsigned int calibration_result; | ||
105 | |||
106 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
107 | /* Function Prototypes */ | ||
108 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
109 | |||
110 | void smp_prepare_boot_cpu(void); | ||
111 | void smp_prepare_cpus(unsigned int); | ||
112 | static void smp_tune_scheduling(void); | ||
113 | static void init_ipi_lock(void); | ||
114 | static void do_boot_cpu(int); | ||
115 | int __cpu_up(unsigned int); | ||
116 | void smp_cpus_done(unsigned int); | ||
117 | |||
118 | int start_secondary(void *); | ||
119 | static void smp_callin(void); | ||
120 | static void smp_online(void); | ||
121 | |||
122 | static void show_mp_info(int); | ||
123 | static void smp_store_cpu_info(int); | ||
124 | static void show_cpu_info(int); | ||
125 | int setup_profiling_timer(unsigned int); | ||
126 | static void init_cpu_to_physid(void); | ||
127 | static void map_cpu_to_physid(int, int); | ||
128 | static void unmap_cpu_to_physid(int, int); | ||
129 | |||
130 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
131 | /* Boot up APs Routins : BSP */ | ||
132 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
133 | void __devinit smp_prepare_boot_cpu(void) | ||
134 | { | ||
135 | bsp_phys_id = hard_smp_processor_id(); | ||
136 | physid_set(bsp_phys_id, phys_cpu_present_map); | ||
137 | cpu_set(0, cpu_online_map); /* BSP's cpu_id == 0 */ | ||
138 | cpu_set(0, cpu_callout_map); | ||
139 | cpu_set(0, cpu_callin_map); | ||
140 | |||
141 | /* | ||
142 | * Initialize the logical to physical CPU number mapping | ||
143 | */ | ||
144 | init_cpu_to_physid(); | ||
145 | map_cpu_to_physid(0, bsp_phys_id); | ||
146 | current_thread_info()->cpu = 0; | ||
147 | } | ||
148 | |||
149 | /*==========================================================================* | ||
150 | * Name: smp_prepare_cpus (old smp_boot_cpus) | ||
151 | * | ||
152 | * Description: This routine boot up APs. | ||
153 | * | ||
154 | * Born on Date: 2002.02.05 | ||
155 | * | ||
156 | * Arguments: NONE | ||
157 | * | ||
158 | * Returns: void (cannot fail) | ||
159 | * | ||
160 | * Modification log: | ||
161 | * Date Who Description | ||
162 | * ---------- --- -------------------------------------------------------- | ||
163 | * 2003-06-24 hy modify for linux-2.5.69 | ||
164 | * | ||
165 | *==========================================================================*/ | ||
166 | void __init smp_prepare_cpus(unsigned int max_cpus) | ||
167 | { | ||
168 | int phys_id; | ||
169 | unsigned long nr_cpu; | ||
170 | |||
171 | nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL); | ||
172 | if (nr_cpu > NR_CPUS) { | ||
173 | printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]", | ||
174 | nr_cpu, NR_CPUS); | ||
175 | goto smp_done; | ||
176 | } | ||
177 | for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) | ||
178 | physid_set(phys_id, phys_cpu_present_map); | ||
179 | |||
180 | show_mp_info(nr_cpu); | ||
181 | |||
182 | init_ipi_lock(); | ||
183 | |||
184 | /* | ||
185 | * Setup boot CPU information | ||
186 | */ | ||
187 | smp_store_cpu_info(0); /* Final full version of the data */ | ||
188 | smp_tune_scheduling(); | ||
189 | |||
190 | /* | ||
191 | * If SMP should be disabled, then really disable it! | ||
192 | */ | ||
193 | if (!max_cpus) { | ||
194 | printk(KERN_INFO "SMP mode deactivated by commandline.\n"); | ||
195 | goto smp_done; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Now scan the CPU present map and fire up the other CPUs. | ||
200 | */ | ||
201 | Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map)); | ||
202 | |||
203 | for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) { | ||
204 | /* | ||
205 | * Don't even attempt to start the boot CPU! | ||
206 | */ | ||
207 | if (phys_id == bsp_phys_id) | ||
208 | continue; | ||
209 | |||
210 | if (!physid_isset(phys_id, phys_cpu_present_map)) | ||
211 | continue; | ||
212 | |||
213 | if ((max_cpus >= 0) && (max_cpus <= cpucount + 1)) | ||
214 | continue; | ||
215 | |||
216 | do_boot_cpu(phys_id); | ||
217 | |||
218 | /* | ||
219 | * Make sure we unmap all failed CPUs | ||
220 | */ | ||
221 | if (physid_to_cpu(phys_id) == -1) { | ||
222 | physid_clear(phys_id, phys_cpu_present_map); | ||
223 | printk("phys CPU#%d not responding - " \ | ||
224 | "cannot use it.\n", phys_id); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | smp_done: | ||
229 | Dprintk("Boot done.\n"); | ||
230 | } | ||
231 | |||
232 | static void __init smp_tune_scheduling(void) | ||
233 | { | ||
234 | /* Nothing to do. */ | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * init_ipi_lock : Initialize IPI locks. | ||
239 | */ | ||
240 | static void __init init_ipi_lock(void) | ||
241 | { | ||
242 | int ipi; | ||
243 | |||
244 | for (ipi = 0 ; ipi < NR_IPIS ; ipi++) | ||
245 | spin_lock_init(&ipi_lock[ipi]); | ||
246 | } | ||
247 | |||
248 | /*==========================================================================* | ||
249 | * Name: do_boot_cpu | ||
250 | * | ||
251 | * Description: This routine boot up one AP. | ||
252 | * | ||
253 | * Born on Date: 2002.02.05 | ||
254 | * | ||
255 | * Arguments: phys_id - Target CPU physical ID | ||
256 | * | ||
257 | * Returns: void (cannot fail) | ||
258 | * | ||
259 | * Modification log: | ||
260 | * Date Who Description | ||
261 | * ---------- --- -------------------------------------------------------- | ||
262 | * 2003-06-24 hy modify for linux-2.5.69 | ||
263 | * | ||
264 | *==========================================================================*/ | ||
265 | static void __init do_boot_cpu(int phys_id) | ||
266 | { | ||
267 | struct task_struct *idle; | ||
268 | unsigned long send_status, boot_status; | ||
269 | int timeout, cpu_id; | ||
270 | |||
271 | cpu_id = ++cpucount; | ||
272 | |||
273 | /* | ||
274 | * We can't use kernel_thread since we must avoid to | ||
275 | * reschedule the child. | ||
276 | */ | ||
277 | idle = fork_idle(cpu_id); | ||
278 | if (IS_ERR(idle)) | ||
279 | panic("failed fork for CPU#%d.", cpu_id); | ||
280 | |||
281 | idle->thread.lr = (unsigned long)start_secondary; | ||
282 | |||
283 | map_cpu_to_physid(cpu_id, phys_id); | ||
284 | |||
285 | /* So we see what's up */ | ||
286 | printk("Booting processor %d/%d\n", phys_id, cpu_id); | ||
287 | stack_start.spi = (void *)idle->thread.sp; | ||
288 | idle->thread_info->cpu = cpu_id; | ||
289 | |||
290 | /* | ||
291 | * Send Startup IPI | ||
292 | * 1.IPI received by CPU#(phys_id). | ||
293 | * 2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S) | ||
294 | * 3.CPU#(phys_id) enter start_secondary() | ||
295 | */ | ||
296 | send_status = 0; | ||
297 | boot_status = 0; | ||
298 | |||
299 | cpu_set(phys_id, cpu_bootout_map); | ||
300 | |||
301 | /* Send Startup IPI */ | ||
302 | send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0); | ||
303 | |||
304 | Dprintk("Waiting for send to finish...\n"); | ||
305 | timeout = 0; | ||
306 | |||
307 | /* Wait 100[ms] */ | ||
308 | do { | ||
309 | Dprintk("+"); | ||
310 | udelay(1000); | ||
311 | send_status = !cpu_isset(phys_id, cpu_bootin_map); | ||
312 | } while (send_status && (timeout++ < 100)); | ||
313 | |||
314 | Dprintk("After Startup.\n"); | ||
315 | |||
316 | if (!send_status) { | ||
317 | /* | ||
318 | * allow APs to start initializing. | ||
319 | */ | ||
320 | Dprintk("Before Callout %d.\n", cpu_id); | ||
321 | cpu_set(cpu_id, cpu_callout_map); | ||
322 | Dprintk("After Callout %d.\n", cpu_id); | ||
323 | |||
324 | /* | ||
325 | * Wait 5s total for a response | ||
326 | */ | ||
327 | for (timeout = 0; timeout < 5000; timeout++) { | ||
328 | if (cpu_isset(cpu_id, cpu_callin_map)) | ||
329 | break; /* It has booted */ | ||
330 | udelay(1000); | ||
331 | } | ||
332 | |||
333 | if (cpu_isset(cpu_id, cpu_callin_map)) { | ||
334 | /* number CPUs logically, starting from 1 (BSP is 0) */ | ||
335 | Dprintk("OK.\n"); | ||
336 | } else { | ||
337 | boot_status = 1; | ||
338 | printk("Not responding.\n"); | ||
339 | } | ||
340 | } else | ||
341 | printk("IPI never delivered???\n"); | ||
342 | |||
343 | if (send_status || boot_status) { | ||
344 | unmap_cpu_to_physid(cpu_id, phys_id); | ||
345 | cpu_clear(cpu_id, cpu_callout_map); | ||
346 | cpu_clear(cpu_id, cpu_callin_map); | ||
347 | cpu_clear(cpu_id, cpu_initialized); | ||
348 | cpucount--; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | int __devinit __cpu_up(unsigned int cpu_id) | ||
353 | { | ||
354 | int timeout; | ||
355 | |||
356 | cpu_set(cpu_id, smp_commenced_mask); | ||
357 | |||
358 | /* | ||
359 | * Wait 5s total for a response | ||
360 | */ | ||
361 | for (timeout = 0; timeout < 5000; timeout++) { | ||
362 | if (cpu_isset(cpu_id, cpu_online_map)) | ||
363 | break; | ||
364 | udelay(1000); | ||
365 | } | ||
366 | if (!cpu_isset(cpu_id, cpu_online_map)) | ||
367 | BUG(); | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | void __init smp_cpus_done(unsigned int max_cpus) | ||
373 | { | ||
374 | int cpu_id, timeout; | ||
375 | unsigned long bogosum = 0; | ||
376 | |||
377 | for (timeout = 0; timeout < 5000; timeout++) { | ||
378 | if (cpus_equal(cpu_callin_map, cpu_online_map)) | ||
379 | break; | ||
380 | udelay(1000); | ||
381 | } | ||
382 | if (!cpus_equal(cpu_callin_map, cpu_online_map)) | ||
383 | BUG(); | ||
384 | |||
385 | for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++) | ||
386 | show_cpu_info(cpu_id); | ||
387 | |||
388 | /* | ||
389 | * Allow the user to impress friends. | ||
390 | */ | ||
391 | Dprintk("Before bogomips.\n"); | ||
392 | if (cpucount) { | ||
393 | for_each_cpu_mask(cpu_id, cpu_online_map) | ||
394 | bogosum += cpu_data[cpu_id].loops_per_jiffy; | ||
395 | |||
396 | printk(KERN_INFO "Total of %d processors activated " \ | ||
397 | "(%lu.%02lu BogoMIPS).\n", cpucount + 1, | ||
398 | bogosum / (500000 / HZ), | ||
399 | (bogosum / (5000 / HZ)) % 100); | ||
400 | Dprintk("Before bogocount - setting activated=1.\n"); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
405 | /* Activate a secondary processor Routins */ | ||
406 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
407 | |||
408 | /*==========================================================================* | ||
409 | * Name: start_secondary | ||
410 | * | ||
411 | * Description: This routine activate a secondary processor. | ||
412 | * | ||
413 | * Born on Date: 2002.02.05 | ||
414 | * | ||
415 | * Arguments: *unused - currently unused. | ||
416 | * | ||
417 | * Returns: void (cannot fail) | ||
418 | * | ||
419 | * Modification log: | ||
420 | * Date Who Description | ||
421 | * ---------- --- -------------------------------------------------------- | ||
422 | * 2003-06-24 hy modify for linux-2.5.69 | ||
423 | * | ||
424 | *==========================================================================*/ | ||
425 | int __init start_secondary(void *unused) | ||
426 | { | ||
427 | cpu_init(); | ||
428 | smp_callin(); | ||
429 | while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) | ||
430 | cpu_relax(); | ||
431 | |||
432 | smp_online(); | ||
433 | |||
434 | /* | ||
435 | * low-memory mappings have been cleared, flush them from | ||
436 | * the local TLBs too. | ||
437 | */ | ||
438 | local_flush_tlb_all(); | ||
439 | |||
440 | cpu_idle(); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /*==========================================================================* | ||
445 | * Name: smp_callin | ||
446 | * | ||
447 | * Description: This routine activate a secondary processor. | ||
448 | * | ||
449 | * Born on Date: 2002.02.05 | ||
450 | * | ||
451 | * Arguments: NONE | ||
452 | * | ||
453 | * Returns: void (cannot fail) | ||
454 | * | ||
455 | * Modification log: | ||
456 | * Date Who Description | ||
457 | * ---------- --- -------------------------------------------------------- | ||
458 | * 2003-06-24 hy modify for linux-2.5.69 | ||
459 | * | ||
460 | *==========================================================================*/ | ||
461 | static void __init smp_callin(void) | ||
462 | { | ||
463 | int phys_id = hard_smp_processor_id(); | ||
464 | int cpu_id = smp_processor_id(); | ||
465 | unsigned long timeout; | ||
466 | |||
467 | if (cpu_isset(cpu_id, cpu_callin_map)) { | ||
468 | printk("huh, phys CPU#%d, CPU#%d already present??\n", | ||
469 | phys_id, cpu_id); | ||
470 | BUG(); | ||
471 | } | ||
472 | Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id); | ||
473 | |||
474 | /* Waiting 2s total for startup (udelay is not yet working) */ | ||
475 | timeout = jiffies + (2 * HZ); | ||
476 | while (time_before(jiffies, timeout)) { | ||
477 | /* Has the boot CPU finished it's STARTUP sequence ? */ | ||
478 | if (cpu_isset(cpu_id, cpu_callout_map)) | ||
479 | break; | ||
480 | cpu_relax(); | ||
481 | } | ||
482 | |||
483 | if (!time_before(jiffies, timeout)) { | ||
484 | printk("BUG: CPU#%d started up but did not get a callout!\n", | ||
485 | cpu_id); | ||
486 | BUG(); | ||
487 | } | ||
488 | |||
489 | /* Allow the master to continue. */ | ||
490 | cpu_set(cpu_id, cpu_callin_map); | ||
491 | } | ||
492 | |||
493 | static void __init smp_online(void) | ||
494 | { | ||
495 | int cpu_id = smp_processor_id(); | ||
496 | |||
497 | local_irq_enable(); | ||
498 | |||
499 | /* Get our bogomips. */ | ||
500 | calibrate_delay(); | ||
501 | |||
502 | /* Save our processor parameters */ | ||
503 | smp_store_cpu_info(cpu_id); | ||
504 | |||
505 | cpu_set(cpu_id, cpu_online_map); | ||
506 | } | ||
507 | |||
508 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
509 | /* Boot up CPUs common Routins */ | ||
510 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | ||
511 | static void __init show_mp_info(int nr_cpu) | ||
512 | { | ||
513 | int i; | ||
514 | char cpu_model0[17], cpu_model1[17], cpu_ver[9]; | ||
515 | |||
516 | strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16); | ||
517 | strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16); | ||
518 | strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8); | ||
519 | |||
520 | cpu_model0[16] = '\0'; | ||
521 | for (i = 15 ; i >= 0 ; i--) { | ||
522 | if (cpu_model0[i] != ' ') | ||
523 | break; | ||
524 | cpu_model0[i] = '\0'; | ||
525 | } | ||
526 | cpu_model1[16] = '\0'; | ||
527 | for (i = 15 ; i >= 0 ; i--) { | ||
528 | if (cpu_model1[i] != ' ') | ||
529 | break; | ||
530 | cpu_model1[i] = '\0'; | ||
531 | } | ||
532 | cpu_ver[8] = '\0'; | ||
533 | for (i = 7 ; i >= 0 ; i--) { | ||
534 | if (cpu_ver[i] != ' ') | ||
535 | break; | ||
536 | cpu_ver[i] = '\0'; | ||
537 | } | ||
538 | |||
539 | printk(KERN_INFO "M32R-mp information\n"); | ||
540 | printk(KERN_INFO " On-chip CPUs : %d\n", nr_cpu); | ||
541 | printk(KERN_INFO " CPU model : %s/%s(%s)\n", cpu_model0, | ||
542 | cpu_model1, cpu_ver); | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * The bootstrap kernel entry code has set these up. Save them for | ||
547 | * a given CPU | ||
548 | */ | ||
549 | static void __init smp_store_cpu_info(int cpu_id) | ||
550 | { | ||
551 | struct cpuinfo_m32r *ci = cpu_data + cpu_id; | ||
552 | |||
553 | *ci = boot_cpu_data; | ||
554 | ci->loops_per_jiffy = loops_per_jiffy; | ||
555 | } | ||
556 | |||
557 | static void __init show_cpu_info(int cpu_id) | ||
558 | { | ||
559 | struct cpuinfo_m32r *ci = &cpu_data[cpu_id]; | ||
560 | |||
561 | printk("CPU#%d : ", cpu_id); | ||
562 | |||
563 | #define PRINT_CLOCK(name, value) \ | ||
564 | printk(name " clock %d.%02dMHz", \ | ||
565 | ((value) / 1000000), ((value) % 1000000) / 10000) | ||
566 | |||
567 | PRINT_CLOCK("CPU", (int)ci->cpu_clock); | ||
568 | PRINT_CLOCK(", Bus", (int)ci->bus_clock); | ||
569 | printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy); | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * the frequency of the profiling timer can be changed | ||
574 | * by writing a multiplier value into /proc/profile. | ||
575 | */ | ||
576 | int setup_profiling_timer(unsigned int multiplier) | ||
577 | { | ||
578 | int i; | ||
579 | |||
580 | /* | ||
581 | * Sanity check. [at least 500 APIC cycles should be | ||
582 | * between APIC interrupts as a rule of thumb, to avoid | ||
583 | * irqs flooding us] | ||
584 | */ | ||
585 | if ( (!multiplier) || (calibration_result / multiplier < 500)) | ||
586 | return -EINVAL; | ||
587 | |||
588 | /* | ||
589 | * Set the new multiplier for each CPU. CPUs don't start using the | ||
590 | * new values until the next timer interrupt in which they do process | ||
591 | * accounting. At that time they also adjust their APIC timers | ||
592 | * accordingly. | ||
593 | */ | ||
594 | for (i = 0; i < NR_CPUS; ++i) | ||
595 | per_cpu(prof_multiplier, i) = multiplier; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /* Initialize all maps between cpu number and apicids */ | ||
601 | static void __init init_cpu_to_physid(void) | ||
602 | { | ||
603 | int i; | ||
604 | |||
605 | for (i = 0 ; i < NR_CPUS ; i++) { | ||
606 | cpu_2_physid[i] = -1; | ||
607 | physid_2_cpu[i] = -1; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, | ||
613 | * else physical apic ids | ||
614 | */ | ||
615 | static void __init map_cpu_to_physid(int cpu_id, int phys_id) | ||
616 | { | ||
617 | physid_2_cpu[phys_id] = cpu_id; | ||
618 | cpu_2_physid[cpu_id] = phys_id; | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, | ||
623 | * else physical apic ids | ||
624 | */ | ||
625 | static void __init unmap_cpu_to_physid(int cpu_id, int phys_id) | ||
626 | { | ||
627 | physid_2_cpu[phys_id] = -1; | ||
628 | cpu_2_physid[cpu_id] = -1; | ||
629 | } | ||
630 | |||
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c new file mode 100644 index 000000000000..e0500e12c5fb --- /dev/null +++ b/arch/m32r/kernel/sys_m32r.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/sys_m32r.c | ||
3 | * | ||
4 | * This file contains various random system calls that | ||
5 | * have a non-standard calling sequence on the Linux/M32R platform. | ||
6 | * | ||
7 | * Taken from i386 version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/sem.h> | ||
17 | #include <linux/msg.h> | ||
18 | #include <linux/shm.h> | ||
19 | #include <linux/stat.h> | ||
20 | #include <linux/syscalls.h> | ||
21 | #include <linux/mman.h> | ||
22 | #include <linux/file.h> | ||
23 | #include <linux/utsname.h> | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/cachectl.h> | ||
27 | #include <asm/cacheflush.h> | ||
28 | #include <asm/ipc.h> | ||
29 | |||
30 | /* | ||
31 | * sys_tas() - test-and-set | ||
32 | * linuxthreads testing version | ||
33 | */ | ||
34 | #ifndef CONFIG_SMP | ||
35 | asmlinkage int sys_tas(int *addr) | ||
36 | { | ||
37 | int oldval; | ||
38 | unsigned long flags; | ||
39 | |||
40 | if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) | ||
41 | return -EFAULT; | ||
42 | local_irq_save(flags); | ||
43 | oldval = *addr; | ||
44 | *addr = 1; | ||
45 | local_irq_restore(flags); | ||
46 | return oldval; | ||
47 | } | ||
48 | #else /* CONFIG_SMP */ | ||
49 | #include <linux/spinlock.h> | ||
50 | |||
51 | static DEFINE_SPINLOCK(tas_lock); | ||
52 | |||
53 | asmlinkage int sys_tas(int *addr) | ||
54 | { | ||
55 | int oldval; | ||
56 | |||
57 | if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) | ||
58 | return -EFAULT; | ||
59 | |||
60 | _raw_spin_lock(&tas_lock); | ||
61 | oldval = *addr; | ||
62 | *addr = 1; | ||
63 | _raw_spin_unlock(&tas_lock); | ||
64 | |||
65 | return oldval; | ||
66 | } | ||
67 | #endif /* CONFIG_SMP */ | ||
68 | |||
69 | /* | ||
70 | * sys_pipe() is the normal C calling standard for creating | ||
71 | * a pipe. It's not the way Unix traditionally does this, though. | ||
72 | */ | ||
73 | asmlinkage int | ||
74 | sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2, | ||
75 | unsigned long r3, unsigned long r4, unsigned long r5, | ||
76 | unsigned long r6, struct pt_regs regs) | ||
77 | { | ||
78 | int fd[2]; | ||
79 | int error; | ||
80 | |||
81 | error = do_pipe(fd); | ||
82 | if (!error) { | ||
83 | if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int))) | ||
84 | error = -EFAULT; | ||
85 | } | ||
86 | return error; | ||
87 | } | ||
88 | |||
89 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
90 | unsigned long prot, unsigned long flags, | ||
91 | unsigned long fd, unsigned long pgoff) | ||
92 | { | ||
93 | int error = -EBADF; | ||
94 | struct file *file = NULL; | ||
95 | |||
96 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
97 | if (!(flags & MAP_ANONYMOUS)) { | ||
98 | file = fget(fd); | ||
99 | if (!file) | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | down_write(¤t->mm->mmap_sem); | ||
104 | error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
105 | up_write(¤t->mm->mmap_sem); | ||
106 | |||
107 | if (file) | ||
108 | fput(file); | ||
109 | out: | ||
110 | return error; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | ||
115 | * | ||
116 | * This is really horribly ugly. | ||
117 | */ | ||
118 | asmlinkage int sys_ipc(uint call, int first, int second, | ||
119 | int third, void __user *ptr, long fifth) | ||
120 | { | ||
121 | int version, ret; | ||
122 | |||
123 | version = call >> 16; /* hack for backward compatibility */ | ||
124 | call &= 0xffff; | ||
125 | |||
126 | switch (call) { | ||
127 | case SEMOP: | ||
128 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | ||
129 | second, NULL); | ||
130 | case SEMTIMEDOP: | ||
131 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | ||
132 | second, (const struct timespec __user *)fifth); | ||
133 | case SEMGET: | ||
134 | return sys_semget (first, second, third); | ||
135 | case SEMCTL: { | ||
136 | union semun fourth; | ||
137 | if (!ptr) | ||
138 | return -EINVAL; | ||
139 | if (get_user(fourth.__pad, (void __user * __user *) ptr)) | ||
140 | return -EFAULT; | ||
141 | return sys_semctl (first, second, third, fourth); | ||
142 | } | ||
143 | |||
144 | case MSGSND: | ||
145 | return sys_msgsnd (first, (struct msgbuf __user *) ptr, | ||
146 | second, third); | ||
147 | case MSGRCV: | ||
148 | switch (version) { | ||
149 | case 0: { | ||
150 | struct ipc_kludge tmp; | ||
151 | if (!ptr) | ||
152 | return -EINVAL; | ||
153 | |||
154 | if (copy_from_user(&tmp, | ||
155 | (struct ipc_kludge __user *) ptr, | ||
156 | sizeof (tmp))) | ||
157 | return -EFAULT; | ||
158 | return sys_msgrcv (first, tmp.msgp, second, | ||
159 | tmp.msgtyp, third); | ||
160 | } | ||
161 | default: | ||
162 | return sys_msgrcv (first, | ||
163 | (struct msgbuf __user *) ptr, | ||
164 | second, fifth, third); | ||
165 | } | ||
166 | case MSGGET: | ||
167 | return sys_msgget ((key_t) first, second); | ||
168 | case MSGCTL: | ||
169 | return sys_msgctl (first, second, | ||
170 | (struct msqid_ds __user *) ptr); | ||
171 | case SHMAT: { | ||
172 | ulong raddr; | ||
173 | |||
174 | if (!access_ok(VERIFY_WRITE, (ulong __user *) third, | ||
175 | sizeof(ulong))) | ||
176 | return -EFAULT; | ||
177 | ret = do_shmat (first, (char __user *) ptr, second, &raddr); | ||
178 | if (ret) | ||
179 | return ret; | ||
180 | return put_user (raddr, (ulong __user *) third); | ||
181 | } | ||
182 | case SHMDT: | ||
183 | return sys_shmdt ((char __user *)ptr); | ||
184 | case SHMGET: | ||
185 | return sys_shmget (first, second, third); | ||
186 | case SHMCTL: | ||
187 | return sys_shmctl (first, second, | ||
188 | (struct shmid_ds __user *) ptr); | ||
189 | default: | ||
190 | return -ENOSYS; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | asmlinkage int sys_uname(struct old_utsname * name) | ||
195 | { | ||
196 | int err; | ||
197 | if (!name) | ||
198 | return -EFAULT; | ||
199 | down_read(&uts_sem); | ||
200 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | ||
201 | up_read(&uts_sem); | ||
202 | return err?-EFAULT:0; | ||
203 | } | ||
204 | |||
205 | asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) | ||
206 | { | ||
207 | /* This should flush more selectivly ... */ | ||
208 | _flush_cache_all(); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | asmlinkage int sys_cachectl(char *addr, int nbytes, int op) | ||
213 | { | ||
214 | /* Not implemented yet. */ | ||
215 | return -ENOSYS; | ||
216 | } | ||
217 | |||
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c new file mode 100644 index 000000000000..3c4707280a52 --- /dev/null +++ b/arch/m32r/kernel/time.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/time.c | ||
3 | * | ||
4 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
5 | * Hitoshi Yamamoto | ||
6 | * Taken from i386 version. | ||
7 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
8 | * Copyright (C) 1996, 1997, 1998 Ralf Baechle | ||
9 | * | ||
10 | * This file contains the time handling details for PC-style clocks as | ||
11 | * found in some MIPS systems. | ||
12 | * | ||
13 | * Some code taken from sh version. | ||
14 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
15 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
16 | */ | ||
17 | |||
18 | #undef DEBUG_TIMER | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/param.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/profile.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/m32r.h> | ||
34 | |||
35 | #include <asm/hw_irq.h> | ||
36 | |||
37 | #ifdef CONFIG_SMP | ||
38 | extern void send_IPI_allbutself(int, int); | ||
39 | extern void smp_local_timer_interrupt(struct pt_regs *); | ||
40 | #endif | ||
41 | |||
42 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
43 | |||
44 | EXPORT_SYMBOL(jiffies_64); | ||
45 | |||
46 | extern unsigned long wall_jiffies; | ||
47 | #define TICK_SIZE (tick_nsec / 1000) | ||
48 | |||
49 | /* | ||
50 | * Change this if you have some constant time drift | ||
51 | */ | ||
52 | |||
53 | /* This is for machines which generate the exact clock. */ | ||
54 | #define USECS_PER_JIFFY (1000000/HZ) | ||
55 | |||
56 | static unsigned long latch; | ||
57 | |||
58 | static unsigned long do_gettimeoffset(void) | ||
59 | { | ||
60 | unsigned long elapsed_time = 0; /* [us] */ | ||
61 | |||
62 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ | ||
63 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | ||
64 | || defined(CONFIG_CHIP_OPSP) | ||
65 | #ifndef CONFIG_SMP | ||
66 | |||
67 | unsigned long count; | ||
68 | |||
69 | /* timer count may underflow right here */ | ||
70 | count = inl(M32R_MFT2CUT_PORTL); | ||
71 | |||
72 | if (inl(M32R_ICU_CR18_PORTL) & 0x00000100) /* underflow check */ | ||
73 | count = 0; | ||
74 | |||
75 | count = (latch - count) * TICK_SIZE; | ||
76 | elapsed_time = (count + latch / 2) / latch; | ||
77 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ | ||
78 | |||
79 | #else /* CONFIG_SMP */ | ||
80 | unsigned long count; | ||
81 | static unsigned long p_jiffies = -1; | ||
82 | static unsigned long p_count = 0; | ||
83 | |||
84 | /* timer count may underflow right here */ | ||
85 | count = inl(M32R_MFT2CUT_PORTL); | ||
86 | |||
87 | if (jiffies == p_jiffies && count > p_count) | ||
88 | count = 0; | ||
89 | |||
90 | p_jiffies = jiffies; | ||
91 | p_count = count; | ||
92 | |||
93 | count = (latch - count) * TICK_SIZE; | ||
94 | elapsed_time = (count + latch / 2) / latch; | ||
95 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ | ||
96 | #endif /* CONFIG_SMP */ | ||
97 | #elif defined(CONFIG_CHIP_M32310) | ||
98 | #warning do_gettimeoffse not implemented | ||
99 | #else | ||
100 | #error no chip configuration | ||
101 | #endif | ||
102 | |||
103 | return elapsed_time; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * This version of gettimeofday has near microsecond resolution. | ||
108 | */ | ||
109 | void do_gettimeofday(struct timeval *tv) | ||
110 | { | ||
111 | unsigned long seq; | ||
112 | unsigned long usec, sec; | ||
113 | unsigned long max_ntp_tick = tick_usec - tickadj; | ||
114 | |||
115 | do { | ||
116 | unsigned long lost; | ||
117 | |||
118 | seq = read_seqbegin(&xtime_lock); | ||
119 | |||
120 | usec = do_gettimeoffset(); | ||
121 | lost = jiffies - wall_jiffies; | ||
122 | |||
123 | /* | ||
124 | * If time_adjust is negative then NTP is slowing the clock | ||
125 | * so make sure not to go into next possible interval. | ||
126 | * Better to lose some accuracy than have time go backwards.. | ||
127 | */ | ||
128 | if (unlikely(time_adjust < 0)) { | ||
129 | usec = min(usec, max_ntp_tick); | ||
130 | if (lost) | ||
131 | usec += lost * max_ntp_tick; | ||
132 | } else if (unlikely(lost)) | ||
133 | usec += lost * tick_usec; | ||
134 | |||
135 | sec = xtime.tv_sec; | ||
136 | usec += (xtime.tv_nsec / 1000); | ||
137 | } while (read_seqretry(&xtime_lock, seq)); | ||
138 | |||
139 | while (usec >= 1000000) { | ||
140 | usec -= 1000000; | ||
141 | sec++; | ||
142 | } | ||
143 | |||
144 | tv->tv_sec = sec; | ||
145 | tv->tv_usec = usec; | ||
146 | } | ||
147 | |||
148 | EXPORT_SYMBOL(do_gettimeofday); | ||
149 | |||
150 | int do_settimeofday(struct timespec *tv) | ||
151 | { | ||
152 | time_t wtm_sec, sec = tv->tv_sec; | ||
153 | long wtm_nsec, nsec = tv->tv_nsec; | ||
154 | |||
155 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | write_seqlock_irq(&xtime_lock); | ||
159 | /* | ||
160 | * This is revolting. We need to set "xtime" correctly. However, the | ||
161 | * value in this location is the value at the most recent update of | ||
162 | * wall time. Discover what correction gettimeofday() would have | ||
163 | * made, and then undo it! | ||
164 | */ | ||
165 | nsec -= do_gettimeoffset() * NSEC_PER_USEC; | ||
166 | nsec -= (jiffies - wall_jiffies) * TICK_NSEC; | ||
167 | |||
168 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
169 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
170 | |||
171 | set_normalized_timespec(&xtime, sec, nsec); | ||
172 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
173 | |||
174 | time_adjust = 0; /* stop active adjtime() */ | ||
175 | time_status |= STA_UNSYNC; | ||
176 | time_maxerror = NTP_PHASE_LIMIT; | ||
177 | time_esterror = NTP_PHASE_LIMIT; | ||
178 | write_sequnlock_irq(&xtime_lock); | ||
179 | clock_was_set(); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | EXPORT_SYMBOL(do_settimeofday); | ||
185 | |||
186 | /* | ||
187 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | ||
188 | * called 500 ms after the second nowtime has started, because when | ||
189 | * nowtime is written into the registers of the CMOS clock, it will | ||
190 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
191 | * MC146818A or Dallas DS12887 data sheet for details. | ||
192 | * | ||
193 | * BUG: This routine does not handle hour overflow properly; it just | ||
194 | * sets the minutes. Usually you won't notice until after reboot! | ||
195 | */ | ||
196 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* last time the cmos clock got updated */ | ||
202 | static long last_rtc_update = 0; | ||
203 | |||
204 | /* | ||
205 | * timer_interrupt() needs to keep up the real-time clock, | ||
206 | * as well as call the "do_timer()" routine every clocktick | ||
207 | */ | ||
208 | static inline void | ||
209 | do_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
210 | { | ||
211 | #ifndef CONFIG_SMP | ||
212 | profile_tick(CPU_PROFILING, regs); | ||
213 | #endif | ||
214 | do_timer(regs); | ||
215 | |||
216 | #ifndef CONFIG_SMP | ||
217 | update_process_times(user_mode(regs)); | ||
218 | #endif | ||
219 | /* | ||
220 | * If we have an externally synchronized Linux clock, then update | ||
221 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
222 | * called as close as possible to 500 ms before the new second starts. | ||
223 | */ | ||
224 | if ((time_status & STA_UNSYNC) == 0 | ||
225 | && xtime.tv_sec > last_rtc_update + 660 | ||
226 | && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2 | ||
227 | && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2) | ||
228 | { | ||
229 | if (set_rtc_mmss(xtime.tv_sec) == 0) | ||
230 | last_rtc_update = xtime.tv_sec; | ||
231 | else /* do it again in 60 s */ | ||
232 | last_rtc_update = xtime.tv_sec - 600; | ||
233 | } | ||
234 | /* As we return to user mode fire off the other CPU schedulers.. | ||
235 | this is basically because we don't yet share IRQ's around. | ||
236 | This message is rigged to be safe on the 386 - basically it's | ||
237 | a hack, so don't look closely for now.. */ | ||
238 | |||
239 | #ifdef CONFIG_SMP | ||
240 | smp_local_timer_interrupt(regs); | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
245 | { | ||
246 | write_seqlock(&xtime_lock); | ||
247 | do_timer_interrupt(irq, NULL, regs); | ||
248 | write_sequnlock(&xtime_lock); | ||
249 | |||
250 | return IRQ_HANDLED; | ||
251 | } | ||
252 | |||
253 | struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, | ||
254 | "MFT2", NULL, NULL }; | ||
255 | |||
256 | void __init time_init(void) | ||
257 | { | ||
258 | unsigned int epoch, year, mon, day, hour, min, sec; | ||
259 | |||
260 | sec = min = hour = day = mon = year = 0; | ||
261 | epoch = 0; | ||
262 | |||
263 | year = 23; | ||
264 | mon = 4; | ||
265 | day = 17; | ||
266 | |||
267 | /* Attempt to guess the epoch. This is the same heuristic as in rtc.c | ||
268 | so no stupid things will happen to timekeeping. Who knows, maybe | ||
269 | Ultrix also uses 1952 as epoch ... */ | ||
270 | if (year > 10 && year < 44) | ||
271 | epoch = 1980; | ||
272 | else if (year < 96) | ||
273 | epoch = 1952; | ||
274 | year += epoch; | ||
275 | |||
276 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
277 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
278 | set_normalized_timespec(&wall_to_monotonic, | ||
279 | -xtime.tv_sec, -xtime.tv_nsec); | ||
280 | |||
281 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ | ||
282 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | ||
283 | || defined(CONFIG_CHIP_OPSP) | ||
284 | |||
285 | /* M32102 MFT setup */ | ||
286 | setup_irq(M32R_IRQ_MFT2, &irq0); | ||
287 | { | ||
288 | unsigned long bus_clock; | ||
289 | unsigned short divide; | ||
290 | |||
291 | bus_clock = boot_cpu_data.bus_clock; | ||
292 | divide = boot_cpu_data.timer_divide; | ||
293 | latch = (bus_clock/divide + HZ / 2) / HZ; | ||
294 | |||
295 | printk("Timer start : latch = %ld\n", latch); | ||
296 | |||
297 | outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \ | ||
298 | |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL); | ||
299 | outl(latch, M32R_MFT2RLD_PORTL); | ||
300 | outl(latch, M32R_MFT2CUT_PORTL); | ||
301 | outl(0, M32R_MFT2CMPRLD_PORTL); | ||
302 | outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL); | ||
303 | } | ||
304 | |||
305 | #elif defined(CONFIG_CHIP_M32310) | ||
306 | #warning time_init not implemented | ||
307 | #else | ||
308 | #error no chip configuration | ||
309 | #endif | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Scheduler clock - returns current time in nanosec units. | ||
314 | */ | ||
315 | unsigned long long sched_clock(void) | ||
316 | { | ||
317 | return (unsigned long long)jiffies * (1000000000 / HZ); | ||
318 | } | ||
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c new file mode 100644 index 000000000000..01922271d17e --- /dev/null +++ b/arch/m32r/kernel/traps.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/traps.c | ||
3 | * | ||
4 | * Copyright (C) 2001, 2002 Hirokazu Takata, Hiroyuki Kondo, | ||
5 | * Hitoshi Yamamoto | ||
6 | */ | ||
7 | |||
8 | /* $Id$ */ | ||
9 | |||
10 | /* | ||
11 | * 'traps.c' handles hardware traps and faults after we have saved some | ||
12 | * state in 'entry.S'. | ||
13 | */ | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/kallsyms.h> | ||
18 | #include <linux/stddef.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/processor.h> | ||
23 | |||
24 | #include <asm/system.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/atomic.h> | ||
28 | |||
29 | #include <asm/smp.h> | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | |||
33 | asmlinkage void alignment_check(void); | ||
34 | asmlinkage void ei_handler(void); | ||
35 | asmlinkage void rie_handler(void); | ||
36 | asmlinkage void debug_trap(void); | ||
37 | asmlinkage void cache_flushing_handler(void); | ||
38 | |||
39 | #ifdef CONFIG_SMP | ||
40 | extern void smp_reschedule_interrupt(void); | ||
41 | extern void smp_invalidate_interrupt(void); | ||
42 | extern void smp_call_function_interrupt(void); | ||
43 | extern void smp_ipi_timer_interrupt(void); | ||
44 | extern void smp_flush_cache_all_interrupt(void); | ||
45 | |||
46 | /* | ||
47 | * for Boot AP function | ||
48 | */ | ||
49 | asm ( | ||
50 | " .section .eit_vector4,\"ax\" \n" | ||
51 | " .global _AP_RE \n" | ||
52 | " .global startup_AP \n" | ||
53 | "_AP_RE: \n" | ||
54 | " .fill 32, 4, 0 \n" | ||
55 | "_AP_EI: bra startup_AP \n" | ||
56 | " .previous \n" | ||
57 | ); | ||
58 | #endif /* CONFIG_SMP */ | ||
59 | |||
60 | extern unsigned long eit_vector[]; | ||
61 | #define BRA_INSN(func, entry) \ | ||
62 | ((unsigned long)func - (unsigned long)eit_vector - entry*4)/4 \ | ||
63 | + 0xff000000UL | ||
64 | |||
65 | void set_eit_vector_entries(void) | ||
66 | { | ||
67 | extern void default_eit_handler(void); | ||
68 | extern void system_call(void); | ||
69 | extern void pie_handler(void); | ||
70 | extern void ace_handler(void); | ||
71 | extern void tme_handler(void); | ||
72 | extern void _flush_cache_copyback_all(void); | ||
73 | |||
74 | eit_vector[0] = 0xd0c00001; /* seth r0, 0x01 */ | ||
75 | eit_vector[1] = BRA_INSN(default_eit_handler, 1); | ||
76 | eit_vector[4] = 0xd0c00010; /* seth r0, 0x10 */ | ||
77 | eit_vector[5] = BRA_INSN(default_eit_handler, 5); | ||
78 | eit_vector[8] = BRA_INSN(rie_handler, 8); | ||
79 | eit_vector[12] = BRA_INSN(alignment_check, 12); | ||
80 | eit_vector[16] = 0xff000000UL; | ||
81 | eit_vector[17] = BRA_INSN(debug_trap, 17); | ||
82 | eit_vector[18] = BRA_INSN(system_call, 18); | ||
83 | eit_vector[19] = 0xff000000UL; | ||
84 | eit_vector[20] = 0xff000000UL; | ||
85 | eit_vector[21] = 0xff000000UL; | ||
86 | eit_vector[22] = 0xff000000UL; | ||
87 | eit_vector[23] = 0xff000000UL; | ||
88 | eit_vector[24] = 0xff000000UL; | ||
89 | eit_vector[25] = 0xff000000UL; | ||
90 | eit_vector[26] = 0xff000000UL; | ||
91 | eit_vector[27] = 0xff000000UL; | ||
92 | eit_vector[28] = BRA_INSN(cache_flushing_handler, 28); | ||
93 | eit_vector[29] = 0xff000000UL; | ||
94 | eit_vector[30] = 0xff000000UL; | ||
95 | eit_vector[31] = 0xff000000UL; | ||
96 | eit_vector[32] = BRA_INSN(ei_handler, 32); | ||
97 | eit_vector[64] = BRA_INSN(pie_handler, 64); | ||
98 | #ifdef CONFIG_MMU | ||
99 | eit_vector[68] = BRA_INSN(ace_handler, 68); | ||
100 | eit_vector[72] = BRA_INSN(tme_handler, 72); | ||
101 | #endif /* CONFIG_MMU */ | ||
102 | #ifdef CONFIG_SMP | ||
103 | eit_vector[184] = (unsigned long)smp_reschedule_interrupt; | ||
104 | eit_vector[185] = (unsigned long)smp_invalidate_interrupt; | ||
105 | eit_vector[186] = (unsigned long)smp_call_function_interrupt; | ||
106 | eit_vector[187] = (unsigned long)smp_ipi_timer_interrupt; | ||
107 | eit_vector[188] = (unsigned long)smp_flush_cache_all_interrupt; | ||
108 | eit_vector[189] = 0; | ||
109 | eit_vector[190] = 0; | ||
110 | eit_vector[191] = 0; | ||
111 | #endif | ||
112 | _flush_cache_copyback_all(); | ||
113 | } | ||
114 | |||
115 | void __init trap_init(void) | ||
116 | { | ||
117 | set_eit_vector_entries(); | ||
118 | |||
119 | /* | ||
120 | * Should be a barrier for any external CPU state. | ||
121 | */ | ||
122 | cpu_init(); | ||
123 | } | ||
124 | |||
125 | int kstack_depth_to_print = 24; | ||
126 | |||
127 | void show_trace(struct task_struct *task, unsigned long *stack) | ||
128 | { | ||
129 | unsigned long addr; | ||
130 | |||
131 | if (!stack) | ||
132 | stack = (unsigned long*)&stack; | ||
133 | |||
134 | printk("Call Trace: "); | ||
135 | while (!kstack_end(stack)) { | ||
136 | addr = *stack++; | ||
137 | if (__kernel_text_address(addr)) { | ||
138 | printk("[<%08lx>] ", addr); | ||
139 | print_symbol("%s\n", addr); | ||
140 | } | ||
141 | } | ||
142 | printk("\n"); | ||
143 | } | ||
144 | |||
145 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
146 | { | ||
147 | unsigned long *stack; | ||
148 | int i; | ||
149 | |||
150 | /* | ||
151 | * debugging aid: "show_stack(NULL);" prints the | ||
152 | * back trace for this cpu. | ||
153 | */ | ||
154 | |||
155 | if(sp==NULL) { | ||
156 | if (task) | ||
157 | sp = (unsigned long *)task->thread.sp; | ||
158 | else | ||
159 | sp=(unsigned long*)&sp; | ||
160 | } | ||
161 | |||
162 | stack = sp; | ||
163 | for(i=0; i < kstack_depth_to_print; i++) { | ||
164 | if (kstack_end(stack)) | ||
165 | break; | ||
166 | if (i && ((i % 4) == 0)) | ||
167 | printk("\n "); | ||
168 | printk("%08lx ", *stack++); | ||
169 | } | ||
170 | printk("\n"); | ||
171 | show_trace(task, sp); | ||
172 | } | ||
173 | |||
174 | void dump_stack(void) | ||
175 | { | ||
176 | unsigned long stack; | ||
177 | |||
178 | show_trace(current, &stack); | ||
179 | } | ||
180 | |||
181 | EXPORT_SYMBOL(dump_stack); | ||
182 | |||
183 | static void show_registers(struct pt_regs *regs) | ||
184 | { | ||
185 | int i = 0; | ||
186 | int in_kernel = 1; | ||
187 | unsigned long sp; | ||
188 | |||
189 | printk("CPU: %d\n", smp_processor_id()); | ||
190 | show_regs(regs); | ||
191 | |||
192 | sp = (unsigned long) (1+regs); | ||
193 | if (user_mode(regs)) { | ||
194 | in_kernel = 0; | ||
195 | sp = regs->spu; | ||
196 | printk("SPU: %08lx\n", sp); | ||
197 | } else { | ||
198 | printk("SPI: %08lx\n", sp); | ||
199 | } | ||
200 | printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", | ||
201 | current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); | ||
202 | |||
203 | /* | ||
204 | * When in-kernel, we also print out the stack and code at the | ||
205 | * time of the fault.. | ||
206 | */ | ||
207 | if (in_kernel) { | ||
208 | printk("\nStack: "); | ||
209 | show_stack(current, (unsigned long*) sp); | ||
210 | |||
211 | printk("\nCode: "); | ||
212 | if (regs->bpc < PAGE_OFFSET) | ||
213 | goto bad; | ||
214 | |||
215 | for(i=0;i<20;i++) { | ||
216 | unsigned char c; | ||
217 | if (__get_user(c, &((unsigned char*)regs->bpc)[i])) { | ||
218 | bad: | ||
219 | printk(" Bad PC value."); | ||
220 | break; | ||
221 | } | ||
222 | printk("%02x ", c); | ||
223 | } | ||
224 | } | ||
225 | printk("\n"); | ||
226 | } | ||
227 | |||
228 | DEFINE_SPINLOCK(die_lock); | ||
229 | |||
230 | void die(const char * str, struct pt_regs * regs, long err) | ||
231 | { | ||
232 | console_verbose(); | ||
233 | spin_lock_irq(&die_lock); | ||
234 | bust_spinlocks(1); | ||
235 | printk("%s: %04lx\n", str, err & 0xffff); | ||
236 | show_registers(regs); | ||
237 | bust_spinlocks(0); | ||
238 | spin_unlock_irq(&die_lock); | ||
239 | do_exit(SIGSEGV); | ||
240 | } | ||
241 | |||
242 | static __inline__ void die_if_kernel(const char * str, | ||
243 | struct pt_regs * regs, long err) | ||
244 | { | ||
245 | if (!user_mode(regs)) | ||
246 | die(str, regs, err); | ||
247 | } | ||
248 | |||
249 | static __inline__ void do_trap(int trapnr, int signr, const char * str, | ||
250 | struct pt_regs * regs, long error_code, siginfo_t *info) | ||
251 | { | ||
252 | if (user_mode(regs)) { | ||
253 | /* trap_signal */ | ||
254 | struct task_struct *tsk = current; | ||
255 | tsk->thread.error_code = error_code; | ||
256 | tsk->thread.trap_no = trapnr; | ||
257 | if (info) | ||
258 | force_sig_info(signr, info, tsk); | ||
259 | else | ||
260 | force_sig(signr, tsk); | ||
261 | return; | ||
262 | } else { | ||
263 | /* kernel_trap */ | ||
264 | if (!fixup_exception(regs)) | ||
265 | die(str, regs, error_code); | ||
266 | return; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | #define DO_ERROR(trapnr, signr, str, name) \ | ||
271 | asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | ||
272 | { \ | ||
273 | do_trap(trapnr, signr, 0, regs, error_code, NULL); \ | ||
274 | } | ||
275 | |||
276 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | ||
277 | asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | ||
278 | { \ | ||
279 | siginfo_t info; \ | ||
280 | info.si_signo = signr; \ | ||
281 | info.si_errno = 0; \ | ||
282 | info.si_code = sicode; \ | ||
283 | info.si_addr = (void __user *)siaddr; \ | ||
284 | do_trap(trapnr, signr, str, regs, error_code, &info); \ | ||
285 | } | ||
286 | |||
287 | DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap) | ||
288 | DO_ERROR_INFO(0x20, SIGILL, "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc) | ||
289 | DO_ERROR_INFO(0x100, SIGILL, "privilege instruction", pie_handler, ILL_PRVOPC, regs->bpc) | ||
290 | |||
291 | extern int handle_unaligned_access(unsigned long, struct pt_regs *); | ||
292 | |||
293 | /* This code taken from arch/sh/kernel/traps.c */ | ||
294 | asmlinkage void do_alignment_check(struct pt_regs *regs, long error_code) | ||
295 | { | ||
296 | mm_segment_t oldfs; | ||
297 | unsigned long insn; | ||
298 | int tmp; | ||
299 | |||
300 | oldfs = get_fs(); | ||
301 | |||
302 | if (user_mode(regs)) { | ||
303 | local_irq_enable(); | ||
304 | current->thread.error_code = error_code; | ||
305 | current->thread.trap_no = 0x17; | ||
306 | |||
307 | set_fs(USER_DS); | ||
308 | if (copy_from_user(&insn, (void *)regs->bpc, 4)) { | ||
309 | set_fs(oldfs); | ||
310 | goto uspace_segv; | ||
311 | } | ||
312 | tmp = handle_unaligned_access(insn, regs); | ||
313 | set_fs(oldfs); | ||
314 | |||
315 | if (!tmp) | ||
316 | return; | ||
317 | |||
318 | uspace_segv: | ||
319 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " | ||
320 | "access\n", current->comm); | ||
321 | force_sig(SIGSEGV, current); | ||
322 | } else { | ||
323 | set_fs(KERNEL_DS); | ||
324 | if (copy_from_user(&insn, (void *)regs->bpc, 4)) { | ||
325 | set_fs(oldfs); | ||
326 | die("insn faulting in do_address_error", regs, 0); | ||
327 | } | ||
328 | handle_unaligned_access(insn, regs); | ||
329 | set_fs(oldfs); | ||
330 | } | ||
331 | } | ||
332 | |||
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..729a2645a03f --- /dev/null +++ b/arch/m32r/kernel/vmlinux.lds.S | |||
@@ -0,0 +1,143 @@ | |||
1 | /* ld script to make M32R Linux kernel | ||
2 | */ | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | #include <asm-generic/vmlinux.lds.h> | ||
6 | #include <asm/addrspace.h> | ||
7 | #include <asm/page.h> | ||
8 | |||
9 | OUTPUT_ARCH(m32r) | ||
10 | ENTRY(startup_32) | ||
11 | #if defined(__LITTLE_ENDIAN__) | ||
12 | jiffies = jiffies_64; | ||
13 | #else | ||
14 | jiffies = jiffies_64 + 4; | ||
15 | #endif | ||
16 | SECTIONS | ||
17 | { | ||
18 | . = CONFIG_MEMORY_START + __PAGE_OFFSET; | ||
19 | eit_vector = .; | ||
20 | |||
21 | . = . + 0x1000; | ||
22 | .empty_zero_page : { *(.empty_zero_page) } = 0 | ||
23 | |||
24 | /* read-only */ | ||
25 | _text = .; /* Text and read-only data */ | ||
26 | .boot : { *(.boot) } = 0 | ||
27 | .text : { | ||
28 | *(.text) | ||
29 | SCHED_TEXT | ||
30 | LOCK_TEXT | ||
31 | *(.fixup) | ||
32 | *(.gnu.warning) | ||
33 | } = 0x9090 | ||
34 | #ifdef CONFIG_SMP | ||
35 | . = ALIGN(65536); | ||
36 | .eit_vector4 : { *(.eit_vector4) } | ||
37 | #endif | ||
38 | _etext = .; /* End of text section */ | ||
39 | |||
40 | . = ALIGN(16); /* Exception table */ | ||
41 | __start___ex_table = .; | ||
42 | __ex_table : { *(__ex_table) } | ||
43 | __stop___ex_table = .; | ||
44 | |||
45 | RODATA | ||
46 | |||
47 | /* writeable */ | ||
48 | .data : { /* Data */ | ||
49 | *(.spu) | ||
50 | *(.spi) | ||
51 | *(.data) | ||
52 | CONSTRUCTORS | ||
53 | } | ||
54 | |||
55 | . = ALIGN(4096); | ||
56 | __nosave_begin = .; | ||
57 | .data_nosave : { *(.data.nosave) } | ||
58 | . = ALIGN(4096); | ||
59 | __nosave_end = .; | ||
60 | |||
61 | . = ALIGN(4096); | ||
62 | .data.page_aligned : { *(.data.idt) } | ||
63 | |||
64 | . = ALIGN(32); | ||
65 | .data.cacheline_aligned : { *(.data.cacheline_aligned) } | ||
66 | |||
67 | _edata = .; /* End of data section */ | ||
68 | |||
69 | . = ALIGN(8192); /* init_task */ | ||
70 | .data.init_task : { *(.data.init_task) } | ||
71 | |||
72 | /* will be freed after init */ | ||
73 | . = ALIGN(4096); /* Init code and data */ | ||
74 | __init_begin = .; | ||
75 | .init.text : { | ||
76 | _sinittext = .; | ||
77 | *(.init.text) | ||
78 | _einittext = .; | ||
79 | } | ||
80 | .init.data : { *(.init.data) } | ||
81 | . = ALIGN(16); | ||
82 | __setup_start = .; | ||
83 | .init.setup : { *(.init.setup) } | ||
84 | __setup_end = .; | ||
85 | __initcall_start = .; | ||
86 | .initcall.init : { | ||
87 | *(.initcall1.init) | ||
88 | *(.initcall2.init) | ||
89 | *(.initcall3.init) | ||
90 | *(.initcall4.init) | ||
91 | *(.initcall5.init) | ||
92 | *(.initcall6.init) | ||
93 | *(.initcall7.init) | ||
94 | } | ||
95 | __initcall_end = .; | ||
96 | __con_initcall_start = .; | ||
97 | .con_initcall.init : { *(.con_initcall.init) } | ||
98 | __con_initcall_end = .; | ||
99 | SECURITY_INIT | ||
100 | . = ALIGN(4); | ||
101 | __alt_instructions = .; | ||
102 | .altinstructions : { *(.altinstructions) } | ||
103 | __alt_instructions_end = .; | ||
104 | .altinstr_replacement : { *(.altinstr_replacement) } | ||
105 | /* .exit.text is discard at runtime, not link time, to deal with references | ||
106 | from .altinstructions and .eh_frame */ | ||
107 | .exit.text : { *(.exit.text) } | ||
108 | .exit.data : { *(.exit.data) } | ||
109 | . = ALIGN(4096); | ||
110 | __initramfs_start = .; | ||
111 | .init.ramfs : { *(.init.ramfs) } | ||
112 | __initramfs_end = .; | ||
113 | . = ALIGN(32); | ||
114 | __per_cpu_start = .; | ||
115 | .data.percpu : { *(.data.percpu) } | ||
116 | __per_cpu_end = .; | ||
117 | . = ALIGN(4096); | ||
118 | __init_end = .; | ||
119 | /* freed after init ends here */ | ||
120 | |||
121 | __bss_start = .; /* BSS */ | ||
122 | .bss : { *(.bss) } | ||
123 | . = ALIGN(4); | ||
124 | __bss_stop = .; | ||
125 | |||
126 | _end = . ; | ||
127 | |||
128 | /* Sections to be discarded */ | ||
129 | /DISCARD/ : { | ||
130 | *(.exit.text) | ||
131 | *(.exit.data) | ||
132 | *(.exitcall.exit) | ||
133 | } | ||
134 | |||
135 | /* Stabs debugging sections. */ | ||
136 | .stab 0 : { *(.stab) } | ||
137 | .stabstr 0 : { *(.stabstr) } | ||
138 | .stab.excl 0 : { *(.stab.excl) } | ||
139 | .stab.exclstr 0 : { *(.stab.exclstr) } | ||
140 | .stab.index 0 : { *(.stab.index) } | ||
141 | .stab.indexstr 0 : { *(.stab.indexstr) } | ||
142 | .comment 0 : { *(.comment) } | ||
143 | } | ||