OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [mips/] [kernel/] [smp-mt.c] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 *  This program is free software; you can distribute it and/or modify it
3
 *  under the terms of the GNU General Public License (Version 2) as
4
 *  published by the Free Software Foundation.
5
 *
6
 *  This program is distributed in the hope it will be useful, but WITHOUT
7
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9
 *  for more details.
10
 *
11
 *  You should have received a copy of the GNU General Public License along
12
 *  with this program; if not, write to the Free Software Foundation, Inc.,
13
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
14
 *
15
 * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
16
 *    Elizabeth Clarke (beth@mips.com)
17
 *    Ralf Baechle (ralf@linux-mips.org)
18
 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
19
 */
20
#include <linux/kernel.h>
21
#include <linux/sched.h>
22
#include <linux/cpumask.h>
23
#include <linux/interrupt.h>
24
#include <linux/compiler.h>
25
 
26
#include <asm/atomic.h>
27
#include <asm/cacheflush.h>
28
#include <asm/cpu.h>
29
#include <asm/processor.h>
30
#include <asm/system.h>
31
#include <asm/hardirq.h>
32
#include <asm/mmu_context.h>
33
#include <asm/smp.h>
34
#include <asm/time.h>
35
#include <asm/mipsregs.h>
36
#include <asm/mipsmtregs.h>
37
#include <asm/mips_mt.h>
38
 
39
#define MIPS_CPU_IPI_RESCHED_IRQ 0
40
#define MIPS_CPU_IPI_CALL_IRQ 1
41
 
42
static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
43
 
44
#if 0
45
static void dump_mtregisters(int vpe, int tc)
46
{
47
        printk("vpe %d tc %d\n", vpe, tc);
48
 
49
        settc(tc);
50
 
51
        printk("  c0 status  0x%lx\n", read_vpe_c0_status());
52
        printk("  vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol());
53
        printk("  vpeconf0    0x%lx\n", read_vpe_c0_vpeconf0());
54
        printk("  tcstatus 0x%lx\n", read_tc_c0_tcstatus());
55
        printk("  tcrestart 0x%lx\n", read_tc_c0_tcrestart());
56
        printk("  tcbind 0x%lx\n", read_tc_c0_tcbind());
57
        printk("  tchalt 0x%lx\n", read_tc_c0_tchalt());
58
}
59
#endif
60
 
61
void __init sanitize_tlb_entries(void)
62
{
63
        int i, tlbsiz;
64
        unsigned long mvpconf0, ncpu;
65
 
66
        if (!cpu_has_mipsmt)
67
                return;
68
 
69
        /* Enable VPC */
70
        set_c0_mvpcontrol(MVPCONTROL_VPC);
71
 
72
        back_to_back_c0_hazard();
73
 
74
        /* Disable TLB sharing */
75
        clear_c0_mvpcontrol(MVPCONTROL_STLB);
76
 
77
        mvpconf0 = read_c0_mvpconf0();
78
 
79
        printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0,
80
                   (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT,
81
                           (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT);
82
 
83
        tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT;
84
        ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
85
 
86
        printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu);
87
 
88
        if (tlbsiz > 0) {
89
                /* share them out across the vpe's */
90
                tlbsiz /= ncpu;
91
 
92
                printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz);
93
 
94
                for (i = 0; i < ncpu; i++) {
95
                        settc(i);
96
 
97
                        if (i == 0)
98
                                write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25));
99
                        else
100
                                write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) |
101
                                                   (tlbsiz << 25));
102
                }
103
        }
104
 
105
        clear_c0_mvpcontrol(MVPCONTROL_VPC);
106
}
107
 
108
static void ipi_resched_dispatch(void)
109
{
110
        do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
111
}
112
 
113
static void ipi_call_dispatch(void)
114
{
115
        do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
116
}
117
 
118
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
119
{
120
        return IRQ_HANDLED;
121
}
122
 
123
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
124
{
125
        smp_call_function_interrupt();
126
 
127
        return IRQ_HANDLED;
128
}
129
 
130
static struct irqaction irq_resched = {
131
        .handler        = ipi_resched_interrupt,
132
        .flags          = IRQF_DISABLED|IRQF_PERCPU,
133
        .name           = "IPI_resched"
134
};
135
 
136
static struct irqaction irq_call = {
137
        .handler        = ipi_call_interrupt,
138
        .flags          = IRQF_DISABLED|IRQF_PERCPU,
139
        .name           = "IPI_call"
140
};
141
 
142
static void __init smp_copy_vpe_config(void)
143
{
144
        write_vpe_c0_status(
145
                (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
146
 
147
        /* set config to be the same as vpe0, particularly kseg0 coherency alg */
148
        write_vpe_c0_config( read_c0_config());
149
 
150
        /* make sure there are no software interrupts pending */
151
        write_vpe_c0_cause(0);
152
 
153
        /* Propagate Config7 */
154
        write_vpe_c0_config7(read_c0_config7());
155
 
156
        write_vpe_c0_count(read_c0_count());
157
}
158
 
159
static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
160
        unsigned int ncpu)
161
{
162
        if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
163
                return ncpu;
164
 
165
        /* Deactivate all but VPE 0 */
166
        if (tc != 0) {
167
                unsigned long tmp = read_vpe_c0_vpeconf0();
168
 
169
                tmp &= ~VPECONF0_VPA;
170
 
171
                /* master VPE */
172
                tmp |= VPECONF0_MVP;
173
                write_vpe_c0_vpeconf0(tmp);
174
 
175
                /* Record this as available CPU */
176
                cpu_set(tc, phys_cpu_present_map);
177
                __cpu_number_map[tc]    = ++ncpu;
178
                __cpu_logical_map[ncpu] = tc;
179
        }
180
 
181
        /* Disable multi-threading with TC's */
182
        write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
183
 
184
        if (tc != 0)
185
                smp_copy_vpe_config();
186
 
187
        return ncpu;
188
}
189
 
190
static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0)
191
{
192
        unsigned long tmp;
193
 
194
        if (!tc)
195
                return;
196
 
197
        /* bind a TC to each VPE, May as well put all excess TC's
198
           on the last VPE */
199
        if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1))
200
                write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
201
        else {
202
                write_tc_c0_tcbind(read_tc_c0_tcbind() | tc);
203
 
204
                /* and set XTC */
205
                write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT));
206
        }
207
 
208
        tmp = read_tc_c0_tcstatus();
209
 
210
        /* mark not allocated and not dynamically allocatable */
211
        tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
212
        tmp |= TCSTATUS_IXMT;           /* interrupt exempt */
213
        write_tc_c0_tcstatus(tmp);
214
 
215
        write_tc_c0_tchalt(TCHALT_H);
216
}
217
 
218
/*
219
 * Common setup before any secondaries are started
220
 * Make sure all CPU's are in a sensible state before we boot any of the
221
 * secondarys
222
 */
223
void __init plat_smp_setup(void)
224
{
225
        unsigned int mvpconf0, ntc, tc, ncpu = 0;
226
 
227
#ifdef CONFIG_MIPS_MT_FPAFF
228
        /* If we have an FPU, enroll ourselves in the FPU-full mask */
229
        if (cpu_has_fpu)
230
                cpu_set(0, mt_fpu_cpumask);
231
#endif /* CONFIG_MIPS_MT_FPAFF */
232
        if (!cpu_has_mipsmt)
233
                return;
234
 
235
        /* disable MT so we can configure */
236
        dvpe();
237
        dmt();
238
 
239
        /* Put MVPE's into 'configuration state' */
240
        set_c0_mvpcontrol(MVPCONTROL_VPC);
241
 
242
        mvpconf0 = read_c0_mvpconf0();
243
        ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT;
244
 
245
        /* we'll always have more TC's than VPE's, so loop setting everything
246
           to a sensible state */
247
        for (tc = 0; tc <= ntc; tc++) {
248
                settc(tc);
249
 
250
                smp_tc_init(tc, mvpconf0);
251
                ncpu = smp_vpe_init(tc, mvpconf0, ncpu);
252
        }
253
 
254
        /* Release config state */
255
        clear_c0_mvpcontrol(MVPCONTROL_VPC);
256
 
257
        /* We'll wait until starting the secondaries before starting MVPE */
258
 
259
        printk(KERN_INFO "Detected %i available secondary CPU(s)\n", ncpu);
260
}
261
 
262
void __init plat_prepare_cpus(unsigned int max_cpus)
263
{
264
        mips_mt_set_cpuoptions();
265
 
266
        /* set up ipi interrupts */
267
        if (cpu_has_vint) {
268
                set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
269
                set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
270
        }
271
 
272
        cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
273
        cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
274
 
275
        setup_irq(cpu_ipi_resched_irq, &irq_resched);
276
        setup_irq(cpu_ipi_call_irq, &irq_call);
277
 
278
        set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
279
        set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
280
}
281
 
282
/*
283
 * Setup the PC, SP, and GP of a secondary processor and start it
284
 * running!
285
 * smp_bootstrap is the place to resume from
286
 * __KSTK_TOS(idle) is apparently the stack pointer
287
 * (unsigned long)idle->thread_info the gp
288
 * assumes a 1:1 mapping of TC => VPE
289
 */
290
void __cpuinit prom_boot_secondary(int cpu, struct task_struct *idle)
291
{
292
        struct thread_info *gp = task_thread_info(idle);
293
        dvpe();
294
        set_c0_mvpcontrol(MVPCONTROL_VPC);
295
 
296
        settc(cpu);
297
 
298
        /* restart */
299
        write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
300
 
301
        /* enable the tc this vpe/cpu will be running */
302
        write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A);
303
 
304
        write_tc_c0_tchalt(0);
305
 
306
        /* enable the VPE */
307
        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
308
 
309
        /* stack pointer */
310
        write_tc_gpr_sp( __KSTK_TOS(idle));
311
 
312
        /* global pointer */
313
        write_tc_gpr_gp((unsigned long)gp);
314
 
315
        flush_icache_range((unsigned long)gp,
316
                           (unsigned long)(gp + sizeof(struct thread_info)));
317
 
318
        /* finally out of configuration and into chaos */
319
        clear_c0_mvpcontrol(MVPCONTROL_VPC);
320
 
321
        evpe(EVPE_ENABLE);
322
}
323
 
324
void __cpuinit prom_init_secondary(void)
325
{
326
        /* Enable per-cpu interrupts */
327
 
328
        /* This is Malta specific: IPI,performance and timer inetrrupts */
329
        write_c0_status((read_c0_status() & ~ST0_IM ) |
330
                        (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7));
331
}
332
 
333
void __cpuinit prom_smp_finish(void)
334
{
335
        write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
336
 
337
#ifdef CONFIG_MIPS_MT_FPAFF
338
        /* If we have an FPU, enroll ourselves in the FPU-full mask */
339
        if (cpu_has_fpu)
340
                cpu_set(smp_processor_id(), mt_fpu_cpumask);
341
#endif /* CONFIG_MIPS_MT_FPAFF */
342
 
343
        local_irq_enable();
344
}
345
 
346
void prom_cpus_done(void)
347
{
348
}
349
 
350
void core_send_ipi(int cpu, unsigned int action)
351
{
352
        int i;
353
        unsigned long flags;
354
        int vpflags;
355
 
356
        local_irq_save(flags);
357
 
358
        vpflags = dvpe();       /* cant access the other CPU's registers whilst MVPE enabled */
359
 
360
        switch (action) {
361
        case SMP_CALL_FUNCTION:
362
                i = C_SW1;
363
                break;
364
 
365
        case SMP_RESCHEDULE_YOURSELF:
366
        default:
367
                i = C_SW0;
368
                break;
369
        }
370
 
371
        /* 1:1 mapping of vpe and tc... */
372
        settc(cpu);
373
        write_vpe_c0_cause(read_vpe_c0_cause() | i);
374
        evpe(vpflags);
375
 
376
        local_irq_restore(flags);
377
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.