move new files out from platform support patch
[openwrt/openwrt.git] / target / linux / ubicom32 / files / arch / ubicom32 / kernel / thread.c
1 /*
2 * arch/ubicom32/kernel/thread.c
3 * Ubicom32 architecture hardware thread support.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28
29 #include <linux/module.h>
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/sched.h>
33 #include <linux/interrupt.h>
34 #include <linux/irq.h>
35 #include <linux/profile.h>
36 #include <linux/clocksource.h>
37 #include <linux/types.h>
38 #include <asm/ip5000.h>
39 #include <asm/machdep.h>
40 #include <asm/asm-offsets.h>
41 #include <asm/thread.h>
42
43 /*
44 * TODO: At some point change the name here to be thread_ksp
45 */
46 unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
47
48 static unsigned int thread_mask = -1;
49 static unsigned int thread_mainline_mask;
50
51 /*
52 * thread_entry()
53 * Returning from the called function will disable the thread.
54 *
55 * This could be a naked call to allow for hwthreads that do not have stacks.
56 * However, with -O0, the code still writes to thex stack, and this was
57 * corrupting memory just after the callers stack.
58 */
59 static void thread_entry(void *arg, thread_exec_fn_t exec)
60 {
61 /*
62 * Call thread function
63 */
64 exec(arg);
65
66 /*
67 * Complete => Disable self
68 */
69 thread_disable(thread_get_self());
70 }
71
72 /*
73 * thread_start()
74 * Start the specified function on the specified hardware thread.
75 */
76 thread_t thread_start(thread_t thread,
77 thread_exec_fn_t exec,
78 void *arg,
79 unsigned int *sp_high,
80 thread_type_t type)
81 {
82 /*
83 * Sanity check
84 */
85 unsigned int enabled, mask, csr;
86 asm volatile (
87 "move.4 %0, MT_EN\n\t"
88 : "=m" (enabled)
89 );
90
91 mask = 1 << thread;
92 if (enabled & mask) {
93 printk(KERN_WARNING "request to enable a previously enabled thread\n");
94 return (thread_t)-1;
95 }
96
97 /*
98 * Update thread state
99 */
100 csr = (thread << 15) | (1 << 14);
101 asm volatile (
102 "setcsr %0 \n\t"
103 "setcsr_flush 0 \n\t"
104
105 "move.4 A0, #0 \n\t"
106 "move.4 A1, #0 \n\t"
107 "move.4 A2, #0 \n\t"
108 "move.4 A3, #0 \n\t"
109 "move.4 A4, #0 \n\t"
110 "move.4 A5, #0 \n\t"
111 "move.4 A6, #0 \n\t"
112 "move.4 SP, %4 \n\t" /* A7 is SP */
113
114 "move.4 D0, %3 \n\t"
115 "move.4 D1, %2 \n\t"
116 "move.4 D2, #0 \n\t"
117 "move.4 D3, #0 \n\t"
118 "move.4 D4, #0 \n\t"
119 "move.4 D5, #0 \n\t"
120 "move.4 D6, #0 \n\t"
121 "move.4 D7, #0 \n\t"
122 "move.4 D8, #0 \n\t"
123 "move.4 D9, #0 \n\t"
124 "move.4 D10, #0 \n\t"
125 "move.4 D11, #0 \n\t"
126 "move.4 D12, #0 \n\t"
127 "move.4 D13, #0 \n\t"
128 "move.4 D14, #0 \n\t"
129 "move.4 D15, #0 \n\t"
130
131 "move.4 INT_MASK0, #0 \n\t"
132 "move.4 INT_MASK1, #0 \n\t"
133 "move.4 PC, %1 \n\t"
134 "setcsr #0 \n\t"
135 "setcsr_flush 0 \n\t"
136 :
137 : "r" (csr), "r" (thread_entry), "r" (exec),
138 "r" (arg), "r" (sp_high)
139 );
140
141 /*
142 * Apply HRT state
143 */
144 if (type & THREAD_TYPE_HRT) {
145 asm volatile (
146 "or.4 MT_HRT, MT_HRT, %0\n\t"
147 :
148 : "d" (mask)
149 : "cc"
150 );
151 } else {
152 asm volatile (
153 "and.4 MT_HRT, MT_HRT, %0\n\t"
154 :
155 : "d" (~mask)
156 : "cc"
157 );
158 }
159
160 /*
161 * Set priority
162 */
163 asm volatile (
164 "or.4 MT_HPRI, MT_HPRI, %0\n\t"
165 :
166 : "d" (mask)
167 : "cc"
168 );
169
170 /*
171 * Enable thread
172 */
173 asm volatile (
174 "move.4 MT_ACTIVE_SET, %0 \n\t"
175 :
176 : "d" (mask)
177 );
178 thread_enable_mask(mask);
179 return thread;
180 }
181
182 /*
183 * thread_get_mainline()
184 * Return a mask of those threads that are Linux mainline threads.
185 */
186 unsigned int thread_get_mainline(void)
187 {
188 return thread_mainline_mask;
189 }
190
191 /*
192 * thread_set_mainline()
193 * Indicate that the specified thread is a Linux mainline thread.
194 */
195 void thread_set_mainline(thread_t tid)
196 {
197 thread_mainline_mask |= (1 << tid);
198 }
199
200 /*
201 * thread_alloc()
202 * Allocate an unused hardware thread.
203 */
204 thread_t thread_alloc(void)
205 {
206 thread_t tid;
207
208 /*
209 * If this is the first time we are here get the list of unused
210 * threads from the processor device tree node.
211 */
212 if (thread_mask == -1) {
213 thread_mask = processor_threads();
214 }
215
216 if (!thread_mask) {
217 return (thread_t)-1;
218 }
219
220 tid = ffs(thread_mask);
221 if (tid != 0) {
222 tid--;
223 thread_mask &= ~(1 << tid);
224 return tid;
225 }
226
227 return (thread_t)-1;
228 }