aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/Makefile14
-rw-r--r--arch/blackfin/kernel/asm-offsets.c136
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c742
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c637
-rw-r--r--arch/blackfin/kernel/bfin_ksyms.c119
-rw-r--r--arch/blackfin/kernel/dma-mapping.c183
-rw-r--r--arch/blackfin/kernel/dualcore_test.c49
-rw-r--r--arch/blackfin/kernel/entry.S94
-rw-r--r--arch/blackfin/kernel/flat.c101
-rw-r--r--arch/blackfin/kernel/init_task.c60
-rw-r--r--arch/blackfin/kernel/irqchip.c147
-rw-r--r--arch/blackfin/kernel/module.c429
-rw-r--r--arch/blackfin/kernel/process.c394
-rw-r--r--arch/blackfin/kernel/ptrace.c430
-rw-r--r--arch/blackfin/kernel/setup.c902
-rw-r--r--arch/blackfin/kernel/signal.c356
-rw-r--r--arch/blackfin/kernel/sys_bfin.c115
-rw-r--r--arch/blackfin/kernel/time.c326
-rw-r--r--arch/blackfin/kernel/traps.c649
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S228
20 files changed, 6111 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
new file mode 100644
index 000000000000..f3b7d2f9d49c
--- /dev/null
+++ b/arch/blackfin/kernel/Makefile
@@ -0,0 +1,14 @@
1#
2# arch/blackfin/kernel/Makefile
3#
4
5extra-y := init_task.o vmlinux.lds
6
7obj-y := \
8 entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
9 sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
10 flat.o
11
12obj-$(CONFIG_MODULES) += module.o
13obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
14obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
new file mode 100644
index 000000000000..41d9a9f89700
--- /dev/null
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -0,0 +1,136 @@
1/*
2 * File: arch/blackfin/kernel/asm-offsets.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: generate definitions needed by assembly language modules.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/stddef.h>
31#include <linux/sched.h>
32#include <linux/kernel_stat.h>
33#include <linux/ptrace.h>
34#include <linux/hardirq.h>
35#include <asm/irq.h>
36#include <asm/thread_info.h>
37
38#define DEFINE(sym, val) \
39 asm volatile("\n->" #sym " %0 " #val : : "i" (val))
40
41int main(void)
42{
43 /* offsets into the task struct */
44 DEFINE(TASK_STATE, offsetof(struct task_struct, state));
45 DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
46 DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
47 DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
48 DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
49 DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
50 DEFINE(TASK_MM, offsetof(struct task_struct, mm));
51 DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
52 DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
53
54 /* offsets into the irq_cpustat_t struct */
55 DEFINE(CPUSTAT_SOFTIRQ_PENDING,
56 offsetof(irq_cpustat_t, __softirq_pending));
57
58 /* offsets into the thread struct */
59 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
60 DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
61 DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
62 DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
63 DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
64 DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
65 DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
66
67 /* offsets into the pt_regs */
68 DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
69 DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
70 DEFINE(PT_R0, offsetof(struct pt_regs, r0));
71 DEFINE(PT_R1, offsetof(struct pt_regs, r1));
72 DEFINE(PT_R2, offsetof(struct pt_regs, r2));
73 DEFINE(PT_R3, offsetof(struct pt_regs, r3));
74 DEFINE(PT_R4, offsetof(struct pt_regs, r4));
75 DEFINE(PT_R5, offsetof(struct pt_regs, r5));
76 DEFINE(PT_R6, offsetof(struct pt_regs, r6));
77 DEFINE(PT_R7, offsetof(struct pt_regs, r7));
78
79 DEFINE(PT_P0, offsetof(struct pt_regs, p0));
80 DEFINE(PT_P1, offsetof(struct pt_regs, p1));
81 DEFINE(PT_P2, offsetof(struct pt_regs, p2));
82 DEFINE(PT_P3, offsetof(struct pt_regs, p3));
83 DEFINE(PT_P4, offsetof(struct pt_regs, p4));
84 DEFINE(PT_P5, offsetof(struct pt_regs, p5));
85
86 DEFINE(PT_FP, offsetof(struct pt_regs, fp));
87 DEFINE(PT_USP, offsetof(struct pt_regs, usp));
88 DEFINE(PT_I0, offsetof(struct pt_regs, i0));
89 DEFINE(PT_I1, offsetof(struct pt_regs, i1));
90 DEFINE(PT_I2, offsetof(struct pt_regs, i2));
91 DEFINE(PT_I3, offsetof(struct pt_regs, i3));
92 DEFINE(PT_M0, offsetof(struct pt_regs, m0));
93 DEFINE(PT_M1, offsetof(struct pt_regs, m1));
94 DEFINE(PT_M2, offsetof(struct pt_regs, m2));
95 DEFINE(PT_M3, offsetof(struct pt_regs, m3));
96 DEFINE(PT_L0, offsetof(struct pt_regs, l0));
97 DEFINE(PT_L1, offsetof(struct pt_regs, l1));
98 DEFINE(PT_L2, offsetof(struct pt_regs, l2));
99 DEFINE(PT_L3, offsetof(struct pt_regs, l3));
100 DEFINE(PT_B0, offsetof(struct pt_regs, b0));
101 DEFINE(PT_B1, offsetof(struct pt_regs, b1));
102 DEFINE(PT_B2, offsetof(struct pt_regs, b2));
103 DEFINE(PT_B3, offsetof(struct pt_regs, b3));
104 DEFINE(PT_A0X, offsetof(struct pt_regs, a0x));
105 DEFINE(PT_A0W, offsetof(struct pt_regs, a0w));
106 DEFINE(PT_A1X, offsetof(struct pt_regs, a1x));
107 DEFINE(PT_A1W, offsetof(struct pt_regs, a1w));
108 DEFINE(PT_LC0, offsetof(struct pt_regs, lc0));
109 DEFINE(PT_LC1, offsetof(struct pt_regs, lc1));
110 DEFINE(PT_LT0, offsetof(struct pt_regs, lt0));
111 DEFINE(PT_LT1, offsetof(struct pt_regs, lt1));
112 DEFINE(PT_LB0, offsetof(struct pt_regs, lb0));
113 DEFINE(PT_LB1, offsetof(struct pt_regs, lb1));
114 DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat));
115 DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved));
116 DEFINE(PT_RETS, offsetof(struct pt_regs, rets));
117 DEFINE(PT_PC, offsetof(struct pt_regs, pc));
118 DEFINE(PT_RETX, offsetof(struct pt_regs, retx));
119 DEFINE(PT_RETN, offsetof(struct pt_regs, retn));
120 DEFINE(PT_RETE, offsetof(struct pt_regs, rete));
121 DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat));
122 DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg));
123 DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend));
124 DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs));
125 DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs)); /* Needed by gdb */
126 DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */
127 DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs)); /* Needed by gdb */
128 DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs)); /* Needed by gdb */
129 DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */
130
131 /* signal defines */
132 DEFINE(SIGSEGV, SIGSEGV);
133 DEFINE(SIGTRAP, SIGTRAP);
134
135 return 0;
136}
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
new file mode 100644
index 000000000000..8ea079ebecb5
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -0,0 +1,742 @@
1/*
2 * File: arch/blackfin/kernel/bfin_dma_5xx.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/errno.h>
31#include <linux/module.h>
32#include <linux/sched.h>
33#include <linux/interrupt.h>
34#include <linux/kernel.h>
35#include <linux/param.h>
36
37#include <asm/dma.h>
38#include <asm/cacheflush.h>
39
40/* Remove unused code not exported by symbol or internally called */
41#define REMOVE_DEAD_CODE
42
43/**************************************************************************
44 * Global Variables
45***************************************************************************/
46
47static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
48#if defined (CONFIG_BF561)
49static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
50 (struct dma_register *) DMA1_0_NEXT_DESC_PTR,
51 (struct dma_register *) DMA1_1_NEXT_DESC_PTR,
52 (struct dma_register *) DMA1_2_NEXT_DESC_PTR,
53 (struct dma_register *) DMA1_3_NEXT_DESC_PTR,
54 (struct dma_register *) DMA1_4_NEXT_DESC_PTR,
55 (struct dma_register *) DMA1_5_NEXT_DESC_PTR,
56 (struct dma_register *) DMA1_6_NEXT_DESC_PTR,
57 (struct dma_register *) DMA1_7_NEXT_DESC_PTR,
58 (struct dma_register *) DMA1_8_NEXT_DESC_PTR,
59 (struct dma_register *) DMA1_9_NEXT_DESC_PTR,
60 (struct dma_register *) DMA1_10_NEXT_DESC_PTR,
61 (struct dma_register *) DMA1_11_NEXT_DESC_PTR,
62 (struct dma_register *) DMA2_0_NEXT_DESC_PTR,
63 (struct dma_register *) DMA2_1_NEXT_DESC_PTR,
64 (struct dma_register *) DMA2_2_NEXT_DESC_PTR,
65 (struct dma_register *) DMA2_3_NEXT_DESC_PTR,
66 (struct dma_register *) DMA2_4_NEXT_DESC_PTR,
67 (struct dma_register *) DMA2_5_NEXT_DESC_PTR,
68 (struct dma_register *) DMA2_6_NEXT_DESC_PTR,
69 (struct dma_register *) DMA2_7_NEXT_DESC_PTR,
70 (struct dma_register *) DMA2_8_NEXT_DESC_PTR,
71 (struct dma_register *) DMA2_9_NEXT_DESC_PTR,
72 (struct dma_register *) DMA2_10_NEXT_DESC_PTR,
73 (struct dma_register *) DMA2_11_NEXT_DESC_PTR,
74 (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
75 (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
76 (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
77 (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
78 (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
79 (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
80 (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
81 (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
82 (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
83 (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
84 (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
85 (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
86};
87#else
88static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
89 (struct dma_register *) DMA0_NEXT_DESC_PTR,
90 (struct dma_register *) DMA1_NEXT_DESC_PTR,
91 (struct dma_register *) DMA2_NEXT_DESC_PTR,
92 (struct dma_register *) DMA3_NEXT_DESC_PTR,
93 (struct dma_register *) DMA4_NEXT_DESC_PTR,
94 (struct dma_register *) DMA5_NEXT_DESC_PTR,
95 (struct dma_register *) DMA6_NEXT_DESC_PTR,
96 (struct dma_register *) DMA7_NEXT_DESC_PTR,
97#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
98 (struct dma_register *) DMA8_NEXT_DESC_PTR,
99 (struct dma_register *) DMA9_NEXT_DESC_PTR,
100 (struct dma_register *) DMA10_NEXT_DESC_PTR,
101 (struct dma_register *) DMA11_NEXT_DESC_PTR,
102#endif
103 (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
104 (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
105 (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
106 (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
107};
108#endif
109
110/*------------------------------------------------------------------------------
111 * Set the Buffer Clear bit in the Configuration register of specific DMA
112 * channel. This will stop the descriptor based DMA operation.
113 *-----------------------------------------------------------------------------*/
114static void clear_dma_buffer(unsigned int channel)
115{
116 dma_ch[channel].regs->cfg |= RESTART;
117 SSYNC();
118 dma_ch[channel].regs->cfg &= ~RESTART;
119 SSYNC();
120}
121
122int __init blackfin_dma_init(void)
123{
124 int i;
125
126 printk(KERN_INFO "Blackfin DMA Controller\n");
127
128 for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
129 dma_ch[i].chan_status = DMA_CHANNEL_FREE;
130 dma_ch[i].regs = base_addr[i];
131 mutex_init(&(dma_ch[i].dmalock));
132 }
133
134 return 0;
135}
136
137arch_initcall(blackfin_dma_init);
138
139/*
140 * Form the channel find the irq number for that channel.
141 */
142#if !defined(CONFIG_BF561)
143
144static int bf533_channel2irq(unsigned int channel)
145{
146 int ret_irq = -1;
147
148 switch (channel) {
149 case CH_PPI:
150 ret_irq = IRQ_PPI;
151 break;
152
153#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
154 case CH_EMAC_RX:
155 ret_irq = IRQ_MAC_RX;
156 break;
157
158 case CH_EMAC_TX:
159 ret_irq = IRQ_MAC_TX;
160 break;
161
162 case CH_UART1_RX:
163 ret_irq = IRQ_UART1_RX;
164 break;
165
166 case CH_UART1_TX:
167 ret_irq = IRQ_UART1_TX;
168 break;
169#endif
170
171 case CH_SPORT0_RX:
172 ret_irq = IRQ_SPORT0_RX;
173 break;
174
175 case CH_SPORT0_TX:
176 ret_irq = IRQ_SPORT0_TX;
177 break;
178
179 case CH_SPORT1_RX:
180 ret_irq = IRQ_SPORT1_RX;
181 break;
182
183 case CH_SPORT1_TX:
184 ret_irq = IRQ_SPORT1_TX;
185 break;
186
187 case CH_SPI:
188 ret_irq = IRQ_SPI;
189 break;
190
191 case CH_UART_RX:
192 ret_irq = IRQ_UART_RX;
193 break;
194
195 case CH_UART_TX:
196 ret_irq = IRQ_UART_TX;
197 break;
198
199 case CH_MEM_STREAM0_SRC:
200 case CH_MEM_STREAM0_DEST:
201 ret_irq = IRQ_MEM_DMA0;
202 break;
203
204 case CH_MEM_STREAM1_SRC:
205 case CH_MEM_STREAM1_DEST:
206 ret_irq = IRQ_MEM_DMA1;
207 break;
208 }
209 return ret_irq;
210}
211
212# define channel2irq(channel) bf533_channel2irq(channel)
213
214#else
215
216static int bf561_channel2irq(unsigned int channel)
217{
218 int ret_irq = -1;
219
220 switch (channel) {
221 case CH_PPI0:
222 ret_irq = IRQ_PPI0;
223 break;
224 case CH_PPI1:
225 ret_irq = IRQ_PPI1;
226 break;
227 case CH_SPORT0_RX:
228 ret_irq = IRQ_SPORT0_RX;
229 break;
230 case CH_SPORT0_TX:
231 ret_irq = IRQ_SPORT0_TX;
232 break;
233 case CH_SPORT1_RX:
234 ret_irq = IRQ_SPORT1_RX;
235 break;
236 case CH_SPORT1_TX:
237 ret_irq = IRQ_SPORT1_TX;
238 break;
239 case CH_SPI:
240 ret_irq = IRQ_SPI;
241 break;
242 case CH_UART_RX:
243 ret_irq = IRQ_UART_RX;
244 break;
245 case CH_UART_TX:
246 ret_irq = IRQ_UART_TX;
247 break;
248
249 case CH_MEM_STREAM0_SRC:
250 case CH_MEM_STREAM0_DEST:
251 ret_irq = IRQ_MEM_DMA0;
252 break;
253 case CH_MEM_STREAM1_SRC:
254 case CH_MEM_STREAM1_DEST:
255 ret_irq = IRQ_MEM_DMA1;
256 break;
257 case CH_MEM_STREAM2_SRC:
258 case CH_MEM_STREAM2_DEST:
259 ret_irq = IRQ_MEM_DMA2;
260 break;
261 case CH_MEM_STREAM3_SRC:
262 case CH_MEM_STREAM3_DEST:
263 ret_irq = IRQ_MEM_DMA3;
264 break;
265
266 case CH_IMEM_STREAM0_SRC:
267 case CH_IMEM_STREAM0_DEST:
268 ret_irq = IRQ_IMEM_DMA0;
269 break;
270 case CH_IMEM_STREAM1_SRC:
271 case CH_IMEM_STREAM1_DEST:
272 ret_irq = IRQ_IMEM_DMA1;
273 break;
274 }
275 return ret_irq;
276}
277
278# define channel2irq(channel) bf561_channel2irq(channel)
279
280#endif
281
282/*------------------------------------------------------------------------------
283 * Request the specific DMA channel from the system.
284 *-----------------------------------------------------------------------------*/
285int request_dma(unsigned int channel, char *device_id)
286{
287
288 pr_debug("request_dma() : BEGIN \n");
289 mutex_lock(&(dma_ch[channel].dmalock));
290
291 if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
292 || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
293 mutex_unlock(&(dma_ch[channel].dmalock));
294 pr_debug("DMA CHANNEL IN USE \n");
295 return -EBUSY;
296 } else {
297 dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
298 pr_debug("DMA CHANNEL IS ALLOCATED \n");
299 }
300
301 mutex_unlock(&(dma_ch[channel].dmalock));
302
303 dma_ch[channel].device_id = device_id;
304 dma_ch[channel].irq_callback = NULL;
305
306 /* This is to be enabled by putting a restriction -
307 * you have to request DMA, before doing any operations on
308 * descriptor/channel
309 */
310 pr_debug("request_dma() : END \n");
311 return channel;
312}
313EXPORT_SYMBOL(request_dma);
314
315int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data)
316{
317 int ret_irq = 0;
318
319 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
320 && channel < MAX_BLACKFIN_DMA_CHANNEL));
321
322 if (callback != NULL) {
323 int ret_val;
324 ret_irq = channel2irq(channel);
325
326 dma_ch[channel].data = data;
327
328 ret_val =
329 request_irq(ret_irq, (void *)callback, IRQF_DISABLED,
330 dma_ch[channel].device_id, data);
331 if (ret_val) {
332 printk(KERN_NOTICE
333 "Request irq in DMA engine failed.\n");
334 return -EPERM;
335 }
336 dma_ch[channel].irq_callback = callback;
337 }
338 return 0;
339}
340EXPORT_SYMBOL(set_dma_callback);
341
342void free_dma(unsigned int channel)
343{
344 int ret_irq;
345
346 pr_debug("freedma() : BEGIN \n");
347 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
348 && channel < MAX_BLACKFIN_DMA_CHANNEL));
349
350 /* Halt the DMA */
351 disable_dma(channel);
352 clear_dma_buffer(channel);
353
354 if (dma_ch[channel].irq_callback != NULL) {
355 ret_irq = channel2irq(channel);
356 free_irq(ret_irq, dma_ch[channel].data);
357 }
358
359 /* Clear the DMA Variable in the Channel */
360 mutex_lock(&(dma_ch[channel].dmalock));
361 dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
362 mutex_unlock(&(dma_ch[channel].dmalock));
363
364 pr_debug("freedma() : END \n");
365}
366EXPORT_SYMBOL(free_dma);
367
368void dma_enable_irq(unsigned int channel)
369{
370 int ret_irq;
371
372 pr_debug("dma_enable_irq() : BEGIN \n");
373 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
374 && channel < MAX_BLACKFIN_DMA_CHANNEL));
375
376 ret_irq = channel2irq(channel);
377 enable_irq(ret_irq);
378}
379EXPORT_SYMBOL(dma_enable_irq);
380
381void dma_disable_irq(unsigned int channel)
382{
383 int ret_irq;
384
385 pr_debug("dma_disable_irq() : BEGIN \n");
386 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
387 && channel < MAX_BLACKFIN_DMA_CHANNEL));
388
389 ret_irq = channel2irq(channel);
390 disable_irq(ret_irq);
391}
392EXPORT_SYMBOL(dma_disable_irq);
393
394int dma_channel_active(unsigned int channel)
395{
396 if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) {
397 return 0;
398 } else {
399 return 1;
400 }
401}
402EXPORT_SYMBOL(dma_channel_active);
403
404/*------------------------------------------------------------------------------
405* stop the specific DMA channel.
406*-----------------------------------------------------------------------------*/
407void disable_dma(unsigned int channel)
408{
409 pr_debug("stop_dma() : BEGIN \n");
410
411 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
412 && channel < MAX_BLACKFIN_DMA_CHANNEL));
413
414 dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */
415 SSYNC();
416 dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
417 /* Needs to be enabled Later */
418 pr_debug("stop_dma() : END \n");
419 return;
420}
421EXPORT_SYMBOL(disable_dma);
422
423void enable_dma(unsigned int channel)
424{
425 pr_debug("enable_dma() : BEGIN \n");
426
427 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
428 && channel < MAX_BLACKFIN_DMA_CHANNEL));
429
430 dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
431 dma_ch[channel].regs->curr_x_count = 0;
432 dma_ch[channel].regs->curr_y_count = 0;
433
434 dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */
435 SSYNC();
436 pr_debug("enable_dma() : END \n");
437 return;
438}
439EXPORT_SYMBOL(enable_dma);
440
441/*------------------------------------------------------------------------------
442* Set the Start Address register for the specific DMA channel
443* This function can be used for register based DMA,
444* to setup the start address
445* addr: Starting address of the DMA Data to be transferred.
446*-----------------------------------------------------------------------------*/
447void set_dma_start_addr(unsigned int channel, unsigned long addr)
448{
449 pr_debug("set_dma_start_addr() : BEGIN \n");
450
451 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
452 && channel < MAX_BLACKFIN_DMA_CHANNEL));
453
454 dma_ch[channel].regs->start_addr = addr;
455 SSYNC();
456 pr_debug("set_dma_start_addr() : END\n");
457}
458EXPORT_SYMBOL(set_dma_start_addr);
459
460void set_dma_next_desc_addr(unsigned int channel, unsigned long addr)
461{
462 pr_debug("set_dma_next_desc_addr() : BEGIN \n");
463
464 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
465 && channel < MAX_BLACKFIN_DMA_CHANNEL));
466
467 dma_ch[channel].regs->next_desc_ptr = addr;
468 SSYNC();
469 pr_debug("set_dma_start_addr() : END\n");
470}
471EXPORT_SYMBOL(set_dma_next_desc_addr);
472
473void set_dma_x_count(unsigned int channel, unsigned short x_count)
474{
475 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
476 && channel < MAX_BLACKFIN_DMA_CHANNEL));
477
478 dma_ch[channel].regs->x_count = x_count;
479 SSYNC();
480}
481EXPORT_SYMBOL(set_dma_x_count);
482
483void set_dma_y_count(unsigned int channel, unsigned short y_count)
484{
485 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
486 && channel < MAX_BLACKFIN_DMA_CHANNEL));
487
488 dma_ch[channel].regs->y_count = y_count;
489 SSYNC();
490}
491EXPORT_SYMBOL(set_dma_y_count);
492
493void set_dma_x_modify(unsigned int channel, short x_modify)
494{
495 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
496 && channel < MAX_BLACKFIN_DMA_CHANNEL));
497
498 dma_ch[channel].regs->x_modify = x_modify;
499 SSYNC();
500}
501EXPORT_SYMBOL(set_dma_x_modify);
502
503void set_dma_y_modify(unsigned int channel, short y_modify)
504{
505 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
506 && channel < MAX_BLACKFIN_DMA_CHANNEL));
507
508 dma_ch[channel].regs->y_modify = y_modify;
509 SSYNC();
510}
511EXPORT_SYMBOL(set_dma_y_modify);
512
513void set_dma_config(unsigned int channel, unsigned short config)
514{
515 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
516 && channel < MAX_BLACKFIN_DMA_CHANNEL));
517
518 dma_ch[channel].regs->cfg = config;
519 SSYNC();
520}
521EXPORT_SYMBOL(set_dma_config);
522
523unsigned short
524set_bfin_dma_config(char direction, char flow_mode,
525 char intr_mode, char dma_mode, char width)
526{
527 unsigned short config;
528
529 config =
530 ((direction << 1) | (width << 2) | (dma_mode << 4) |
531 (intr_mode << 6) | (flow_mode << 12) | RESTART);
532 return config;
533}
534EXPORT_SYMBOL(set_bfin_dma_config);
535
536void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
537{
538 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
539 && channel < MAX_BLACKFIN_DMA_CHANNEL));
540
541 dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8);
542
543 dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg;
544
545 SSYNC();
546}
547EXPORT_SYMBOL(set_dma_sg);
548
549/*------------------------------------------------------------------------------
550 * Get the DMA status of a specific DMA channel from the system.
551 *-----------------------------------------------------------------------------*/
552unsigned short get_dma_curr_irqstat(unsigned int channel)
553{
554 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
555 && channel < MAX_BLACKFIN_DMA_CHANNEL));
556
557 return dma_ch[channel].regs->irq_status;
558}
559EXPORT_SYMBOL(get_dma_curr_irqstat);
560
561/*------------------------------------------------------------------------------
562 * Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt.
563 *-----------------------------------------------------------------------------*/
564void clear_dma_irqstat(unsigned int channel)
565{
566 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
567 && channel < MAX_BLACKFIN_DMA_CHANNEL));
568 dma_ch[channel].regs->irq_status |= 3;
569}
570EXPORT_SYMBOL(clear_dma_irqstat);
571
572/*------------------------------------------------------------------------------
573 * Get current DMA xcount of a specific DMA channel from the system.
574 *-----------------------------------------------------------------------------*/
575unsigned short get_dma_curr_xcount(unsigned int channel)
576{
577 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
578 && channel < MAX_BLACKFIN_DMA_CHANNEL));
579
580 return dma_ch[channel].regs->curr_x_count;
581}
582EXPORT_SYMBOL(get_dma_curr_xcount);
583
584/*------------------------------------------------------------------------------
585 * Get current DMA ycount of a specific DMA channel from the system.
586 *-----------------------------------------------------------------------------*/
587unsigned short get_dma_curr_ycount(unsigned int channel)
588{
589 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
590 && channel < MAX_BLACKFIN_DMA_CHANNEL));
591
592 return dma_ch[channel].regs->curr_y_count;
593}
594EXPORT_SYMBOL(get_dma_curr_ycount);
595
596void *dma_memcpy(void *dest, const void *src, size_t size)
597{
598 int direction; /* 1 - address decrease, 0 - address increase */
599 int flag_align; /* 1 - address aligned, 0 - address unaligned */
600 int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */
601
602 if (size <= 0)
603 return NULL;
604
605 if ((unsigned long)src < memory_end)
606 blackfin_dcache_flush_range((unsigned int)src,
607 (unsigned int)(src + size));
608
609 bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
610
611 if ((unsigned long)src < (unsigned long)dest)
612 direction = 1;
613 else
614 direction = 0;
615
616 if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0)
617 && ((size % 2) == 0))
618 flag_align = 1;
619 else
620 flag_align = 0;
621
622 if (size > 0x10000) /* size > 64K */
623 flag_2D = 1;
624 else
625 flag_2D = 0;
626
627 /* Setup destination and source start address */
628 if (direction) {
629 if (flag_align) {
630 bfin_write_MDMA_D0_START_ADDR(dest + size - 2);
631 bfin_write_MDMA_S0_START_ADDR(src + size - 2);
632 } else {
633 bfin_write_MDMA_D0_START_ADDR(dest + size - 1);
634 bfin_write_MDMA_S0_START_ADDR(src + size - 1);
635 }
636 } else {
637 bfin_write_MDMA_D0_START_ADDR(dest);
638 bfin_write_MDMA_S0_START_ADDR(src);
639 }
640
641 /* Setup destination and source xcount */
642 if (flag_2D) {
643 if (flag_align) {
644 bfin_write_MDMA_D0_X_COUNT(1024 / 2);
645 bfin_write_MDMA_S0_X_COUNT(1024 / 2);
646 } else {
647 bfin_write_MDMA_D0_X_COUNT(1024);
648 bfin_write_MDMA_S0_X_COUNT(1024);
649 }
650 bfin_write_MDMA_D0_Y_COUNT(size >> 10);
651 bfin_write_MDMA_S0_Y_COUNT(size >> 10);
652 } else {
653 if (flag_align) {
654 bfin_write_MDMA_D0_X_COUNT(size / 2);
655 bfin_write_MDMA_S0_X_COUNT(size / 2);
656 } else {
657 bfin_write_MDMA_D0_X_COUNT(size);
658 bfin_write_MDMA_S0_X_COUNT(size);
659 }
660 }
661
662 /* Setup destination and source xmodify and ymodify */
663 if (direction) {
664 if (flag_align) {
665 bfin_write_MDMA_D0_X_MODIFY(-2);
666 bfin_write_MDMA_S0_X_MODIFY(-2);
667 if (flag_2D) {
668 bfin_write_MDMA_D0_Y_MODIFY(-2);
669 bfin_write_MDMA_S0_Y_MODIFY(-2);
670 }
671 } else {
672 bfin_write_MDMA_D0_X_MODIFY(-1);
673 bfin_write_MDMA_S0_X_MODIFY(-1);
674 if (flag_2D) {
675 bfin_write_MDMA_D0_Y_MODIFY(-1);
676 bfin_write_MDMA_S0_Y_MODIFY(-1);
677 }
678 }
679 } else {
680 if (flag_align) {
681 bfin_write_MDMA_D0_X_MODIFY(2);
682 bfin_write_MDMA_S0_X_MODIFY(2);
683 if (flag_2D) {
684 bfin_write_MDMA_D0_Y_MODIFY(2);
685 bfin_write_MDMA_S0_Y_MODIFY(2);
686 }
687 } else {
688 bfin_write_MDMA_D0_X_MODIFY(1);
689 bfin_write_MDMA_S0_X_MODIFY(1);
690 if (flag_2D) {
691 bfin_write_MDMA_D0_Y_MODIFY(1);
692 bfin_write_MDMA_S0_Y_MODIFY(1);
693 }
694 }
695 }
696
697 /* Enable source DMA */
698 if (flag_2D) {
699 if (flag_align) {
700 bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16);
701 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16);
702 } else {
703 bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D);
704 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D);
705 }
706 } else {
707 if (flag_align) {
708 bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
709 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
710 } else {
711 bfin_write_MDMA_S0_CONFIG(DMAEN);
712 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN);
713 }
714 }
715
716 while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
717 ;
718
719 bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() |
720 (DMA_DONE | DMA_ERR));
721
722 bfin_write_MDMA_S0_CONFIG(0);
723 bfin_write_MDMA_D0_CONFIG(0);
724
725 if ((unsigned long)dest < memory_end)
726 blackfin_dcache_invalidate_range((unsigned int)dest,
727 (unsigned int)(dest + size));
728
729 return dest;
730}
731EXPORT_SYMBOL(dma_memcpy);
732
733void *safe_dma_memcpy(void *dest, const void *src, size_t size)
734{
735 int flags = 0;
736 void *addr;
737 local_irq_save(flags);
738 addr = dma_memcpy(dest, src, size);
739 local_irq_restore(flags);
740 return addr;
741}
742EXPORT_SYMBOL(safe_dma_memcpy);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
new file mode 100644
index 000000000000..e9f24a9a46ba
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -0,0 +1,637 @@
1/*
2 * File: arch/blackfin/kernel/bfin_gpio.c
3 * Based on:
4 * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
5 *
6 * Created:
7 * Description: GPIO Abstraction Layer
8 *
9 * Modified:
10 * Copyright 2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30/*
31* Number BF537/6/4 BF561 BF533/2/1
32*
33* GPIO_0 PF0 PF0 PF0
34* GPIO_1 PF1 PF1 PF1
35* GPIO_2 PF2 PF2 PF2
36* GPIO_3 PF3 PF3 PF3
37* GPIO_4 PF4 PF4 PF4
38* GPIO_5 PF5 PF5 PF5
39* GPIO_6 PF6 PF6 PF6
40* GPIO_7 PF7 PF7 PF7
41* GPIO_8 PF8 PF8 PF8
42* GPIO_9 PF9 PF9 PF9
43* GPIO_10 PF10 PF10 PF10
44* GPIO_11 PF11 PF11 PF11
45* GPIO_12 PF12 PF12 PF12
46* GPIO_13 PF13 PF13 PF13
47* GPIO_14 PF14 PF14 PF14
48* GPIO_15 PF15 PF15 PF15
49* GPIO_16 PG0 PF16
50* GPIO_17 PG1 PF17
51* GPIO_18 PG2 PF18
52* GPIO_19 PG3 PF19
53* GPIO_20 PG4 PF20
54* GPIO_21 PG5 PF21
55* GPIO_22 PG6 PF22
56* GPIO_23 PG7 PF23
57* GPIO_24 PG8 PF24
58* GPIO_25 PG9 PF25
59* GPIO_26 PG10 PF26
60* GPIO_27 PG11 PF27
61* GPIO_28 PG12 PF28
62* GPIO_29 PG13 PF29
63* GPIO_30 PG14 PF30
64* GPIO_31 PG15 PF31
65* GPIO_32 PH0 PF32
66* GPIO_33 PH1 PF33
67* GPIO_34 PH2 PF34
68* GPIO_35 PH3 PF35
69* GPIO_36 PH4 PF36
70* GPIO_37 PH5 PF37
71* GPIO_38 PH6 PF38
72* GPIO_39 PH7 PF39
73* GPIO_40 PH8 PF40
74* GPIO_41 PH9 PF41
75* GPIO_42 PH10 PF42
76* GPIO_43 PH11 PF43
77* GPIO_44 PH12 PF44
78* GPIO_45 PH13 PF45
79* GPIO_46 PH14 PF46
80* GPIO_47 PH15 PF47
81*/
82
83#include <linux/module.h>
84#include <linux/err.h>
85#include <asm/blackfin.h>
86#include <asm/gpio.h>
87#include <linux/irq.h>
88
89#ifdef BF533_FAMILY
90static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
91 (struct gpio_port_t *) FIO_FLAG_D,
92};
93#endif
94
95#ifdef BF537_FAMILY
96static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
97 (struct gpio_port_t *) PORTFIO,
98 (struct gpio_port_t *) PORTGIO,
99 (struct gpio_port_t *) PORTHIO,
100};
101
102static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
103 (unsigned short *) PORTF_FER,
104 (unsigned short *) PORTG_FER,
105 (unsigned short *) PORTH_FER,
106};
107
108#endif
109
110#ifdef BF561_FAMILY
111static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
112 (struct gpio_port_t *) FIO0_FLAG_D,
113 (struct gpio_port_t *) FIO1_FLAG_D,
114 (struct gpio_port_t *) FIO2_FLAG_D,
115};
116#endif
117
118static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
119
120#ifdef CONFIG_PM
121static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
122static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
123static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
124
125#ifdef BF533_FAMILY
126static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};
127#endif
128
129#ifdef BF537_FAMILY
130static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
131#endif
132
133#ifdef BF561_FAMILY
134static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
135#endif
136
137#endif /* CONFIG_PM */
138
139inline int check_gpio(unsigned short gpio)
140{
141 if (gpio > MAX_BLACKFIN_GPIOS)
142 return -EINVAL;
143 return 0;
144}
145
146#ifdef BF537_FAMILY
147void port_setup(unsigned short gpio, unsigned short usage)
148{
149 if (usage == GPIO_USAGE) {
150 if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
151 printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
152 "usage and GPIO %d detected!\n", gpio);
153 *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
154 } else
155 *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
156 SSYNC();
157}
158#else
159# define port_setup(...) do { } while (0)
160#endif
161
162
163void default_gpio(unsigned short gpio)
164{
165 unsigned short bank,bitmask;
166
167 bank = gpio_bank(gpio);
168 bitmask = gpio_bit(gpio);
169
170 gpio_bankb[bank]->maska_clear = bitmask;
171 gpio_bankb[bank]->maskb_clear = bitmask;
172 SSYNC();
173 gpio_bankb[bank]->inen &= ~bitmask;
174 gpio_bankb[bank]->dir &= ~bitmask;
175 gpio_bankb[bank]->polar &= ~bitmask;
176 gpio_bankb[bank]->both &= ~bitmask;
177 gpio_bankb[bank]->edge &= ~bitmask;
178}
179
180
181int __init bfin_gpio_init(void)
182{
183 int i;
184
185 printk(KERN_INFO "Blackfin GPIO Controller\n");
186
187 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
188 reserved_map[gpio_bank(i)] = 0;
189
190#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
191# if defined(CONFIG_BFIN_MAC_RMII)
192 reserved_map[PORT_H] = 0xC373;
193# else
194 reserved_map[PORT_H] = 0xFFFF;
195# endif
196#endif
197
198 return 0;
199}
200
201arch_initcall(bfin_gpio_init);
202
203
204/***********************************************************
205*
206* FUNCTIONS: Blackfin General Purpose Ports Access Functions
207*
208* INPUTS/OUTPUTS:
209* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
210*
211*
212* DESCRIPTION: These functions abstract direct register access
213* to Blackfin processor General Purpose
214* Ports Regsiters
215*
216* CAUTION: These functions do not belong to the GPIO Driver API
217*************************************************************
218* MODIFICATION HISTORY :
219**************************************************************/
220
221/* Set a specific bit */
222
223#define SET_GPIO(name) \
224void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
225{ \
226 unsigned long flags; \
227 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
228 local_irq_save(flags); \
229 if (arg) \
230 gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
231 else \
232 gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
233 local_irq_restore(flags); \
234} \
235EXPORT_SYMBOL(set_gpio_ ## name);
236
237SET_GPIO(dir)
238SET_GPIO(inen)
239SET_GPIO(polar)
240SET_GPIO(edge)
241SET_GPIO(both)
242
243
244#define SET_GPIO_SC(name) \
245void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
246{ \
247 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
248 if (arg) \
249 gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
250 else \
251 gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
252} \
253EXPORT_SYMBOL(set_gpio_ ## name);
254
255SET_GPIO_SC(maska)
256SET_GPIO_SC(maskb)
257
258#if defined(ANOMALY_05000311)
259void set_gpio_data(unsigned short gpio, unsigned short arg)
260{
261 unsigned long flags;
262 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
263 local_irq_save(flags);
264 if (arg)
265 gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
266 else
267 gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
268 bfin_read_CHIPID();
269 local_irq_restore(flags);
270}
271EXPORT_SYMBOL(set_gpio_data);
272#else
273SET_GPIO_SC(data)
274#endif
275
276
277#if defined(ANOMALY_05000311)
278void set_gpio_toggle(unsigned short gpio)
279{
280 unsigned long flags;
281 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
282 local_irq_save(flags);
283 gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
284 bfin_read_CHIPID();
285 local_irq_restore(flags);
286}
287#else
288void set_gpio_toggle(unsigned short gpio)
289{
290 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
291 gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
292}
293#endif
294EXPORT_SYMBOL(set_gpio_toggle);
295
296
297/*Set current PORT date (16-bit word)*/
298
299#define SET_GPIO_P(name) \
300void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
301{ \
302 gpio_bankb[gpio_bank(gpio)]->name = arg; \
303} \
304EXPORT_SYMBOL(set_gpiop_ ## name);
305
306SET_GPIO_P(dir)
307SET_GPIO_P(inen)
308SET_GPIO_P(polar)
309SET_GPIO_P(edge)
310SET_GPIO_P(both)
311SET_GPIO_P(maska)
312SET_GPIO_P(maskb)
313
314
315#if defined(ANOMALY_05000311)
316void set_gpiop_data(unsigned short gpio, unsigned short arg)
317{
318 unsigned long flags;
319 local_irq_save(flags);
320 gpio_bankb[gpio_bank(gpio)]->data = arg;
321 bfin_read_CHIPID();
322 local_irq_restore(flags);
323}
324EXPORT_SYMBOL(set_gpiop_data);
325#else
326SET_GPIO_P(data)
327#endif
328
329
330
331/* Get a specific bit */
332
333#define GET_GPIO(name) \
334unsigned short get_gpio_ ## name(unsigned short gpio) \
335{ \
336 return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
337} \
338EXPORT_SYMBOL(get_gpio_ ## name);
339
340GET_GPIO(dir)
341GET_GPIO(inen)
342GET_GPIO(polar)
343GET_GPIO(edge)
344GET_GPIO(both)
345GET_GPIO(maska)
346GET_GPIO(maskb)
347
348
349#if defined(ANOMALY_05000311)
350unsigned short get_gpio_data(unsigned short gpio)
351{
352 unsigned long flags;
353 unsigned short ret;
354 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
355 local_irq_save(flags);
356 ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
357 bfin_read_CHIPID();
358 local_irq_restore(flags);
359 return ret;
360}
361EXPORT_SYMBOL(get_gpio_data);
362#else
363GET_GPIO(data)
364#endif
365
366/*Get current PORT date (16-bit word)*/
367
368#define GET_GPIO_P(name) \
369unsigned short get_gpiop_ ## name(unsigned short gpio) \
370{ \
371 return (gpio_bankb[gpio_bank(gpio)]->name);\
372} \
373EXPORT_SYMBOL(get_gpiop_ ## name);
374
375GET_GPIO_P(dir)
376GET_GPIO_P(inen)
377GET_GPIO_P(polar)
378GET_GPIO_P(edge)
379GET_GPIO_P(both)
380GET_GPIO_P(maska)
381GET_GPIO_P(maskb)
382
383#if defined(ANOMALY_05000311)
384unsigned short get_gpiop_data(unsigned short gpio)
385{
386 unsigned long flags;
387 unsigned short ret;
388 local_irq_save(flags);
389 ret = gpio_bankb[gpio_bank(gpio)]->data;
390 bfin_read_CHIPID();
391 local_irq_restore(flags);
392 return ret;
393}
394EXPORT_SYMBOL(get_gpiop_data);
395#else
396GET_GPIO_P(data)
397#endif
398
399#ifdef CONFIG_PM
400/***********************************************************
401*
402* FUNCTIONS: Blackfin PM Setup API
403*
404* INPUTS/OUTPUTS:
405* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
406* type -
407* PM_WAKE_RISING
408* PM_WAKE_FALLING
409* PM_WAKE_HIGH
410* PM_WAKE_LOW
411* PM_WAKE_BOTH_EDGES
412*
413* DESCRIPTION: Blackfin PM Driver API
414*
415* CAUTION:
416*************************************************************
417* MODIFICATION HISTORY :
418**************************************************************/
419int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
420{
421 unsigned long flags;
422
423 if ((check_gpio(gpio) < 0) || !type)
424 return -EINVAL;
425
426 local_irq_save(flags);
427
428 wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
429 wakeup_flags_map[gpio] = type;
430 local_irq_restore(flags);
431
432 return 0;
433}
434EXPORT_SYMBOL(gpio_pm_wakeup_request);
435
436void gpio_pm_wakeup_free(unsigned short gpio)
437{
438 unsigned long flags;
439
440 if (check_gpio(gpio) < 0)
441 return;
442
443 local_irq_save(flags);
444
445 wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
446
447 local_irq_restore(flags);
448}
449EXPORT_SYMBOL(gpio_pm_wakeup_free);
450
451static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
452{
453 port_setup(gpio, GPIO_USAGE);
454 set_gpio_dir(gpio, 0);
455 set_gpio_inen(gpio, 1);
456
457 if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
458 set_gpio_edge(gpio, 1);
459 else
460 set_gpio_edge(gpio, 0);
461
462 if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
463 set_gpio_both(gpio, 1);
464 else
465 set_gpio_both(gpio, 0);
466
467 if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
468 set_gpio_polar(gpio, 1);
469 else
470 set_gpio_polar(gpio, 0);
471
472 SSYNC();
473
474 return 0;
475}
476
477u32 gpio_pm_setup(void)
478{
479 u32 sic_iwr = 0;
480 u16 bank, mask, i, gpio;
481
482 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
483 mask = wakeup_map[gpio_bank(i)];
484 bank = gpio_bank(i);
485
486 gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb;
487 gpio_bankb[bank]->maskb = 0;
488
489 if (mask) {
490#ifdef BF537_FAMILY
491 gpio_bank_saved[bank].fer = *port_fer[bank];
492#endif
493 gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
494 gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
495 gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
496 gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
497 gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
498
499 gpio = i;
500
501 while (mask) {
502 if (mask & 1) {
503 bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]);
504 set_gpio_data(gpio, 0); /*Clear*/
505 }
506 gpio++;
507 mask >>= 1;
508 }
509
510 sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
511 gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
512 }
513 }
514
515 if (sic_iwr)
516 return sic_iwr;
517 else
518 return IWR_ENABLE_ALL;
519}
520
521
522void gpio_pm_restore(void)
523{
524 u16 bank, mask, i;
525
526 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
527 mask = wakeup_map[gpio_bank(i)];
528 bank = gpio_bank(i);
529
530 if (mask) {
531#ifdef BF537_FAMILY
532 *port_fer[bank] = gpio_bank_saved[bank].fer;
533#endif
534 gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
535 gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir;
536 gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
537 gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
538 gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
539 }
540
541 gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
542 }
543}
544
545#endif
546
547/***********************************************************
548*
549* FUNCTIONS: Blackfin GPIO Driver
550*
551* INPUTS/OUTPUTS:
552* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
553*
554*
555* DESCRIPTION: Blackfin GPIO Driver API
556*
557* CAUTION:
558*************************************************************
559* MODIFICATION HISTORY :
560**************************************************************/
561
562int gpio_request(unsigned short gpio, const char *label)
563{
564 unsigned long flags;
565
566 if (check_gpio(gpio) < 0)
567 return -EINVAL;
568
569 local_irq_save(flags);
570
571 if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
572 printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
573 dump_stack();
574 local_irq_restore(flags);
575 return -EBUSY;
576 }
577 reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
578
579 local_irq_restore(flags);
580
581 port_setup(gpio, GPIO_USAGE);
582
583 return 0;
584}
585EXPORT_SYMBOL(gpio_request);
586
587
588void gpio_free(unsigned short gpio)
589{
590 unsigned long flags;
591
592 if (check_gpio(gpio) < 0)
593 return;
594
595 local_irq_save(flags);
596
597 if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
598 printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
599 dump_stack();
600 local_irq_restore(flags);
601 return;
602 }
603
604 default_gpio(gpio);
605
606 reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
607
608 local_irq_restore(flags);
609}
610EXPORT_SYMBOL(gpio_free);
611
612
613void gpio_direction_input(unsigned short gpio)
614{
615 unsigned long flags;
616
617 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
618
619 local_irq_save(flags);
620 gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
621 gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
622 local_irq_restore(flags);
623}
624EXPORT_SYMBOL(gpio_direction_input);
625
626void gpio_direction_output(unsigned short gpio)
627{
628 unsigned long flags;
629
630 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
631
632 local_irq_save(flags);
633 gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
634 gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
635 local_irq_restore(flags);
636}
637EXPORT_SYMBOL(gpio_direction_output);
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
new file mode 100644
index 000000000000..f64ecb638fab
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -0,0 +1,119 @@
1/*
2 * File: arch/blackfin/kernel/bfin_ksyms.c
3 * Based on: none - original work
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/module.h>
31#include <asm/irq.h>
32#include <asm/checksum.h>
33#include <asm/cacheflush.h>
34#include <asm/uaccess.h>
35
36/* platform dependent support */
37
38EXPORT_SYMBOL(__ioremap);
39EXPORT_SYMBOL(strcmp);
40EXPORT_SYMBOL(strncmp);
41EXPORT_SYMBOL(dump_thread);
42
43EXPORT_SYMBOL(ip_fast_csum);
44
45EXPORT_SYMBOL(kernel_thread);
46
47EXPORT_SYMBOL(__up);
48EXPORT_SYMBOL(__down);
49EXPORT_SYMBOL(__down_trylock);
50EXPORT_SYMBOL(__down_interruptible);
51
52EXPORT_SYMBOL(is_in_rom);
53
54/* Networking helper routines. */
55EXPORT_SYMBOL(csum_partial_copy);
56
57/* The following are special because they're not called
58 * explicitly (the C compiler generates them). Fortunately,
59 * their interface isn't gonna change any time soon now, so
60 * it's OK to leave it out of version control.
61 */
62EXPORT_SYMBOL(memcpy);
63EXPORT_SYMBOL(memset);
64EXPORT_SYMBOL(memcmp);
65EXPORT_SYMBOL(memmove);
66EXPORT_SYMBOL(memchr);
67EXPORT_SYMBOL(get_wchan);
68
69/*
70 * libgcc functions - functions that are used internally by the
71 * compiler... (prototypes are not correct though, but that
72 * doesn't really matter since they're not versioned).
73 */
74extern void __ashldi3(void);
75extern void __ashrdi3(void);
76extern void __smulsi3_highpart(void);
77extern void __umulsi3_highpart(void);
78extern void __divsi3(void);
79extern void __lshrdi3(void);
80extern void __modsi3(void);
81extern void __muldi3(void);
82extern void __udivsi3(void);
83extern void __umodsi3(void);
84
85/* gcc lib functions */
86EXPORT_SYMBOL(__ashldi3);
87EXPORT_SYMBOL(__ashrdi3);
88EXPORT_SYMBOL(__umulsi3_highpart);
89EXPORT_SYMBOL(__smulsi3_highpart);
90EXPORT_SYMBOL(__divsi3);
91EXPORT_SYMBOL(__lshrdi3);
92EXPORT_SYMBOL(__modsi3);
93EXPORT_SYMBOL(__muldi3);
94EXPORT_SYMBOL(__udivsi3);
95EXPORT_SYMBOL(__umodsi3);
96
97EXPORT_SYMBOL(outsb);
98EXPORT_SYMBOL(insb);
99EXPORT_SYMBOL(outsw);
100EXPORT_SYMBOL(insw);
101EXPORT_SYMBOL(outsl);
102EXPORT_SYMBOL(insl);
103EXPORT_SYMBOL(irq_flags);
104EXPORT_SYMBOL(iounmap);
105EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
106EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
107EXPORT_SYMBOL(blackfin_icache_flush_range);
108EXPORT_SYMBOL(blackfin_dcache_flush_range);
109EXPORT_SYMBOL(blackfin_dflush_page);
110
111EXPORT_SYMBOL(csum_partial);
112EXPORT_SYMBOL(__init_begin);
113EXPORT_SYMBOL(__init_end);
114EXPORT_SYMBOL(_ebss_l1);
115EXPORT_SYMBOL(_stext_l1);
116EXPORT_SYMBOL(_etext_l1);
117EXPORT_SYMBOL(_sdata_l1);
118EXPORT_SYMBOL(_ebss_b_l1);
119EXPORT_SYMBOL(_sdata_b_l1);
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
new file mode 100644
index 000000000000..539eb24e062f
--- /dev/null
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -0,0 +1,183 @@
1/*
2 * File: arch/blackfin/kernel/dma-mapping.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Dynamic DMA mapping support.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/types.h>
31#include <linux/mm.h>
32#include <linux/string.h>
33#include <linux/bootmem.h>
34#include <linux/spinlock.h>
35#include <linux/device.h>
36#include <linux/dma-mapping.h>
37#include <asm/cacheflush.h>
38#include <asm/io.h>
39#include <asm/bfin-global.h>
40
41static spinlock_t dma_page_lock;
42static unsigned int *dma_page;
43static unsigned int dma_pages;
44static unsigned long dma_base;
45static unsigned long dma_size;
46static unsigned int dma_initialized;
47
48void dma_alloc_init(unsigned long start, unsigned long end)
49{
50 spin_lock_init(&dma_page_lock);
51 dma_initialized = 0;
52
53 dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
54 memset(dma_page, 0, PAGE_SIZE);
55 dma_base = PAGE_ALIGN(start);
56 dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
57 dma_pages = dma_size >> PAGE_SHIFT;
58 memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
59 dma_initialized = 1;
60
61 printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
62 dma_page, dma_pages, dma_base);
63}
64
65static inline unsigned int get_pages(size_t size)
66{
67 return ((size - 1) >> PAGE_SHIFT) + 1;
68}
69
70static unsigned long __alloc_dma_pages(unsigned int pages)
71{
72 unsigned long ret = 0, flags;
73 int i, count = 0;
74
75 if (dma_initialized == 0)
76 dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
77
78 spin_lock_irqsave(&dma_page_lock, flags);
79
80 for (i = 0; i < dma_pages;) {
81 if (dma_page[i++] == 0) {
82 if (++count == pages) {
83 while (count--)
84 dma_page[--i] = 1;
85 ret = dma_base + (i << PAGE_SHIFT);
86 break;
87 }
88 } else
89 count = 0;
90 }
91 spin_unlock_irqrestore(&dma_page_lock, flags);
92 return ret;
93}
94
95static void __free_dma_pages(unsigned long addr, unsigned int pages)
96{
97 unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
98 unsigned long flags;
99 int i;
100
101 if ((page + pages) > dma_pages) {
102 printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
103 BUG();
104 }
105
106 spin_lock_irqsave(&dma_page_lock, flags);
107 for (i = page; i < page + pages; i++) {
108 dma_page[i] = 0;
109 }
110 spin_unlock_irqrestore(&dma_page_lock, flags);
111}
112
113void *dma_alloc_coherent(struct device *dev, size_t size,
114 dma_addr_t * dma_handle, gfp_t gfp)
115{
116 void *ret;
117
118 ret = (void *)__alloc_dma_pages(get_pages(size));
119
120 if (ret) {
121 memset(ret, 0, size);
122 *dma_handle = virt_to_phys(ret);
123 }
124
125 return ret;
126}
127EXPORT_SYMBOL(dma_alloc_coherent);
128
129void
130dma_free_coherent(struct device *dev, size_t size, void *vaddr,
131 dma_addr_t dma_handle)
132{
133 __free_dma_pages((unsigned long)vaddr, get_pages(size));
134}
135EXPORT_SYMBOL(dma_free_coherent);
136
137/*
138 * Dummy functions defined for some existing drivers
139 */
140
141dma_addr_t
142dma_map_single(struct device *dev, void *ptr, size_t size,
143 enum dma_data_direction direction)
144{
145 BUG_ON(direction == DMA_NONE);
146
147 invalidate_dcache_range((unsigned long)ptr,
148 (unsigned long)ptr + size);
149
150 return (dma_addr_t) ptr;
151}
152EXPORT_SYMBOL(dma_map_single);
153
154int
155dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
156 enum dma_data_direction direction)
157{
158 int i;
159
160 BUG_ON(direction == DMA_NONE);
161
162 for (i = 0; i < nents; i++)
163 invalidate_dcache_range(sg_dma_address(&sg[i]),
164 sg_dma_address(&sg[i]) +
165 sg_dma_len(&sg[i]));
166
167 return nents;
168}
169EXPORT_SYMBOL(dma_map_sg);
170
171void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
172 enum dma_data_direction direction)
173{
174 BUG_ON(direction == DMA_NONE);
175}
176EXPORT_SYMBOL(dma_unmap_single);
177
178void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
179 int nhwentries, enum dma_data_direction direction)
180{
181 BUG_ON(direction == DMA_NONE);
182}
183EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/blackfin/kernel/dualcore_test.c b/arch/blackfin/kernel/dualcore_test.c
new file mode 100644
index 000000000000..8b89c99f9dfa
--- /dev/null
+++ b/arch/blackfin/kernel/dualcore_test.c
@@ -0,0 +1,49 @@
1/*
2 * File: arch/blackfin/kernel/dualcore_test.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Small test code for CoreB on a BF561
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/init.h>
31#include <linux/module.h>
32
33static int *testarg = (int*)0xfeb00000;
34
35static int test_init(void)
36{
37 *testarg = 1;
38 printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
39 *testarg, testarg);
40 return 0;
41}
42
43static void test_exit(void)
44{
45 printk("Dual core test module removed: testarg = [%d]\n", *testarg);
46}
47
48module_init(test_init);
49module_exit(test_exit);
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
new file mode 100644
index 000000000000..5880b270bd50
--- /dev/null
+++ b/arch/blackfin/kernel/entry.S
@@ -0,0 +1,94 @@
1/*
2 * File: arch/blackfin/kernel/entry.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/linkage.h>
31#include <asm/thread_info.h>
32#include <asm/errno.h>
33#include <asm/asm-offsets.h>
34
35#include <asm/mach-common/context.S>
36
37#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
38.section .l1.text
39#else
40.text
41#endif
42
43ENTRY(_ret_from_fork)
44 SP += -12;
45 call _schedule_tail;
46 SP += 12;
47 r0 = [sp + PT_IPEND];
48 cc = bittst(r0,1);
49 if cc jump .Lin_kernel;
50 RESTORE_CONTEXT
51 rti;
52.Lin_kernel:
53 bitclr(r0,1);
54 [sp + PT_IPEND] = r0;
55 /* do a 'fake' RTI by jumping to [RETI]
56 * to avoid clearing supervisor mode in child
57 */
58 RESTORE_ALL_SYS
59 p0 = reti;
60 jump (p0);
61
62ENTRY(_sys_fork)
63 r0 = -EINVAL;
64 rts;
65
66ENTRY(_sys_vfork)
67 r0 = sp;
68 r0 += 24;
69 [--sp] = rets;
70 SP += -12;
71 call _bfin_vfork;
72 SP += 12;
73 rets = [sp++];
74 rts;
75
76ENTRY(_sys_clone)
77 r0 = sp;
78 r0 += 24;
79 [--sp] = rets;
80 SP += -12;
81 call _bfin_clone;
82 SP += 12;
83 rets = [sp++];
84 rts;
85
86ENTRY(_sys_rt_sigreturn)
87 r0 = sp;
88 r0 += 24;
89 [--sp] = rets;
90 SP += -12;
91 call _do_rt_sigreturn;
92 SP += 12;
93 rets = [sp++];
94 rts;
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
new file mode 100644
index 000000000000..a92587b628b5
--- /dev/null
+++ b/arch/blackfin/kernel/flat.c
@@ -0,0 +1,101 @@
1/*
2 * arch/blackfin/kernel/flat.c
3 *
4 * Copyright (C) 2007 Analog Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/module.h>
22#include <linux/sched.h>
23#include <linux/flat.h>
24
25#define FLAT_BFIN_RELOC_TYPE_16_BIT 0
26#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
27#define FLAT_BFIN_RELOC_TYPE_32_BIT 2
28
29unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
30 unsigned long relval,
31 unsigned long flags,
32 unsigned long *persistent)
33{
34 unsigned short *usptr = (unsigned short *)ptr;
35 int type = (relval >> 26) & 7;
36 unsigned long val;
37
38 switch (type) {
39 case FLAT_BFIN_RELOC_TYPE_16_BIT:
40 case FLAT_BFIN_RELOC_TYPE_16H_BIT:
41 usptr = (unsigned short *)ptr;
42 pr_debug("*usptr = %x", get_unaligned(usptr));
43 val = get_unaligned(usptr);
44 val += *persistent;
45 break;
46
47 case FLAT_BFIN_RELOC_TYPE_32_BIT:
48 pr_debug("*ptr = %lx", get_unaligned(ptr));
49 val = get_unaligned(ptr);
50 break;
51
52 default:
53 pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
54 type);
55
56 return 0;
57 }
58
59 /*
60 * Stack-relative relocs contain the offset into the stack, we
61 * have to add the stack's start address here and return 1 from
62 * flat_addr_absolute to prevent the normal address calculations
63 */
64 if (relval & (1 << 29))
65 return val + current->mm->context.end_brk;
66
67 if ((flags & FLAT_FLAG_GOTPIC) == 0)
68 val = htonl(val);
69 return val;
70}
71EXPORT_SYMBOL(bfin_get_addr_from_rp);
72
73/*
74 * Insert the address ADDR into the symbol reference at RP;
75 * RELVAL is the raw relocation-table entry from which RP is derived
76 */
77void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
78 unsigned long relval)
79{
80 unsigned short *usptr = (unsigned short *)ptr;
81 int type = (relval >> 26) & 7;
82
83 switch (type) {
84 case FLAT_BFIN_RELOC_TYPE_16_BIT:
85 put_unaligned(addr, usptr);
86 pr_debug("new value %x at %p", get_unaligned(usptr),
87 usptr);
88 break;
89
90 case FLAT_BFIN_RELOC_TYPE_16H_BIT:
91 put_unaligned(addr >> 16, usptr);
92 pr_debug("new value %x", get_unaligned(usptr));
93 break;
94
95 case FLAT_BFIN_RELOC_TYPE_32_BIT:
96 put_unaligned(addr, ptr);
97 pr_debug("new ptr =%lx", get_unaligned(ptr));
98 break;
99 }
100}
101EXPORT_SYMBOL(bfin_put_addr_at_rp);
diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c
new file mode 100644
index 000000000000..b45188f8512e
--- /dev/null
+++ b/arch/blackfin/kernel/init_task.c
@@ -0,0 +1,60 @@
1/*
2 * File: arch/blackfin/kernel/init_task.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/mm.h>
31#include <linux/module.h>
32#include <linux/init_task.h>
33#include <linux/mqueue.h>
34
35static struct fs_struct init_fs = INIT_FS;
36static struct files_struct init_files = INIT_FILES;
37static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
38static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
39
40struct mm_struct init_mm = INIT_MM(init_mm);
41EXPORT_SYMBOL(init_mm);
42
43/*
44 * Initial task structure.
45 *
46 * All other task structs will be allocated on slabs in fork.c
47 */
48struct task_struct init_task = INIT_TASK(init_task);
49EXPORT_SYMBOL(init_task);
50
51/*
52 * Initial thread structure.
53 *
54 * We need to make sure that this is 8192-byte aligned due to the
55 * way process stacks are handled. This is done by having a special
56 * "init_task" linker map entry.
57 */
58union thread_union init_thread_union
59 __attribute__ ((__section__(".data.init_task"))) = {
60INIT_THREAD_INFO(init_task)};
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
new file mode 100644
index 000000000000..df5bf022cf79
--- /dev/null
+++ b/arch/blackfin/kernel/irqchip.c
@@ -0,0 +1,147 @@
1/*
2 * File: arch/blackfin/kernel/irqchip.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/kernel_stat.h>
31#include <linux/module.h>
32#include <linux/random.h>
33#include <linux/seq_file.h>
34#include <linux/kallsyms.h>
35#include <linux/interrupt.h>
36#include <linux/irq.h>
37
38static unsigned long irq_err_count;
39static spinlock_t irq_controller_lock;
40
41/*
42 * Dummy mask/unmask handler
43 */
44void dummy_mask_unmask_irq(unsigned int irq)
45{
46}
47
48void ack_bad_irq(unsigned int irq)
49{
50 irq_err_count += 1;
51 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
52}
53EXPORT_SYMBOL(ack_bad_irq);
54
55static struct irq_chip bad_chip = {
56 .ack = dummy_mask_unmask_irq,
57 .mask = dummy_mask_unmask_irq,
58 .unmask = dummy_mask_unmask_irq,
59};
60
61static struct irq_desc bad_irq_desc = {
62 .chip = &bad_chip,
63 .handle_irq = handle_bad_irq,
64 .depth = 1,
65};
66
67int show_interrupts(struct seq_file *p, void *v)
68{
69 int i = *(loff_t *) v;
70 struct irqaction *action;
71 unsigned long flags;
72
73 if (i < NR_IRQS) {
74 spin_lock_irqsave(&irq_desc[i].lock, flags);
75 action = irq_desc[i].action;
76 if (!action)
77 goto unlock;
78
79 seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
80 seq_printf(p, " %s", action->name);
81 for (action = action->next; action; action = action->next)
82 seq_printf(p, ", %s", action->name);
83
84 seq_putc(p, '\n');
85 unlock:
86 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
87 } else if (i == NR_IRQS) {
88 seq_printf(p, "Err: %10lu\n", irq_err_count);
89 }
90 return 0;
91}
92
93/*
94 * do_IRQ handles all hardware IRQ's. Decoded IRQs should not
95 * come via this function. Instead, they should provide their
96 * own 'handler'
97 */
98
99#ifdef CONFIG_DO_IRQ_L1
100asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text));
101#endif
102
103asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
104{
105 struct pt_regs *old_regs;
106 struct irq_desc *desc = irq_desc + irq;
107 unsigned short pending, other_ints;
108
109 old_regs = set_irq_regs(regs);
110
111 /*
112 * Some hardware gives randomly wrong interrupts. Rather
113 * than crashing, do something sensible.
114 */
115 if (irq >= NR_IRQS)
116 desc = &bad_irq_desc;
117
118 irq_enter();
119
120 generic_handle_irq(irq);
121
122 /* If we're the only interrupt running (ignoring IRQ15 which is for
123 syscalls), lower our priority to IRQ14 so that softirqs run at
124 that level. If there's another, lower-level interrupt, irq_exit
125 will defer softirqs to that. */
126 CSYNC();
127 pending = bfin_read_IPEND() & ~0x8000;
128 other_ints = pending & (pending - 1);
129 if (other_ints == 0)
130 lower_to_irq14();
131 irq_exit();
132
133 set_irq_regs(old_regs);
134}
135
136void __init init_IRQ(void)
137{
138 struct irq_desc *desc;
139 int irq;
140
141 spin_lock_init(&irq_controller_lock);
142 for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
143 *desc = bad_irq_desc;
144 }
145
146 init_arch_irq();
147}
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
new file mode 100644
index 000000000000..372f756f1ad9
--- /dev/null
+++ b/arch/blackfin/kernel/module.c
@@ -0,0 +1,429 @@
1/*
2 * File: arch/blackfin/kernel/module.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30
31#include <linux/moduleloader.h>
32#include <linux/elf.h>
33#include <linux/vmalloc.h>
34#include <linux/fs.h>
35#include <linux/string.h>
36#include <linux/kernel.h>
37#include <asm/dma.h>
38#include <asm/cacheflush.h>
39
40/*
41 * handle arithmetic relocations.
42 * See binutils/bfd/elf32-bfin.c for more details
43 */
44#define RELOC_STACK_SIZE 100
45static uint32_t reloc_stack[RELOC_STACK_SIZE];
46static unsigned int reloc_stack_tos;
47
48#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
49
50static void reloc_stack_push(uint32_t value)
51{
52 reloc_stack[reloc_stack_tos++] = value;
53}
54
55static uint32_t reloc_stack_pop(void)
56{
57 return reloc_stack[--reloc_stack_tos];
58}
59
60static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
61{
62 uint32_t value;
63
64 switch (oper) {
65 case R_add:
66 value = reloc_stack[reloc_stack_tos - 2] +
67 reloc_stack[reloc_stack_tos - 1];
68 reloc_stack_tos -= 2;
69 break;
70 case R_sub:
71 value = reloc_stack[reloc_stack_tos - 2] -
72 reloc_stack[reloc_stack_tos - 1];
73 reloc_stack_tos -= 2;
74 break;
75 case R_mult:
76 value = reloc_stack[reloc_stack_tos - 2] *
77 reloc_stack[reloc_stack_tos - 1];
78 reloc_stack_tos -= 2;
79 break;
80 case R_div:
81 value = reloc_stack[reloc_stack_tos - 2] /
82 reloc_stack[reloc_stack_tos - 1];
83 reloc_stack_tos -= 2;
84 break;
85 case R_mod:
86 value = reloc_stack[reloc_stack_tos - 2] %
87 reloc_stack[reloc_stack_tos - 1];
88 reloc_stack_tos -= 2;
89 break;
90 case R_lshift:
91 value = reloc_stack[reloc_stack_tos - 2] <<
92 reloc_stack[reloc_stack_tos - 1];
93 reloc_stack_tos -= 2;
94 break;
95 case R_rshift:
96 value = reloc_stack[reloc_stack_tos - 2] >>
97 reloc_stack[reloc_stack_tos - 1];
98 reloc_stack_tos -= 2;
99 break;
100 case R_and:
101 value = reloc_stack[reloc_stack_tos - 2] &
102 reloc_stack[reloc_stack_tos - 1];
103 reloc_stack_tos -= 2;
104 break;
105 case R_or:
106 value = reloc_stack[reloc_stack_tos - 2] |
107 reloc_stack[reloc_stack_tos - 1];
108 reloc_stack_tos -= 2;
109 break;
110 case R_xor:
111 value = reloc_stack[reloc_stack_tos - 2] ^
112 reloc_stack[reloc_stack_tos - 1];
113 reloc_stack_tos -= 2;
114 break;
115 case R_land:
116 value = reloc_stack[reloc_stack_tos - 2] &&
117 reloc_stack[reloc_stack_tos - 1];
118 reloc_stack_tos -= 2;
119 break;
120 case R_lor:
121 value = reloc_stack[reloc_stack_tos - 2] ||
122 reloc_stack[reloc_stack_tos - 1];
123 reloc_stack_tos -= 2;
124 break;
125 case R_neg:
126 value = -reloc_stack[reloc_stack_tos - 1];
127 reloc_stack_tos--;
128 break;
129 case R_comp:
130 value = ~reloc_stack[reloc_stack_tos - 1];
131 reloc_stack_tos -= 1;
132 break;
133 default:
134 printk(KERN_WARNING "module %s: unhandled reloction\n",
135 mod->name);
136 return 0;
137 }
138
139 /* now push the new value back on stack */
140 reloc_stack_push(value);
141
142 return value;
143}
144
145void *module_alloc(unsigned long size)
146{
147 if (size == 0)
148 return NULL;
149 return vmalloc(size);
150}
151
152/* Free memory returned from module_alloc */
153void module_free(struct module *mod, void *module_region)
154{
155 vfree(module_region);
156}
157
158/* Transfer the section to the L1 memory */
159int
160module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
161 char *secstrings, struct module *mod)
162{
163 Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
164 void *dest = NULL;
165
166 for (s = sechdrs; s < sechdrs_end; ++s) {
167 if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
168 ((strcmp(".text", secstrings + s->sh_name)==0) &&
169 (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
170 mod->arch.text_l1 = s;
171 dest = l1_inst_sram_alloc(s->sh_size);
172 if (dest == NULL) {
173 printk(KERN_ERR
174 "module %s: L1 instruction memory allocation failed\n",
175 mod->name);
176 return -1;
177 }
178 dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
179 s->sh_flags &= ~SHF_ALLOC;
180 s->sh_addr = (unsigned long)dest;
181 }
182 if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
183 ((strcmp(".data", secstrings + s->sh_name)==0) &&
184 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
185 mod->arch.data_a_l1 = s;
186 dest = l1_data_sram_alloc(s->sh_size);
187 if (dest == NULL) {
188 printk(KERN_ERR
189 "module %s: L1 data memory allocation failed\n",
190 mod->name);
191 return -1;
192 }
193 memcpy(dest, (void *)s->sh_addr, s->sh_size);
194 s->sh_flags &= ~SHF_ALLOC;
195 s->sh_addr = (unsigned long)dest;
196 }
197 if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
198 ((strcmp(".bss", secstrings + s->sh_name)==0) &&
199 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
200 mod->arch.bss_a_l1 = s;
201 dest = l1_data_sram_alloc(s->sh_size);
202 if (dest == NULL) {
203 printk(KERN_ERR
204 "module %s: L1 data memory allocation failed\n",
205 mod->name);
206 return -1;
207 }
208 memset(dest, 0, s->sh_size);
209 s->sh_flags &= ~SHF_ALLOC;
210 s->sh_addr = (unsigned long)dest;
211 }
212 if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
213 mod->arch.data_b_l1 = s;
214 dest = l1_data_B_sram_alloc(s->sh_size);
215 if (dest == NULL) {
216 printk(KERN_ERR
217 "module %s: L1 data memory allocation failed\n",
218 mod->name);
219 return -1;
220 }
221 memcpy(dest, (void *)s->sh_addr, s->sh_size);
222 s->sh_flags &= ~SHF_ALLOC;
223 s->sh_addr = (unsigned long)dest;
224 }
225 if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
226 mod->arch.bss_b_l1 = s;
227 dest = l1_data_B_sram_alloc(s->sh_size);
228 if (dest == NULL) {
229 printk(KERN_ERR
230 "module %s: L1 data memory allocation failed\n",
231 mod->name);
232 return -1;
233 }
234 memset(dest, 0, s->sh_size);
235 s->sh_flags &= ~SHF_ALLOC;
236 s->sh_addr = (unsigned long)dest;
237 }
238 }
239 return 0;
240}
241
242int
243apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
244 unsigned int symindex, unsigned int relsec, struct module *me)
245{
246 printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
247 return -ENOEXEC;
248}
249
250/*************************************************************************/
251/* FUNCTION : apply_relocate_add */
252/* ABSTRACT : Blackfin specific relocation handling for the loadable */
253/* modules. Modules are expected to be .o files. */
254/* Arithmetic relocations are handled. */
255/* We do not expect LSETUP to be split and hence is not */
256/* handled. */
257/* R_byte and R_byte2 are also not handled as the gas */
258/* does not generate it. */
259/*************************************************************************/
260int
261apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
262 unsigned int symindex, unsigned int relsec,
263 struct module *mod)
264{
265 unsigned int i;
266 unsigned short tmp;
267 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
268 Elf32_Sym *sym;
269 uint32_t *location32;
270 uint16_t *location16;
271 uint32_t value;
272
273 pr_debug("Applying relocate section %u to %u\n", relsec,
274 sechdrs[relsec].sh_info);
275 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
276 /* This is where to make the change */
277 location16 =
278 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
279 rel[i].r_offset);
280 location32 = (uint32_t *) location16;
281 /* This is the symbol it is referring to. Note that all
282 undefined symbols have been resolved. */
283 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
284 + ELF32_R_SYM(rel[i].r_info);
285 if (is_reloc_stack_empty()) {
286 value = sym->st_value;
287 } else {
288 value = reloc_stack_pop();
289 }
290 value += rel[i].r_addend;
291 pr_debug("location is %x, value is %x type is %d \n",
292 (unsigned int) location32, value,
293 ELF32_R_TYPE(rel[i].r_info));
294
295 switch (ELF32_R_TYPE(rel[i].r_info)) {
296
297 case R_pcrel24:
298 case R_pcrel24_jump_l:
299 /* Add the value, subtract its postition */
300 location16 =
301 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
302 sh_addr + rel[i].r_offset - 2);
303 location32 = (uint32_t *) location16;
304 value -= (uint32_t) location32;
305 value >>= 1;
306 pr_debug("value is %x, before %x-%x after %x-%x\n", value,
307 *location16, *(location16 + 1),
308 (*location16 & 0xff00) | (value >> 16 & 0x00ff),
309 value & 0xffff);
310 *location16 =
311 (*location16 & 0xff00) | (value >> 16 & 0x00ff);
312 *(location16 + 1) = value & 0xffff;
313 break;
314 case R_pcrel12_jump:
315 case R_pcrel12_jump_s:
316 value -= (uint32_t) location32;
317 value >>= 1;
318 *location16 = (value & 0xfff);
319 break;
320 case R_pcrel10:
321 value -= (uint32_t) location32;
322 value >>= 1;
323 *location16 = (value & 0x3ff);
324 break;
325 case R_luimm16:
326 pr_debug("before %x after %x\n", *location16,
327 (value & 0xffff));
328 tmp = (value & 0xffff);
329 if((unsigned long)location16 >= L1_CODE_START) {
330 dma_memcpy(location16, &tmp, 2);
331 } else
332 *location16 = tmp;
333 break;
334 case R_huimm16:
335 pr_debug("before %x after %x\n", *location16,
336 ((value >> 16) & 0xffff));
337 tmp = ((value >> 16) & 0xffff);
338 if((unsigned long)location16 >= L1_CODE_START) {
339 dma_memcpy(location16, &tmp, 2);
340 } else
341 *location16 = tmp;
342 break;
343 case R_rimm16:
344 *location16 = (value & 0xffff);
345 break;
346 case R_byte4_data:
347 pr_debug("before %x after %x\n", *location32, value);
348 *location32 = value;
349 break;
350 case R_push:
351 reloc_stack_push(value);
352 break;
353 case R_const:
354 reloc_stack_push(rel[i].r_addend);
355 break;
356 case R_add:
357 case R_sub:
358 case R_mult:
359 case R_div:
360 case R_mod:
361 case R_lshift:
362 case R_rshift:
363 case R_and:
364 case R_or:
365 case R_xor:
366 case R_land:
367 case R_lor:
368 case R_neg:
369 case R_comp:
370 reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
371 break;
372 default:
373 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
374 mod->name, ELF32_R_TYPE(rel[i].r_info));
375 return -ENOEXEC;
376 }
377 }
378 return 0;
379}
380
381int
382module_finalize(const Elf_Ehdr * hdr,
383 const Elf_Shdr * sechdrs, struct module *mod)
384{
385 unsigned int i, strindex = 0, symindex = 0;
386 char *secstrings;
387
388 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
389
390 for (i = 1; i < hdr->e_shnum; i++) {
391 /* Internal symbols and strings. */
392 if (sechdrs[i].sh_type == SHT_SYMTAB) {
393 symindex = i;
394 strindex = sechdrs[i].sh_link;
395 }
396 }
397
398 for (i = 1; i < hdr->e_shnum; i++) {
399 const char *strtab = (char *)sechdrs[strindex].sh_addr;
400 unsigned int info = sechdrs[i].sh_info;
401
402 /* Not a valid relocation section? */
403 if (info >= hdr->e_shnum)
404 continue;
405
406 if ((sechdrs[i].sh_type == SHT_RELA) &&
407 ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
408 ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
409 (hdr->e_flags & FLG_CODE_IN_L1)))) {
410 apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
411 symindex, i, mod);
412 }
413 }
414 return 0;
415}
416
417void module_arch_cleanup(struct module *mod)
418{
419 if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
420 l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
421 if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
422 l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
423 if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
424 l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
425 if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
426 l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
427 if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
428 l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
429}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
new file mode 100644
index 000000000000..3eff7439d8d3
--- /dev/null
+++ b/arch/blackfin/kernel/process.c
@@ -0,0 +1,394 @@
1/*
2 * File: arch/blackfin/kernel/process.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Blackfin architecture-dependent process handling.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/module.h>
31#include <linux/smp_lock.h>
32#include <linux/unistd.h>
33#include <linux/user.h>
34#include <linux/a.out.h>
35
36#include <asm/blackfin.h>
37#include <asm/uaccess.h>
38
39#define LED_ON 0
40#define LED_OFF 1
41
42asmlinkage void ret_from_fork(void);
43
44/* Points to the SDRAM backup memory for the stack that is currently in
45 * L1 scratchpad memory.
46 */
47void *current_l1_stack_save;
48
49/* The number of tasks currently using a L1 stack area. The SRAM is
50 * allocated/deallocated whenever this changes from/to zero.
51 */
52int nr_l1stack_tasks;
53
54/* Start and length of the area in L1 scratchpad memory which we've allocated
55 * for process stacks.
56 */
57void *l1_stack_base;
58unsigned long l1_stack_len;
59
60/*
61 * Powermanagement idle function, if any..
62 */
63void (*pm_idle)(void) = NULL;
64EXPORT_SYMBOL(pm_idle);
65
66void (*pm_power_off)(void) = NULL;
67EXPORT_SYMBOL(pm_power_off);
68
69/*
70 * We are using a different LED from the one used to indicate timer interrupt.
71 */
72#if defined(CONFIG_BFIN_IDLE_LED)
73static inline void leds_switch(int flag)
74{
75 unsigned short tmp = 0;
76
77 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
78 SSYNC();
79
80 if (flag == LED_ON)
81 tmp &= ~CONFIG_BFIN_IDLE_LED_PIN; /* light on */
82 else
83 tmp |= CONFIG_BFIN_IDLE_LED_PIN; /* light off */
84
85 bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
86 SSYNC();
87
88}
89#else
90static inline void leds_switch(int flag)
91{
92}
93#endif
94
95/*
96 * The idle loop on BFIN
97 */
98#ifdef CONFIG_IDLE_L1
99void default_idle(void)__attribute__((l1_text));
100void cpu_idle(void)__attribute__((l1_text));
101#endif
102
103void default_idle(void)
104{
105 while (!need_resched()) {
106 leds_switch(LED_OFF);
107 local_irq_disable();
108 if (likely(!need_resched()))
109 idle_with_irq_disabled();
110 local_irq_enable();
111 leds_switch(LED_ON);
112 }
113}
114
115void (*idle)(void) = default_idle;
116
117/*
118 * The idle thread. There's no useful work to be
119 * done, so just try to conserve power and have a
120 * low exit latency (ie sit in a loop waiting for
121 * somebody to say that they'd like to reschedule)
122 */
123void cpu_idle(void)
124{
125 /* endless idle loop with no priority at all */
126 while (1) {
127 idle();
128 preempt_enable_no_resched();
129 schedule();
130 preempt_disable();
131 }
132}
133
134void machine_restart(char *__unused)
135{
136#if defined(CONFIG_BLKFIN_CACHE)
137 bfin_write_IMEM_CONTROL(0x01);
138 SSYNC();
139#endif
140 bfin_reset();
141 /* Dont do anything till the reset occurs */
142 while (1) {
143 SSYNC();
144 }
145}
146
147void machine_halt(void)
148{
149 for (;;)
150 asm volatile ("idle");
151}
152
153void machine_power_off(void)
154{
155 for (;;)
156 asm volatile ("idle");
157}
158
159void show_regs(struct pt_regs *regs)
160{
161 printk(KERN_NOTICE "\n");
162 printk(KERN_NOTICE
163 "PC: %08lu Status: %04lu SysStatus: %04lu RETS: %08lu\n",
164 regs->pc, regs->astat, regs->seqstat, regs->rets);
165 printk(KERN_NOTICE
166 "A0.x: %08lx A0.w: %08lx A1.x: %08lx A1.w: %08lx\n",
167 regs->a0x, regs->a0w, regs->a1x, regs->a1w);
168 printk(KERN_NOTICE "P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
169 regs->p0, regs->p1, regs->p2, regs->p3);
170 printk(KERN_NOTICE "P4: %08lx P5: %08lx\n", regs->p4, regs->p5);
171 printk(KERN_NOTICE "R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
172 regs->r0, regs->r1, regs->r2, regs->r3);
173 printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
174 regs->r4, regs->r5, regs->r6, regs->r7);
175
176 if (!(regs->ipend))
177 printk("USP: %08lx\n", rdusp());
178}
179
180/* Fill in the fpu structure for a core dump. */
181
182int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
183{
184 return 1;
185}
186
187/*
188 * This gets run with P1 containing the
189 * function to call, and R1 containing
190 * the "args". Note P0 is clobbered on the way here.
191 */
192void kernel_thread_helper(void);
193__asm__(".section .text\n"
194 ".align 4\n"
195 "_kernel_thread_helper:\n\t"
196 "\tsp += -12;\n\t"
197 "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
198
199/*
200 * Create a kernel thread.
201 */
202pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
203{
204 struct pt_regs regs;
205
206 memset(&regs, 0, sizeof(regs));
207
208 regs.r1 = (unsigned long)arg;
209 regs.p1 = (unsigned long)fn;
210 regs.pc = (unsigned long)kernel_thread_helper;
211 regs.orig_p0 = -1;
212 /* Set bit 2 to tell ret_from_fork we should be returning to kernel
213 mode. */
214 regs.ipend = 0x8002;
215 __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
216 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
217 NULL);
218}
219
220void flush_thread(void)
221{
222}
223
224asmlinkage int bfin_vfork(struct pt_regs *regs)
225{
226 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
227 NULL);
228}
229
230asmlinkage int bfin_clone(struct pt_regs *regs)
231{
232 unsigned long clone_flags;
233 unsigned long newsp;
234
235 /* syscall2 puts clone_flags in r0 and usp in r1 */
236 clone_flags = regs->r0;
237 newsp = regs->r1;
238 if (!newsp)
239 newsp = rdusp();
240 else
241 newsp -= 12;
242 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
243}
244
245int
246copy_thread(int nr, unsigned long clone_flags,
247 unsigned long usp, unsigned long topstk,
248 struct task_struct *p, struct pt_regs *regs)
249{
250 struct pt_regs *childregs;
251
252 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
253 *childregs = *regs;
254 childregs->r0 = 0;
255
256 p->thread.usp = usp;
257 p->thread.ksp = (unsigned long)childregs;
258 p->thread.pc = (unsigned long)ret_from_fork;
259
260 return 0;
261}
262
263/*
264 * fill in the user structure for a core dump..
265 */
266void dump_thread(struct pt_regs *regs, struct user *dump)
267{
268 dump->magic = CMAGIC;
269 dump->start_code = 0;
270 dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
271 dump->u_tsize = ((unsigned long)current->mm->end_code) >> PAGE_SHIFT;
272 dump->u_dsize = ((unsigned long)(current->mm->brk +
273 (PAGE_SIZE - 1))) >> PAGE_SHIFT;
274 dump->u_dsize -= dump->u_tsize;
275 dump->u_ssize = 0;
276
277 if (dump->start_stack < TASK_SIZE)
278 dump->u_ssize =
279 ((unsigned long)(TASK_SIZE -
280 dump->start_stack)) >> PAGE_SHIFT;
281
282 dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
283
284 dump->regs.r0 = regs->r0;
285 dump->regs.r1 = regs->r1;
286 dump->regs.r2 = regs->r2;
287 dump->regs.r3 = regs->r3;
288 dump->regs.r4 = regs->r4;
289 dump->regs.r5 = regs->r5;
290 dump->regs.r6 = regs->r6;
291 dump->regs.r7 = regs->r7;
292 dump->regs.p0 = regs->p0;
293 dump->regs.p1 = regs->p1;
294 dump->regs.p2 = regs->p2;
295 dump->regs.p3 = regs->p3;
296 dump->regs.p4 = regs->p4;
297 dump->regs.p5 = regs->p5;
298 dump->regs.orig_p0 = regs->orig_p0;
299 dump->regs.a0w = regs->a0w;
300 dump->regs.a1w = regs->a1w;
301 dump->regs.a0x = regs->a0x;
302 dump->regs.a1x = regs->a1x;
303 dump->regs.rets = regs->rets;
304 dump->regs.astat = regs->astat;
305 dump->regs.pc = regs->pc;
306}
307
308/*
309 * sys_execve() executes a new program.
310 */
311
312asmlinkage int sys_execve(char *name, char **argv, char **envp)
313{
314 int error;
315 char *filename;
316 struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
317
318 lock_kernel();
319 filename = getname(name);
320 error = PTR_ERR(filename);
321 if (IS_ERR(filename))
322 goto out;
323 error = do_execve(filename, argv, envp, regs);
324 putname(filename);
325 out:
326 unlock_kernel();
327 return error;
328}
329
330unsigned long get_wchan(struct task_struct *p)
331{
332 unsigned long fp, pc;
333 unsigned long stack_page;
334 int count = 0;
335 if (!p || p == current || p->state == TASK_RUNNING)
336 return 0;
337
338 stack_page = (unsigned long)p;
339 fp = p->thread.usp;
340 do {
341 if (fp < stack_page + sizeof(struct thread_info) ||
342 fp >= 8184 + stack_page)
343 return 0;
344 pc = ((unsigned long *)fp)[1];
345 if (!in_sched_functions(pc))
346 return pc;
347 fp = *(unsigned long *)fp;
348 }
349 while (count++ < 16);
350 return 0;
351}
352
353#if defined(CONFIG_ACCESS_CHECK)
354int _access_ok(unsigned long addr, unsigned long size)
355{
356
357 if (addr > (addr + size))
358 return 0;
359 if (segment_eq(get_fs(),KERNEL_DS))
360 return 1;
361#ifdef CONFIG_MTD_UCLINUX
362 if (addr >= memory_start && (addr + size) <= memory_end)
363 return 1;
364 if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
365 return 1;
366#else
367 if (addr >= memory_start && (addr + size) <= physical_mem_end)
368 return 1;
369#endif
370 if (addr >= (unsigned long)__init_begin &&
371 addr + size <= (unsigned long)__init_end)
372 return 1;
373 if (addr >= L1_SCRATCH_START
374 && addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)
375 return 1;
376#if L1_CODE_LENGTH != 0
377 if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1)
378 && addr + size <= L1_CODE_START + L1_CODE_LENGTH)
379 return 1;
380#endif
381#if L1_DATA_A_LENGTH != 0
382 if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1)
383 && addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)
384 return 1;
385#endif
386#if L1_DATA_B_LENGTH != 0
387 if (addr >= L1_DATA_B_START
388 && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
389 return 1;
390#endif
391 return 0;
392}
393EXPORT_SYMBOL(_access_ok);
394#endif /* CONFIG_ACCESS_CHECK */
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
new file mode 100644
index 000000000000..d7c8e514cb92
--- /dev/null
+++ b/arch/blackfin/kernel/ptrace.c
@@ -0,0 +1,430 @@
1/*
2 * File: arch/blackfin/kernel/ptrace.c
3 * Based on: Taken from linux/kernel/ptrace.c
4 * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
5 *
6 * Created: 1/23/92
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/mm.h>
33#include <linux/smp.h>
34#include <linux/smp_lock.h>
35#include <linux/errno.h>
36#include <linux/ptrace.h>
37#include <linux/user.h>
38#include <linux/signal.h>
39
40#include <asm/uaccess.h>
41#include <asm/page.h>
42#include <asm/pgtable.h>
43#include <asm/system.h>
44#include <asm/processor.h>
45#include <asm/asm-offsets.h>
46#include <asm/dma.h>
47
48#define MAX_SHARED_LIBS 3
49#define TEXT_OFFSET 0
50/*
51 * does not yet catch signals sent when the child dies.
52 * in exit.c or in signal.c.
53 */
54
55/* determines which bits in the SYSCFG reg the user has access to. */
56/* 1 = access 0 = no access */
57#define SYSCFG_MASK 0x0007 /* SYSCFG reg */
58/* sets the trace bits. */
59#define TRACE_BITS 0x0001
60
61/* Find the stack offset for a register, relative to thread.esp0. */
62#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
63
64/*
65 * Get the address of the live pt_regs for the specified task.
66 * These are saved onto the top kernel stack when the process
67 * is not running.
68 *
69 * Note: if a user thread is execve'd from kernel space, the
70 * kernel stack will not be empty on entry to the kernel, so
71 * ptracing these tasks will fail.
72 */
73static inline struct pt_regs *get_user_regs(struct task_struct *task)
74{
75 return (struct pt_regs *)
76 ((unsigned long)task->thread_info +
77 (THREAD_SIZE - sizeof(struct pt_regs)));
78}
79
80/*
81 * Get all user integer registers.
82 */
83static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
84{
85 struct pt_regs *regs = get_user_regs(tsk);
86 return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
87}
88
89/* Mapping from PT_xxx to the stack offset at which the register is
90 * saved. Notice that usp has no stack-slot and needs to be treated
91 * specially (see get_reg/put_reg below).
92 */
93
94/*
95 * Get contents of register REGNO in task TASK.
96 */
97static inline long get_reg(struct task_struct *task, int regno)
98{
99 unsigned char *reg_ptr;
100
101 struct pt_regs *regs =
102 (struct pt_regs *)((unsigned long)task->thread_info +
103 (THREAD_SIZE - sizeof(struct pt_regs)));
104 reg_ptr = (char *)regs;
105
106 switch (regno) {
107 case PT_USP:
108 return task->thread.usp;
109 default:
110 if (regno <= 216)
111 return *(long *)(reg_ptr + regno);
112 }
113 /* slight mystery ... never seems to come here but kernel misbehaves without this code! */
114
115 printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
116 return 0;
117}
118
119/*
120 * Write contents of register REGNO in task TASK.
121 */
122static inline int
123put_reg(struct task_struct *task, int regno, unsigned long data)
124{
125 char * reg_ptr;
126
127 struct pt_regs *regs =
128 (struct pt_regs *)((unsigned long)task->thread_info +
129 (THREAD_SIZE - sizeof(struct pt_regs)));
130 reg_ptr = (char *)regs;
131
132 switch (regno) {
133 case PT_PC:
134 /*********************************************************************/
135 /* At this point the kernel is most likely in exception. */
136 /* The RETX register will be used to populate the pc of the process. */
137 /*********************************************************************/
138 regs->retx = data;
139 regs->pc = data;
140 break;
141 case PT_RETX:
142 break; /* regs->retx = data; break; */
143 case PT_USP:
144 regs->usp = data;
145 task->thread.usp = data;
146 break;
147 default:
148 if (regno <= 216)
149 *(long *)(reg_ptr + regno) = data;
150 }
151 return 0;
152}
153
154/*
155 * check that an address falls within the bounds of the target process's memory mappings
156 */
157static inline int is_user_addr_valid(struct task_struct *child,
158 unsigned long start, unsigned long len)
159{
160 struct vm_list_struct *vml;
161 struct sram_list_struct *sraml;
162
163 for (vml = child->mm->context.vmlist; vml; vml = vml->next)
164 if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
165 return 0;
166
167 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
168 if (start >= (unsigned long)sraml->addr
169 && start + len <= (unsigned long)sraml->addr + sraml->length)
170 return 0;
171
172 return -EIO;
173}
174
175/*
176 * Called by kernel/ptrace.c when detaching..
177 *
178 * Make sure the single step bit is not set.
179 */
180void ptrace_disable(struct task_struct *child)
181{
182 unsigned long tmp;
183 /* make sure the single step bit is not set. */
184 tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
185 put_reg(child, PT_SR, tmp);
186}
187
188long arch_ptrace(struct task_struct *child, long request, long addr, long data)
189{
190 int ret;
191 int add = 0;
192
193 switch (request) {
194 /* when I and D space are separate, these will need to be fixed. */
195 case PTRACE_PEEKDATA:
196 pr_debug("ptrace: PEEKDATA\n");
197 add = MAX_SHARED_LIBS * 4; /* space between text and data */
198 /* fall through */
199 case PTRACE_PEEKTEXT: /* read word at location addr. */
200 {
201 unsigned long tmp = 0;
202 int copied;
203
204 ret = -EIO;
205 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
206 sizeof(data));
207 if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
208 break;
209 pr_debug("ptrace: user address is valid\n");
210
211#if L1_CODE_LENGTH != 0
212 if (addr + add >= L1_CODE_START
213 && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
214 safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
215 copied = sizeof(tmp);
216 } else
217#endif
218 copied =
219 access_process_vm(child, addr + add, &tmp,
220 sizeof(tmp), 0);
221 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
222 if (copied != sizeof(tmp))
223 break;
224 ret = put_user(tmp, (unsigned long *)data);
225 break;
226 }
227
228 /* read the word at location addr in the USER area. */
229 case PTRACE_PEEKUSR:
230 {
231 unsigned long tmp;
232 ret = -EIO;
233 tmp = 0;
234 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
235 printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
236 "0 - %x sizeof(pt_regs) is %lx\n",
237 (int)addr, sizeof(struct pt_regs));
238 break;
239 }
240 if (addr == sizeof(struct pt_regs)) {
241 /* PT_TEXT_ADDR */
242 tmp = child->mm->start_code + TEXT_OFFSET;
243 } else if (addr == (sizeof(struct pt_regs) + 4)) {
244 /* PT_TEXT_END_ADDR */
245 tmp = child->mm->end_code;
246 } else if (addr == (sizeof(struct pt_regs) + 8)) {
247 /* PT_DATA_ADDR */
248 tmp = child->mm->start_data;
249#ifdef CONFIG_BINFMT_ELF_FDPIC
250 } else if (addr == (sizeof(struct pt_regs) + 12)) {
251 tmp = child->mm->context.exec_fdpic_loadmap;
252 } else if (addr == (sizeof(struct pt_regs) + 16)) {
253 tmp = child->mm->context.interp_fdpic_loadmap;
254#endif
255 } else {
256 tmp = get_reg(child, addr);
257 }
258 ret = put_user(tmp, (unsigned long *)data);
259 break;
260 }
261
262 /* when I and D space are separate, this will have to be fixed. */
263 case PTRACE_POKEDATA:
264 printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
265 /* fall through */
266 case PTRACE_POKETEXT: /* write the word at location addr. */
267 {
268 int copied;
269
270 ret = -EIO;
271 pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
272 addr, add, sizeof(data), data);
273 if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
274 break;
275 pr_debug("ptrace: user address is valid\n");
276
277#if L1_CODE_LENGTH != 0
278 if (addr + add >= L1_CODE_START
279 && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
280 safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
281 copied = sizeof(data);
282 } else
283#endif
284 copied =
285 access_process_vm(child, addr + add, &data,
286 sizeof(data), 1);
287 pr_debug("ptrace: copied size %d\n", copied);
288 if (copied != sizeof(data))
289 break;
290 ret = 0;
291 break;
292 }
293
294 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
295 ret = -EIO;
296 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
297 printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
298 break;
299 }
300
301 if (addr >= (sizeof(struct pt_regs))) {
302 ret = 0;
303 break;
304 }
305 if (addr == PT_SYSCFG) {
306 data &= SYSCFG_MASK;
307 data |= get_reg(child, PT_SYSCFG);
308 }
309 ret = put_reg(child, addr, data);
310 break;
311
312 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
313 case PTRACE_CONT:
314 { /* restart after signal. */
315 long tmp;
316
317 pr_debug("ptrace_cont\n");
318
319 ret = -EIO;
320 if (!valid_signal(data))
321 break;
322 if (request == PTRACE_SYSCALL)
323 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
324 else
325 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
326
327 child->exit_code = data;
328 /* make sure the single step bit is not set. */
329 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
330 put_reg(child, PT_SYSCFG, tmp);
331 pr_debug("before wake_up_process\n");
332 wake_up_process(child);
333 ret = 0;
334 break;
335 }
336
337 /*
338 * make the child exit. Best I can do is send it a sigkill.
339 * perhaps it should be put in the status that it wants to
340 * exit.
341 */
342 case PTRACE_KILL:
343 {
344 long tmp;
345 ret = 0;
346 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
347 break;
348 child->exit_code = SIGKILL;
349 /* make sure the single step bit is not set. */
350 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
351 put_reg(child, PT_SYSCFG, tmp);
352 wake_up_process(child);
353 break;
354 }
355
356 case PTRACE_SINGLESTEP:
357 { /* set the trap flag. */
358 long tmp;
359
360 pr_debug("single step\n");
361 ret = -EIO;
362 if (!valid_signal(data))
363 break;
364 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
365
366 tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
367 put_reg(child, PT_SYSCFG, tmp);
368
369 child->exit_code = data;
370 /* give it a chance to run. */
371 wake_up_process(child);
372 ret = 0;
373 break;
374 }
375
376 case PTRACE_DETACH:
377 { /* detach a process that was attached. */
378 ret = ptrace_detach(child, data);
379 break;
380 }
381
382 case PTRACE_GETREGS:
383 {
384
385 /* Get all gp regs from the child. */
386 ret = ptrace_getregs(child, (void __user *)data);
387 break;
388 }
389
390 case PTRACE_SETREGS:
391 {
392 printk(KERN_NOTICE
393 "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
394 /* Set all gp regs in the child. */
395 ret = 0;
396 break;
397 }
398 default:
399 ret = ptrace_request(child, request, addr, data);
400 break;
401 }
402
403 return ret;
404}
405
406asmlinkage void syscall_trace(void)
407{
408
409 if (!test_thread_flag(TIF_SYSCALL_TRACE))
410 return;
411
412 if (!(current->ptrace & PT_PTRACED))
413 return;
414
415 /* the 0x80 provides a way for the tracing parent to distinguish
416 * between a syscall stop and SIGTRAP delivery
417 */
418 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
419 ? 0x80 : 0));
420
421 /*
422 * this isn't the same as continuing with a signal, but it will do
423 * for normal use. strace only continues with a signal if the
424 * stopping signal is not SIGTRAP. -brl
425 */
426 if (current->exit_code) {
427 send_sig(current->exit_code, current, 1);
428 current->exit_code = 0;
429 }
430}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
new file mode 100644
index 000000000000..342bb8dd56ac
--- /dev/null
+++ b/arch/blackfin/kernel/setup.c
@@ -0,0 +1,902 @@
1/*
2 * File: arch/blackfin/kernel/setup.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/delay.h>
31#include <linux/console.h>
32#include <linux/bootmem.h>
33#include <linux/seq_file.h>
34#include <linux/cpu.h>
35#include <linux/module.h>
36#include <linux/console.h>
37#include <linux/tty.h>
38
39#include <linux/ext2_fs.h>
40#include <linux/cramfs_fs.h>
41#include <linux/romfs_fs.h>
42
43#include <asm/cacheflush.h>
44#include <asm/blackfin.h>
45#include <asm/cplbinit.h>
46
47unsigned long memory_start, memory_end, physical_mem_end;
48unsigned long reserved_mem_dcache_on;
49unsigned long reserved_mem_icache_on;
50EXPORT_SYMBOL(memory_start);
51EXPORT_SYMBOL(memory_end);
52EXPORT_SYMBOL(physical_mem_end);
53EXPORT_SYMBOL(_ramend);
54
55#ifdef CONFIG_MTD_UCLINUX
56unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
57unsigned long _ebss;
58EXPORT_SYMBOL(memory_mtd_end);
59EXPORT_SYMBOL(memory_mtd_start);
60EXPORT_SYMBOL(mtd_size);
61#endif
62
63char command_line[COMMAND_LINE_SIZE];
64
65#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
66static void generate_cpl_tables(void);
67#endif
68
69void __init bf53x_cache_init(void)
70{
71#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
72 generate_cpl_tables();
73#endif
74
75#ifdef CONFIG_BLKFIN_CACHE
76 bfin_icache_init();
77 printk(KERN_INFO "Instruction Cache Enabled\n");
78#endif
79
80#ifdef CONFIG_BLKFIN_DCACHE
81 bfin_dcache_init();
82 printk(KERN_INFO "Data Cache Enabled"
83# if defined CONFIG_BLKFIN_WB
84 " (write-back)"
85# elif defined CONFIG_BLKFIN_WT
86 " (write-through)"
87# endif
88 "\n");
89#endif
90}
91
92void bf53x_relocate_l1_mem(void)
93{
94 unsigned long l1_code_length;
95 unsigned long l1_data_a_length;
96 unsigned long l1_data_b_length;
97
98 l1_code_length = _etext_l1 - _stext_l1;
99 if (l1_code_length > L1_CODE_LENGTH)
100 l1_code_length = L1_CODE_LENGTH;
101 /* cannot complain as printk is not available as yet.
102 * But we can continue booting and complain later!
103 */
104
105 /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
106 dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
107
108 l1_data_a_length = _ebss_l1 - _sdata_l1;
109 if (l1_data_a_length > L1_DATA_A_LENGTH)
110 l1_data_a_length = L1_DATA_A_LENGTH;
111
112 /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
113 dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
114
115 l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
116 if (l1_data_b_length > L1_DATA_B_LENGTH)
117 l1_data_b_length = L1_DATA_B_LENGTH;
118
119 /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
120 dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
121 l1_data_a_length, l1_data_b_length);
122
123}
124
125/*
126 * Initial parsing of the command line. Currently, we support:
127 * - Controlling the linux memory size: mem=xxx[KMG]
128 * - Controlling the physical memory size: max_mem=xxx[KMG][$][#]
129 * $ -> reserved memory is dcacheable
130 * # -> reserved memory is icacheable
131 */
132static __init void parse_cmdline_early(char *cmdline_p)
133{
134 char c = ' ', *to = cmdline_p;
135 unsigned int memsize;
136 for (;;) {
137 if (c == ' ') {
138
139 if (!memcmp(to, "mem=", 4)) {
140 to += 4;
141 memsize = memparse(to, &to);
142 if (memsize)
143 _ramend = memsize;
144
145 } else if (!memcmp(to, "max_mem=", 8)) {
146 to += 8;
147 memsize = memparse(to, &to);
148 if (memsize) {
149 physical_mem_end = memsize;
150 if (*to != ' ') {
151 if (*to == '$'
152 || *(to + 1) == '$')
153 reserved_mem_dcache_on =
154 1;
155 if (*to == '#'
156 || *(to + 1) == '#')
157 reserved_mem_icache_on =
158 1;
159 }
160 }
161 }
162
163 }
164 c = *(to++);
165 if (!c)
166 break;
167 }
168}
169
170void __init setup_arch(char **cmdline_p)
171{
172 int bootmap_size;
173 unsigned long l1_length, sclk, cclk;
174#ifdef CONFIG_MTD_UCLINUX
175 unsigned long mtd_phys = 0;
176#endif
177
178 cclk = get_cclk();
179 sclk = get_sclk();
180
181#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273)
182 if (cclk == sclk)
183 panic("ANOMALY 05000273, SCLK can not be same as CCLK");
184#endif
185
186#if defined(ANOMALY_05000266)
187 bfin_read_IMDMA_D0_IRQ_STATUS();
188 bfin_read_IMDMA_D1_IRQ_STATUS();
189#endif
190
191#ifdef DEBUG_SERIAL_EARLY_INIT
192 bfin_console_init(); /* early console registration */
193 /* this give a chance to get printk() working before crash. */
194#endif
195
196#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
197 /* we need to initialize the Flashrom device here since we might
198 * do things with flash early on in the boot
199 */
200 flash_probe();
201#endif
202
203#if defined(CONFIG_CMDLINE_BOOL)
204 memset(command_line, 0, sizeof(command_line));
205 strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
206 command_line[sizeof(command_line) - 1] = 0;
207#endif
208
209 /* Keep a copy of command line */
210 *cmdline_p = &command_line[0];
211 memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
212 boot_command_line[COMMAND_LINE_SIZE - 1] = 0;
213
214 /* setup memory defaults from the user config */
215 physical_mem_end = 0;
216 _ramend = CONFIG_MEM_SIZE * 1024 * 1024;
217
218 parse_cmdline_early(&command_line[0]);
219
220 if (physical_mem_end == 0)
221 physical_mem_end = _ramend;
222
223 /* by now the stack is part of the init task */
224 memory_end = _ramend - DMA_UNCACHED_REGION;
225
226 _ramstart = (unsigned long)__bss_stop;
227 memory_start = PAGE_ALIGN(_ramstart);
228
229#if defined(CONFIG_MTD_UCLINUX)
230 /* generic memory mapped MTD driver */
231 memory_mtd_end = memory_end;
232
233 mtd_phys = _ramstart;
234 mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
235
236# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
237 if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
238 mtd_size =
239 PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
240# endif
241
242# if defined(CONFIG_CRAMFS)
243 if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC)
244 mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4)));
245# endif
246
247# if defined(CONFIG_ROMFS_FS)
248 if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
249 && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
250 mtd_size =
251 PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
252# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
253 /* Due to a Hardware Anomaly we need to limit the size of usable
254 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
255 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
256 */
257# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
258 if (memory_end >= 56 * 1024 * 1024)
259 memory_end = 56 * 1024 * 1024;
260# else
261 if (memory_end >= 60 * 1024 * 1024)
262 memory_end = 60 * 1024 * 1024;
263# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
264# endif /* ANOMALY_05000263 */
265# endif /* CONFIG_ROMFS_FS */
266
267 memory_end -= mtd_size;
268
269 if (mtd_size == 0) {
270 console_init();
271 panic("Don't boot kernel without rootfs attached.\n");
272 }
273
274 /* Relocate MTD image to the top of memory after the uncached memory area */
275 dma_memcpy((char *)memory_end, __bss_stop, mtd_size);
276
277 memory_mtd_start = memory_end;
278 _ebss = memory_mtd_start; /* define _ebss for compatible */
279#endif /* CONFIG_MTD_UCLINUX */
280
281#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
282 /* Due to a Hardware Anomaly we need to limit the size of usable
283 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
284 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
285 */
286#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
287 if (memory_end >= 56 * 1024 * 1024)
288 memory_end = 56 * 1024 * 1024;
289#else
290 if (memory_end >= 60 * 1024 * 1024)
291 memory_end = 60 * 1024 * 1024;
292#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
293 printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
294#endif /* ANOMALY_05000263 */
295
296#if !defined(CONFIG_MTD_UCLINUX)
297 memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
298#endif
299 init_mm.start_code = (unsigned long)_stext;
300 init_mm.end_code = (unsigned long)_etext;
301 init_mm.end_data = (unsigned long)_edata;
302 init_mm.brk = (unsigned long)0;
303
304 init_leds();
305
306 printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n");
307 printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
308 if (bfin_revid() != bfin_compiled_revid())
309 printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
310 bfin_compiled_revid(), bfin_revid());
311 if (bfin_revid() < SUPPORTED_REVID)
312 printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
313 CPU, bfin_revid());
314 printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
315
316 printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
317 cclk / 1000000, sclk / 1000000);
318
319#if defined(ANOMALY_05000273)
320 if ((cclk >> 1) <= sclk)
321 printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
322#endif
323
324 printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
325 printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
326
327 printk(KERN_INFO "Memory map:\n"
328 KERN_INFO " text = 0x%p-0x%p\n"
329 KERN_INFO " init = 0x%p-0x%p\n"
330 KERN_INFO " data = 0x%p-0x%p\n"
331 KERN_INFO " stack = 0x%p-0x%p\n"
332 KERN_INFO " bss = 0x%p-0x%p\n"
333 KERN_INFO " available = 0x%p-0x%p\n"
334#ifdef CONFIG_MTD_UCLINUX
335 KERN_INFO " rootfs = 0x%p-0x%p\n"
336#endif
337#if DMA_UNCACHED_REGION > 0
338 KERN_INFO " DMA Zone = 0x%p-0x%p\n"
339#endif
340 , _stext, _etext,
341 __init_begin, __init_end,
342 _sdata, _edata,
343 (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
344 __bss_start, __bss_stop,
345 (void*)_ramstart, (void*)memory_end
346#ifdef CONFIG_MTD_UCLINUX
347 , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
348#endif
349#if DMA_UNCACHED_REGION > 0
350 , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
351#endif
352 );
353
354 /*
355 * give all the memory to the bootmap allocator, tell it to put the
356 * boot mem_map at the start of memory
357 */
358 bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */
359 PAGE_OFFSET >> PAGE_SHIFT,
360 memory_end >> PAGE_SHIFT);
361 /*
362 * free the usable memory, we have to make sure we do not free
363 * the bootmem bitmap so we then reserve it after freeing it :-)
364 */
365 free_bootmem(memory_start, memory_end - memory_start);
366
367 reserve_bootmem(memory_start, bootmap_size);
368 /*
369 * get kmalloc into gear
370 */
371 paging_init();
372
373 /* check the size of the l1 area */
374 l1_length = _etext_l1 - _stext_l1;
375 if (l1_length > L1_CODE_LENGTH)
376 panic("L1 memory overflow\n");
377
378 l1_length = _ebss_l1 - _sdata_l1;
379 if (l1_length > L1_DATA_A_LENGTH)
380 panic("L1 memory overflow\n");
381
382 bf53x_cache_init();
383
384#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
385# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP)
386 /* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
387 bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
388 bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
389 SSYNC();
390# endif
391# if defined (CONFIG_BFIN561_EZKIT)
392 bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12));
393 SSYNC();
394# endif /* defined (CONFIG_BFIN561_EZKIT) */
395#endif
396
397 printk(KERN_INFO "Hardware Trace Enabled\n");
398 bfin_write_TBUFCTL(0x03);
399}
400
401#if defined(CONFIG_BF561)
402static struct cpu cpu[2];
403#else
404static struct cpu cpu[1];
405#endif
406static int __init topology_init(void)
407{
408#if defined (CONFIG_BF561)
409 register_cpu(&cpu[0], 0);
410 register_cpu(&cpu[1], 1);
411 return 0;
412#else
413 return register_cpu(cpu, 0);
414#endif
415}
416
417subsys_initcall(topology_init);
418
419#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
420u16 lock_kernel_check(u32 start, u32 end)
421{
422 if ((start <= (u32) _stext && end >= (u32) _end)
423 || (start >= (u32) _stext && end <= (u32) _end))
424 return IN_KERNEL;
425 return 0;
426}
427
428static unsigned short __init
429fill_cplbtab(struct cplb_tab *table,
430 unsigned long start, unsigned long end,
431 unsigned long block_size, unsigned long cplb_data)
432{
433 int i;
434
435 switch (block_size) {
436 case SIZE_4M:
437 i = 3;
438 break;
439 case SIZE_1M:
440 i = 2;
441 break;
442 case SIZE_4K:
443 i = 1;
444 break;
445 case SIZE_1K:
446 default:
447 i = 0;
448 break;
449 }
450
451 cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
452
453 while ((start < end) && (table->pos < table->size)) {
454
455 table->tab[table->pos++] = start;
456
457 if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
458 table->tab[table->pos++] =
459 cplb_data | CPLB_LOCK | CPLB_DIRTY;
460 else
461 table->tab[table->pos++] = cplb_data;
462
463 start += block_size;
464 }
465 return 0;
466}
467
468static unsigned short __init
469close_cplbtab(struct cplb_tab *table)
470{
471
472 while (table->pos < table->size) {
473
474 table->tab[table->pos++] = 0;
475 table->tab[table->pos++] = 0; /* !CPLB_VALID */
476 }
477 return 0;
478}
479
480static void __init generate_cpl_tables(void)
481{
482
483 u16 i, j, process;
484 u32 a_start, a_end, as, ae, as_1m;
485
486 struct cplb_tab *t_i = NULL;
487 struct cplb_tab *t_d = NULL;
488 struct s_cplb cplb;
489
490 cplb.init_i.size = MAX_CPLBS;
491 cplb.init_d.size = MAX_CPLBS;
492 cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
493 cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
494
495 cplb.init_i.pos = 0;
496 cplb.init_d.pos = 0;
497 cplb.switch_i.pos = 0;
498 cplb.switch_d.pos = 0;
499
500 cplb.init_i.tab = icplb_table;
501 cplb.init_d.tab = dcplb_table;
502 cplb.switch_i.tab = ipdt_table;
503 cplb.switch_d.tab = dpdt_table;
504
505 cplb_data[SDRAM_KERN].end = memory_end;
506
507#ifdef CONFIG_MTD_UCLINUX
508 cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
509 cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
510 cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
511# if defined(CONFIG_ROMFS_FS)
512 cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
513
514 /*
515 * The ROMFS_FS size is often not multiple of 1MB.
516 * This can cause multiple CPLB sets covering the same memory area.
517 * This will then cause multiple CPLB hit exceptions.
518 * Workaround: We ensure a contiguous memory area by extending the kernel
519 * memory section over the mtd section.
520 * For ROMFS_FS memory must be covered with ICPLBs anyways.
521 * So there is no difference between kernel and mtd memory setup.
522 */
523
524 cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
525 cplb_data[SDRAM_RAM_MTD].valid = 0;
526
527# endif
528#else
529 cplb_data[SDRAM_RAM_MTD].valid = 0;
530#endif
531
532 cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
533 cplb_data[SDRAM_DMAZ].end = _ramend;
534
535 cplb_data[RES_MEM].start = _ramend;
536 cplb_data[RES_MEM].end = physical_mem_end;
537
538 if (reserved_mem_dcache_on)
539 cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
540 else
541 cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
542
543 if (reserved_mem_icache_on)
544 cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
545 else
546 cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
547
548 for (i = ZERO_P; i <= L2_MEM; i++) {
549
550 if (cplb_data[i].valid) {
551
552 as_1m = cplb_data[i].start % SIZE_1M;
553
554 /* We need to make sure all sections are properly 1M aligned
555 * However between Kernel Memory and the Kernel mtd section, depending on the
556 * rootfs size, there can be overlapping memory areas.
557 */
558
559 if (as_1m && i!=L1I_MEM && i!=L1D_MEM) {
560#ifdef CONFIG_MTD_UCLINUX
561 if (i == SDRAM_RAM_MTD) {
562 if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
563 cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
564 else
565 cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
566 } else
567#endif
568 printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
569 cplb_data[i].name, cplb_data[i].start);
570 }
571
572 as = cplb_data[i].start % SIZE_4M;
573 ae = cplb_data[i].end % SIZE_4M;
574
575 if (as)
576 a_start = cplb_data[i].start + (SIZE_4M - (as));
577 else
578 a_start = cplb_data[i].start;
579
580 a_end = cplb_data[i].end - ae;
581
582 for (j = INITIAL_T; j <= SWITCH_T; j++) {
583
584 switch (j) {
585 case INITIAL_T:
586 if (cplb_data[i].attr & INITIAL_T) {
587 t_i = &cplb.init_i;
588 t_d = &cplb.init_d;
589 process = 1;
590 } else
591 process = 0;
592 break;
593 case SWITCH_T:
594 if (cplb_data[i].attr & SWITCH_T) {
595 t_i = &cplb.switch_i;
596 t_d = &cplb.switch_d;
597 process = 1;
598 } else
599 process = 0;
600 break;
601 default:
602 process = 0;
603 break;
604 }
605
606 if (process) {
607 if (cplb_data[i].attr & I_CPLB) {
608
609 if (cplb_data[i].psize) {
610 fill_cplbtab(t_i,
611 cplb_data[i].start,
612 cplb_data[i].end,
613 cplb_data[i].psize,
614 cplb_data[i].i_conf);
615 } else {
616 /*icplb_table */
617#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
618 if (i == SDRAM_KERN) {
619 fill_cplbtab(t_i,
620 cplb_data[i].start,
621 cplb_data[i].end,
622 SIZE_4M,
623 cplb_data[i].i_conf);
624 } else
625#endif
626 {
627 fill_cplbtab(t_i,
628 cplb_data[i].start,
629 a_start,
630 SIZE_1M,
631 cplb_data[i].i_conf);
632 fill_cplbtab(t_i,
633 a_start,
634 a_end,
635 SIZE_4M,
636 cplb_data[i].i_conf);
637 fill_cplbtab(t_i, a_end,
638 cplb_data[i].end,
639 SIZE_1M,
640 cplb_data[i].i_conf);
641 }
642 }
643
644 }
645 if (cplb_data[i].attr & D_CPLB) {
646
647 if (cplb_data[i].psize) {
648 fill_cplbtab(t_d,
649 cplb_data[i].start,
650 cplb_data[i].end,
651 cplb_data[i].psize,
652 cplb_data[i].d_conf);
653 } else {
654/*dcplb_table*/
655 fill_cplbtab(t_d,
656 cplb_data[i].start,
657 a_start, SIZE_1M,
658 cplb_data[i].d_conf);
659 fill_cplbtab(t_d, a_start,
660 a_end, SIZE_4M,
661 cplb_data[i].d_conf);
662 fill_cplbtab(t_d, a_end,
663 cplb_data[i].end,
664 SIZE_1M,
665 cplb_data[i].d_conf);
666
667 }
668
669 }
670 }
671 }
672
673 }
674 }
675
676/* close tables */
677
678 close_cplbtab(&cplb.init_i);
679 close_cplbtab(&cplb.init_d);
680
681 cplb.init_i.tab[cplb.init_i.pos] = -1;
682 cplb.init_d.tab[cplb.init_d.pos] = -1;
683 cplb.switch_i.tab[cplb.switch_i.pos] = -1;
684 cplb.switch_d.tab[cplb.switch_d.pos] = -1;
685
686}
687
688#endif
689
690static inline u_long get_vco(void)
691{
692 u_long msel;
693 u_long vco;
694
695 msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
696 if (0 == msel)
697 msel = 64;
698
699 vco = CONFIG_CLKIN_HZ;
700 vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */
701 vco = msel * vco;
702 return vco;
703}
704
705/*Get the Core clock*/
706u_long get_cclk(void)
707{
708 u_long csel, ssel;
709 if (bfin_read_PLL_STAT() & 0x1)
710 return CONFIG_CLKIN_HZ;
711
712 ssel = bfin_read_PLL_DIV();
713 csel = ((ssel >> 4) & 0x03);
714 ssel &= 0xf;
715 if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */
716 return get_vco() / ssel;
717 return get_vco() >> csel;
718}
719
720EXPORT_SYMBOL(get_cclk);
721
722/* Get the System clock */
723u_long get_sclk(void)
724{
725 u_long ssel;
726
727 if (bfin_read_PLL_STAT() & 0x1)
728 return CONFIG_CLKIN_HZ;
729
730 ssel = (bfin_read_PLL_DIV() & 0xf);
731 if (0 == ssel) {
732 printk(KERN_WARNING "Invalid System Clock\n");
733 ssel = 1;
734 }
735
736 return get_vco() / ssel;
737}
738
739EXPORT_SYMBOL(get_sclk);
740
741/*
742 * Get CPU information for use by the procfs.
743 */
744static int show_cpuinfo(struct seq_file *m, void *v)
745{
746 char *cpu, *mmu, *fpu, *name;
747 uint32_t revid;
748
749 u_long cclk = 0, sclk = 0;
750 u_int dcache_size = 0, dsup_banks = 0;
751
752 cpu = CPU;
753 mmu = "none";
754 fpu = "none";
755 revid = bfin_revid();
756 name = bfin_board_name;
757
758 cclk = get_cclk();
759 sclk = get_sclk();
760
761 seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
762 "MMU:\t\t%s\n"
763 "FPU:\t\t%s\n"
764 "Core Clock:\t%9lu Hz\n"
765 "System Clock:\t%9lu Hz\n"
766 "BogoMips:\t%lu.%02lu\n"
767 "Calibration:\t%lu loops\n",
768 cpu, revid, mmu, fpu,
769 cclk,
770 sclk,
771 (loops_per_jiffy * HZ) / 500000,
772 ((loops_per_jiffy * HZ) / 5000) % 100,
773 (loops_per_jiffy * HZ));
774 seq_printf(m, "Board Name:\t%s\n", name);
775 seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
776 seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
777 if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
778 seq_printf(m, "I-CACHE:\tON\n");
779 else
780 seq_printf(m, "I-CACHE:\tOFF\n");
781 if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
782 seq_printf(m, "D-CACHE:\tON"
783#if defined CONFIG_BLKFIN_WB
784 " (write-back)"
785#elif defined CONFIG_BLKFIN_WT
786 " (write-through)"
787#endif
788 "\n");
789 else
790 seq_printf(m, "D-CACHE:\tOFF\n");
791
792
793 switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
794 case ACACHE_BSRAM:
795 seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
796 dcache_size = 16;
797 dsup_banks = 1;
798 break;
799 case ACACHE_BCACHE:
800 seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
801 dcache_size = 32;
802 dsup_banks = 2;
803 break;
804 case ASRAM_BSRAM:
805 seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
806 dcache_size = 0;
807 dsup_banks = 0;
808 break;
809 default:
810 break;
811 }
812
813
814 seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024);
815 seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
816 seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
817 BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES);
818 seq_printf(m,
819 "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
820 dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS,
821 BLKFIN_DLINES);
822#ifdef CONFIG_BLKFIN_CACHE_LOCK
823 switch (read_iloc()) {
824 case WAY0_L:
825 seq_printf(m, "Way0 Locked-Down\n");
826 break;
827 case WAY1_L:
828 seq_printf(m, "Way1 Locked-Down\n");
829 break;
830 case WAY01_L:
831 seq_printf(m, "Way0,Way1 Locked-Down\n");
832 break;
833 case WAY2_L:
834 seq_printf(m, "Way2 Locked-Down\n");
835 break;
836 case WAY02_L:
837 seq_printf(m, "Way0,Way2 Locked-Down\n");
838 break;
839 case WAY12_L:
840 seq_printf(m, "Way1,Way2 Locked-Down\n");
841 break;
842 case WAY012_L:
843 seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
844 break;
845 case WAY3_L:
846 seq_printf(m, "Way3 Locked-Down\n");
847 break;
848 case WAY03_L:
849 seq_printf(m, "Way0,Way3 Locked-Down\n");
850 break;
851 case WAY13_L:
852 seq_printf(m, "Way1,Way3 Locked-Down\n");
853 break;
854 case WAY013_L:
855 seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
856 break;
857 case WAY32_L:
858 seq_printf(m, "Way3,Way2 Locked-Down\n");
859 break;
860 case WAY320_L:
861 seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
862 break;
863 case WAY321_L:
864 seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
865 break;
866 case WAYALL_L:
867 seq_printf(m, "All Ways are locked\n");
868 break;
869 default:
870 seq_printf(m, "No Ways are locked\n");
871 }
872#endif
873 return 0;
874}
875
876static void *c_start(struct seq_file *m, loff_t *pos)
877{
878 return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
879}
880
881static void *c_next(struct seq_file *m, void *v, loff_t *pos)
882{
883 ++*pos;
884 return c_start(m, pos);
885}
886
887static void c_stop(struct seq_file *m, void *v)
888{
889}
890
891struct seq_operations cpuinfo_op = {
892 .start = c_start,
893 .next = c_next,
894 .stop = c_stop,
895 .show = show_cpuinfo,
896};
897
898void cmdline_init(unsigned long r0)
899{
900 if (r0)
901 strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE);
902}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
new file mode 100644
index 000000000000..316e65c3439d
--- /dev/null
+++ b/arch/blackfin/kernel/signal.c
@@ -0,0 +1,356 @@
1/*
2 * File: arch/blackfin/kernel/signal.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/signal.h>
31#include <linux/syscalls.h>
32#include <linux/ptrace.h>
33#include <linux/tty.h>
34#include <linux/personality.h>
35#include <linux/binfmts.h>
36#include <linux/freezer.h>
37
38#include <asm/uaccess.h>
39#include <asm/cacheflush.h>
40#include <asm/ucontext.h>
41
42#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
43
44struct fdpic_func_descriptor {
45 unsigned long text;
46 unsigned long GOT;
47};
48
49struct rt_sigframe {
50 int sig;
51 struct siginfo *pinfo;
52 void *puc;
53 char retcode[8];
54 struct siginfo info;
55 struct ucontext uc;
56};
57
58asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
59{
60 return do_sigaltstack(uss, uoss, rdusp());
61}
62
63static inline int
64rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
65{
66 unsigned long usp = 0;
67 int err = 0;
68
69#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
70
71 /* restore passed registers */
72 RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3);
73 RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7);
74 RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3);
75 RESTORE(p4); RESTORE(p5);
76 err |= __get_user(usp, &sc->sc_usp);
77 wrusp(usp);
78 RESTORE(a0w); RESTORE(a1w);
79 RESTORE(a0x); RESTORE(a1x);
80 RESTORE(astat);
81 RESTORE(rets);
82 RESTORE(pc);
83 RESTORE(retx);
84 RESTORE(fp);
85 RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3);
86 RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3);
87 RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3);
88 RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3);
89 RESTORE(lc0); RESTORE(lc1);
90 RESTORE(lt0); RESTORE(lt1);
91 RESTORE(lb0); RESTORE(lb1);
92 RESTORE(seqstat);
93
94 regs->orig_p0 = -1; /* disable syscall checks */
95
96 *pr0 = regs->r0;
97 return err;
98}
99
100asmlinkage int do_rt_sigreturn(unsigned long __unused)
101{
102 struct pt_regs *regs = (struct pt_regs *)__unused;
103 unsigned long usp = rdusp();
104 struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
105 sigset_t set;
106 int r0;
107
108 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
109 goto badframe;
110 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
111 goto badframe;
112
113 sigdelsetmask(&set, ~_BLOCKABLE);
114 spin_lock_irq(&current->sighand->siglock);
115 current->blocked = set;
116 recalc_sigpending();
117 spin_unlock_irq(&current->sighand->siglock);
118
119 if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
120 goto badframe;
121
122 if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
123 goto badframe;
124
125 return r0;
126
127 badframe:
128 force_sig(SIGSEGV, current);
129 return 0;
130}
131
132static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
133{
134 int err = 0;
135
136#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x)
137
138 SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3);
139 SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7);
140 SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3);
141 SETUP(p4); SETUP(p5);
142 err |= __put_user(rdusp(), &sc->sc_usp);
143 SETUP(a0w); SETUP(a1w);
144 SETUP(a0x); SETUP(a1x);
145 SETUP(astat);
146 SETUP(rets);
147 SETUP(pc);
148 SETUP(retx);
149 SETUP(fp);
150 SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3);
151 SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3);
152 SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3);
153 SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3);
154 SETUP(lc0); SETUP(lc1);
155 SETUP(lt0); SETUP(lt1);
156 SETUP(lb0); SETUP(lb1);
157 SETUP(seqstat);
158
159 return err;
160}
161
162static inline void push_cache(unsigned long vaddr, unsigned int len)
163{
164 flush_icache_range(vaddr, vaddr + len);
165}
166
167static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
168 size_t frame_size)
169{
170 unsigned long usp;
171
172 /* Default to using normal stack. */
173 usp = rdusp();
174
175 /* This is the X/Open sanctioned signal stack switching. */
176 if (ka->sa.sa_flags & SA_ONSTACK) {
177 if (!on_sig_stack(usp))
178 usp = current->sas_ss_sp + current->sas_ss_size;
179 }
180 return (void *)((usp - frame_size) & -8UL);
181}
182
183static int
184setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
185 sigset_t * set, struct pt_regs *regs)
186{
187 struct rt_sigframe *frame;
188 int err = 0;
189
190 frame = get_sigframe(ka, regs, sizeof(*frame));
191
192 err |= __put_user((current_thread_info()->exec_domain
193 && current_thread_info()->exec_domain->signal_invmap
194 && sig < 32
195 ? current_thread_info()->exec_domain->
196 signal_invmap[sig] : sig), &frame->sig);
197
198 err |= __put_user(&frame->info, &frame->pinfo);
199 err |= __put_user(&frame->uc, &frame->puc);
200 err |= copy_siginfo_to_user(&frame->info, info);
201
202 /* Create the ucontext. */
203 err |= __put_user(0, &frame->uc.uc_flags);
204 err |= __put_user(0, &frame->uc.uc_link);
205 err |=
206 __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
207 err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
208 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
209 err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
210 err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
211
212 /* Set up to return from userspace. */
213 err |= __put_user(0x28, &(frame->retcode[0]));
214 err |= __put_user(0xe1, &(frame->retcode[1]));
215 err |= __put_user(0xad, &(frame->retcode[2]));
216 err |= __put_user(0x00, &(frame->retcode[3]));
217 err |= __put_user(0xa0, &(frame->retcode[4]));
218 err |= __put_user(0x00, &(frame->retcode[5]));
219
220 if (err)
221 goto give_sigsegv;
222
223 push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
224
225 /* Set up registers for signal handler */
226 wrusp((unsigned long)frame);
227 if (get_personality & FDPIC_FUNCPTRS) {
228 struct fdpic_func_descriptor __user *funcptr =
229 (struct fdpic_func_descriptor *) ka->sa.sa_handler;
230 __get_user(regs->pc, &funcptr->text);
231 __get_user(regs->p3, &funcptr->GOT);
232 } else
233 regs->pc = (unsigned long)ka->sa.sa_handler;
234 regs->rets = (unsigned long)(frame->retcode);
235
236 regs->r0 = frame->sig;
237 regs->r1 = (unsigned long)(&frame->info);
238 regs->r2 = (unsigned long)(&frame->uc);
239
240 return 0;
241
242 give_sigsegv:
243 if (sig == SIGSEGV)
244 ka->sa.sa_handler = SIG_DFL;
245 force_sig(SIGSEGV, current);
246 return -EFAULT;
247}
248
249static inline void
250handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
251{
252 switch (regs->r0) {
253 case -ERESTARTNOHAND:
254 if (!has_handler)
255 goto do_restart;
256 regs->r0 = -EINTR;
257 break;
258
259 case -ERESTARTSYS:
260 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
261 regs->r0 = -EINTR;
262 break;
263 }
264 /* fallthrough */
265 case -ERESTARTNOINTR:
266 do_restart:
267 regs->p0 = regs->orig_p0;
268 regs->r0 = regs->orig_r0;
269 regs->pc -= 2;
270 break;
271 }
272}
273
274/*
275 * OK, we're invoking a handler
276 */
277static int
278handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
279 sigset_t *oldset, struct pt_regs *regs)
280{
281 int ret;
282
283 /* are we from a system call? to see pt_regs->orig_p0 */
284 if (regs->orig_p0 >= 0)
285 /* If so, check system call restarting.. */
286 handle_restart(regs, ka, 1);
287
288 /* set up the stack frame */
289 ret = setup_rt_frame(sig, ka, info, oldset, regs);
290
291 if (ret == 0) {
292 spin_lock_irq(&current->sighand->siglock);
293 sigorsets(&current->blocked, &current->blocked,
294 &ka->sa.sa_mask);
295 if (!(ka->sa.sa_flags & SA_NODEFER))
296 sigaddset(&current->blocked, sig);
297 recalc_sigpending();
298 spin_unlock_irq(&current->sighand->siglock);
299 }
300 return ret;
301}
302
303/*
304 * Note that 'init' is a special process: it doesn't get signals it doesn't
305 * want to handle. Thus you cannot kill init even with a SIGKILL even by
306 * mistake.
307 *
308 * Note that we go through the signals twice: once to check the signals
309 * that the kernel can handle, and then we build all the user-level signal
310 * handling stack-frames in one go after that.
311 */
312asmlinkage void do_signal(struct pt_regs *regs)
313{
314 siginfo_t info;
315 int signr;
316 struct k_sigaction ka;
317 sigset_t *oldset;
318
319 current->thread.esp0 = (unsigned long)regs;
320
321 if (try_to_freeze())
322 goto no_signal;
323
324 if (test_thread_flag(TIF_RESTORE_SIGMASK))
325 oldset = &current->saved_sigmask;
326 else
327 oldset = &current->blocked;
328
329 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
330 if (signr > 0) {
331 /* Whee! Actually deliver the signal. */
332 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
333 /* a signal was successfully delivered; the saved
334 * sigmask will have been stored in the signal frame,
335 * and will be restored by sigreturn, so we can simply
336 * clear the TIF_RESTORE_SIGMASK flag */
337 if (test_thread_flag(TIF_RESTORE_SIGMASK))
338 clear_thread_flag(TIF_RESTORE_SIGMASK);
339 }
340
341 return;
342 }
343
344no_signal:
345 /* Did we come from a system call? */
346 if (regs->orig_p0 >= 0)
347 /* Restart the system call - no handlers present */
348 handle_restart(regs, NULL, 0);
349
350 /* if there's no signal to deliver, we just put the saved sigmask
351 * back */
352 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
353 clear_thread_flag(TIF_RESTORE_SIGMASK);
354 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
355 }
356}
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
new file mode 100644
index 000000000000..f436e6743f5a
--- /dev/null
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -0,0 +1,115 @@
1/*
2 * File: arch/blackfin/kernel/sys_bfin.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains various random system calls that
8 * have a non-standard calling sequence on the Linux/bfin
9 * platform.
10 *
11 * Modified:
12 * Copyright 2004-2006 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <linux/smp_lock.h>
33#include <linux/spinlock.h>
34#include <linux/sem.h>
35#include <linux/msg.h>
36#include <linux/shm.h>
37#include <linux/syscalls.h>
38#include <linux/mman.h>
39#include <linux/file.h>
40
41#include <asm/cacheflush.h>
42#include <asm/uaccess.h>
43#include <asm/ipc.h>
44#include <asm/dma.h>
45#include <asm/unistd.h>
46
47/*
48 * sys_pipe() is the normal C calling standard for creating
49 * a pipe. It's not the way unix traditionally does this, though.
50 */
51asmlinkage int sys_pipe(unsigned long *fildes)
52{
53 int fd[2];
54 int error;
55
56 error = do_pipe(fd);
57 if (!error) {
58 if (copy_to_user(fildes, fd, 2 * sizeof(int)))
59 error = -EFAULT;
60 }
61 return error;
62}
63
64/* common code for old and new mmaps */
65static inline long
66do_mmap2(unsigned long addr, unsigned long len,
67 unsigned long prot, unsigned long flags,
68 unsigned long fd, unsigned long pgoff)
69{
70 int error = -EBADF;
71 struct file *file = NULL;
72
73 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
74 if (!(flags & MAP_ANONYMOUS)) {
75 file = fget(fd);
76 if (!file)
77 goto out;
78 }
79
80 down_write(&current->mm->mmap_sem);
81 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
82 up_write(&current->mm->mmap_sem);
83
84 if (file)
85 fput(file);
86 out:
87 return error;
88}
89
90asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
91 unsigned long prot, unsigned long flags,
92 unsigned long fd, unsigned long pgoff)
93{
94 return do_mmap2(addr, len, prot, flags, fd, pgoff);
95}
96
97asmlinkage int sys_getpagesize(void)
98{
99 return PAGE_SIZE;
100}
101
102asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
103{
104 return sram_alloc_with_lsl(size, flags);
105}
106
107asmlinkage int sys_sram_free(const void *addr)
108{
109 return sram_free_with_lsl(addr);
110}
111
112asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
113{
114 return safe_dma_memcpy(dest, src, len);
115}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
new file mode 100644
index 000000000000..f578176b6d92
--- /dev/null
+++ b/arch/blackfin/kernel/time.c
@@ -0,0 +1,326 @@
1/*
2 * File: arch/blackfin/kernel/time.c
3 * Based on: none - original work
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the bfin-specific time handling details.
8 * Most of the stuff is located in the machine specific files.
9 *
10 * Modified:
11 * Copyright 2004-2006 Analog Devices Inc.
12 *
13 * Bugs: Enter bugs at http://blackfin.uclinux.org/
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see the file COPYING, or write
27 * to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31#include <linux/module.h>
32#include <linux/profile.h>
33#include <linux/interrupt.h>
34#include <linux/time.h>
35#include <linux/irq.h>
36
37#include <asm/blackfin.h>
38
39/* This is an NTP setting */
40#define TICK_SIZE (tick_nsec / 1000)
41
42static void time_sched_init(irqreturn_t(*timer_routine)
43 (int, void *));
44static unsigned long gettimeoffset(void);
45static inline void do_leds(void);
46
47#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
48void __init init_leds(void)
49{
50 unsigned int tmp = 0;
51
52#if defined(CONFIG_BFIN_ALIVE_LED)
53 /* config pins as output. */
54 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
55 SSYNC();
56 bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
57 SSYNC();
58
59 /* First set led be off */
60 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
61 SSYNC();
62 bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); /* light off */
63 SSYNC();
64#endif
65
66#if defined(CONFIG_BFIN_IDLE_LED)
67 /* config pins as output. */
68 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
69 SSYNC();
70 bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
71 SSYNC();
72
73 /* First set led be off */
74 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
75 SSYNC();
76 bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); /* light off */
77 SSYNC();
78#endif
79}
80#else
81void __init init_leds(void)
82{
83}
84#endif
85
86#if defined(CONFIG_BFIN_ALIVE_LED)
87static inline void do_leds(void)
88{
89 static unsigned int count = 50;
90 static int flag = 0;
91 unsigned short tmp = 0;
92
93 if (--count == 0) {
94 count = 50;
95 flag = ~flag;
96 }
97 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
98 SSYNC();
99
100 if (flag)
101 tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN; /* light on */
102 else
103 tmp |= CONFIG_BFIN_ALIVE_LED_PIN; /* light off */
104
105 bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
106 SSYNC();
107
108}
109#else
110static inline void do_leds(void)
111{
112}
113#endif
114
115static struct irqaction bfin_timer_irq = {
116 .name = "BFIN Timer Tick",
117 .flags = IRQF_DISABLED
118};
119
120/*
121 * The way that the Blackfin core timer works is:
122 * - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
123 * - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
124 *
125 * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
126 * 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
127 * (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
128 * to use TSCALE, and program it to zero (which is pass CCLK through).
129 * If you feel like using it, try to keep HZ * TIMESCALE to some
130 * value that divides easy (like power of 2).
131 */
132
133#define TIME_SCALE 1
134
135static void
136time_sched_init(irqreturn_t(*timer_routine) (int, void *))
137{
138 u32 tcount;
139
140 /* power up the timer, but don't enable it just yet */
141 bfin_write_TCNTL(1);
142 CSYNC();
143
144 /*
145 * the TSCALE prescaler counter.
146 */
147 bfin_write_TSCALE((TIME_SCALE - 1));
148
149 tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
150 bfin_write_TPERIOD(tcount);
151 bfin_write_TCOUNT(tcount);
152
153 /* now enable the timer */
154 CSYNC();
155
156 bfin_write_TCNTL(7);
157
158 bfin_timer_irq.handler = (irq_handler_t)timer_routine;
159 /* call setup_irq instead of request_irq because request_irq calls
160 * kmalloc which has not been initialized yet
161 */
162 setup_irq(IRQ_CORETMR, &bfin_timer_irq);
163}
164
165/*
166 * Should return useconds since last timer tick
167 */
168static unsigned long gettimeoffset(void)
169{
170 unsigned long offset;
171 unsigned long clocks_per_jiffy;
172
173 clocks_per_jiffy = bfin_read_TPERIOD();
174 offset =
175 (clocks_per_jiffy -
176 bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
177 USEC_PER_SEC);
178
179 /* Check if we just wrapped the counters and maybe missed a tick */
180 if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
181 && (offset < (100000 / HZ / 2)))
182 offset += (USEC_PER_SEC / HZ);
183
184 return offset;
185}
186
187static inline int set_rtc_mmss(unsigned long nowtime)
188{
189 return 0;
190}
191
192/*
193 * timer_interrupt() needs to keep up the real-time clock,
194 * as well as call the "do_timer()" routine every clocktick
195 */
196#ifdef CONFIG_CORE_TIMER_IRQ_L1
197irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
198#endif
199
200irqreturn_t timer_interrupt(int irq, void *dummy)
201{
202 /* last time the cmos clock got updated */
203 static long last_rtc_update = 0;
204
205 write_seqlock(&xtime_lock);
206
207 do_timer(1);
208 do_leds();
209
210#ifndef CONFIG_SMP
211 update_process_times(user_mode(get_irq_regs()));
212#endif
213 profile_tick(CPU_PROFILING);
214
215 /*
216 * If we have an externally synchronized Linux clock, then update
217 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
218 * called as close as possible to 500 ms before the new second starts.
219 */
220
221 if (ntp_synced() &&
222 xtime.tv_sec > last_rtc_update + 660 &&
223 (xtime.tv_nsec / NSEC_PER_USEC) >=
224 500000 - ((unsigned)TICK_SIZE) / 2
225 && (xtime.tv_nsec / NSEC_PER_USEC) <=
226 500000 + ((unsigned)TICK_SIZE) / 2) {
227 if (set_rtc_mmss(xtime.tv_sec) == 0)
228 last_rtc_update = xtime.tv_sec;
229 else
230 /* Do it again in 60s. */
231 last_rtc_update = xtime.tv_sec - 600;
232 }
233 write_sequnlock(&xtime_lock);
234 return IRQ_HANDLED;
235}
236
237void __init time_init(void)
238{
239 time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
240
241#ifdef CONFIG_RTC_DRV_BFIN
242 /* [#2663] hack to filter junk RTC values that would cause
243 * userspace to have to deal with time values greater than
244 * 2^31 seconds (which uClibc cannot cope with yet)
245 */
246 if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
247 printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
248 bfin_write_RTC_STAT(0);
249 }
250#endif
251
252 /* Initialize xtime. From now on, xtime is updated with timer interrupts */
253 xtime.tv_sec = secs_since_1970;
254 xtime.tv_nsec = 0;
255
256 wall_to_monotonic.tv_sec = -xtime.tv_sec;
257
258 time_sched_init(timer_interrupt);
259}
260
261#ifndef CONFIG_GENERIC_TIME
262void do_gettimeofday(struct timeval *tv)
263{
264 unsigned long flags;
265 unsigned long seq;
266 unsigned long usec, sec;
267
268 do {
269 seq = read_seqbegin_irqsave(&xtime_lock, flags);
270 usec = gettimeoffset();
271 sec = xtime.tv_sec;
272 usec += (xtime.tv_nsec / NSEC_PER_USEC);
273 }
274 while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
275
276 while (usec >= USEC_PER_SEC) {
277 usec -= USEC_PER_SEC;
278 sec++;
279 }
280
281 tv->tv_sec = sec;
282 tv->tv_usec = usec;
283}
284EXPORT_SYMBOL(do_gettimeofday);
285
286int do_settimeofday(struct timespec *tv)
287{
288 time_t wtm_sec, sec = tv->tv_sec;
289 long wtm_nsec, nsec = tv->tv_nsec;
290
291 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
292 return -EINVAL;
293
294 write_seqlock_irq(&xtime_lock);
295 /*
296 * This is revolting. We need to set the xtime.tv_usec
297 * correctly. However, the value in this location is
298 * is value at the last tick.
299 * Discover what correction gettimeofday
300 * would have done, and then undo it!
301 */
302 nsec -= (gettimeoffset() * NSEC_PER_USEC);
303
304 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
305 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
306
307 set_normalized_timespec(&xtime, sec, nsec);
308 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
309
310 ntp_clear();
311
312 write_sequnlock_irq(&xtime_lock);
313 clock_was_set();
314
315 return 0;
316}
317EXPORT_SYMBOL(do_settimeofday);
318#endif /* !CONFIG_GENERIC_TIME */
319
320/*
321 * Scheduler clock - returns current time in nanosec units.
322 */
323unsigned long long sched_clock(void)
324{
325 return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
326}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
new file mode 100644
index 000000000000..9556b73de808
--- /dev/null
+++ b/arch/blackfin/kernel/traps.c
@@ -0,0 +1,649 @@
1/*
2 * File: arch/blackfin/kernel/traps.c
3 * Based on:
4 * Author: Hamish Macdonald
5 *
6 * Created:
7 * Description: uses S/W interrupt 15 for the system calls
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <asm/uaccess.h>
31#include <asm/traps.h>
32#include <asm/cacheflush.h>
33#include <asm/blackfin.h>
34#include <asm/uaccess.h>
35#include <asm/irq_handler.h>
36#include <linux/interrupt.h>
37#include <linux/module.h>
38#include <linux/kallsyms.h>
39
40#ifdef CONFIG_KGDB
41# include <linux/debugger.h>
42# include <linux/kgdb.h>
43#endif
44
45/* Initiate the event table handler */
46void __init trap_init(void)
47{
48 CSYNC();
49 bfin_write_EVT3(trap);
50 CSYNC();
51}
52
53asmlinkage void trap_c(struct pt_regs *fp);
54
55int kstack_depth_to_print = 48;
56
57static int printk_address(unsigned long address)
58{
59 struct vm_list_struct *vml;
60 struct task_struct *p;
61 struct mm_struct *mm;
62
63#ifdef CONFIG_KALLSYMS
64 unsigned long offset = 0, symsize;
65 const char *symname;
66 char *modname;
67 char *delim = ":";
68 char namebuf[128];
69
70 /* look up the address and see if we are in kernel space */
71 symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
72
73 if (symname) {
74 /* yeah! kernel space! */
75 if (!modname)
76 modname = delim = "";
77 return printk("<0x%p> { %s%s%s%s + 0x%lx }",
78 (void*)address, delim, modname, delim, symname,
79 (unsigned long)offset);
80
81 }
82#endif
83
84 /* looks like we're off in user-land, so let's walk all the
85 * mappings of all our processes and see if we can't be a whee
86 * bit more specific
87 */
88 write_lock_irq(&tasklist_lock);
89 for_each_process(p) {
90 mm = get_task_mm(p);
91 if (!mm)
92 continue;
93
94 vml = mm->context.vmlist;
95 while (vml) {
96 struct vm_area_struct *vma = vml->vma;
97
98 if (address >= vma->vm_start && address < vma->vm_end) {
99 char *name = p->comm;
100 struct file *file = vma->vm_file;
101 if (file) {
102 char _tmpbuf[256];
103 name = d_path(file->f_dentry,
104 file->f_vfsmnt,
105 _tmpbuf,
106 sizeof(_tmpbuf));
107 }
108
109 write_unlock_irq(&tasklist_lock);
110 return printk("<0x%p> [ %s + 0x%lx ]",
111 (void*)address, name,
112 (unsigned long)
113 ((address - vma->vm_start) +
114 (vma->vm_pgoff << PAGE_SHIFT)));
115 }
116
117 vml = vml->next;
118 }
119 }
120 write_unlock_irq(&tasklist_lock);
121
122 /* we were unable to find this address anywhere */
123 return printk("[<0x%p>]", (void*)address);
124}
125
126#define trace_buffer_save(x) \
127 do { \
128 (x) = bfin_read_TBUFCTL(); \
129 bfin_write_TBUFCTL((x) & ~TBUFEN); \
130 } while (0)
131#define trace_buffer_restore(x) \
132 do { \
133 bfin_write_TBUFCTL((x)); \
134 } while (0)
135
136asmlinkage void trap_c(struct pt_regs *fp)
137{
138 int j, sig = 0;
139 siginfo_t info;
140 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
141
142#ifdef CONFIG_KGDB
143# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0)
144# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0)
145#else
146# define CHK_DEBUGGER_TRAP() do { } while (0)
147# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
148#endif
149
150 trace_buffer_save(j);
151
152 /* trap_c() will be called for exceptions. During exceptions
153 * processing, the pc value should be set with retx value.
154 * With this change we can cleanup some code in signal.c- TODO
155 */
156 fp->orig_pc = fp->retx;
157 /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
158 trapnr, fp->ipend, fp->pc, fp->retx); */
159
160 /* send the appropriate signal to the user program */
161 switch (trapnr) {
162
163 /* This table works in conjuction with the one in ./mach-common/entry.S
164 * Some exceptions are handled there (in assembly, in exception space)
165 * Some are handled here, (in C, in interrupt space)
166 * Some, like CPLB, are handled in both, where the normal path is
167 * handled in assembly/exception space, and the error path is handled
168 * here
169 */
170
171 /* 0x00 - Linux Syscall, getting here is an error */
172 /* 0x01 - userspace gdb breakpoint, handled here */
173 case VEC_EXCPT01:
174 info.si_code = TRAP_ILLTRAP;
175 sig = SIGTRAP;
176 CHK_DEBUGGER_TRAP_MAYBE();
177 /* Check if this is a breakpoint in kernel space */
178 if (fp->ipend & 0xffc0)
179 return;
180 else
181 break;
182#ifdef CONFIG_KGDB
183 case VEC_EXCPT02 : /* gdb connection */
184 info.si_code = TRAP_ILLTRAP;
185 sig = SIGTRAP;
186 CHK_DEBUGGER_TRAP();
187 return;
188#else
189 /* 0x02 - User Defined, Caught by default */
190#endif
191 /* 0x03 - Atomic test and set */
192 case VEC_EXCPT03:
193 info.si_code = SEGV_STACKFLOW;
194 sig = SIGSEGV;
195 printk(KERN_EMERG EXC_0x03);
196 CHK_DEBUGGER_TRAP();
197 break;
198 /* 0x04 - spinlock - handled by _ex_spinlock,
199 getting here is an error */
200 /* 0x05 - User Defined, Caught by default */
201 /* 0x06 - User Defined, Caught by default */
202 /* 0x07 - User Defined, Caught by default */
203 /* 0x08 - User Defined, Caught by default */
204 /* 0x09 - User Defined, Caught by default */
205 /* 0x0A - User Defined, Caught by default */
206 /* 0x0B - User Defined, Caught by default */
207 /* 0x0C - User Defined, Caught by default */
208 /* 0x0D - User Defined, Caught by default */
209 /* 0x0E - User Defined, Caught by default */
210 /* 0x0F - User Defined, Caught by default */
211 /* 0x10 HW Single step, handled here */
212 case VEC_STEP:
213 info.si_code = TRAP_STEP;
214 sig = SIGTRAP;
215 CHK_DEBUGGER_TRAP_MAYBE();
216 /* Check if this is a single step in kernel space */
217 if (fp->ipend & 0xffc0)
218 return;
219 else
220 break;
221 /* 0x11 - Trace Buffer Full, handled here */
222 case VEC_OVFLOW:
223 info.si_code = TRAP_TRACEFLOW;
224 sig = SIGTRAP;
225 printk(KERN_EMERG EXC_0x11);
226 CHK_DEBUGGER_TRAP();
227 break;
228 /* 0x12 - Reserved, Caught by default */
229 /* 0x13 - Reserved, Caught by default */
230 /* 0x14 - Reserved, Caught by default */
231 /* 0x15 - Reserved, Caught by default */
232 /* 0x16 - Reserved, Caught by default */
233 /* 0x17 - Reserved, Caught by default */
234 /* 0x18 - Reserved, Caught by default */
235 /* 0x19 - Reserved, Caught by default */
236 /* 0x1A - Reserved, Caught by default */
237 /* 0x1B - Reserved, Caught by default */
238 /* 0x1C - Reserved, Caught by default */
239 /* 0x1D - Reserved, Caught by default */
240 /* 0x1E - Reserved, Caught by default */
241 /* 0x1F - Reserved, Caught by default */
242 /* 0x20 - Reserved, Caught by default */
243 /* 0x21 - Undefined Instruction, handled here */
244 case VEC_UNDEF_I:
245 info.si_code = ILL_ILLOPC;
246 sig = SIGILL;
247 printk(KERN_EMERG EXC_0x21);
248 CHK_DEBUGGER_TRAP();
249 break;
250 /* 0x22 - Illegal Instruction Combination, handled here */
251 case VEC_ILGAL_I:
252 info.si_code = ILL_ILLPARAOP;
253 sig = SIGILL;
254 printk(KERN_EMERG EXC_0x22);
255 CHK_DEBUGGER_TRAP();
256 break;
257 /* 0x23 - Data CPLB Protection Violation,
258 normal case is handled in _cplb_hdr */
259 case VEC_CPLB_VL:
260 info.si_code = ILL_CPLB_VI;
261 sig = SIGILL;
262 printk(KERN_EMERG EXC_0x23);
263 CHK_DEBUGGER_TRAP();
264 break;
265 /* 0x24 - Data access misaligned, handled here */
266 case VEC_MISALI_D:
267 info.si_code = BUS_ADRALN;
268 sig = SIGBUS;
269 printk(KERN_EMERG EXC_0x24);
270 CHK_DEBUGGER_TRAP();
271 break;
272 /* 0x25 - Unrecoverable Event, handled here */
273 case VEC_UNCOV:
274 info.si_code = ILL_ILLEXCPT;
275 sig = SIGILL;
276 printk(KERN_EMERG EXC_0x25);
277 CHK_DEBUGGER_TRAP();
278 break;
279 /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
280 error case is handled here */
281 case VEC_CPLB_M:
282 info.si_code = BUS_ADRALN;
283 sig = SIGBUS;
284 printk(KERN_EMERG EXC_0x26);
285 CHK_DEBUGGER_TRAP();
286 break;
287 /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
288 case VEC_CPLB_MHIT:
289 info.si_code = ILL_CPLB_MULHIT;
290#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
291 sig = SIGSEGV;
292 printk(KERN_EMERG "\n\nNULL pointer access (probably)\n");
293#else
294 sig = SIGILL;
295 printk(KERN_EMERG EXC_0x27);
296#endif
297 CHK_DEBUGGER_TRAP();
298 break;
299 /* 0x28 - Emulation Watchpoint, handled here */
300 case VEC_WATCH:
301 info.si_code = TRAP_WATCHPT;
302 sig = SIGTRAP;
303 pr_debug(EXC_0x28);
304 CHK_DEBUGGER_TRAP_MAYBE();
305 /* Check if this is a watchpoint in kernel space */
306 if (fp->ipend & 0xffc0)
307 return;
308 else
309 break;
310#ifdef CONFIG_BF535
311 /* 0x29 - Instruction fetch access error (535 only) */
312 case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
313 info.si_code = BUS_OPFETCH;
314 sig = SIGBUS;
315 printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n");
316 CHK_DEBUGGER_TRAP();
317 break;
318#else
319 /* 0x29 - Reserved, Caught by default */
320#endif
321 /* 0x2A - Instruction fetch misaligned, handled here */
322 case VEC_MISALI_I:
323 info.si_code = BUS_ADRALN;
324 sig = SIGBUS;
325 printk(KERN_EMERG EXC_0x2A);
326 CHK_DEBUGGER_TRAP();
327 break;
328 /* 0x2B - Instruction CPLB protection Violation,
329 handled in _cplb_hdr */
330 case VEC_CPLB_I_VL:
331 info.si_code = ILL_CPLB_VI;
332 sig = SIGILL;
333 printk(KERN_EMERG EXC_0x2B);
334 CHK_DEBUGGER_TRAP();
335 break;
336 /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
337 case VEC_CPLB_I_M:
338 info.si_code = ILL_CPLB_MISS;
339 sig = SIGBUS;
340 printk(KERN_EMERG EXC_0x2C);
341 CHK_DEBUGGER_TRAP();
342 break;
343 /* 0x2D - Instruction CPLB Multiple Hits, handled here */
344 case VEC_CPLB_I_MHIT:
345 info.si_code = ILL_CPLB_MULHIT;
346#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
347 sig = SIGSEGV;
348 printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n");
349#else
350 sig = SIGILL;
351 printk(KERN_EMERG EXC_0x2D);
352#endif
353 CHK_DEBUGGER_TRAP();
354 break;
355 /* 0x2E - Illegal use of Supervisor Resource, handled here */
356 case VEC_ILL_RES:
357 info.si_code = ILL_PRVOPC;
358 sig = SIGILL;
359 printk(KERN_EMERG EXC_0x2E);
360 CHK_DEBUGGER_TRAP();
361 break;
362 /* 0x2F - Reserved, Caught by default */
363 /* 0x30 - Reserved, Caught by default */
364 /* 0x31 - Reserved, Caught by default */
365 /* 0x32 - Reserved, Caught by default */
366 /* 0x33 - Reserved, Caught by default */
367 /* 0x34 - Reserved, Caught by default */
368 /* 0x35 - Reserved, Caught by default */
369 /* 0x36 - Reserved, Caught by default */
370 /* 0x37 - Reserved, Caught by default */
371 /* 0x38 - Reserved, Caught by default */
372 /* 0x39 - Reserved, Caught by default */
373 /* 0x3A - Reserved, Caught by default */
374 /* 0x3B - Reserved, Caught by default */
375 /* 0x3C - Reserved, Caught by default */
376 /* 0x3D - Reserved, Caught by default */
377 /* 0x3E - Reserved, Caught by default */
378 /* 0x3F - Reserved, Caught by default */
379 default:
380 info.si_code = TRAP_ILLTRAP;
381 sig = SIGTRAP;
382 printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
383 (fp->seqstat & SEQSTAT_EXCAUSE));
384 CHK_DEBUGGER_TRAP();
385 break;
386 }
387
388 info.si_signo = sig;
389 info.si_errno = 0;
390 info.si_addr = (void *)fp->pc;
391 force_sig_info(sig, &info, current);
392 if (sig != 0 && sig != SIGTRAP) {
393 unsigned long stack;
394 dump_bfin_regs(fp, (void *)fp->retx);
395 dump_bfin_trace_buffer();
396 show_stack(current, &stack);
397 if (current->mm == NULL)
398 panic("Kernel exception");
399 }
400
401 /* if the address that we are about to return to is not valid, set it
402 * to a valid address, if we have a current application or panic
403 */
404 if (!(fp->pc <= physical_mem_end
405#if L1_CODE_LENGTH != 0
406 || (fp->pc >= L1_CODE_START &&
407 fp->pc <= (L1_CODE_START + L1_CODE_LENGTH))
408#endif
409 )) {
410 if (current->mm) {
411 fp->pc = current->mm->start_code;
412 } else {
413 printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n");
414 panic("Help - I've fallen and can't get up\n");
415 }
416 }
417
418 trace_buffer_restore(j);
419 return;
420}
421
422/* Typical exception handling routines */
423
424void dump_bfin_trace_buffer(void)
425{
426 int tflags;
427 trace_buffer_save(tflags);
428
429 if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
430 int i;
431 printk(KERN_EMERG "Hardware Trace:\n");
432 for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
433 printk(KERN_EMERG "%2i Target : ", i);
434 printk_address((unsigned long)bfin_read_TBUF());
435 printk("\n" KERN_EMERG " Source : ");
436 printk_address((unsigned long)bfin_read_TBUF());
437 printk("\n");
438 }
439 }
440
441 trace_buffer_restore(tflags);
442}
443EXPORT_SYMBOL(dump_bfin_trace_buffer);
444
445static void show_trace(struct task_struct *tsk, unsigned long *sp)
446{
447 unsigned long addr;
448
449 printk("\nCall Trace:");
450#ifdef CONFIG_KALLSYMS
451 printk("\n");
452#endif
453
454 while (!kstack_end(sp)) {
455 addr = *sp++;
456 /*
457 * If the address is either in the text segment of the
458 * kernel, or in the region which contains vmalloc'ed
459 * memory, it *may* be the address of a calling
460 * routine; if so, print it so that someone tracing
461 * down the cause of the crash will be able to figure
462 * out the call path that was taken.
463 */
464 if (kernel_text_address(addr))
465 print_ip_sym(addr);
466 }
467
468 printk("\n");
469}
470
471void show_stack(struct task_struct *task, unsigned long *stack)
472{
473 unsigned long *endstack, addr;
474 int i;
475
476 /* Cannot call dump_bfin_trace_buffer() here as show_stack() is
477 * called externally in some places in the kernel.
478 */
479
480 if (!stack) {
481 if (task)
482 stack = (unsigned long *)task->thread.ksp;
483 else
484 stack = (unsigned long *)&stack;
485 }
486
487 addr = (unsigned long)stack;
488 endstack = (unsigned long *)PAGE_ALIGN(addr);
489
490 printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
491 for (i = 0; i < kstack_depth_to_print; i++) {
492 if (stack + 1 > endstack)
493 break;
494 if (i % 8 == 0)
495 printk("\n" KERN_EMERG " ");
496 printk(" %08lx", *stack++);
497 }
498
499 show_trace(task, stack);
500}
501
502void dump_stack(void)
503{
504 unsigned long stack;
505 int tflags;
506 trace_buffer_save(tflags);
507 dump_bfin_trace_buffer();
508 show_stack(current, &stack);
509 trace_buffer_restore(tflags);
510}
511
512EXPORT_SYMBOL(dump_stack);
513
514void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
515{
516 if (current->pid) {
517 printk("\nCURRENT PROCESS:\n\n");
518 printk("COMM=%s PID=%d\n", current->comm, current->pid);
519 } else {
520 printk
521 ("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n");
522 }
523
524 if (current->mm) {
525 printk("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
526 "BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n",
527 (void*)current->mm->start_code,
528 (void*)current->mm->end_code,
529 (void*)current->mm->start_data,
530 (void*)current->mm->end_data,
531 (void*)current->mm->end_data,
532 (void*)current->mm->brk,
533 (void*)current->mm->start_stack);
534 }
535
536 printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr);
537 if (retaddr != 0 && retaddr <= (void*)physical_mem_end
538#if L1_CODE_LENGTH != 0
539 /* FIXME: Copy the code out of L1 Instruction SRAM through dma
540 memcpy. */
541 && !(retaddr >= (void*)L1_CODE_START
542 && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
543#endif
544 ) {
545 int i = 0;
546 unsigned short x = 0;
547 for (i = -16; i < 8; i++) {
548 if (get_user(x, (unsigned short *)retaddr + i))
549 break;
550#ifndef CONFIG_DEBUG_HWERR
551 /* If one of the last few instructions was a STI
552 * it is likily that the error occured awhile ago
553 * and we just noticed
554 */
555 if (x >= 0x0040 && x <= 0x0047 && i <= 0)
556 panic("\n\nWARNING : You should reconfigure the kernel to turn on\n"
557 " 'Hardware error interrupt debugging'\n"
558 " The rest of this error is meanless\n");
559#endif
560
561 if (i == -8)
562 printk("\n");
563 if (i == 0)
564 printk("X\n");
565 printk("%04x ", x);
566 }
567 } else
568 printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n");
569
570 printk("\n\n");
571
572 printk("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n",
573 fp->rete, fp->retn, fp->retx, fp->rets);
574 printk("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg);
575 printk("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp);
576 printk("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
577 fp->r0, fp->r1, fp->r2, fp->r3);
578 printk("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
579 fp->r4, fp->r5, fp->r6, fp->r7);
580 printk("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
581 fp->p0, fp->p1, fp->p2, fp->p3);
582 printk("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp);
583 printk("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
584 fp->a0w, fp->a0x, fp->a1w, fp->a1x);
585
586 printk("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0,
587 fp->lc0);
588 printk("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1,
589 fp->lc1);
590 printk("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0,
591 fp->m0, fp->i0);
592 printk("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1,
593 fp->m1, fp->i1);
594 printk("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2,
595 fp->m2, fp->i2);
596 printk("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3,
597 fp->m3, fp->i3);
598
599 printk("\nUSP: %08lx ASTAT: %08lx\n", rdusp(), fp->astat);
600 if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
601 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
602 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
603 }
604
605 printk("\n\n");
606}
607
608#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
609asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
610#endif
611
612asmlinkage int sys_bfin_spinlock(int *spinlock)
613{
614 int ret = 0;
615 int tmp = 0;
616
617 local_irq_disable();
618 ret = get_user(tmp, spinlock);
619 if (ret == 0) {
620 if (tmp)
621 ret = 1;
622 tmp = 1;
623 put_user(tmp, spinlock);
624 }
625 local_irq_enable();
626 return ret;
627}
628
629void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
630{
631 switch (cplb_panic) {
632 case CPLB_NO_UNLOCKED:
633 printk(KERN_EMERG "All CPLBs are locked\n");
634 break;
635 case CPLB_PROT_VIOL:
636 return;
637 case CPLB_NO_ADDR_MATCH:
638 return;
639 case CPLB_UNKNOWN_ERR:
640 printk(KERN_EMERG "Unknown CPLB Exception\n");
641 break;
642 }
643
644 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
645 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
646 dump_bfin_regs(fp, (void *)fp->retx);
647 dump_stack();
648 panic("Unrecoverable event\n");
649}
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..6ae9ebbd8e58
--- /dev/null
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -0,0 +1,228 @@
1/*
2 * File: arch/blackfin/kernel/vmlinux.lds.S
3 * Based on: none - original work
4 * Author:
5 *
6 * Created: Tue Sep 21 2004
7 * Description: Master linker script for blackfin architecture
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#define VMLINUX_SYMBOL(_sym_) _##_sym_
31
32#include <asm-generic/vmlinux.lds.h>
33#include <asm/mem_map.h>
34
35
36OUTPUT_FORMAT("elf32-bfin")
37ENTRY(__start)
38_jiffies = _jiffies_64;
39
40MEMORY
41{
42 ram : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD)
43 l1_data_a : ORIGIN = L1_DATA_A_START, LENGTH = L1_DATA_A_LENGTH
44 l1_data_b : ORIGIN = L1_DATA_B_START, LENGTH = L1_DATA_B_LENGTH
45 l1_code : ORIGIN = L1_CODE_START, LENGTH = L1_CODE_LENGTH
46 l1_scratch : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH
47}
48
49SECTIONS
50{
51 . = CONFIG_BOOT_LOAD;
52
53 .text :
54 {
55 _text = .;
56 __stext = .;
57 *(.text)
58 SCHED_TEXT
59 *(.text.lock)
60 . = ALIGN(16);
61 ___start___ex_table = .;
62 *(__ex_table)
63 ___stop___ex_table = .;
64
65 *($code)
66 *(.rodata)
67 *(.rodata.*)
68 *(__vermagic) /* Kernel version magic */
69 *(.rodata1)
70 *(.fixup)
71 *(.spinlock.text)
72
73 /* Kernel symbol table: Normal symbols */
74 . = ALIGN(4);
75 ___start___ksymtab = .;
76 *(__ksymtab)
77 ___stop___ksymtab = .;
78
79 /* Kernel symbol table: GPL-only symbols */
80 ___start___ksymtab_gpl = .;
81 *(__ksymtab_gpl)
82 ___stop___ksymtab_gpl = .;
83
84 /* Kernel symbol table: Normal unused symbols */ \
85 ___start___ksymtab_unused = .;
86 *(__ksymtab_unused)
87 ___stop___ksymtab_unused = .;
88
89 /* Kernel symbol table: GPL-only unused symbols */
90 ___start___ksymtab_unused_gpl = .;
91 *(__ksymtab_unused_gpl)
92 ___stop___ksymtab_unused_gpl = .;
93
94
95 /* Kernel symbol table: GPL-future symbols */
96 ___start___ksymtab_gpl_future = .;
97 *(__ksymtab_gpl_future)
98 ___stop___ksymtab_gpl_future = .;
99
100 /* Kernel symbol table: Normal symbols */
101 ___start___kcrctab = .;
102 *(__kcrctab)
103 ___stop___kcrctab = .;
104
105 /* Kernel symbol table: GPL-only symbols */
106 ___start___kcrctab_gpl = .;
107 *(__kcrctab_gpl)
108 ___stop___kcrctab_gpl = .;
109
110 /* Kernel symbol table: GPL-future symbols */
111 ___start___kcrctab_gpl_future = .;
112 *(__kcrctab_gpl_future)
113 ___stop___kcrctab_gpl_future = .;
114
115 /* Kernel symbol table: strings */
116 *(__ksymtab_strings)
117
118 . = ALIGN(4);
119 __etext = .;
120 } > ram
121
122 .init :
123 {
124 . = ALIGN(4096);
125 ___init_begin = .;
126 __sinittext = .;
127 *(.init.text)
128 __einittext = .;
129 *(.init.data)
130 . = ALIGN(16);
131 ___setup_start = .;
132 *(.init.setup)
133 ___setup_end = .;
134 ___start___param = .;
135 *(__param)
136 ___stop___param = .;
137 ___initcall_start = .;
138 INITCALLS
139 ___initcall_end = .;
140 ___con_initcall_start = .;
141 *(.con_initcall.init)
142 ___con_initcall_end = .;
143 ___security_initcall_start = .;
144 *(.security_initcall.init)
145 ___security_initcall_end = .;
146 . = ALIGN(4);
147 ___initramfs_start = .;
148 *(.init.ramfs)
149 ___initramfs_end = .;
150 . = ALIGN(4);
151 ___init_end = .;
152 } > ram
153
154 __l1_lma_start = .;
155
156 .text_l1 :
157 {
158 . = ALIGN(4);
159 __stext_l1 = .;
160 *(.l1.text)
161
162 . = ALIGN(4);
163 __etext_l1 = .;
164 } > l1_code AT > ram
165
166 .data_l1 :
167 {
168 . = ALIGN(4);
169 __sdata_l1 = .;
170 *(.l1.data)
171 __edata_l1 = .;
172
173 . = ALIGN(4);
174 __sbss_l1 = .;
175 *(.l1.bss)
176
177 . = ALIGN(32);
178 *(.data_l1.cacheline_aligned)
179
180 . = ALIGN(4);
181 __ebss_l1 = .;
182 } > l1_data_a AT > ram
183 .data_b_l1 :
184 {
185 . = ALIGN(4);
186 __sdata_b_l1 = .;
187 *(.l1.data.B)
188 __edata_b_l1 = .;
189
190 . = ALIGN(4);
191 __sbss_b_l1 = .;
192 *(.l1.bss.B)
193
194 . = ALIGN(4);
195 __ebss_b_l1 = .;
196 } > l1_data_b AT > ram
197
198 .data :
199 {
200 __sdata = .;
201 . = ALIGN(0x2000);
202 *(.data.init_task)
203 *(.data)
204
205 . = ALIGN(32);
206 *(.data.cacheline_aligned)
207
208 . = ALIGN(0x2000);
209 __edata = .;
210 } > ram
211
212 /DISCARD/ : { /* Exit code and data*/
213 *(.exit.text)
214 *(.exit.data)
215 *(.exitcall.exit)
216 } > ram
217
218 .bss :
219 {
220 . = ALIGN(4);
221 ___bss_start = .;
222 *(.bss)
223 *(COMMON)
224 . = ALIGN(4);
225 ___bss_stop = .;
226 __end = . ;
227 } > ram
228}