aaa5fbea4e8f0359682803c4a3ba83c7bceae6d7
[10.03/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 }