aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /arch/arm/kernel
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/atags.c83
-rw-r--r--arch/arm/kernel/compat.c219
-rw-r--r--arch/arm/kernel/compat.h11
-rw-r--r--arch/arm/kernel/cpu_pm.c116
-rw-r--r--arch/arm/kernel/crunch-bits.S305
-rw-r--r--arch/arm/kernel/crunch.c88
-rw-r--r--arch/arm/kernel/ecard.c1241
-rw-r--r--arch/arm/kernel/ecard.h69
-rw-r--r--arch/arm/kernel/init_task.c37
-rw-r--r--arch/arm/kernel/leds.c144
-rw-r--r--arch/arm/kernel/pmu.c201
11 files changed, 2514 insertions, 0 deletions
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c
new file mode 100644
index 00000000000..42a1a1415fa
--- /dev/null
+++ b/arch/arm/kernel/atags.c
@@ -0,0 +1,83 @@
1#include <linux/slab.h>
2#include <linux/proc_fs.h>
3#include <asm/setup.h>
4#include <asm/types.h>
5#include <asm/page.h>
6
7struct buffer {
8 size_t size;
9 char data[];
10};
11
12static int
13read_buffer(char* page, char** start, off_t off, int count,
14 int* eof, void* data)
15{
16 struct buffer *buffer = (struct buffer *)data;
17
18 if (off >= buffer->size) {
19 *eof = 1;
20 return 0;
21 }
22
23 count = min((int) (buffer->size - off), count);
24
25 memcpy(page, &buffer->data[off], count);
26
27 return count;
28}
29
30#define BOOT_PARAMS_SIZE 1536
31static char __initdata atags_copy[BOOT_PARAMS_SIZE];
32
33void __init save_atags(const struct tag *tags)
34{
35 memcpy(atags_copy, tags, sizeof(atags_copy));
36}
37
38static int __init init_atags_procfs(void)
39{
40 /*
41 * This cannot go into save_atags() because kmalloc and proc don't work
42 * yet when it is called.
43 */
44 struct proc_dir_entry *tags_entry;
45 struct tag *tag = (struct tag *)atags_copy;
46 struct buffer *b;
47 size_t size;
48
49 if (tag->hdr.tag != ATAG_CORE) {
50 printk(KERN_INFO "No ATAGs?");
51 return -EINVAL;
52 }
53
54 for (; tag->hdr.size; tag = tag_next(tag))
55 ;
56
57 /* include the terminating ATAG_NONE */
58 size = (char *)tag - atags_copy + sizeof(struct tag_header);
59
60 WARN_ON(tag->hdr.tag != ATAG_NONE);
61
62 b = kmalloc(sizeof(*b) + size, GFP_KERNEL);
63 if (!b)
64 goto nomem;
65
66 b->size = size;
67 memcpy(b->data, atags_copy, size);
68
69 tags_entry = create_proc_read_entry("atags", 0400,
70 NULL, read_buffer, b);
71
72 if (!tags_entry)
73 goto nomem;
74
75 return 0;
76
77nomem:
78 kfree(b);
79 printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
80
81 return -ENOMEM;
82}
83arch_initcall(init_atags_procfs);
diff --git a/arch/arm/kernel/compat.c b/arch/arm/kernel/compat.c
new file mode 100644
index 00000000000..925652318b8
--- /dev/null
+++ b/arch/arm/kernel/compat.c
@@ -0,0 +1,219 @@
1/*
2 * linux/arch/arm/kernel/compat.c
3 *
4 * Copyright (C) 2001 Russell King
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 version 2 as
8 * published by the Free Software Foundation.
9 *
10 * We keep the old params compatibility cruft in one place (here)
11 * so we don't end up with lots of mess around other places.
12 *
13 * NOTE:
14 * The old struct param_struct is deprecated, but it will be kept in
15 * the kernel for 5 years from now (2001). This will allow boot loaders
16 * to convert to the new struct tag way.
17 */
18#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/init.h>
22
23#include <asm/setup.h>
24#include <asm/mach-types.h>
25#include <asm/page.h>
26
27#include <asm/mach/arch.h>
28
29#include "compat.h"
30
31/*
32 * Usage:
33 * - do not go blindly adding fields, add them at the end
34 * - when adding fields, don't rely on the address until
35 * a patch from me has been released
36 * - unused fields should be zero (for future expansion)
37 * - this structure is relatively short-lived - only
38 * guaranteed to contain useful data in setup_arch()
39 *
40 * This is the old deprecated way to pass parameters to the kernel
41 */
42struct param_struct {
43 union {
44 struct {
45 unsigned long page_size; /* 0 */
46 unsigned long nr_pages; /* 4 */
47 unsigned long ramdisk_size; /* 8 */
48 unsigned long flags; /* 12 */
49#define FLAG_READONLY 1
50#define FLAG_RDLOAD 4
51#define FLAG_RDPROMPT 8
52 unsigned long rootdev; /* 16 */
53 unsigned long video_num_cols; /* 20 */
54 unsigned long video_num_rows; /* 24 */
55 unsigned long video_x; /* 28 */
56 unsigned long video_y; /* 32 */
57 unsigned long memc_control_reg; /* 36 */
58 unsigned char sounddefault; /* 40 */
59 unsigned char adfsdrives; /* 41 */
60 unsigned char bytes_per_char_h; /* 42 */
61 unsigned char bytes_per_char_v; /* 43 */
62 unsigned long pages_in_bank[4]; /* 44 */
63 unsigned long pages_in_vram; /* 60 */
64 unsigned long initrd_start; /* 64 */
65 unsigned long initrd_size; /* 68 */
66 unsigned long rd_start; /* 72 */
67 unsigned long system_rev; /* 76 */
68 unsigned long system_serial_low; /* 80 */
69 unsigned long system_serial_high; /* 84 */
70 unsigned long mem_fclk_21285; /* 88 */
71 } s;
72 char unused[256];
73 } u1;
74 union {
75 char paths[8][128];
76 struct {
77 unsigned long magic;
78 char n[1024 - sizeof(unsigned long)];
79 } s;
80 } u2;
81 char commandline[COMMAND_LINE_SIZE];
82};
83
84static struct tag * __init memtag(struct tag *tag, unsigned long start, unsigned long size)
85{
86 tag = tag_next(tag);
87 tag->hdr.tag = ATAG_MEM;
88 tag->hdr.size = tag_size(tag_mem32);
89 tag->u.mem.size = size;
90 tag->u.mem.start = start;
91
92 return tag;
93}
94
95static void __init build_tag_list(struct param_struct *params, void *taglist)
96{
97 struct tag *tag = taglist;
98
99 if (params->u1.s.page_size != PAGE_SIZE) {
100 printk(KERN_WARNING "Warning: bad configuration page, "
101 "trying to continue\n");
102 return;
103 }
104
105 printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
106
107#ifdef CONFIG_ARCH_NETWINDER
108 if (params->u1.s.nr_pages != 0x02000 &&
109 params->u1.s.nr_pages != 0x04000 &&
110 params->u1.s.nr_pages != 0x08000 &&
111 params->u1.s.nr_pages != 0x10000) {
112 printk(KERN_WARNING "Warning: bad NeTTrom parameters "
113 "detected, using defaults\n");
114
115 params->u1.s.nr_pages = 0x1000; /* 16MB */
116 params->u1.s.ramdisk_size = 0;
117 params->u1.s.flags = FLAG_READONLY;
118 params->u1.s.initrd_start = 0;
119 params->u1.s.initrd_size = 0;
120 params->u1.s.rd_start = 0;
121 }
122#endif
123
124 tag->hdr.tag = ATAG_CORE;
125 tag->hdr.size = tag_size(tag_core);
126 tag->u.core.flags = params->u1.s.flags & FLAG_READONLY;
127 tag->u.core.pagesize = params->u1.s.page_size;
128 tag->u.core.rootdev = params->u1.s.rootdev;
129
130 tag = tag_next(tag);
131 tag->hdr.tag = ATAG_RAMDISK;
132 tag->hdr.size = tag_size(tag_ramdisk);
133 tag->u.ramdisk.flags = (params->u1.s.flags & FLAG_RDLOAD ? 1 : 0) |
134 (params->u1.s.flags & FLAG_RDPROMPT ? 2 : 0);
135 tag->u.ramdisk.size = params->u1.s.ramdisk_size;
136 tag->u.ramdisk.start = params->u1.s.rd_start;
137
138 tag = tag_next(tag);
139 tag->hdr.tag = ATAG_INITRD;
140 tag->hdr.size = tag_size(tag_initrd);
141 tag->u.initrd.start = params->u1.s.initrd_start;
142 tag->u.initrd.size = params->u1.s.initrd_size;
143
144 tag = tag_next(tag);
145 tag->hdr.tag = ATAG_SERIAL;
146 tag->hdr.size = tag_size(tag_serialnr);
147 tag->u.serialnr.low = params->u1.s.system_serial_low;
148 tag->u.serialnr.high = params->u1.s.system_serial_high;
149
150 tag = tag_next(tag);
151 tag->hdr.tag = ATAG_REVISION;
152 tag->hdr.size = tag_size(tag_revision);
153 tag->u.revision.rev = params->u1.s.system_rev;
154
155#ifdef CONFIG_ARCH_ACORN
156 if (machine_is_riscpc()) {
157 int i;
158 for (i = 0; i < 4; i++)
159 tag = memtag(tag, PHYS_OFFSET + (i << 26),
160 params->u1.s.pages_in_bank[i] * PAGE_SIZE);
161 } else
162#endif
163 tag = memtag(tag, PHYS_OFFSET, params->u1.s.nr_pages * PAGE_SIZE);
164
165#ifdef CONFIG_FOOTBRIDGE
166 if (params->u1.s.mem_fclk_21285) {
167 tag = tag_next(tag);
168 tag->hdr.tag = ATAG_MEMCLK;
169 tag->hdr.size = tag_size(tag_memclk);
170 tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285;
171 }
172#endif
173
174#ifdef CONFIG_ARCH_EBSA285
175 if (machine_is_ebsa285()) {
176 tag = tag_next(tag);
177 tag->hdr.tag = ATAG_VIDEOTEXT;
178 tag->hdr.size = tag_size(tag_videotext);
179 tag->u.videotext.x = params->u1.s.video_x;
180 tag->u.videotext.y = params->u1.s.video_y;
181 tag->u.videotext.video_page = 0;
182 tag->u.videotext.video_mode = 0;
183 tag->u.videotext.video_cols = params->u1.s.video_num_cols;
184 tag->u.videotext.video_ega_bx = 0;
185 tag->u.videotext.video_lines = params->u1.s.video_num_rows;
186 tag->u.videotext.video_isvga = 1;
187 tag->u.videotext.video_points = 8;
188 }
189#endif
190
191#ifdef CONFIG_ARCH_ACORN
192 tag = tag_next(tag);
193 tag->hdr.tag = ATAG_ACORN;
194 tag->hdr.size = tag_size(tag_acorn);
195 tag->u.acorn.memc_control_reg = params->u1.s.memc_control_reg;
196 tag->u.acorn.vram_pages = params->u1.s.pages_in_vram;
197 tag->u.acorn.sounddefault = params->u1.s.sounddefault;
198 tag->u.acorn.adfsdrives = params->u1.s.adfsdrives;
199#endif
200
201 tag = tag_next(tag);
202 tag->hdr.tag = ATAG_CMDLINE;
203 tag->hdr.size = (strlen(params->commandline) + 3 +
204 sizeof(struct tag_header)) >> 2;
205 strcpy(tag->u.cmdline.cmdline, params->commandline);
206
207 tag = tag_next(tag);
208 tag->hdr.tag = ATAG_NONE;
209 tag->hdr.size = 0;
210
211 memmove(params, taglist, ((int)tag) - ((int)taglist) +
212 sizeof(struct tag_header));
213}
214
215void __init convert_to_tag_list(struct tag *tags)
216{
217 struct param_struct *params = (struct param_struct *)tags;
218 build_tag_list(params, &params->u2);
219}
diff --git a/arch/arm/kernel/compat.h b/arch/arm/kernel/compat.h
new file mode 100644
index 00000000000..39264ab1b9c
--- /dev/null
+++ b/arch/arm/kernel/compat.h
@@ -0,0 +1,11 @@
1/*
2 * linux/arch/arm/kernel/compat.h
3 *
4 * Copyright (C) 2001 Russell King
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 version 2 as
8 * published by the Free Software Foundation.
9*/
10
11extern void convert_to_tag_list(struct tag *tags);
diff --git a/arch/arm/kernel/cpu_pm.c b/arch/arm/kernel/cpu_pm.c
new file mode 100644
index 00000000000..748af1f1f43
--- /dev/null
+++ b/arch/arm/kernel/cpu_pm.c
@@ -0,0 +1,116 @@
1/*
2 * Copyright (C) 2011 Google, Inc.
3 *
4 * Author:
5 * Colin Cross <ccross@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
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 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/notifier.h>
21#include <linux/spinlock.h>
22
23#include <asm/cpu_pm.h>
24
25static DEFINE_RWLOCK(cpu_pm_notifier_lock);
26static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
27
28int cpu_pm_register_notifier(struct notifier_block *nb)
29{
30 unsigned long flags;
31 int ret;
32
33 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
34 ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
35 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
36
37 return ret;
38}
39EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
40
41int cpu_pm_unregister_notifier(struct notifier_block *nb)
42{
43 unsigned long flags;
44 int ret;
45
46 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
47 ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
48 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
49
50 return ret;
51}
52EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
53
54static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
55{
56 int ret;
57
58 ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
59 nr_to_call, nr_calls);
60
61 return notifier_to_errno(ret);
62}
63
64int cpu_pm_enter(void)
65{
66 int nr_calls;
67 int ret = 0;
68
69 read_lock(&cpu_pm_notifier_lock);
70 ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
71 if (ret)
72 cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
73 read_unlock(&cpu_pm_notifier_lock);
74
75 return ret;
76}
77EXPORT_SYMBOL_GPL(cpu_pm_enter);
78
79int cpu_pm_exit(void)
80{
81 int ret;
82
83 read_lock(&cpu_pm_notifier_lock);
84 ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
85 read_unlock(&cpu_pm_notifier_lock);
86
87 return ret;
88}
89EXPORT_SYMBOL_GPL(cpu_pm_exit);
90
91int cpu_complex_pm_enter(void)
92{
93 int nr_calls;
94 int ret = 0;
95
96 read_lock(&cpu_pm_notifier_lock);
97 ret = cpu_pm_notify(CPU_COMPLEX_PM_ENTER, -1, &nr_calls);
98 if (ret)
99 cpu_pm_notify(CPU_COMPLEX_PM_ENTER_FAILED, nr_calls - 1, NULL);
100 read_unlock(&cpu_pm_notifier_lock);
101
102 return ret;
103}
104EXPORT_SYMBOL_GPL(cpu_complex_pm_enter);
105
106int cpu_complex_pm_exit(void)
107{
108 int ret;
109
110 read_lock(&cpu_pm_notifier_lock);
111 ret = cpu_pm_notify(CPU_COMPLEX_PM_EXIT, -1, NULL);
112 read_unlock(&cpu_pm_notifier_lock);
113
114 return ret;
115}
116EXPORT_SYMBOL_GPL(cpu_complex_pm_exit);
diff --git a/arch/arm/kernel/crunch-bits.S b/arch/arm/kernel/crunch-bits.S
new file mode 100644
index 00000000000..0ec9bb48fab
--- /dev/null
+++ b/arch/arm/kernel/crunch-bits.S
@@ -0,0 +1,305 @@
1/*
2 * arch/arm/kernel/crunch-bits.S
3 * Cirrus MaverickCrunch context switching and handling
4 *
5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
6 *
7 * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
8 * Copyright (c) 2003-2004, MontaVista Software, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/linkage.h>
16#include <asm/ptrace.h>
17#include <asm/thread_info.h>
18#include <asm/asm-offsets.h>
19#include <mach/ep93xx-regs.h>
20
21/*
22 * We can't use hex constants here due to a bug in gas.
23 */
24#define CRUNCH_MVDX0 0
25#define CRUNCH_MVDX1 8
26#define CRUNCH_MVDX2 16
27#define CRUNCH_MVDX3 24
28#define CRUNCH_MVDX4 32
29#define CRUNCH_MVDX5 40
30#define CRUNCH_MVDX6 48
31#define CRUNCH_MVDX7 56
32#define CRUNCH_MVDX8 64
33#define CRUNCH_MVDX9 72
34#define CRUNCH_MVDX10 80
35#define CRUNCH_MVDX11 88
36#define CRUNCH_MVDX12 96
37#define CRUNCH_MVDX13 104
38#define CRUNCH_MVDX14 112
39#define CRUNCH_MVDX15 120
40#define CRUNCH_MVAX0L 128
41#define CRUNCH_MVAX0M 132
42#define CRUNCH_MVAX0H 136
43#define CRUNCH_MVAX1L 140
44#define CRUNCH_MVAX1M 144
45#define CRUNCH_MVAX1H 148
46#define CRUNCH_MVAX2L 152
47#define CRUNCH_MVAX2M 156
48#define CRUNCH_MVAX2H 160
49#define CRUNCH_MVAX3L 164
50#define CRUNCH_MVAX3M 168
51#define CRUNCH_MVAX3H 172
52#define CRUNCH_DSPSC 176
53
54#define CRUNCH_SIZE 184
55
56 .text
57
58/*
59 * Lazy switching of crunch coprocessor context
60 *
61 * r10 = struct thread_info pointer
62 * r9 = ret_from_exception
63 * lr = undefined instr exit
64 *
65 * called from prefetch exception handler with interrupts disabled
66 */
67ENTRY(crunch_task_enable)
68 ldr r8, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr
69
70 ldr r1, [r8, #0x80]
71 tst r1, #0x00800000 @ access to crunch enabled?
72 movne pc, lr @ if so no business here
73 mov r3, #0xaa @ unlock syscon swlock
74 str r3, [r8, #0xc0]
75 orr r1, r1, #0x00800000 @ enable access to crunch
76 str r1, [r8, #0x80]
77
78 ldr r3, =crunch_owner
79 add r0, r10, #TI_CRUNCH_STATE @ get task crunch save area
80 ldr r2, [sp, #60] @ current task pc value
81 ldr r1, [r3] @ get current crunch owner
82 str r0, [r3] @ this task now owns crunch
83 sub r2, r2, #4 @ adjust pc back
84 str r2, [sp, #60]
85
86 ldr r2, [r8, #0x80]
87 mov r2, r2 @ flush out enable (@@@)
88
89 teq r1, #0 @ test for last ownership
90 mov lr, r9 @ normal exit from exception
91 beq crunch_load @ no owner, skip save
92
93crunch_save:
94 cfstr64 mvdx0, [r1, #CRUNCH_MVDX0] @ save 64b registers
95 cfstr64 mvdx1, [r1, #CRUNCH_MVDX1]
96 cfstr64 mvdx2, [r1, #CRUNCH_MVDX2]
97 cfstr64 mvdx3, [r1, #CRUNCH_MVDX3]
98 cfstr64 mvdx4, [r1, #CRUNCH_MVDX4]
99 cfstr64 mvdx5, [r1, #CRUNCH_MVDX5]
100 cfstr64 mvdx6, [r1, #CRUNCH_MVDX6]
101 cfstr64 mvdx7, [r1, #CRUNCH_MVDX7]
102 cfstr64 mvdx8, [r1, #CRUNCH_MVDX8]
103 cfstr64 mvdx9, [r1, #CRUNCH_MVDX9]
104 cfstr64 mvdx10, [r1, #CRUNCH_MVDX10]
105 cfstr64 mvdx11, [r1, #CRUNCH_MVDX11]
106 cfstr64 mvdx12, [r1, #CRUNCH_MVDX12]
107 cfstr64 mvdx13, [r1, #CRUNCH_MVDX13]
108 cfstr64 mvdx14, [r1, #CRUNCH_MVDX14]
109 cfstr64 mvdx15, [r1, #CRUNCH_MVDX15]
110
111#ifdef __ARMEB__
112#error fix me for ARMEB
113#endif
114
115 cfmv32al mvfx0, mvax0 @ save 72b accumulators
116 cfstr32 mvfx0, [r1, #CRUNCH_MVAX0L]
117 cfmv32am mvfx0, mvax0
118 cfstr32 mvfx0, [r1, #CRUNCH_MVAX0M]
119 cfmv32ah mvfx0, mvax0
120 cfstr32 mvfx0, [r1, #CRUNCH_MVAX0H]
121 cfmv32al mvfx0, mvax1
122 cfstr32 mvfx0, [r1, #CRUNCH_MVAX1L]
123 cfmv32am mvfx0, mvax1
124 cfstr32 mvfx0, [r1, #CRUNCH_MVAX1M]
125 cfmv32ah mvfx0, mvax1
126 cfstr32 mvfx0, [r1, #CRUNCH_MVAX1H]
127 cfmv32al mvfx0, mvax2
128 cfstr32 mvfx0, [r1, #CRUNCH_MVAX2L]
129 cfmv32am mvfx0, mvax2
130 cfstr32 mvfx0, [r1, #CRUNCH_MVAX2M]
131 cfmv32ah mvfx0, mvax2
132 cfstr32 mvfx0, [r1, #CRUNCH_MVAX2H]
133 cfmv32al mvfx0, mvax3
134 cfstr32 mvfx0, [r1, #CRUNCH_MVAX3L]
135 cfmv32am mvfx0, mvax3
136 cfstr32 mvfx0, [r1, #CRUNCH_MVAX3M]
137 cfmv32ah mvfx0, mvax3
138 cfstr32 mvfx0, [r1, #CRUNCH_MVAX3H]
139
140 cfmv32sc mvdx0, dspsc @ save status word
141 cfstr64 mvdx0, [r1, #CRUNCH_DSPSC]
142
143 teq r0, #0 @ anything to load?
144 cfldr64eq mvdx0, [r1, #CRUNCH_MVDX0] @ mvdx0 was clobbered
145 moveq pc, lr
146
147crunch_load:
148 cfldr64 mvdx0, [r0, #CRUNCH_DSPSC] @ load status word
149 cfmvsc32 dspsc, mvdx0
150
151 cfldr32 mvfx0, [r0, #CRUNCH_MVAX0L] @ load 72b accumulators
152 cfmval32 mvax0, mvfx0
153 cfldr32 mvfx0, [r0, #CRUNCH_MVAX0M]
154 cfmvam32 mvax0, mvfx0
155 cfldr32 mvfx0, [r0, #CRUNCH_MVAX0H]
156 cfmvah32 mvax0, mvfx0
157 cfldr32 mvfx0, [r0, #CRUNCH_MVAX1L]
158 cfmval32 mvax1, mvfx0
159 cfldr32 mvfx0, [r0, #CRUNCH_MVAX1M]
160 cfmvam32 mvax1, mvfx0
161 cfldr32 mvfx0, [r0, #CRUNCH_MVAX1H]
162 cfmvah32 mvax1, mvfx0
163 cfldr32 mvfx0, [r0, #CRUNCH_MVAX2L]
164 cfmval32 mvax2, mvfx0
165 cfldr32 mvfx0, [r0, #CRUNCH_MVAX2M]
166 cfmvam32 mvax2, mvfx0
167 cfldr32 mvfx0, [r0, #CRUNCH_MVAX2H]
168 cfmvah32 mvax2, mvfx0
169 cfldr32 mvfx0, [r0, #CRUNCH_MVAX3L]
170 cfmval32 mvax3, mvfx0
171 cfldr32 mvfx0, [r0, #CRUNCH_MVAX3M]
172 cfmvam32 mvax3, mvfx0
173 cfldr32 mvfx0, [r0, #CRUNCH_MVAX3H]
174 cfmvah32 mvax3, mvfx0
175
176 cfldr64 mvdx0, [r0, #CRUNCH_MVDX0] @ load 64b registers
177 cfldr64 mvdx1, [r0, #CRUNCH_MVDX1]
178 cfldr64 mvdx2, [r0, #CRUNCH_MVDX2]
179 cfldr64 mvdx3, [r0, #CRUNCH_MVDX3]
180 cfldr64 mvdx4, [r0, #CRUNCH_MVDX4]
181 cfldr64 mvdx5, [r0, #CRUNCH_MVDX5]
182 cfldr64 mvdx6, [r0, #CRUNCH_MVDX6]
183 cfldr64 mvdx7, [r0, #CRUNCH_MVDX7]
184 cfldr64 mvdx8, [r0, #CRUNCH_MVDX8]
185 cfldr64 mvdx9, [r0, #CRUNCH_MVDX9]
186 cfldr64 mvdx10, [r0, #CRUNCH_MVDX10]
187 cfldr64 mvdx11, [r0, #CRUNCH_MVDX11]
188 cfldr64 mvdx12, [r0, #CRUNCH_MVDX12]
189 cfldr64 mvdx13, [r0, #CRUNCH_MVDX13]
190 cfldr64 mvdx14, [r0, #CRUNCH_MVDX14]
191 cfldr64 mvdx15, [r0, #CRUNCH_MVDX15]
192
193 mov pc, lr
194
195/*
196 * Back up crunch regs to save area and disable access to them
197 * (mainly for gdb or sleep mode usage)
198 *
199 * r0 = struct thread_info pointer of target task or NULL for any
200 */
201ENTRY(crunch_task_disable)
202 stmfd sp!, {r4, r5, lr}
203
204 mrs ip, cpsr
205 orr r2, ip, #PSR_I_BIT @ disable interrupts
206 msr cpsr_c, r2
207
208 ldr r4, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr
209
210 ldr r3, =crunch_owner
211 add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
212 ldr r1, [r3] @ get current crunch owner
213 teq r1, #0 @ any current owner?
214 beq 1f @ no: quit
215 teq r0, #0 @ any owner?
216 teqne r1, r2 @ or specified one?
217 bne 1f @ no: quit
218
219 ldr r5, [r4, #0x80] @ enable access to crunch
220 mov r2, #0xaa
221 str r2, [r4, #0xc0]
222 orr r5, r5, #0x00800000
223 str r5, [r4, #0x80]
224
225 mov r0, #0 @ nothing to load
226 str r0, [r3] @ no more current owner
227 ldr r2, [r4, #0x80] @ flush out enable (@@@)
228 mov r2, r2
229 bl crunch_save
230
231 mov r2, #0xaa @ disable access to crunch
232 str r2, [r4, #0xc0]
233 bic r5, r5, #0x00800000
234 str r5, [r4, #0x80]
235 ldr r5, [r4, #0x80] @ flush out enable (@@@)
236 mov r5, r5
237
2381: msr cpsr_c, ip @ restore interrupt mode
239 ldmfd sp!, {r4, r5, pc}
240
241/*
242 * Copy crunch state to given memory address
243 *
244 * r0 = struct thread_info pointer of target task
245 * r1 = memory address where to store crunch state
246 *
247 * this is called mainly in the creation of signal stack frames
248 */
249ENTRY(crunch_task_copy)
250 mrs ip, cpsr
251 orr r2, ip, #PSR_I_BIT @ disable interrupts
252 msr cpsr_c, r2
253
254 ldr r3, =crunch_owner
255 add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
256 ldr r3, [r3] @ get current crunch owner
257 teq r2, r3 @ does this task own it...
258 beq 1f
259
260 @ current crunch values are in the task save area
261 msr cpsr_c, ip @ restore interrupt mode
262 mov r0, r1
263 mov r1, r2
264 mov r2, #CRUNCH_SIZE
265 b memcpy
266
2671: @ this task owns crunch regs -- grab a copy from there
268 mov r0, #0 @ nothing to load
269 mov r3, lr @ preserve return address
270 bl crunch_save
271 msr cpsr_c, ip @ restore interrupt mode
272 mov pc, r3
273
274/*
275 * Restore crunch state from given memory address
276 *
277 * r0 = struct thread_info pointer of target task
278 * r1 = memory address where to get crunch state from
279 *
280 * this is used to restore crunch state when unwinding a signal stack frame
281 */
282ENTRY(crunch_task_restore)
283 mrs ip, cpsr
284 orr r2, ip, #PSR_I_BIT @ disable interrupts
285 msr cpsr_c, r2
286
287 ldr r3, =crunch_owner
288 add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
289 ldr r3, [r3] @ get current crunch owner
290 teq r2, r3 @ does this task own it...
291 beq 1f
292
293 @ this task doesn't own crunch regs -- use its save area
294 msr cpsr_c, ip @ restore interrupt mode
295 mov r0, r2
296 mov r2, #CRUNCH_SIZE
297 b memcpy
298
2991: @ this task owns crunch regs -- load them directly
300 mov r0, r1
301 mov r1, #0 @ nothing to save
302 mov r3, lr @ preserve return address
303 bl crunch_load
304 msr cpsr_c, ip @ restore interrupt mode
305 mov pc, r3
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
new file mode 100644
index 00000000000..25ef223ba7f
--- /dev/null
+++ b/arch/arm/kernel/crunch.c
@@ -0,0 +1,88 @@
1/*
2 * arch/arm/kernel/crunch.c
3 * Cirrus MaverickCrunch context switching and handling
4 *
5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/signal.h>
16#include <linux/sched.h>
17#include <linux/init.h>
18#include <linux/io.h>
19#include <mach/ep93xx-regs.h>
20#include <asm/thread_notify.h>
21
22struct crunch_state *crunch_owner;
23
24void crunch_task_release(struct thread_info *thread)
25{
26 local_irq_disable();
27 if (crunch_owner == &thread->crunchstate)
28 crunch_owner = NULL;
29 local_irq_enable();
30}
31
32static int crunch_enabled(u32 devcfg)
33{
34 return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
35}
36
37static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
38{
39 struct thread_info *thread = (struct thread_info *)t;
40 struct crunch_state *crunch_state;
41 u32 devcfg;
42
43 crunch_state = &thread->crunchstate;
44
45 switch (cmd) {
46 case THREAD_NOTIFY_FLUSH:
47 memset(crunch_state, 0, sizeof(*crunch_state));
48
49 /*
50 * FALLTHROUGH: Ensure we don't try to overwrite our newly
51 * initialised state information on the first fault.
52 */
53
54 case THREAD_NOTIFY_EXIT:
55 crunch_task_release(thread);
56 break;
57
58 case THREAD_NOTIFY_SWITCH:
59 devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
60 if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
61 /*
62 * We don't use ep93xx_syscon_swlocked_write() here
63 * because we are on the context switch path and
64 * preemption is already disabled.
65 */
66 devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
67 __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
68 __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
69 }
70 break;
71 }
72
73 return NOTIFY_DONE;
74}
75
76static struct notifier_block crunch_notifier_block = {
77 .notifier_call = crunch_do,
78};
79
80static int __init crunch_init(void)
81{
82 thread_register_notifier(&crunch_notifier_block);
83 elf_hwcap |= HWCAP_CRUNCH;
84
85 return 0;
86}
87
88late_initcall(crunch_init);
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
new file mode 100644
index 00000000000..d16500110ee
--- /dev/null
+++ b/arch/arm/kernel/ecard.c
@@ -0,0 +1,1241 @@
1/*
2 * linux/arch/arm/kernel/ecard.c
3 *
4 * Copyright 1995-2001 Russell King
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 version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Find all installed expansion cards, and handle interrupts from them.
11 *
12 * Created from information from Acorns RiscOS3 PRMs
13 *
14 * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether
15 * podule slot.
16 * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work.
17 * 12-Sep-1997 RMK Created new handling of interrupt enables/disables
18 * - cards can now register their own routine to control
19 * interrupts (recommended).
20 * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled
21 * on reset from Linux. (Caused cards not to respond
22 * under RiscOS without hard reset).
23 * 15-Feb-1998 RMK Added DMA support
24 * 12-Sep-1998 RMK Added EASI support
25 * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment.
26 * 17-Apr-1999 RMK Support for EASI Type C cycles.
27 */
28#define ECARD_C
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/types.h>
33#include <linux/sched.h>
34#include <linux/interrupt.h>
35#include <linux/completion.h>
36#include <linux/reboot.h>
37#include <linux/mm.h>
38#include <linux/slab.h>
39#include <linux/proc_fs.h>
40#include <linux/seq_file.h>
41#include <linux/device.h>
42#include <linux/init.h>
43#include <linux/mutex.h>
44#include <linux/kthread.h>
45#include <linux/io.h>
46
47#include <asm/dma.h>
48#include <asm/ecard.h>
49#include <mach/hardware.h>
50#include <asm/irq.h>
51#include <asm/mmu_context.h>
52#include <asm/mach/irq.h>
53#include <asm/tlbflush.h>
54
55#include "ecard.h"
56
57#ifndef CONFIG_ARCH_RPC
58#define HAVE_EXPMASK
59#endif
60
61struct ecard_request {
62 void (*fn)(struct ecard_request *);
63 ecard_t *ec;
64 unsigned int address;
65 unsigned int length;
66 unsigned int use_loader;
67 void *buffer;
68 struct completion *complete;
69};
70
71struct expcard_blacklist {
72 unsigned short manufacturer;
73 unsigned short product;
74 const char *type;
75};
76
77static ecard_t *cards;
78static ecard_t *slot_to_expcard[MAX_ECARDS];
79static unsigned int ectcr;
80#ifdef HAS_EXPMASK
81static unsigned int have_expmask;
82#endif
83
84/* List of descriptions of cards which don't have an extended
85 * identification, or chunk directories containing a description.
86 */
87static struct expcard_blacklist __initdata blacklist[] = {
88 { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
89};
90
91asmlinkage extern int
92ecard_loader_reset(unsigned long base, loader_t loader);
93asmlinkage extern int
94ecard_loader_read(int off, unsigned long base, loader_t loader);
95
96static inline unsigned short ecard_getu16(unsigned char *v)
97{
98 return v[0] | v[1] << 8;
99}
100
101static inline signed long ecard_gets24(unsigned char *v)
102{
103 return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
104}
105
106static inline ecard_t *slot_to_ecard(unsigned int slot)
107{
108 return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
109}
110
111/* ===================== Expansion card daemon ======================== */
112/*
113 * Since the loader programs on the expansion cards need to be run
114 * in a specific environment, create a separate task with this
115 * environment up, and pass requests to this task as and when we
116 * need to.
117 *
118 * This should allow 99% of loaders to be called from Linux.
119 *
120 * From a security standpoint, we trust the card vendors. This
121 * may be a misplaced trust.
122 */
123static void ecard_task_reset(struct ecard_request *req)
124{
125 struct expansion_card *ec = req->ec;
126 struct resource *res;
127
128 res = ec->slot_no == 8
129 ? &ec->resource[ECARD_RES_MEMC]
130 : ec->easi
131 ? &ec->resource[ECARD_RES_EASI]
132 : &ec->resource[ECARD_RES_IOCSYNC];
133
134 ecard_loader_reset(res->start, ec->loader);
135}
136
137static void ecard_task_readbytes(struct ecard_request *req)
138{
139 struct expansion_card *ec = req->ec;
140 unsigned char *buf = req->buffer;
141 unsigned int len = req->length;
142 unsigned int off = req->address;
143
144 if (ec->slot_no == 8) {
145 void __iomem *base = (void __iomem *)
146 ec->resource[ECARD_RES_MEMC].start;
147
148 /*
149 * The card maintains an index which increments the address
150 * into a 4096-byte page on each access. We need to keep
151 * track of the counter.
152 */
153 static unsigned int index;
154 unsigned int page;
155
156 page = (off >> 12) * 4;
157 if (page > 256 * 4)
158 return;
159
160 off &= 4095;
161
162 /*
163 * If we are reading offset 0, or our current index is
164 * greater than the offset, reset the hardware index counter.
165 */
166 if (off == 0 || index > off) {
167 writeb(0, base);
168 index = 0;
169 }
170
171 /*
172 * Increment the hardware index counter until we get to the
173 * required offset. The read bytes are discarded.
174 */
175 while (index < off) {
176 readb(base + page);
177 index += 1;
178 }
179
180 while (len--) {
181 *buf++ = readb(base + page);
182 index += 1;
183 }
184 } else {
185 unsigned long base = (ec->easi
186 ? &ec->resource[ECARD_RES_EASI]
187 : &ec->resource[ECARD_RES_IOCSYNC])->start;
188 void __iomem *pbase = (void __iomem *)base;
189
190 if (!req->use_loader || !ec->loader) {
191 off *= 4;
192 while (len--) {
193 *buf++ = readb(pbase + off);
194 off += 4;
195 }
196 } else {
197 while(len--) {
198 /*
199 * The following is required by some
200 * expansion card loader programs.
201 */
202 *(unsigned long *)0x108 = 0;
203 *buf++ = ecard_loader_read(off++, base,
204 ec->loader);
205 }
206 }
207 }
208
209}
210
211static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
212static struct ecard_request *ecard_req;
213static DEFINE_MUTEX(ecard_mutex);
214
215/*
216 * Set up the expansion card daemon's page tables.
217 */
218static void ecard_init_pgtables(struct mm_struct *mm)
219{
220 struct vm_area_struct vma;
221
222 /* We want to set up the page tables for the following mapping:
223 * Virtual Physical
224 * 0x03000000 0x03000000
225 * 0x03010000 unmapped
226 * 0x03210000 0x03210000
227 * 0x03400000 unmapped
228 * 0x08000000 0x08000000
229 * 0x10000000 unmapped
230 *
231 * FIXME: we don't follow this 100% yet.
232 */
233 pgd_t *src_pgd, *dst_pgd;
234
235 src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
236 dst_pgd = pgd_offset(mm, IO_START);
237
238 memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
239
240 src_pgd = pgd_offset(mm, EASI_BASE);
241 dst_pgd = pgd_offset(mm, EASI_START);
242
243 memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
244
245 vma.vm_mm = mm;
246
247 flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
248 flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
249}
250
251static int ecard_init_mm(void)
252{
253 struct mm_struct * mm = mm_alloc();
254 struct mm_struct *active_mm = current->active_mm;
255
256 if (!mm)
257 return -ENOMEM;
258
259 current->mm = mm;
260 current->active_mm = mm;
261 activate_mm(active_mm, mm);
262 mmdrop(active_mm);
263 ecard_init_pgtables(mm);
264 return 0;
265}
266
267static int
268ecard_task(void * unused)
269{
270 /*
271 * Allocate a mm. We're not a lazy-TLB kernel task since we need
272 * to set page table entries where the user space would be. Note
273 * that this also creates the page tables. Failure is not an
274 * option here.
275 */
276 if (ecard_init_mm())
277 panic("kecardd: unable to alloc mm\n");
278
279 while (1) {
280 struct ecard_request *req;
281
282 wait_event_interruptible(ecard_wait, ecard_req != NULL);
283
284 req = xchg(&ecard_req, NULL);
285 if (req != NULL) {
286 req->fn(req);
287 complete(req->complete);
288 }
289 }
290}
291
292/*
293 * Wake the expansion card daemon to action our request.
294 *
295 * FIXME: The test here is not sufficient to detect if the
296 * kcardd is running.
297 */
298static void ecard_call(struct ecard_request *req)
299{
300 DECLARE_COMPLETION_ONSTACK(completion);
301
302 req->complete = &completion;
303
304 mutex_lock(&ecard_mutex);
305 ecard_req = req;
306 wake_up(&ecard_wait);
307
308 /*
309 * Now wait for kecardd to run.
310 */
311 wait_for_completion(&completion);
312 mutex_unlock(&ecard_mutex);
313}
314
315/* ======================= Mid-level card control ===================== */
316
317static void
318ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
319{
320 struct ecard_request req;
321
322 req.fn = ecard_task_readbytes;
323 req.ec = ec;
324 req.address = off;
325 req.length = len;
326 req.use_loader = useld;
327 req.buffer = addr;
328
329 ecard_call(&req);
330}
331
332int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
333{
334 struct ex_chunk_dir excd;
335 int index = 16;
336 int useld = 0;
337
338 if (!ec->cid.cd)
339 return 0;
340
341 while(1) {
342 ecard_readbytes(&excd, ec, index, 8, useld);
343 index += 8;
344 if (c_id(&excd) == 0) {
345 if (!useld && ec->loader) {
346 useld = 1;
347 index = 0;
348 continue;
349 }
350 return 0;
351 }
352 if (c_id(&excd) == 0xf0) { /* link */
353 index = c_start(&excd);
354 continue;
355 }
356 if (c_id(&excd) == 0x80) { /* loader */
357 if (!ec->loader) {
358 ec->loader = kmalloc(c_len(&excd),
359 GFP_KERNEL);
360 if (ec->loader)
361 ecard_readbytes(ec->loader, ec,
362 (int)c_start(&excd),
363 c_len(&excd), useld);
364 else
365 return 0;
366 }
367 continue;
368 }
369 if (c_id(&excd) == id && num-- == 0)
370 break;
371 }
372
373 if (c_id(&excd) & 0x80) {
374 switch (c_id(&excd) & 0x70) {
375 case 0x70:
376 ecard_readbytes((unsigned char *)excd.d.string, ec,
377 (int)c_start(&excd), c_len(&excd),
378 useld);
379 break;
380 case 0x00:
381 break;
382 }
383 }
384 cd->start_offset = c_start(&excd);
385 memcpy(cd->d.string, excd.d.string, 256);
386 return 1;
387}
388
389/* ======================= Interrupt control ============================ */
390
391static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
392{
393#ifdef HAS_EXPMASK
394 if (irqnr < 4 && have_expmask) {
395 have_expmask |= 1 << irqnr;
396 __raw_writeb(have_expmask, EXPMASK_ENABLE);
397 }
398#endif
399}
400
401static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
402{
403#ifdef HAS_EXPMASK
404 if (irqnr < 4 && have_expmask) {
405 have_expmask &= ~(1 << irqnr);
406 __raw_writeb(have_expmask, EXPMASK_ENABLE);
407 }
408#endif
409}
410
411static int ecard_def_irq_pending(ecard_t *ec)
412{
413 return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
414}
415
416static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
417{
418 panic("ecard_def_fiq_enable called - impossible");
419}
420
421static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
422{
423 panic("ecard_def_fiq_disable called - impossible");
424}
425
426static int ecard_def_fiq_pending(ecard_t *ec)
427{
428 return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
429}
430
431static expansioncard_ops_t ecard_default_ops = {
432 ecard_def_irq_enable,
433 ecard_def_irq_disable,
434 ecard_def_irq_pending,
435 ecard_def_fiq_enable,
436 ecard_def_fiq_disable,
437 ecard_def_fiq_pending
438};
439
440/*
441 * Enable and disable interrupts from expansion cards.
442 * (interrupts are disabled for these functions).
443 *
444 * They are not meant to be called directly, but via enable/disable_irq.
445 */
446static void ecard_irq_unmask(struct irq_data *d)
447{
448 ecard_t *ec = slot_to_ecard(d->irq - 32);
449
450 if (ec) {
451 if (!ec->ops)
452 ec->ops = &ecard_default_ops;
453
454 if (ec->claimed && ec->ops->irqenable)
455 ec->ops->irqenable(ec, d->irq);
456 else
457 printk(KERN_ERR "ecard: rejecting request to "
458 "enable IRQs for %d\n", d->irq);
459 }
460}
461
462static void ecard_irq_mask(struct irq_data *d)
463{
464 ecard_t *ec = slot_to_ecard(d->irq - 32);
465
466 if (ec) {
467 if (!ec->ops)
468 ec->ops = &ecard_default_ops;
469
470 if (ec->ops && ec->ops->irqdisable)
471 ec->ops->irqdisable(ec, d->irq);
472 }
473}
474
475static struct irq_chip ecard_chip = {
476 .name = "ECARD",
477 .irq_ack = ecard_irq_mask,
478 .irq_mask = ecard_irq_mask,
479 .irq_unmask = ecard_irq_unmask,
480};
481
482void ecard_enablefiq(unsigned int fiqnr)
483{
484 ecard_t *ec = slot_to_ecard(fiqnr);
485
486 if (ec) {
487 if (!ec->ops)
488 ec->ops = &ecard_default_ops;
489
490 if (ec->claimed && ec->ops->fiqenable)
491 ec->ops->fiqenable(ec, fiqnr);
492 else
493 printk(KERN_ERR "ecard: rejecting request to "
494 "enable FIQs for %d\n", fiqnr);
495 }
496}
497
498void ecard_disablefiq(unsigned int fiqnr)
499{
500 ecard_t *ec = slot_to_ecard(fiqnr);
501
502 if (ec) {
503 if (!ec->ops)
504 ec->ops = &ecard_default_ops;
505
506 if (ec->ops->fiqdisable)
507 ec->ops->fiqdisable(ec, fiqnr);
508 }
509}
510
511static void ecard_dump_irq_state(void)
512{
513 ecard_t *ec;
514
515 printk("Expansion card IRQ state:\n");
516
517 for (ec = cards; ec; ec = ec->next) {
518 if (ec->slot_no == 8)
519 continue;
520
521 printk(" %d: %sclaimed, ",
522 ec->slot_no, ec->claimed ? "" : "not ");
523
524 if (ec->ops && ec->ops->irqpending &&
525 ec->ops != &ecard_default_ops)
526 printk("irq %spending\n",
527 ec->ops->irqpending(ec) ? "" : "not ");
528 else
529 printk("irqaddr %p, mask = %02X, status = %02X\n",
530 ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
531 }
532}
533
534static void ecard_check_lockup(struct irq_desc *desc)
535{
536 static unsigned long last;
537 static int lockup;
538
539 /*
540 * If the timer interrupt has not run since the last million
541 * unrecognised expansion card interrupts, then there is
542 * something seriously wrong. Disable the expansion card
543 * interrupts so at least we can continue.
544 *
545 * Maybe we ought to start a timer to re-enable them some time
546 * later?
547 */
548 if (last == jiffies) {
549 lockup += 1;
550 if (lockup > 1000000) {
551 printk(KERN_ERR "\nInterrupt lockup detected - "
552 "disabling all expansion card interrupts\n");
553
554 desc->irq_data.chip->irq_mask(&desc->irq_data);
555 ecard_dump_irq_state();
556 }
557 } else
558 lockup = 0;
559
560 /*
561 * If we did not recognise the source of this interrupt,
562 * warn the user, but don't flood the user with these messages.
563 */
564 if (!last || time_after(jiffies, last + 5*HZ)) {
565 last = jiffies;
566 printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
567 ecard_dump_irq_state();
568 }
569}
570
571static void
572ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
573{
574 ecard_t *ec;
575 int called = 0;
576
577 desc->irq_data.chip->irq_mask(&desc->irq_data);
578 for (ec = cards; ec; ec = ec->next) {
579 int pending;
580
581 if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
582 continue;
583
584 if (ec->ops && ec->ops->irqpending)
585 pending = ec->ops->irqpending(ec);
586 else
587 pending = ecard_default_ops.irqpending(ec);
588
589 if (pending) {
590 generic_handle_irq(ec->irq);
591 called ++;
592 }
593 }
594 desc->irq_data.chip->irq_unmask(&desc->irq_data);
595
596 if (called == 0)
597 ecard_check_lockup(desc);
598}
599
600#ifdef HAS_EXPMASK
601static unsigned char priority_masks[] =
602{
603 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff
604};
605
606static unsigned char first_set[] =
607{
608 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
609 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
610};
611
612static void
613ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc)
614{
615 const unsigned int statusmask = 15;
616 unsigned int status;
617
618 status = __raw_readb(EXPMASK_STATUS) & statusmask;
619 if (status) {
620 unsigned int slot = first_set[status];
621 ecard_t *ec = slot_to_ecard(slot);
622
623 if (ec->claimed) {
624 /*
625 * this ugly code is so that we can operate a
626 * prioritorising system:
627 *
628 * Card 0 highest priority
629 * Card 1
630 * Card 2
631 * Card 3 lowest priority
632 *
633 * Serial cards should go in 0/1, ethernet/scsi in 2/3
634 * otherwise you will lose serial data at high speeds!
635 */
636 generic_handle_irq(ec->irq);
637 } else {
638 printk(KERN_WARNING "card%d: interrupt from unclaimed "
639 "card???\n", slot);
640 have_expmask &= ~(1 << slot);
641 __raw_writeb(have_expmask, EXPMASK_ENABLE);
642 }
643 } else
644 printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
645}
646
647static int __init ecard_probeirqhw(void)
648{
649 ecard_t *ec;
650 int found;
651
652 __raw_writeb(0x00, EXPMASK_ENABLE);
653 __raw_writeb(0xff, EXPMASK_STATUS);
654 found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
655 __raw_writeb(0xff, EXPMASK_ENABLE);
656
657 if (found) {
658 printk(KERN_DEBUG "Expansion card interrupt "
659 "management hardware found\n");
660
661 /* for each card present, set a bit to '1' */
662 have_expmask = 0x80000000;
663
664 for (ec = cards; ec; ec = ec->next)
665 have_expmask |= 1 << ec->slot_no;
666
667 __raw_writeb(have_expmask, EXPMASK_ENABLE);
668 }
669
670 return found;
671}
672#else
673#define ecard_irqexp_handler NULL
674#define ecard_probeirqhw() (0)
675#endif
676
677#ifndef IO_EC_MEMC8_BASE
678#define IO_EC_MEMC8_BASE 0
679#endif
680
681static unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
682{
683 unsigned long address = 0;
684 int slot = ec->slot_no;
685
686 if (ec->slot_no == 8)
687 return IO_EC_MEMC8_BASE;
688
689 ectcr &= ~(1 << slot);
690
691 switch (type) {
692 case ECARD_MEMC:
693 if (slot < 4)
694 address = IO_EC_MEMC_BASE + (slot << 12);
695 break;
696
697 case ECARD_IOC:
698 if (slot < 4)
699 address = IO_EC_IOC_BASE + (slot << 12);
700#ifdef IO_EC_IOC4_BASE
701 else
702 address = IO_EC_IOC4_BASE + ((slot - 4) << 12);
703#endif
704 if (address)
705 address += speed << 17;
706 break;
707
708#ifdef IO_EC_EASI_BASE
709 case ECARD_EASI:
710 address = IO_EC_EASI_BASE + (slot << 22);
711 if (speed == ECARD_FAST)
712 ectcr |= 1 << slot;
713 break;
714#endif
715 default:
716 break;
717 }
718
719#ifdef IOMD_ECTCR
720 iomd_writeb(ectcr, IOMD_ECTCR);
721#endif
722 return address;
723}
724
725static int ecard_prints(struct seq_file *m, ecard_t *ec)
726{
727 seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " ");
728
729 if (ec->cid.id == 0) {
730 struct in_chunk_dir incd;
731
732 seq_printf(m, "[%04X:%04X] ",
733 ec->cid.manufacturer, ec->cid.product);
734
735 if (!ec->card_desc && ec->cid.cd &&
736 ecard_readchunk(&incd, ec, 0xf5, 0)) {
737 ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
738
739 if (ec->card_desc)
740 strcpy((char *)ec->card_desc, incd.d.string);
741 }
742
743 seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
744 } else
745 seq_printf(m, "Simple card %d\n", ec->cid.id);
746
747 return 0;
748}
749
750static int ecard_devices_proc_show(struct seq_file *m, void *v)
751{
752 ecard_t *ec = cards;
753
754 while (ec) {
755 ecard_prints(m, ec);
756 ec = ec->next;
757 }
758 return 0;
759}
760
761static int ecard_devices_proc_open(struct inode *inode, struct file *file)
762{
763 return single_open(file, ecard_devices_proc_show, NULL);
764}
765
766static const struct file_operations bus_ecard_proc_fops = {
767 .owner = THIS_MODULE,
768 .open = ecard_devices_proc_open,
769 .read = seq_read,
770 .llseek = seq_lseek,
771 .release = single_release,
772};
773
774static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
775
776static void ecard_proc_init(void)
777{
778 proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
779 proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
780}
781
782#define ec_set_resource(ec,nr,st,sz) \
783 do { \
784 (ec)->resource[nr].name = dev_name(&ec->dev); \
785 (ec)->resource[nr].start = st; \
786 (ec)->resource[nr].end = (st) + (sz) - 1; \
787 (ec)->resource[nr].flags = IORESOURCE_MEM; \
788 } while (0)
789
790static void __init ecard_free_card(struct expansion_card *ec)
791{
792 int i;
793
794 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
795 if (ec->resource[i].flags)
796 release_resource(&ec->resource[i]);
797
798 kfree(ec);
799}
800
801static struct expansion_card *__init ecard_alloc_card(int type, int slot)
802{
803 struct expansion_card *ec;
804 unsigned long base;
805 int i;
806
807 ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
808 if (!ec) {
809 ec = ERR_PTR(-ENOMEM);
810 goto nomem;
811 }
812
813 ec->slot_no = slot;
814 ec->easi = type == ECARD_EASI;
815 ec->irq = NO_IRQ;
816 ec->fiq = NO_IRQ;
817 ec->dma = NO_DMA;
818 ec->ops = &ecard_default_ops;
819
820 dev_set_name(&ec->dev, "ecard%d", slot);
821 ec->dev.parent = NULL;
822 ec->dev.bus = &ecard_bus_type;
823 ec->dev.dma_mask = &ec->dma_mask;
824 ec->dma_mask = (u64)0xffffffff;
825 ec->dev.coherent_dma_mask = ec->dma_mask;
826
827 if (slot < 4) {
828 ec_set_resource(ec, ECARD_RES_MEMC,
829 PODSLOT_MEMC_BASE + (slot << 14),
830 PODSLOT_MEMC_SIZE);
831 base = PODSLOT_IOC0_BASE + (slot << 14);
832 } else
833 base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
834
835#ifdef CONFIG_ARCH_RPC
836 if (slot < 8) {
837 ec_set_resource(ec, ECARD_RES_EASI,
838 PODSLOT_EASI_BASE + (slot << 24),
839 PODSLOT_EASI_SIZE);
840 }
841
842 if (slot == 8) {
843 ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
844 } else
845#endif
846
847 for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
848 ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
849 base + (i << 19), PODSLOT_IOC_SIZE);
850
851 for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
852 if (ec->resource[i].flags &&
853 request_resource(&iomem_resource, &ec->resource[i])) {
854 dev_err(&ec->dev, "resource(s) not available\n");
855 ec->resource[i].end -= ec->resource[i].start;
856 ec->resource[i].start = 0;
857 ec->resource[i].flags = 0;
858 }
859 }
860
861 nomem:
862 return ec;
863}
864
865static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
866{
867 struct expansion_card *ec = ECARD_DEV(dev);
868 return sprintf(buf, "%u\n", ec->irq);
869}
870
871static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
872{
873 struct expansion_card *ec = ECARD_DEV(dev);
874 return sprintf(buf, "%u\n", ec->dma);
875}
876
877static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
878{
879 struct expansion_card *ec = ECARD_DEV(dev);
880 char *str = buf;
881 int i;
882
883 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
884 str += sprintf(str, "%08x %08x %08lx\n",
885 ec->resource[i].start,
886 ec->resource[i].end,
887 ec->resource[i].flags);
888
889 return str - buf;
890}
891
892static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
893{
894 struct expansion_card *ec = ECARD_DEV(dev);
895 return sprintf(buf, "%u\n", ec->cid.manufacturer);
896}
897
898static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
899{
900 struct expansion_card *ec = ECARD_DEV(dev);
901 return sprintf(buf, "%u\n", ec->cid.product);
902}
903
904static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
905{
906 struct expansion_card *ec = ECARD_DEV(dev);
907 return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
908}
909
910static struct device_attribute ecard_dev_attrs[] = {
911 __ATTR(device, S_IRUGO, ecard_show_device, NULL),
912 __ATTR(dma, S_IRUGO, ecard_show_dma, NULL),
913 __ATTR(irq, S_IRUGO, ecard_show_irq, NULL),
914 __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
915 __ATTR(type, S_IRUGO, ecard_show_type, NULL),
916 __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL),
917 __ATTR_NULL,
918};
919
920
921int ecard_request_resources(struct expansion_card *ec)
922{
923 int i, err = 0;
924
925 for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
926 if (ecard_resource_end(ec, i) &&
927 !request_mem_region(ecard_resource_start(ec, i),
928 ecard_resource_len(ec, i),
929 ec->dev.driver->name)) {
930 err = -EBUSY;
931 break;
932 }
933 }
934
935 if (err) {
936 while (i--)
937 if (ecard_resource_end(ec, i))
938 release_mem_region(ecard_resource_start(ec, i),
939 ecard_resource_len(ec, i));
940 }
941 return err;
942}
943EXPORT_SYMBOL(ecard_request_resources);
944
945void ecard_release_resources(struct expansion_card *ec)
946{
947 int i;
948
949 for (i = 0; i < ECARD_NUM_RESOURCES; i++)
950 if (ecard_resource_end(ec, i))
951 release_mem_region(ecard_resource_start(ec, i),
952 ecard_resource_len(ec, i));
953}
954EXPORT_SYMBOL(ecard_release_resources);
955
956void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
957{
958 ec->irq_data = irq_data;
959 barrier();
960 ec->ops = ops;
961}
962EXPORT_SYMBOL(ecard_setirq);
963
964void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
965 unsigned long offset, unsigned long maxsize)
966{
967 unsigned long start = ecard_resource_start(ec, res);
968 unsigned long end = ecard_resource_end(ec, res);
969
970 if (offset > (end - start))
971 return NULL;
972
973 start += offset;
974 if (maxsize && end - start > maxsize)
975 end = start + maxsize;
976
977 return devm_ioremap(&ec->dev, start, end - start);
978}
979EXPORT_SYMBOL(ecardm_iomap);
980
981/*
982 * Probe for an expansion card.
983 *
984 * If bit 1 of the first byte of the card is set, then the
985 * card does not exist.
986 */
987static int __init
988ecard_probe(int slot, card_type_t type)
989{
990 ecard_t **ecp;
991 ecard_t *ec;
992 struct ex_ecid cid;
993 int i, rc;
994
995 ec = ecard_alloc_card(type, slot);
996 if (IS_ERR(ec)) {
997 rc = PTR_ERR(ec);
998 goto nomem;
999 }
1000
1001 rc = -ENODEV;
1002 if ((ec->podaddr = __ecard_address(ec, type, ECARD_SYNC)) == 0)
1003 goto nodev;
1004
1005 cid.r_zero = 1;
1006 ecard_readbytes(&cid, ec, 0, 16, 0);
1007 if (cid.r_zero)
1008 goto nodev;
1009
1010 ec->cid.id = cid.r_id;
1011 ec->cid.cd = cid.r_cd;
1012 ec->cid.is = cid.r_is;
1013 ec->cid.w = cid.r_w;
1014 ec->cid.manufacturer = ecard_getu16(cid.r_manu);
1015 ec->cid.product = ecard_getu16(cid.r_prod);
1016 ec->cid.country = cid.r_country;
1017 ec->cid.irqmask = cid.r_irqmask;
1018 ec->cid.irqoff = ecard_gets24(cid.r_irqoff);
1019 ec->cid.fiqmask = cid.r_fiqmask;
1020 ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
1021 ec->fiqaddr =
1022 ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr);
1023
1024 if (ec->cid.is) {
1025 ec->irqmask = ec->cid.irqmask;
1026 ec->irqaddr += ec->cid.irqoff;
1027 ec->fiqmask = ec->cid.fiqmask;
1028 ec->fiqaddr += ec->cid.fiqoff;
1029 } else {
1030 ec->irqmask = 1;
1031 ec->fiqmask = 4;
1032 }
1033
1034 for (i = 0; i < ARRAY_SIZE(blacklist); i++)
1035 if (blacklist[i].manufacturer == ec->cid.manufacturer &&
1036 blacklist[i].product == ec->cid.product) {
1037 ec->card_desc = blacklist[i].type;
1038 break;
1039 }
1040
1041 /*
1042 * hook the interrupt handlers
1043 */
1044 if (slot < 8) {
1045 ec->irq = 32 + slot;
1046 irq_set_chip_and_handler(ec->irq, &ecard_chip,
1047 handle_level_irq);
1048 set_irq_flags(ec->irq, IRQF_VALID);
1049 }
1050
1051#ifdef IO_EC_MEMC8_BASE
1052 if (slot == 8)
1053 ec->irq = 11;
1054#endif
1055#ifdef CONFIG_ARCH_RPC
1056 /* On RiscPC, only first two slots have DMA capability */
1057 if (slot < 2)
1058 ec->dma = 2 + slot;
1059#endif
1060
1061 for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
1062
1063 *ecp = ec;
1064 slot_to_expcard[slot] = ec;
1065
1066 device_register(&ec->dev);
1067
1068 return 0;
1069
1070 nodev:
1071 ecard_free_card(ec);
1072 nomem:
1073 return rc;
1074}
1075
1076/*
1077 * Initialise the expansion card system.
1078 * Locate all hardware - interrupt management and
1079 * actual cards.
1080 */
1081static int __init ecard_init(void)
1082{
1083 struct task_struct *task;
1084 int slot, irqhw;
1085
1086 task = kthread_run(ecard_task, NULL, "kecardd");
1087 if (IS_ERR(task)) {
1088 printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
1089 PTR_ERR(task));
1090 return PTR_ERR(task);
1091 }
1092
1093 printk("Probing expansion cards\n");
1094
1095 for (slot = 0; slot < 8; slot ++) {
1096 if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
1097 ecard_probe(slot, ECARD_IOC);
1098 }
1099
1100#ifdef IO_EC_MEMC8_BASE
1101 ecard_probe(8, ECARD_IOC);
1102#endif
1103
1104 irqhw = ecard_probeirqhw();
1105
1106 irq_set_chained_handler(IRQ_EXPANSIONCARD,
1107 irqhw ? ecard_irqexp_handler : ecard_irq_handler);
1108
1109 ecard_proc_init();
1110
1111 return 0;
1112}
1113
1114subsys_initcall(ecard_init);
1115
1116/*
1117 * ECARD "bus"
1118 */
1119static const struct ecard_id *
1120ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
1121{
1122 int i;
1123
1124 for (i = 0; ids[i].manufacturer != 65535; i++)
1125 if (ec->cid.manufacturer == ids[i].manufacturer &&
1126 ec->cid.product == ids[i].product)
1127 return ids + i;
1128
1129 return NULL;
1130}
1131
1132static int ecard_drv_probe(struct device *dev)
1133{
1134 struct expansion_card *ec = ECARD_DEV(dev);
1135 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1136 const struct ecard_id *id;
1137 int ret;
1138
1139 id = ecard_match_device(drv->id_table, ec);
1140
1141 ec->claimed = 1;
1142 ret = drv->probe(ec, id);
1143 if (ret)
1144 ec->claimed = 0;
1145 return ret;
1146}
1147
1148static int ecard_drv_remove(struct device *dev)
1149{
1150 struct expansion_card *ec = ECARD_DEV(dev);
1151 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1152
1153 drv->remove(ec);
1154 ec->claimed = 0;
1155
1156 /*
1157 * Restore the default operations. We ensure that the
1158 * ops are set before we change the data.
1159 */
1160 ec->ops = &ecard_default_ops;
1161 barrier();
1162 ec->irq_data = NULL;
1163
1164 return 0;
1165}
1166
1167/*
1168 * Before rebooting, we must make sure that the expansion card is in a
1169 * sensible state, so it can be re-detected. This means that the first
1170 * page of the ROM must be visible. We call the expansion cards reset
1171 * handler, if any.
1172 */
1173static void ecard_drv_shutdown(struct device *dev)
1174{
1175 struct expansion_card *ec = ECARD_DEV(dev);
1176 struct ecard_driver *drv = ECARD_DRV(dev->driver);
1177 struct ecard_request req;
1178
1179 if (dev->driver) {
1180 if (drv->shutdown)
1181 drv->shutdown(ec);
1182 ec->claimed = 0;
1183 }
1184
1185 /*
1186 * If this card has a loader, call the reset handler.
1187 */
1188 if (ec->loader) {
1189 req.fn = ecard_task_reset;
1190 req.ec = ec;
1191 ecard_call(&req);
1192 }
1193}
1194
1195int ecard_register_driver(struct ecard_driver *drv)
1196{
1197 drv->drv.bus = &ecard_bus_type;
1198
1199 return driver_register(&drv->drv);
1200}
1201
1202void ecard_remove_driver(struct ecard_driver *drv)
1203{
1204 driver_unregister(&drv->drv);
1205}
1206
1207static int ecard_match(struct device *_dev, struct device_driver *_drv)
1208{
1209 struct expansion_card *ec = ECARD_DEV(_dev);
1210 struct ecard_driver *drv = ECARD_DRV(_drv);
1211 int ret;
1212
1213 if (drv->id_table) {
1214 ret = ecard_match_device(drv->id_table, ec) != NULL;
1215 } else {
1216 ret = ec->cid.id == drv->id;
1217 }
1218
1219 return ret;
1220}
1221
1222struct bus_type ecard_bus_type = {
1223 .name = "ecard",
1224 .dev_attrs = ecard_dev_attrs,
1225 .match = ecard_match,
1226 .probe = ecard_drv_probe,
1227 .remove = ecard_drv_remove,
1228 .shutdown = ecard_drv_shutdown,
1229};
1230
1231static int ecard_bus_init(void)
1232{
1233 return bus_register(&ecard_bus_type);
1234}
1235
1236postcore_initcall(ecard_bus_init);
1237
1238EXPORT_SYMBOL(ecard_readchunk);
1239EXPORT_SYMBOL(ecard_register_driver);
1240EXPORT_SYMBOL(ecard_remove_driver);
1241EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h
new file mode 100644
index 00000000000..4642d436be2
--- /dev/null
+++ b/arch/arm/kernel/ecard.h
@@ -0,0 +1,69 @@
1/*
2 * ecard.h
3 *
4 * Copyright 2007 Russell King
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11/* Definitions internal to ecard.c - for it's use only!!
12 *
13 * External expansion card header as read from the card
14 */
15struct ex_ecid {
16 unsigned char r_irq:1;
17 unsigned char r_zero:1;
18 unsigned char r_fiq:1;
19 unsigned char r_id:4;
20 unsigned char r_a:1;
21
22 unsigned char r_cd:1;
23 unsigned char r_is:1;
24 unsigned char r_w:2;
25 unsigned char r_r1:4;
26
27 unsigned char r_r2:8;
28
29 unsigned char r_prod[2];
30
31 unsigned char r_manu[2];
32
33 unsigned char r_country;
34
35 unsigned char r_fiqmask;
36 unsigned char r_fiqoff[3];
37
38 unsigned char r_irqmask;
39 unsigned char r_irqoff[3];
40};
41
42/*
43 * Chunk directory entry as read from the card
44 */
45struct ex_chunk_dir {
46 unsigned char r_id;
47 unsigned char r_len[3];
48 unsigned long r_start;
49 union {
50 char string[256];
51 char data[1];
52 } d;
53#define c_id(x) ((x)->r_id)
54#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
55#define c_start(x) ((x)->r_start)
56};
57
58typedef enum ecard_type { /* Cards address space */
59 ECARD_IOC,
60 ECARD_MEMC,
61 ECARD_EASI
62} card_type_t;
63
64typedef enum { /* Speed for ECARD_IOC space */
65 ECARD_SLOW = 0,
66 ECARD_MEDIUM = 1,
67 ECARD_FAST = 2,
68 ECARD_SYNC = 3
69} card_speed_t;
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
new file mode 100644
index 00000000000..e7cbb50dc35
--- /dev/null
+++ b/arch/arm/kernel/init_task.c
@@ -0,0 +1,37 @@
1/*
2 * linux/arch/arm/kernel/init_task.c
3 */
4#include <linux/mm.h>
5#include <linux/module.h>
6#include <linux/fs.h>
7#include <linux/sched.h>
8#include <linux/init.h>
9#include <linux/init_task.h>
10#include <linux/mqueue.h>
11#include <linux/uaccess.h>
12
13#include <asm/pgtable.h>
14
15static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
16static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
17/*
18 * Initial thread structure.
19 *
20 * We need to make sure that this is 8192-byte aligned due to the
21 * way process stacks are handled. This is done by making sure
22 * the linker maps this in the .text segment right after head.S,
23 * and making head.S ensure the proper alignment.
24 *
25 * The things we do for performance..
26 */
27union thread_union init_thread_union __init_task_data =
28 { INIT_THREAD_INFO(init_task) };
29
30/*
31 * Initial task structure.
32 *
33 * All other task structs will be allocated on slabs in fork.c
34 */
35struct task_struct init_task = INIT_TASK(init_task);
36
37EXPORT_SYMBOL(init_task);
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
new file mode 100644
index 00000000000..136e8376a3e
--- /dev/null
+++ b/arch/arm/kernel/leds.c
@@ -0,0 +1,144 @@
1/*
2 * LED support code, ripped out of arch/arm/kernel/time.c
3 *
4 * Copyright (C) 1994-2001 Russell King
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/notifier.h>
13#include <linux/cpu.h>
14#include <linux/sysdev.h>
15#include <linux/syscore_ops.h>
16
17#include <asm/leds.h>
18
19static void dummy_leds_event(led_event_t evt)
20{
21}
22
23void (*leds_event)(led_event_t) = dummy_leds_event;
24
25struct leds_evt_name {
26 const char name[8];
27 int on;
28 int off;
29};
30
31static const struct leds_evt_name evt_names[] = {
32 { "amber", led_amber_on, led_amber_off },
33 { "blue", led_blue_on, led_blue_off },
34 { "green", led_green_on, led_green_off },
35 { "red", led_red_on, led_red_off },
36};
37
38static ssize_t leds_store(struct sys_device *dev,
39 struct sysdev_attribute *attr,
40 const char *buf, size_t size)
41{
42 int ret = -EINVAL, len = strcspn(buf, " ");
43
44 if (len > 0 && buf[len] == '\0')
45 len--;
46
47 if (strncmp(buf, "claim", len) == 0) {
48 leds_event(led_claim);
49 ret = size;
50 } else if (strncmp(buf, "release", len) == 0) {
51 leds_event(led_release);
52 ret = size;
53 } else {
54 int i;
55
56 for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
57 if (strlen(evt_names[i].name) != len ||
58 strncmp(buf, evt_names[i].name, len) != 0)
59 continue;
60 if (strncmp(buf+len, " on", 3) == 0) {
61 leds_event(evt_names[i].on);
62 ret = size;
63 } else if (strncmp(buf+len, " off", 4) == 0) {
64 leds_event(evt_names[i].off);
65 ret = size;
66 }
67 break;
68 }
69 }
70 return ret;
71}
72
73static SYSDEV_ATTR(event, 0200, NULL, leds_store);
74
75static struct sysdev_class leds_sysclass = {
76 .name = "leds",
77};
78
79static struct sys_device leds_device = {
80 .id = 0,
81 .cls = &leds_sysclass,
82};
83
84static int leds_suspend(void)
85{
86 leds_event(led_stop);
87 return 0;
88}
89
90static void leds_resume(void)
91{
92 leds_event(led_start);
93}
94
95static void leds_shutdown(void)
96{
97 leds_event(led_halted);
98}
99
100static struct syscore_ops leds_syscore_ops = {
101 .shutdown = leds_shutdown,
102 .suspend = leds_suspend,
103 .resume = leds_resume,
104};
105
106static int leds_idle_notifier(struct notifier_block *nb, unsigned long val,
107 void *data)
108{
109 switch (val) {
110 case IDLE_START:
111 leds_event(led_idle_start);
112 break;
113 case IDLE_END:
114 leds_event(led_idle_end);
115 break;
116 }
117
118 return 0;
119}
120
121static struct notifier_block leds_idle_nb = {
122 .notifier_call = leds_idle_notifier,
123};
124
125static int __init leds_init(void)
126{
127 int ret;
128 ret = sysdev_class_register(&leds_sysclass);
129 if (ret == 0)
130 ret = sysdev_register(&leds_device);
131 if (ret == 0)
132 ret = sysdev_create_file(&leds_device, &attr_event);
133
134 if (ret == 0) {
135 register_syscore_ops(&leds_syscore_ops);
136 idle_notifier_register(&leds_idle_nb);
137 }
138
139 return ret;
140}
141
142device_initcall(leds_init);
143
144EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
new file mode 100644
index 00000000000..c53474fe84d
--- /dev/null
+++ b/arch/arm/kernel/pmu.c
@@ -0,0 +1,201 @@
1/*
2 * linux/arch/arm/kernel/pmu.c
3 *
4 * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
5 * Copyright (C) 2010 ARM Ltd, Will Deacon
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#define pr_fmt(fmt) "PMU: " fmt
14
15#include <linux/cpumask.h>
16#include <linux/err.h>
17#include <linux/interrupt.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/of_device.h>
21#include <linux/platform_device.h>
22
23#include <asm/pmu.h>
24
25static volatile long pmu_lock;
26
27static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
28
29static int __devinit pmu_register(struct platform_device *pdev,
30 enum arm_pmu_type type)
31{
32 if (type < 0 || type >= ARM_NUM_PMU_DEVICES) {
33 pr_warning("received registration request for unknown "
34 "PMU device type %d\n", type);
35 return -EINVAL;
36 }
37
38 if (pmu_devices[type]) {
39 pr_warning("rejecting duplicate registration of PMU device "
40 "type %d.", type);
41 return -ENOSPC;
42 }
43
44 pr_info("registered new PMU device of type %d\n", type);
45 pmu_devices[type] = pdev;
46 return 0;
47}
48
49#define OF_MATCH_PMU(_name, _type) { \
50 .compatible = _name, \
51 .data = (void *)_type, \
52}
53
54#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU)
55
56static struct of_device_id armpmu_of_device_ids[] = {
57 OF_MATCH_CPU("arm,cortex-a9-pmu"),
58 OF_MATCH_CPU("arm,cortex-a8-pmu"),
59 OF_MATCH_CPU("arm,arm1136-pmu"),
60 OF_MATCH_CPU("arm,arm1176-pmu"),
61 {},
62};
63
64#define PLAT_MATCH_PMU(_name, _type) { \
65 .name = _name, \
66 .driver_data = _type, \
67}
68
69#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU)
70
71static struct platform_device_id armpmu_plat_device_ids[] = {
72 PLAT_MATCH_CPU("arm-pmu"),
73 {},
74};
75
76enum arm_pmu_type armpmu_device_type(struct platform_device *pdev)
77{
78 const struct of_device_id *of_id;
79 const struct platform_device_id *pdev_id;
80
81 /* provided by of_device_id table */
82 if (pdev->dev.of_node) {
83 of_id = of_match_device(armpmu_of_device_ids, &pdev->dev);
84 BUG_ON(!of_id);
85 return (enum arm_pmu_type)of_id->data;
86 }
87
88 /* Provided by platform_device_id table */
89 pdev_id = platform_get_device_id(pdev);
90 BUG_ON(!pdev_id);
91 return pdev_id->driver_data;
92}
93
94static int __devinit armpmu_device_probe(struct platform_device *pdev)
95{
96 return pmu_register(pdev, armpmu_device_type(pdev));
97}
98
99static struct platform_driver armpmu_driver = {
100 .driver = {
101 .name = "arm-pmu",
102 .of_match_table = armpmu_of_device_ids,
103 },
104 .probe = armpmu_device_probe,
105 .id_table = armpmu_plat_device_ids,
106};
107
108static int __init register_pmu_driver(void)
109{
110 return platform_driver_register(&armpmu_driver);
111}
112device_initcall(register_pmu_driver);
113
114struct platform_device *
115reserve_pmu(enum arm_pmu_type type)
116{
117 struct platform_device *pdev;
118
119 if (test_and_set_bit_lock(type, &pmu_lock)) {
120 pdev = ERR_PTR(-EBUSY);
121 } else if (pmu_devices[type] == NULL) {
122 clear_bit_unlock(type, &pmu_lock);
123 pdev = ERR_PTR(-ENODEV);
124 } else {
125 pdev = pmu_devices[type];
126 }
127
128 return pdev;
129}
130EXPORT_SYMBOL_GPL(reserve_pmu);
131
132int
133release_pmu(enum arm_pmu_type type)
134{
135 if (WARN_ON(!pmu_devices[type]))
136 return -EINVAL;
137 clear_bit_unlock(type, &pmu_lock);
138 return 0;
139}
140EXPORT_SYMBOL_GPL(release_pmu);
141
142static int
143set_irq_affinity(int irq,
144 unsigned int cpu)
145{
146#ifdef CONFIG_SMP
147 int err = irq_set_affinity(irq, cpumask_of(cpu));
148 if (err)
149 pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
150 irq, cpu);
151 return err;
152#else
153 return -EINVAL;
154#endif
155}
156
157static int
158init_cpu_pmu(void)
159{
160 int i, irqs, err = 0;
161 struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
162
163 if (!pdev)
164 return -ENODEV;
165
166 irqs = pdev->num_resources;
167
168 /*
169 * If we have a single PMU interrupt that we can't shift, assume that
170 * we're running on a uniprocessor machine and continue.
171 */
172 if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
173 return 0;
174
175 for (i = 0; i < irqs; ++i) {
176 err = set_irq_affinity(platform_get_irq(pdev, i), i);
177 if (err)
178 break;
179 }
180
181 return err;
182}
183
184int
185init_pmu(enum arm_pmu_type type)
186{
187 int err = 0;
188
189 switch (type) {
190 case ARM_PMU_DEVICE_CPU:
191 err = init_cpu_pmu();
192 break;
193 default:
194 pr_warning("attempt to initialise PMU of unknown "
195 "type %d\n", type);
196 err = -EINVAL;
197 }
198
199 return err;
200}
201EXPORT_SYMBOL_GPL(init_pmu);