Root/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 */
46unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
47
48static unsigned int thread_mask = -1;
49static 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 */
59static 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 */
76thread_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 */
186unsigned 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 */
195void 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 */
204thread_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}
229

Archive Download this file



interactive