aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r--arch/microblaze/kernel/Makefile19
-rw-r--r--arch/microblaze/kernel/asm-offsets.c115
-rw-r--r--arch/microblaze/kernel/cpu/Makefile8
-rw-r--r--arch/microblaze/kernel/cpu/cache.c255
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c106
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-static.c144
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c86
-rw-r--r--arch/microblaze/kernel/cpu/mb.c148
-rw-r--r--arch/microblaze/kernel/cpu/pvr.c81
-rw-r--r--arch/microblaze/kernel/early_printk.c107
-rw-r--r--arch/microblaze/kernel/entry-nommu.S596
-rw-r--r--arch/microblaze/kernel/exceptions.c124
-rw-r--r--arch/microblaze/kernel/head.S56
-rw-r--r--arch/microblaze/kernel/heartbeat.c67
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S458
-rw-r--r--arch/microblaze/kernel/init_task.c29
-rw-r--r--arch/microblaze/kernel/intc.c172
-rw-r--r--arch/microblaze/kernel/irq.c104
-rw-r--r--arch/microblaze/kernel/microblaze_ksyms.c47
-rw-r--r--arch/microblaze/kernel/module.c151
-rw-r--r--arch/microblaze/kernel/of_device.c113
-rw-r--r--arch/microblaze/kernel/of_platform.c201
-rw-r--r--arch/microblaze/kernel/process.c190
-rw-r--r--arch/microblaze/kernel/prom.c1146
-rw-r--r--arch/microblaze/kernel/prom_parse.c1025
-rw-r--r--arch/microblaze/kernel/ptrace.c181
-rw-r--r--arch/microblaze/kernel/selfmod.c81
-rw-r--r--arch/microblaze/kernel/setup.c199
-rw-r--r--arch/microblaze/kernel/signal.c543
-rw-r--r--arch/microblaze/kernel/sys_microblaze.c225
-rw-r--r--arch/microblaze/kernel/syscall_table.S367
-rw-r--r--arch/microblaze/kernel/timer.c262
-rw-r--r--arch/microblaze/kernel/traps.c107
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S163
34 files changed, 7676 insertions, 0 deletions
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
new file mode 100644
index 000000000000..da94bec4ecba
--- /dev/null
+++ b/arch/microblaze/kernel/Makefile
@@ -0,0 +1,19 @@
1#
2# Makefile
3#
4
5extra-y := head.o vmlinux.lds
6
7obj-y += exceptions.o \
8 hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
9 of_platform.o process.o prom.o prom_parse.o ptrace.o \
10 setup.o signal.o sys_microblaze.o timer.o traps.o
11
12obj-y += cpu/
13
14obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
15obj-$(CONFIG_SELFMOD) += selfmod.o
16obj-$(CONFIG_HEART_BEAT) += heartbeat.o
17obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
18
19obj-y += entry$(MMUEXT).o
diff --git a/arch/microblaze/kernel/asm-offsets.c b/arch/microblaze/kernel/asm-offsets.c
new file mode 100644
index 000000000000..aabd9e9423a6
--- /dev/null
+++ b/arch/microblaze/kernel/asm-offsets.c
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2007-2009 PetaLogix
3 * Copyright (C) 2006 Atmark Techno, Inc.
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file "COPYING" in the main directory of this archive
7 * for more details.
8 */
9
10#include <linux/init.h>
11#include <linux/stddef.h>
12#include <linux/sched.h>
13#include <linux/kernel_stat.h>
14#include <linux/ptrace.h>
15#include <linux/hardirq.h>
16#include <linux/thread_info.h>
17#include <linux/kbuild.h>
18
19int main(int argc, char *argv[])
20{
21 /* struct pt_regs */
22 DEFINE(PT_SIZE, sizeof(struct pt_regs));
23 DEFINE(PT_MSR, offsetof(struct pt_regs, msr));
24 DEFINE(PT_EAR, offsetof(struct pt_regs, ear));
25 DEFINE(PT_ESR, offsetof(struct pt_regs, esr));
26 DEFINE(PT_FSR, offsetof(struct pt_regs, fsr));
27 DEFINE(PT_PC, offsetof(struct pt_regs, pc));
28 DEFINE(PT_R0, offsetof(struct pt_regs, r0));
29 DEFINE(PT_R1, offsetof(struct pt_regs, r1));
30 DEFINE(PT_R2, offsetof(struct pt_regs, r2));
31 DEFINE(PT_R3, offsetof(struct pt_regs, r3));
32 DEFINE(PT_R4, offsetof(struct pt_regs, r4));
33 DEFINE(PT_R5, offsetof(struct pt_regs, r5));
34 DEFINE(PT_R6, offsetof(struct pt_regs, r6));
35 DEFINE(PT_R7, offsetof(struct pt_regs, r7));
36 DEFINE(PT_R8, offsetof(struct pt_regs, r8));
37 DEFINE(PT_R9, offsetof(struct pt_regs, r9));
38 DEFINE(PT_R10, offsetof(struct pt_regs, r10));
39 DEFINE(PT_R11, offsetof(struct pt_regs, r11));
40 DEFINE(PT_R12, offsetof(struct pt_regs, r12));
41 DEFINE(PT_R13, offsetof(struct pt_regs, r13));
42 DEFINE(PT_R14, offsetof(struct pt_regs, r14));
43 DEFINE(PT_R15, offsetof(struct pt_regs, r15));
44 DEFINE(PT_R16, offsetof(struct pt_regs, r16));
45 DEFINE(PT_R17, offsetof(struct pt_regs, r17));
46 DEFINE(PT_R18, offsetof(struct pt_regs, r18));
47 DEFINE(PT_R19, offsetof(struct pt_regs, r19));
48 DEFINE(PT_R20, offsetof(struct pt_regs, r20));
49 DEFINE(PT_R21, offsetof(struct pt_regs, r21));
50 DEFINE(PT_R22, offsetof(struct pt_regs, r22));
51 DEFINE(PT_R23, offsetof(struct pt_regs, r23));
52 DEFINE(PT_R24, offsetof(struct pt_regs, r24));
53 DEFINE(PT_R25, offsetof(struct pt_regs, r25));
54 DEFINE(PT_R26, offsetof(struct pt_regs, r26));
55 DEFINE(PT_R27, offsetof(struct pt_regs, r27));
56 DEFINE(PT_R28, offsetof(struct pt_regs, r28));
57 DEFINE(PT_R29, offsetof(struct pt_regs, r29));
58 DEFINE(PT_R30, offsetof(struct pt_regs, r30));
59 DEFINE(PT_R31, offsetof(struct pt_regs, r31));
60 DEFINE(PT_MODE, offsetof(struct pt_regs, pt_mode));
61 BLANK();
62
63 /* Magic offsets for PTRACE PEEK/POKE etc */
64 DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs) + 1);
65 DEFINE(PT_TEXT_LEN, sizeof(struct pt_regs) + 2);
66 DEFINE(PT_DATA_ADDR, sizeof(struct pt_regs) + 3);
67 BLANK();
68
69 /* struct task_struct */
70 DEFINE(TS_THREAD_INFO, offsetof(struct task_struct, stack));
71
72 /* struct thread_info */
73 DEFINE(TI_TASK, offsetof(struct thread_info, task));
74 DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
75 DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
76 DEFINE(TI_STATUS, offsetof(struct thread_info, status));
77 DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
78 DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
79 DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
80 DEFINE(TI_RESTART_BLOCK, offsetof(struct thread_info, restart_block));
81 DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
82 BLANK();
83
84 /* struct cpu_context */
85 DEFINE(CC_R1, offsetof(struct cpu_context, r1)); /* r1 */
86 DEFINE(CC_R2, offsetof(struct cpu_context, r2));
87 /* dedicated registers */
88 DEFINE(CC_R13, offsetof(struct cpu_context, r13));
89 DEFINE(CC_R14, offsetof(struct cpu_context, r14));
90 DEFINE(CC_R15, offsetof(struct cpu_context, r15));
91 DEFINE(CC_R16, offsetof(struct cpu_context, r16));
92 DEFINE(CC_R17, offsetof(struct cpu_context, r17));
93 DEFINE(CC_R18, offsetof(struct cpu_context, r18));
94 /* non-volatile registers */
95 DEFINE(CC_R19, offsetof(struct cpu_context, r19));
96 DEFINE(CC_R20, offsetof(struct cpu_context, r20));
97 DEFINE(CC_R21, offsetof(struct cpu_context, r21));
98 DEFINE(CC_R22, offsetof(struct cpu_context, r22));
99 DEFINE(CC_R23, offsetof(struct cpu_context, r23));
100 DEFINE(CC_R24, offsetof(struct cpu_context, r24));
101 DEFINE(CC_R25, offsetof(struct cpu_context, r25));
102 DEFINE(CC_R26, offsetof(struct cpu_context, r26));
103 DEFINE(CC_R27, offsetof(struct cpu_context, r27));
104 DEFINE(CC_R28, offsetof(struct cpu_context, r28));
105 DEFINE(CC_R29, offsetof(struct cpu_context, r29));
106 DEFINE(CC_R30, offsetof(struct cpu_context, r30));
107 /* special purpose registers */
108 DEFINE(CC_MSR, offsetof(struct cpu_context, msr));
109 DEFINE(CC_EAR, offsetof(struct cpu_context, ear));
110 DEFINE(CC_ESR, offsetof(struct cpu_context, esr));
111 DEFINE(CC_FSR, offsetof(struct cpu_context, fsr));
112 BLANK();
113
114 return 0;
115}
diff --git a/arch/microblaze/kernel/cpu/Makefile b/arch/microblaze/kernel/cpu/Makefile
new file mode 100644
index 000000000000..20646e549271
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/Makefile
@@ -0,0 +1,8 @@
1#
2# Build the appropriate CPU version support
3#
4
5EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
6 -DCPU_REV=$(CPU_REV)
7
8obj-y += cache.o cpuinfo.o cpuinfo-pvr-full.o cpuinfo-static.o mb.o pvr.o
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c
new file mode 100644
index 000000000000..af866a450125
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cache.c
@@ -0,0 +1,255 @@
1/*
2 * Cache control for MicroBlaze cache memories
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
11 */
12
13#include <asm/cacheflush.h>
14#include <linux/cache.h>
15#include <asm/cpuinfo.h>
16
17/* Exported functions */
18
19void _enable_icache(void)
20{
21 if (cpuinfo.use_icache) {
22#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
23 __asm__ __volatile__ (" \
24 msrset r0, %0; \
25 nop; " \
26 : \
27 : "i" (MSR_ICE) \
28 : "memory");
29#else
30 __asm__ __volatile__ (" \
31 mfs r12, rmsr; \
32 nop; \
33 ori r12, r12, %0; \
34 mts rmsr, r12; \
35 nop; " \
36 : \
37 : "i" (MSR_ICE) \
38 : "memory", "r12");
39#endif
40 }
41}
42
43void _disable_icache(void)
44{
45 if (cpuinfo.use_icache) {
46#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
47 __asm__ __volatile__ (" \
48 msrclr r0, %0; \
49 nop; " \
50 : \
51 : "i" (MSR_ICE) \
52 : "memory");
53#else
54 __asm__ __volatile__ (" \
55 mfs r12, rmsr; \
56 nop; \
57 andi r12, r12, ~%0; \
58 mts rmsr, r12; \
59 nop; " \
60 : \
61 : "i" (MSR_ICE) \
62 : "memory", "r12");
63#endif
64 }
65}
66
67void _invalidate_icache(unsigned int addr)
68{
69 if (cpuinfo.use_icache) {
70 __asm__ __volatile__ (" \
71 wic %0, r0" \
72 : \
73 : "r" (addr));
74 }
75}
76
77void _enable_dcache(void)
78{
79 if (cpuinfo.use_dcache) {
80#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
81 __asm__ __volatile__ (" \
82 msrset r0, %0; \
83 nop; " \
84 : \
85 : "i" (MSR_DCE) \
86 : "memory");
87#else
88 __asm__ __volatile__ (" \
89 mfs r12, rmsr; \
90 nop; \
91 ori r12, r12, %0; \
92 mts rmsr, r12; \
93 nop; " \
94 : \
95 : "i" (MSR_DCE) \
96 : "memory", "r12");
97#endif
98 }
99}
100
101void _disable_dcache(void)
102{
103#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
104 __asm__ __volatile__ (" \
105 msrclr r0, %0; \
106 nop; " \
107 : \
108 : "i" (MSR_DCE) \
109 : "memory");
110#else
111 __asm__ __volatile__ (" \
112 mfs r12, rmsr; \
113 nop; \
114 andi r12, r12, ~%0; \
115 mts rmsr, r12; \
116 nop; " \
117 : \
118 : "i" (MSR_DCE) \
119 : "memory", "r12");
120#endif
121}
122
123void _invalidate_dcache(unsigned int addr)
124{
125 __asm__ __volatile__ (" \
126 wdc %0, r0" \
127 : \
128 : "r" (addr));
129}
130
131void __invalidate_icache_all(void)
132{
133 unsigned int i;
134 unsigned flags;
135
136 if (cpuinfo.use_icache) {
137 local_irq_save(flags);
138 __disable_icache();
139
140 /* Just loop through cache size and invalidate, no need to add
141 CACHE_BASE address */
142 for (i = 0; i < cpuinfo.icache_size;
143 i += cpuinfo.icache_line)
144 __invalidate_icache(i);
145
146 __enable_icache();
147 local_irq_restore(flags);
148 }
149}
150
151void __invalidate_icache_range(unsigned long start, unsigned long end)
152{
153 unsigned int i;
154 unsigned flags;
155 unsigned int align;
156
157 if (cpuinfo.use_icache) {
158 /*
159 * No need to cover entire cache range,
160 * just cover cache footprint
161 */
162 end = min(start + cpuinfo.icache_size, end);
163 align = ~(cpuinfo.icache_line - 1);
164 start &= align; /* Make sure we are aligned */
165 /* Push end up to the next cache line */
166 end = ((end & align) + cpuinfo.icache_line);
167
168 local_irq_save(flags);
169 __disable_icache();
170
171 for (i = start; i < end; i += cpuinfo.icache_line)
172 __invalidate_icache(i);
173
174 __enable_icache();
175 local_irq_restore(flags);
176 }
177}
178
179void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
180{
181 __invalidate_icache_all();
182}
183
184void __invalidate_icache_user_range(struct vm_area_struct *vma,
185 struct page *page, unsigned long adr,
186 int len)
187{
188 __invalidate_icache_all();
189}
190
191void __invalidate_cache_sigtramp(unsigned long addr)
192{
193 __invalidate_icache_range(addr, addr + 8);
194}
195
196void __invalidate_dcache_all(void)
197{
198 unsigned int i;
199 unsigned flags;
200
201 if (cpuinfo.use_dcache) {
202 local_irq_save(flags);
203 __disable_dcache();
204
205 /*
206 * Just loop through cache size and invalidate,
207 * no need to add CACHE_BASE address
208 */
209 for (i = 0; i < cpuinfo.dcache_size;
210 i += cpuinfo.dcache_line)
211 __invalidate_dcache(i);
212
213 __enable_dcache();
214 local_irq_restore(flags);
215 }
216}
217
218void __invalidate_dcache_range(unsigned long start, unsigned long end)
219{
220 unsigned int i;
221 unsigned flags;
222 unsigned int align;
223
224 if (cpuinfo.use_dcache) {
225 /*
226 * No need to cover entire cache range,
227 * just cover cache footprint
228 */
229 end = min(start + cpuinfo.dcache_size, end);
230 align = ~(cpuinfo.dcache_line - 1);
231 start &= align; /* Make sure we are aligned */
232 /* Push end up to the next cache line */
233 end = ((end & align) + cpuinfo.dcache_line);
234 local_irq_save(flags);
235 __disable_dcache();
236
237 for (i = start; i < end; i += cpuinfo.dcache_line)
238 __invalidate_dcache(i);
239
240 __enable_dcache();
241 local_irq_restore(flags);
242 }
243}
244
245void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
246{
247 __invalidate_dcache_all();
248}
249
250void __invalidate_dcache_user_range(struct vm_area_struct *vma,
251 struct page *page, unsigned long adr,
252 int len)
253{
254 __invalidate_dcache_all();
255}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
new file mode 100644
index 000000000000..153f57c57b6d
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -0,0 +1,106 @@
1/*
2 * Support for MicroBlaze PVR (processor version register)
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/string.h>
15#include <asm/pvr.h>
16#include <asm/cpuinfo.h>
17
18/*
19 * Helper macro to map between fields in our struct cpuinfo, and
20 * the PVR macros in pvr.h.
21 */
22
23#define CI(c, p) { ci->c = PVR_##p(pvr); }
24#define err_printk(x) \
25 early_printk("ERROR: Microblaze " x " - different for PVR and DTS\n");
26
27void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
28{
29 struct pvr_s pvr;
30 int temp; /* for saving temp value */
31 get_pvr(&pvr);
32
33 CI(ver_code, VERSION);
34 if (!ci->ver_code) {
35 printk(KERN_ERR "ERROR: MB has broken PVR regs "
36 "-> use DTS setting\n");
37 return;
38 }
39
40 temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\
41 PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr);
42 if (ci->use_instr != temp)
43 err_printk("BARREL, MSR, PCMP or DIV");
44 ci->use_instr = temp;
45
46 temp = PVR_USE_HW_MUL(pvr) | PVR_USE_MUL64(pvr);
47 if (ci->use_mult != temp)
48 err_printk("HW_MUL");
49 ci->use_mult = temp;
50
51 temp = PVR_USE_FPU(pvr) | PVR_USE_FPU2(pvr);
52 if (ci->use_fpu != temp)
53 err_printk("HW_FPU");
54 ci->use_fpu = temp;
55
56 ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\
57 PVR_UNALIGNED_EXCEPTION(pvr) |\
58 PVR_ILL_OPCODE_EXCEPTION(pvr) |\
59 PVR_IOPB_BUS_EXCEPTION(pvr) |\
60 PVR_DOPB_BUS_EXCEPTION(pvr) |\
61 PVR_DIV_ZERO_EXCEPTION(pvr) |\
62 PVR_FPU_EXCEPTION(pvr) |\
63 PVR_FSL_EXCEPTION(pvr);
64
65 CI(pvr_user1, USER1);
66 CI(pvr_user2, USER2);
67
68 CI(mmu, USE_MMU);
69
70 CI(use_icache, USE_ICACHE);
71 CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
72 CI(icache_write, ICACHE_ALLOW_WR);
73 CI(icache_line, ICACHE_LINE_LEN);
74 CI(icache_size, ICACHE_BYTE_SIZE);
75 CI(icache_base, ICACHE_BASEADDR);
76 CI(icache_high, ICACHE_HIGHADDR);
77
78 CI(use_dcache, USE_DCACHE);
79 CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
80 CI(dcache_write, DCACHE_ALLOW_WR);
81 CI(dcache_line, DCACHE_LINE_LEN);
82 CI(dcache_size, DCACHE_BYTE_SIZE);
83 CI(dcache_base, DCACHE_BASEADDR);
84 CI(dcache_high, DCACHE_HIGHADDR);
85
86 CI(use_dopb, D_OPB);
87 CI(use_iopb, I_OPB);
88 CI(use_dlmb, D_LMB);
89 CI(use_ilmb, I_LMB);
90 CI(num_fsl, FSL_LINKS);
91
92 CI(irq_edge, INTERRUPT_IS_EDGE);
93 CI(irq_positive, EDGE_IS_POSITIVE);
94
95 CI(area_optimised, AREA_OPTIMISED);
96
97 CI(hw_debug, DEBUG_ENABLED);
98 CI(num_pc_brk, NUMBER_OF_PC_BRK);
99 CI(num_rd_brk, NUMBER_OF_RD_ADDR_BRK);
100 CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);
101
102 CI(fpga_family_code, TARGET_FAMILY);
103
104 /* take timebase-frequency from DTS */
105 ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
106}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
new file mode 100644
index 000000000000..450ca6bb828d
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c
@@ -0,0 +1,144 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/string.h>
14#include <asm/cpuinfo.h>
15#include <asm/pvr.h>
16
17static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
18static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
19
20#define err_printk(x) \
21 early_printk("ERROR: Microblaze " x "- different for kernel and DTS\n");
22
23void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
24{
25 int i = 0;
26
27 ci->use_instr =
28 (fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) |
29 (fcpu(cpu, "xlnx,use-msr-instr") ? PVR2_USE_MSR_INSTR : 0) |
30 (fcpu(cpu, "xlnx,use-pcmp-instr") ? PVR2_USE_PCMP_INSTR : 0) |
31 (fcpu(cpu, "xlnx,use-div") ? PVR0_USE_DIV_MASK : 0);
32 if (CONFIG_XILINX_MICROBLAZE0_USE_BARREL)
33 i |= PVR0_USE_BARREL_MASK;
34 if (CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR)
35 i |= PVR2_USE_MSR_INSTR;
36 if (CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR)
37 i |= PVR2_USE_PCMP_INSTR;
38 if (CONFIG_XILINX_MICROBLAZE0_USE_DIV)
39 i |= PVR0_USE_DIV_MASK;
40 if (ci->use_instr != i)
41 err_printk("BARREL, MSR, PCMP or DIV");
42
43 ci->use_mult = fcpu(cpu, "xlnx,use-hw-mul");
44 if (ci->use_mult != CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL)
45 err_printk("HW_MUL");
46 ci->use_mult =
47 (ci->use_mult > 1 ?
48 (PVR2_USE_MUL64_MASK | PVR0_USE_HW_MUL_MASK) :
49 (ci->use_mult == 1 ? PVR0_USE_HW_MUL_MASK : 0));
50
51 ci->use_fpu = fcpu(cpu, "xlnx,use-fpu");
52 if (ci->use_fpu != CONFIG_XILINX_MICROBLAZE0_USE_FPU)
53 err_printk("HW_FPU");
54 ci->use_fpu = (ci->use_fpu > 1 ?
55 (PVR2_USE_FPU2_MASK | PVR0_USE_FPU_MASK) :
56 (ci->use_fpu == 1 ? PVR0_USE_FPU_MASK : 0));
57
58 ci->use_exc =
59 (fcpu(cpu, "xlnx,unaligned-exceptions") ?
60 PVR2_UNALIGNED_EXC_MASK : 0) |
61 (fcpu(cpu, "xlnx,ill-opcode-exception") ?
62 PVR2_ILL_OPCODE_EXC_MASK : 0) |
63 (fcpu(cpu, "xlnx,iopb-bus-exception") ?
64 PVR2_IOPB_BUS_EXC_MASK : 0) |
65 (fcpu(cpu, "xlnx,dopb-bus-exception") ?
66 PVR2_DOPB_BUS_EXC_MASK : 0) |
67 (fcpu(cpu, "xlnx,div-zero-exception") ?
68 PVR2_DIV_ZERO_EXC_MASK : 0) |
69 (fcpu(cpu, "xlnx,fpu-exception") ? PVR2_FPU_EXC_MASK : 0) |
70 (fcpu(cpu, "xlnx,fsl-exception") ? PVR2_USE_EXTEND_FSL : 0);
71
72 ci->use_icache = fcpu(cpu, "xlnx,use-icache");
73 ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
74 ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
75 ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
76 if (!ci->icache_line) {
77 if (fcpu(cpu, "xlnx,icache-use-fsl"))
78 ci->icache_line = 4 << 2;
79 else
80 ci->icache_line = 1 << 2;
81 }
82 ci->icache_size = fcpu(cpu, "i-cache-size");
83 ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
84 ci->icache_high = fcpu(cpu, "i-cache-highaddr");
85
86 ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
87 ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
88 ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
89 ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
90 if (!ci->dcache_line) {
91 if (fcpu(cpu, "xlnx,dcache-use-fsl"))
92 ci->dcache_line = 4 << 2;
93 else
94 ci->dcache_line = 1 << 2;
95 }
96 ci->dcache_size = fcpu(cpu, "d-cache-size");
97 ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
98 ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
99
100 ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
101 ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
102 ci->use_dlmb = fcpu(cpu, "xlnx,d-lmb");
103 ci->use_ilmb = fcpu(cpu, "xlnx,i-lmb");
104
105 ci->num_fsl = fcpu(cpu, "xlnx,fsl-links");
106 ci->irq_edge = fcpu(cpu, "xlnx,interrupt-is-edge");
107 ci->irq_positive = fcpu(cpu, "xlnx,edge-is-positive");
108 ci->area_optimised = 0;
109
110 ci->hw_debug = fcpu(cpu, "xlnx,debug-enabled");
111 ci->num_pc_brk = fcpu(cpu, "xlnx,number-of-pc-brk");
112 ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
113 ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");
114
115 ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
116
117 ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");
118 ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
119
120 ci->mmu = fcpu(cpu, "xlnx,use-mmu");
121
122 ci->ver_code = 0;
123 ci->fpga_family_code = 0;
124
125 /* Do various fixups based on CPU version and FPGA family strings */
126
127 /* Resolved the CPU version code */
128 for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
129 if (strcmp(cpu_ver_lookup[i].s, cpu_ver_string) == 0)
130 ci->ver_code = cpu_ver_lookup[i].k;
131 }
132
133 /* Resolved the fpga family code */
134 for (i = 0; family_string_lookup[i].s != NULL; i++) {
135 if (strcmp(family_string_lookup[i].s, family_string) == 0)
136 ci->fpga_family_code = family_string_lookup[i].k;
137 }
138
139 /* FIXME - mb3 and spartan2 do not exist in PVR */
140 /* This is mb3 and on a non Spartan2 */
141 if (ci->ver_code == 0x20 && ci->fpga_family_code != 0xf0)
142 /* Hardware Multiplier in use */
143 ci->use_mult = 1;
144}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
new file mode 100644
index 000000000000..a10bea119b94
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/slab.h>
13#include <asm/cpuinfo.h>
14#include <asm/pvr.h>
15
16const struct cpu_ver_key cpu_ver_lookup[] = {
17 /* These key value are as per MBV field in PVR0 */
18 {"5.00.a", 0x01},
19 {"5.00.b", 0x02},
20 {"5.00.c", 0x03},
21 {"6.00.a", 0x04},
22 {"6.00.b", 0x06},
23 {"7.00.a", 0x05},
24 {"7.00.b", 0x07},
25 {"7.10.a", 0x08},
26 {"7.10.b", 0x09},
27 {"7.10.c", 0x0a},
28 {"7.10.d", 0x0b},
29 /* FIXME There is no keycode defined in MBV for these versions */
30 {"2.10.a", 0x10},
31 {"3.00.a", 0x20},
32 {"4.00.a", 0x30},
33 {"4.00.b", 0x40},
34 {NULL, 0},
35};
36
37/*
38 * FIXME Not sure if the actual key is defined by Xilinx in the PVR
39 */
40const struct family_string_key family_string_lookup[] = {
41 {"virtex2", 0x4},
42 {"virtex2pro", 0x5},
43 {"spartan3", 0x6},
44 {"virtex4", 0x7},
45 {"virtex5", 0x8},
46 {"spartan3e", 0x9},
47 {"spartan3a", 0xa},
48 {"spartan3an", 0xb},
49 {"spartan3adsp", 0xc},
50 /* FIXME There is no key code defined for spartan2 */
51 {"spartan2", 0xf0},
52 {NULL, 0},
53};
54
55struct cpuinfo cpuinfo;
56
57void __init setup_cpuinfo(void)
58{
59 struct device_node *cpu = NULL;
60
61 cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");
62 if (!cpu)
63 printk(KERN_ERR "You don't have cpu!!!\n");
64
65 printk(KERN_INFO "%s: initialising\n", __func__);
66
67 switch (cpu_has_pvr()) {
68 case 0:
69 printk(KERN_WARNING
70 "%s: No PVR support. Using static CPU info from FDT\n",
71 __func__);
72 set_cpuinfo_static(&cpuinfo, cpu);
73 break;
74/* FIXME I found weird behavior with MB 7.00.a/b 7.10.a
75 * please do not use FULL PVR with MMU */
76 case 1:
77 printk(KERN_INFO "%s: Using full CPU PVR support\n",
78 __func__);
79 set_cpuinfo_static(&cpuinfo, cpu);
80 set_cpuinfo_pvr_full(&cpuinfo, cpu);
81 break;
82 default:
83 printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__);
84 set_cpuinfo_static(&cpuinfo, cpu);
85 }
86}
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c
new file mode 100644
index 000000000000..4dcfccdbc364
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/mb.c
@@ -0,0 +1,148 @@
1/*
2 * CPU-version specific code
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2006-2009 PetaLogix
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11
12#include <linux/init.h>
13#include <linux/string.h>
14#include <linux/seq_file.h>
15#include <linux/cpu.h>
16#include <linux/initrd.h>
17
18#include <linux/bug.h>
19#include <asm/cpuinfo.h>
20#include <linux/delay.h>
21#include <linux/io.h>
22#include <asm/page.h>
23#include <linux/param.h>
24#include <asm/pvr.h>
25#include <asm/sections.h>
26#include <asm/setup.h>
27
28static int show_cpuinfo(struct seq_file *m, void *v)
29{
30 int count = 0;
31 char *fpga_family = "Unknown";
32 char *cpu_ver = "Unknown";
33 int i;
34
35 /* Denormalised to get the fpga family string */
36 for (i = 0; family_string_lookup[i].s != NULL; i++) {
37 if (cpuinfo.fpga_family_code == family_string_lookup[i].k) {
38 fpga_family = (char *)family_string_lookup[i].s;
39 break;
40 }
41 }
42
43 /* Denormalised to get the hw version string */
44 for (i = 0; cpu_ver_lookup[i].s != NULL; i++) {
45 if (cpuinfo.ver_code == cpu_ver_lookup[i].k) {
46 cpu_ver = (char *)cpu_ver_lookup[i].s;
47 break;
48 }
49 }
50
51 count = seq_printf(m,
52 "CPU-Family: MicroBlaze\n"
53 "FPGA-Arch: %s\n"
54 "CPU-Ver: %s\n"
55 "CPU-MHz: %d.%02d\n"
56 "BogoMips: %lu.%02lu\n",
57 fpga_family,
58 cpu_ver,
59 cpuinfo.cpu_clock_freq /
60 1000000,
61 cpuinfo.cpu_clock_freq %
62 1000000,
63 loops_per_jiffy / (500000 / HZ),
64 (loops_per_jiffy / (5000 / HZ)) % 100);
65
66 count += seq_printf(m,
67 "HW:\n Shift:\t\t%s\n"
68 " MSR:\t\t%s\n"
69 " PCMP:\t\t%s\n"
70 " DIV:\t\t%s\n",
71 (cpuinfo.use_instr & PVR0_USE_BARREL_MASK) ? "yes" : "no",
72 (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) ? "yes" : "no",
73 (cpuinfo.use_instr & PVR2_USE_PCMP_INSTR) ? "yes" : "no",
74 (cpuinfo.use_instr & PVR0_USE_DIV_MASK) ? "yes" : "no");
75
76 count += seq_printf(m,
77 " MMU:\t\t%x\n",
78 cpuinfo.mmu);
79
80 count += seq_printf(m,
81 " MUL:\t\t%s\n"
82 " FPU:\t\t%s\n",
83 (cpuinfo.use_mult & PVR2_USE_MUL64_MASK) ? "v2" :
84 (cpuinfo.use_mult & PVR0_USE_HW_MUL_MASK) ? "v1" : "no",
85 (cpuinfo.use_fpu & PVR2_USE_FPU2_MASK) ? "v2" :
86 (cpuinfo.use_fpu & PVR0_USE_FPU_MASK) ? "v1" : "no");
87
88 count += seq_printf(m,
89 " Exc:\t\t%s%s%s%s%s%s%s%s\n",
90 (cpuinfo.use_exc & PVR2_OPCODE_0x0_ILL_MASK) ? "op0x0 " : "",
91 (cpuinfo.use_exc & PVR2_UNALIGNED_EXC_MASK) ? "unal " : "",
92 (cpuinfo.use_exc & PVR2_ILL_OPCODE_EXC_MASK) ? "ill " : "",
93 (cpuinfo.use_exc & PVR2_IOPB_BUS_EXC_MASK) ? "iopb " : "",
94 (cpuinfo.use_exc & PVR2_DOPB_BUS_EXC_MASK) ? "dopb " : "",
95 (cpuinfo.use_exc & PVR2_DIV_ZERO_EXC_MASK) ? "zero " : "",
96 (cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "",
97 (cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : "");
98
99 if (cpuinfo.use_icache)
100 count += seq_printf(m,
101 "Icache:\t\t%ukB\n",
102 cpuinfo.icache_size >> 10);
103 else
104 count += seq_printf(m, "Icache:\t\tno\n");
105
106 if (cpuinfo.use_dcache)
107 count += seq_printf(m,
108 "Dcache:\t\t%ukB\n",
109 cpuinfo.dcache_size >> 10);
110 else
111 count += seq_printf(m, "Dcache:\t\tno\n");
112
113 count += seq_printf(m,
114 "HW-Debug:\t%s\n",
115 cpuinfo.hw_debug ? "yes" : "no");
116
117 count += seq_printf(m,
118 "PVR-USR1:\t%02x\n"
119 "PVR-USR2:\t%08x\n",
120 cpuinfo.pvr_user1,
121 cpuinfo.pvr_user2);
122
123 return 0;
124}
125
126static void *c_start(struct seq_file *m, loff_t *pos)
127{
128 int i = *pos;
129
130 return i < NR_CPUS ? (void *) (i + 1) : NULL;
131}
132
133static void *c_next(struct seq_file *m, void *v, loff_t *pos)
134{
135 ++*pos;
136 return c_start(m, pos);
137}
138
139static void c_stop(struct seq_file *m, void *v)
140{
141}
142
143const struct seq_operations cpuinfo_op = {
144 .start = c_start,
145 .next = c_next,
146 .stop = c_stop,
147 .show = show_cpuinfo,
148};
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
new file mode 100644
index 000000000000..c9a4340ddd53
--- /dev/null
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -0,0 +1,81 @@
1/*
2 * Support for MicroBlaze PVR (processor version register)
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/compiler.h>
15#include <asm/system.h>
16#include <asm/exceptions.h>
17#include <asm/pvr.h>
18
19/*
20 * Until we get an assembler that knows about the pvr registers,
21 * this horrible cruft will have to do.
22 * That hardcoded opcode is mfs r3, rpvrNN
23 */
24
25#define get_single_pvr(pvrid, val) \
26{ \
27 register unsigned tmp __asm__("r3"); \
28 tmp = 0x0; /* Prevent warning about unused */ \
29 __asm__ __volatile__ ( \
30 ".byte 0x94,0x60,0xa0, " #pvrid "\n\t" \
31 : "=r" (tmp) : : "memory"); \
32 val = tmp; \
33}
34
35/*
36 * Does the CPU support the PVR register?
37 * return value:
38 * 0: no PVR
39 * 1: simple PVR
40 * 2: full PVR
41 *
42 * This must work on all CPU versions, including those before the
43 * PVR was even an option.
44 */
45
46int cpu_has_pvr(void)
47{
48 unsigned flags;
49 unsigned pvr0;
50
51 local_save_flags(flags);
52
53 /* PVR bit in MSR tells us if there is any support */
54 if (!(flags & PVR_MSR_BIT))
55 return 0;
56
57 get_single_pvr(0x00, pvr0);
58 pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
59
60 if (pvr0 & PVR0_PVR_FULL_MASK)
61 return 1;
62
63 /* for partial PVR use static cpuinfo */
64 return 2;
65}
66
67void get_pvr(struct pvr_s *p)
68{
69 get_single_pvr(0, p->pvr[0]);
70 get_single_pvr(1, p->pvr[1]);
71 get_single_pvr(2, p->pvr[2]);
72 get_single_pvr(3, p->pvr[3]);
73 get_single_pvr(4, p->pvr[4]);
74 get_single_pvr(5, p->pvr[5]);
75 get_single_pvr(6, p->pvr[6]);
76 get_single_pvr(7, p->pvr[7]);
77 get_single_pvr(8, p->pvr[8]);
78 get_single_pvr(9, p->pvr[9]);
79 get_single_pvr(10, p->pvr[10]);
80 get_single_pvr(11, p->pvr[11]);
81}
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
new file mode 100644
index 000000000000..4b0f0fdb9ca0
--- /dev/null
+++ b/arch/microblaze/kernel/early_printk.c
@@ -0,0 +1,107 @@
1/*
2 * Early printk support for Microblaze.
3 *
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2003-2006 Yasushi SHOJI <yashi@atmark-techno.com>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/console.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/string.h>
17#include <linux/tty.h>
18#include <linux/io.h>
19#include <asm/processor.h>
20#include <linux/fcntl.h>
21#include <asm/setup.h>
22#include <asm/prom.h>
23
24static u32 early_console_initialized;
25static u32 base_addr;
26
27static void early_printk_putc(char c)
28{
29 /*
30 * Limit how many times we'll spin waiting for TX FIFO status.
31 * This will prevent lockups if the base address is incorrectly
32 * set, or any other issue on the UARTLITE.
33 * This limit is pretty arbitrary, unless we are at about 10 baud
34 * we'll never timeout on a working UART.
35 */
36
37 unsigned retries = 10000;
38 /* read status bit - 0x8 offset */
39 while (--retries && (in_be32(base_addr + 8) & (1 << 3)))
40 ;
41
42 /* Only attempt the iowrite if we didn't timeout */
43 /* write to TX_FIFO - 0x4 offset */
44 if (retries)
45 out_be32(base_addr + 4, c & 0xff);
46}
47
48static void early_printk_write(struct console *unused,
49 const char *s, unsigned n)
50{
51 while (*s && n-- > 0) {
52 early_printk_putc(*s);
53 if (*s == '\n')
54 early_printk_putc('\r');
55 s++;
56 }
57}
58
59static struct console early_serial_console = {
60 .name = "earlyser",
61 .write = early_printk_write,
62 .flags = CON_PRINTBUFFER,
63 .index = -1,
64};
65
66static struct console *early_console = &early_serial_console;
67
68void early_printk(const char *fmt, ...)
69{
70 char buf[512];
71 int n;
72 va_list ap;
73
74 if (early_console_initialized) {
75 va_start(ap, fmt);
76 n = vscnprintf(buf, 512, fmt, ap);
77 early_console->write(early_console, buf, n);
78 va_end(ap);
79 }
80}
81
82int __init setup_early_printk(char *opt)
83{
84 if (early_console_initialized)
85 return 1;
86
87 base_addr = early_uartlite_console();
88 if (base_addr) {
89 early_console_initialized = 1;
90 early_printk("early_printk_console is enabled at 0x%08x\n",
91 base_addr);
92
93 /* register_console(early_console); */
94
95 return 0;
96 } else
97 return 1;
98}
99
100void __init disable_early_printk(void)
101{
102 if (!early_console_initialized || !early_console)
103 return;
104 printk(KERN_WARNING "disabling early console\n");
105 unregister_console(early_console);
106 early_console_initialized = 0;
107}
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
new file mode 100644
index 000000000000..f24b1268baaf
--- /dev/null
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -0,0 +1,596 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/linkage.h>
12#include <asm/thread_info.h>
13#include <asm/errno.h>
14#include <asm/entry.h>
15#include <asm/asm-offsets.h>
16#include <asm/registers.h>
17#include <asm/unistd.h>
18#include <asm/percpu.h>
19#include <asm/signal.h>
20
21#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
22 .macro disable_irq
23 msrclr r0, MSR_IE
24 .endm
25
26 .macro enable_irq
27 msrset r0, MSR_IE
28 .endm
29
30 .macro clear_bip
31 msrclr r0, MSR_BIP
32 .endm
33#else
34 .macro disable_irq
35 mfs r11, rmsr
36 andi r11, r11, ~MSR_IE
37 mts rmsr, r11
38 .endm
39
40 .macro enable_irq
41 mfs r11, rmsr
42 ori r11, r11, MSR_IE
43 mts rmsr, r11
44 .endm
45
46 .macro clear_bip
47 mfs r11, rmsr
48 andi r11, r11, ~MSR_BIP
49 mts rmsr, r11
50 .endm
51#endif
52
53ENTRY(_interrupt)
54 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
55 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
56 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
57 beqid r11, 1f
58 nop
59 brid 2f /* jump over */
60 addik r1, r1, (-PT_SIZE) /* room for pt_regs (delay slot) */
611: /* switch to kernel stack */
62 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
63 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
64 /* calculate kernel stack pointer */
65 addik r1, r1, THREAD_SIZE - PT_SIZE
662:
67 swi r11, r1, PT_MODE /* store the mode */
68 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
69 swi r2, r1, PT_R2
70 swi r3, r1, PT_R3
71 swi r4, r1, PT_R4
72 swi r5, r1, PT_R5
73 swi r6, r1, PT_R6
74 swi r7, r1, PT_R7
75 swi r8, r1, PT_R8
76 swi r9, r1, PT_R9
77 swi r10, r1, PT_R10
78 swi r11, r1, PT_R11
79 swi r12, r1, PT_R12
80 swi r13, r1, PT_R13
81 swi r14, r1, PT_R14
82 swi r14, r1, PT_PC
83 swi r15, r1, PT_R15
84 swi r16, r1, PT_R16
85 swi r17, r1, PT_R17
86 swi r18, r1, PT_R18
87 swi r19, r1, PT_R19
88 swi r20, r1, PT_R20
89 swi r21, r1, PT_R21
90 swi r22, r1, PT_R22
91 swi r23, r1, PT_R23
92 swi r24, r1, PT_R24
93 swi r25, r1, PT_R25
94 swi r26, r1, PT_R26
95 swi r27, r1, PT_R27
96 swi r28, r1, PT_R28
97 swi r29, r1, PT_R29
98 swi r30, r1, PT_R30
99 swi r31, r1, PT_R31
100 /* special purpose registers */
101 mfs r11, rmsr
102 swi r11, r1, PT_MSR
103 mfs r11, rear
104 swi r11, r1, PT_EAR
105 mfs r11, resr
106 swi r11, r1, PT_ESR
107 mfs r11, rfsr
108 swi r11, r1, PT_FSR
109 /* reload original stack pointer and save it */
110 lwi r11, r0, PER_CPU(ENTRY_SP)
111 swi r11, r1, PT_R1
112 /* update mode indicator we are in kernel mode */
113 addik r11, r0, 1
114 swi r11, r0, PER_CPU(KM)
115 /* restore r31 */
116 lwi r31, r0, PER_CPU(CURRENT_SAVE)
117 /* prepare the link register, the argument and jump */
118 la r15, r0, ret_from_intr - 8
119 addk r6, r0, r15
120 braid do_IRQ
121 add r5, r0, r1
122
123ret_from_intr:
124 lwi r11, r1, PT_MODE
125 bneid r11, 3f
126
127 lwi r6, r31, TS_THREAD_INFO /* get thread info */
128 lwi r19, r6, TI_FLAGS /* get flags in thread info */
129 /* do an extra work if any bits are set */
130
131 andi r11, r19, _TIF_NEED_RESCHED
132 beqi r11, 1f
133 bralid r15, schedule
134 nop
1351: andi r11, r19, _TIF_SIGPENDING
136 beqid r11, no_intr_reshed
137 addk r5, r1, r0
138 addk r7, r0, r0
139 bralid r15, do_signal
140 addk r6, r0, r0
141
142no_intr_reshed:
143 /* save mode indicator */
144 lwi r11, r1, PT_MODE
1453:
146 swi r11, r0, PER_CPU(KM)
147
148 /* save r31 */
149 swi r31, r0, PER_CPU(CURRENT_SAVE)
150restore_context:
151 /* special purpose registers */
152 lwi r11, r1, PT_FSR
153 mts rfsr, r11
154 lwi r11, r1, PT_ESR
155 mts resr, r11
156 lwi r11, r1, PT_EAR
157 mts rear, r11
158 lwi r11, r1, PT_MSR
159 mts rmsr, r11
160
161 lwi r31, r1, PT_R31
162 lwi r30, r1, PT_R30
163 lwi r29, r1, PT_R29
164 lwi r28, r1, PT_R28
165 lwi r27, r1, PT_R27
166 lwi r26, r1, PT_R26
167 lwi r25, r1, PT_R25
168 lwi r24, r1, PT_R24
169 lwi r23, r1, PT_R23
170 lwi r22, r1, PT_R22
171 lwi r21, r1, PT_R21
172 lwi r20, r1, PT_R20
173 lwi r19, r1, PT_R19
174 lwi r18, r1, PT_R18
175 lwi r17, r1, PT_R17
176 lwi r16, r1, PT_R16
177 lwi r15, r1, PT_R15
178 lwi r14, r1, PT_PC
179 lwi r13, r1, PT_R13
180 lwi r12, r1, PT_R12
181 lwi r11, r1, PT_R11
182 lwi r10, r1, PT_R10
183 lwi r9, r1, PT_R9
184 lwi r8, r1, PT_R8
185 lwi r7, r1, PT_R7
186 lwi r6, r1, PT_R6
187 lwi r5, r1, PT_R5
188 lwi r4, r1, PT_R4
189 lwi r3, r1, PT_R3
190 lwi r2, r1, PT_R2
191 lwi r1, r1, PT_R1
192 rtid r14, 0
193 nop
194
195ENTRY(_reset)
196 brai 0;
197
198ENTRY(_user_exception)
199 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
200 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
201 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
202 beqid r11, 1f /* Already in kernel mode? */
203 nop
204 brid 2f /* jump over */
205 addik r1, r1, (-PT_SIZE) /* Room for pt_regs (delay slot) */
2061: /* Switch to kernel stack */
207 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
208 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
209 /* calculate kernel stack pointer */
210 addik r1, r1, THREAD_SIZE - PT_SIZE
211 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
212 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
2132:
214 swi r11, r1, PT_MODE /* store the mode */
215 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
216 /* save them on stack */
217 swi r2, r1, PT_R2
218 swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
219 swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
220 swi r5, r1, PT_R5
221 swi r6, r1, PT_R6
222 swi r7, r1, PT_R7
223 swi r8, r1, PT_R8
224 swi r9, r1, PT_R9
225 swi r10, r1, PT_R10
226 swi r11, r1, PT_R11
227 /* r12: _always_ in clobber list; see unistd.h */
228 swi r12, r1, PT_R12
229 swi r13, r1, PT_R13
230 /* r14: _always_ in clobber list; see unistd.h */
231 swi r14, r1, PT_R14
232 /* but we want to return to the next inst. */
233 addik r14, r14, 0x4
234 swi r14, r1, PT_PC /* increment by 4 and store in pc */
235 swi r15, r1, PT_R15
236 swi r16, r1, PT_R16
237 swi r17, r1, PT_R17
238 swi r18, r1, PT_R18
239 swi r19, r1, PT_R19
240 swi r20, r1, PT_R20
241 swi r21, r1, PT_R21
242 swi r22, r1, PT_R22
243 swi r23, r1, PT_R23
244 swi r24, r1, PT_R24
245 swi r25, r1, PT_R25
246 swi r26, r1, PT_R26
247 swi r27, r1, PT_R27
248 swi r28, r1, PT_R28
249 swi r29, r1, PT_R29
250 swi r30, r1, PT_R30
251 swi r31, r1, PT_R31
252
253 disable_irq
254 nop /* make sure IE bit is in effect */
255 clear_bip /* once IE is in effect it is safe to clear BIP */
256 nop
257
258 /* special purpose registers */
259 mfs r11, rmsr
260 swi r11, r1, PT_MSR
261 mfs r11, rear
262 swi r11, r1, PT_EAR
263 mfs r11, resr
264 swi r11, r1, PT_ESR
265 mfs r11, rfsr
266 swi r11, r1, PT_FSR
267 /* reload original stack pointer and save it */
268 lwi r11, r0, PER_CPU(ENTRY_SP)
269 swi r11, r1, PT_R1
270 /* update mode indicator we are in kernel mode */
271 addik r11, r0, 1
272 swi r11, r0, PER_CPU(KM)
273 /* restore r31 */
274 lwi r31, r0, PER_CPU(CURRENT_SAVE)
275 /* re-enable interrupts now we are in kernel mode */
276 enable_irq
277
278 /* See if the system call number is valid. */
279 addi r11, r12, -__NR_syscalls
280 bgei r11, 1f /* return to user if not valid */
281 /* Figure out which function to use for this system call. */
282 /* Note Microblaze barrel shift is optional, so don't rely on it */
283 add r12, r12, r12 /* convert num -> ptr */
284 add r12, r12, r12
285 lwi r12, r12, sys_call_table /* Get function pointer */
286 la r15, r0, ret_to_user-8 /* set return address */
287 bra r12 /* Make the system call. */
288 bri 0 /* won't reach here */
2891:
290 brid ret_to_user /* jump to syscall epilogue */
291 addi r3, r0, -ENOSYS /* set errno in delay slot */
292
293/*
294 * Debug traps are like a system call, but entered via brki r14, 0x60
295 * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
296 * will handle the rest
297 */
298ENTRY(_debug_exception)
299 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
300 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
301 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
302 addik r1, r1, THREAD_SIZE - PT_SIZE /* get the kernel stack */
303 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
304 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
305//save_context:
306 swi r11, r1, PT_MODE /* store the mode */
307 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
308 /* save them on stack */
309 swi r2, r1, PT_R2
310 swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
311 swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
312 swi r5, r1, PT_R5
313 swi r6, r1, PT_R6
314 swi r7, r1, PT_R7
315 swi r8, r1, PT_R8
316 swi r9, r1, PT_R9
317 swi r10, r1, PT_R10
318 swi r11, r1, PT_R11
319 /* r12: _always_ in clobber list; see unistd.h */
320 swi r12, r1, PT_R12
321 swi r13, r1, PT_R13
322 /* r14: _always_ in clobber list; see unistd.h */
323 swi r14, r1, PT_R14
324 swi r14, r1, PT_PC /* Will return to interrupted instruction */
325 swi r15, r1, PT_R15
326 swi r16, r1, PT_R16
327 swi r17, r1, PT_R17
328 swi r18, r1, PT_R18
329 swi r19, r1, PT_R19
330 swi r20, r1, PT_R20
331 swi r21, r1, PT_R21
332 swi r22, r1, PT_R22
333 swi r23, r1, PT_R23
334 swi r24, r1, PT_R24
335 swi r25, r1, PT_R25
336 swi r26, r1, PT_R26
337 swi r27, r1, PT_R27
338 swi r28, r1, PT_R28
339 swi r29, r1, PT_R29
340 swi r30, r1, PT_R30
341 swi r31, r1, PT_R31
342
343 disable_irq
344 nop /* make sure IE bit is in effect */
345 clear_bip /* once IE is in effect it is safe to clear BIP */
346 nop
347
348 /* special purpose registers */
349 mfs r11, rmsr
350 swi r11, r1, PT_MSR
351 mfs r11, rear
352 swi r11, r1, PT_EAR
353 mfs r11, resr
354 swi r11, r1, PT_ESR
355 mfs r11, rfsr
356 swi r11, r1, PT_FSR
357 /* reload original stack pointer and save it */
358 lwi r11, r0, PER_CPU(ENTRY_SP)
359 swi r11, r1, PT_R1
360 /* update mode indicator we are in kernel mode */
361 addik r11, r0, 1
362 swi r11, r0, PER_CPU(KM)
363 /* restore r31 */
364 lwi r31, r0, PER_CPU(CURRENT_SAVE)
365 /* re-enable interrupts now we are in kernel mode */
366 enable_irq
367
368 addi r5, r0, SIGTRAP /* sending the trap signal */
369 add r6, r0, r31 /* to current */
370 bralid r15, send_sig
371 add r7, r0, r0 /* 3rd param zero */
372
373 /* Restore r3/r4 to work around how ret_to_user works */
374 lwi r3, r1, PT_R3
375 lwi r4, r1, PT_R4
376 bri ret_to_user
377
378ENTRY(_break)
379 bri 0
380
381/* struct task_struct *_switch_to(struct thread_info *prev,
382 struct thread_info *next); */
383ENTRY(_switch_to)
384 /* prepare return value */
385 addk r3, r0, r31
386
387 /* save registers in cpu_context */
388 /* use r11 and r12, volatile registers, as temp register */
389 addik r11, r5, TI_CPU_CONTEXT
390 swi r1, r11, CC_R1
391 swi r2, r11, CC_R2
392 /* skip volatile registers.
393 * they are saved on stack when we jumped to _switch_to() */
394 /* dedicated registers */
395 swi r13, r11, CC_R13
396 swi r14, r11, CC_R14
397 swi r15, r11, CC_R15
398 swi r16, r11, CC_R16
399 swi r17, r11, CC_R17
400 swi r18, r11, CC_R18
401 /* save non-volatile registers */
402 swi r19, r11, CC_R19
403 swi r20, r11, CC_R20
404 swi r21, r11, CC_R21
405 swi r22, r11, CC_R22
406 swi r23, r11, CC_R23
407 swi r24, r11, CC_R24
408 swi r25, r11, CC_R25
409 swi r26, r11, CC_R26
410 swi r27, r11, CC_R27
411 swi r28, r11, CC_R28
412 swi r29, r11, CC_R29
413 swi r30, r11, CC_R30
414 /* special purpose registers */
415 mfs r12, rmsr
416 swi r12, r11, CC_MSR
417 mfs r12, rear
418 swi r12, r11, CC_EAR
419 mfs r12, resr
420 swi r12, r11, CC_ESR
421 mfs r12, rfsr
422 swi r12, r11, CC_FSR
423
424 /* update r31, the current */
425 lwi r31, r6, TI_TASK
426 swi r31, r0, PER_CPU(CURRENT_SAVE)
427
428 /* get new process' cpu context and restore */
429 addik r11, r6, TI_CPU_CONTEXT
430
431 /* special purpose registers */
432 lwi r12, r11, CC_FSR
433 mts rfsr, r12
434 lwi r12, r11, CC_ESR
435 mts resr, r12
436 lwi r12, r11, CC_EAR
437 mts rear, r12
438 lwi r12, r11, CC_MSR
439 mts rmsr, r12
440 /* non-volatile registers */
441 lwi r30, r11, CC_R30
442 lwi r29, r11, CC_R29
443 lwi r28, r11, CC_R28
444 lwi r27, r11, CC_R27
445 lwi r26, r11, CC_R26
446 lwi r25, r11, CC_R25
447 lwi r24, r11, CC_R24
448 lwi r23, r11, CC_R23
449 lwi r22, r11, CC_R22
450 lwi r21, r11, CC_R21
451 lwi r20, r11, CC_R20
452 lwi r19, r11, CC_R19
453 /* dedicated registers */
454 lwi r18, r11, CC_R18
455 lwi r17, r11, CC_R17
456 lwi r16, r11, CC_R16
457 lwi r15, r11, CC_R15
458 lwi r14, r11, CC_R14
459 lwi r13, r11, CC_R13
460 /* skip volatile registers */
461 lwi r2, r11, CC_R2
462 lwi r1, r11, CC_R1
463
464 rtsd r15, 8
465 nop
466
467ENTRY(ret_from_fork)
468 addk r5, r0, r3
469 addk r6, r0, r1
470 brlid r15, schedule_tail
471 nop
472 swi r31, r1, PT_R31 /* save r31 in user context. */
473 /* will soon be restored to r31 in ret_to_user */
474 addk r3, r0, r0
475 brid ret_to_user
476 nop
477
478work_pending:
479 andi r11, r19, _TIF_NEED_RESCHED
480 beqi r11, 1f
481 bralid r15, schedule
482 nop
4831: andi r11, r19, _TIF_SIGPENDING
484 beqi r11, no_work_pending
485 addk r5, r1, r0
486 addik r7, r0, 1
487 bralid r15, do_signal
488 addk r6, r0, r0
489 bri no_work_pending
490
491ENTRY(ret_to_user)
492 disable_irq
493
494 swi r4, r1, PT_R4 /* return val */
495 swi r3, r1, PT_R3 /* return val */
496
497 lwi r6, r31, TS_THREAD_INFO /* get thread info */
498 lwi r19, r6, TI_FLAGS /* get flags in thread info */
499 bnei r19, work_pending /* do an extra work if any bits are set */
500no_work_pending:
501 disable_irq
502
503 /* save r31 */
504 swi r31, r0, PER_CPU(CURRENT_SAVE)
505 /* save mode indicator */
506 lwi r18, r1, PT_MODE
507 swi r18, r0, PER_CPU(KM)
508//restore_context:
509 /* special purpose registers */
510 lwi r18, r1, PT_FSR
511 mts rfsr, r18
512 lwi r18, r1, PT_ESR
513 mts resr, r18
514 lwi r18, r1, PT_EAR
515 mts rear, r18
516 lwi r18, r1, PT_MSR
517 mts rmsr, r18
518
519 lwi r31, r1, PT_R31
520 lwi r30, r1, PT_R30
521 lwi r29, r1, PT_R29
522 lwi r28, r1, PT_R28
523 lwi r27, r1, PT_R27
524 lwi r26, r1, PT_R26
525 lwi r25, r1, PT_R25
526 lwi r24, r1, PT_R24
527 lwi r23, r1, PT_R23
528 lwi r22, r1, PT_R22
529 lwi r21, r1, PT_R21
530 lwi r20, r1, PT_R20
531 lwi r19, r1, PT_R19
532 lwi r18, r1, PT_R18
533 lwi r17, r1, PT_R17
534 lwi r16, r1, PT_R16
535 lwi r15, r1, PT_R15
536 lwi r14, r1, PT_PC
537 lwi r13, r1, PT_R13
538 lwi r12, r1, PT_R12
539 lwi r11, r1, PT_R11
540 lwi r10, r1, PT_R10
541 lwi r9, r1, PT_R9
542 lwi r8, r1, PT_R8
543 lwi r7, r1, PT_R7
544 lwi r6, r1, PT_R6
545 lwi r5, r1, PT_R5
546 lwi r4, r1, PT_R4 /* return val */
547 lwi r3, r1, PT_R3 /* return val */
548 lwi r2, r1, PT_R2
549 lwi r1, r1, PT_R1
550
551 rtid r14, 0
552 nop
553
554sys_vfork_wrapper:
555 brid sys_vfork
556 addk r5, r1, r0
557
558sys_clone_wrapper:
559 brid sys_clone
560 addk r7, r1, r0
561
562sys_execve_wrapper:
563 brid sys_execve
564 addk r8, r1, r0
565
566sys_sigreturn_wrapper:
567 brid sys_sigreturn
568 addk r5, r1, r0
569
570sys_rt_sigreturn_wrapper:
571 brid sys_rt_sigreturn
572 addk r5, r1, r0
573
574sys_sigsuspend_wrapper:
575 brid sys_rt_sigsuspend
576 addk r6, r1, r0
577
578sys_rt_sigsuspend_wrapper:
579 brid sys_rt_sigsuspend
580 addk r7, r1, r0
581
582 /* Interrupt vector table */
583 .section .init.ivt, "ax"
584 .org 0x0
585 brai _reset
586 brai _user_exception
587 brai _interrupt
588 brai _break
589 brai _hw_exception_handler
590 .org 0x60
591 brai _debug_exception
592
593.section .rodata,"a"
594#include "syscall_table.S"
595
596syscall_table_size=(.-sys_call_table)
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
new file mode 100644
index 000000000000..4a8a4064c7ee
--- /dev/null
+++ b/arch/microblaze/kernel/exceptions.c
@@ -0,0 +1,124 @@
1/*
2 * HW exception handling
3 *
4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2008 PetaLogix
6 *
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License. See the file COPYING in the main directory of this
9 * archive for more details.
10 */
11
12/*
13 * This file handles the architecture-dependent parts of hardware exceptions
14 */
15
16#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/sched.h>
19#include <linux/kallsyms.h>
20#include <linux/module.h>
21
22#include <asm/exceptions.h>
23#include <asm/entry.h> /* For KM CPU var */
24#include <asm/uaccess.h>
25#include <asm/errno.h>
26#include <asm/ptrace.h>
27#include <asm/current.h>
28
29#define MICROBLAZE_ILL_OPCODE_EXCEPTION 0x02
30#define MICROBLAZE_IBUS_EXCEPTION 0x03
31#define MICROBLAZE_DBUS_EXCEPTION 0x04
32#define MICROBLAZE_DIV_ZERO_EXCEPTION 0x05
33#define MICROBLAZE_FPU_EXCEPTION 0x06
34#define MICROBLAZE_PRIVILEG_EXCEPTION 0x07
35
36static DEFINE_SPINLOCK(die_lock);
37
38void die(const char *str, struct pt_regs *fp, long err)
39{
40 console_verbose();
41 spin_lock_irq(&die_lock);
42 printk(KERN_WARNING "Oops: %s, sig: %ld\n", str, err);
43 show_regs(fp);
44 spin_unlock_irq(&die_lock);
45 /* do_exit() should take care of panic'ing from an interrupt
46 * context so we don't handle it here
47 */
48 do_exit(err);
49}
50
51void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
52{
53 siginfo_t info;
54
55 if (kernel_mode(regs)) {
56 debugger(regs);
57 die("Exception in kernel mode", regs, signr);
58 }
59 info.si_signo = signr;
60 info.si_errno = 0;
61 info.si_code = code;
62 info.si_addr = (void __user *) addr;
63 force_sig_info(signr, &info, current);
64}
65
66asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
67 int fsr, int addr)
68{
69#if 0
70 printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
71 type, user_mode(regs) ? "user" : "kernel", fsr,
72 (unsigned int) regs->pc, (unsigned int) regs->esr);
73#endif
74
75 switch (type & 0x1F) {
76 case MICROBLAZE_ILL_OPCODE_EXCEPTION:
77 _exception(SIGILL, regs, ILL_ILLOPC, addr);
78 break;
79 case MICROBLAZE_IBUS_EXCEPTION:
80 if (user_mode(regs)) {
81 printk(KERN_WARNING "Instruction bus error exception in user mode.\n");
82 _exception(SIGBUS, regs, BUS_ADRERR, addr);
83 return;
84 }
85 printk(KERN_WARNING "Instruction bus error exception in kernel mode.\n");
86 die("bus exception", regs, SIGBUS);
87 break;
88 case MICROBLAZE_DBUS_EXCEPTION:
89 if (user_mode(regs)) {
90 printk(KERN_WARNING "Data bus error exception in user mode.\n");
91 _exception(SIGBUS, regs, BUS_ADRERR, addr);
92 return;
93 }
94 printk(KERN_WARNING "Data bus error exception in kernel mode.\n");
95 die("bus exception", regs, SIGBUS);
96 break;
97 case MICROBLAZE_DIV_ZERO_EXCEPTION:
98 printk(KERN_WARNING "Divide by zero exception\n");
99 _exception(SIGILL, regs, ILL_ILLOPC, addr);
100 break;
101
102 case MICROBLAZE_FPU_EXCEPTION:
103 /* IEEE FP exception */
104 /* I removed fsr variable and use code var for storing fsr */
105 if (fsr & FSR_IO)
106 fsr = FPE_FLTINV;
107 else if (fsr & FSR_OF)
108 fsr = FPE_FLTOVF;
109 else if (fsr & FSR_UF)
110 fsr = FPE_FLTUND;
111 else if (fsr & FSR_DZ)
112 fsr = FPE_FLTDIV;
113 else if (fsr & FSR_DO)
114 fsr = FPE_FLTRES;
115 _exception(SIGFPE, regs, fsr, addr);
116 break;
117
118 default:
119 printk(KERN_WARNING "Unexpected exception %02x "
120 "PC=%08x in %s mode\n", type, (unsigned int) addr,
121 kernel_mode(regs) ? "kernel" : "user");
122 }
123 return;
124}
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
new file mode 100644
index 000000000000..319dc35fc922
--- /dev/null
+++ b/arch/microblaze/kernel/head.S
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/linkage.h>
12#include <asm/thread_info.h>
13#include <asm/page.h>
14
15 .text
16ENTRY(_start)
17 mfs r1, rmsr
18 andi r1, r1, ~2
19 mts rmsr, r1
20
21/* save fdt to kernel location */
22/* r7 stores pointer to fdt blob */
23 beqi r7, no_fdt_arg
24 or r11, r0, r0 /* incremment */
25 ori r4, r0, TOPHYS(_fdt_start) /* save bram context */
26 ori r3, r0, (0x4000 - 4)
27_copy_fdt:
28 lw r12, r7, r11 /* r12 = r7 + r11 */
29 sw r12, r4, r11 /* addr[r4 + r11] = r12 */
30 addik r11, r11, 4 /* increment counting */
31 bgtid r3, _copy_fdt /* loop for all entries */
32 addik r3, r3, -4 /* descrement loop */
33no_fdt_arg:
34
35 /* Initialize small data anchors */
36 la r13, r0, _KERNEL_SDA_BASE_
37 la r2, r0, _KERNEL_SDA2_BASE_
38
39 /* Initialize stack pointer */
40 la r1, r0, init_thread_union + THREAD_SIZE - 4
41
42 /* Initialize r31 with current task address */
43 la r31, r0, init_task
44
45 /*
46 * Call platform dependent initialize function.
47 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
48 * the function.
49 */
50 la r8, r0, machine_early_init
51 brald r15, r8
52 nop
53
54 la r15, r0, machine_halt
55 braid start_kernel
56 nop
diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c
new file mode 100644
index 000000000000..1bdf20222b92
--- /dev/null
+++ b/arch/microblaze/kernel/heartbeat.c
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/sched.h>
12#include <linux/io.h>
13
14#include <asm/setup.h>
15#include <asm/page.h>
16#include <asm/prom.h>
17
18static unsigned int base_addr;
19
20void heartbeat(void)
21{
22 static unsigned int cnt, period, dist;
23
24 if (base_addr) {
25 if (cnt == 0 || cnt == dist)
26 out_be32(base_addr, 1);
27 else if (cnt == 7 || cnt == dist + 7)
28 out_be32(base_addr, 0);
29
30 if (++cnt > period) {
31 cnt = 0;
32 /*
33 * The hyperbolic function below modifies the heartbeat
34 * period length in dependency of the current (5min)
35 * load. It goes through the points f(0)=126, f(1)=86,
36 * f(5)=51, f(inf)->30.
37 */
38 period = ((672 << FSHIFT) / (5 * avenrun[0] +
39 (7 << FSHIFT))) + 30;
40 dist = period / 4;
41 }
42 }
43}
44
45void setup_heartbeat(void)
46{
47 struct device_node *gpio = NULL;
48 int j;
49 char *gpio_list[] = {
50 "xlnx,xps-gpio-1.00.a",
51 "xlnx,opb-gpio-1.00.a",
52 NULL
53 };
54
55 for (j = 0; gpio_list[j] != NULL; j++) {
56 gpio = of_find_compatible_node(NULL, NULL, gpio_list[j]);
57 if (gpio)
58 break;
59 }
60
61 base_addr = *(int *) of_get_property(gpio, "reg", NULL);
62 base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
63 printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
64
65 if (*(int *) of_get_property(gpio, "xlnx,is-bidir", NULL))
66 out_be32(base_addr + 4, 0); /* GPIO is configured as output */
67}
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
new file mode 100644
index 000000000000..cf9486d99838
--- /dev/null
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -0,0 +1,458 @@
1/*
2 * Exception handling for Microblaze
3 *
4 * Rewriten interrupt handling
5 *
6 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
7 * Copyright (C) 2008-2009 PetaLogix
8 *
9 * uClinux customisation (C) 2005 John Williams
10 *
11 * MMU code derived from arch/ppc/kernel/head_4xx.S:
12 * Copyright (C) 1995-1996 Gary Thomas <gdt@linuxppc.org>
13 * Initial PowerPC version.
14 * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
15 * Rewritten for PReP
16 * Copyright (C) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
17 * Low-level exception handers, MMU support, and rewrite.
18 * Copyright (C) 1997 Dan Malek <dmalek@jlc.net>
19 * PowerPC 8xx modifications.
20 * Copyright (C) 1998-1999 TiVo, Inc.
21 * PowerPC 403GCX modifications.
22 * Copyright (C) 1999 Grant Erickson <grant@lcse.umn.edu>
23 * PowerPC 403GCX/405GP modifications.
24 * Copyright 2000 MontaVista Software Inc.
25 * PPC405 modifications
26 * PowerPC 403GCX/405GP modifications.
27 * Author: MontaVista Software, Inc.
28 * frank_rowand@mvista.com or source@mvista.com
29 * debbie_chu@mvista.com
30 *
31 * Original code
32 * Copyright (C) 2004 Xilinx, Inc.
33 *
34 * This program is free software; you can redistribute it and/or modify it
35 * under the terms of the GNU General Public License version 2 as published
36 * by the Free Software Foundation.
37 */
38
39/*
40 * Here are the handlers which don't require enabling translation
41 * and calling other kernel code thus we can keep their design very simple
42 * and do all processing in real mode. All what they need is a valid current
43 * (that is an issue for the CONFIG_REGISTER_TASK_PTR case)
44 * This handlers use r3,r4,r5,r6 and optionally r[current] to work therefore
45 * these registers are saved/restored
46 * The handlers which require translation are in entry.S --KAA
47 *
48 * Microblaze HW Exception Handler
49 * - Non self-modifying exception handler for the following exception conditions
50 * - Unalignment
51 * - Instruction bus error
52 * - Data bus error
53 * - Illegal instruction opcode
54 * - Divide-by-zero
55 *
56 * Note we disable interrupts during exception handling, otherwise we will
57 * possibly get multiple re-entrancy if interrupt handles themselves cause
58 * exceptions. JW
59 */
60
61#include <asm/exceptions.h>
62#include <asm/unistd.h>
63#include <asm/page.h>
64
65#include <asm/entry.h>
66#include <asm/current.h>
67#include <linux/linkage.h>
68
69#include <asm/mmu.h>
70#include <asm/pgtable.h>
71#include <asm/asm-offsets.h>
72
73/* Helpful Macros */
74#define EX_HANDLER_STACK_SIZ (4*19)
75#define NUM_TO_REG(num) r ## num
76
77#define LWREG_NOP \
78 bri ex_handler_unhandled; \
79 nop;
80
81#define SWREG_NOP \
82 bri ex_handler_unhandled; \
83 nop;
84
85/* FIXME this is weird - for noMMU kernel is not possible to use brid
86 * instruction which can shorten executed time
87 */
88
89/* r3 is the source */
90#define R3_TO_LWREG_V(regnum) \
91 swi r3, r1, 4 * regnum; \
92 bri ex_handler_done;
93
94/* r3 is the source */
95#define R3_TO_LWREG(regnum) \
96 or NUM_TO_REG (regnum), r0, r3; \
97 bri ex_handler_done;
98
99/* r3 is the target */
100#define SWREG_TO_R3_V(regnum) \
101 lwi r3, r1, 4 * regnum; \
102 bri ex_sw_tail;
103
104/* r3 is the target */
105#define SWREG_TO_R3(regnum) \
106 or r3, r0, NUM_TO_REG (regnum); \
107 bri ex_sw_tail;
108
109.extern other_exception_handler /* Defined in exception.c */
110
111/*
112 * hw_exception_handler - Handler for exceptions
113 *
114 * Exception handler notes:
115 * - Handles all exceptions
116 * - Does not handle unaligned exceptions during load into r17, r1, r0.
117 * - Does not handle unaligned exceptions during store from r17 (cannot be
118 * done) and r1 (slows down common case)
119 *
120 * Relevant register structures
121 *
122 * EAR - |----|----|----|----|----|----|----|----|
123 * - < ## 32 bit faulting address ## >
124 *
125 * ESR - |----|----|----|----|----| - | - |-----|-----|
126 * - W S REG EXC
127 *
128 *
129 * STACK FRAME STRUCTURE (for NO_MMU)
130 * ---------------------------------
131 *
132 * +-------------+ + 0
133 * | MSR |
134 * +-------------+ + 4
135 * | r1 |
136 * | . |
137 * | . |
138 * | . |
139 * | . |
140 * | r18 |
141 * +-------------+ + 76
142 * | . |
143 * | . |
144 *
145 * NO_MMU kernel use the same r0_ram pointed space - look to vmlinux.lds.S
146 * which is used for storing register values - old style was, that value were
147 * stored in stack but in case of failure you lost information about register.
148 * Currently you can see register value in memory in specific place.
149 * In compare to with previous solution the speed should be the same.
150 *
151 * MMU exception handler has different handling compare to no MMU kernel.
152 * Exception handler use jump table for directing of what happen. For MMU kernel
153 * is this approach better because MMU relate exception are handled by asm code
154 * in this file. In compare to with MMU expect of unaligned exception
155 * is everything handled by C code.
156 */
157
158/*
159 * every of these handlers is entered having R3/4/5/6/11/current saved on stack
160 * and clobbered so care should be taken to restore them if someone is going to
161 * return from exception
162 */
163
164/* wrappers to restore state before coming to entry.S */
165
166.global _hw_exception_handler
167.section .text
168.align 4
169.ent _hw_exception_handler
170_hw_exception_handler:
171 addik r1, r1, -(EX_HANDLER_STACK_SIZ); /* Create stack frame */
172 swi r3, r1, PT_R3
173 swi r4, r1, PT_R4
174 swi r5, r1, PT_R5
175 swi r6, r1, PT_R6
176
177 mfs r5, rmsr;
178 nop
179 swi r5, r1, 0;
180 mfs r4, rbtr /* Save BTR before jumping to handler */
181 nop
182 mfs r3, resr
183 nop
184
185 andi r5, r3, 0x1000; /* Check ESR[DS] */
186 beqi r5, not_in_delay_slot; /* Branch if ESR[DS] not set */
187 mfs r17, rbtr; /* ESR[DS] set - return address in BTR */
188 nop
189not_in_delay_slot:
190 swi r17, r1, PT_R17
191
192 andi r5, r3, 0x1F; /* Extract ESR[EXC] */
193
194 /* Exceptions enabled here. This will allow nested exceptions */
195 mfs r6, rmsr;
196 nop
197 swi r6, r1, 0; /* RMSR_OFFSET */
198 ori r6, r6, 0x100; /* Turn ON the EE bit */
199 andi r6, r6, ~2; /* Disable interrupts */
200 mts rmsr, r6;
201 nop
202
203 xori r6, r5, 1; /* 00001 = Unaligned Exception */
204 /* Jump to unalignment exception handler */
205 beqi r6, handle_unaligned_ex;
206
207handle_other_ex: /* Handle Other exceptions here */
208 /* Save other volatiles before we make procedure calls below */
209 swi r7, r1, PT_R7
210 swi r8, r1, PT_R8
211 swi r9, r1, PT_R9
212 swi r10, r1, PT_R10
213 swi r11, r1, PT_R11
214 swi r12, r1, PT_R12
215 swi r14, r1, PT_R14
216 swi r15, r1, PT_R15
217 swi r18, r1, PT_R18
218
219 or r5, r1, r0
220 andi r6, r3, 0x1F; /* Load ESR[EC] */
221 lwi r7, r0, PER_CPU(KM) /* MS: saving current kernel mode to regs */
222 swi r7, r1, PT_MODE
223 mfs r7, rfsr
224 nop
225 addk r8, r17, r0; /* Load exception address */
226 bralid r15, full_exception; /* Branch to the handler */
227 nop;
228
229 /*
230 * Trigger execution of the signal handler by enabling
231 * interrupts and calling an invalid syscall.
232 */
233 mfs r5, rmsr;
234 nop
235 ori r5, r5, 2;
236 mts rmsr, r5; /* enable interrupt */
237 nop
238 addi r12, r0, __NR_syscalls;
239 brki r14, 0x08;
240 mfs r5, rmsr; /* disable interrupt */
241 nop
242 andi r5, r5, ~2;
243 mts rmsr, r5;
244 nop
245
246 lwi r7, r1, PT_R7
247 lwi r8, r1, PT_R8
248 lwi r9, r1, PT_R9
249 lwi r10, r1, PT_R10
250 lwi r11, r1, PT_R11
251 lwi r12, r1, PT_R12
252 lwi r14, r1, PT_R14
253 lwi r15, r1, PT_R15
254 lwi r18, r1, PT_R18
255
256 bri ex_handler_done; /* Complete exception handling */
257
258/* 0x01 - Unaligned data access exception
259 * This occurs when a word access is not aligned on a word boundary,
260 * or when a 16-bit access is not aligned on a 16-bit boundary.
261 * This handler perform the access, and returns, except for MMU when
262 * the unaligned address is last on a 4k page or the physical address is
263 * not found in the page table, in which case unaligned_data_trap is called.
264 */
265handle_unaligned_ex:
266 /* Working registers already saved: R3, R4, R5, R6
267 * R3 = ESR
268 * R4 = BTR
269 */
270 mfs r4, rear;
271 nop
272
273 andi r6, r3, 0x3E0; /* Mask and extract the register operand */
274 srl r6, r6; /* r6 >> 5 */
275 srl r6, r6;
276 srl r6, r6;
277 srl r6, r6;
278 srl r6, r6;
279 /* Store the register operand in a temporary location */
280 sbi r6, r0, TOPHYS(ex_reg_op);
281
282 andi r6, r3, 0x400; /* Extract ESR[S] */
283 bnei r6, ex_sw;
284ex_lw:
285 andi r6, r3, 0x800; /* Extract ESR[W] */
286 beqi r6, ex_lhw;
287 lbui r5, r4, 0; /* Exception address in r4 */
288 /* Load a word, byte-by-byte from destination address
289 and save it in tmp space */
290 sbi r5, r0, TOPHYS(ex_tmp_data_loc_0);
291 lbui r5, r4, 1;
292 sbi r5, r0, TOPHYS(ex_tmp_data_loc_1);
293 lbui r5, r4, 2;
294 sbi r5, r0, TOPHYS(ex_tmp_data_loc_2);
295 lbui r5, r4, 3;
296 sbi r5, r0, TOPHYS(ex_tmp_data_loc_3);
297 /* Get the destination register value into r3 */
298 lwi r3, r0, TOPHYS(ex_tmp_data_loc_0);
299 bri ex_lw_tail;
300ex_lhw:
301 lbui r5, r4, 0; /* Exception address in r4 */
302 /* Load a half-word, byte-by-byte from destination
303 address and save it in tmp space */
304 sbi r5, r0, TOPHYS(ex_tmp_data_loc_0);
305 lbui r5, r4, 1;
306 sbi r5, r0, TOPHYS(ex_tmp_data_loc_1);
307 /* Get the destination register value into r3 */
308 lhui r3, r0, TOPHYS(ex_tmp_data_loc_0);
309ex_lw_tail:
310 /* Get the destination register number into r5 */
311 lbui r5, r0, TOPHYS(ex_reg_op);
312 /* Form load_word jump table offset (lw_table + (8 * regnum)) */
313 la r6, r0, TOPHYS(lw_table);
314 addk r5, r5, r5;
315 addk r5, r5, r5;
316 addk r5, r5, r5;
317 addk r5, r5, r6;
318 bra r5;
319ex_lw_end: /* Exception handling of load word, ends */
320ex_sw:
321 /* Get the destination register number into r5 */
322 lbui r5, r0, TOPHYS(ex_reg_op);
323 /* Form store_word jump table offset (sw_table + (8 * regnum)) */
324 la r6, r0, TOPHYS(sw_table);
325 add r5, r5, r5;
326 add r5, r5, r5;
327 add r5, r5, r5;
328 add r5, r5, r6;
329 bra r5;
330ex_sw_tail:
331 mfs r6, resr;
332 nop
333 andi r6, r6, 0x800; /* Extract ESR[W] */
334 beqi r6, ex_shw;
335 /* Get the word - delay slot */
336 swi r3, r0, TOPHYS(ex_tmp_data_loc_0);
337 /* Store the word, byte-by-byte into destination address */
338 lbui r3, r0, TOPHYS(ex_tmp_data_loc_0);
339 sbi r3, r4, 0;
340 lbui r3, r0, TOPHYS(ex_tmp_data_loc_1);
341 sbi r3, r4, 1;
342 lbui r3, r0, TOPHYS(ex_tmp_data_loc_2);
343 sbi r3, r4, 2;
344 lbui r3, r0, TOPHYS(ex_tmp_data_loc_3);
345 sbi r3, r4, 3;
346 bri ex_handler_done;
347
348ex_shw:
349 /* Store the lower half-word, byte-by-byte into destination address */
350 swi r3, r0, TOPHYS(ex_tmp_data_loc_0);
351 lbui r3, r0, TOPHYS(ex_tmp_data_loc_2);
352 sbi r3, r4, 0;
353 lbui r3, r0, TOPHYS(ex_tmp_data_loc_3);
354 sbi r3, r4, 1;
355ex_sw_end: /* Exception handling of store word, ends. */
356
357ex_handler_done:
358 lwi r5, r1, 0 /* RMSR */
359 mts rmsr, r5
360 nop
361 lwi r3, r1, PT_R3
362 lwi r4, r1, PT_R4
363 lwi r5, r1, PT_R5
364 lwi r6, r1, PT_R6
365 lwi r17, r1, PT_R17
366
367 rted r17, 0
368 addik r1, r1, (EX_HANDLER_STACK_SIZ); /* Restore stack frame */
369
370.end _hw_exception_handler
371
372ex_handler_unhandled:
373/* FIXME add handle function for unhandled exception - dump register */
374 bri 0
375
376.section .text
377.align 4
378lw_table:
379lw_r0: R3_TO_LWREG (0);
380lw_r1: LWREG_NOP;
381lw_r2: R3_TO_LWREG (2);
382lw_r3: R3_TO_LWREG_V (3);
383lw_r4: R3_TO_LWREG_V (4);
384lw_r5: R3_TO_LWREG_V (5);
385lw_r6: R3_TO_LWREG_V (6);
386lw_r7: R3_TO_LWREG (7);
387lw_r8: R3_TO_LWREG (8);
388lw_r9: R3_TO_LWREG (9);
389lw_r10: R3_TO_LWREG (10);
390lw_r11: R3_TO_LWREG (11);
391lw_r12: R3_TO_LWREG (12);
392lw_r13: R3_TO_LWREG (13);
393lw_r14: R3_TO_LWREG (14);
394lw_r15: R3_TO_LWREG (15);
395lw_r16: R3_TO_LWREG (16);
396lw_r17: LWREG_NOP;
397lw_r18: R3_TO_LWREG (18);
398lw_r19: R3_TO_LWREG (19);
399lw_r20: R3_TO_LWREG (20);
400lw_r21: R3_TO_LWREG (21);
401lw_r22: R3_TO_LWREG (22);
402lw_r23: R3_TO_LWREG (23);
403lw_r24: R3_TO_LWREG (24);
404lw_r25: R3_TO_LWREG (25);
405lw_r26: R3_TO_LWREG (26);
406lw_r27: R3_TO_LWREG (27);
407lw_r28: R3_TO_LWREG (28);
408lw_r29: R3_TO_LWREG (29);
409lw_r30: R3_TO_LWREG (30);
410lw_r31: R3_TO_LWREG (31);
411
412sw_table:
413sw_r0: SWREG_TO_R3 (0);
414sw_r1: SWREG_NOP;
415sw_r2: SWREG_TO_R3 (2);
416sw_r3: SWREG_TO_R3_V (3);
417sw_r4: SWREG_TO_R3_V (4);
418sw_r5: SWREG_TO_R3_V (5);
419sw_r6: SWREG_TO_R3_V (6);
420sw_r7: SWREG_TO_R3 (7);
421sw_r8: SWREG_TO_R3 (8);
422sw_r9: SWREG_TO_R3 (9);
423sw_r10: SWREG_TO_R3 (10);
424sw_r11: SWREG_TO_R3 (11);
425sw_r12: SWREG_TO_R3 (12);
426sw_r13: SWREG_TO_R3 (13);
427sw_r14: SWREG_TO_R3 (14);
428sw_r15: SWREG_TO_R3 (15);
429sw_r16: SWREG_TO_R3 (16);
430sw_r17: SWREG_NOP;
431sw_r18: SWREG_TO_R3 (18);
432sw_r19: SWREG_TO_R3 (19);
433sw_r20: SWREG_TO_R3 (20);
434sw_r21: SWREG_TO_R3 (21);
435sw_r22: SWREG_TO_R3 (22);
436sw_r23: SWREG_TO_R3 (23);
437sw_r24: SWREG_TO_R3 (24);
438sw_r25: SWREG_TO_R3 (25);
439sw_r26: SWREG_TO_R3 (26);
440sw_r27: SWREG_TO_R3 (27);
441sw_r28: SWREG_TO_R3 (28);
442sw_r29: SWREG_TO_R3 (29);
443sw_r30: SWREG_TO_R3 (30);
444sw_r31: SWREG_TO_R3 (31);
445
446/* Temporary data structures used in the handler */
447.section .data
448.align 4
449ex_tmp_data_loc_0:
450 .byte 0
451ex_tmp_data_loc_1:
452 .byte 0
453ex_tmp_data_loc_2:
454 .byte 0
455ex_tmp_data_loc_3:
456 .byte 0
457ex_reg_op:
458 .byte 0
diff --git a/arch/microblaze/kernel/init_task.c b/arch/microblaze/kernel/init_task.c
new file mode 100644
index 000000000000..48eb9fb255fa
--- /dev/null
+++ b/arch/microblaze/kernel/init_task.c
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/module.h>
12#include <linux/sched.h>
13#include <linux/init_task.h>
14#include <linux/fs.h>
15#include <linux/mqueue.h>
16
17#include <asm/pgtable.h>
18
19static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
20static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
21struct mm_struct init_mm = INIT_MM(init_mm);
22EXPORT_SYMBOL(init_mm);
23
24union thread_union init_thread_union
25 __attribute__((__section__(".data.init_task"))) =
26{ INIT_THREAD_INFO(init_task) };
27
28struct task_struct init_task = INIT_TASK(init_task);
29EXPORT_SYMBOL(init_task);
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
new file mode 100644
index 000000000000..b15605299a57
--- /dev/null
+++ b/arch/microblaze/kernel/intc.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/irq.h>
13#include <asm/page.h>
14#include <linux/io.h>
15
16#include <asm/prom.h>
17#include <asm/irq.h>
18
19#ifdef CONFIG_SELFMOD_INTC
20#include <asm/selfmod.h>
21#define INTC_BASE BARRIER_BASE_ADDR
22#else
23static unsigned int intc_baseaddr;
24#define INTC_BASE intc_baseaddr
25#endif
26
27unsigned int nr_irq;
28
29/* No one else should require these constants, so define them locally here. */
30#define ISR 0x00 /* Interrupt Status Register */
31#define IPR 0x04 /* Interrupt Pending Register */
32#define IER 0x08 /* Interrupt Enable Register */
33#define IAR 0x0c /* Interrupt Acknowledge Register */
34#define SIE 0x10 /* Set Interrupt Enable bits */
35#define CIE 0x14 /* Clear Interrupt Enable bits */
36#define IVR 0x18 /* Interrupt Vector Register */
37#define MER 0x1c /* Master Enable Register */
38
39#define MER_ME (1<<0)
40#define MER_HIE (1<<1)
41
42static void intc_enable_or_unmask(unsigned int irq)
43{
44 pr_debug("enable_or_unmask: %d\n", irq);
45 out_be32(INTC_BASE + SIE, 1 << irq);
46}
47
48static void intc_disable_or_mask(unsigned int irq)
49{
50 pr_debug("disable: %d\n", irq);
51 out_be32(INTC_BASE + CIE, 1 << irq);
52}
53
54static void intc_ack(unsigned int irq)
55{
56 pr_debug("ack: %d\n", irq);
57 out_be32(INTC_BASE + IAR, 1 << irq);
58}
59
60static void intc_mask_ack(unsigned int irq)
61{
62 unsigned long mask = 1 << irq;
63 pr_debug("disable_and_ack: %d\n", irq);
64 out_be32(INTC_BASE + CIE, mask);
65 out_be32(INTC_BASE + IAR, mask);
66}
67
68static void intc_end(unsigned int irq)
69{
70 unsigned long mask = 1 << irq;
71 pr_debug("end: %d\n", irq);
72 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
73 out_be32(INTC_BASE + SIE, mask);
74 /* ack level sensitive intr */
75 if (irq_desc[irq].status & IRQ_LEVEL)
76 out_be32(INTC_BASE + IAR, mask);
77 }
78}
79
80static struct irq_chip intc_dev = {
81 .name = "Xilinx INTC",
82 .unmask = intc_enable_or_unmask,
83 .mask = intc_disable_or_mask,
84 .ack = intc_ack,
85 .mask_ack = intc_mask_ack,
86 .end = intc_end,
87};
88
89unsigned int get_irq(struct pt_regs *regs)
90{
91 int irq;
92
93 /*
94 * NOTE: This function is the one that needs to be improved in
95 * order to handle multiple interrupt controllers. It currently
96 * is hardcoded to check for interrupts only on the first INTC.
97 */
98 irq = in_be32(INTC_BASE + IVR);
99 pr_debug("get_irq: %d\n", irq);
100
101 return irq;
102}
103
104void __init init_IRQ(void)
105{
106 u32 i, j, intr_type;
107 struct device_node *intc = NULL;
108#ifdef CONFIG_SELFMOD_INTC
109 unsigned int intc_baseaddr = 0;
110 static int arr_func[] = {
111 (int)&get_irq,
112 (int)&intc_enable_or_unmask,
113 (int)&intc_disable_or_mask,
114 (int)&intc_mask_ack,
115 (int)&intc_ack,
116 (int)&intc_end,
117 0
118 };
119#endif
120 static char *intc_list[] = {
121 "xlnx,xps-intc-1.00.a",
122 "xlnx,opb-intc-1.00.c",
123 "xlnx,opb-intc-1.00.b",
124 "xlnx,opb-intc-1.00.a",
125 NULL
126 };
127
128 for (j = 0; intc_list[j] != NULL; j++) {
129 intc = of_find_compatible_node(NULL, NULL, intc_list[j]);
130 if (intc)
131 break;
132 }
133
134 intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL);
135 intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
136 nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL);
137
138 intr_type =
139 *(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL);
140 if (intr_type >= (1 << (nr_irq + 1)))
141 printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
142
143#ifdef CONFIG_SELFMOD_INTC
144 selfmod_function((int *) arr_func, intc_baseaddr);
145#endif
146 printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
147 intc_list[j], intc_baseaddr, nr_irq, intr_type);
148
149 /*
150 * Disable all external interrupts until they are
151 * explicity requested.
152 */
153 out_be32(intc_baseaddr + IER, 0);
154
155 /* Acknowledge any pending interrupts just in case. */
156 out_be32(intc_baseaddr + IAR, 0xffffffff);
157
158 /* Turn on the Master Enable. */
159 out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
160
161 for (i = 0; i < nr_irq; ++i) {
162 if (intr_type & (0x00000001 << i)) {
163 set_irq_chip_and_handler_name(i, &intc_dev,
164 handle_edge_irq, intc_dev.name);
165 irq_desc[i].status &= ~IRQ_LEVEL;
166 } else {
167 set_irq_chip_and_handler_name(i, &intc_dev,
168 handle_level_irq, intc_dev.name);
169 irq_desc[i].status |= IRQ_LEVEL;
170 }
171 }
172}
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
new file mode 100644
index 000000000000..f688ee93e3b9
--- /dev/null
+++ b/arch/microblaze/kernel/irq.c
@@ -0,0 +1,104 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/hardirq.h>
14#include <linux/interrupt.h>
15#include <linux/irqflags.h>
16#include <linux/seq_file.h>
17#include <linux/kernel_stat.h>
18#include <linux/irq.h>
19
20#include <asm/prom.h>
21
22unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
23{
24 struct of_irq oirq;
25
26 if (of_irq_map_one(dev, index, &oirq))
27 return NO_IRQ;
28
29 return oirq.specifier[0];
30}
31EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
32
33/*
34 * 'what should we do if we get a hw irq event on an illegal vector'.
35 * each architecture has to answer this themselves.
36 */
37void ack_bad_irq(unsigned int irq)
38{
39 printk(KERN_WARNING "unexpected IRQ trap at vector %02x\n", irq);
40}
41
42static u32 concurrent_irq;
43
44void do_IRQ(struct pt_regs *regs)
45{
46 unsigned int irq;
47 struct pt_regs *old_regs = set_irq_regs(regs);
48
49 irq_enter();
50 irq = get_irq(regs);
51next_irq:
52 BUG_ON(irq == -1U);
53 generic_handle_irq(irq);
54
55 irq = get_irq(regs);
56 if (irq != -1U) {
57 pr_debug("next irq: %d\n", irq);
58 ++concurrent_irq;
59 goto next_irq;
60 }
61
62 irq_exit();
63 set_irq_regs(old_regs);
64}
65
66int show_interrupts(struct seq_file *p, void *v)
67{
68 int i = *(loff_t *) v, j;
69 struct irqaction *action;
70 unsigned long flags;
71
72 if (i == 0) {
73 seq_printf(p, " ");
74 for_each_online_cpu(j)
75 seq_printf(p, "CPU%-8d", j);
76 seq_putc(p, '\n');
77 }
78
79 if (i < nr_irq) {
80 spin_lock_irqsave(&irq_desc[i].lock, flags);
81 action = irq_desc[i].action;
82 if (!action)
83 goto skip;
84 seq_printf(p, "%3d: ", i);
85#ifndef CONFIG_SMP
86 seq_printf(p, "%10u ", kstat_irqs(i));
87#else
88 for_each_online_cpu(j)
89 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
90#endif
91 seq_printf(p, " %8s", irq_desc[i].status &
92 IRQ_LEVEL ? "level" : "edge");
93 seq_printf(p, " %8s", irq_desc[i].chip->name);
94 seq_printf(p, " %s", action->name);
95
96 for (action = action->next; action; action = action->next)
97 seq_printf(p, ", %s", action->name);
98
99 seq_putc(p, '\n');
100skip:
101 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
102 }
103 return 0;
104}
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
new file mode 100644
index 000000000000..5f71790e3c3c
--- /dev/null
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2008-2009 PetaLogix
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/string.h>
12#include <linux/cryptohash.h>
13#include <linux/delay.h>
14#include <linux/in6.h>
15#include <linux/syscalls.h>
16
17#include <asm/checksum.h>
18#include <linux/io.h>
19#include <asm/page.h>
20#include <asm/system.h>
21#include <linux/uaccess.h>
22
23/*
24 * libgcc functions - functions that are used internally by the
25 * compiler... (prototypes are not correct though, but that
26 * doesn't really matter since they're not versioned).
27 */
28extern void __ashldi3(void);
29EXPORT_SYMBOL(__ashldi3);
30extern void __ashrdi3(void);
31EXPORT_SYMBOL(__ashrdi3);
32extern void __divsi3(void);
33EXPORT_SYMBOL(__divsi3);
34extern void __lshrdi3(void);
35EXPORT_SYMBOL(__lshrdi3);
36extern void __modsi3(void);
37EXPORT_SYMBOL(__modsi3);
38extern void __mulsi3(void);
39EXPORT_SYMBOL(__mulsi3);
40extern void __muldi3(void);
41EXPORT_SYMBOL(__muldi3);
42extern void __ucmpdi2(void);
43EXPORT_SYMBOL(__ucmpdi2);
44extern void __udivsi3(void);
45EXPORT_SYMBOL(__udivsi3);
46extern void __umodsi3(void);
47EXPORT_SYMBOL(__umodsi3);
diff --git a/arch/microblaze/kernel/module.c b/arch/microblaze/kernel/module.c
new file mode 100644
index 000000000000..51414171326f
--- /dev/null
+++ b/arch/microblaze/kernel/module.c
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/moduleloader.h>
12#include <linux/kernel.h>
13#include <linux/elf.h>
14#include <linux/vmalloc.h>
15#include <linux/slab.h>
16#include <linux/fs.h>
17#include <linux/string.h>
18
19#include <asm/pgtable.h>
20
21void *module_alloc(unsigned long size)
22{
23 void *ret;
24 ret = (size == 0) ? NULL : vmalloc(size);
25 pr_debug("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret);
26 return ret;
27}
28
29void module_free(struct module *module, void *region)
30{
31 pr_debug("module_free(%s,%08lx)\n", module->name,
32 (unsigned long)region);
33 vfree(region);
34}
35
36int module_frob_arch_sections(Elf_Ehdr *hdr,
37 Elf_Shdr *sechdrs,
38 char *secstrings,
39 struct module *mod)
40{
41 return 0;
42}
43
44int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab,
45 unsigned int symindex, unsigned int relsec, struct module *module)
46{
47 printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
48 module->name);
49 return -ENOEXEC;
50}
51
52int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
53 unsigned int symindex, unsigned int relsec, struct module *module)
54{
55
56 unsigned int i;
57 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
58 Elf32_Sym *sym;
59 unsigned long int *location;
60 unsigned long int locoffs;
61 unsigned long int value;
62#if __GNUC__ < 4
63 unsigned long int old_value;
64#endif
65
66 pr_debug("Applying add relocation section %u to %u\n",
67 relsec, sechdrs[relsec].sh_info);
68
69 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
70
71 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr +
72 rela[i].r_offset;
73 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr +
74 ELF32_R_SYM(rela[i].r_info);
75 value = sym->st_value + rela[i].r_addend;
76
77 switch (ELF32_R_TYPE(rela[i].r_info)) {
78
79 /*
80 * Be careful! mb-gcc / mb-ld splits the relocs between the
81 * text and the reloc table. In general this means we must
82 * read the current contents of (*location), add any offset
83 * then store the result back in
84 */
85
86 case R_MICROBLAZE_32:
87#if __GNUC__ < 4
88 old_value = *location;
89 *location = value + old_value;
90
91 pr_debug("R_MICROBLAZE_32 (%08lx->%08lx)\n",
92 old_value, value);
93#else
94 *location = value;
95#endif
96 break;
97
98 case R_MICROBLAZE_64:
99#if __GNUC__ < 4
100 /* Split relocs only required/used pre gcc4.1.1 */
101 old_value = ((location[0] & 0x0000FFFF) << 16) |
102 (location[1] & 0x0000FFFF);
103 value += old_value;
104#endif
105 location[0] = (location[0] & 0xFFFF0000) |
106 (value >> 16);
107 location[1] = (location[1] & 0xFFFF0000) |
108 (value & 0xFFFF);
109#if __GNUC__ < 4
110 pr_debug("R_MICROBLAZE_64 (%08lx->%08lx)\n",
111 old_value, value);
112#endif
113 break;
114
115 case R_MICROBLAZE_64_PCREL:
116 locoffs = (location[0] & 0xFFFF) << 16 |
117 (location[1] & 0xFFFF);
118 value -= (unsigned long int)(location) + 4 +
119 locoffs;
120 location[0] = (location[0] & 0xFFFF0000) |
121 (value >> 16);
122 location[1] = (location[1] & 0xFFFF0000) |
123 (value & 0xFFFF);
124 pr_debug("R_MICROBLAZE_64_PCREL (%08lx)\n",
125 value);
126 break;
127
128 case R_MICROBLAZE_NONE:
129 pr_debug("R_MICROBLAZE_NONE\n");
130 break;
131
132 default:
133 printk(KERN_ERR "module %s: "
134 "Unknown relocation: %u\n",
135 module->name,
136 ELF32_R_TYPE(rela->r_info));
137 return -ENOEXEC;
138 }
139 }
140 return 0;
141}
142
143int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
144 struct module *module)
145{
146 return 0;
147}
148
149void module_arch_cleanup(struct module *mod)
150{
151}
diff --git a/arch/microblaze/kernel/of_device.c b/arch/microblaze/kernel/of_device.c
new file mode 100644
index 000000000000..9a0f7632c47c
--- /dev/null
+++ b/arch/microblaze/kernel/of_device.c
@@ -0,0 +1,113 @@
1#include <linux/string.h>
2#include <linux/kernel.h>
3#include <linux/of.h>
4#include <linux/init.h>
5#include <linux/module.h>
6#include <linux/mod_devicetable.h>
7#include <linux/slab.h>
8#include <linux/of_device.h>
9
10#include <linux/errno.h>
11
12void of_device_make_bus_id(struct of_device *dev)
13{
14 static atomic_t bus_no_reg_magic;
15 struct device_node *node = dev->node;
16 const u32 *reg;
17 u64 addr;
18 int magic;
19
20 /*
21 * For MMIO, get the physical address
22 */
23 reg = of_get_property(node, "reg", NULL);
24 if (reg) {
25 addr = of_translate_address(node, reg);
26 if (addr != OF_BAD_ADDR) {
27 dev_set_name(&dev->dev, "%llx.%s",
28 (unsigned long long)addr, node->name);
29 return;
30 }
31 }
32
33 /*
34 * No BusID, use the node name and add a globally incremented
35 * counter (and pray...)
36 */
37 magic = atomic_add_return(1, &bus_no_reg_magic);
38 dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1);
39}
40EXPORT_SYMBOL(of_device_make_bus_id);
41
42struct of_device *of_device_alloc(struct device_node *np,
43 const char *bus_id,
44 struct device *parent)
45{
46 struct of_device *dev;
47
48 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
49 if (!dev)
50 return NULL;
51
52 dev->node = of_node_get(np);
53 dev->dev.dma_mask = &dev->dma_mask;
54 dev->dev.parent = parent;
55 dev->dev.release = of_release_dev;
56 dev->dev.archdata.of_node = np;
57
58 if (bus_id)
59 dev_set_name(&dev->dev, bus_id);
60 else
61 of_device_make_bus_id(dev);
62
63 return dev;
64}
65EXPORT_SYMBOL(of_device_alloc);
66
67int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
68{
69 struct of_device *ofdev;
70 const char *compat;
71 int seen = 0, cplen, sl;
72
73 if (!dev)
74 return -ENODEV;
75
76 ofdev = to_of_device(dev);
77
78 if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
79 return -ENOMEM;
80
81 if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
82 return -ENOMEM;
83
84 /* Since the compatible field can contain pretty much anything
85 * it's not really legal to split it out with commas. We split it
86 * up using a number of environment variables instead. */
87
88 compat = of_get_property(ofdev->node, "compatible", &cplen);
89 while (compat && *compat && cplen > 0) {
90 if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
91 return -ENOMEM;
92
93 sl = strlen(compat) + 1;
94 compat += sl;
95 cplen -= sl;
96 seen++;
97 }
98
99 if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
100 return -ENOMEM;
101
102 /* modalias is trickier, we add it in 2 steps */
103 if (add_uevent_var(env, "MODALIAS="))
104 return -ENOMEM;
105 sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
106 sizeof(env->buf) - env->buflen);
107 if (sl >= (sizeof(env->buf) - env->buflen))
108 return -ENOMEM;
109 env->buflen += sl;
110
111 return 0;
112}
113EXPORT_SYMBOL(of_device_uevent);
diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c
new file mode 100644
index 000000000000..acf4574d0f18
--- /dev/null
+++ b/arch/microblaze/kernel/of_platform.c
@@ -0,0 +1,201 @@
1/*
2 * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
3 * <benh@kernel.crashing.org>
4 * and Arnd Bergmann, IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#undef DEBUG
14
15#include <linux/string.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/mod_devicetable.h>
20#include <linux/slab.h>
21#include <linux/pci.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/of_platform.h>
25
26#include <linux/errno.h>
27#include <linux/topology.h>
28#include <asm/atomic.h>
29
30struct bus_type of_platform_bus_type = {
31 .uevent = of_device_uevent,
32};
33EXPORT_SYMBOL(of_platform_bus_type);
34
35static int __init of_bus_driver_init(void)
36{
37 return of_bus_type_init(&of_platform_bus_type, "of_platform");
38}
39postcore_initcall(of_bus_driver_init);
40
41struct of_device *of_platform_device_create(struct device_node *np,
42 const char *bus_id,
43 struct device *parent)
44{
45 struct of_device *dev;
46
47 dev = of_device_alloc(np, bus_id, parent);
48 if (!dev)
49 return NULL;
50
51 dev->dma_mask = 0xffffffffUL;
52 dev->dev.bus = &of_platform_bus_type;
53
54 /* We do not fill the DMA ops for platform devices by default.
55 * This is currently the responsibility of the platform code
56 * to do such, possibly using a device notifier
57 */
58
59 if (of_device_register(dev) != 0) {
60 of_device_free(dev);
61 return NULL;
62 }
63
64 return dev;
65}
66EXPORT_SYMBOL(of_platform_device_create);
67
68/**
69 * of_platform_bus_create - Create an OF device for a bus node and all its
70 * children. Optionally recursively instanciate matching busses.
71 * @bus: device node of the bus to instanciate
72 * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
73 * disallow recursive creation of child busses
74 */
75static int of_platform_bus_create(const struct device_node *bus,
76 const struct of_device_id *matches,
77 struct device *parent)
78{
79 struct device_node *child;
80 struct of_device *dev;
81 int rc = 0;
82
83 for_each_child_of_node(bus, child) {
84 pr_debug(" create child: %s\n", child->full_name);
85 dev = of_platform_device_create(child, NULL, parent);
86 if (dev == NULL)
87 rc = -ENOMEM;
88 else if (!of_match_node(matches, child))
89 continue;
90 if (rc == 0) {
91 pr_debug(" and sub busses\n");
92 rc = of_platform_bus_create(child, matches, &dev->dev);
93 }
94 if (rc) {
95 of_node_put(child);
96 break;
97 }
98 }
99 return rc;
100}
101
102
103/**
104 * of_platform_bus_probe - Probe the device-tree for platform busses
105 * @root: parent of the first level to probe or NULL for the root of the tree
106 * @matches: match table, NULL to use the default
107 * @parent: parent to hook devices from, NULL for toplevel
108 *
109 * Note that children of the provided root are not instanciated as devices
110 * unless the specified root itself matches the bus list and is not NULL.
111 */
112
113int of_platform_bus_probe(struct device_node *root,
114 const struct of_device_id *matches,
115 struct device *parent)
116{
117 struct device_node *child;
118 struct of_device *dev;
119 int rc = 0;
120
121 if (matches == NULL)
122 matches = of_default_bus_ids;
123 if (matches == OF_NO_DEEP_PROBE)
124 return -EINVAL;
125 if (root == NULL)
126 root = of_find_node_by_path("/");
127 else
128 of_node_get(root);
129
130 pr_debug("of_platform_bus_probe()\n");
131 pr_debug(" starting at: %s\n", root->full_name);
132
133 /* Do a self check of bus type, if there's a match, create
134 * children
135 */
136 if (of_match_node(matches, root)) {
137 pr_debug(" root match, create all sub devices\n");
138 dev = of_platform_device_create(root, NULL, parent);
139 if (dev == NULL) {
140 rc = -ENOMEM;
141 goto bail;
142 }
143 pr_debug(" create all sub busses\n");
144 rc = of_platform_bus_create(root, matches, &dev->dev);
145 goto bail;
146 }
147 for_each_child_of_node(root, child) {
148 if (!of_match_node(matches, child))
149 continue;
150
151 pr_debug(" match: %s\n", child->full_name);
152 dev = of_platform_device_create(child, NULL, parent);
153 if (dev == NULL)
154 rc = -ENOMEM;
155 else
156 rc = of_platform_bus_create(child, matches, &dev->dev);
157 if (rc) {
158 of_node_put(child);
159 break;
160 }
161 }
162 bail:
163 of_node_put(root);
164 return rc;
165}
166EXPORT_SYMBOL(of_platform_bus_probe);
167
168static int of_dev_node_match(struct device *dev, void *data)
169{
170 return to_of_device(dev)->node == data;
171}
172
173struct of_device *of_find_device_by_node(struct device_node *np)
174{
175 struct device *dev;
176
177 dev = bus_find_device(&of_platform_bus_type,
178 NULL, np, of_dev_node_match);
179 if (dev)
180 return to_of_device(dev);
181 return NULL;
182}
183EXPORT_SYMBOL(of_find_device_by_node);
184
185static int of_dev_phandle_match(struct device *dev, void *data)
186{
187 phandle *ph = data;
188 return to_of_device(dev)->node->linux_phandle == *ph;
189}
190
191struct of_device *of_find_device_by_phandle(phandle ph)
192{
193 struct device *dev;
194
195 dev = bus_find_device(&of_platform_bus_type,
196 NULL, &ph, of_dev_phandle_match);
197 if (dev)
198 return to_of_device(dev);
199 return NULL;
200}
201EXPORT_SYMBOL(of_find_device_by_phandle);
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
new file mode 100644
index 000000000000..07d4fa339eda
--- /dev/null
+++ b/arch/microblaze/kernel/process.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2008-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/module.h>
12#include <linux/sched.h>
13#include <linux/pm.h>
14#include <linux/tick.h>
15#include <linux/bitops.h>
16#include <asm/system.h>
17#include <asm/pgalloc.h>
18
19void show_regs(struct pt_regs *regs)
20{
21 printk(KERN_INFO " Registers dump: mode=%X\r\n", regs->pt_mode);
22 printk(KERN_INFO " r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n",
23 regs->r1, regs->r2, regs->r3, regs->r4);
24 printk(KERN_INFO " r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n",
25 regs->r5, regs->r6, regs->r7, regs->r8);
26 printk(KERN_INFO " r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n",
27 regs->r9, regs->r10, regs->r11, regs->r12);
28 printk(KERN_INFO " r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n",
29 regs->r13, regs->r14, regs->r15, regs->r16);
30 printk(KERN_INFO " r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n",
31 regs->r17, regs->r18, regs->r19, regs->r20);
32 printk(KERN_INFO " r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n",
33 regs->r21, regs->r22, regs->r23, regs->r24);
34 printk(KERN_INFO " r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n",
35 regs->r25, regs->r26, regs->r27, regs->r28);
36 printk(KERN_INFO " r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n",
37 regs->r29, regs->r30, regs->r31, regs->pc);
38 printk(KERN_INFO " msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n",
39 regs->msr, regs->ear, regs->esr, regs->fsr);
40}
41
42void (*pm_idle)(void);
43void (*pm_power_off)(void) = NULL;
44EXPORT_SYMBOL(pm_power_off);
45
46static int hlt_counter = 1;
47
48void disable_hlt(void)
49{
50 hlt_counter++;
51}
52EXPORT_SYMBOL(disable_hlt);
53
54void enable_hlt(void)
55{
56 hlt_counter--;
57}
58EXPORT_SYMBOL(enable_hlt);
59
60static int __init nohlt_setup(char *__unused)
61{
62 hlt_counter = 1;
63 return 1;
64}
65__setup("nohlt", nohlt_setup);
66
67static int __init hlt_setup(char *__unused)
68{
69 hlt_counter = 0;
70 return 1;
71}
72__setup("hlt", hlt_setup);
73
74void default_idle(void)
75{
76 if (!hlt_counter) {
77 clear_thread_flag(TIF_POLLING_NRFLAG);
78 smp_mb__after_clear_bit();
79 local_irq_disable();
80 while (!need_resched())
81 cpu_sleep();
82 local_irq_enable();
83 set_thread_flag(TIF_POLLING_NRFLAG);
84 } else
85 while (!need_resched())
86 cpu_relax();
87}
88
89void cpu_idle(void)
90{
91 set_thread_flag(TIF_POLLING_NRFLAG);
92
93 /* endless idle loop with no priority at all */
94 while (1) {
95 void (*idle)(void) = pm_idle;
96
97 if (!idle)
98 idle = default_idle;
99
100 tick_nohz_stop_sched_tick(1);
101 while (!need_resched())
102 idle();
103 tick_nohz_restart_sched_tick();
104
105 preempt_enable_no_resched();
106 schedule();
107 preempt_disable();
108 check_pgt_cache();
109 }
110}
111
112void flush_thread(void)
113{
114}
115
116int copy_thread(unsigned long clone_flags, unsigned long usp,
117 unsigned long unused,
118 struct task_struct *p, struct pt_regs *regs)
119{
120 struct pt_regs *childregs = task_pt_regs(p);
121 struct thread_info *ti = task_thread_info(p);
122
123 *childregs = *regs;
124 if (user_mode(regs))
125 childregs->r1 = usp;
126 else
127 childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
128
129 memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
130 ti->cpu_context.r1 = (unsigned long)childregs;
131 ti->cpu_context.msr = (unsigned long)childregs->msr;
132 ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
133
134 if (clone_flags & CLONE_SETTLS)
135 ;
136
137 return 0;
138}
139
140/*
141 * Return saved PC of a blocked thread.
142 */
143unsigned long thread_saved_pc(struct task_struct *tsk)
144{
145 struct cpu_context *ctx =
146 &(((struct thread_info *)(tsk->stack))->cpu_context);
147
148 /* Check whether the thread is blocked in resume() */
149 if (in_sched_functions(ctx->r15))
150 return (unsigned long)ctx->r15;
151 else
152 return ctx->r14;
153}
154
155static void kernel_thread_helper(int (*fn)(void *), void *arg)
156{
157 fn(arg);
158 do_exit(-1);
159}
160
161int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
162{
163 struct pt_regs regs;
164
165 memset(&regs, 0, sizeof(regs));
166 /* store them in non-volatile registers */
167 regs.r5 = (unsigned long)fn;
168 regs.r6 = (unsigned long)arg;
169 local_save_flags(regs.msr);
170 regs.pc = (unsigned long)kernel_thread_helper;
171 regs.pt_mode = 1;
172
173 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
174 &regs, 0, NULL, NULL);
175}
176
177unsigned long get_wchan(struct task_struct *p)
178{
179/* TBD (used by procfs) */
180 return 0;
181}
182
183/* Set up a thread for executing a new program */
184void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
185{
186 set_fs(USER_DS);
187 regs->pc = pc;
188 regs->r1 = usp;
189 regs->pt_mode = 0;
190}
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
new file mode 100644
index 000000000000..34c48718061a
--- /dev/null
+++ b/arch/microblaze/kernel/prom.c
@@ -0,0 +1,1146 @@
1/*
2 * Procedures for creating, accessing and interpreting the device tree.
3 *
4 * Paul Mackerras August 1996.
5 * Copyright (C) 1996-2005 Paul Mackerras.
6 *
7 * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8 * {engebret|bergner}@us.ibm.com
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 */
15
16#include <stdarg.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/init.h>
20#include <linux/threads.h>
21#include <linux/spinlock.h>
22#include <linux/types.h>
23#include <linux/pci.h>
24#include <linux/stringify.h>
25#include <linux/delay.h>
26#include <linux/initrd.h>
27#include <linux/bitops.h>
28#include <linux/module.h>
29#include <linux/kexec.h>
30#include <linux/debugfs.h>
31#include <linux/irq.h>
32#include <linux/lmb.h>
33
34#include <asm/prom.h>
35#include <asm/page.h>
36#include <asm/processor.h>
37#include <asm/irq.h>
38#include <linux/io.h>
39#include <asm/system.h>
40#include <asm/mmu.h>
41#include <asm/pgtable.h>
42#include <asm/sections.h>
43#include <asm/pci-bridge.h>
44
45static int __initdata dt_root_addr_cells;
46static int __initdata dt_root_size_cells;
47
48typedef u32 cell_t;
49
50static struct boot_param_header *initial_boot_params;
51
52/* export that to outside world */
53struct device_node *of_chosen;
54
55static inline char *find_flat_dt_string(u32 offset)
56{
57 return ((char *)initial_boot_params) +
58 initial_boot_params->off_dt_strings + offset;
59}
60
61/**
62 * This function is used to scan the flattened device-tree, it is
63 * used to extract the memory informations at boot before we can
64 * unflatten the tree
65 */
66int __init of_scan_flat_dt(int (*it)(unsigned long node,
67 const char *uname, int depth,
68 void *data),
69 void *data)
70{
71 unsigned long p = ((unsigned long)initial_boot_params) +
72 initial_boot_params->off_dt_struct;
73 int rc = 0;
74 int depth = -1;
75
76 do {
77 u32 tag = *((u32 *)p);
78 char *pathp;
79
80 p += 4;
81 if (tag == OF_DT_END_NODE) {
82 depth--;
83 continue;
84 }
85 if (tag == OF_DT_NOP)
86 continue;
87 if (tag == OF_DT_END)
88 break;
89 if (tag == OF_DT_PROP) {
90 u32 sz = *((u32 *)p);
91 p += 8;
92 if (initial_boot_params->version < 0x10)
93 p = _ALIGN(p, sz >= 8 ? 8 : 4);
94 p += sz;
95 p = _ALIGN(p, 4);
96 continue;
97 }
98 if (tag != OF_DT_BEGIN_NODE) {
99 printk(KERN_WARNING "Invalid tag %x scanning flattened"
100 " device tree !\n", tag);
101 return -EINVAL;
102 }
103 depth++;
104 pathp = (char *)p;
105 p = _ALIGN(p + strlen(pathp) + 1, 4);
106 if ((*pathp) == '/') {
107 char *lp, *np;
108 for (lp = NULL, np = pathp; *np; np++)
109 if ((*np) == '/')
110 lp = np+1;
111 if (lp != NULL)
112 pathp = lp;
113 }
114 rc = it(p, pathp, depth, data);
115 if (rc != 0)
116 break;
117 } while (1);
118
119 return rc;
120}
121
122unsigned long __init of_get_flat_dt_root(void)
123{
124 unsigned long p = ((unsigned long)initial_boot_params) +
125 initial_boot_params->off_dt_struct;
126
127 while (*((u32 *)p) == OF_DT_NOP)
128 p += 4;
129 BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE);
130 p += 4;
131 return _ALIGN(p + strlen((char *)p) + 1, 4);
132}
133
134/**
135 * This function can be used within scan_flattened_dt callback to get
136 * access to properties
137 */
138void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
139 unsigned long *size)
140{
141 unsigned long p = node;
142
143 do {
144 u32 tag = *((u32 *)p);
145 u32 sz, noff;
146 const char *nstr;
147
148 p += 4;
149 if (tag == OF_DT_NOP)
150 continue;
151 if (tag != OF_DT_PROP)
152 return NULL;
153
154 sz = *((u32 *)p);
155 noff = *((u32 *)(p + 4));
156 p += 8;
157 if (initial_boot_params->version < 0x10)
158 p = _ALIGN(p, sz >= 8 ? 8 : 4);
159
160 nstr = find_flat_dt_string(noff);
161 if (nstr == NULL) {
162 printk(KERN_WARNING "Can't find property index"
163 " name !\n");
164 return NULL;
165 }
166 if (strcmp(name, nstr) == 0) {
167 if (size)
168 *size = sz;
169 return (void *)p;
170 }
171 p += sz;
172 p = _ALIGN(p, 4);
173 } while (1);
174}
175
176int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
177{
178 const char *cp;
179 unsigned long cplen, l;
180
181 cp = of_get_flat_dt_prop(node, "compatible", &cplen);
182 if (cp == NULL)
183 return 0;
184 while (cplen > 0) {
185 if (strncasecmp(cp, compat, strlen(compat)) == 0)
186 return 1;
187 l = strlen(cp) + 1;
188 cp += l;
189 cplen -= l;
190 }
191
192 return 0;
193}
194
195static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
196 unsigned long align)
197{
198 void *res;
199
200 *mem = _ALIGN(*mem, align);
201 res = (void *)*mem;
202 *mem += size;
203
204 return res;
205}
206
207static unsigned long __init unflatten_dt_node(unsigned long mem,
208 unsigned long *p,
209 struct device_node *dad,
210 struct device_node ***allnextpp,
211 unsigned long fpsize)
212{
213 struct device_node *np;
214 struct property *pp, **prev_pp = NULL;
215 char *pathp;
216 u32 tag;
217 unsigned int l, allocl;
218 int has_name = 0;
219 int new_format = 0;
220
221 tag = *((u32 *)(*p));
222 if (tag != OF_DT_BEGIN_NODE) {
223 printk("Weird tag at start of node: %x\n", tag);
224 return mem;
225 }
226 *p += 4;
227 pathp = (char *)*p;
228 l = allocl = strlen(pathp) + 1;
229 *p = _ALIGN(*p + l, 4);
230
231 /* version 0x10 has a more compact unit name here instead of the full
232 * path. we accumulate the full path size using "fpsize", we'll rebuild
233 * it later. We detect this because the first character of the name is
234 * not '/'.
235 */
236 if ((*pathp) != '/') {
237 new_format = 1;
238 if (fpsize == 0) {
239 /* root node: special case. fpsize accounts for path
240 * plus terminating zero. root node only has '/', so
241 * fpsize should be 2, but we want to avoid the first
242 * level nodes to have two '/' so we use fpsize 1 here
243 */
244 fpsize = 1;
245 allocl = 2;
246 } else {
247 /* account for '/' and path size minus terminal 0
248 * already in 'l'
249 */
250 fpsize += l;
251 allocl = fpsize;
252 }
253 }
254
255 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
256 __alignof__(struct device_node));
257 if (allnextpp) {
258 memset(np, 0, sizeof(*np));
259 np->full_name = ((char *)np) + sizeof(struct device_node);
260 if (new_format) {
261 char *p2 = np->full_name;
262 /* rebuild full path for new format */
263 if (dad && dad->parent) {
264 strcpy(p2, dad->full_name);
265#ifdef DEBUG
266 if ((strlen(p2) + l + 1) != allocl) {
267 pr_debug("%s: p: %d, l: %d, a: %d\n",
268 pathp, (int)strlen(p2),
269 l, allocl);
270 }
271#endif
272 p2 += strlen(p2);
273 }
274 *(p2++) = '/';
275 memcpy(p2, pathp, l);
276 } else
277 memcpy(np->full_name, pathp, l);
278 prev_pp = &np->properties;
279 **allnextpp = np;
280 *allnextpp = &np->allnext;
281 if (dad != NULL) {
282 np->parent = dad;
283 /* we temporarily use the next field as `last_child'*/
284 if (dad->next == NULL)
285 dad->child = np;
286 else
287 dad->next->sibling = np;
288 dad->next = np;
289 }
290 kref_init(&np->kref);
291 }
292 while (1) {
293 u32 sz, noff;
294 char *pname;
295
296 tag = *((u32 *)(*p));
297 if (tag == OF_DT_NOP) {
298 *p += 4;
299 continue;
300 }
301 if (tag != OF_DT_PROP)
302 break;
303 *p += 4;
304 sz = *((u32 *)(*p));
305 noff = *((u32 *)((*p) + 4));
306 *p += 8;
307 if (initial_boot_params->version < 0x10)
308 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
309
310 pname = find_flat_dt_string(noff);
311 if (pname == NULL) {
312 printk(KERN_INFO
313 "Can't find property name in list !\n");
314 break;
315 }
316 if (strcmp(pname, "name") == 0)
317 has_name = 1;
318 l = strlen(pname) + 1;
319 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
320 __alignof__(struct property));
321 if (allnextpp) {
322 if (strcmp(pname, "linux,phandle") == 0) {
323 np->node = *((u32 *)*p);
324 if (np->linux_phandle == 0)
325 np->linux_phandle = np->node;
326 }
327 if (strcmp(pname, "ibm,phandle") == 0)
328 np->linux_phandle = *((u32 *)*p);
329 pp->name = pname;
330 pp->length = sz;
331 pp->value = (void *)*p;
332 *prev_pp = pp;
333 prev_pp = &pp->next;
334 }
335 *p = _ALIGN((*p) + sz, 4);
336 }
337 /* with version 0x10 we may not have the name property, recreate
338 * it here from the unit name if absent
339 */
340 if (!has_name) {
341 char *p1 = pathp, *ps = pathp, *pa = NULL;
342 int sz;
343
344 while (*p1) {
345 if ((*p1) == '@')
346 pa = p1;
347 if ((*p1) == '/')
348 ps = p1 + 1;
349 p1++;
350 }
351 if (pa < ps)
352 pa = p1;
353 sz = (pa - ps) + 1;
354 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
355 __alignof__(struct property));
356 if (allnextpp) {
357 pp->name = "name";
358 pp->length = sz;
359 pp->value = pp + 1;
360 *prev_pp = pp;
361 prev_pp = &pp->next;
362 memcpy(pp->value, ps, sz - 1);
363 ((char *)pp->value)[sz - 1] = 0;
364 pr_debug("fixed up name for %s -> %s\n", pathp,
365 (char *)pp->value);
366 }
367 }
368 if (allnextpp) {
369 *prev_pp = NULL;
370 np->name = of_get_property(np, "name", NULL);
371 np->type = of_get_property(np, "device_type", NULL);
372
373 if (!np->name)
374 np->name = "<NULL>";
375 if (!np->type)
376 np->type = "<NULL>";
377 }
378 while (tag == OF_DT_BEGIN_NODE) {
379 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
380 tag = *((u32 *)(*p));
381 }
382 if (tag != OF_DT_END_NODE) {
383 printk(KERN_INFO "Weird tag at end of node: %x\n", tag);
384 return mem;
385 }
386 *p += 4;
387 return mem;
388}
389
390/**
391 * unflattens the device-tree passed by the firmware, creating the
392 * tree of struct device_node. It also fills the "name" and "type"
393 * pointers of the nodes so the normal device-tree walking functions
394 * can be used (this used to be done by finish_device_tree)
395 */
396void __init unflatten_device_tree(void)
397{
398 unsigned long start, mem, size;
399 struct device_node **allnextp = &allnodes;
400
401 pr_debug(" -> unflatten_device_tree()\n");
402
403 /* First pass, scan for size */
404 start = ((unsigned long)initial_boot_params) +
405 initial_boot_params->off_dt_struct;
406 size = unflatten_dt_node(0, &start, NULL, NULL, 0);
407 size = (size | 3) + 1;
408
409 pr_debug(" size is %lx, allocating...\n", size);
410
411 /* Allocate memory for the expanded device tree */
412 mem = lmb_alloc(size + 4, __alignof__(struct device_node));
413 mem = (unsigned long) __va(mem);
414
415 ((u32 *)mem)[size / 4] = 0xdeadbeef;
416
417 pr_debug(" unflattening %lx...\n", mem);
418
419 /* Second pass, do actual unflattening */
420 start = ((unsigned long)initial_boot_params) +
421 initial_boot_params->off_dt_struct;
422 unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
423 if (*((u32 *)start) != OF_DT_END)
424 printk(KERN_WARNING "Weird tag at end of tree: %08x\n",
425 *((u32 *)start));
426 if (((u32 *)mem)[size / 4] != 0xdeadbeef)
427 printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
428 ((u32 *)mem)[size / 4]);
429 *allnextp = NULL;
430
431 /* Get pointer to OF "/chosen" node for use everywhere */
432 of_chosen = of_find_node_by_path("/chosen");
433 if (of_chosen == NULL)
434 of_chosen = of_find_node_by_path("/chosen@0");
435
436 pr_debug(" <- unflatten_device_tree()\n");
437}
438
439#define early_init_dt_scan_drconf_memory(node) 0
440
441static int __init early_init_dt_scan_cpus(unsigned long node,
442 const char *uname, int depth,
443 void *data)
444{
445 static int logical_cpuid;
446 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
447 const u32 *intserv;
448 int i, nthreads;
449 int found = 0;
450
451 /* We are scanning "cpu" nodes only */
452 if (type == NULL || strcmp(type, "cpu") != 0)
453 return 0;
454
455 /* Get physical cpuid */
456 intserv = of_get_flat_dt_prop(node, "reg", NULL);
457 nthreads = 1;
458
459 /*
460 * Now see if any of these threads match our boot cpu.
461 * NOTE: This must match the parsing done in smp_setup_cpu_maps.
462 */
463 for (i = 0; i < nthreads; i++) {
464 /*
465 * version 2 of the kexec param format adds the phys cpuid of
466 * booted proc.
467 */
468 if (initial_boot_params && initial_boot_params->version >= 2) {
469 if (intserv[i] ==
470 initial_boot_params->boot_cpuid_phys) {
471 found = 1;
472 break;
473 }
474 } else {
475 /*
476 * Check if it's the boot-cpu, set it's hw index now,
477 * unfortunately this format did not support booting
478 * off secondary threads.
479 */
480 if (of_get_flat_dt_prop(node,
481 "linux,boot-cpu", NULL) != NULL) {
482 found = 1;
483 break;
484 }
485 }
486
487#ifdef CONFIG_SMP
488 /* logical cpu id is always 0 on UP kernels */
489 logical_cpuid++;
490#endif
491 }
492
493 if (found) {
494 pr_debug("boot cpu: logical %d physical %d\n", logical_cpuid,
495 intserv[i]);
496 boot_cpuid = logical_cpuid;
497 }
498
499 return 0;
500}
501
502#ifdef CONFIG_BLK_DEV_INITRD
503static void __init early_init_dt_check_for_initrd(unsigned long node)
504{
505 unsigned long l;
506 u32 *prop;
507
508 pr_debug("Looking for initrd properties... ");
509
510 prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
511 if (prop) {
512 initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
513
514 prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
515 if (prop) {
516 initrd_end = (unsigned long)
517 __va(of_read_ulong(prop, l/4));
518 initrd_below_start_ok = 1;
519 } else {
520 initrd_start = 0;
521 }
522 }
523
524 pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n",
525 initrd_start, initrd_end);
526}
527#else
528static inline void early_init_dt_check_for_initrd(unsigned long node)
529{
530}
531#endif /* CONFIG_BLK_DEV_INITRD */
532
533static int __init early_init_dt_scan_chosen(unsigned long node,
534 const char *uname, int depth, void *data)
535{
536 unsigned long l;
537 char *p;
538
539 pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
540
541 if (depth != 1 ||
542 (strcmp(uname, "chosen") != 0 &&
543 strcmp(uname, "chosen@0") != 0))
544 return 0;
545
546#ifdef CONFIG_KEXEC
547 lprop = (u64 *)of_get_flat_dt_prop(node,
548 "linux,crashkernel-base", NULL);
549 if (lprop)
550 crashk_res.start = *lprop;
551
552 lprop = (u64 *)of_get_flat_dt_prop(node,
553 "linux,crashkernel-size", NULL);
554 if (lprop)
555 crashk_res.end = crashk_res.start + *lprop - 1;
556#endif
557
558 early_init_dt_check_for_initrd(node);
559
560 /* Retreive command line */
561 p = of_get_flat_dt_prop(node, "bootargs", &l);
562 if (p != NULL && l > 0)
563 strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
564
565#ifdef CONFIG_CMDLINE
566 if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
567 strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
568#endif /* CONFIG_CMDLINE */
569
570 pr_debug("Command line is: %s\n", cmd_line);
571
572 /* break now */
573 return 1;
574}
575
576static int __init early_init_dt_scan_root(unsigned long node,
577 const char *uname, int depth, void *data)
578{
579 u32 *prop;
580
581 if (depth != 0)
582 return 0;
583
584 prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
585 dt_root_size_cells = (prop == NULL) ? 1 : *prop;
586 pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
587
588 prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
589 dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
590 pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
591
592 /* break now */
593 return 1;
594}
595
596static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
597{
598 cell_t *p = *cellp;
599
600 *cellp = p + s;
601 return of_read_number(p, s);
602}
603
604static int __init early_init_dt_scan_memory(unsigned long node,
605 const char *uname, int depth, void *data)
606{
607 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
608 cell_t *reg, *endp;
609 unsigned long l;
610
611 /* Look for the ibm,dynamic-reconfiguration-memory node */
612/* if (depth == 1 &&
613 strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
614 return early_init_dt_scan_drconf_memory(node);
615*/
616 /* We are scanning "memory" nodes only */
617 if (type == NULL) {
618 /*
619 * The longtrail doesn't have a device_type on the
620 * /memory node, so look for the node called /memory@0.
621 */
622 if (depth != 1 || strcmp(uname, "memory@0") != 0)
623 return 0;
624 } else if (strcmp(type, "memory") != 0)
625 return 0;
626
627 reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
628 if (reg == NULL)
629 reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
630 if (reg == NULL)
631 return 0;
632
633 endp = reg + (l / sizeof(cell_t));
634
635 pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
636 uname, l, reg[0], reg[1], reg[2], reg[3]);
637
638 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
639 u64 base, size;
640
641 base = dt_mem_next_cell(dt_root_addr_cells, &reg);
642 size = dt_mem_next_cell(dt_root_size_cells, &reg);
643
644 if (size == 0)
645 continue;
646 pr_debug(" - %llx , %llx\n", (unsigned long long)base,
647 (unsigned long long)size);
648
649 lmb_add(base, size);
650 }
651 return 0;
652}
653
654#ifdef CONFIG_PHYP_DUMP
655/**
656 * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg
657 *
658 * Function to find the largest size we need to reserve
659 * during early boot process.
660 *
661 * It either looks for boot param and returns that OR
662 * returns larger of 256 or 5% rounded down to multiples of 256MB.
663 *
664 */
665static inline unsigned long phyp_dump_calculate_reserve_size(void)
666{
667 unsigned long tmp;
668
669 if (phyp_dump_info->reserve_bootvar)
670 return phyp_dump_info->reserve_bootvar;
671
672 /* divide by 20 to get 5% of value */
673 tmp = lmb_end_of_DRAM();
674 do_div(tmp, 20);
675
676 /* round it down in multiples of 256 */
677 tmp = tmp & ~0x0FFFFFFFUL;
678
679 return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END);
680}
681
682/**
683 * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
684 *
685 * This routine may reserve memory regions in the kernel only
686 * if the system is supported and a dump was taken in last
687 * boot instance or if the hardware is supported and the
688 * scratch area needs to be setup. In other instances it returns
689 * without reserving anything. The memory in case of dump being
690 * active is freed when the dump is collected (by userland tools).
691 */
692static void __init phyp_dump_reserve_mem(void)
693{
694 unsigned long base, size;
695 unsigned long variable_reserve_size;
696
697 if (!phyp_dump_info->phyp_dump_configured) {
698 printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
699 return;
700 }
701
702 if (!phyp_dump_info->phyp_dump_at_boot) {
703 printk(KERN_INFO "Phyp-dump disabled at boot time\n");
704 return;
705 }
706
707 variable_reserve_size = phyp_dump_calculate_reserve_size();
708
709 if (phyp_dump_info->phyp_dump_is_active) {
710 /* Reserve *everything* above RMR.Area freed by userland tools*/
711 base = variable_reserve_size;
712 size = lmb_end_of_DRAM() - base;
713
714 /* XXX crashed_ram_end is wrong, since it may be beyond
715 * the memory_limit, it will need to be adjusted. */
716 lmb_reserve(base, size);
717
718 phyp_dump_info->init_reserve_start = base;
719 phyp_dump_info->init_reserve_size = size;
720 } else {
721 size = phyp_dump_info->cpu_state_size +
722 phyp_dump_info->hpte_region_size +
723 variable_reserve_size;
724 base = lmb_end_of_DRAM() - size;
725 lmb_reserve(base, size);
726 phyp_dump_info->init_reserve_start = base;
727 phyp_dump_info->init_reserve_size = size;
728 }
729}
730#else
731static inline void __init phyp_dump_reserve_mem(void) {}
732#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */
733
734#ifdef CONFIG_EARLY_PRINTK
735/* MS this is Microblaze specifig function */
736static int __init early_init_dt_scan_serial(unsigned long node,
737 const char *uname, int depth, void *data)
738{
739 unsigned long l;
740 char *p;
741 int *addr;
742
743 pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
744
745/* find all serial nodes */
746 if (strncmp(uname, "serial", 6) != 0)
747 return 0;
748
749 early_init_dt_check_for_initrd(node);
750
751/* find compatible node with uartlite */
752 p = of_get_flat_dt_prop(node, "compatible", &l);
753 if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
754 (strncmp(p, "xlnx,opb-uartlite", 17) != 0))
755 return 0;
756
757 addr = of_get_flat_dt_prop(node, "reg", &l);
758 return *addr; /* return address */
759}
760
761/* this function is looking for early uartlite console - Microblaze specific */
762int __init early_uartlite_console(void)
763{
764 return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
765}
766#endif
767
768void __init early_init_devtree(void *params)
769{
770 pr_debug(" -> early_init_devtree(%p)\n", params);
771
772 /* Setup flat device-tree pointer */
773 initial_boot_params = params;
774
775#ifdef CONFIG_PHYP_DUMP
776 /* scan tree to see if dump occured during last boot */
777 of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
778#endif
779
780 /* Retrieve various informations from the /chosen node of the
781 * device-tree, including the platform type, initrd location and
782 * size, TCE reserve, and more ...
783 */
784 of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
785
786 /* Scan memory nodes and rebuild LMBs */
787 lmb_init();
788 of_scan_flat_dt(early_init_dt_scan_root, NULL);
789 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
790
791 /* Save command line for /proc/cmdline and then parse parameters */
792 strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
793 parse_early_param();
794
795 lmb_analyze();
796
797 pr_debug("Phys. mem: %lx\n", (unsigned long) lmb_phys_mem_size());
798
799 pr_debug("Scanning CPUs ...\n");
800
801 /* Retreive CPU related informations from the flat tree
802 * (altivec support, boot CPU ID, ...)
803 */
804 of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
805
806 pr_debug(" <- early_init_devtree()\n");
807}
808
809/**
810 * Indicates whether the root node has a given value in its
811 * compatible property.
812 */
813int machine_is_compatible(const char *compat)
814{
815 struct device_node *root;
816 int rc = 0;
817
818 root = of_find_node_by_path("/");
819 if (root) {
820 rc = of_device_is_compatible(root, compat);
821 of_node_put(root);
822 }
823 return rc;
824}
825EXPORT_SYMBOL(machine_is_compatible);
826
827/*******
828 *
829 * New implementation of the OF "find" APIs, return a refcounted
830 * object, call of_node_put() when done. The device tree and list
831 * are protected by a rw_lock.
832 *
833 * Note that property management will need some locking as well,
834 * this isn't dealt with yet.
835 *
836 *******/
837
838/**
839 * of_find_node_by_phandle - Find a node given a phandle
840 * @handle: phandle of the node to find
841 *
842 * Returns a node pointer with refcount incremented, use
843 * of_node_put() on it when done.
844 */
845struct device_node *of_find_node_by_phandle(phandle handle)
846{
847 struct device_node *np;
848
849 read_lock(&devtree_lock);
850 for (np = allnodes; np != NULL; np = np->allnext)
851 if (np->linux_phandle == handle)
852 break;
853 of_node_get(np);
854 read_unlock(&devtree_lock);
855 return np;
856}
857EXPORT_SYMBOL(of_find_node_by_phandle);
858
859/**
860 * of_find_all_nodes - Get next node in global list
861 * @prev: Previous node or NULL to start iteration
862 * of_node_put() will be called on it
863 *
864 * Returns a node pointer with refcount incremented, use
865 * of_node_put() on it when done.
866 */
867struct device_node *of_find_all_nodes(struct device_node *prev)
868{
869 struct device_node *np;
870
871 read_lock(&devtree_lock);
872 np = prev ? prev->allnext : allnodes;
873 for (; np != NULL; np = np->allnext)
874 if (of_node_get(np))
875 break;
876 of_node_put(prev);
877 read_unlock(&devtree_lock);
878 return np;
879}
880EXPORT_SYMBOL(of_find_all_nodes);
881
882/**
883 * of_node_get - Increment refcount of a node
884 * @node: Node to inc refcount, NULL is supported to
885 * simplify writing of callers
886 *
887 * Returns node.
888 */
889struct device_node *of_node_get(struct device_node *node)
890{
891 if (node)
892 kref_get(&node->kref);
893 return node;
894}
895EXPORT_SYMBOL(of_node_get);
896
897static inline struct device_node *kref_to_device_node(struct kref *kref)
898{
899 return container_of(kref, struct device_node, kref);
900}
901
902/**
903 * of_node_release - release a dynamically allocated node
904 * @kref: kref element of the node to be released
905 *
906 * In of_node_put() this function is passed to kref_put()
907 * as the destructor.
908 */
909static void of_node_release(struct kref *kref)
910{
911 struct device_node *node = kref_to_device_node(kref);
912 struct property *prop = node->properties;
913
914 /* We should never be releasing nodes that haven't been detached. */
915 if (!of_node_check_flag(node, OF_DETACHED)) {
916 printk(KERN_INFO "WARNING: Bad of_node_put() on %s\n",
917 node->full_name);
918 dump_stack();
919 kref_init(&node->kref);
920 return;
921 }
922
923 if (!of_node_check_flag(node, OF_DYNAMIC))
924 return;
925
926 while (prop) {
927 struct property *next = prop->next;
928 kfree(prop->name);
929 kfree(prop->value);
930 kfree(prop);
931 prop = next;
932
933 if (!prop) {
934 prop = node->deadprops;
935 node->deadprops = NULL;
936 }
937 }
938 kfree(node->full_name);
939 kfree(node->data);
940 kfree(node);
941}
942
943/**
944 * of_node_put - Decrement refcount of a node
945 * @node: Node to dec refcount, NULL is supported to
946 * simplify writing of callers
947 *
948 */
949void of_node_put(struct device_node *node)
950{
951 if (node)
952 kref_put(&node->kref, of_node_release);
953}
954EXPORT_SYMBOL(of_node_put);
955
956/*
957 * Plug a device node into the tree and global list.
958 */
959void of_attach_node(struct device_node *np)
960{
961 unsigned long flags;
962
963 write_lock_irqsave(&devtree_lock, flags);
964 np->sibling = np->parent->child;
965 np->allnext = allnodes;
966 np->parent->child = np;
967 allnodes = np;
968 write_unlock_irqrestore(&devtree_lock, flags);
969}
970
971/*
972 * "Unplug" a node from the device tree. The caller must hold
973 * a reference to the node. The memory associated with the node
974 * is not freed until its refcount goes to zero.
975 */
976void of_detach_node(struct device_node *np)
977{
978 struct device_node *parent;
979 unsigned long flags;
980
981 write_lock_irqsave(&devtree_lock, flags);
982
983 parent = np->parent;
984 if (!parent)
985 goto out_unlock;
986
987 if (allnodes == np)
988 allnodes = np->allnext;
989 else {
990 struct device_node *prev;
991 for (prev = allnodes;
992 prev->allnext != np;
993 prev = prev->allnext)
994 ;
995 prev->allnext = np->allnext;
996 }
997
998 if (parent->child == np)
999 parent->child = np->sibling;
1000 else {
1001 struct device_node *prevsib;
1002 for (prevsib = np->parent->child;
1003 prevsib->sibling != np;
1004 prevsib = prevsib->sibling)
1005 ;
1006 prevsib->sibling = np->sibling;
1007 }
1008
1009 of_node_set_flag(np, OF_DETACHED);
1010
1011out_unlock:
1012 write_unlock_irqrestore(&devtree_lock, flags);
1013}
1014
1015/*
1016 * Add a property to a node
1017 */
1018int prom_add_property(struct device_node *np, struct property *prop)
1019{
1020 struct property **next;
1021 unsigned long flags;
1022
1023 prop->next = NULL;
1024 write_lock_irqsave(&devtree_lock, flags);
1025 next = &np->properties;
1026 while (*next) {
1027 if (strcmp(prop->name, (*next)->name) == 0) {
1028 /* duplicate ! don't insert it */
1029 write_unlock_irqrestore(&devtree_lock, flags);
1030 return -1;
1031 }
1032 next = &(*next)->next;
1033 }
1034 *next = prop;
1035 write_unlock_irqrestore(&devtree_lock, flags);
1036
1037#ifdef CONFIG_PROC_DEVICETREE
1038 /* try to add to proc as well if it was initialized */
1039 if (np->pde)
1040 proc_device_tree_add_prop(np->pde, prop);
1041#endif /* CONFIG_PROC_DEVICETREE */
1042
1043 return 0;
1044}
1045
1046/*
1047 * Remove a property from a node. Note that we don't actually
1048 * remove it, since we have given out who-knows-how-many pointers
1049 * to the data using get-property. Instead we just move the property
1050 * to the "dead properties" list, so it won't be found any more.
1051 */
1052int prom_remove_property(struct device_node *np, struct property *prop)
1053{
1054 struct property **next;
1055 unsigned long flags;
1056 int found = 0;
1057
1058 write_lock_irqsave(&devtree_lock, flags);
1059 next = &np->properties;
1060 while (*next) {
1061 if (*next == prop) {
1062 /* found the node */
1063 *next = prop->next;
1064 prop->next = np->deadprops;
1065 np->deadprops = prop;
1066 found = 1;
1067 break;
1068 }
1069 next = &(*next)->next;
1070 }
1071 write_unlock_irqrestore(&devtree_lock, flags);
1072
1073 if (!found)
1074 return -ENODEV;
1075
1076#ifdef CONFIG_PROC_DEVICETREE
1077 /* try to remove the proc node as well */
1078 if (np->pde)
1079 proc_device_tree_remove_prop(np->pde, prop);
1080#endif /* CONFIG_PROC_DEVICETREE */
1081
1082 return 0;
1083}
1084
1085/*
1086 * Update a property in a node. Note that we don't actually
1087 * remove it, since we have given out who-knows-how-many pointers
1088 * to the data using get-property. Instead we just move the property
1089 * to the "dead properties" list, and add the new property to the
1090 * property list
1091 */
1092int prom_update_property(struct device_node *np,
1093 struct property *newprop,
1094 struct property *oldprop)
1095{
1096 struct property **next;
1097 unsigned long flags;
1098 int found = 0;
1099
1100 write_lock_irqsave(&devtree_lock, flags);
1101 next = &np->properties;
1102 while (*next) {
1103 if (*next == oldprop) {
1104 /* found the node */
1105 newprop->next = oldprop->next;
1106 *next = newprop;
1107 oldprop->next = np->deadprops;
1108 np->deadprops = oldprop;
1109 found = 1;
1110 break;
1111 }
1112 next = &(*next)->next;
1113 }
1114 write_unlock_irqrestore(&devtree_lock, flags);
1115
1116 if (!found)
1117 return -ENODEV;
1118
1119#ifdef CONFIG_PROC_DEVICETREE
1120 /* try to add to proc as well if it was initialized */
1121 if (np->pde)
1122 proc_device_tree_update_prop(np->pde, newprop, oldprop);
1123#endif /* CONFIG_PROC_DEVICETREE */
1124
1125 return 0;
1126}
1127
1128#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
1129static struct debugfs_blob_wrapper flat_dt_blob;
1130
1131static int __init export_flat_device_tree(void)
1132{
1133 struct dentry *d;
1134
1135 flat_dt_blob.data = initial_boot_params;
1136 flat_dt_blob.size = initial_boot_params->totalsize;
1137
1138 d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
1139 of_debugfs_root, &flat_dt_blob);
1140 if (!d)
1141 return 1;
1142
1143 return 0;
1144}
1145device_initcall(export_flat_device_tree);
1146#endif
diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
new file mode 100644
index 000000000000..ae0352ecd5a9
--- /dev/null
+++ b/arch/microblaze/kernel/prom_parse.c
@@ -0,0 +1,1025 @@
1#undef DEBUG
2
3#include <linux/kernel.h>
4#include <linux/string.h>
5#include <linux/pci_regs.h>
6#include <linux/module.h>
7#include <linux/ioport.h>
8#include <linux/etherdevice.h>
9#include <asm/prom.h>
10#include <asm/pci-bridge.h>
11
12#define PRu64 "%llx"
13
14/* Max address size we deal with */
15#define OF_MAX_ADDR_CELLS 4
16#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
17 (ns) > 0)
18
19static struct of_bus *of_match_bus(struct device_node *np);
20static int __of_address_to_resource(struct device_node *dev,
21 const u32 *addrp, u64 size, unsigned int flags,
22 struct resource *r);
23
24/* Debug utility */
25#ifdef DEBUG
26static void of_dump_addr(const char *s, const u32 *addr, int na)
27{
28 printk(KERN_INFO "%s", s);
29 while (na--)
30 printk(KERN_INFO " %08x", *(addr++));
31 printk(KERN_INFO "\n");
32}
33#else
34static void of_dump_addr(const char *s, const u32 *addr, int na) { }
35#endif
36
37/* Callbacks for bus specific translators */
38struct of_bus {
39 const char *name;
40 const char *addresses;
41 int (*match)(struct device_node *parent);
42 void (*count_cells)(struct device_node *child,
43 int *addrc, int *sizec);
44 u64 (*map)(u32 *addr, const u32 *range,
45 int na, int ns, int pna);
46 int (*translate)(u32 *addr, u64 offset, int na);
47 unsigned int (*get_flags)(const u32 *addr);
48};
49
50/*
51 * Default translator (generic bus)
52 */
53
54static void of_bus_default_count_cells(struct device_node *dev,
55 int *addrc, int *sizec)
56{
57 if (addrc)
58 *addrc = of_n_addr_cells(dev);
59 if (sizec)
60 *sizec = of_n_size_cells(dev);
61}
62
63static u64 of_bus_default_map(u32 *addr, const u32 *range,
64 int na, int ns, int pna)
65{
66 u64 cp, s, da;
67
68 cp = of_read_number(range, na);
69 s = of_read_number(range + na + pna, ns);
70 da = of_read_number(addr, na);
71
72 pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
73 cp, s, da);
74
75 if (da < cp || da >= (cp + s))
76 return OF_BAD_ADDR;
77 return da - cp;
78}
79
80static int of_bus_default_translate(u32 *addr, u64 offset, int na)
81{
82 u64 a = of_read_number(addr, na);
83 memset(addr, 0, na * 4);
84 a += offset;
85 if (na > 1)
86 addr[na - 2] = a >> 32;
87 addr[na - 1] = a & 0xffffffffu;
88
89 return 0;
90}
91
92static unsigned int of_bus_default_get_flags(const u32 *addr)
93{
94 return IORESOURCE_MEM;
95}
96
97#ifdef CONFIG_PCI
98/*
99 * PCI bus specific translator
100 */
101
102static int of_bus_pci_match(struct device_node *np)
103{
104 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
105 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
106}
107
108static void of_bus_pci_count_cells(struct device_node *np,
109 int *addrc, int *sizec)
110{
111 if (addrc)
112 *addrc = 3;
113 if (sizec)
114 *sizec = 2;
115}
116
117static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
118{
119 u64 cp, s, da;
120
121 /* Check address type match */
122 if ((addr[0] ^ range[0]) & 0x03000000)
123 return OF_BAD_ADDR;
124
125 /* Read address values, skipping high cell */
126 cp = of_read_number(range + 1, na - 1);
127 s = of_read_number(range + na + pna, ns);
128 da = of_read_number(addr + 1, na - 1);
129
130 pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
131
132 if (da < cp || da >= (cp + s))
133 return OF_BAD_ADDR;
134 return da - cp;
135}
136
137static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
138{
139 return of_bus_default_translate(addr + 1, offset, na - 1);
140}
141
142static unsigned int of_bus_pci_get_flags(const u32 *addr)
143{
144 unsigned int flags = 0;
145 u32 w = addr[0];
146
147 switch ((w >> 24) & 0x03) {
148 case 0x01:
149 flags |= IORESOURCE_IO;
150 break;
151 case 0x02: /* 32 bits */
152 case 0x03: /* 64 bits */
153 flags |= IORESOURCE_MEM;
154 break;
155 }
156 if (w & 0x40000000)
157 flags |= IORESOURCE_PREFETCH;
158 return flags;
159}
160
161const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
162 unsigned int *flags)
163{
164 const u32 *prop;
165 unsigned int psize;
166 struct device_node *parent;
167 struct of_bus *bus;
168 int onesize, i, na, ns;
169
170 /* Get parent & match bus type */
171 parent = of_get_parent(dev);
172 if (parent == NULL)
173 return NULL;
174 bus = of_match_bus(parent);
175 if (strcmp(bus->name, "pci")) {
176 of_node_put(parent);
177 return NULL;
178 }
179 bus->count_cells(dev, &na, &ns);
180 of_node_put(parent);
181 if (!OF_CHECK_COUNTS(na, ns))
182 return NULL;
183
184 /* Get "reg" or "assigned-addresses" property */
185 prop = of_get_property(dev, bus->addresses, &psize);
186 if (prop == NULL)
187 return NULL;
188 psize /= 4;
189
190 onesize = na + ns;
191 for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
192 if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
193 if (size)
194 *size = of_read_number(prop + na, ns);
195 if (flags)
196 *flags = bus->get_flags(prop);
197 return prop;
198 }
199 return NULL;
200}
201EXPORT_SYMBOL(of_get_pci_address);
202
203int of_pci_address_to_resource(struct device_node *dev, int bar,
204 struct resource *r)
205{
206 const u32 *addrp;
207 u64 size;
208 unsigned int flags;
209
210 addrp = of_get_pci_address(dev, bar, &size, &flags);
211 if (addrp == NULL)
212 return -EINVAL;
213 return __of_address_to_resource(dev, addrp, size, flags, r);
214}
215EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
216
217static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
218{
219 return (((pin - 1) + slot) % 4) + 1;
220}
221
222int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
223{
224 struct device_node *dn, *ppnode;
225 struct pci_dev *ppdev;
226 u32 lspec;
227 u32 laddr[3];
228 u8 pin;
229 int rc;
230
231 /* Check if we have a device node, if yes, fallback to standard OF
232 * parsing
233 */
234 dn = pci_device_to_OF_node(pdev);
235 if (dn)
236 return of_irq_map_one(dn, 0, out_irq);
237
238 /* Ok, we don't, time to have fun. Let's start by building up an
239 * interrupt spec. we assume #interrupt-cells is 1, which is standard
240 * for PCI. If you do different, then don't use that routine.
241 */
242 rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
243 if (rc != 0)
244 return rc;
245 /* No pin, exit */
246 if (pin == 0)
247 return -ENODEV;
248
249 /* Now we walk up the PCI tree */
250 lspec = pin;
251 for (;;) {
252 /* Get the pci_dev of our parent */
253 ppdev = pdev->bus->self;
254
255 /* Ouch, it's a host bridge... */
256 if (ppdev == NULL) {
257 struct pci_controller *host;
258 host = pci_bus_to_host(pdev->bus);
259 ppnode = host ? host->arch_data : NULL;
260 /* No node for host bridge ? give up */
261 if (ppnode == NULL)
262 return -EINVAL;
263 } else
264 /* We found a P2P bridge, check if it has a node */
265 ppnode = pci_device_to_OF_node(ppdev);
266
267 /* Ok, we have found a parent with a device-node, hand over to
268 * the OF parsing code.
269 * We build a unit address from the linux device to be used for
270 * resolution. Note that we use the linux bus number which may
271 * not match your firmware bus numbering.
272 * Fortunately, in most cases, interrupt-map-mask doesn't
273 * include the bus number as part of the matching.
274 * You should still be careful about that though if you intend
275 * to rely on this function (you ship a firmware that doesn't
276 * create device nodes for all PCI devices).
277 */
278 if (ppnode)
279 break;
280
281 /* We can only get here if we hit a P2P bridge with no node,
282 * let's do standard swizzling and try again
283 */
284 lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec);
285 pdev = ppdev;
286 }
287
288 laddr[0] = (pdev->bus->number << 16)
289 | (pdev->devfn << 8);
290 laddr[1] = laddr[2] = 0;
291 return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq);
292}
293EXPORT_SYMBOL_GPL(of_irq_map_pci);
294#endif /* CONFIG_PCI */
295
296/*
297 * ISA bus specific translator
298 */
299
300static int of_bus_isa_match(struct device_node *np)
301{
302 return !strcmp(np->name, "isa");
303}
304
305static void of_bus_isa_count_cells(struct device_node *child,
306 int *addrc, int *sizec)
307{
308 if (addrc)
309 *addrc = 2;
310 if (sizec)
311 *sizec = 1;
312}
313
314static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
315{
316 u64 cp, s, da;
317
318 /* Check address type match */
319 if ((addr[0] ^ range[0]) & 0x00000001)
320 return OF_BAD_ADDR;
321
322 /* Read address values, skipping high cell */
323 cp = of_read_number(range + 1, na - 1);
324 s = of_read_number(range + na + pna, ns);
325 da = of_read_number(addr + 1, na - 1);
326
327 pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
328
329 if (da < cp || da >= (cp + s))
330 return OF_BAD_ADDR;
331 return da - cp;
332}
333
334static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
335{
336 return of_bus_default_translate(addr + 1, offset, na - 1);
337}
338
339static unsigned int of_bus_isa_get_flags(const u32 *addr)
340{
341 unsigned int flags = 0;
342 u32 w = addr[0];
343
344 if (w & 1)
345 flags |= IORESOURCE_IO;
346 else
347 flags |= IORESOURCE_MEM;
348 return flags;
349}
350
351/*
352 * Array of bus specific translators
353 */
354
355static struct of_bus of_busses[] = {
356#ifdef CONFIG_PCI
357 /* PCI */
358 {
359 .name = "pci",
360 .addresses = "assigned-addresses",
361 .match = of_bus_pci_match,
362 .count_cells = of_bus_pci_count_cells,
363 .map = of_bus_pci_map,
364 .translate = of_bus_pci_translate,
365 .get_flags = of_bus_pci_get_flags,
366 },
367#endif /* CONFIG_PCI */
368 /* ISA */
369 {
370 .name = "isa",
371 .addresses = "reg",
372 .match = of_bus_isa_match,
373 .count_cells = of_bus_isa_count_cells,
374 .map = of_bus_isa_map,
375 .translate = of_bus_isa_translate,
376 .get_flags = of_bus_isa_get_flags,
377 },
378 /* Default */
379 {
380 .name = "default",
381 .addresses = "reg",
382 .match = NULL,
383 .count_cells = of_bus_default_count_cells,
384 .map = of_bus_default_map,
385 .translate = of_bus_default_translate,
386 .get_flags = of_bus_default_get_flags,
387 },
388};
389
390static struct of_bus *of_match_bus(struct device_node *np)
391{
392 int i;
393
394 for (i = 0; i < ARRAY_SIZE(of_busses); i++)
395 if (!of_busses[i].match || of_busses[i].match(np))
396 return &of_busses[i];
397 BUG();
398 return NULL;
399}
400
401static int of_translate_one(struct device_node *parent, struct of_bus *bus,
402 struct of_bus *pbus, u32 *addr,
403 int na, int ns, int pna)
404{
405 const u32 *ranges;
406 unsigned int rlen;
407 int rone;
408 u64 offset = OF_BAD_ADDR;
409
410 /* Normally, an absence of a "ranges" property means we are
411 * crossing a non-translatable boundary, and thus the addresses
412 * below the current not cannot be converted to CPU physical ones.
413 * Unfortunately, while this is very clear in the spec, it's not
414 * what Apple understood, and they do have things like /uni-n or
415 * /ht nodes with no "ranges" property and a lot of perfectly
416 * useable mapped devices below them. Thus we treat the absence of
417 * "ranges" as equivalent to an empty "ranges" property which means
418 * a 1:1 translation at that level. It's up to the caller not to try
419 * to translate addresses that aren't supposed to be translated in
420 * the first place. --BenH.
421 */
422 ranges = of_get_property(parent, "ranges", (int *) &rlen);
423 if (ranges == NULL || rlen == 0) {
424 offset = of_read_number(addr, na);
425 memset(addr, 0, pna * 4);
426 pr_debug("OF: no ranges, 1:1 translation\n");
427 goto finish;
428 }
429
430 pr_debug("OF: walking ranges...\n");
431
432 /* Now walk through the ranges */
433 rlen /= 4;
434 rone = na + pna + ns;
435 for (; rlen >= rone; rlen -= rone, ranges += rone) {
436 offset = bus->map(addr, ranges, na, ns, pna);
437 if (offset != OF_BAD_ADDR)
438 break;
439 }
440 if (offset == OF_BAD_ADDR) {
441 pr_debug("OF: not found !\n");
442 return 1;
443 }
444 memcpy(addr, ranges + na, 4 * pna);
445
446 finish:
447 of_dump_addr("OF: parent translation for:", addr, pna);
448 pr_debug("OF: with offset: "PRu64"\n", offset);
449
450 /* Translate it into parent bus space */
451 return pbus->translate(addr, offset, pna);
452}
453
454/*
455 * Translate an address from the device-tree into a CPU physical address,
456 * this walks up the tree and applies the various bus mappings on the
457 * way.
458 *
459 * Note: We consider that crossing any level with #size-cells == 0 to mean
460 * that translation is impossible (that is we are not dealing with a value
461 * that can be mapped to a cpu physical address). This is not really specified
462 * that way, but this is traditionally the way IBM at least do things
463 */
464u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
465{
466 struct device_node *parent = NULL;
467 struct of_bus *bus, *pbus;
468 u32 addr[OF_MAX_ADDR_CELLS];
469 int na, ns, pna, pns;
470 u64 result = OF_BAD_ADDR;
471
472 pr_debug("OF: ** translation for device %s **\n", dev->full_name);
473
474 /* Increase refcount at current level */
475 of_node_get(dev);
476
477 /* Get parent & match bus type */
478 parent = of_get_parent(dev);
479 if (parent == NULL)
480 goto bail;
481 bus = of_match_bus(parent);
482
483 /* Cound address cells & copy address locally */
484 bus->count_cells(dev, &na, &ns);
485 if (!OF_CHECK_COUNTS(na, ns)) {
486 printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
487 dev->full_name);
488 goto bail;
489 }
490 memcpy(addr, in_addr, na * 4);
491
492 pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
493 bus->name, na, ns, parent->full_name);
494 of_dump_addr("OF: translating address:", addr, na);
495
496 /* Translate */
497 for (;;) {
498 /* Switch to parent bus */
499 of_node_put(dev);
500 dev = parent;
501 parent = of_get_parent(dev);
502
503 /* If root, we have finished */
504 if (parent == NULL) {
505 pr_debug("OF: reached root node\n");
506 result = of_read_number(addr, na);
507 break;
508 }
509
510 /* Get new parent bus and counts */
511 pbus = of_match_bus(parent);
512 pbus->count_cells(dev, &pna, &pns);
513 if (!OF_CHECK_COUNTS(pna, pns)) {
514 printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
515 dev->full_name);
516 break;
517 }
518
519 pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
520 pbus->name, pna, pns, parent->full_name);
521
522 /* Apply bus translation */
523 if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
524 break;
525
526 /* Complete the move up one level */
527 na = pna;
528 ns = pns;
529 bus = pbus;
530
531 of_dump_addr("OF: one level translation:", addr, na);
532 }
533 bail:
534 of_node_put(parent);
535 of_node_put(dev);
536
537 return result;
538}
539EXPORT_SYMBOL(of_translate_address);
540
541const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
542 unsigned int *flags)
543{
544 const u32 *prop;
545 unsigned int psize;
546 struct device_node *parent;
547 struct of_bus *bus;
548 int onesize, i, na, ns;
549
550 /* Get parent & match bus type */
551 parent = of_get_parent(dev);
552 if (parent == NULL)
553 return NULL;
554 bus = of_match_bus(parent);
555 bus->count_cells(dev, &na, &ns);
556 of_node_put(parent);
557 if (!OF_CHECK_COUNTS(na, ns))
558 return NULL;
559
560 /* Get "reg" or "assigned-addresses" property */
561 prop = of_get_property(dev, bus->addresses, (int *) &psize);
562 if (prop == NULL)
563 return NULL;
564 psize /= 4;
565
566 onesize = na + ns;
567 for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
568 if (i == index) {
569 if (size)
570 *size = of_read_number(prop + na, ns);
571 if (flags)
572 *flags = bus->get_flags(prop);
573 return prop;
574 }
575 return NULL;
576}
577EXPORT_SYMBOL(of_get_address);
578
579static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
580 u64 size, unsigned int flags,
581 struct resource *r)
582{
583 u64 taddr;
584
585 if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
586 return -EINVAL;
587 taddr = of_translate_address(dev, addrp);
588 if (taddr == OF_BAD_ADDR)
589 return -EINVAL;
590 memset(r, 0, sizeof(struct resource));
591 if (flags & IORESOURCE_IO) {
592 unsigned long port;
593 port = -1; /* pci_address_to_pio(taddr); */
594 if (port == (unsigned long)-1)
595 return -EINVAL;
596 r->start = port;
597 r->end = port + size - 1;
598 } else {
599 r->start = taddr;
600 r->end = taddr + size - 1;
601 }
602 r->flags = flags;
603 r->name = dev->name;
604 return 0;
605}
606
607int of_address_to_resource(struct device_node *dev, int index,
608 struct resource *r)
609{
610 const u32 *addrp;
611 u64 size;
612 unsigned int flags;
613
614 addrp = of_get_address(dev, index, &size, &flags);
615 if (addrp == NULL)
616 return -EINVAL;
617 return __of_address_to_resource(dev, addrp, size, flags, r);
618}
619EXPORT_SYMBOL_GPL(of_address_to_resource);
620
621void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
622 unsigned long *busno, unsigned long *phys, unsigned long *size)
623{
624 const u32 *dma_window;
625 u32 cells;
626 const unsigned char *prop;
627
628 dma_window = dma_window_prop;
629
630 /* busno is always one cell */
631 *busno = *(dma_window++);
632
633 prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
634 if (!prop)
635 prop = of_get_property(dn, "#address-cells", NULL);
636
637 cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
638 *phys = of_read_number(dma_window, cells);
639
640 dma_window += cells;
641
642 prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
643 cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
644 *size = of_read_number(dma_window, cells);
645}
646
647/*
648 * Interrupt remapper
649 */
650
651static unsigned int of_irq_workarounds;
652static struct device_node *of_irq_dflt_pic;
653
654static struct device_node *of_irq_find_parent(struct device_node *child)
655{
656 struct device_node *p;
657 const phandle *parp;
658
659 if (!of_node_get(child))
660 return NULL;
661
662 do {
663 parp = of_get_property(child, "interrupt-parent", NULL);
664 if (parp == NULL)
665 p = of_get_parent(child);
666 else {
667 if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
668 p = of_node_get(of_irq_dflt_pic);
669 else
670 p = of_find_node_by_phandle(*parp);
671 }
672 of_node_put(child);
673 child = p;
674 } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
675
676 return p;
677}
678
679/* This doesn't need to be called if you don't have any special workaround
680 * flags to pass
681 */
682void of_irq_map_init(unsigned int flags)
683{
684 of_irq_workarounds = flags;
685
686 /* OldWorld, don't bother looking at other things */
687 if (flags & OF_IMAP_OLDWORLD_MAC)
688 return;
689
690 /* If we don't have phandles, let's try to locate a default interrupt
691 * controller (happens when booting with BootX). We do a first match
692 * here, hopefully, that only ever happens on machines with one
693 * controller.
694 */
695 if (flags & OF_IMAP_NO_PHANDLE) {
696 struct device_node *np;
697
698 for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
699 if (of_get_property(np, "interrupt-controller", NULL)
700 == NULL)
701 continue;
702 /* Skip /chosen/interrupt-controller */
703 if (strcmp(np->name, "chosen") == 0)
704 continue;
705 /* It seems like at least one person on this planet
706 * wants to use BootX on a machine with an AppleKiwi
707 * controller which happens to pretend to be an
708 * interrupt controller too.
709 */
710 if (strcmp(np->name, "AppleKiwi") == 0)
711 continue;
712 /* I think we found one ! */
713 of_irq_dflt_pic = np;
714 break;
715 }
716 }
717
718}
719
720int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
721 const u32 *addr, struct of_irq *out_irq)
722{
723 struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
724 const u32 *tmp, *imap, *imask;
725 u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
726 int imaplen, match, i;
727
728 pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],"
729 "ointsize=%d\n",
730 parent->full_name, intspec[0], intspec[1], ointsize);
731
732 ipar = of_node_get(parent);
733
734 /* First get the #interrupt-cells property of the current cursor
735 * that tells us how to interpret the passed-in intspec. If there
736 * is none, we are nice and just walk up the tree
737 */
738 do {
739 tmp = of_get_property(ipar, "#interrupt-cells", NULL);
740 if (tmp != NULL) {
741 intsize = *tmp;
742 break;
743 }
744 tnode = ipar;
745 ipar = of_irq_find_parent(ipar);
746 of_node_put(tnode);
747 } while (ipar);
748 if (ipar == NULL) {
749 pr_debug(" -> no parent found !\n");
750 goto fail;
751 }
752
753 pr_debug("of_irq_map_raw: ipar=%s, size=%d\n",
754 ipar->full_name, intsize);
755
756 if (ointsize != intsize)
757 return -EINVAL;
758
759 /* Look for this #address-cells. We have to implement the old linux
760 * trick of looking for the parent here as some device-trees rely on it
761 */
762 old = of_node_get(ipar);
763 do {
764 tmp = of_get_property(old, "#address-cells", NULL);
765 tnode = of_get_parent(old);
766 of_node_put(old);
767 old = tnode;
768 } while (old && tmp == NULL);
769 of_node_put(old);
770 old = NULL;
771 addrsize = (tmp == NULL) ? 2 : *tmp;
772
773 pr_debug(" -> addrsize=%d\n", addrsize);
774
775 /* Now start the actual "proper" walk of the interrupt tree */
776 while (ipar != NULL) {
777 /* Now check if cursor is an interrupt-controller and if it is
778 * then we are done
779 */
780 if (of_get_property(ipar, "interrupt-controller", NULL) !=
781 NULL) {
782 pr_debug(" -> got it !\n");
783 memcpy(out_irq->specifier, intspec,
784 intsize * sizeof(u32));
785 out_irq->size = intsize;
786 out_irq->controller = ipar;
787 of_node_put(old);
788 return 0;
789 }
790
791 /* Now look for an interrupt-map */
792 imap = of_get_property(ipar, "interrupt-map", &imaplen);
793 /* No interrupt map, check for an interrupt parent */
794 if (imap == NULL) {
795 pr_debug(" -> no map, getting parent\n");
796 newpar = of_irq_find_parent(ipar);
797 goto skiplevel;
798 }
799 imaplen /= sizeof(u32);
800
801 /* Look for a mask */
802 imask = of_get_property(ipar, "interrupt-map-mask", NULL);
803
804 /* If we were passed no "reg" property and we attempt to parse
805 * an interrupt-map, then #address-cells must be 0.
806 * Fail if it's not.
807 */
808 if (addr == NULL && addrsize != 0) {
809 pr_debug(" -> no reg passed in when needed !\n");
810 goto fail;
811 }
812
813 /* Parse interrupt-map */
814 match = 0;
815 while (imaplen > (addrsize + intsize + 1) && !match) {
816 /* Compare specifiers */
817 match = 1;
818 for (i = 0; i < addrsize && match; ++i) {
819 u32 mask = imask ? imask[i] : 0xffffffffu;
820 match = ((addr[i] ^ imap[i]) & mask) == 0;
821 }
822 for (; i < (addrsize + intsize) && match; ++i) {
823 u32 mask = imask ? imask[i] : 0xffffffffu;
824 match =
825 ((intspec[i-addrsize] ^ imap[i])
826 & mask) == 0;
827 }
828 imap += addrsize + intsize;
829 imaplen -= addrsize + intsize;
830
831 pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
832
833 /* Get the interrupt parent */
834 if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
835 newpar = of_node_get(of_irq_dflt_pic);
836 else
837 newpar =
838 of_find_node_by_phandle((phandle)*imap);
839 imap++;
840 --imaplen;
841
842 /* Check if not found */
843 if (newpar == NULL) {
844 pr_debug(" -> imap parent not found !\n");
845 goto fail;
846 }
847
848 /* Get #interrupt-cells and #address-cells of new
849 * parent
850 */
851 tmp = of_get_property(newpar, "#interrupt-cells", NULL);
852 if (tmp == NULL) {
853 pr_debug(" -> parent lacks "
854 "#interrupt-cells!\n");
855 goto fail;
856 }
857 newintsize = *tmp;
858 tmp = of_get_property(newpar, "#address-cells", NULL);
859 newaddrsize = (tmp == NULL) ? 0 : *tmp;
860
861 pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
862 newintsize, newaddrsize);
863
864 /* Check for malformed properties */
865 if (imaplen < (newaddrsize + newintsize))
866 goto fail;
867
868 imap += newaddrsize + newintsize;
869 imaplen -= newaddrsize + newintsize;
870
871 pr_debug(" -> imaplen=%d\n", imaplen);
872 }
873 if (!match)
874 goto fail;
875
876 of_node_put(old);
877 old = of_node_get(newpar);
878 addrsize = newaddrsize;
879 intsize = newintsize;
880 intspec = imap - intsize;
881 addr = intspec - addrsize;
882
883skiplevel:
884 /* Iterate again with new parent */
885 pr_debug(" -> new parent: %s\n",
886 newpar ? newpar->full_name : "<>");
887 of_node_put(ipar);
888 ipar = newpar;
889 newpar = NULL;
890 }
891fail:
892 of_node_put(ipar);
893 of_node_put(old);
894 of_node_put(newpar);
895
896 return -EINVAL;
897}
898EXPORT_SYMBOL_GPL(of_irq_map_raw);
899
900int of_irq_map_one(struct device_node *device,
901 int index, struct of_irq *out_irq)
902{
903 struct device_node *p;
904 const u32 *intspec, *tmp, *addr;
905 u32 intsize, intlen;
906 int res;
907
908 pr_debug("of_irq_map_one: dev=%s, index=%d\n",
909 device->full_name, index);
910
911 /* Get the interrupts property */
912 intspec = of_get_property(device, "interrupts", (int *) &intlen);
913 if (intspec == NULL)
914 return -EINVAL;
915 intlen /= sizeof(u32);
916
917 pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen);
918
919 /* Get the reg property (if any) */
920 addr = of_get_property(device, "reg", NULL);
921
922 /* Look for the interrupt parent. */
923 p = of_irq_find_parent(device);
924 if (p == NULL)
925 return -EINVAL;
926
927 /* Get size of interrupt specifier */
928 tmp = of_get_property(p, "#interrupt-cells", NULL);
929 if (tmp == NULL) {
930 of_node_put(p);
931 return -EINVAL;
932 }
933 intsize = *tmp;
934
935 pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
936
937 /* Check index */
938 if ((index + 1) * intsize > intlen)
939 return -EINVAL;
940
941 /* Get new specifier and map it */
942 res = of_irq_map_raw(p, intspec + index * intsize, intsize,
943 addr, out_irq);
944 of_node_put(p);
945 return res;
946}
947EXPORT_SYMBOL_GPL(of_irq_map_one);
948
949/**
950 * Search the device tree for the best MAC address to use. 'mac-address' is
951 * checked first, because that is supposed to contain to "most recent" MAC
952 * address. If that isn't set, then 'local-mac-address' is checked next,
953 * because that is the default address. If that isn't set, then the obsolete
954 * 'address' is checked, just in case we're using an old device tree.
955 *
956 * Note that the 'address' property is supposed to contain a virtual address of
957 * the register set, but some DTS files have redefined that property to be the
958 * MAC address.
959 *
960 * All-zero MAC addresses are rejected, because those could be properties that
961 * exist in the device tree, but were not set by U-Boot. For example, the
962 * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
963 * addresses. Some older U-Boots only initialized 'local-mac-address'. In
964 * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
965 * but is all zeros.
966*/
967const void *of_get_mac_address(struct device_node *np)
968{
969 struct property *pp;
970
971 pp = of_find_property(np, "mac-address", NULL);
972 if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
973 return pp->value;
974
975 pp = of_find_property(np, "local-mac-address", NULL);
976 if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
977 return pp->value;
978
979 pp = of_find_property(np, "address", NULL);
980 if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
981 return pp->value;
982
983 return NULL;
984}
985EXPORT_SYMBOL(of_get_mac_address);
986
987int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
988{
989 struct of_irq out_irq;
990 int irq;
991 int res;
992
993 res = of_irq_map_one(dev, index, &out_irq);
994
995 /* Get irq for the device */
996 if (res) {
997 pr_debug("IRQ not found... code = %d", res);
998 return NO_IRQ;
999 }
1000 /* Assuming single interrupt controller... */
1001 irq = out_irq.specifier[0];
1002
1003 pr_debug("IRQ found = %d", irq);
1004
1005 /* Only dereference the resource if both the
1006 * resource and the irq are valid. */
1007 if (r && irq != NO_IRQ) {
1008 r->start = r->end = irq;
1009 r->flags = IORESOURCE_IRQ;
1010 }
1011
1012 return irq;
1013}
1014EXPORT_SYMBOL_GPL(of_irq_to_resource);
1015
1016void __iomem *of_iomap(struct device_node *np, int index)
1017{
1018 struct resource res;
1019
1020 if (of_address_to_resource(np, index, &res))
1021 return NULL;
1022
1023 return ioremap(res.start, 1 + res.end - res.start);
1024}
1025EXPORT_SYMBOL(of_iomap);
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
new file mode 100644
index 000000000000..b86aa623e36d
--- /dev/null
+++ b/arch/microblaze/kernel/ptrace.c
@@ -0,0 +1,181 @@
1/*
2 * `ptrace' system call
3 *
4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
7 *
8 * derived from arch/v850/kernel/ptrace.c
9 *
10 * Copyright (C) 2002,03 NEC Electronics Corporation
11 * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
12 *
13 * Derived from arch/mips/kernel/ptrace.c:
14 *
15 * Copyright (C) 1992 Ross Biro
16 * Copyright (C) Linus Torvalds
17 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
18 * Copyright (C) 1996 David S. Miller
19 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
20 * Copyright (C) 1999 MIPS Technologies, Inc.
21 *
22 * This file is subject to the terms and conditions of the GNU General
23 * Public License. See the file COPYING in the main directory of this
24 * archive for more details.
25 */
26
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <linux/sched.h>
30#include <linux/smp_lock.h>
31#include <linux/ptrace.h>
32#include <linux/signal.h>
33
34#include <linux/errno.h>
35#include <asm/processor.h>
36#include <linux/uaccess.h>
37#include <asm/asm-offsets.h>
38
39/* Returns the address where the register at REG_OFFS in P is stashed away. */
40static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
41 struct task_struct *t)
42{
43 struct pt_regs *regs;
44
45 /*
46 * Three basic cases:
47 *
48 * (1) A register normally saved before calling the scheduler, is
49 * available in the kernel entry pt_regs structure at the top
50 * of the kernel stack. The kernel trap/irq exit path takes
51 * care to save/restore almost all registers for ptrace'd
52 * processes.
53 *
54 * (2) A call-clobbered register, where the process P entered the
55 * kernel via [syscall] trap, is not stored anywhere; that's
56 * OK, because such registers are not expected to be preserved
57 * when the trap returns anyway (so we don't actually bother to
58 * test for this case).
59 *
60 * (3) A few registers not used at all by the kernel, and so
61 * normally never saved except by context-switches, are in the
62 * context switch state.
63 */
64
65 /* Register saved during kernel entry (or not available). */
66 regs = task_pt_regs(t);
67
68 return (microblaze_reg_t *)((char *)regs + reg_offs);
69}
70
71long arch_ptrace(struct task_struct *child, long request, long addr, long data)
72{
73 int rval;
74 unsigned long val = 0;
75 unsigned long copied;
76
77 switch (request) {
78 case PTRACE_PEEKTEXT: /* read word at location addr. */
79 case PTRACE_PEEKDATA:
80 pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
81 copied = access_process_vm(child, addr, &val, sizeof(val), 0);
82 rval = -EIO;
83 if (copied != sizeof(val))
84 break;
85 rval = put_user(val, (unsigned long *)data);
86 break;
87
88 case PTRACE_POKETEXT: /* write the word at location addr. */
89 case PTRACE_POKEDATA:
90 pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
91 rval = 0;
92 if (access_process_vm(child, addr, &data, sizeof(data), 1)
93 == sizeof(data))
94 break;
95 rval = -EIO;
96 break;
97
98 /* Read/write the word at location ADDR in the registers. */
99 case PTRACE_PEEKUSR:
100 case PTRACE_POKEUSR:
101 pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
102 rval = 0;
103 if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
104 /*
105 * Special requests that don't actually correspond
106 * to offsets in struct pt_regs.
107 */
108 if (addr == PT_TEXT_ADDR) {
109 val = child->mm->start_code;
110 } else if (addr == PT_DATA_ADDR) {
111 val = child->mm->start_data;
112 } else if (addr == PT_TEXT_LEN) {
113 val = child->mm->end_code
114 - child->mm->start_code;
115 } else {
116 rval = -EIO;
117 }
118 } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
119 microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
120 if (request == PTRACE_PEEKUSR)
121 val = *reg_addr;
122 else
123 *reg_addr = data;
124 } else
125 rval = -EIO;
126
127 if (rval == 0 && request == PTRACE_PEEKUSR)
128 rval = put_user(val, (unsigned long *)data);
129 break;
130 /* Continue and stop at next (return from) syscall */
131 case PTRACE_SYSCALL:
132 pr_debug("PTRACE_SYSCALL\n");
133 case PTRACE_SINGLESTEP:
134 pr_debug("PTRACE_SINGLESTEP\n");
135 /* Restart after a signal. */
136 case PTRACE_CONT:
137 pr_debug("PTRACE_CONT\n");
138 rval = -EIO;
139 if (!valid_signal(data))
140 break;
141
142 if (request == PTRACE_SYSCALL)
143 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
144 else
145 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
146
147 child->exit_code = data;
148 pr_debug("wakeup_process\n");
149 wake_up_process(child);
150 rval = 0;
151 break;
152
153 /*
154 * make the child exit. Best I can do is send it a sigkill.
155 * perhaps it should be put in the status that it wants to
156 * exit.
157 */
158 case PTRACE_KILL:
159 pr_debug("PTRACE_KILL\n");
160 rval = 0;
161 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
162 break;
163 child->exit_code = SIGKILL;
164 wake_up_process(child);
165 break;
166
167 case PTRACE_DETACH: /* detach a process that was attached. */
168 pr_debug("PTRACE_DETACH\n");
169 rval = ptrace_detach(child, data);
170 break;
171 default:
172 /* rval = ptrace_request(child, request, addr, data); noMMU */
173 rval = -EIO;
174 }
175 return rval;
176}
177
178void ptrace_disable(struct task_struct *child)
179{
180 /* nothing to do */
181}
diff --git a/arch/microblaze/kernel/selfmod.c b/arch/microblaze/kernel/selfmod.c
new file mode 100644
index 000000000000..89508bdc9f3c
--- /dev/null
+++ b/arch/microblaze/kernel/selfmod.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2009 PetaLogix
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file "COPYING" in the main directory of this archive
7 * for more details.
8 */
9
10#include <linux/interrupt.h>
11#include <asm/selfmod.h>
12
13#undef DEBUG
14
15#if __GNUC__ > 3
16#error GCC 4 unsupported SELFMOD. Please disable SELFMOD from menuconfig.
17#endif
18
19#define OPCODE_IMM 0xB0000000
20#define OPCODE_LWI 0xE8000000
21#define OPCODE_LWI_MASK 0xEC000000
22#define OPCODE_RTSD 0xB60F0008 /* return from func: rtsd r15, 8 */
23#define OPCODE_ADDIK 0x30000000
24#define OPCODE_ADDIK_MASK 0xFC000000
25
26#define IMM_BASE (OPCODE_IMM | (BARRIER_BASE_ADDR >> 16))
27#define LWI_BASE (OPCODE_LWI | (BARRIER_BASE_ADDR & 0x0000ff00))
28#define LWI_BASE_MASK (OPCODE_LWI_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
29#define ADDIK_BASE (OPCODE_ADDIK | (BARRIER_BASE_ADDR & 0x0000ff00))
30#define ADDIK_BASE_MASK (OPCODE_ADDIK_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
31
32#define MODIFY_INSTR { \
33 pr_debug("%s: curr instr, (%d):0x%x, next(%d):0x%x\n", \
34 __func__, i, addr[i], i + 1, addr[i + 1]); \
35 addr[i] = OPCODE_IMM + (base >> 16); \
36 /* keep instruction opcode and add only last 16bits */ \
37 addr[i + 1] = (addr[i + 1] & 0xffff00ff) + (base & 0xffff); \
38 __invalidate_icache(addr[i]); \
39 __invalidate_icache(addr[i + 1]); \
40 pr_debug("%s: hack instr, (%d):0x%x, next(%d):0x%x\n", \
41 __func__, i, addr[i], i + 1, addr[i + 1]); }
42
43/* NOTE
44 * self-modified part of code for improvement of interrupt controller
45 * save instruction in interrupt rutine
46 */
47void selfmod_function(const int *arr_fce, const unsigned int base)
48{
49 unsigned int flags, i, j, *addr = NULL;
50
51 local_irq_save(flags);
52 __disable_icache();
53
54 /* zero terminated array */
55 for (j = 0; arr_fce[j] != 0; j++) {
56 /* get start address of function */
57 addr = (unsigned int *) arr_fce[j];
58 pr_debug("%s: func(%d) at 0x%x\n",
59 __func__, j, (unsigned int) addr);
60 for (i = 0; ; i++) {
61 pr_debug("%s: instruction code at %d: 0x%x\n",
62 __func__, i, addr[i]);
63 if (addr[i] == IMM_BASE) {
64 /* detecting of lwi (0xE8) or swi (0xF8) instr
65 * I can detect both opcode with one mask */
66 if ((addr[i + 1] & LWI_BASE_MASK) == LWI_BASE) {
67 MODIFY_INSTR;
68 } else /* detection addik for ack */
69 if ((addr[i + 1] & ADDIK_BASE_MASK) ==
70 ADDIK_BASE) {
71 MODIFY_INSTR;
72 }
73 } else if (addr[i] == OPCODE_RTSD) {
74 /* return from function means end of function */
75 pr_debug("%s: end of array %d\n", __func__, i);
76 break;
77 }
78 }
79 }
80 local_irq_restore(flags);
81} /* end of self-modified code */
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
new file mode 100644
index 000000000000..eb6b41758e23
--- /dev/null
+++ b/arch/microblaze/kernel/setup.c
@@ -0,0 +1,199 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/string.h>
13#include <linux/seq_file.h>
14#include <linux/cpu.h>
15#include <linux/initrd.h>
16#include <linux/console.h>
17#include <linux/debugfs.h>
18
19#include <asm/setup.h>
20#include <asm/sections.h>
21#include <asm/page.h>
22#include <linux/io.h>
23#include <linux/bug.h>
24#include <linux/param.h>
25#include <linux/cache.h>
26#include <asm/cacheflush.h>
27#include <asm/entry.h>
28#include <asm/cpuinfo.h>
29
30#include <asm/system.h>
31#include <asm/prom.h>
32#include <asm/pgtable.h>
33
34DEFINE_PER_CPU(unsigned int, KSP); /* Saved kernel stack pointer */
35DEFINE_PER_CPU(unsigned int, KM); /* Kernel/user mode */
36DEFINE_PER_CPU(unsigned int, ENTRY_SP); /* Saved SP on kernel entry */
37DEFINE_PER_CPU(unsigned int, R11_SAVE); /* Temp variable for entry */
38DEFINE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */
39
40unsigned int boot_cpuid;
41char cmd_line[COMMAND_LINE_SIZE];
42
43void __init setup_arch(char **cmdline_p)
44{
45#ifdef CONFIG_CMDLINE_FORCE
46 strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
47 strlcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
48#endif
49 *cmdline_p = cmd_line;
50
51 console_verbose();
52
53 unflatten_device_tree();
54
55 /* NOTE I think that this function is not necessary to call */
56 /* irq_early_init(); */
57 setup_cpuinfo();
58
59 __invalidate_icache_all();
60 __enable_icache();
61
62 __invalidate_dcache_all();
63 __enable_dcache();
64
65 panic_timeout = 120;
66
67 setup_memory();
68
69#if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
70 printk(KERN_NOTICE "Self modified code enable\n");
71#endif
72
73#ifdef CONFIG_VT
74#if defined(CONFIG_XILINX_CONSOLE)
75 conswitchp = &xil_con;
76#elif defined(CONFIG_DUMMY_CONSOLE)
77 conswitchp = &dummy_con;
78#endif
79#endif
80}
81
82#ifdef CONFIG_MTD_UCLINUX
83/* Handle both romfs and cramfs types, without generating unnecessary
84 code (ie no point checking for CRAMFS if it's not even enabled) */
85inline unsigned get_romfs_len(unsigned *addr)
86{
87#ifdef CONFIG_ROMFS_FS
88 if (memcmp(&addr[0], "-rom1fs-", 8) == 0) /* romfs */
89 return be32_to_cpu(addr[2]);
90#endif
91
92#ifdef CONFIG_CRAMFS
93 if (addr[0] == le32_to_cpu(0x28cd3d45)) /* cramfs */
94 return le32_to_cpu(addr[1]);
95#endif
96 return 0;
97}
98#endif /* CONFIG_MTD_UCLINUX_EBSS */
99
100void __init machine_early_init(const char *cmdline, unsigned int ram,
101 unsigned int fdt)
102{
103 unsigned long *src, *dst = (unsigned long *)0x0;
104
105/* clearing bss section */
106 memset(__bss_start, 0, __bss_stop-__bss_start);
107 memset(_ssbss, 0, _esbss-_ssbss);
108
109 /*
110 * Copy command line passed from bootloader, or use default
111 * if none provided, or forced
112 */
113#ifndef CONFIG_CMDLINE_BOOL
114 if (cmdline && cmdline[0] != '\0')
115 strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
116#endif
117
118/* initialize device tree for usage in early_printk */
119 early_init_devtree((void *)_fdt_start);
120
121#ifdef CONFIG_EARLY_PRINTK
122 setup_early_printk(NULL);
123#endif
124
125 early_printk("Ramdisk addr 0x%08x, FDT 0x%08x\n", ram, fdt);
126 printk(KERN_NOTICE "Found FDT at 0x%08x\n", fdt);
127
128#ifdef CONFIG_MTD_UCLINUX
129 {
130 int size;
131 unsigned int romfs_base;
132 romfs_base = (ram ? ram : (unsigned int)&__init_end);
133 /* if CONFIG_MTD_UCLINUX_EBSS is defined, assume ROMFS is at the
134 * end of kernel, which is ROMFS_LOCATION defined above. */
135 size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
136 early_printk("Found romfs @ 0x%08x (0x%08x)\n",
137 romfs_base, size);
138 early_printk("#### klimit %p ####\n", klimit);
139 BUG_ON(size < 0); /* What else can we do? */
140
141 /* Use memmove to handle likely case of memory overlap */
142 early_printk("Moving 0x%08x bytes from 0x%08x to 0x%08x\n",
143 size, romfs_base, (unsigned)&_ebss);
144 memmove(&_ebss, (int *)romfs_base, size);
145
146 /* update klimit */
147 klimit += PAGE_ALIGN(size);
148 early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
149 }
150#endif
151
152 for (src = __ivt_start; src < __ivt_end; src++, dst++)
153 *dst = *src;
154
155 /* Initialize global data */
156 per_cpu(KM, 0) = 0x1; /* We start in kernel mode */
157 per_cpu(CURRENT_SAVE, 0) = (unsigned long)current;
158}
159
160#ifdef CONFIG_DEBUG_FS
161struct dentry *of_debugfs_root;
162
163static int microblaze_debugfs_init(void)
164{
165 of_debugfs_root = debugfs_create_dir("microblaze", NULL);
166
167 return of_debugfs_root == NULL;
168}
169arch_initcall(microblaze_debugfs_init);
170#endif
171
172void machine_restart(char *cmd)
173{
174 printk(KERN_NOTICE "Machine restart...\n");
175 dump_stack();
176 while (1)
177 ;
178}
179
180void machine_shutdown(void)
181{
182 printk(KERN_NOTICE "Machine shutdown...\n");
183 while (1)
184 ;
185}
186
187void machine_halt(void)
188{
189 printk(KERN_NOTICE "Machine halt...\n");
190 while (1)
191 ;
192}
193
194void machine_power_off(void)
195{
196 printk(KERN_NOTICE "Machine power off...\n");
197 while (1)
198 ;
199}
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
new file mode 100644
index 000000000000..40d36931e363
--- /dev/null
+++ b/arch/microblaze/kernel/signal.c
@@ -0,0 +1,543 @@
1/*
2 * Signal handling
3 *
4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2008-2009 PetaLogix
6 * Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au>
7 * Copyright (C) 2001 NEC Corporation
8 * Copyright (C) 2001 Miles Bader <miles@gnu.org>
9 * Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima
10 * Copyright (C) 1991,1992 Linus Torvalds
11 *
12 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
13 *
14 * This file was was derived from the sh version, arch/sh/kernel/signal.c
15 *
16 * This file is subject to the terms and conditions of the GNU General
17 * Public License. See the file COPYING in the main directory of this
18 * archive for more details.
19 */
20
21#include <linux/sched.h>
22#include <linux/mm.h>
23#include <linux/smp.h>
24#include <linux/smp_lock.h>
25#include <linux/kernel.h>
26#include <linux/signal.h>
27#include <linux/errno.h>
28#include <linux/wait.h>
29#include <linux/ptrace.h>
30#include <linux/unistd.h>
31#include <linux/stddef.h>
32#include <linux/personality.h>
33#include <linux/percpu.h>
34#include <linux/linkage.h>
35#include <asm/entry.h>
36#include <asm/ucontext.h>
37#include <linux/uaccess.h>
38#include <asm/pgtable.h>
39#include <asm/pgalloc.h>
40#include <linux/syscalls.h>
41#include <asm/cacheflush.h>
42#include <asm/syscalls.h>
43
44#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
45
46asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
47
48/*
49 * Atomically swap in the new signal mask, and wait for a signal.
50 */
51asmlinkage int
52sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs)
53{
54 sigset_t saveset;
55
56 mask &= _BLOCKABLE;
57 spin_lock_irq(&current->sighand->siglock);
58 saveset = current->blocked;
59 siginitset(&current->blocked, mask);
60 recalc_sigpending();
61 spin_unlock_irq(&current->sighand->siglock);
62
63 regs->r3 = -EINTR;
64 while (1) {
65 current->state = TASK_INTERRUPTIBLE;
66 schedule();
67 if (do_signal(regs, &saveset, 1))
68 return -EINTR;
69 }
70}
71
72asmlinkage int
73sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
74 struct pt_regs *regs)
75{
76 sigset_t saveset, newset;
77
78 /* XXX: Don't preclude handling different sized sigset_t's. */
79 if (sigsetsize != sizeof(sigset_t))
80 return -EINVAL;
81
82 if (copy_from_user(&newset, unewset, sizeof(newset)))
83 return -EFAULT;
84 sigdelsetmask(&newset, ~_BLOCKABLE);
85 spin_lock_irq(&current->sighand->siglock);
86 saveset = current->blocked;
87 current->blocked = newset;
88 recalc_sigpending();
89 spin_unlock_irq(&current->sighand->siglock);
90
91 regs->r3 = -EINTR;
92 while (1) {
93 current->state = TASK_INTERRUPTIBLE;
94 schedule();
95 if (do_signal(regs, &saveset, 1))
96 return -EINTR;
97 }
98}
99
100asmlinkage int
101sys_sigaction(int sig, const struct old_sigaction *act,
102 struct old_sigaction *oact)
103{
104 struct k_sigaction new_ka, old_ka;
105 int ret;
106
107 if (act) {
108 old_sigset_t mask;
109 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
110 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
111 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
112 return -EFAULT;
113 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
114 __get_user(mask, &act->sa_mask);
115 siginitset(&new_ka.sa.sa_mask, mask);
116 }
117
118 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
119
120 if (!ret && oact) {
121 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
122 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
123 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
124 return -EFAULT;
125 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
126 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
127 }
128
129 return ret;
130}
131
132asmlinkage int
133sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
134 struct pt_regs *regs)
135{
136 return do_sigaltstack(uss, uoss, regs->r1);
137}
138
139/*
140 * Do a signal return; undo the signal stack.
141 */
142
143struct sigframe {
144 struct sigcontext sc;
145 unsigned long extramask[_NSIG_WORDS-1];
146 unsigned long tramp[2]; /* signal trampoline */
147};
148
149struct rt_sigframe {
150 struct siginfo info;
151 struct ucontext uc;
152 unsigned long tramp[2]; /* signal trampoline */
153};
154
155static int
156restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p)
157{
158 unsigned int err = 0;
159
160#define COPY(x) {err |= __get_user(regs->x, &sc->regs.x); }
161 COPY(r0);
162 COPY(r1);
163 COPY(r2); COPY(r3); COPY(r4); COPY(r5);
164 COPY(r6); COPY(r7); COPY(r8); COPY(r9);
165 COPY(r10); COPY(r11); COPY(r12); COPY(r13);
166 COPY(r14); COPY(r15); COPY(r16); COPY(r17);
167 COPY(r18); COPY(r19); COPY(r20); COPY(r21);
168 COPY(r22); COPY(r23); COPY(r24); COPY(r25);
169 COPY(r26); COPY(r27); COPY(r28); COPY(r29);
170 COPY(r30); COPY(r31);
171 COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
172#undef COPY
173
174 *rval_p = regs->r3;
175
176 return err;
177}
178
179asmlinkage int sys_sigreturn(struct pt_regs *regs)
180{
181 struct sigframe *frame =
182 (struct sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
183
184 sigset_t set;
185 int rval;
186
187 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
188 goto badframe;
189
190 if (__get_user(set.sig[0], &frame->sc.oldmask)
191 || (_NSIG_WORDS > 1
192 && __copy_from_user(&set.sig[1], &frame->extramask,
193 sizeof(frame->extramask))))
194 goto badframe;
195
196 sigdelsetmask(&set, ~_BLOCKABLE);
197
198 spin_lock_irq(&current->sighand->siglock);
199 current->blocked = set;
200 recalc_sigpending();
201 spin_unlock_irq(&current->sighand->siglock);
202
203 if (restore_sigcontext(regs, &frame->sc, &rval))
204 goto badframe;
205 return rval;
206
207badframe:
208 force_sig(SIGSEGV, current);
209 return 0;
210}
211
212asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
213{
214 struct rt_sigframe *frame =
215 (struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
216
217 sigset_t set;
218 stack_t st;
219 int rval;
220
221 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
222 goto badframe;
223
224 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
225 goto badframe;
226
227 sigdelsetmask(&set, ~_BLOCKABLE);
228 spin_lock_irq(&current->sighand->siglock);
229 current->blocked = set;
230 recalc_sigpending();
231 spin_unlock_irq(&current->sighand->siglock);
232
233 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
234 goto badframe;
235
236 if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st)))
237 goto badframe;
238 /* It is more difficult to avoid calling this function than to
239 call it and ignore errors. */
240 do_sigaltstack(&st, NULL, regs->r1);
241
242 return rval;
243
244badframe:
245 force_sig(SIGSEGV, current);
246 return 0;
247}
248
249/*
250 * Set up a signal frame.
251 */
252
253static int
254setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
255 unsigned long mask)
256{
257 int err = 0;
258
259#define COPY(x) {err |= __put_user(regs->x, &sc->regs.x); }
260 COPY(r0);
261 COPY(r1);
262 COPY(r2); COPY(r3); COPY(r4); COPY(r5);
263 COPY(r6); COPY(r7); COPY(r8); COPY(r9);
264 COPY(r10); COPY(r11); COPY(r12); COPY(r13);
265 COPY(r14); COPY(r15); COPY(r16); COPY(r17);
266 COPY(r18); COPY(r19); COPY(r20); COPY(r21);
267 COPY(r22); COPY(r23); COPY(r24); COPY(r25);
268 COPY(r26); COPY(r27); COPY(r28); COPY(r29);
269 COPY(r30); COPY(r31);
270 COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
271#undef COPY
272
273 err |= __put_user(mask, &sc->oldmask);
274
275 return err;
276}
277
278/*
279 * Determine which stack to use..
280 */
281static inline void *
282get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
283{
284 /* Default to using normal stack */
285 unsigned long sp = regs->r1;
286
287 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
288 sp = current->sas_ss_sp + current->sas_ss_size;
289
290 return (void *)((sp - frame_size) & -8UL);
291}
292
293static void setup_frame(int sig, struct k_sigaction *ka,
294 sigset_t *set, struct pt_regs *regs)
295{
296 struct sigframe *frame;
297 int err = 0;
298 int signal;
299
300 frame = get_sigframe(ka, regs, sizeof(*frame));
301
302 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
303 goto give_sigsegv;
304
305 signal = current_thread_info()->exec_domain
306 && current_thread_info()->exec_domain->signal_invmap
307 && sig < 32
308 ? current_thread_info()->exec_domain->signal_invmap[sig]
309 : sig;
310
311 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
312
313 if (_NSIG_WORDS > 1) {
314 err |= __copy_to_user(frame->extramask, &set->sig[1],
315 sizeof(frame->extramask));
316 }
317
318 /* Set up to return from userspace. If provided, use a stub
319 already in userspace. */
320 /* minus 8 is offset to cater for "rtsd r15,8" offset */
321 if (ka->sa.sa_flags & SA_RESTORER) {
322 regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
323 } else {
324 /* Note, these encodings are _big endian_! */
325
326 /* addi r12, r0, __NR_sigreturn */
327 err |= __put_user(0x31800000 | __NR_sigreturn ,
328 frame->tramp + 0);
329 /* brki r14, 0x8 */
330 err |= __put_user(0xb9cc0008, frame->tramp + 1);
331
332 /* Return from sighandler will jump to the tramp.
333 Negative 8 offset because return is rtsd r15, 8 */
334 regs->r15 = ((unsigned long)frame->tramp)-8;
335
336 __invalidate_cache_sigtramp((unsigned long)frame->tramp);
337 }
338
339 if (err)
340 goto give_sigsegv;
341
342 /* Set up registers for signal handler */
343 regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
344
345 /* Signal handler args: */
346 regs->r5 = signal; /* Arg 0: signum */
347 regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */
348
349 /* Offset of 4 to handle microblaze rtid r14, 0 */
350 regs->pc = (unsigned long)ka->sa.sa_handler;
351
352 set_fs(USER_DS);
353
354#ifdef DEBUG_SIG
355 printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
356 current->comm, current->pid, frame, regs->pc);
357#endif
358
359 return;
360
361give_sigsegv:
362 if (sig == SIGSEGV)
363 ka->sa.sa_handler = SIG_DFL;
364 force_sig(SIGSEGV, current);
365}
366
367static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
368 sigset_t *set, struct pt_regs *regs)
369{
370 struct rt_sigframe *frame;
371 int err = 0;
372 int signal;
373
374 frame = get_sigframe(ka, regs, sizeof(*frame));
375
376 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
377 goto give_sigsegv;
378
379 signal = current_thread_info()->exec_domain
380 && current_thread_info()->exec_domain->signal_invmap
381 && sig < 32
382 ? current_thread_info()->exec_domain->signal_invmap[sig]
383 : sig;
384
385 err |= copy_siginfo_to_user(&frame->info, info);
386
387 /* Create the ucontext. */
388 err |= __put_user(0, &frame->uc.uc_flags);
389 err |= __put_user(0, &frame->uc.uc_link);
390 err |= __put_user((void *)current->sas_ss_sp,
391 &frame->uc.uc_stack.ss_sp);
392 err |= __put_user(sas_ss_flags(regs->r1),
393 &frame->uc.uc_stack.ss_flags);
394 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
395 err |= setup_sigcontext(&frame->uc.uc_mcontext,
396 regs, set->sig[0]);
397 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
398
399 /* Set up to return from userspace. If provided, use a stub
400 already in userspace. */
401 /* minus 8 is offset to cater for "rtsd r15,8" */
402 if (ka->sa.sa_flags & SA_RESTORER) {
403 regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
404 } else {
405 /* addi r12, r0, __NR_sigreturn */
406 err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
407 frame->tramp + 0);
408 /* brki r14, 0x8 */
409 err |= __put_user(0xb9cc0008, frame->tramp + 1);
410
411 /* Return from sighandler will jump to the tramp.
412 Negative 8 offset because return is rtsd r15, 8 */
413 regs->r15 = ((unsigned long)frame->tramp)-8;
414
415 __invalidate_cache_sigtramp((unsigned long)frame->tramp);
416 }
417
418 if (err)
419 goto give_sigsegv;
420
421 /* Set up registers for signal handler */
422 regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
423
424 /* Signal handler args: */
425 regs->r5 = signal; /* arg 0: signum */
426 regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */
427 regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */
428 /* Offset to handle microblaze rtid r14, 0 */
429 regs->pc = (unsigned long)ka->sa.sa_handler;
430
431 set_fs(USER_DS);
432
433#ifdef DEBUG_SIG
434 printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
435 current->comm, current->pid, frame, regs->pc);
436#endif
437
438 return;
439
440give_sigsegv:
441 if (sig == SIGSEGV)
442 ka->sa.sa_handler = SIG_DFL;
443 force_sig(SIGSEGV, current);
444}
445
446/* Handle restarting system calls */
447static inline void
448handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
449{
450 switch (regs->r3) {
451 case -ERESTART_RESTARTBLOCK:
452 case -ERESTARTNOHAND:
453 if (!has_handler)
454 goto do_restart;
455 regs->r3 = -EINTR;
456 break;
457 case -ERESTARTSYS:
458 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
459 regs->r3 = -EINTR;
460 break;
461 }
462 /* fallthrough */
463 case -ERESTARTNOINTR:
464do_restart:
465 /* offset of 4 bytes to re-execute trap (brki) instruction */
466 regs->pc -= 4;
467 break;
468 }
469}
470
471/*
472 * OK, we're invoking a handler
473 */
474
475static void
476handle_signal(unsigned long sig, struct k_sigaction *ka,
477 siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
478{
479 /* Set up the stack frame */
480 if (ka->sa.sa_flags & SA_SIGINFO)
481 setup_rt_frame(sig, ka, info, oldset, regs);
482 else
483 setup_frame(sig, ka, oldset, regs);
484
485 if (ka->sa.sa_flags & SA_ONESHOT)
486 ka->sa.sa_handler = SIG_DFL;
487
488 if (!(ka->sa.sa_flags & SA_NODEFER)) {
489 spin_lock_irq(&current->sighand->siglock);
490 sigorsets(&current->blocked,
491 &current->blocked, &ka->sa.sa_mask);
492 sigaddset(&current->blocked, sig);
493 recalc_sigpending();
494 spin_unlock_irq(&current->sighand->siglock);
495 }
496}
497
498/*
499 * Note that 'init' is a special process: it doesn't get signals it doesn't
500 * want to handle. Thus you cannot kill init even with a SIGKILL even by
501 * mistake.
502 *
503 * Note that we go through the signals twice: once to check the signals that
504 * the kernel can handle, and then we build all the user-level signal handling
505 * stack-frames in one go after that.
506 */
507int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
508{
509 siginfo_t info;
510 int signr;
511 struct k_sigaction ka;
512#ifdef DEBUG_SIG
513 printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
514 printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
515 regs->r12, current_thread_info()->flags);
516#endif
517 /*
518 * We want the common case to go fast, which
519 * is why we may in certain cases get here from
520 * kernel mode. Just return without doing anything
521 * if so.
522 */
523 if (kernel_mode(regs))
524 return 1;
525
526 if (!oldset)
527 oldset = &current->blocked;
528
529 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
530 if (signr > 0) {
531 /* Whee! Actually deliver the signal. */
532 if (in_syscall)
533 handle_restart(regs, &ka, 1);
534 handle_signal(signr, &ka, &info, oldset, regs);
535 return 1;
536 }
537
538 if (in_syscall)
539 handle_restart(regs, NULL, 0);
540
541 /* Did we come from a system call? */
542 return 0;
543}
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c
new file mode 100644
index 000000000000..31905ff590b7
--- /dev/null
+++ b/arch/microblaze/kernel/sys_microblaze.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
5 *
6 * Copyright (C) 2006 Atmark Techno, Inc.
7 * Yasushi SHOJI <yashi@atmark-techno.com>
8 * Tetsuya OHKAWA <tetsuya@atmark-techno.com>
9 *
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file "COPYING" in the main directory of this archive
12 * for more details.
13 */
14
15#include <linux/errno.h>
16#include <linux/mm.h>
17#include <linux/smp.h>
18#include <linux/smp_lock.h>
19#include <linux/syscalls.h>
20#include <linux/sem.h>
21#include <linux/msg.h>
22#include <linux/shm.h>
23#include <linux/stat.h>
24#include <linux/mman.h>
25#include <linux/sys.h>
26#include <linux/ipc.h>
27#include <linux/utsname.h>
28#include <linux/file.h>
29#include <linux/module.h>
30#include <linux/err.h>
31#include <linux/fs.h>
32#include <linux/semaphore.h>
33#include <linux/uaccess.h>
34#include <linux/unistd.h>
35
36#include <asm/syscalls.h>
37/*
38 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
39 *
40 * This is really horribly ugly. This will be remove with new toolchain.
41 */
42asmlinkage int
43sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
44{
45 int version, ret;
46
47 version = call >> 16; /* hack for backward compatibility */
48 call &= 0xffff;
49
50 ret = -EINVAL;
51 switch (call) {
52 case SEMOP:
53 ret = sys_semop(first, (struct sembuf *)ptr, second);
54 break;
55 case SEMGET:
56 ret = sys_semget(first, second, third);
57 break;
58 case SEMCTL:
59 {
60 union semun fourth;
61
62 if (!ptr)
63 break;
64 ret = (access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
65 || (get_user(fourth.__pad, (void **)ptr)) ;
66 if (ret)
67 break;
68 ret = sys_semctl(first, second, third, fourth);
69 break;
70 }
71 case MSGSND:
72 ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third);
73 break;
74 case MSGRCV:
75 switch (version) {
76 case 0: {
77 struct ipc_kludge tmp;
78
79 if (!ptr)
80 break;
81 ret = (access_ok(VERIFY_READ, ptr, sizeof(tmp))
82 ? 0 : -EFAULT) || copy_from_user(&tmp,
83 (struct ipc_kludge *) ptr, sizeof(tmp));
84 if (ret)
85 break;
86 ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp,
87 third);
88 break;
89 }
90 default:
91 ret = sys_msgrcv(first, (struct msgbuf *) ptr,
92 second, fifth, third);
93 break;
94 }
95 break;
96 case MSGGET:
97 ret = sys_msgget((key_t) first, second);
98 break;
99 case MSGCTL:
100 ret = sys_msgctl(first, second, (struct msqid_ds *) ptr);
101 break;
102 case SHMAT:
103 switch (version) {
104 default: {
105 ulong raddr;
106 ret = access_ok(VERIFY_WRITE, (ulong *) third,
107 sizeof(ulong)) ? 0 : -EFAULT;
108 if (ret)
109 break;
110 ret = do_shmat(first, (char *) ptr, second, &raddr);
111 if (ret)
112 break;
113 ret = put_user(raddr, (ulong *) third);
114 break;
115 }
116 case 1: /* iBCS2 emulator entry point */
117 if (!segment_eq(get_fs(), get_ds()))
118 break;
119 ret = do_shmat(first, (char *) ptr, second,
120 (ulong *) third);
121 break;
122 }
123 break;
124 case SHMDT:
125 ret = sys_shmdt((char *)ptr);
126 break;
127 case SHMGET:
128 ret = sys_shmget(first, second, third);
129 break;
130 case SHMCTL:
131 ret = sys_shmctl(first, second, (struct shmid_ds *) ptr);
132 break;
133 }
134 return ret;
135}
136
137asmlinkage int sys_vfork(struct pt_regs *regs)
138{
139 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1,
140 regs, 0, NULL, NULL);
141}
142
143asmlinkage int sys_clone(int flags, unsigned long stack, struct pt_regs *regs)
144{
145 if (!stack)
146 stack = regs->r1;
147 return do_fork(flags, stack, regs, 0, NULL, NULL);
148}
149
150asmlinkage int sys_execve(char __user *filenamei, char __user *__user *argv,
151 char __user *__user *envp, struct pt_regs *regs)
152{
153 int error;
154 char *filename;
155
156 filename = getname(filenamei);
157 error = PTR_ERR(filename);
158 if (IS_ERR(filename))
159 goto out;
160 error = do_execve(filename, argv, envp, regs);
161 putname(filename);
162out:
163 return error;
164}
165
166asmlinkage unsigned long
167sys_mmap2(unsigned long addr, size_t len,
168 unsigned long prot, unsigned long flags,
169 unsigned long fd, unsigned long pgoff)
170{
171 struct file *file = NULL;
172 int ret = -EBADF;
173
174 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
175 if (!(flags & MAP_ANONYMOUS)) {
176 file = fget(fd);
177 if (!file) {
178 printk(KERN_INFO "no fd in mmap\r\n");
179 goto out;
180 }
181 }
182
183 down_write(&current->mm->mmap_sem);
184 ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
185 up_write(&current->mm->mmap_sem);
186 if (file)
187 fput(file);
188out:
189 return ret;
190}
191
192asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
193 unsigned long prot, unsigned long flags,
194 unsigned long fd, off_t offset)
195{
196 int err = -EINVAL;
197
198 if (offset & ~PAGE_MASK) {
199 printk(KERN_INFO "no pagemask in mmap\r\n");
200 goto out;
201 }
202
203 err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
204out:
205 return err;
206}
207
208/*
209 * Do a system call from kernel instead of calling sys_execve so we
210 * end up with proper pt_regs.
211 */
212int kernel_execve(const char *filename, char *const argv[], char *const envp[])
213{
214 register const char *__a __asm__("r5") = filename;
215 register const void *__b __asm__("r6") = argv;
216 register const void *__c __asm__("r7") = envp;
217 register unsigned long __syscall __asm__("r12") = __NR_execve;
218 register unsigned long __ret __asm__("r3");
219 __asm__ __volatile__ ("brki r14, 0x8"
220 : "=r" (__ret), "=r" (__syscall)
221 : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c)
222 : "r4", "r8", "r9",
223 "r10", "r11", "r14", "cc", "memory");
224 return __ret;
225}
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
new file mode 100644
index 000000000000..3bb42ec924c2
--- /dev/null
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -0,0 +1,367 @@
1ENTRY(sys_call_table)
2 .long sys_restart_syscall /* 0 - old "setup()" system call,
3 * used for restarting */
4 .long sys_exit
5 .long sys_ni_syscall /* was fork */
6 .long sys_read
7 .long sys_write
8 .long sys_open /* 5 */
9 .long sys_close
10 .long sys_waitpid
11 .long sys_creat
12 .long sys_link
13 .long sys_unlink /* 10 */
14 .long sys_execve_wrapper
15 .long sys_chdir
16 .long sys_time
17 .long sys_mknod
18 .long sys_chmod /* 15 */
19 .long sys_lchown
20 .long sys_ni_syscall /* old break syscall holder */
21 .long sys_ni_syscall /* old stat */
22 .long sys_lseek
23 .long sys_getpid /* 20 */
24 .long sys_mount
25 .long sys_oldumount
26 .long sys_setuid
27 .long sys_getuid
28 .long sys_stime /* 25 */
29 .long sys_ptrace
30 .long sys_alarm
31 .long sys_ni_syscall /* oldfstat */
32 .long sys_pause
33 .long sys_utime /* 30 */
34 .long sys_ni_syscall /* old stty syscall holder */
35 .long sys_ni_syscall /* old gtty syscall holder */
36 .long sys_access
37 .long sys_nice
38 .long sys_ni_syscall /* 35 - old ftime syscall holder */
39 .long sys_sync
40 .long sys_kill
41 .long sys_rename
42 .long sys_mkdir
43 .long sys_rmdir /* 40 */
44 .long sys_dup
45 .long sys_pipe
46 .long sys_times
47 .long sys_ni_syscall /* old prof syscall holder */
48 .long sys_brk /* 45 */
49 .long sys_setgid
50 .long sys_getgid
51 .long sys_signal
52 .long sys_geteuid
53 .long sys_getegid /* 50 */
54 .long sys_acct
55 .long sys_umount /* recycled never used phys() */
56 .long sys_ni_syscall /* old lock syscall holder */
57 .long sys_ioctl
58 .long sys_fcntl /* 55 */
59 .long sys_ni_syscall /* old mpx syscall holder */
60 .long sys_setpgid
61 .long sys_ni_syscall /* old ulimit syscall holder */
62 .long sys_ni_syscall /* olduname */
63 .long sys_umask /* 60 */
64 .long sys_chroot
65 .long sys_ustat
66 .long sys_dup2
67 .long sys_getppid
68 .long sys_getpgrp /* 65 */
69 .long sys_setsid
70 .long sys_sigaction
71 .long sys_sgetmask
72 .long sys_ssetmask
73 .long sys_setreuid /* 70 */
74 .long sys_setregid
75 .long sys_sigsuspend_wrapper
76 .long sys_sigpending
77 .long sys_sethostname
78 .long sys_setrlimit /* 75 */
79 .long sys_ni_syscall /* old_getrlimit */
80 .long sys_getrusage
81 .long sys_gettimeofday
82 .long sys_settimeofday
83 .long sys_getgroups /* 80 */
84 .long sys_setgroups
85 .long sys_ni_syscall /* old_select */
86 .long sys_symlink
87 .long sys_ni_syscall /* oldlstat */
88 .long sys_readlink /* 85 */
89 .long sys_uselib
90 .long sys_swapon
91 .long sys_reboot
92 .long sys_ni_syscall /* old_readdir */
93 .long sys_mmap /* 90 */ /* old_mmap */
94 .long sys_munmap
95 .long sys_truncate
96 .long sys_ftruncate
97 .long sys_fchmod
98 .long sys_fchown /* 95 */
99 .long sys_getpriority
100 .long sys_setpriority
101 .long sys_ni_syscall /* old profil syscall holder */
102 .long sys_statfs
103 .long sys_fstatfs /* 100 */
104 .long sys_ni_syscall /* ioperm */
105 .long sys_socketcall
106 .long sys_syslog /* operation with system console */
107 .long sys_setitimer
108 .long sys_getitimer /* 105 */
109 .long sys_newstat
110 .long sys_newlstat
111 .long sys_newfstat
112 .long sys_ni_syscall /* uname */
113 .long sys_ni_syscall /* 110 */ /* iopl */
114 .long sys_vhangup
115 .long sys_ni_syscall /* old "idle" system call */
116 .long sys_ni_syscall /* old sys_vm86old */
117 .long sys_wait4
118 .long sys_swapoff /* 115 */
119 .long sys_sysinfo
120 .long sys_ipc
121 .long sys_fsync
122 .long sys_sigreturn_wrapper
123 .long sys_clone_wrapper /* 120 */
124 .long sys_setdomainname
125 .long sys_newuname
126 .long sys_ni_syscall /* modify_ldt */
127 .long sys_adjtimex
128 .long sys_mprotect /* 125: sys_mprotect */
129 .long sys_sigprocmask
130 .long sys_ni_syscall /* old "create_module" */
131 .long sys_init_module
132 .long sys_delete_module
133 .long sys_ni_syscall /* 130: old "get_kernel_syms" */
134 .long sys_quotactl
135 .long sys_getpgid
136 .long sys_fchdir
137 .long sys_bdflush
138 .long sys_sysfs /* 135 */
139 .long sys_personality
140 .long sys_ni_syscall /* reserved for afs_syscall */
141 .long sys_setfsuid
142 .long sys_setfsgid
143 .long sys_llseek /* 140 */
144 .long sys_getdents
145 .long sys_select
146 .long sys_flock
147 .long sys_msync
148 .long sys_readv /* 145 */
149 .long sys_writev
150 .long sys_getsid
151 .long sys_fdatasync
152 .long sys_sysctl
153 .long sys_mlock /* 150: sys_mlock */
154 .long sys_munlock
155 .long sys_mlockall
156 .long sys_munlockall
157 .long sys_sched_setparam
158 .long sys_sched_getparam /* 155 */
159 .long sys_sched_setscheduler
160 .long sys_sched_getscheduler
161 .long sys_sched_yield
162 .long sys_sched_get_priority_max
163 .long sys_sched_get_priority_min /* 160 */
164 .long sys_sched_rr_get_interval
165 .long sys_nanosleep
166 .long sys_mremap
167 .long sys_setresuid
168 .long sys_getresuid /* 165 */
169 .long sys_ni_syscall /* sys_vm86 */
170 .long sys_ni_syscall /* Old sys_query_module */
171 .long sys_poll
172 .long sys_nfsservctl
173 .long sys_setresgid /* 170 */
174 .long sys_getresgid
175 .long sys_prctl
176 .long sys_rt_sigreturn_wrapper
177 .long sys_rt_sigaction
178 .long sys_rt_sigprocmask /* 175 */
179 .long sys_rt_sigpending
180 .long sys_rt_sigtimedwait
181 .long sys_rt_sigqueueinfo
182 .long sys_rt_sigsuspend_wrapper
183 .long sys_pread64 /* 180 */
184 .long sys_pwrite64
185 .long sys_chown
186 .long sys_getcwd
187 .long sys_capget
188 .long sys_capset /* 185 */
189 .long sys_ni_syscall /* sigaltstack */
190 .long sys_sendfile
191 .long sys_ni_syscall /* reserved for streams1 */
192 .long sys_ni_syscall /* reserved for streams2 */
193 .long sys_vfork_wrapper /* 190 */
194 .long sys_getrlimit
195 .long sys_mmap2 /* mmap2 */
196 .long sys_truncate64
197 .long sys_ftruncate64
198 .long sys_stat64 /* 195 */
199 .long sys_lstat64
200 .long sys_fstat64
201 .long sys_lchown
202 .long sys_getuid
203 .long sys_getgid /* 200 */
204 .long sys_geteuid
205 .long sys_getegid
206 .long sys_setreuid
207 .long sys_setregid
208 .long sys_getgroups /* 205 */
209 .long sys_setgroups
210 .long sys_fchown
211 .long sys_setresuid
212 .long sys_getresuid
213 .long sys_setresgid /* 210 */
214 .long sys_getresgid
215 .long sys_chown
216 .long sys_setuid
217 .long sys_setgid
218 .long sys_setfsuid /* 215 */
219 .long sys_setfsgid
220 .long sys_pivot_root
221 .long sys_mincore
222 .long sys_madvise
223 .long sys_getdents64 /* 220 */
224 .long sys_fcntl64
225 .long sys_ni_syscall /* reserved for TUX */
226 .long sys_ni_syscall
227 .long sys_gettid
228 .long sys_readahead /* 225 */
229 .long sys_setxattr
230 .long sys_lsetxattr
231 .long sys_fsetxattr
232 .long sys_getxattr
233 .long sys_lgetxattr /* 230 */
234 .long sys_fgetxattr
235 .long sys_listxattr
236 .long sys_llistxattr
237 .long sys_flistxattr
238 .long sys_removexattr /* 235 */
239 .long sys_lremovexattr
240 .long sys_fremovexattr
241 .long sys_tkill
242 .long sys_sendfile64
243 .long sys_futex /* 240 */
244 .long sys_sched_setaffinity
245 .long sys_sched_getaffinity
246 .long sys_ni_syscall /* set_thread_area */
247 .long sys_ni_syscall /* get_thread_area */
248 .long sys_io_setup /* 245 */
249 .long sys_io_destroy
250 .long sys_io_getevents
251 .long sys_io_submit
252 .long sys_io_cancel
253 .long sys_fadvise64 /* 250 */
254 .long sys_ni_syscall
255 .long sys_exit_group
256 .long sys_lookup_dcookie
257 .long sys_epoll_create
258 .long sys_epoll_ctl /* 255 */
259 .long sys_epoll_wait
260 .long sys_remap_file_pages
261 .long sys_set_tid_address
262 .long sys_timer_create
263 .long sys_timer_settime /* 260 */
264 .long sys_timer_gettime
265 .long sys_timer_getoverrun
266 .long sys_timer_delete
267 .long sys_clock_settime
268 .long sys_clock_gettime /* 265 */
269 .long sys_clock_getres
270 .long sys_clock_nanosleep
271 .long sys_statfs64
272 .long sys_fstatfs64
273 .long sys_tgkill /* 270 */
274 .long sys_utimes
275 .long sys_fadvise64_64
276 .long sys_ni_syscall /* sys_vserver */
277 .long sys_mbind
278 .long sys_get_mempolicy
279 .long sys_set_mempolicy
280 .long sys_mq_open
281 .long sys_mq_unlink
282 .long sys_mq_timedsend
283 .long sys_mq_timedreceive /* 280 */
284 .long sys_mq_notify
285 .long sys_mq_getsetattr
286 .long sys_kexec_load
287 .long sys_waitid
288 .long sys_ni_syscall /* 285 */ /* available */
289 .long sys_add_key
290 .long sys_request_key
291 .long sys_keyctl
292 .long sys_ioprio_set
293 .long sys_ioprio_get /* 290 */
294 .long sys_inotify_init
295 .long sys_inotify_add_watch
296 .long sys_inotify_rm_watch
297 .long sys_ni_syscall /* sys_migrate_pages */
298 .long sys_openat /* 295 */
299 .long sys_mkdirat
300 .long sys_mknodat
301 .long sys_fchownat
302 .long sys_ni_syscall
303 .long sys_fstatat64 /* 300 */
304 .long sys_unlinkat
305 .long sys_renameat
306 .long sys_linkat
307 .long sys_symlinkat
308 .long sys_readlinkat /* 305 */
309 .long sys_fchmodat
310 .long sys_faccessat
311 .long sys_ni_syscall /* pselect6 */
312 .long sys_ni_syscall /* sys_ppoll */
313 .long sys_unshare /* 310 */
314 .long sys_set_robust_list
315 .long sys_get_robust_list
316 .long sys_splice
317 .long sys_sync_file_range
318 .long sys_tee /* 315 */
319 .long sys_vmsplice
320 .long sys_move_pages
321 .long sys_getcpu
322 .long sys_epoll_pwait
323 .long sys_utimensat /* 320 */
324 .long sys_signalfd
325 .long sys_timerfd_create
326 .long sys_eventfd
327 .long sys_fallocate
328 .long sys_semtimedop /* 325 */
329 .long sys_timerfd_settime
330 .long sys_timerfd_gettime
331 .long sys_semctl
332 .long sys_semget
333 .long sys_semop /* 330 */
334 .long sys_msgctl
335 .long sys_msgget
336 .long sys_msgrcv
337 .long sys_msgsnd
338 .long sys_shmat /* 335 */
339 .long sys_shmctl
340 .long sys_shmdt
341 .long sys_shmget
342 .long sys_signalfd4 /* new syscall */
343 .long sys_eventfd2 /* 340 */
344 .long sys_epoll_create1
345 .long sys_dup3
346 .long sys_pipe2
347 .long sys_inotify_init1
348 .long sys_socket /* 345 */
349 .long sys_socketpair
350 .long sys_bind
351 .long sys_listen
352 .long sys_accept
353 .long sys_connect /* 350 */
354 .long sys_getsockname
355 .long sys_getpeername
356 .long sys_sendto
357 .long sys_send
358 .long sys_recvfrom /* 355 */
359 .long sys_recv
360 .long sys_setsockopt
361 .long sys_getsockopt
362 .long sys_shutdown
363 .long sys_sendmsg /* 360 */
364 .long sys_recvmsg
365 .long sys_ni_syscall
366 .long sys_ni_syscall
367 .long sys_ni_syscall
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
new file mode 100644
index 000000000000..bdfa2f9f0c81
--- /dev/null
+++ b/arch/microblaze/kernel/timer.c
@@ -0,0 +1,262 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/param.h>
14#include <linux/interrupt.h>
15#include <linux/profile.h>
16#include <linux/irq.h>
17#include <linux/delay.h>
18#include <linux/sched.h>
19#include <linux/spinlock.h>
20#include <linux/err.h>
21#include <linux/clk.h>
22#include <linux/clocksource.h>
23#include <linux/clockchips.h>
24#include <linux/io.h>
25#include <asm/cpuinfo.h>
26#include <asm/setup.h>
27#include <asm/prom.h>
28#include <asm/irq.h>
29#include <asm/system.h>
30
31#ifdef CONFIG_SELFMOD_TIMER
32#include <asm/selfmod.h>
33#define TIMER_BASE BARRIER_BASE_ADDR
34#else
35static unsigned int timer_baseaddr;
36#define TIMER_BASE timer_baseaddr
37#endif
38
39#define TCSR0 (0x00)
40#define TLR0 (0x04)
41#define TCR0 (0x08)
42#define TCSR1 (0x10)
43#define TLR1 (0x14)
44#define TCR1 (0x18)
45
46#define TCSR_MDT (1<<0)
47#define TCSR_UDT (1<<1)
48#define TCSR_GENT (1<<2)
49#define TCSR_CAPT (1<<3)
50#define TCSR_ARHT (1<<4)
51#define TCSR_LOAD (1<<5)
52#define TCSR_ENIT (1<<6)
53#define TCSR_ENT (1<<7)
54#define TCSR_TINT (1<<8)
55#define TCSR_PWMA (1<<9)
56#define TCSR_ENALL (1<<10)
57
58static inline void microblaze_timer0_stop(void)
59{
60 out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT);
61}
62
63static inline void microblaze_timer0_start_periodic(unsigned long load_val)
64{
65 if (!load_val)
66 load_val = 1;
67 out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
68
69 /* load the initial value */
70 out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
71
72 /* see timer data sheet for detail
73 * !ENALL - don't enable 'em all
74 * !PWMA - disable pwm
75 * TINT - clear interrupt status
76 * ENT- enable timer itself
77 * EINT - enable interrupt
78 * !LOAD - clear the bit to let go
79 * ARHT - auto reload
80 * !CAPT - no external trigger
81 * !GENT - no external signal
82 * UDT - set the timer as down counter
83 * !MDT0 - generate mode
84 */
85 out_be32(TIMER_BASE + TCSR0,
86 TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
87}
88
89static inline void microblaze_timer0_start_oneshot(unsigned long load_val)
90{
91 if (!load_val)
92 load_val = 1;
93 out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
94
95 /* load the initial value */
96 out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
97
98 out_be32(TIMER_BASE + TCSR0,
99 TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
100}
101
102static int microblaze_timer_set_next_event(unsigned long delta,
103 struct clock_event_device *dev)
104{
105 pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
106 microblaze_timer0_start_oneshot(delta);
107 return 0;
108}
109
110static void microblaze_timer_set_mode(enum clock_event_mode mode,
111 struct clock_event_device *evt)
112{
113 switch (mode) {
114 case CLOCK_EVT_MODE_PERIODIC:
115 printk(KERN_INFO "%s: periodic\n", __func__);
116 microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
117 break;
118 case CLOCK_EVT_MODE_ONESHOT:
119 printk(KERN_INFO "%s: oneshot\n", __func__);
120 break;
121 case CLOCK_EVT_MODE_UNUSED:
122 printk(KERN_INFO "%s: unused\n", __func__);
123 break;
124 case CLOCK_EVT_MODE_SHUTDOWN:
125 printk(KERN_INFO "%s: shutdown\n", __func__);
126 microblaze_timer0_stop();
127 break;
128 case CLOCK_EVT_MODE_RESUME:
129 printk(KERN_INFO "%s: resume\n", __func__);
130 break;
131 }
132}
133
134static struct clock_event_device clockevent_microblaze_timer = {
135 .name = "microblaze_clockevent",
136 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
137 .shift = 24,
138 .rating = 300,
139 .set_next_event = microblaze_timer_set_next_event,
140 .set_mode = microblaze_timer_set_mode,
141};
142
143static inline void timer_ack(void)
144{
145 out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0));
146}
147
148static irqreturn_t timer_interrupt(int irq, void *dev_id)
149{
150 struct clock_event_device *evt = &clockevent_microblaze_timer;
151#ifdef CONFIG_HEART_BEAT
152 heartbeat();
153#endif
154 timer_ack();
155 evt->event_handler(evt);
156 return IRQ_HANDLED;
157}
158
159static struct irqaction timer_irqaction = {
160 .handler = timer_interrupt,
161 .flags = IRQF_DISABLED | IRQF_TIMER,
162 .name = "timer",
163 .dev_id = &clockevent_microblaze_timer,
164};
165
166static __init void microblaze_clockevent_init(void)
167{
168 clockevent_microblaze_timer.mult =
169 div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
170 clockevent_microblaze_timer.shift);
171 clockevent_microblaze_timer.max_delta_ns =
172 clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
173 clockevent_microblaze_timer.min_delta_ns =
174 clockevent_delta2ns(1, &clockevent_microblaze_timer);
175 clockevent_microblaze_timer.cpumask = cpumask_of(0);
176 clockevents_register_device(&clockevent_microblaze_timer);
177}
178
179static cycle_t microblaze_read(struct clocksource *cs)
180{
181 /* reading actual value of timer 1 */
182 return (cycle_t) (in_be32(TIMER_BASE + TCR1));
183}
184
185static struct clocksource clocksource_microblaze = {
186 .name = "microblaze_clocksource",
187 .rating = 300,
188 .read = microblaze_read,
189 .mask = CLOCKSOURCE_MASK(32),
190 .shift = 24, /* I can shift it */
191 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
192};
193
194static int __init microblaze_clocksource_init(void)
195{
196 clocksource_microblaze.mult =
197 clocksource_hz2mult(cpuinfo.cpu_clock_freq,
198 clocksource_microblaze.shift);
199 if (clocksource_register(&clocksource_microblaze))
200 panic("failed to register clocksource");
201
202 /* stop timer1 */
203 out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
204 /* start timer1 - up counting without interrupt */
205 out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
206 return 0;
207}
208
209void __init time_init(void)
210{
211 u32 irq, i = 0;
212 u32 timer_num = 1;
213 struct device_node *timer = NULL;
214#ifdef CONFIG_SELFMOD_TIMER
215 unsigned int timer_baseaddr = 0;
216 int arr_func[] = {
217 (int)&microblaze_read,
218 (int)&timer_interrupt,
219 (int)&microblaze_clocksource_init,
220 (int)&microblaze_timer_set_mode,
221 (int)&microblaze_timer_set_next_event,
222 0
223 };
224#endif
225 char *timer_list[] = {
226 "xlnx,xps-timer-1.00.a",
227 "xlnx,opb-timer-1.00.b",
228 "xlnx,opb-timer-1.00.a",
229 NULL
230 };
231
232 for (i = 0; timer_list[i] != NULL; i++) {
233 timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
234 if (timer)
235 break;
236 }
237
238 timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
239 timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
240 irq = *(int *) of_get_property(timer, "interrupts", NULL);
241 timer_num =
242 *(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
243 if (timer_num) {
244 printk(KERN_EMERG "Please enable two timers in HW\n");
245 BUG();
246 }
247
248#ifdef CONFIG_SELFMOD_TIMER
249 selfmod_function((int *) arr_func, timer_baseaddr);
250#endif
251 printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
252 timer_list[i], timer_baseaddr, irq);
253
254 cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
255
256 setup_irq(irq, &timer_irqaction);
257#ifdef CONFIG_HEART_BEAT
258 setup_heartbeat();
259#endif
260 microblaze_clocksource_init();
261 microblaze_clockevent_init();
262}
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
new file mode 100644
index 000000000000..293ef486013a
--- /dev/null
+++ b/arch/microblaze/kernel/traps.c
@@ -0,0 +1,107 @@
1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/kallsyms.h>
13#include <linux/module.h>
14#include <linux/sched.h>
15#include <linux/debug_locks.h>
16
17#include <asm/exceptions.h>
18#include <asm/system.h>
19
20void trap_init(void)
21{
22 __enable_hw_exceptions();
23}
24
25void __bad_xchg(volatile void *ptr, int size)
26{
27 printk(KERN_INFO "xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
28 __builtin_return_address(0), ptr, size);
29 BUG();
30}
31EXPORT_SYMBOL(__bad_xchg);
32
33static int kstack_depth_to_print = 24;
34
35static int __init kstack_setup(char *s)
36{
37 kstack_depth_to_print = strict_strtoul(s, 0, NULL);
38
39 return 1;
40}
41__setup("kstack=", kstack_setup);
42
43void show_trace(struct task_struct *task, unsigned long *stack)
44{
45 unsigned long addr;
46
47 if (!stack)
48 stack = (unsigned long *)&stack;
49
50 printk(KERN_NOTICE "Call Trace: ");
51#ifdef CONFIG_KALLSYMS
52 printk(KERN_NOTICE "\n");
53#endif
54 while (!kstack_end(stack)) {
55 addr = *stack++;
56 /*
57 * If the address is either in the text segment of the
58 * kernel, or in the region which contains vmalloc'ed
59 * memory, it *may* be the address of a calling
60 * routine; if so, print it so that someone tracing
61 * down the cause of the crash will be able to figure
62 * out the call path that was taken.
63 */
64 if (kernel_text_address(addr))
65 print_ip_sym(addr);
66 }
67 printk(KERN_NOTICE "\n");
68
69 if (!task)
70 task = current;
71
72 debug_show_held_locks(task);
73}
74
75void show_stack(struct task_struct *task, unsigned long *sp)
76{
77 unsigned long *stack;
78 int i;
79
80 if (sp == NULL) {
81 if (task)
82 sp = (unsigned long *) ((struct thread_info *)
83 (task->stack))->cpu_context.r1;
84 else
85 sp = (unsigned long *)&sp;
86 }
87
88 stack = sp;
89
90 printk(KERN_INFO "\nStack:\n ");
91
92 for (i = 0; i < kstack_depth_to_print; i++) {
93 if (kstack_end(sp))
94 break;
95 if (i && ((i % 8) == 0))
96 printk("\n ");
97 printk("%08lx ", *sp++);
98 }
99 printk("\n");
100 show_trace(task, stack);
101}
102
103void dump_stack(void)
104{
105 show_stack(NULL, NULL);
106}
107EXPORT_SYMBOL(dump_stack);
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..840385e51291
--- /dev/null
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -0,0 +1,163 @@
1/*
2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2008-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
12OUTPUT_ARCH(microblaze)
13ENTRY(_start)
14
15#include <asm-generic/vmlinux.lds.h>
16
17jiffies = jiffies_64 + 4;
18
19SECTIONS {
20 . = CONFIG_KERNEL_BASE_ADDR;
21
22 .text : {
23 _text = . ;
24 _stext = . ;
25 *(.text .text.*)
26 *(.fixup)
27
28 *(.exitcall.exit)
29 SCHED_TEXT
30 LOCK_TEXT
31 KPROBES_TEXT
32 . = ALIGN (4) ;
33 _etext = . ;
34 }
35
36 . = ALIGN (4) ;
37 _fdt_start = . ; /* place for fdt blob */
38 . = . + 0x4000;
39 _fdt_end = . ;
40
41 . = ALIGN(16);
42 RODATA
43 . = ALIGN(16);
44 __ex_table : {
45 __start___ex_table = .;
46 *(__ex_table)
47 __stop___ex_table = .;
48 }
49
50 /*
51 * sdata2 section can go anywhere, but must be word aligned
52 * and SDA2_BASE must point to the middle of it
53 */
54 .sdata2 : {
55 _ssrw = .;
56 . = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */
57 *(.sdata2)
58 . = ALIGN(8);
59 _essrw = .;
60 _ssrw_size = _essrw - _ssrw;
61 _KERNEL_SDA2_BASE_ = _ssrw + (_ssrw_size / 2);
62 }
63
64 _sdata = . ;
65 .data ALIGN (4096) : { /* page aligned when MMU used - origin 0x4 */
66 *(.data)
67 }
68 . = ALIGN(32);
69 .data.cacheline_aligned : { *(.data.cacheline_aligned) }
70 _edata = . ;
71
72 /* Reserve some low RAM for r0 based memory references */
73 . = ALIGN(0x4) ;
74 r0_ram = . ;
75 . = . + 4096; /* a page should be enough */
76
77 /* The initial task */
78 . = ALIGN(8192);
79 .data.init_task : { *(.data.init_task) }
80
81 /* Under the microblaze ABI, .sdata and .sbss must be contiguous */
82 . = ALIGN(8);
83 .sdata : {
84 _ssro = .;
85 *(.sdata)
86 }
87
88 .sbss : {
89 _ssbss = .;
90 *(.sbss)
91 _esbss = .;
92 _essro = .;
93 _ssro_size = _essro - _ssro ;
94 _KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
95 }
96
97 __init_begin = .;
98
99 . = ALIGN(4096);
100 .init.text : {
101 _sinittext = . ;
102 *(.init.text)
103 *(.exit.text)
104 *(.exit.data)
105 _einittext = .;
106 }
107
108 .init.data : { *(.init.data) }
109
110 . = ALIGN(4);
111 .init.ivt : {
112 __ivt_start = .;
113 *(.init.ivt)
114 __ivt_end = .;
115 }
116
117 .init.setup : {
118 __setup_start = .;
119 *(.init.setup)
120 __setup_end = .;
121 }
122
123 .initcall.init : {
124 __initcall_start = .;
125 INITCALLS
126 __initcall_end = .;
127 }
128
129 .con_initcall.init : {
130 __con_initcall_start = .;
131 *(.con_initcall.init)
132 __con_initcall_end = .;
133 }
134
135 __init_end_before_initramfs = .;
136
137 .init.ramfs ALIGN(4096) : {
138 __initramfs_start = .;
139 *(.init.ramfs)
140 __initramfs_end = .;
141 . = ALIGN(4);
142 LONG(0);
143/*
144 * FIXME this can break initramfs for MMU.
145 * Pad init.ramfs up to page boundary,
146 * so that __init_end == __bss_start. This will make image.elf
147 * consistent with the image.bin
148 */
149 /* . = ALIGN(4096); */
150 }
151 __init_end = .;
152
153 .bss ALIGN (4096) : { /* page aligned when MMU used */
154 __bss_start = . ;
155 *(.bss*)
156 *(COMMON)
157 . = ALIGN (4) ;
158 __bss_stop = . ;
159 _ebss = . ;
160 }
161 . = ALIGN(4096);
162 _end = .;
163}